Maintenance commit.

This commit is contained in:
Evert Prants 2020-05-28 21:30:21 +03:00
parent f608316e89
commit 787cc6fc73
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
42 changed files with 4242 additions and 4093 deletions

View File

@ -6,7 +6,7 @@ if (process.argv.indexOf('-d') === -1 && process.argv.indexOf('--development') =
}
require('@babel/register')({
plugins: [ '@babel/plugin-transform-modules-commonjs' ]
plugins: ['@babel/plugin-transform-modules-commonjs']
})
require(path.join(__dirname, 'server'))

7242
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -30,58 +30,58 @@
},
"homepage": "https://icynet.eu",
"dependencies": {
"@babel/plugin-transform-modules-commonjs": "^7.8.3",
"@babel/register": "^7.8.3",
"@babel/plugin-transform-modules-commonjs": "^7.10.1",
"@babel/register": "^7.10.1",
"bcryptjs": "^2.4.3",
"bluebird": "^3.7.2",
"body-parser": "^1.19.0",
"connect-redis": "^3.4.2",
"connect-session-knex": "^1.5.0",
"email-templates": "^2.7.1",
"connect-redis": "^4.0.4",
"connect-session-knex": "^1.6.0",
"email-templates": "^7.0.5",
"express": "^4.17.1",
"express-rate-limit": "^2.14.2",
"express-session": "^1.17.0",
"feed": "^1.1.1",
"fs-extra": "^4.0.3",
"express-rate-limit": "^5.1.3",
"express-session": "^1.17.1",
"feed": "^4.2.0",
"fs-extra": "^9.0.0",
"gm": "^1.23.1",
"knex": "^0.14.6",
"knex": "^0.21.1",
"multiparty": "^4.2.1",
"mysql": "^2.18.1",
"nodemailer": "^4.7.0",
"nodemailer": "^6.4.8",
"notp": "^2.0.3",
"oauth-libre": "^0.9.17",
"objection": "^0.8.9",
"redis": "^2.8.0",
"objection": "^2.1.5",
"redis": "^3.0.2",
"serve-favicon": "^2.5.0",
"stylus": "^0.54.7",
"thirty-two": "^1.0.2",
"toml": "^2.3.6",
"uuid": "^3.4.0",
"toml": "^3.0.0",
"uuid": "^8.1.0",
"vue": "^2.6.11"
},
"devDependencies": {
"@babel/core": "^7.8.3",
"@babel/preset-env": "^7.8.3",
"babel-loader": "^8.0.6",
"bootstrap": "^4.4.1",
"concurrently": "^5.1.0",
"eslint-plugin-import": "^2.20.0",
"jquery": "^3.4.1",
"morgan": "^1.9.1",
"mustache": "^2.3.2",
"@babel/core": "^7.10.1",
"@babel/preset-env": "^7.10.1",
"babel-loader": "^8.1.0",
"bootstrap": "^4.5.0",
"concurrently": "^5.2.0",
"eslint-plugin-import": "^2.20.2",
"jquery": "^3.5.1",
"morgan": "^1.10.0",
"mustache": "^4.0.1",
"popper.js": "^1.16.1",
"pug": "^2.0.4",
"pug": "^3.0.0",
"pug-plain-loader": "^1.0.0",
"standard": "^10.0.3",
"terser-webpack-plugin": "^2.3.3",
"standard": "^14.3.4",
"terser-webpack-plugin": "^3.0.2",
"vue-clickaway": "^2.2.2",
"vue-loader": "^15.8.3",
"vue-loader": "^15.9.2",
"vue-resource": "^1.5.1",
"vue-router": "^3.1.5",
"vue-router": "^3.3.1",
"vue-template-compiler": "^2.6.11",
"watch": "^1.0.2",
"webpack": "^4.41.5",
"webpack-cli": "^3.3.10",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11",
"webpack-merge": "^4.2.2"
},
"standard": {

View File

@ -8,7 +8,7 @@ const format = util.format
module.exports = function (options) {
options = options || {}
let safe = (options.unsafe === undefined) ? true : !options.unsafe
const safe = (options.unsafe === undefined) ? true : !options.unsafe
return function (req, res, next) {
if (req.flash && safe) { return next() }
@ -20,10 +20,10 @@ module.exports = function (options) {
function _flash (type, msg) {
if (this.session === undefined) throw Error('req.flash() requires sessions')
let msgs = this.session.flash = this.session.flash || {}
const msgs = this.session.flash = this.session.flash || {}
if (type && msg) {
if (arguments.length > 2 && format) {
let args = Array.prototype.slice.call(arguments, 1)
const args = Array.prototype.slice.call(arguments, 1)
msg = format.apply(undefined, args)
} else if (Array.isArray(msg)) {
msg.forEach((val) => {
@ -33,7 +33,7 @@ function _flash (type, msg) {
}
return (msgs[type] = msgs[type] || []).push(msg)
} else if (type) {
let arr = msgs[type]
const arr = msgs[type]
delete msgs[type]
return arr || []
} else {

View File

@ -1,17 +1,17 @@
import url from 'url'
import { URL } from 'url'
import qs from 'querystring'
import fs from 'fs'
function HTTP_GET (link, headers = {}, lback) {
if (lback && lback >= 4) throw new Error('infinite loop!') // Prevent infinite loop requests
let parsed = url.parse(link)
let opts = {
const parsed = new URL(link)
const opts = {
host: parsed.hostname,
port: parsed.port,
path: parsed.path,
headers: {
'User-Agent': 'Icy Network Back-end (icynet.eu)',
'Accept': '*/*',
Accept: '*/*',
'Accept-Language': 'en-GB,enq=0.5'
}
}
@ -22,9 +22,9 @@ function HTTP_GET (link, headers = {}, lback) {
let reqTimeOut
let httpModule = parsed.protocol === 'https:' ? require('https') : require('http')
const httpModule = parsed.protocol === 'https:' ? require('https') : require('http')
return new Promise((resolve, reject) => {
let req = httpModule.get(opts, (res) => {
const req = httpModule.get(opts, (res) => {
if (res.statusCode === 302 || res.statusCode === 301) {
if (!lback) {
lback = 1
@ -61,10 +61,10 @@ function HTTP_GET (link, headers = {}, lback) {
}
function HTTP_POST (link, headers = {}, data) {
let parsed = url.parse(link)
const parsed = new URL(link)
let postData = qs.stringify(data)
let opts = {
const opts = {
host: parsed.host,
port: parsed.port,
path: parsed.path,
@ -85,8 +85,8 @@ function HTTP_POST (link, headers = {}, data) {
}
return new Promise((resolve, reject) => {
let httpModule = parsed.protocol === 'https:' ? require('https') : require('http')
let req = httpModule.request(opts, (res) => {
const httpModule = parsed.protocol === 'https:' ? require('https') : require('http')
const req = httpModule.request(opts, (res) => {
res.setEncoding('utf8')
let data = ''
@ -108,8 +108,8 @@ function HTTP_POST (link, headers = {}, data) {
async function Download (url, dest) {
return new Promise((resolve, reject) => {
let file = fs.createWriteStream(dest)
let protocol = url.indexOf('https:') === 0 ? require('https') : require('http')
const file = fs.createWriteStream(dest)
const protocol = url.indexOf('https:') === 0 ? require('https') : require('http')
protocol.get(url, function (response) {
response.pipe(file)
file.on('finish', function () {

View File

@ -3,8 +3,8 @@ const knex = require('knex')
const objection = require('objection')
const knexfile = require(path.join(__dirname, '../knexfile'))
let knexDB = knex(knexfile)
let objectionModel = objection.Model
const knexDB = knex(knexfile)
const objectionModel = objection.Model
objectionModel.knex(knexDB)

View File

@ -20,11 +20,12 @@ function dateFormat (date) {
// Console.log/error/warn "middleware" - add timestamp and write to file
function stampAndWrite (fnc, color, prfx, message) {
let prefix = '[' + prfx + '] [' + dateFormat(new Date()) + '] '
const prefix = '[' + prfx + '] [' + dateFormat(new Date()) + '] '
message = color + prefix + message + ((color && color !== '') ? '\x1b[0m' : '')
message = message.replace(/\\u001b/g, '\x1b')
if (lfs) {
// eslint-disable-next-line no-control-regex
lfs.write(message.replace(/(\u001b\[\d\d?m)/g, '') + '\n')
}
@ -34,24 +35,24 @@ function stampAndWrite (fnc, color, prfx, message) {
// Reassign logger functions and send them to the "middleware"
const realConsoleLog = console.log
console.log = function () {
let message = util.format.apply(null, arguments)
const message = util.format.apply(null, arguments)
stampAndWrite.call(this, realConsoleLog, '', 'info', message)
}
const realConsoleWarn = console.warn
console.warn = function () {
let message = util.format.apply(null, arguments)
const message = util.format.apply(null, arguments)
stampAndWrite.call(this, realConsoleWarn, '\x1b[33m', 'warn', message)
}
const realConsoleError = console.error
console.error = function () {
let message = util.format.apply(null, arguments)
const message = util.format.apply(null, arguments)
stampAndWrite.call(this, realConsoleError, '\x1b[31m', ' err', message)
}
async function initializeLogger () {
let logPath = path.resolve(config.logger.file)
const logPath = path.resolve(config.logger.file)
// Only throw bad permission errors
try {
@ -61,7 +62,7 @@ async function initializeLogger () {
}
try {
lfs = fs.createWriteStream(logPath, {flags: 'a'})
lfs = fs.createWriteStream(logPath, { flags: 'a' })
} catch (e) {
lfs = null
console.error('Failed to initiate log file write stream')

View File

@ -4,7 +4,7 @@ import Models from './models'
const perPage = 6
async function cleanUserObject (dbe, admin) {
let totp = await Users.User.Login.totpTokenRequired(dbe)
const totp = await Users.User.Login.totpTokenRequired(dbe)
return {
id: dbe.id,
@ -25,7 +25,7 @@ async function cleanUserObject (dbe, admin) {
}
async function cleanClientObject (dbe) {
let user = await Users.User.get(dbe.user_id)
const user = await Users.User.get(dbe.user_id)
return {
id: dbe.id,
title: dbe.title,
@ -46,8 +46,8 @@ async function cleanClientObject (dbe) {
}
async function cleanBanObject (dbe) {
let user = await Users.User.get(dbe.user_id)
let admin = await Users.User.get(dbe.admin_id)
const user = await Users.User.get(dbe.user_id)
const admin = await Users.User.get(dbe.admin_id)
return {
id: dbe.id,
reason: dbe.reason,
@ -68,14 +68,14 @@ async function cleanBanObject (dbe) {
function dataFilter (data, fields, optional = []) {
// Remove keys not listed in `fields`
for (let i in data) {
for (const i in data) {
if (fields.indexOf(i) === -1) {
delete data[i]
}
}
// Ensure all the entries in `fields` are present as keys in `data` or are `optional`
for (let j in fields) {
for (const j in fields) {
if (!data[fields[j]] && optional.indexOf(fields[j]) === -1) return null
}
@ -86,18 +86,18 @@ const API = {
// List all users (paginated)
getAllUsers: async function (page, adminId) {
let count = await Models.User.query().count('id as ids')
if (!count.length || !count[0]['ids'] || isNaN(page)) {
if (!count.length || !count[0].ids || isNaN(page)) {
return { error: 'No users found in database' }
}
count = count[0].ids
let paginated = Users.Pagination(perPage, parseInt(count), page)
let raw = await Models.User.query().offset(paginated.offset).limit(perPage)
let admin = await Users.User.get(adminId)
const paginated = Users.Pagination(perPage, parseInt(count), page)
const raw = await Models.User.query().offset(paginated.offset).limit(perPage)
const admin = await Users.User.get(adminId)
let users = []
for (let i in raw) {
let entry = raw[i]
const users = []
for (const i in raw) {
const entry = raw[i]
users.push(await cleanUserObject(entry, admin))
}
@ -108,16 +108,16 @@ const API = {
}
},
getUser: async function (id) {
let user = await Users.User.get(id)
const user = await Users.User.get(id)
if (!user) throw new Error('No such user')
return cleanUserObject(user, null)
},
editUser: async function (id, data) {
let user = await Users.User.get(id)
const user = await Users.User.get(id)
if (!user) throw new Error('No such user')
let fields = [
const fields = [
'username', 'display_name', 'email', 'nw_privilege', 'activated'
]
@ -129,7 +129,7 @@ const API = {
return {}
},
resendActivationEmail: async function (id) {
let user = await Users.User.get(id)
const user = await Users.User.get(id)
if (!user) throw new Error('No such user')
if (user.activated === 1) return {}
@ -139,7 +139,7 @@ const API = {
return {}
},
revokeTotpToken: async function (id) {
let user = await Users.User.get(id)
const user = await Users.User.get(id)
if (!user) throw new Error('No such user')
await Models.TotpToken.query().delete().where('user_id', user.id)
@ -147,12 +147,12 @@ const API = {
return {}
},
sendPasswordEmail: async function (id) {
let user = await Users.User.get(id)
const user = await Users.User.get(id)
if (!user) throw new Error('No such user')
let token = await Users.User.Reset.reset(user.email, false, true)
const token = await Users.User.Reset.reset(user.email, false, true)
return {token}
return { token }
},
// Search for users by terms and fields
searchUsers: async function (terms, fields = ['email']) {
@ -167,12 +167,12 @@ const API = {
}
}
let rows = await qb.limit(8)
const rows = await qb.limit(8)
if (!rows.length) return { error: 'No results' }
let cleaned = []
for (let i in rows) {
let userRaw = rows[i]
const cleaned = []
for (const i in rows) {
const userRaw = rows[i]
cleaned.push(await cleanUserObject(userRaw, null))
}
@ -181,17 +181,17 @@ const API = {
// List all clients (paginated)
getAllClients: async function (page) {
let count = await Models.OAuth2Client.query().count('id as ids')
if (!count.length || !count[0]['ids'] || isNaN(page)) {
if (!count.length || !count[0].ids || isNaN(page)) {
return { error: 'No clients' }
}
count = count[0].ids
let paginated = Users.Pagination(perPage, parseInt(count), page)
let raw = await Models.OAuth2Client.query().offset(paginated.offset).limit(perPage)
const paginated = Users.Pagination(perPage, parseInt(count), page)
const raw = await Models.OAuth2Client.query().offset(paginated.offset).limit(perPage)
let clients = []
for (let i in raw) {
let entry = raw[i]
const clients = []
for (const i in raw) {
const entry = raw[i]
clients.push(await cleanClientObject(entry))
}
@ -202,14 +202,14 @@ const API = {
},
// Get information about a client via id
getClient: async function (id) {
let raw = await Models.OAuth2Client.query().where('id', id)
const raw = await Models.OAuth2Client.query().where('id', id)
if (!raw.length) throw new Error('No such client')
return cleanClientObject(raw[0])
},
// Update a client `id` in database with `data`
updateClient: async function (id, data) {
let fields = [
const fields = [
'title', 'description', 'url', 'redirect_url', 'scope', 'verified'
]
@ -228,10 +228,10 @@ const API = {
// Create a new secret for a client
newSecret: async function (id) {
if (isNaN(id)) throw new Error('Invalid client ID')
let secret = Users.Hash(16)
const secret = Users.Hash(16)
try {
await Models.OAuth2Client.query().patchAndFetchById(id, {secret: secret})
await Models.OAuth2Client.query().patchAndFetchById(id, { secret: secret })
} catch (e) {
throw new Error('No such client')
}
@ -240,14 +240,14 @@ const API = {
},
// Create a new client
createClient: async function (data, user) {
let fields = [
const fields = [
'title', 'description', 'url', 'redirect_url', 'scope'
]
data = dataFilter(data, fields, ['scope'])
if (!data) throw new Error('Missing fields')
let obj = Object.assign({
const obj = Object.assign({
secret: Users.Hash(16),
grants: 'authorization_code',
created_at: new Date(),
@ -268,17 +268,17 @@ const API = {
// List all bans (paginated)
getAllBans: async function (page) {
let count = await Models.Ban.query().count('id as ids')
if (!count.length || !count[0]['ids'] || isNaN(page)) {
if (!count.length || !count[0].ids || isNaN(page)) {
return { error: 'No bans on record' }
}
count = count[0].ids
let paginated = Users.Pagination(perPage, parseInt(count), page)
let raw = await Models.Ban.query().offset(paginated.offset).limit(perPage)
const paginated = Users.Pagination(perPage, parseInt(count), page)
const raw = await Models.Ban.query().offset(paginated.offset).limit(perPage)
let bans = []
for (let i in raw) {
let entry = raw[i]
const bans = []
for (const i in raw) {
const entry = raw[i]
bans.push(await cleanBanObject(entry))
}
@ -293,16 +293,16 @@ const API = {
},
// Create a ban
addBan: async function (data, adminId) {
let user = await Users.User.get(parseInt(data.user_id))
const user = await Users.User.get(parseInt(data.user_id))
if (!user) throw new Error('No such user.')
if (user.id === adminId) throw new Error('Cannot ban yourself!')
let admin = await Users.User.get(adminId)
const admin = await Users.User.get(adminId)
if (user.nw_privilege > admin.nw_privilege) throw new Error('Cannot ban user.')
let banAdd = {
const banAdd = {
reason: data.reason || 'Unspecified ban',
admin_id: adminId,
user_id: user.id,
@ -315,13 +315,13 @@ const API = {
return {}
},
lockAccount: async function (userId) {
let user = await Users.User.get(userId)
const user = await Users.User.get(userId)
if (user.id === 1 || user.nw_privilege > 2) {
throw new Error('Cannot lock this user.')
}
let lockId = Users.Hash(4)
let userObf = {
const lockId = Users.Hash(4)
const userObf = {
username: lockId,
display_name: user.username,
email: `${lockId}@icynet.eu`,

View File

@ -1,4 +1,4 @@
import {EmailTemplate} from 'email-templates'
import { EmailTemplate } from 'email-templates'
import path from 'path'
import nodemailer from 'nodemailer'
@ -10,7 +10,7 @@ tls.DEFAULT_ECDH_CURVE = 'auto'
const templateDir = path.join(__dirname, '../../', 'templates')
let templateCache = {}
const templateCache = {}
let transporter
// Send an email to `email` with `headers`
@ -42,7 +42,7 @@ async function pushMail (template, email, context) {
templ = templateCache[template]
}
let result = await templ.render(context)
const result = await templ.render(context)
console.debug('Mail being sent: %s to %s', template, email)

View File

@ -1,6 +1,6 @@
import qs from 'querystring'
import oauth from 'oauth-libre'
import uuidV1 from 'uuid/v1'
import { v1 as uuidV1 } from 'uuid'
import crypto from 'crypto'
import config from '../../scripts/load-config'
@ -18,7 +18,7 @@ const API = {
Common: {
// Generate a hash based on the current session
stateGenerator: (req) => {
let sessionCrypto = req.session.id + ':' + config.server.session_secret
const sessionCrypto = req.session.id + ':' + config.server.session_secret
return crypto.createHash('sha256').update(sessionCrypto).digest('hex')
},
// Find an user with an external ID
@ -29,7 +29,7 @@ const API = {
extr.user = null
if (extr.user_id !== null) {
let user = await UAPI.User.get(extr.user_id)
const user = await UAPI.User.get(extr.user_id)
if (user) {
extr.user = user
}
@ -39,12 +39,12 @@ const API = {
},
// Get user ban status
getBan: async (user, ipAddress) => {
let banList = await UAPI.User.getBanStatus(ipAddress || user.id, ipAddress != null)
const banList = await UAPI.User.getBanStatus(ipAddress || user.id, ipAddress != null)
return banList
},
// Create a new `external` instance for a user
new: async (service, identifier, user) => {
let data = {
const data = {
user_id: user.id,
service: service,
identifier: identifier,
@ -57,7 +57,7 @@ const API = {
// Create a new user
newUser: async (service, identifier, data) => {
if (config.external.registrations !== true) throw new Error('Registrations from third-party websites are not allowed.')
let udataLimited = Object.assign({
const udataLimited = Object.assign({
activated: 1,
created_at: new Date(),
updated_at: new Date(),
@ -83,14 +83,14 @@ const API = {
// Check if the email given to us is already registered, if so,
// tell them to log in first.
if (udataLimited.email && udataLimited.email !== '') {
let getByEmail = await UAPI.User.get(udataLimited.email)
const getByEmail = await UAPI.User.get(udataLimited.email)
if (getByEmail) {
throw new Error('An user with this email address is already registered, but this external account is are not linked. If you wish to link the account, please log in first.')
}
}
// Create a new user based on the information we got from an external service
let newUser = await models.User.query().insert(udataLimited)
const newUser = await models.User.query().insert(udataLimited)
await API.Common.new(service, identifier, newUser)
return newUser
@ -98,7 +98,7 @@ const API = {
// Remove an `external` object (thus unlinking from a service)
remove: async (user, service) => {
user = await UAPI.User.ensureObject(user, ['password'])
let userExterns = await models.External.query().orderBy('created_at', 'asc').where('user_id', user.id)
const userExterns = await models.External.query().orderBy('created_at', 'asc').where('user_id', user.id)
if (!userExterns.length) {
return false
@ -113,30 +113,30 @@ const API = {
},
// Common code for all auth callbacks
callback: async (identifier, uid, user, ipAddress, remoteData, avatarFunc) => {
let exists = await API.Common.getExternal(identifier, uid)
const exists = await API.Common.getExternal(identifier, uid)
if (user) {
// Get bans for user
let bans = await API.Common.getBan(user)
const bans = await API.Common.getBan(user)
if (bans.length) return { banned: bans, ip: false }
if (exists) return {error: null, user: user}
if (exists) return { error: null, user: user }
await API.Common.new(identifier, uid, user)
return {error: null, user: user}
return { error: null, user: user }
}
// Callback succeeded with user id and the external table exists, we log in the user
if (exists) {
// Get bans for user
let bans = await API.Common.getBan(exists.user)
const bans = await API.Common.getBan(exists.user)
if (bans.length) return { banned: bans, ip: false }
return {error: null, user: exists.user}
return { error: null, user: exists.user }
}
// Get bans for IP address
let bans = await API.Common.getBan(null, ipAddress)
const bans = await API.Common.getBan(null, ipAddress)
if (bans.length) return { banned: bans, ip: true }
// Run the function for avatar fetching
@ -146,14 +146,14 @@ const API = {
}
// Assign the data
let newUData = Object.assign({
const newUData = Object.assign({
email: remoteData.email || '',
avatar_file: avatar,
ip_address: ipAddress
}, remoteData)
// Remove unnecessary fields
for (let i in newUData) {
for (const i in newUData) {
if (userFields.indexOf(i) === -1) {
delete newUData[i]
}
@ -163,10 +163,10 @@ const API = {
try {
newUser = await API.Common.newUser(identifier, uid, newUData)
} catch (e) {
return {error: e.message}
return { error: e.message }
}
return {error: null, user: newUser}
return { error: null, user: newUser }
}
},
Facebook: {
@ -175,7 +175,7 @@ const API = {
if (rawData.picture) {
if (rawData.picture.is_silhouette === false && rawData.picture.url) {
let imgdata = await Image.downloadImage(rawData.picture.url)
const imgdata = await Image.downloadImage(rawData.picture.url)
if (imgdata && imgdata.fileName) {
profilepic = imgdata.fileName
}
@ -186,17 +186,17 @@ const API = {
},
callback: async (user, authResponse, ipAddress) => {
if (!authResponse) {
return {error: 'No Authorization'}
return { error: 'No Authorization' }
}
let uid = authResponse.userID
const uid = authResponse.userID
if (!uid) {
return {error: 'No Authorization'}
return { error: 'No Authorization' }
}
// Get facebook user information in order to create a new user or verify
let fbdata
let intel = {
const intel = {
access_token: authResponse.accessToken,
fields: 'name,email,picture,short_name'
}
@ -205,14 +205,14 @@ const API = {
fbdata = await http.GET('https://graph.facebook.com/v2.10/' + uid + '?' + qs.stringify(intel))
fbdata = JSON.parse(fbdata)
} catch (e) {
return {error: 'Could not get user information', errorObject: e}
return { error: 'Could not get user information', errorObject: e }
}
if (fbdata.error) {
return {error: fbdata.error.message}
return { error: fbdata.error.message }
}
let cleanedData = Object.assign(fbdata, {
const cleanedData = Object.assign(fbdata, {
username: fbdata.short_name || 'FB' + UAPI.Hash(4),
display_name: fbdata.name,
email: fbdata.email || ''
@ -226,7 +226,7 @@ const API = {
let profilepic = null
if (rawData.profile_image_url_https) {
let imgdata = await Image.downloadImage(rawData.profile_image_url_https)
const imgdata = await Image.downloadImage(rawData.profile_image_url_https)
if (imgdata && imgdata.fileName) {
profilepic = imgdata.fileName
}
@ -236,7 +236,7 @@ const API = {
},
oauthApp: function () {
if (!twitterApp) {
let redirectUri = config.server.domain + '/api/external/twitter/callback'
const redirectUri = config.server.domain + '/api/external/twitter/callback'
twitterApp = new oauth.PromiseOAuth(
'https://api.twitter.com/oauth/request_token',
'https://api.twitter.com/oauth/access_token',
@ -256,12 +256,12 @@ const API = {
tokens = await twitterApp.getOAuthRequestToken()
} catch (e) {
console.error(e)
return {error: 'No tokens returned'}
return { error: 'No tokens returned' }
}
if (tokens[2].oauth_callback_confirmed !== 'true') return {error: 'No tokens returned.'}
if (tokens[2].oauth_callback_confirmed !== 'true') return { error: 'No tokens returned.' }
return {error: null, token: tokens[0], token_secret: tokens[1]}
return { error: null, token: tokens[0], token_secret: tokens[1] }
},
getAccessTokens: async function (token, secret, verifier) {
if (!twitterApp) API.Twitter.oauthApp()
@ -271,28 +271,28 @@ const API = {
tokens = await twitterApp.getOAuthAccessToken(token, secret, verifier)
} catch (e) {
console.error(e)
return {error: 'No tokens returned'}
return { error: 'No tokens returned' }
}
if (!tokens || !tokens.length) return {error: 'No tokens returned'}
if (!tokens || !tokens.length) return { error: 'No tokens returned' }
return {error: null, access_token: tokens[0], access_token_secret: tokens[1]}
return { error: null, access_token: tokens[0], access_token_secret: tokens[1] }
},
callback: async function (user, accessTokens, ipAddress) {
if (!twitterApp) API.Twitter.oauthApp()
let twdata
try {
let resp = await twitterApp.get('https://api.twitter.com/1.1/account/verify_credentials.json?include_email=true',
const resp = await twitterApp.get('https://api.twitter.com/1.1/account/verify_credentials.json?include_email=true',
accessTokens.access_token, accessTokens.access_token_secret)
twdata = JSON.parse(resp[0])
} catch (e) {
console.error(e)
return {error: 'Failed to verify user credentials.'}
return { error: 'Failed to verify user credentials.' }
}
let uid = twdata.id_str
const uid = twdata.id_str
let cleanedData = Object.assign(twdata, {
const cleanedData = Object.assign(twdata, {
username: twdata.screen_name,
display_name: twdata.name,
email: twdata.email || ''
@ -305,7 +305,7 @@ const API = {
getAvatar: async (rawData) => {
let profilepic = null
if (rawData.image) {
let imgdata = await Image.downloadImage(rawData.image)
const imgdata = await Image.downloadImage(rawData.image)
if (imgdata && imgdata.fileName) {
profilepic = imgdata.fileName
}
@ -317,10 +317,10 @@ const API = {
let uid
try {
let test = await http.GET('https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=' + data.id_token)
const test = await http.GET('https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=' + data.id_token)
if (!test) throw new Error('No response!')
let jsondata = JSON.parse(test)
const jsondata = JSON.parse(test)
if (!jsondata || !jsondata.email || !jsondata.name) throw new Error('Please allow Basic Profile and Email.')
if (jsondata.email !== data.email || jsondata.name !== data.name) throw new Error('Conflicting data. Please try again!')
@ -329,10 +329,10 @@ const API = {
uid = jsondata.sub
} catch (e) {
return {error: e.message}
return { error: e.message }
}
let cleanedData = Object.assign(data, {
const cleanedData = Object.assign(data, {
username: data.name,
display_name: data.name,
email: data.email || ''
@ -344,10 +344,10 @@ const API = {
Discord: {
getAvatar: async (rawData) => {
let profilepic = null
let aviSnowflake = rawData.avatar
const aviSnowflake = rawData.avatar
if (aviSnowflake) {
try {
let avpt = await Image.downloadImage('https://cdn.discordapp.com/avatars/' + rawData.id + '/' + aviSnowflake + '.png')
const avpt = await Image.downloadImage('https://cdn.discordapp.com/avatars/' + rawData.id + '/' + aviSnowflake + '.png')
if (avpt && avpt.fileName) {
profilepic = avpt.fileName
}
@ -372,54 +372,54 @@ const API = {
},
getAuthorizeURL: function (req) {
if (!discordApp) API.Discord.oauth2App()
let state = API.Common.stateGenerator(req)
let redirectUri = config.server.domain + '/api/external/discord/callback'
const state = API.Common.stateGenerator(req)
const redirectUri = config.server.domain + '/api/external/discord/callback'
const params = {
'client_id': config.external.discord.api,
'redirect_uri': redirectUri,
'scope': 'identify email',
'response_type': 'code',
'state': state
client_id: config.external.discord.api,
redirect_uri: redirectUri,
scope: 'identify email',
response_type: 'code',
state: state
}
let url = discordApp.getAuthorizeUrl(params)
const url = discordApp.getAuthorizeUrl(params)
return {error: null, state: state, url: url}
return { error: null, state: state, url: url }
},
getAccessToken: async function (code) {
if (!discordApp) API.Discord.oauth2App()
let redirectUri = config.server.domain + '/api/external/discord/callback'
const redirectUri = config.server.domain + '/api/external/discord/callback'
let tokens
try {
tokens = await discordApp.getOAuthAccessToken(code, {grant_type: 'authorization_code', redirect_uri: redirectUri})
tokens = await discordApp.getOAuthAccessToken(code, { grant_type: 'authorization_code', redirect_uri: redirectUri })
} catch (e) {
console.error(e)
return {error: 'No Authorization'}
return { error: 'No Authorization' }
}
if (!tokens.length) return {error: 'No Tokens'}
if (!tokens.length) return { error: 'No Tokens' }
tokens = tokens[2]
return {error: null, accessToken: tokens.access_token}
return { error: null, accessToken: tokens.access_token }
},
callback: async function (user, accessToken, ipAddress) {
if (!discordApp) API.Discord.oauth2App()
let ddata
try {
let resp = await discordApp.get('https://discordapp.com/api/users/@me', accessToken)
const resp = await discordApp.get('https://discordapp.com/api/users/@me', accessToken)
ddata = JSON.parse(resp)
} catch (e) {
console.error(e)
return {error: 'Could not get user information'}
return { error: 'Could not get user information' }
}
let uid = ddata.id
const uid = ddata.id
// Create a new user
let cleanedData = Object.assign(ddata, {
const cleanedData = Object.assign(ddata, {
display_name: ddata.username,
email: ddata.email || ''
})

View File

@ -1,8 +1,8 @@
import gm from 'gm'
import url from 'url'
import { URL } from 'url'
import path from 'path'
import crypto from 'crypto'
import uuid from 'uuid/v4'
import { v4 as uuid } from 'uuid'
import http from '../../scripts/http'
@ -20,8 +20,8 @@ const imageTypes = {
}
function decodeBase64Image (dataString) {
let matches = dataString.match(/^data:([A-Za-z-+/]+);base64,(.+)$/)
let response = {}
const matches = dataString.match(/^data:([A-Za-z-+/]+);base64,(.+)$/)
const response = {}
if (matches.length !== 3) {
return null
@ -34,10 +34,10 @@ function decodeBase64Image (dataString) {
}
function saneFields (fields) {
let out = {}
const out = {}
for (let i in fields) {
let entry = fields[i]
for (const i in fields) {
const entry = fields[i]
if (typeof entry === 'object' && entry.length === 1 && !isNaN(parseInt(entry[0]))) {
out[i] = parseInt(entry[0])
}
@ -53,17 +53,17 @@ async function bailOut (file, error) {
async function imageBase64 (baseObj) {
if (!baseObj) return null
let imgData = decodeBase64Image(baseObj)
const imgData = decodeBase64Image(baseObj)
if (!imgData) return null
if (!imageTypes[imgData.type]) return null
let imageName = 'base64-' + uuid()
let ext = imageTypes[imgData.type] || '.png'
const ext = imageTypes[imgData.type] || '.png'
imageName += ext
let fpath = path.join(images, imageName)
const fpath = path.join(images, imageName)
try {
await fs.writeFile(fpath, imgData.data)
@ -72,11 +72,11 @@ async function imageBase64 (baseObj) {
return null
}
return {file: fpath}
return { file: fpath }
}
function gravatarURL (email) {
let sum = crypto.createHash('md5').update(email).digest('hex')
const sum = crypto.createHash('md5').update(email).digest('hex')
return gravatar + sum + '.jpg'
}
@ -85,8 +85,8 @@ async function downloadImage (imgUrl, designation) {
if (!designation) designation = 'download'
let imageName = designation + '-' + uuid()
let uridata = url.parse(imgUrl)
let pathdata = path.parse(uridata.path)
const uridata = new URL(imgUrl)
const pathdata = path.parse(uridata.path)
imageName += pathdata.ext || '.png'
@ -108,23 +108,23 @@ async function uploadImage (identifier, fields, files) {
fields = saneFields(fields)
// Get file info, generate a file name
let fileHash = uuid()
let contentType = file.headers['content-type']
const fileHash = uuid()
const contentType = file.headers['content-type']
if (!contentType) return bailOut(file.path, 'Invalid of missing content-type header')
file = file.path
// Make sure content type is allowed
let match = false
for (let i in imageTypes) {
for (const i in imageTypes) {
if (i === contentType) {
match = true
break
}
}
if (!match) return bailOut(file, 'Invalid image type. Only PNG, JPG and JPEG files are allowed.')
let extension = imageTypes[contentType]
let fileName = identifier + '-' + fileHash + extension
const extension = imageTypes[contentType]
const fileName = identifier + '-' + fileHash + extension
// Check for cropping
if (fields.x == null || fields.y == null || fields.width == null || fields.height == null) {
@ -172,7 +172,7 @@ async function uploadImage (identifier, fields, files) {
return bailOut(file, 'An error occured while cropping.')
}
return {file: fileName}
return { file: fileName }
}
module.exports = {

View File

@ -3,7 +3,7 @@ import cprog from 'child_process'
import crypto from 'crypto'
import notp from 'notp'
import base32 from 'thirty-two'
import uuidV1 from 'uuid/v1'
import { v1 as uuidV1 } from 'uuid'
import fs from 'fs-extra'
import config from '../../scripts/load-config'
@ -16,12 +16,12 @@ const emailRe = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\
// Fork a bcrypt process to hash and compare passwords
function bcryptTask (data) {
return new Promise((resolve, reject) => {
let proc = cprog.fork(path.join(__dirname, '../../scripts', 'bcrypt.js'))
const proc = cprog.fork(path.join(__dirname, '../../scripts', 'bcrypt.js'))
let done = false
proc.send(data.task + ' ' + JSON.stringify(data))
proc.on('message', (chunk) => {
if (chunk == null) return reject(new Error('No response'))
let line = chunk.toString().trim()
const line = chunk.toString().trim()
done = true
if (line === 'error') {
return reject(new Error(line))
@ -43,8 +43,8 @@ function bcryptTask (data) {
function keysAvailable (object, required) {
let found = true
for (let i in required) {
let key = required[i]
for (const i in required) {
const key = required[i]
if (object[key] == null) {
found = false
}
@ -65,7 +65,7 @@ async function cleanUpDonation (obj, mcOnly, timeframe) {
user = await API.User.get(obj.user_id)
}
let result = {
const result = {
trackId: obj.id,
amount: obj.amount,
donated: obj.created_at
@ -75,10 +75,10 @@ async function cleanUpDonation (obj, mcOnly, timeframe) {
result.name = user.display_name
}
let sources = obj.source.split(',')
for (let i in sources) {
const sources = obj.source.split(',')
for (const i in sources) {
if (sources[i].indexOf('mcu:') === 0) {
let mcu = sources[i].split(':')[1]
const mcu = sources[i].split(':')[1]
if (mcu.match(/^([\w_]{2,16})$/i)) {
result.minecraft_username = mcu
}
@ -90,7 +90,7 @@ async function cleanUpDonation (obj, mcOnly, timeframe) {
return result
}
let txnStore = []
const txnStore = []
const API = {
Hash: (len) => {
@ -101,10 +101,10 @@ const API = {
if (!ppp) ppp = 5
if (!dcount) return null
let pageCount = Math.ceil(dcount / ppp)
const pageCount = Math.ceil(dcount / ppp)
if (page > pageCount) page = pageCount
let offset = (page - 1) * ppp
const offset = (page - 1) * ppp
return {
page: page,
@ -135,7 +135,7 @@ const API = {
}
}
let user = await models.User.query().where(scope, identifier)
const user = await models.User.query().where(scope, identifier)
if (!user.length) return null
return user[0]
@ -154,16 +154,16 @@ const API = {
socialStatus: async function (user) {
user = await API.User.ensureObject(user, ['password'])
if (!user) return null
let external = await models.External.query().orderBy('created_at', 'asc').where('user_id', user.id)
let enabled = {}
const external = await models.External.query().orderBy('created_at', 'asc').where('user_id', user.id)
const enabled = {}
for (let i in external) {
let ext = external[i]
for (const i in external) {
const ext = external[i]
enabled[ext.service] = true
}
let accountSourceIsExternal = user.password === null || user.password === ''
let obj = {
const accountSourceIsExternal = user.password === null || user.password === ''
const obj = {
enabled: enabled,
password: !accountSourceIsExternal
}
@ -186,8 +186,8 @@ const API = {
},
changeAvatar: async function (user, fileName) {
user = await API.User.ensureObject(user, ['avatar_file'])
let uploadsDir = path.join(__dirname, '../../', 'usercontent', 'images')
let pathOf = path.join(uploadsDir, fileName)
const uploadsDir = path.join(__dirname, '../../', 'usercontent', 'images')
const pathOf = path.join(uploadsDir, fileName)
if (!await fs.exists(pathOf)) {
throw new Error('No such file')
@ -195,26 +195,26 @@ const API = {
// Delete previous upload
if (user.avatar_file != null) {
let file = path.join(uploadsDir, user.avatar_file)
const file = path.join(uploadsDir, user.avatar_file)
if (await fs.exists(file)) {
await fs.unlink(file)
}
}
await API.User.update(user, {avatar_file: fileName})
await API.User.update(user, { avatar_file: fileName })
return fileName
},
removeAvatar: async function (user) {
user = await API.User.ensureObject(user, ['avatar_file'])
let uploadsDir = path.join(__dirname, '../../', 'usercontent', 'images')
const uploadsDir = path.join(__dirname, '../../', 'usercontent', 'images')
if (!user.avatar_file) return {}
let file = path.join(uploadsDir, user.avatar_file)
const file = path.join(uploadsDir, user.avatar_file)
if (await fs.exists(file)) {
await fs.unlink(file)
}
return API.User.update(user, {avatar_file: null})
return API.User.update(user, { avatar_file: null })
},
getBanStatus: async function (field, ip = false) {
let bans
@ -224,15 +224,15 @@ const API = {