This commit is contained in:
Troplo 2020-10-12 00:25:48 +11:00
parent 1e4836aefc
commit a3e3503070
12 changed files with 113 additions and 19 deletions

3
.gitignore vendored
View File

@ -65,6 +65,7 @@ yarn-error.log*
# Config folder
config/
config/config.json
# Editor directories and files
.idea
@ -74,5 +75,3 @@ config/
*.sln
>>>>>>> frontend
frontend/dist1/
config/config.json
config/config.json

View File

@ -3,7 +3,7 @@
"username": "troplo",
"password": "ert54iuhuieht9oge5tiuyrg8hhuiydgfbvtbgfdhijn",
"database": "troplo_kaverti",
"host": "192.168.0.13",
"host": "124.169.200.10",
"dialect": "mysql",
"maintenance": "true",
"passkey": "true"
@ -12,7 +12,7 @@
"username": "troplo",
"password": "ert54iuhuieht9oge5tiuyrg8hhuiydgfbvtbgfdhijn",
"database": "troplo_kaverti",
"host": "192.168.0.13",
"host": "124.169.200.10",
"dialect": "mysql",
"maintenance": "true",
"passkey": "true"
@ -21,7 +21,7 @@
"username": "troplo",
"password": "ert54iuhuieht9oge5tiuyrg8hhuiydgfbvtbgfdhijn",
"database": "troplo_kaverti",
"host": "192.168.0.13",
"host": "124.169.200.10",
"dialect": "mysql",
"maintenance": "true",
"passkey": "true"

View File

@ -228,7 +228,7 @@
</modal-window>
<template>
<b-navbar style="border-bottom: 2px solid #e5e5e5" v-bind:fixed-top="true">
<template slot="brand">
<template slot="brand" v-if="!$store.state.username">
<b-navbar-item tag="router-link" :to="{ path: '/' }">
<img
:src = $store.state.meta.icon
@ -236,6 +236,14 @@
<h2 style="padding-left: 3px;">{{name}}</h2>
</b-navbar-item>
</template>
<template slot="brand" v-if="$store.state.username">
<b-navbar-item tag="router-link" :to="{ path: '/dashboard' }">
<img
:src = $store.state.meta.icon
>
<h2 style="padding-left: 3px;">{{name}}</h2>
</b-navbar-item>
</template>
<template slot="start">
<b-navbar-item tag="router-link" :to="{ path: '/forums' }"><b>
Forums
@ -330,7 +338,7 @@
You are using an outdated client, refresh to update.
</div>
</div>
<div v-if='$store.state.meta.bannerText && !$store.state.username' class="is-fullhd" style="padding-left: 5px; padding-right: 5px; padding-top: 20px; padding-bottom: 5px;">
<div v-if='$store.state.meta.bannerText && !$store.state.username' class="container is-fullhd" style="padding-left: 5px; padding-right: 5px; padding-top: 20px; padding-bottom: 5px;">
<div class="notification is-info">
{{$store.state.meta.bannerText}}
</div>

View File

