even more minor changes and reorganizing
This commit is contained in:
parent
e15dc7902c
commit
f3d9435be0
@ -1,6 +1,7 @@
|
||||
import {EmailTemplate} from 'email-templates'
|
||||
import path from 'path'
|
||||
import nodemailer from 'nodemailer'
|
||||
|
||||
import config from '../../scripts/load-config'
|
||||
|
||||
const templateDir = path.join(__dirname, '../../', 'templates')
|
||||
|
@ -1,12 +1,13 @@
|
||||
import qs from 'querystring'
|
||||
import oauth from 'oauth-libre'
|
||||
import uuidV1 from 'uuid/v1'
|
||||
import crypto from 'crypto'
|
||||
|
||||
import config from '../../scripts/load-config'
|
||||
import http from '../../scripts/http'
|
||||
import models from './models'
|
||||
import Image from './image'
|
||||
import UAPI from './index'
|
||||
import qs from 'querystring'
|
||||
import oauth from 'oauth-libre'
|
||||
import uuidV1 from 'uuid/v1'
|
||||
import crypto from 'crypto'
|
||||
|
||||
const userFields = ['username', 'email', 'avatar_file', 'display_name', 'ip_address']
|
||||
|
||||
@ -74,7 +75,7 @@ const API = {
|
||||
udataLimited.username = udataLimited.username.substring(0, 26)
|
||||
|
||||
// Check if the username is already taken
|
||||
if (await UAPI.User.get(udataLimited.username) != null) {
|
||||
if (await UAPI.User.get(udataLimited.username) != null || udataLimited.username.length < 4) {
|
||||
udataLimited.username = udataLimited.username + UAPI.Hash(4)
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
import gm from 'gm'
|
||||
import url from 'url'
|
||||
import path from 'path'
|
||||
import crypto from 'crypto'
|
||||
import Promise from 'bluebird'
|
||||
import uuid from 'uuid/v4'
|
||||
|
||||
import http from '../../scripts/http'
|
||||
|
||||
@ -17,10 +16,6 @@ const imageTypes = {
|
||||
'image/jpeg': '.jpeg'
|
||||
}
|
||||
|
||||
function imageUniquifier () {
|
||||
return crypto.randomBytes(12).toString('hex')
|
||||
}
|
||||
|
||||
function decodeBase64Image (dataString) {
|
||||
let matches = dataString.match(/^data:([A-Za-z-+/]+);base64,(.+)$/)
|
||||
let response = {}
|
||||
@ -60,7 +55,7 @@ async function imageBase64 (baseObj) {
|
||||
if (!imgData) return null
|
||||
if (!imageTypes[imgData.type]) return null
|
||||
|
||||
let imageName = 'base64-' + imageUniquifier()
|
||||
let imageName = 'base64-' + uuid()
|
||||
let ext = imageTypes[imgData.type] || '.png'
|
||||
|
||||
imageName += ext
|
||||
@ -81,7 +76,7 @@ async function downloadImage (imgUrl, designation) {
|
||||
if (!imgUrl) return null
|
||||
if (!designation) designation = 'download'
|
||||
|
||||
let imageName = designation + '-' + imageUniquifier()
|
||||
let imageName = designation + '-' + uuid()
|
||||
let uridata = url.parse(imgUrl)
|
||||
let pathdata = path.parse(uridata.path)
|
||||
|
||||
|
@ -1,15 +1,16 @@
|
||||
import path from 'path'
|
||||
import cprog from 'child_process'
|
||||
import config from '../../scripts/load-config'
|
||||
import http from '../../scripts/http'
|
||||
import models from './models'
|
||||
import crypto from 'crypto'
|
||||
import notp from 'notp'
|
||||
import base32 from 'thirty-two'
|
||||
import emailer from './emailer'
|
||||
import uuidV1 from 'uuid/v1'
|
||||
import fs from 'fs-extra'
|
||||
|
||||
import config from '../../scripts/load-config'
|
||||
import http from '../../scripts/http'
|
||||
import models from './models'
|
||||
import emailer from './emailer'
|
||||
|
||||
const emailRe = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
|
||||
|
||||
// Fork a bcrypt process to hash and compare passwords
|
||||
@ -533,7 +534,6 @@ const API = {
|
||||
console.debug('IPN Verified Notification:', body)
|
||||
}
|
||||
|
||||
// TODO: add database field for this
|
||||
if (body.txn_id) {
|
||||
if (txnStore.indexOf(body.txn_id) !== -1) return true
|
||||
txnStore.push(body.txn_id)
|
||||
|
@ -1,6 +1,7 @@
|
||||
import crypto from 'crypto'
|
||||
|
||||
import API from './index'
|
||||
import Model from './models'
|
||||
import crypto from 'crypto'
|
||||
|
||||
const mAPI = {
|
||||
getToken: async function (user) {
|
||||
|
@ -15,7 +15,7 @@ const args = {
|
||||
|
||||
function spawnWorkers () {
|
||||
let workerCount = config.server.workers === 0 ? cpuCount : config.server.workers
|
||||
console.log('Spinning up ' + workerCount + ' worker process' + (workerCount !== 1 ? 'es' : ''))
|
||||
console.log('Spinning up %d worker process%s', workerCount, (workerCount !== 1 ? 'es' : ''))
|
||||
|
||||
for (let i = 0; i < workerCount; i++) {
|
||||
spawnWorker()
|
||||
@ -68,14 +68,14 @@ function spawnWorker (oldWorker) {
|
||||
w.process.stderr.on('data', (data) => {
|
||||
console.log(w.process.pid, data.toString().trim())
|
||||
})
|
||||
args.verbose && console.log('Starting worker process ' + w.process.pid + '...')
|
||||
args.verbose && console.log('Starting worker process %d...', w.process.pid)
|
||||
|
||||
w.on('message', (message) => {
|
||||
if (message === 'started') {
|
||||
workers.push(w)
|
||||
args.verbose && console.log('Started worker process ' + w.process.pid)
|
||||
args.verbose && console.log('Started worker process', w.process.pid)
|
||||
if (oldWorker) {
|
||||
args.verbose && console.log('Stopping worker process ' + oldWorker.process.pid)
|
||||
args.verbose && console.log('Stopping worker process', oldWorker.process.pid)
|
||||
oldWorker.send('stop')
|
||||
}
|
||||
} else {
|
||||
@ -99,7 +99,7 @@ cluster.setupMaster({
|
||||
cluster.on('exit', (worker, code, signal) => {
|
||||
let extra = ((code || '') + ' ' + (signal || '')).trim()
|
||||
|
||||
console.error('Worker process ' + worker.process.pid + ' exited ' + (extra ? '(' + extra + ')' : ''))
|
||||
console.error('Worker process %d exited %s', worker.process.pid, (extra ? '(' + extra + ')' : ''))
|
||||
|
||||
let index = workers.indexOf(worker)
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
import express from 'express'
|
||||
|
||||
import ensureLogin from '../../scripts/ensureLogin'
|
||||
import wrap from '../../scripts/asyncRoute'
|
||||
import {User} from '../api'
|
||||
import API from '../api/admin'
|
||||
import {User} from '../api'
|
||||
|
||||
const router = express.Router()
|
||||
const apiRouter = express.Router()
|
||||
|
@ -1,12 +1,13 @@
|
||||
import express from 'express'
|
||||
import RateLimit from 'express-rate-limit'
|
||||
import multiparty from 'multiparty'
|
||||
|
||||
import config from '../../scripts/load-config'
|
||||
import wrap from '../../scripts/asyncRoute'
|
||||
import API from '../api'
|
||||
import News from '../api/news'
|
||||
import Image from '../api/image'
|
||||
import APIExtern from '../api/external'
|
||||
import Image from '../api/image'
|
||||
import News from '../api/news'
|
||||
import API from '../api'
|
||||
|
||||
let router = express.Router()
|
||||
let dev = process.env.NODE_ENV !== 'production'
|
||||
|
@ -2,6 +2,7 @@ import fs from 'fs-extra'
|
||||
import path from 'path'
|
||||
import express from 'express'
|
||||
import RateLimit from 'express-rate-limit'
|
||||
|
||||
import ensureLogin from '../../scripts/ensureLogin'
|
||||
import config from '../../scripts/load-config'
|
||||
import wrap from '../../scripts/asyncRoute'
|
||||
@ -78,7 +79,7 @@ router.use(wrap(async (req, res, next) => {
|
||||
}
|
||||
|
||||
// Update user session
|
||||
let udata = await API.User.get(req.session.user.id)
|
||||
let udata = await API.User.get(req.session.user)
|
||||
setSession(req, udata)
|
||||
|
||||
// Update IP address
|
||||
@ -158,6 +159,7 @@ router.get('/reset/:token', wrap(async (req, res) => {
|
||||
|
||||
router.get('/login', extraButtons, (req, res) => {
|
||||
if (req.session.user) return redirectLogin(req, res)
|
||||
|
||||
if (req.query.returnTo) {
|
||||
req.session.redirectUri = req.query.returnTo
|
||||
}
|
||||
@ -175,6 +177,21 @@ router.get('/register', extraButtons, formKeep, (req, res) => {
|
||||
res.render('user/register')
|
||||
})
|
||||
|
||||
// User activation endpoint (emailed link)
|
||||
router.get('/activate/:token', wrap(async (req, res) => {
|
||||
if (req.session.user) return res.redirect('/login')
|
||||
let token = req.params.token
|
||||
let success = await API.User.Login.activationToken(token)
|
||||
|
||||
if (!success) {
|
||||
req.flash('message', {error: true, text: 'Invalid or expired activation token.'})
|
||||
} else {
|
||||
req.flash('message', {error: false, text: 'Your account has been activated! You may now log in.'})
|
||||
}
|
||||
|
||||
res.redirect('/login')
|
||||
}))
|
||||
|
||||
// View for enabling Two-Factor Authentication
|
||||
router.get('/user/two-factor', ensureLogin, wrap(async (req, res) => {
|
||||
let twoFaEnabled = await API.User.Login.totpTokenRequired(req.session.user)
|
||||
@ -291,9 +308,11 @@ function formError (req, res, error, redirect) {
|
||||
// Make sure characters are UTF-8
|
||||
function cleanString (input) {
|
||||
let output = ''
|
||||
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
output += input.charCodeAt(i) <= 127 ? input.charAt(i) : ''
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
@ -309,6 +328,7 @@ function csrfValidation (req, res, next) {
|
||||
// Enabling 2fa
|
||||
router.post('/user/two-factor', csrfValidation, wrap(async (req, res, next) => {
|
||||
if (!req.session.user) return next()
|
||||
|
||||
if (!req.body.code) {
|
||||
return formError(req, res, 'You need to enter the code.')
|
||||
}
|
||||
@ -340,7 +360,9 @@ router.post('/user/two-factor/disable', csrfValidation, wrap(async (req, res, ne
|
||||
// Verify 2FA for login
|
||||
router.post('/login/verify', csrfValidation, wrap(async (req, res, next) => {
|
||||
if (req.session.user) return next()
|
||||
|
||||
if (req.session.totp_check === null) return res.redirect('/login')
|
||||
|
||||
if (!req.body.code && !req.body.recovery) {
|
||||
return formError(req, res, 'You need to enter the code.')
|
||||
}
|
||||
@ -360,6 +382,7 @@ router.post('/login/verify', csrfValidation, wrap(async (req, res, next) => {
|
||||
// Log the user in. Limited resource
|
||||
router.post('/login', accountLimiter, csrfValidation, wrap(async (req, res, next) => {
|
||||
if (req.session.user) return next()
|
||||
|
||||
if (!req.body.username || !req.body.password || req.body.username === '') {
|
||||
return res.redirect('/login')
|
||||
}
|
||||
@ -373,6 +396,7 @@ router.post('/login', accountLimiter, csrfValidation, wrap(async (req, res, next
|
||||
if (!pwMatch) return formError(req, res, 'Invalid username or password.')
|
||||
|
||||
if (user.activated === 0) return formError(req, res, 'Please activate your account first.')
|
||||
|
||||
if (user.locked === 1) return formError(req, res, 'This account has been locked.')
|
||||
|
||||
// Check if the user is banned
|
||||
@ -407,6 +431,7 @@ router.post('/login', accountLimiter, csrfValidation, wrap(async (req, res, next
|
||||
// Password reset
|
||||
router.post('/login/reset', accountLimiter, csrfValidation, wrap(async (req, res, next) => {
|
||||
if (req.session.user) return next()
|
||||
|
||||
if (!req.body.email) {
|
||||
return formError(req, res, 'You need to enter your email address.')
|
||||
}
|
||||
@ -420,7 +445,7 @@ router.post('/login/reset', accountLimiter, csrfValidation, wrap(async (req, res
|
||||
try {
|
||||
await API.User.Reset.reset(email)
|
||||
|
||||
req.flash('message', {error: false, text: 'We\'ve sent a link to your email address. Please check spam folders too!'})
|
||||
req.flash('message', {error: false, text: 'We\'ve sent a link to your email address. Please check spam folders, too!'})
|
||||
res.redirect('/login/reset?success=true')
|
||||
} catch (e) {
|
||||
return formError(req, res, e.message)
|
||||
@ -466,6 +491,7 @@ router.post('/reset/:token', csrfValidation, wrap(async (req, res) => {
|
||||
// Protected & Limited resource: Account registration
|
||||
router.post('/register', accountLimiter, csrfValidation, wrap(async (req, res, next) => {
|
||||
if (req.session.user) return next()
|
||||
|
||||
if (!req.body.username || !req.body.display_name || !req.body.password || !req.body.email) {
|
||||
return formError(req, res, 'Please fill in all the fields.')
|
||||
}
|
||||
@ -563,7 +589,7 @@ router.post('/user/manage', csrfValidation, wrap(async (req, res, next) => {
|
||||
|
||||
let displayName = req.body.display_name
|
||||
if (!displayName || !displayName.match(/^([^\\`]{3,32})$/i)) {
|
||||
return formError(req, res, 'Invalid display name!')
|
||||
return formError(req, res, 'Invalid Display Name!')
|
||||
}
|
||||
|
||||
displayName = cleanString(displayName)
|
||||
@ -680,7 +706,6 @@ router.post('/user/manage/email', accountLimiter, csrfValidation, wrap(async (re
|
||||
return formError(req, res, e.message)
|
||||
}
|
||||
|
||||
// TODO: Send necessary emails
|
||||
console.warn('[SECURITY AUDIT] User \'%s\' email has been changed from %s', user.username, req.realIP)
|
||||
|
||||
req.session.user.email = newEmail
|
||||
@ -790,21 +815,6 @@ router.get('/logout', (req, res) => {
|
||||
res.redirect('/')
|
||||
})
|
||||
|
||||
// User activation endpoint (emailed link)
|
||||
router.get('/activate/:token', wrap(async (req, res) => {
|
||||
if (req.session.user) return res.redirect('/login')
|
||||
let token = req.params.token
|
||||
let success = await API.User.Login.activationToken(token)
|
||||
|
||||
if (!success) {
|
||||
req.flash('message', {error: true, text: 'Invalid or expired activation token.'})
|
||||
} else {
|
||||
req.flash('message', {error: false, text: 'Your account has been activated! You may now log in.'})
|
||||
}
|
||||
|
||||
res.redirect('/login')
|
||||
}))
|
||||
|
||||
router.use('/api', apiRouter)
|
||||
router.use('/admin', adminRouter)
|
||||
router.use('/mc', mcRouter)
|
||||
|
@ -1,4 +1,5 @@
|
||||
import express from 'express'
|
||||
|
||||
import ensureLogin from '../../scripts/ensureLogin'
|
||||
import wrap from '../../scripts/asyncRoute'
|
||||
import Minecraft from '../api/minecraft'
|
||||
|
@ -1,5 +1,6 @@
|
||||
import express from 'express'
|
||||
import uapi from '../api'
|
||||
|
||||
import UAPI from '../api'
|
||||
import OAuth2 from '../api/oauth2'
|
||||
import RateLimit from 'express-rate-limit'
|
||||
import wrap from '../../scripts/asyncRoute'
|
||||
@ -31,7 +32,7 @@ router.post('/introspect', oauth.controller.introspection)
|
||||
// Protected user information resource
|
||||
router.get('/user', oauth.bearer, wrap(async (req, res) => {
|
||||
let accessToken = req.oauth2.accessToken
|
||||
let user = await uapi.User.get(accessToken.user_id)
|
||||
let user = await UAPI.User.get(accessToken.user_id)
|
||||
|
||||
if (!user) {
|
||||
return res.status(404).jsonp({
|
||||
|
@ -68,7 +68,7 @@ module.exports = (args) => {
|
||||
app.set('views', path.join(__dirname, '../views'))
|
||||
|
||||
if (args.dev) {
|
||||
console.log('Worker is in development mode')
|
||||
console.warn('Worker is in development mode')
|
||||
|
||||
// Dev logger
|
||||
const morgan = require('morgan')
|
||||
|
Reference in New Issue
Block a user