download discord avatar automatically

This commit is contained in:
Evert Prants 2017-09-09 14:15:11 +03:00
parent 8a231dfd73
commit f54f6fb1b0
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
6 changed files with 96 additions and 28 deletions

13
package-lock.json generated
View File

@ -455,7 +455,8 @@
"dev": true "dev": true
}, },
"bluebird": { "bluebird": {
"version": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", "version": "3.5.0",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz",
"integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=" "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw="
}, },
"bn.js": { "bn.js": {
@ -1146,7 +1147,7 @@
"resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.14.5.tgz", "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.14.5.tgz",
"integrity": "sha1-WiUEe8dvcwcmZ8jLUsmJiI9JTGM=", "integrity": "sha1-WiUEe8dvcwcmZ8jLUsmJiI9JTGM=",
"requires": { "requires": {
"bluebird": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz" "bluebird": "3.5.0"
} }
}, },
"constantinople": { "constantinople": {
@ -1640,7 +1641,7 @@
"resolved": "https://registry.npmjs.org/email-templates/-/email-templates-2.7.1.tgz", "resolved": "https://registry.npmjs.org/email-templates/-/email-templates-2.7.1.tgz",
"integrity": "sha512-WJ0csXaBK3gV90dwBco5d3liu/XSH1jPEn3qfLDES/AsxOoMv4IRqp/MsQduKBexJZ81577OUbrdgnzvK2Kk9Q==", "integrity": "sha512-WJ0csXaBK3gV90dwBco5d3liu/XSH1jPEn3qfLDES/AsxOoMv4IRqp/MsQduKBexJZ81577OUbrdgnzvK2Kk9Q==",
"requires": { "requires": {
"bluebird": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", "bluebird": "3.5.0",
"consolidate": "0.14.5", "consolidate": "0.14.5",
"debug": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", "debug": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
"glob": "6.0.4", "glob": "6.0.4",
@ -3169,7 +3170,7 @@
"integrity": "sha1-CN1JT2u2SSiTTuydrDR4ehTKX6Q=", "integrity": "sha1-CN1JT2u2SSiTTuydrDR4ehTKX6Q=",
"requires": { "requires": {
"babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz", "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
"bluebird": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", "bluebird": "3.5.0",
"chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"commander": "https://registry.npmjs.org/commander/-/commander-2.10.0.tgz", "commander": "https://registry.npmjs.org/commander/-/commander-2.10.0.tgz",
"debug": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", "debug": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
@ -3661,7 +3662,7 @@
"resolved": "https://registry.npmjs.org/oauth-libre/-/oauth-libre-0.9.17.tgz", "resolved": "https://registry.npmjs.org/oauth-libre/-/oauth-libre-0.9.17.tgz",
"integrity": "sha1-5Jg39iFj4QVj49BRNd82DcYYpxI=", "integrity": "sha1-5Jg39iFj4QVj49BRNd82DcYYpxI=",
"requires": { "requires": {
"bluebird": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", "bluebird": "3.5.0",
"body-parser": "https://registry.npmjs.org/body-parser/-/body-parser-1.17.2.tgz", "body-parser": "https://registry.npmjs.org/body-parser/-/body-parser-1.17.2.tgz",
"express": "https://registry.npmjs.org/express/-/express-4.15.3.tgz", "express": "https://registry.npmjs.org/express/-/express-4.15.3.tgz",
"express-session": "https://registry.npmjs.org/express-session/-/express-session-1.15.3.tgz", "express-session": "https://registry.npmjs.org/express-session/-/express-session-1.15.3.tgz",
@ -3708,7 +3709,7 @@
"integrity": "sha1-CCNKazCoudpFAKWz9ynN63JphY4=", "integrity": "sha1-CCNKazCoudpFAKWz9ynN63JphY4=",
"requires": { "requires": {
"ajv": "https://registry.npmjs.org/ajv/-/ajv-5.2.0.tgz", "ajv": "https://registry.npmjs.org/ajv/-/ajv-5.2.0.tgz",
"bluebird": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", "bluebird": "3.5.0",
"lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz" "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
} }
}, },

View File

@ -35,6 +35,7 @@
"babel-core": "^6.25.0", "babel-core": "^6.25.0",
"babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1",
"bcryptjs": "^2.4.3", "bcryptjs": "^2.4.3",
"bluebird": "^3.5.0",
"body-parser": "^1.17.2", "body-parser": "^1.17.2",
"connect-redis": "^3.3.0", "connect-redis": "^3.3.0",
"connect-session-knex": "^1.3.4", "connect-session-knex": "^1.3.4",

View File

@ -1,8 +1,10 @@
import config from './load-config' import config from './load-config'
import path from 'path' import path from 'path'
import fs from 'fs'
import util from 'util' import util from 'util'
import Promise from 'bluebird'
const fs = Promise.promisifyAll(require('fs'))
let lfs let lfs
function pz (z) { function pz (z) {
@ -49,6 +51,19 @@ console.error = function () {
stampAndWrite.call(this, realConsoleError, ' err', message) stampAndWrite.call(this, realConsoleError, ' err', message)
} }
async function initializeLogger () {
let logPath = path.resolve(config.logger.file)
try {
await fs.accessAsync(logPath, fs.W_OK)
lfs = fs.createWriteStream(logPath, {flags: 'a'})
} catch (e) {
lfs = null
console.error('Failed to initiate log file write stream')
console.error(e.stack)
}
}
module.exports = function () { module.exports = function () {
this.logProcess = (pid, msg) => { this.logProcess = (pid, msg) => {
if (msg.indexOf('warn') === 0) { if (msg.indexOf('warn') === 0) {
@ -64,12 +79,5 @@ module.exports = function () {
// Create log file write stream // Create log file write stream
if (!config.logger || !config.logger.write) return if (!config.logger || !config.logger.write) return
initializeLogger()
try {
lfs = fs.createWriteStream(path.resolve(config.logger.file), {flags: 'a'})
} catch (e) {
lfs = null
console.error('Failed to initiate log file write stream')
console.error(e.stack)
}
} }

View File

@ -7,6 +7,8 @@ import oauth from 'oauth-libre'
import path from 'path' import path from 'path'
import url from 'url' import url from 'url'
const imgdir = path.join(__dirname, '../../', 'usercontent', 'images')
let twitterApp let twitterApp
let discordApp let discordApp
@ -59,7 +61,6 @@ const API = {
}, },
saveAvatar: async (avatarUrl) => { saveAvatar: async (avatarUrl) => {
if (!avatarUrl) return null if (!avatarUrl) return null
let imgdir = path.join(__dirname, '../../', 'usercontent', 'images')
let imageName = 'download-' + UAPI.Hash(12) let imageName = 'download-' + UAPI.Hash(12)
let uridata = url.parse(avatarUrl) let uridata = url.parse(avatarUrl)
let pathdata = path.parse(uridata.path) let pathdata = path.parse(uridata.path)
@ -385,12 +386,23 @@ const API = {
let bans = await API.Common.getBan(null, ipAddress) let bans = await API.Common.getBan(null, ipAddress)
if (bans.length) return { banned: bans, ip: true } if (bans.length) return { banned: bans, ip: true }
// Determine profile picture // Download profile picture
let profilepic = null let profilepic = null
let aviSnowflake = ddata.avatar
if (aviSnowflake) {
try {
let avpt = await API.Common.saveAvatar('https://cdn.discordapp.com/avatars/' + ddata.id + '/' + aviSnowflake + '.png')
if (avpt && avpt.fileName) {
profilepic = avpt.fileName
}
} catch (e) {
profilepic = null
}
}
// Create a new user // Create a new user
let udataLimited = { let udataLimited = {
username: 'D' + ddata.discriminator, username: ddata.username.replace(/\W+/gi, '_'),
display_name: ddata.username, display_name: ddata.username,
email: ddata.email || '', email: ddata.email || '',
avatar_file: profilepic, avatar_file: profilepic,
@ -400,6 +412,11 @@ const API = {
created_at: new Date() created_at: new Date()
} }
// Check if the username is already taken
if (await UAPI.User.get(udataLimited.username) != null) {
udataLimited.username = udataLimited.username + UAPI.Hash(4)
}
// Check if the email Discord gave us is already registered, if so, // Check if the email Discord gave us is already registered, if so,
// associate an external node with the user bearing the email // associate an external node with the user bearing the email
if (udataLimited.email && udataLimited.email !== '') { if (udataLimited.email && udataLimited.email !== '') {

View File

@ -1,12 +1,12 @@
import gm from 'gm' import gm from 'gm'
import fs from 'fs'
import path from 'path' import path from 'path'
import crypto from 'crypto' import crypto from 'crypto'
import Promise from 'bluebird' import Promise from 'bluebird'
const fsBlue = Promise.promisifyAll(fs) const fs = Promise.promisifyAll(require('fs'))
const uploads = path.join(__dirname, '../../', 'usercontent') const uploads = path.join(__dirname, '../../', 'usercontent')
const images = path.join(uploads, 'images')
const maxFileSize = 1000000 const maxFileSize = 1000000
const imageTypes = { const imageTypes = {
'image/png': '.png', 'image/png': '.png',
@ -14,6 +14,20 @@ const imageTypes = {
'image/jpeg': '.jpeg' 'image/jpeg': '.jpeg'
} }
function decodeBase64Image (dataString) {
let matches = dataString.match(/^data:([A-Za-z-+/]+);base64,(.+)$/)
let response = {}
if (matches.length !== 3) {
return null
}
response.type = matches[1]
response.data = Buffer.from(matches[2], 'base64')
return response
}
function saneFields (fields) { function saneFields (fields) {
let out = {} let out = {}
@ -28,12 +42,35 @@ function saneFields (fields) {
} }
async function bailOut (file, error) { async function bailOut (file, error) {
await fsBlue.unlinkAsync(file) await fs.unlinkAsync(file)
return { error: error } return { error: error }
} }
async function imageBase64 (baseObj) {
if (!baseObj) return null
let imgData = decodeBase64Image(baseObj)
if (!imgData) return null
if (!imageTypes[imgData.type]) return null
let imageName = 'base64-' + crypto.randomBytes(12).toString('hex')
let ext = imageTypes[imgData.type] || '.png'
imageName += ext
let fpath = path.join(images, imageName)
try {
fs.writeFileSync(fpath, imgData.data)
} catch (e) {
console.error(e)
return null
}
return {file: fpath}
}
async function uploadImage (identifier, fields, files) { async function uploadImage (identifier, fields, files) {
let directory = path.join(uploads, 'images')
if (!files.image) return {error: 'No image file'} if (!files.image) return {error: 'No image file'}
let file = files.image[0] let file = files.image[0]
@ -89,13 +126,13 @@ async function uploadImage (identifier, fields, files) {
await new Promise(function (resolve, reject) { await new Promise(function (resolve, reject) {
gm(file) gm(file)
.crop(fields.width, fields.height, fields.x, fields.y) .crop(fields.width, fields.height, fields.x, fields.y)
.write(path.join(directory, fileName), (err) => { .write(path.join(images, fileName), (err) => {
if (err) return reject(err) if (err) return reject(err)
resolve(fileName) resolve(fileName)
}) })
}) })
await fsBlue.unlinkAsync(file) await fs.unlinkAsync(file)
} catch (e) { } catch (e) {
console.error(e) console.error(e)
return bailOut(file, 'An error occured while cropping.') return bailOut(file, 'An error occured while cropping.')
@ -105,5 +142,7 @@ async function uploadImage (identifier, fields, files) {
} }
module.exports = { module.exports = {
uploadImage: uploadImage uploadImage: uploadImage,
imageBase64: imageBase64,
types: imageTypes
} }

View File

@ -7,7 +7,9 @@ import crypto from 'crypto'
import notp from 'notp' import notp from 'notp'
import base32 from 'thirty-two' import base32 from 'thirty-two'
import emailer from './emailer' import emailer from './emailer'
import fs from 'fs'
import Promise from 'bluebird'
const fs = Promise.promisifyAll(require('fs'))
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,}))$/ 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,}))$/
@ -191,7 +193,7 @@ const API = {
if (user.avatar_file != null) { if (user.avatar_file != null) {
let file = path.join(uploadsDir, user.avatar_file) let file = path.join(uploadsDir, user.avatar_file)
if (fs.existsSync(file)) { if (fs.existsSync(file)) {
fs.unlinkSync(file) await fs.unlinkAsync(file)
} }
} }
@ -205,7 +207,7 @@ const API = {
let file = path.join(uploadsDir, user.avatar_file) let file = path.join(uploadsDir, user.avatar_file)
if (fs.existsSync(file)) { if (fs.existsSync(file)) {
fs.unlinkSync(file) await fs.unlinkAsync(file)
} }
return API.User.update(user, {avatar_file: null}) return API.User.update(user, {avatar_file: null})