@ -264,7 +264,7 @@
},
mounted () {
this.getUserInfo();
this.$store.dispatch('setTitle', this.$route.params.username + '\'s wall')
this.$store.dispatch('setTitle', 'Dashboard')
this.axios
.get(`/api/v1/user/GlobalWall?wall=true`)
.then(res => {

View File

@ -151,6 +151,12 @@
'email current password': ''
}
},
username: {username: '',
errors: {
'username': ''
},
loading: false,
},
deleteAcc: {
loading: false,
@ -259,6 +265,43 @@
})
},
saveUsername() {
this.username.errors['username'] = ''
if (!this.username.username.length) {
this.username.errors['username'] = 'Cannot be blank'
return
}
this.username.loading = true
this.axios
.put('/api/v1/user/preferences', {
username: this.username.username,
changeUsername: true
})
.then(() => {
this.username.username = ''
this.axios
this.username.loading = false
this.axios.get('/api/v1/userinfo')
.then(res => {
this.$store.commit('setUsername', res.data.username)
this.$store.commit('setEmail', res.data.email)
this.$store.commit('setEmailVerified', res.data.emailVerified)
this.$store.commit('setAdmin', res.data.admin)
})
})
.catch(e => {
this.username.loading = false
AjaxErrorHandler(this.$store)(e)
})
.catch(e => {
this.showConn(e)
})
},
deleteAccount() {
this.deleteAccountLoading = true
this.axios

View File

@ -19,6 +19,10 @@ let Errors = {
'Due to the nature of this action, a login is required.',
401
],
insufficientKoins: [
'Insufficient Koins to complete this transaction.',
400
],
deniedExperiments: [
'Please enable integration developer mode to access experiments.',
401

View File

@ -57,7 +57,7 @@ async function getNextCount (Model, items, limit, where, desc) {
function getPaginationProps(query, desc) {
let from = 0
let limit = 10
let limit = 30
if(desc) {
from = null

View File

@ -316,6 +316,12 @@ module.exports = (sequelize, DataTypes) => {
throw Errors.invalidLoginCredentials
}
},
async updateUsername (username) {
if(typeof username !== 'string') {
throw new sequelize.ValidationError('input must be a string')
}
await this.update({ username: username, koins: this.koins - 200})
},
async comparePassword (password) {
return await bcrypt.compare(password, this.hash)
},

View File

@ -3,6 +3,18 @@ let router = express.Router()
const Errors = require('../lib/errors')
let { User, Thread, Post, Notification, Ban, Sequelize, sequelize } = require('../models')
const rateLimit = require("express-rate-limit");
const postLimiter = rateLimit({
windowMs: 60000,
max: 10,
message: "{\"errors\":[{\"name\":\"rateLimit\",\"message\":\"You may only make 10 requests to this endpoint per minute.\",\"status\":429}]}"
});
const likeLimiter = rateLimit({
windowMs: 60000,
max: 25,
message: "{\"errors\":[{\"name\":\"rateLimit\",\"message\":\"You may only make 25 requests to this endpoint per minute.\",\"status\":429}]}"
});
router.get('/:post_id', async (req, res, next) => {
try {
@ -28,7 +40,7 @@ router.all('*', (req, res, next) => {
})
router.put('/:post_id/like', async (req, res, next) => {
router.put('/:post_id/like', likeLimiter, async (req, res, next) => {
try {
let post = await Post.findById(req.params.post_id)
let user = await User.findOne({ where: { username: req.session.username }})
@ -43,7 +55,7 @@ router.put('/:post_id/like', async (req, res, next) => {
} catch (e) { next(e) }
})
router.delete('/:post_id/like', async (req, res, next) => {
router.delete('/:post_id/like', likeLimiter, async (req, res, next) => {
try {
let post = await Post.findById(req.params.post_id)
let user = await User.findOne({ where: { username: req.session.username }})
@ -57,7 +69,7 @@ router.delete('/:post_id/like', async (req, res, next) => {
} catch (e) { next(e) }
})
router.post('/', async (req, res, next) => {
router.post('/', postLimiter, async (req, res, next) => {
let thread, replyingToPost, post, uniqueMentions = []
let queryObj = {
attributes: {include: ['emailVerified']},

View File

@ -4,7 +4,12 @@ let router = express.Router()
const Errors = require('../lib/errors.js')
let { User, Thread, Notification, Category, Post, Ban, Report, Sequelize } = require('../models')
let pagination = require('../lib/pagination.js')
const rateLimit = require("express-rate-limit");
const postLimiter = rateLimit({
windowMs: 60000,
max: 10,
message: "{\"errors\":[{\"name\":\"rateLimit\",\"message\":\"You may only make 10 requests to this endpoint per minute.\",\"status\":429}]}"
});
router.get('/:thread_id', async (req, res, next) => {
try {
let { from, limit } = pagination.getPaginationProps(req.query)
@ -32,7 +37,7 @@ router.all('*', (req, res, next) => {
}
})
router.post('/', async (req, res, next) => {
router.post('/', postLimiter, async (req, res, next) => {
let validationErrors = []
try {

View File

@ -4,7 +4,12 @@ let router = express.Router()
const Errors = require('../lib/errors')
let { User, userWall, Notification, Ban, Sequelize, sequelize } = require('../models')
let pagination = require('../lib/pagination.js')
const rateLimit = require("express-rate-limit");
const postLimiter = rateLimit({
windowMs: 60000,
max: 10,
message: "{\"errors\":[{\"name\":\"rateLimit\",\"message\":\"You may only make 10 requests to this endpoint per minute.\",\"status\":429}]}"
});
router.get('/show/:username', async (req, res, next) => {
try {
let { limit } = pagination.getPaginationProps(req.query, true)
@ -35,7 +40,7 @@ router.all('*', (req, res, next) => {
}
})
router.post('/post', async (req, res, next) => {
router.post('/post', postLimiter, async (req, res, next) => {
let queryObj = {
attributes: {include: ['emailVerified']},
where: {username: req.session.username}

View File

@ -19,8 +19,6 @@ const crypto = require("crypto")
const cryptoRandomString = require("crypto-random-string")
const rateLimit = require("express-rate-limit");
const moment = require("moment")
const csrf = require('csurf')
const csrfProtection = csrf({ cookie: true })
const emailLimiter = rateLimit({
windowMs: 60000,
max: 1, // limit each IP to 100 requests per windowMs
@ -223,7 +221,7 @@ router.post('/login', async (req, res, next) => {
}
} catch (err) { next(err) }
})
router.post('/recovery/send', async (req, res, next) => {
router.post('/recovery/send', emailLimiter, async (req, res, next) => {
const mailGenerator = new MailGen({
theme: 'salted',
product: {
@ -498,6 +496,20 @@ router.put('/preferences', async (req, res, next) => {
}
})
res.json({ success: true })
} else if(
req.body.username !== undefined &&
req.body.changeUsername !== undefined
) {
let user = await User.findOne({where: {
username: req.session.username
}})
if(user.koins >= 200) {
await user.updateUsername(req.body.username)
} else {
throw Errors.insufficientKoins
}
res.json({ success: true })
} else {
res.json({ success: false })