From f54f6fb1b0858d7a132923fff4c7cd69c3ec644f Mon Sep 17 00:00:00 2001 From: Evert Date: Sat, 9 Sep 2017 14:15:11 +0300 Subject: [PATCH] download discord avatar automatically --- package-lock.json | 13 ++++++----- package.json | 1 + scripts/logger.js | 26 ++++++++++++++------- server/api/external.js | 23 +++++++++++++++--- server/api/image.js | 53 ++++++++++++++++++++++++++++++++++++------ server/api/index.js | 8 ++++--- 6 files changed, 96 insertions(+), 28 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4475cb8..88fdaa9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -455,7 +455,8 @@ "dev": true }, "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=" }, "bn.js": { @@ -1146,7 +1147,7 @@ "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.14.5.tgz", "integrity": "sha1-WiUEe8dvcwcmZ8jLUsmJiI9JTGM=", "requires": { - "bluebird": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz" + "bluebird": "3.5.0" } }, "constantinople": { @@ -1640,7 +1641,7 @@ "resolved": "https://registry.npmjs.org/email-templates/-/email-templates-2.7.1.tgz", "integrity": "sha512-WJ0csXaBK3gV90dwBco5d3liu/XSH1jPEn3qfLDES/AsxOoMv4IRqp/MsQduKBexJZ81577OUbrdgnzvK2Kk9Q==", "requires": { - "bluebird": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", + "bluebird": "3.5.0", "consolidate": "0.14.5", "debug": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", "glob": "6.0.4", @@ -3169,7 +3170,7 @@ "integrity": "sha1-CN1JT2u2SSiTTuydrDR4ehTKX6Q=", "requires": { "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", "commander": "https://registry.npmjs.org/commander/-/commander-2.10.0.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", "integrity": "sha1-5Jg39iFj4QVj49BRNd82DcYYpxI=", "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", "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", @@ -3708,7 +3709,7 @@ "integrity": "sha1-CCNKazCoudpFAKWz9ynN63JphY4=", "requires": { "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" } }, diff --git a/package.json b/package.json index 06296f1..d32c9f9 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "babel-core": "^6.25.0", "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", "bcryptjs": "^2.4.3", + "bluebird": "^3.5.0", "body-parser": "^1.17.2", "connect-redis": "^3.3.0", "connect-session-knex": "^1.3.4", diff --git a/scripts/logger.js b/scripts/logger.js index 8d4561a..d192aa3 100644 --- a/scripts/logger.js +++ b/scripts/logger.js @@ -1,8 +1,10 @@ import config from './load-config' import path from 'path' -import fs from 'fs' import util from 'util' +import Promise from 'bluebird' +const fs = Promise.promisifyAll(require('fs')) + let lfs function pz (z) { @@ -49,6 +51,19 @@ console.error = function () { 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 () { this.logProcess = (pid, msg) => { if (msg.indexOf('warn') === 0) { @@ -64,12 +79,5 @@ module.exports = function () { // Create log file write stream if (!config.logger || !config.logger.write) return - - 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) - } + initializeLogger() } diff --git a/server/api/external.js b/server/api/external.js index 6a21a28..60fabf1 100644 --- a/server/api/external.js +++ b/server/api/external.js @@ -7,6 +7,8 @@ import oauth from 'oauth-libre' import path from 'path' import url from 'url' +const imgdir = path.join(__dirname, '../../', 'usercontent', 'images') + let twitterApp let discordApp @@ -59,7 +61,6 @@ const API = { }, saveAvatar: async (avatarUrl) => { if (!avatarUrl) return null - let imgdir = path.join(__dirname, '../../', 'usercontent', 'images') let imageName = 'download-' + UAPI.Hash(12) let uridata = url.parse(avatarUrl) let pathdata = path.parse(uridata.path) @@ -385,12 +386,23 @@ const API = { let bans = await API.Common.getBan(null, ipAddress) if (bans.length) return { banned: bans, ip: true } - // Determine profile picture + // Download profile picture 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 let udataLimited = { - username: 'D' + ddata.discriminator, + username: ddata.username.replace(/\W+/gi, '_'), display_name: ddata.username, email: ddata.email || '', avatar_file: profilepic, @@ -400,6 +412,11 @@ const API = { 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, // associate an external node with the user bearing the email if (udataLimited.email && udataLimited.email !== '') { diff --git a/server/api/image.js b/server/api/image.js index 7c8587a..20ca21e 100644 --- a/server/api/image.js +++ b/server/api/image.js @@ -1,12 +1,12 @@ import gm from 'gm' -import fs from 'fs' import path from 'path' import crypto from 'crypto' import Promise from 'bluebird' -const fsBlue = Promise.promisifyAll(fs) +const fs = Promise.promisifyAll(require('fs')) const uploads = path.join(__dirname, '../../', 'usercontent') +const images = path.join(uploads, 'images') const maxFileSize = 1000000 const imageTypes = { 'image/png': '.png', @@ -14,6 +14,20 @@ const imageTypes = { '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) { let out = {} @@ -28,12 +42,35 @@ function saneFields (fields) { } async function bailOut (file, error) { - await fsBlue.unlinkAsync(file) + await fs.unlinkAsync(file) 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) { - let directory = path.join(uploads, 'images') if (!files.image) return {error: 'No image file'} let file = files.image[0] @@ -89,13 +126,13 @@ async function uploadImage (identifier, fields, files) { await new Promise(function (resolve, reject) { gm(file) .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) resolve(fileName) }) }) - await fsBlue.unlinkAsync(file) + await fs.unlinkAsync(file) } catch (e) { console.error(e) return bailOut(file, 'An error occured while cropping.') @@ -105,5 +142,7 @@ async function uploadImage (identifier, fields, files) { } module.exports = { - uploadImage: uploadImage + uploadImage: uploadImage, + imageBase64: imageBase64, + types: imageTypes } diff --git a/server/api/index.js b/server/api/index.js index a8f9b32..f696ab5 100644 --- a/server/api/index.js +++ b/server/api/index.js @@ -7,7 +7,9 @@ import crypto from 'crypto' import notp from 'notp' import base32 from 'thirty-two' 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,}))$/ @@ -191,7 +193,7 @@ const API = { if (user.avatar_file != null) { let file = path.join(uploadsDir, user.avatar_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) if (fs.existsSync(file)) { - fs.unlinkSync(file) + await fs.unlinkAsync(file) } return API.User.update(user, {avatar_file: null})