Fix linting
This commit is contained in:
parent
553ba9db9a
commit
bb5189c9ed
35 changed files with 157 additions and 866 deletions
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"extends": "airbnb/base",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 6,
|
||||
"ecmaVersion": 2017,
|
||||
"sourceType": "module",
|
||||
"ecmaFeatures": {
|
||||
"experimentalObjectRestSpread": true
|
||||
},
|
||||
}
|
||||
},
|
||||
"env": {
|
||||
"node": true,
|
||||
|
@ -14,5 +14,6 @@
|
|||
"rules": {
|
||||
"quotes": [2, "single"],
|
||||
"no-underscore-dangle": [0],
|
||||
"no-plusplus": ["error", { "allowForLoopAfterthoughts": true }]
|
||||
}
|
||||
}
|
||||
|
|
14
.vscode/launch.json
vendored
Normal file
14
.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Launch Program",
|
||||
"program": "${workspaceFolder}/app.js"
|
||||
}
|
||||
]
|
||||
}
|
24
api/app.js
24
api/app.js
|
@ -1,12 +1,14 @@
|
|||
import Router from 'koa-router';
|
||||
import stats from '../lib/koa-statsd';
|
||||
import cors from 'kcors';
|
||||
import StatsD from 'statsy';
|
||||
import debugname from 'debug';
|
||||
|
||||
import stats from '../lib/koa-statsd';
|
||||
import auth from './lib/auth';
|
||||
import * as user from './routes/user';
|
||||
import * as file from './routes/file';
|
||||
import * as pro from './routes/pro';
|
||||
import debugname from 'debug';
|
||||
|
||||
const debug = debugname('hostr-api');
|
||||
|
||||
const router = new Router();
|
||||
|
@ -45,17 +47,15 @@ router.use(async (ctx, next) => {
|
|||
code: 604,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
if (!err.status) {
|
||||
debug(err);
|
||||
if (ctx.raven) {
|
||||
ctx.raven.captureError(err);
|
||||
}
|
||||
throw err;
|
||||
} else {
|
||||
ctx.status = err.status;
|
||||
ctx.body = err.message;
|
||||
} else if (!err.status) {
|
||||
debug(err);
|
||||
if (ctx.raven) {
|
||||
ctx.raven.captureError(err);
|
||||
}
|
||||
throw err;
|
||||
} else {
|
||||
ctx.status = err.status;
|
||||
ctx.body = err.message;
|
||||
}
|
||||
}
|
||||
ctx.type = 'application/json';
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import passwords from 'passwords';
|
||||
import auth from 'basic-auth';
|
||||
import models from '../../models';
|
||||
import debugname from 'debug';
|
||||
|
||||
import models from '../../models';
|
||||
|
||||
const debug = debugname('hostr-api:auth');
|
||||
|
||||
const badLoginMsg = '{"error": {"message": "Incorrect login details.", "code": 607}}';
|
||||
|
@ -36,8 +38,10 @@ export default async (ctx, next) => {
|
|||
},
|
||||
});
|
||||
|
||||
ctx.assert(count < 25, 401,
|
||||
'{"error": {"message": "Too many incorrect logins.", "code": 608}}');
|
||||
ctx.assert(
|
||||
count < 25, 401,
|
||||
'{"error": {"message": "Too many incorrect logins.", "code": 608}}',
|
||||
);
|
||||
|
||||
user = await models.user.findOne({
|
||||
where: {
|
||||
|
@ -56,8 +60,10 @@ export default async (ctx, next) => {
|
|||
ctx.assert(user, 401, badLoginMsg);
|
||||
debug('Checking user is activated');
|
||||
debug(user.activated);
|
||||
ctx.assert(user.activated === true, 401,
|
||||
'{"error": {"message": "Account has not been activated.", "code": 603}}');
|
||||
ctx.assert(
|
||||
user.activated === true, 401,
|
||||
'{"error": {"message": "Account has not been activated.", "code": 603}}',
|
||||
);
|
||||
|
||||
login.successful = true;
|
||||
await login.save();
|
||||
|
@ -85,9 +91,11 @@ export default async (ctx, next) => {
|
|||
plan: user.plan,
|
||||
uploads_today: uploadedToday,
|
||||
};
|
||||
ctx.response.set('Daily-Uploads-Remaining',
|
||||
user.type === 'Pro' ? 'unlimited' : 15 - uploadedToday);
|
||||
ctx.response.set(
|
||||
'Daily-Uploads-Remaining',
|
||||
user.type === 'Pro' ? 'unlimited' : 15 - uploadedToday,
|
||||
);
|
||||
ctx.user = normalisedUser;
|
||||
debug('Authenticated user: ', ctx.user.email);
|
||||
await next();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -47,8 +47,8 @@ export async function list(ctx) {
|
|||
processed: true,
|
||||
},
|
||||
order: [
|
||||
['createdAt', 'DESC'],
|
||||
],
|
||||
['createdAt', 'DESC'],
|
||||
],
|
||||
offset,
|
||||
limit,
|
||||
});
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
import path from 'path';
|
||||
import views from 'co-views';
|
||||
const render = views(path.join(__dirname, '/../views'), { default: 'ejs' });
|
||||
import Stripe from 'stripe';
|
||||
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
|
||||
import sendgridInit from 'sendgrid';
|
||||
const sendgrid = sendgridInit(process.env.SENDGRID_KEY);
|
||||
|
||||
import models from '../../models';
|
||||
|
||||
const render = views(path.join(__dirname, '/../views'), { default: 'ejs' });
|
||||
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
|
||||
const sendgrid = sendgridInit(process.env.SENDGRID_KEY);
|
||||
|
||||
const from = process.env.EMAIL_FROM;
|
||||
const fromname = process.env.EMAIL_NAME;
|
||||
|
||||
export async function create(ctx) {
|
||||
const stripeToken = ctx.request.body.stripeToken;
|
||||
const { stripeToken } = ctx.request.body;
|
||||
|
||||
const ip = ctx.request.headers['x-forwarded-for'] || ctx.req.connection.remoteAddress;
|
||||
|
||||
|
@ -74,7 +75,7 @@ export async function cancel(ctx) {
|
|||
await stripe.customers.cancelSubscription(
|
||||
transaction.data.id,
|
||||
transaction.data.subscription.id,
|
||||
{ at_period_end: false }
|
||||
{ at_period_end: false },
|
||||
);
|
||||
|
||||
user.plan = 'Free';
|
||||
|
|
|
@ -2,9 +2,10 @@ import uuid from 'node-uuid';
|
|||
import redis from 'redis';
|
||||
import co from 'co';
|
||||
import passwords from 'passwords';
|
||||
import debugname from 'debug';
|
||||
|
||||
import models from '../../models';
|
||||
|
||||
import debugname from 'debug';
|
||||
const debug = debugname('hostr-api:user');
|
||||
|
||||
const redisUrl = process.env.REDIS_URL;
|
||||
|
@ -26,31 +27,37 @@ export async function transaction(ctx) {
|
|||
},
|
||||
});
|
||||
|
||||
ctx.body = transactions.map((item) => {
|
||||
return {
|
||||
id: item.id,
|
||||
amount: item.amount / 100,
|
||||
date: item.date,
|
||||
description: item.description,
|
||||
type: 'direct',
|
||||
};
|
||||
});
|
||||
ctx.body = transactions.map(item => ({
|
||||
id: item.id,
|
||||
amount: item.amount / 100,
|
||||
date: item.date,
|
||||
description: item.description,
|
||||
type: 'direct',
|
||||
}));
|
||||
}
|
||||
|
||||
export async function settings(ctx) {
|
||||
ctx.assert(ctx.request.body, 400,
|
||||
'{"error": {"message": "Current Password required to update account.", "code": 612}}');
|
||||
ctx.assert(ctx.request.body.current_password, 400,
|
||||
'{"error": {"message": "Current Password required to update account.", "code": 612}}');
|
||||
ctx.assert(
|
||||
ctx.request.body, 400,
|
||||
'{"error": {"message": "Current Password required to update account.", "code": 612}}',
|
||||
);
|
||||
ctx.assert(
|
||||
ctx.request.body.current_password, 400,
|
||||
'{"error": {"message": "Current Password required to update account.", "code": 612}}',
|
||||
);
|
||||
const user = await models.user.findById(ctx.user.id);
|
||||
ctx.assert(await passwords.match(ctx.request.body.current_password, user.password), 400,
|
||||
'{"error": {"message": "Incorrect password", "code": 606}}');
|
||||
ctx.assert(
|
||||
await passwords.match(ctx.request.body.current_password, user.password), 400,
|
||||
'{"error": {"message": "Incorrect password", "code": 606}}',
|
||||
);
|
||||
if (ctx.request.body.email && ctx.request.body.email !== user.email) {
|
||||
user.email = ctx.request.body.email;
|
||||
}
|
||||
if (ctx.request.body.new_password) {
|
||||
ctx.assert(ctx.request.body.new_password.length >= 7, 400,
|
||||
'{"error": {"message": "Password must be 7 or more characters long.", "code": 606}}');
|
||||
ctx.assert(
|
||||
ctx.request.body.new_password.length >= 7, 400,
|
||||
'{"error": {"message": "Password must be 7 or more characters long.", "code": 606}}',
|
||||
);
|
||||
user.password = await passwords.hash(ctx.request.body.new_password);
|
||||
}
|
||||
await user.save();
|
||||
|
|
2
app.js
2
app.js
|
@ -9,11 +9,11 @@ import websockify from 'koa-websocket';
|
|||
import helmet from 'koa-helmet';
|
||||
import session from 'koa-session';
|
||||
import raven from 'raven';
|
||||
import debugname from 'debug';
|
||||
import * as redis from './lib/redis';
|
||||
import api, { ws } from './api/app';
|
||||
import web from './web/app';
|
||||
|
||||
import debugname from 'debug';
|
||||
const debug = debugname('hostr');
|
||||
|
||||
const app = websockify(new Koa());
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import moment from 'moment';
|
||||
import { sniff } from './type';
|
||||
import sniff from './sniff';
|
||||
|
||||
const baseURL = process.env.WEB_BASE_URL;
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import fs from 'fs';
|
||||
import createError from 'http-errors';
|
||||
import debugname from 'debug';
|
||||
import { get as getS3 } from './s3';
|
||||
|
||||
import debugname from 'debug';
|
||||
const debug = debugname('hostr:file-stream');
|
||||
|
||||
function writer(localPath, remoteRead) {
|
||||
|
|
|
@ -4,7 +4,7 @@ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|||
|
||||
function randomID() {
|
||||
let rand = '';
|
||||
for (let i = 0; i < 12; i++) {
|
||||
for (let i = 0; i < 12; i += 1) {
|
||||
rand += chars.charAt(Math.floor((Math.random() * chars.length)));
|
||||
}
|
||||
return rand;
|
||||
|
@ -18,7 +18,7 @@ async function checkId(Files, fileId, attempts) {
|
|||
if (file === null) {
|
||||
return fileId;
|
||||
}
|
||||
return checkId(randomID(), ++attempts); // eslint-disable-line no-param-reassign
|
||||
return checkId(Files, randomID(), attempts + 1);
|
||||
}
|
||||
|
||||
export default function (Files) {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var Stats = require('statsy');
|
||||
const Stats = require('statsy');
|
||||
|
||||
/**
|
||||
* Initialize stats middleware with `opts`
|
||||
|
@ -14,14 +14,13 @@ var Stats = require('statsy');
|
|||
* @api public
|
||||
*/
|
||||
|
||||
module.exports = function(opts){
|
||||
opts = opts || {};
|
||||
var s = new Stats(opts);
|
||||
export default function (opts) {
|
||||
const s = new Stats(opts || {});
|
||||
|
||||
return async (ctx, next) => {
|
||||
// counters
|
||||
s.incr('request.count');
|
||||
s.incr('request.' + ctx.method + '.count');
|
||||
s.incr(`request.${ctx.method}.count`);
|
||||
|
||||
// size
|
||||
s.histogram('request.size', ctx.request.length || 0);
|
||||
|
@ -33,5 +32,5 @@ module.exports = function(opts){
|
|||
ctx.res.on('finish', s.timer('request.duration'));
|
||||
|
||||
await next();
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import virustotal from './virustotal';
|
||||
import getFileReport from './virustotal';
|
||||
|
||||
const extensions = [
|
||||
'EXE',
|
||||
|
@ -65,13 +65,13 @@ function getExtension(filename) {
|
|||
return (i < 0) ? '' : filename.substr(i + 1);
|
||||
}
|
||||
|
||||
export default function* (file) {
|
||||
if (extensions.indexOf(getExtension(file.file_name.toUpperCase())) < 0) {
|
||||
export default async (file) => {
|
||||
if (extensions.indexOf(getExtension(file.name.toUpperCase())) < 0) {
|
||||
return false;
|
||||
}
|
||||
const result = yield virustotal.getFileReport(file.md5);
|
||||
const result = await getFileReport(file.md5);
|
||||
return {
|
||||
positive: result.positives >= 5,
|
||||
result,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
37
lib/mongo.js
37
lib/mongo.js
|
@ -1,37 +0,0 @@
|
|||
import mongodb from 'mongodb-promisified';
|
||||
const MongoClient = mongodb().MongoClient;
|
||||
import debugname from 'debug';
|
||||
const debug = debugname('hostr:mongo');
|
||||
|
||||
/* eslint no-param-reassign: ["error", { "props": false }] */
|
||||
export const mongo = new Promise((resolve, reject) => {
|
||||
debug('Connecting to Mongodb');
|
||||
return MongoClient.connect(process.env.MONGO_URL).then((client) => {
|
||||
debug('Successfully connected to Mongodb');
|
||||
client.Users = client.collection('users');
|
||||
client.Files = client.collection('files');
|
||||
client.Transactions = client.collection('transactions');
|
||||
client.Logins = client.collection('logins');
|
||||
client.Remember = client.collection('remember');
|
||||
client.Reset = client.collection('reset');
|
||||
client.Remember.ensureIndex({ created: 1 }, { expireAfterSeconds: 2592000 });
|
||||
client.Files.ensureIndex({ owner: 1, status: 1, time_added: -1 });
|
||||
client.ObjectId = client.objectId = mongodb().ObjectId;
|
||||
return resolve(client);
|
||||
}).catch((e) => {
|
||||
reject(e);
|
||||
});
|
||||
}).catch((e) => {
|
||||
debug(e);
|
||||
});
|
||||
|
||||
export default function () {
|
||||
return function* dbMiddleware(next) {
|
||||
try {
|
||||
this.db = yield mongo;
|
||||
} catch (e) {
|
||||
debug(e);
|
||||
}
|
||||
yield next;
|
||||
};
|
||||
}
|
|
@ -3,6 +3,7 @@ import coRedis from 'co-redis';
|
|||
import koaRedis from 'koa-redis';
|
||||
import session from 'koa-generic-session';
|
||||
import debugname from 'debug';
|
||||
|
||||
const debug = debugname('hostr:redis');
|
||||
|
||||
const connection = new Promise((resolve, reject) => {
|
||||
|
@ -25,8 +26,7 @@ const redisSession = new Promise((resolve, reject) =>
|
|||
}).catch((err) => {
|
||||
debug('koa-redis error: ', err);
|
||||
reject(err);
|
||||
})
|
||||
);
|
||||
}));
|
||||
|
||||
const wrapped = new Promise((resolve, reject) =>
|
||||
connection.then((client) => {
|
||||
|
@ -40,8 +40,7 @@ const wrapped = new Promise((resolve, reject) =>
|
|||
debug('co-redis error: ', err);
|
||||
reject(err);
|
||||
throw err;
|
||||
})
|
||||
);
|
||||
}));
|
||||
|
||||
export function sessionStore() {
|
||||
return async (ctx, next) => {
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import fs from 'mz/fs';
|
||||
import jimp from 'jimp';
|
||||
import debugname from 'debug';
|
||||
|
||||
const debug = debugname('hostr-api:resize');
|
||||
|
||||
const types = {
|
||||
jpg: jimp.MIME_JPEG,
|
||||
png: jimp.MIME_PNG,
|
||||
gif: jimp.MIME_JPEG,
|
||||
}
|
||||
};
|
||||
|
||||
function cover(path, type, size) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import aws from 'aws-sdk';
|
||||
import debugname from 'debug';
|
||||
|
||||
const debug = debugname('hostr:s3');
|
||||
|
||||
const s3 = new aws.S3({
|
||||
|
|
53
lib/sftp.js
53
lib/sftp.js
|
@ -1,53 +0,0 @@
|
|||
import { dirname, join } from 'path';
|
||||
import StatsD from 'statsy';
|
||||
import Client from './ssh2-sftp-client';
|
||||
import debugname from 'debug';
|
||||
const debug = debugname('hostr:sftp');
|
||||
|
||||
const statsdOpts = { prefix: 'hostr-api', host: process.env.STATSD_HOST };
|
||||
const statsd = new StatsD(statsdOpts);
|
||||
|
||||
export function get(remotePath) {
|
||||
debug('fetching', join('hostr', 'uploads', remotePath));
|
||||
const sftp = new Client();
|
||||
return sftp.connect({
|
||||
host: process.env.SFTP_HOST,
|
||||
port: process.env.SFTP_PORT,
|
||||
username: process.env.SFTP_USERNAME,
|
||||
password: process.env.SFTP_PASSWORD,
|
||||
})
|
||||
.then(() => sftp.get(join('hostr', 'uploads', remotePath), { encoding: null }));
|
||||
}
|
||||
|
||||
function sendFile(localPath, remotePath) {
|
||||
const sftp = new Client();
|
||||
return sftp.connect({
|
||||
host: process.env.SFTP_HOST,
|
||||
port: process.env.SFTP_PORT,
|
||||
username: process.env.SFTP_USERNAME,
|
||||
password: process.env.SFTP_PASSWORD,
|
||||
})
|
||||
.then(() => sftp.put(localPath, remotePath, true))
|
||||
.catch((err) => {
|
||||
if (err.message === 'No such file') {
|
||||
debug('Creating directory');
|
||||
return sftp.mkdir(dirname(remotePath), true)
|
||||
.then(() => sftp.put(localPath, remotePath, true));
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
export function *upload(localPath, remotePath) {
|
||||
let done = false;
|
||||
for (let retries = 0; retries < 5; retries++) {
|
||||
try {
|
||||
done = yield sendFile(localPath, remotePath);
|
||||
break;
|
||||
} catch (err) {
|
||||
statsd.incr('file.upload.retry', 1);
|
||||
debug('retry');
|
||||
}
|
||||
}
|
||||
return done;
|
||||
}
|
|
@ -26,9 +26,9 @@ const extensions = {
|
|||
rar: 'archive',
|
||||
};
|
||||
|
||||
export function sniff(filename) {
|
||||
export default (filename) => {
|
||||
if (extensions[filename.split('.').pop().toLowerCase()]) {
|
||||
return extensions[filename.split('.').pop().toLowerCase()];
|
||||
}
|
||||
return 'other';
|
||||
}
|
||||
};
|
|
@ -1,303 +0,0 @@
|
|||
/**
|
||||
* ssh2 sftp client for node
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
let Client = require('ssh2').Client;
|
||||
|
||||
let SftpClient = function(){
|
||||
this.client = new Client();
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves a directory listing
|
||||
*
|
||||
* @param {String} path, a string containing the path to a directory
|
||||
* @return {Promise} data, list info
|
||||
*/
|
||||
SftpClient.prototype.list = function(path) {
|
||||
let reg = /-/gi;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let sftp = this.sftp;
|
||||
|
||||
if (sftp) {
|
||||
sftp.readdir(path, (err, list) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return false;
|
||||
}
|
||||
// reset file info
|
||||
list.forEach((item, i) => {
|
||||
list[i] = {
|
||||
type: item.longname.substr(0, 1),
|
||||
name: item.filename,
|
||||
size: item.attrs.size,
|
||||
modifyTime: item.attrs.mtime * 1000,
|
||||
accessTime: item.attrs.atime * 1000,
|
||||
rights: {
|
||||
user: item.longname.substr(1, 3).replace(reg, ''),
|
||||
group: item.longname.substr(4,3).replace(reg, ''),
|
||||
other: item.longname.substr(7, 3).replace(reg, '')
|
||||
},
|
||||
owner: item.attrs.uid,
|
||||
group: item.attrs.gid
|
||||
}
|
||||
});
|
||||
resolve(list);
|
||||
});
|
||||
} else {
|
||||
reject('sftp connect error');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* get file
|
||||
*
|
||||
* @param {String} path, path
|
||||
* @param {Object} useCompression, config options
|
||||
* @return {Promise} stream, readable stream
|
||||
*/
|
||||
SftpClient.prototype.get = function(path, useCompression) {
|
||||
useCompression = Object.assign({}, {encoding: 'utf8'}, useCompression);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let sftp = this.sftp;
|
||||
|
||||
if (sftp) {
|
||||
try {
|
||||
let stream = sftp.createReadStream(path, useCompression);
|
||||
|
||||
stream.on('error', reject);
|
||||
|
||||
resolve(stream);
|
||||
} catch(err) {
|
||||
reject(err);
|
||||
}
|
||||
} else {
|
||||
reject('sftp connect error');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Create file
|
||||
*
|
||||
* @param {String|Buffer|stream} input
|
||||
* @param {String} remotePath,
|
||||
* @param {Object} useCompression [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
SftpClient.prototype.put = function(input, remotePath, useCompression) {
|
||||
useCompression = Object.assign({}, {encoding: 'utf8'}, useCompression);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let sftp = this.sftp;
|
||||
|
||||
if (sftp) {
|
||||
if (typeof input === 'string') {
|
||||
sftp.fastPut(input, remotePath, useCompression, (err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return false;
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
return false;
|
||||
}
|
||||
let stream = sftp.createWriteStream(remotePath, useCompression);
|
||||
let data;
|
||||
|
||||
stream.on('error', reject);
|
||||
stream.on('close', resolve);
|
||||
|
||||
if (input instanceof Buffer) {
|
||||
data = stream.end(input);
|
||||
return false;
|
||||
}
|
||||
data = input.pipe(stream);
|
||||
} else {
|
||||
reject('sftp connect error');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
SftpClient.prototype.mkdir = function(path, recursive) {
|
||||
recursive = recursive || false;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let sftp = this.sftp;
|
||||
|
||||
if (sftp) {
|
||||
if (!recursive) {
|
||||
sftp.mkdir(path, (err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return false;
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
let tokens = path.split(/\//g);
|
||||
let p = '';
|
||||
|
||||
let mkdir = () => {
|
||||
let token = tokens.shift();
|
||||
|
||||
if (!token && !tokens.length) {
|
||||
resolve();
|
||||
return false;
|
||||
}
|
||||
token += '/';
|
||||
p = p + token;
|
||||
sftp.mkdir(p, (err) => {
|
||||
if (err && err.code !== 4) {
|
||||
reject(err);
|
||||
}
|
||||
mkdir();
|
||||
});
|
||||
};
|
||||
return mkdir();
|
||||
} else {
|
||||
reject('sftp connect error');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
SftpClient.prototype.rmdir = function(path, recursive) {
|
||||
recursive = recursive || false;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let sftp = this.sftp;
|
||||
|
||||
if (sftp) {
|
||||
if (!recursive) {
|
||||
return sftp.rmdir(path, (err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
let rmdir = (p) => {
|
||||
return this.list(p).then((list) => {
|
||||
if (list.length > 0) {
|
||||
let promises = [];
|
||||
|
||||
list.forEach((item) => {
|
||||
let name = item.name;
|
||||
let promise;
|
||||
var subPath;
|
||||
|
||||
if (name[0] === '/') {
|
||||
subPath = name;
|
||||
} else {
|
||||
if (p[p.length - 1] === '/') {
|
||||
subPath = p + name;
|
||||
} else {
|
||||
subPath = p + '/' + name;
|
||||
}
|
||||
}
|
||||
|
||||
if (item.type === 'd') {
|
||||
if (name !== '.' || name !== '..') {
|
||||
promise = rmdir(subPath);
|
||||
}
|
||||
} else {
|
||||
promise = this.delete(subPath);
|
||||
}
|
||||
promises.push(promise);
|
||||
});
|
||||
if (promises.length) {
|
||||
return Promise.all(promises).then(() => {
|
||||
return rmdir(p);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return new Promise((resolve, reject) => {
|
||||
return sftp.rmdir(p, (err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
return rmdir(path).then(() => {resolve()})
|
||||
.catch((err) => {reject(err)});
|
||||
} else {
|
||||
reject('sftp connect error');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
SftpClient.prototype.delete = function(path) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let sftp = this.sftp;
|
||||
|
||||
if (sftp) {
|
||||
sftp.unlink(path, (err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return false;
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
} else {
|
||||
reject('sftp connect error');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
SftpClient.prototype.rename = function(srcPath, remotePath) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let sftp = this.sftp;
|
||||
|
||||
if (sftp) {
|
||||
sftp.rename(srcPath, remotePath, (err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return false;
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
} else {
|
||||
reject('sftp connect error');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
SftpClient.prototype.connect = function(config) {
|
||||
var c = this.client;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
this.client.on('ready', () => {
|
||||
|
||||
this.client.sftp((err, sftp) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
this.sftp = sftp;
|
||||
resolve(sftp);
|
||||
});
|
||||
}).on('error', (err) => {
|
||||
reject(err);
|
||||
}).connect(config);
|
||||
});
|
||||
};
|
||||
|
||||
SftpClient.prototype.end = function() {
|
||||
return new Promise((resolve) => {
|
||||
this.client.end();
|
||||
resolve();
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = SftpClient;
|
|
@ -3,16 +3,16 @@ import Busboy from 'busboy';
|
|||
import crypto from 'crypto';
|
||||
import fs from 'mz/fs';
|
||||
import sizeOf from 'image-size';
|
||||
import debugname from 'debug';
|
||||
|
||||
import models from '../models';
|
||||
import createHostrId from './hostr-id';
|
||||
import { formatFile } from './format';
|
||||
import resize from './resize';
|
||||
import malware from './malware';
|
||||
import { sniff } from './type';
|
||||
import sniff from './sniff';
|
||||
import { upload as s3upload } from './s3';
|
||||
|
||||
import debugname from 'debug';
|
||||
const debug = debugname('hostr-api:uploader');
|
||||
|
||||
const storePath = process.env.UPLOAD_STORAGE_PATH;
|
||||
|
@ -66,14 +66,12 @@ export default class Uploader {
|
|||
highWaterMark: 10000000,
|
||||
});
|
||||
|
||||
this.upload.on('file', async (fieldname, file, filename, encoding, mimetype) => {
|
||||
debug('FILE', fieldname, file, filename, encoding, mimetype);
|
||||
|
||||
this.upload.on('file', async (fieldname, file, filename) => {
|
||||
this.upload.filename = filename;
|
||||
|
||||
this.file = await models.file.create({
|
||||
id: await createHostrId(),
|
||||
name: this.upload.filename.replace(/[^a-zA-Z0-9\.\-_\s]/g, '').replace(/\s+/g, ''),
|
||||
name: this.upload.filename.replace(/[^a-zA-Z0-9\.\-_\s]/g, '').replace(/\s+/g, ''), // eslint-disable-line no-useless-escape
|
||||
originalName: this.upload.filename,
|
||||
userId: this.context.user.id,
|
||||
status: 'uploading',
|
||||
|
@ -102,7 +100,7 @@ export default class Uploader {
|
|||
|
||||
this.localStream.write(data);
|
||||
|
||||
this.percentComplete = Math.floor(this.receivedSize * 100 / this.expectedSize);
|
||||
this.percentComplete = Math.floor((this.receivedSize * 100) / this.expectedSize);
|
||||
if (this.percentComplete > this.lastPercent && this.lastTick < Date.now() - 1000) {
|
||||
const progressEvent = `{"type": "file-progress", "data":
|
||||
{"id": "${this.file.id}", "complete": ${this.percentComplete}}}`;
|
||||
|
@ -131,7 +129,6 @@ export default class Uploader {
|
|||
this.localStream.on('end', () => {
|
||||
s3upload(fs.createReadStream(join(storePath, this.path)), this.path);
|
||||
});
|
||||
|
||||
});
|
||||
this.context.req.pipe(this.upload);
|
||||
});
|
||||
|
@ -210,7 +207,7 @@ export default class Uploader {
|
|||
// Check in the background
|
||||
process.nextTick(async () => {
|
||||
debug('Malware Scan');
|
||||
const result = await malware(this);
|
||||
const result = await malware(this.file);
|
||||
if (result) {
|
||||
this.file.malwarePositives = result.positives;
|
||||
this.file.save();
|
||||
|
|
|
@ -3,9 +3,9 @@ import FormData from 'form-data';
|
|||
|
||||
const apiRoot = 'https://www.virustotal.com/vtapi/v2';
|
||||
|
||||
export function* getFileReport(resource, apiKey = process.env.VIRUSTOTAL_KEY) {
|
||||
export default async (resource, apiKey = process.env.VIRUSTOTAL_KEY) => {
|
||||
const form = new FormData();
|
||||
form.append('apikey', apiKey);
|
||||
form.append('resource', resource);
|
||||
return yield fetch(`${apiRoot}/file/report`, { method: 'POST' });
|
||||
}
|
||||
return fetch(`${apiRoot}/file/report`, { method: 'POST' });
|
||||
};
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
import co from 'co';
|
||||
|
||||
import models from '../models';
|
||||
import { mongo } from '../lib/mongo';
|
||||
|
||||
import debugname from 'debug';
|
||||
const debug = debugname('hostr:db');
|
||||
let db;
|
||||
|
||||
|
||||
co(function *sync() {
|
||||
debug('Syncing schema');
|
||||
yield models.sequelize.sync();
|
||||
debug('Schema synced');
|
||||
db = yield mongo;
|
||||
const users = yield db.Users.find({}, { sort: [['joined', 'asc']] }).toArray();
|
||||
for (const user of users) {
|
||||
if (user.joined === '0') {
|
||||
const file = yield db.Files.findOne({
|
||||
owner: user._id,
|
||||
}, {
|
||||
limit: 1,
|
||||
sort: [['time_added', 'asc']],
|
||||
});
|
||||
if (file && file.time_added > 0) {
|
||||
user.createdAt = new Date(file.time_added * 1000).getTime();
|
||||
} else {
|
||||
user.createdAt = new Date().getTime();
|
||||
}
|
||||
} else {
|
||||
user.createdAt = new Date(user.joined * 1000).getTime();
|
||||
}
|
||||
}
|
||||
|
||||
users.sort((a, b) => (a.createdAt < b.createdAt ? -1 : 1));
|
||||
|
||||
for (const user of users) {
|
||||
if (!user.email) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const exists = yield models.user.findOne({
|
||||
where: {
|
||||
email: user.email,
|
||||
},
|
||||
});
|
||||
|
||||
if (exists) {
|
||||
debug('User exists, continue');
|
||||
continue;
|
||||
}
|
||||
|
||||
const mongoId = user._id.toString();
|
||||
|
||||
const newUser = yield models.user.create({
|
||||
email: user.email,
|
||||
password: user.salted_password,
|
||||
name: user.first_name ? `${user.first_name} ${user.last_name}` : null,
|
||||
plan: user.type || 'Free',
|
||||
activated: !user.activationCode,
|
||||
banned: !!user.banned,
|
||||
deletedAt: user.status === 'deleted' ? new Date().getTime() : null,
|
||||
createdAt: user.createdAt,
|
||||
updatedAt: user.createdAt,
|
||||
mongoId,
|
||||
});
|
||||
yield newUser.save({ silent: true });
|
||||
}
|
||||
models.sequelize.close();
|
||||
db.close();
|
||||
}).catch((err) => {
|
||||
models.sequelize.close();
|
||||
db.close();
|
||||
debug(err);
|
||||
});
|
|
@ -1,83 +0,0 @@
|
|||
import co from 'co';
|
||||
import validateIp from 'validate-ip';
|
||||
|
||||
import models from '../models';
|
||||
import { mongo } from '../lib/mongo';
|
||||
|
||||
import debugname from 'debug';
|
||||
const debug = debugname('hostr:db');
|
||||
let db;
|
||||
|
||||
|
||||
co(function *sync() {
|
||||
debug('Syncing schema');
|
||||
yield models.sequelize.sync();
|
||||
debug('Schema synced');
|
||||
db = yield mongo;
|
||||
const users = yield models.user.findAll({});
|
||||
const userIds = {};
|
||||
debug('remap');
|
||||
for (const user of users) {
|
||||
userIds[user.mongoId] = user.id;
|
||||
}
|
||||
debug('remap done');
|
||||
let files;
|
||||
try {
|
||||
files = db.Files.find({}, {
|
||||
sort: [['time_added', 'desc']],
|
||||
skip: 0,
|
||||
});
|
||||
} catch (err) {
|
||||
debug(err);
|
||||
}
|
||||
debug('fetched files');
|
||||
|
||||
while (true) {
|
||||
const file = yield files.next();
|
||||
if (!file) {
|
||||
break;
|
||||
}
|
||||
if (!file.time_added || !file.file_size) {
|
||||
continue;
|
||||
}
|
||||
let ip = file.ip ? file.ip.split(',').pop().trim() : null;
|
||||
|
||||
if (typeof ip !== 'string' || !validateIp(ip)) {
|
||||
ip = null;
|
||||
}
|
||||
const processed = file.status !== 'uploading';
|
||||
const accessedAt = file.last_accessed ? new Date(file.last_accessed * 1000) : null;
|
||||
|
||||
const mongoId = file._id.toString();
|
||||
|
||||
yield models.file.upsert({
|
||||
id: file._id.toString(),
|
||||
name: file.file_name,
|
||||
originalName: file.original_name || file.file_name,
|
||||
size: file.file_size,
|
||||
downloads: file.downloads,
|
||||
deletedAt: file.status === 'deleted' ? new Date() : null,
|
||||
createdAt: new Date(file.time_added * 1000),
|
||||
updatedAt: new Date(file.time_added * 1000),
|
||||
accessedAt,
|
||||
processed,
|
||||
type: file.type !== 'file' ? file.type : 'other',
|
||||
width: Number.isInteger(file.width) ? file.width : null,
|
||||
height: Number.isInteger(file.height) ? file.height : null,
|
||||
userId: file.owner !== undefined ? userIds[file.owner] : null,
|
||||
ip,
|
||||
legacyId: file.system_name !== file._id ? file.system_name : null,
|
||||
md5: file.md5,
|
||||
malwarePositives: file.virustotal && file.virustotal.positives > 0 ?
|
||||
file.virustotal.positives : null,
|
||||
mongoId,
|
||||
}, { /* logging: false */ });
|
||||
}
|
||||
|
||||
models.sequelize.close();
|
||||
db.close();
|
||||
}).catch((err) => {
|
||||
models.sequelize.close();
|
||||
db.close();
|
||||
debug(err);
|
||||
});
|
|
@ -1,54 +0,0 @@
|
|||
import co from 'co';
|
||||
import validateIp from 'validate-ip';
|
||||
|
||||
import models from '../models';
|
||||
import { mongo } from '../lib/mongo';
|
||||
|
||||
import debugname from 'debug';
|
||||
const debug = debugname('hostr:db');
|
||||
let db;
|
||||
|
||||
|
||||
co(function *sync() {
|
||||
debug('Syncing schema');
|
||||
yield models.sequelize.sync();
|
||||
debug('Schema synced');
|
||||
db = yield mongo;
|
||||
const users = yield models.user.findAll({});
|
||||
const userIds = {};
|
||||
debug('remap');
|
||||
for (const user of users) {
|
||||
userIds[user._id] = user.id;
|
||||
}
|
||||
debug('remap done');
|
||||
let logins;
|
||||
try {
|
||||
logins = db.Logins.find({}, {
|
||||
skip: 0,
|
||||
});
|
||||
} catch (err) {
|
||||
debug(err);
|
||||
}
|
||||
debug('fetched logins');
|
||||
|
||||
while (true) {
|
||||
const login = yield logins.next();
|
||||
if (!login) {
|
||||
break;
|
||||
}
|
||||
|
||||
const newLogin = yield models.login.create({
|
||||
ip: login.ip,
|
||||
createdAt: login.at * 1000,
|
||||
successful: login.successful,
|
||||
}, { /* logging: false */ });
|
||||
newLogin.save();
|
||||
}
|
||||
|
||||
models.sequelize.close();
|
||||
db.close();
|
||||
}).catch((err) => {
|
||||
models.sequelize.close();
|
||||
db.close();
|
||||
debug(err);
|
||||
});
|
|
@ -1,46 +0,0 @@
|
|||
import co from 'co';
|
||||
|
||||
import models from '../models';
|
||||
import { mongo } from '../lib/mongo';
|
||||
|
||||
import debugname from 'debug';
|
||||
const debug = debugname('hostr:db');
|
||||
let db;
|
||||
|
||||
|
||||
co(function *sync() {
|
||||
debug('Syncing schema');
|
||||
yield models.sequelize.sync();
|
||||
debug('Schema synced');
|
||||
db = yield mongo;
|
||||
|
||||
const files = db.Files.find({}, {
|
||||
sort: [['time_added', 'desc']],
|
||||
skip: 0,
|
||||
});
|
||||
debug('fetched files');
|
||||
|
||||
while (true) {
|
||||
const file = yield files.next();
|
||||
if (!file) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!file.time_added || !file.file_size || !file.malware) {
|
||||
continue;
|
||||
}
|
||||
|
||||
yield models.malware.upsert({
|
||||
fileId: file._id,
|
||||
positives: file.virustotal ? file.virustotal.positives : 100,
|
||||
virustotal: file.virustotal || null,
|
||||
}, { /* logging: false */ });
|
||||
}
|
||||
|
||||
models.sequelize.close();
|
||||
db.close();
|
||||
}).catch((err) => {
|
||||
models.sequelize.close();
|
||||
db.close();
|
||||
debug(err);
|
||||
});
|
|
@ -1,77 +0,0 @@
|
|||
import co from 'co';
|
||||
|
||||
import models from '../models';
|
||||
import { mongo } from '../lib/mongo';
|
||||
|
||||
import debugname from 'debug';
|
||||
const debug = debugname('hostr:db');
|
||||
let db;
|
||||
|
||||
|
||||
co(function *sync() {
|
||||
debug('Syncing schema');
|
||||
yield models.sequelize.sync();
|
||||
debug('Schema synced');
|
||||
db = yield mongo;
|
||||
const users = yield db.Users.find({}, { sort: [['joined', 'asc']] }).toArray();
|
||||
for (const user of users) {
|
||||
if (user.joined === '0') {
|
||||
const file = yield db.Files.findOne({
|
||||
owner: user._id,
|
||||
}, {
|
||||
limit: 1,
|
||||
sort: [['time_added', 'asc']],
|
||||
});
|
||||
if (file && file.time_added > 0) {
|
||||
user.createdAt = new Date(file.time_added * 1000).getTime();
|
||||
} else {
|
||||
user.createdAt = new Date().getTime();
|
||||
}
|
||||
} else {
|
||||
user.createdAt = new Date(user.joined * 1000).getTime();
|
||||
}
|
||||
}
|
||||
|
||||
users.sort((a, b) => (a.createdAt < b.createdAt ? -1 : 1));
|
||||
|
||||
for (const user of users) {
|
||||
if (!user.email) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const exists = yield models.user.findOne({
|
||||
where: {
|
||||
email: user.email,
|
||||
},
|
||||
});
|
||||
|
||||
if (exists) {
|
||||
debug('User exists, continue');
|
||||
continue;
|
||||
}
|
||||
|
||||
const mongoId = user._id.toString();
|
||||
|
||||
const newUser = yield models.user.create({
|
||||
email: user.email,
|
||||
password: user.salted_password,
|
||||
name: user.first_name ? `${user.first_name} ${user.last_name}` : null,
|
||||
plan: user.type || 'Free',
|
||||
activated: !user.activationCode,
|
||||
banned: !!user.banned,
|
||||
deletedAt: user.status === 'deleted' ? new Date().getTime() : null,
|
||||
createdAt: user.createdAt,
|
||||
updatedAt: user.createdAt,
|
||||
mongoId,
|
||||
}, {
|
||||
include: [models.activation],
|
||||
});
|
||||
yield newUser.save({ silent: true });
|
||||
}
|
||||
models.sequelize.close();
|
||||
db.close();
|
||||
}).catch((err) => {
|
||||
models.sequelize.close();
|
||||
db.close();
|
||||
debug(err);
|
||||
});
|
|
@ -13,7 +13,7 @@ export default function (sequelize, DataTypes) {
|
|||
'audio',
|
||||
'video',
|
||||
'archive',
|
||||
'other'
|
||||
'other',
|
||||
),
|
||||
width: DataTypes.INTEGER,
|
||||
height: DataTypes.INTEGER,
|
||||
|
@ -32,14 +32,15 @@ export default function (sequelize, DataTypes) {
|
|||
});
|
||||
|
||||
File.accessed = function accessed(id) {
|
||||
sequelize.query(`
|
||||
sequelize.query(
|
||||
`
|
||||
UPDATE files
|
||||
SET "downloads" = downloads + 1, "accessedAt" = NOW()
|
||||
WHERE "id" = :id`,
|
||||
{
|
||||
replacements: { id },
|
||||
type: sequelize.QueryTypes.UPDATE,
|
||||
}
|
||||
{
|
||||
replacements: { id },
|
||||
type: sequelize.QueryTypes.UPDATE,
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -2,10 +2,6 @@ import fs from 'fs';
|
|||
import path from 'path';
|
||||
import Sequelize from 'sequelize';
|
||||
|
||||
import debugname from 'debug';
|
||||
|
||||
const debug = debugname('hostr:models');
|
||||
|
||||
const config = {
|
||||
dialect: 'postgres',
|
||||
protocol: 'postgres',
|
||||
|
|
17
web/app.js
17
web/app.js
|
@ -2,11 +2,10 @@ import path from 'path';
|
|||
import Router from 'koa-router';
|
||||
import CSRF from 'koa-csrf';
|
||||
import views from 'koa-views';
|
||||
import stats from '../lib/koa-statsd';
|
||||
import StatsD from 'statsy';
|
||||
import errors from 'koa-error';
|
||||
|
||||
import * as redis from '../lib/redis';
|
||||
import stats from '../lib/koa-statsd';
|
||||
import * as index from './routes/index';
|
||||
import * as file from './routes/file';
|
||||
import * as user from './routes/user';
|
||||
|
@ -26,8 +25,6 @@ router.use(async (ctx, next) => {
|
|||
await next();
|
||||
});
|
||||
|
||||
//router.use(redis.sessionStore());
|
||||
|
||||
router.use(async (ctx, next) => {
|
||||
ctx.state = {
|
||||
session: ctx.session,
|
||||
|
@ -71,15 +68,15 @@ router.get('/:id', file.landing);
|
|||
router.get('/file/:id/:name', file.get);
|
||||
router.get('/file/:size/:id/:name', file.get);
|
||||
router.get('/files/:id/:name', file.get);
|
||||
router.get('/download/:id/:name', function* downloadRedirect(id) {
|
||||
this.redirect(`/${id}`);
|
||||
router.get('/download/:id/:name', async (ctx, id) => {
|
||||
ctx.redirect(`/${id}`);
|
||||
});
|
||||
|
||||
router.get('/updaters/mac', function* macUpdater() {
|
||||
this.redirect('/updaters/mac.xml');
|
||||
router.get('/updaters/mac', async (ctx) => {
|
||||
ctx.redirect('/updaters/mac.xml');
|
||||
});
|
||||
router.get('/updaters/mac/changelog', function* macChangelog() {
|
||||
yield this.render('mac-update-changelog');
|
||||
router.get('/updaters/mac/changelog', async (ctx) => {
|
||||
await ctx.render('mac-update-changelog');
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
|
|
@ -41,7 +41,7 @@ export async function authenticate(email, password) {
|
|||
activated: true,
|
||||
},
|
||||
});
|
||||
debug(user);
|
||||
|
||||
const login = await models.login.create({
|
||||
ip: remoteIp,
|
||||
successful: false,
|
||||
|
@ -52,7 +52,6 @@ export async function authenticate(email, password) {
|
|||
debug('Password verified');
|
||||
login.successful = true;
|
||||
await login.save();
|
||||
debug(user);
|
||||
return user;
|
||||
}
|
||||
debug('Password invalid');
|
||||
|
@ -182,18 +181,18 @@ Visit ${process.env.WEB_BASE_URL}/forgot/${reset.id} to set a new one.
|
|||
|
||||
export async function fromToken(token) {
|
||||
const userId = await this.redis.get(token);
|
||||
return await models.user.findById(userId);
|
||||
return models.user.findById(userId);
|
||||
}
|
||||
|
||||
|
||||
export async function fromCookie(rememberId) {
|
||||
const userId = await models.remember.findById(rememberId);
|
||||
return await models.user.findById(userId);
|
||||
return models.user.findById(userId);
|
||||
}
|
||||
|
||||
|
||||
export async function validateResetToken(resetId) {
|
||||
return await models.reset.findById(resetId);
|
||||
return models.reset.findById(resetId);
|
||||
}
|
||||
|
||||
|
||||
|
@ -206,7 +205,6 @@ export async function updatePassword(userId, password) {
|
|||
|
||||
|
||||
export async function activateUser(code) {
|
||||
debug(code);
|
||||
const activation = await models.activation.findOne({
|
||||
where: {
|
||||
id: code,
|
||||
|
|
|
@ -20,7 +20,7 @@ function userAgentCheck(userAgent) {
|
|||
}
|
||||
|
||||
function referrerCheck(referrer) {
|
||||
return referrer && referrerRegexes.some((regex) => referrer.match(regex));
|
||||
return referrer && referrerRegexes.some(regex => referrer.match(regex));
|
||||
}
|
||||
|
||||
function hotlinkCheck(file, userAgent, referrer) {
|
||||
|
@ -52,7 +52,7 @@ export async function get(ctx) {
|
|||
}
|
||||
|
||||
if (file.malware) {
|
||||
const alert = ctx.request.query.alert;
|
||||
const { alert } = ctx.request.query;
|
||||
if (!alert || !alert.match(/i want to download malware/i)) {
|
||||
ctx.redirect(`/${file.id}`);
|
||||
return;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import uuid from 'node-uuid';
|
||||
import auth from '../lib/auth';
|
||||
import { fromToken, fromCookie, setupSession } from '../lib/auth';
|
||||
|
||||
export async function main(ctx) {
|
||||
if (ctx.session.user) {
|
||||
|
@ -11,18 +11,16 @@ export async function main(ctx) {
|
|||
await ctx.redis.set(token, ctx.session.user.id, 'EX', 604800);
|
||||
ctx.session.user.token = token;
|
||||
await ctx.render('index', { user: ctx.session.user });
|
||||
} else if (ctx.query['app-token']) {
|
||||
const user = await fromToken(ctx, ctx.query['app-token']);
|
||||
await setupSession(ctx, user);
|
||||
ctx.redirect('/');
|
||||
} else if (ctx.cookies.r) {
|
||||
const user = await fromCookie(ctx, ctx.cookies.r);
|
||||
await setupSession(ctx, user);
|
||||
ctx.redirect('/');
|
||||
} else {
|
||||
if (ctx.query['app-token']) {
|
||||
const user = await auth.fromToken(ctx, ctx.query['app-token']);
|
||||
await auth.setupSession(ctx, user);
|
||||
ctx.redirect('/');
|
||||
} else if (ctx.cookies.r) {
|
||||
const user = await auth.fromCookie(ctx, ctx.cookies.r);
|
||||
await auth.setupSession(ctx, user);
|
||||
ctx.redirect('/');
|
||||
} else {
|
||||
await ctx.render('marketing');
|
||||
}
|
||||
await ctx.render('marketing');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import debugname from 'debug';
|
||||
import {
|
||||
authenticate, setupSession, signup as signupUser, activateUser, sendResetToken,
|
||||
validateResetToken, updatePassword,
|
||||
} from '../lib/auth';
|
||||
|
||||
import models from '../../models';
|
||||
import debugname from 'debug';
|
||||
|
||||
const debug = debugname('hostr-web:user');
|
||||
|
||||
export async function signin(ctx) {
|
||||
|
@ -44,17 +46,20 @@ export async function signup(ctx) {
|
|||
await ctx.render('signup', { error: 'Emails do not match.', csrf: ctx.csrf });
|
||||
return;
|
||||
} else if (ctx.request.body.email && !ctx.request.body.terms) {
|
||||
await ctx.render('signup', { error: 'You must agree to the terms of service.',
|
||||
csrf: ctx.csrf });
|
||||
await ctx.render('signup', {
|
||||
error: 'You must agree to the terms of service.',
|
||||
csrf: ctx.csrf,
|
||||
});
|
||||
return;
|
||||
} else if (ctx.request.body.password && ctx.request.body.password.length < 7) {
|
||||
await ctx.render('signup', { error: 'Password must be at least 7 characters long.',
|
||||
csrf: ctx.csrf });
|
||||
await ctx.render('signup', {
|
||||
error: 'Password must be at least 7 characters long.',
|
||||
csrf: ctx.csrf,
|
||||
});
|
||||
return;
|
||||
}
|
||||
const ip = ctx.headers['x-forwarded-for'] || ctx.ip;
|
||||
const email = ctx.request.body.email;
|
||||
const password = ctx.request.body.password;
|
||||
const { email, password } = ctx.request.body;
|
||||
try {
|
||||
await signupUser.call(ctx, email, password, ip);
|
||||
} catch (e) {
|
||||
|
@ -66,12 +71,11 @@ export async function signup(ctx) {
|
|||
message: 'Thanks for signing up, we\'ve sent you an email to activate your account.',
|
||||
csrf: '',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
export async function forgot(ctx) {
|
||||
const token = ctx.params.token;
|
||||
const { token } = ctx.params;
|
||||
|
||||
if (ctx.request.body.password) {
|
||||
if (ctx.request.body.password.length < 7) {
|
||||
|
@ -87,7 +91,7 @@ export async function forgot(ctx) {
|
|||
if (user) {
|
||||
await updatePassword(user.userId, ctx.request.body.password);
|
||||
const reset = await models.reset.findById(token);
|
||||
//reset.destroy();
|
||||
reset.destroy();
|
||||
await setupSession.call(ctx, user);
|
||||
ctx.statsd.incr('auth.reset.success', 1);
|
||||
ctx.redirect('/');
|
||||
|
@ -104,11 +108,10 @@ export async function forgot(ctx) {
|
|||
return;
|
||||
}
|
||||
await ctx.render('forgot', { csrf: ctx.csrf, token });
|
||||
return;
|
||||
} else if (ctx.request.body.email) {
|
||||
ctx.assertCSRF(ctx.request.body);
|
||||
try {
|
||||
const email = ctx.request.body.email;
|
||||
const { email } = ctx.request.body;
|
||||
await sendResetToken.call(ctx, email);
|
||||
ctx.statsd.incr('auth.reset.request', 1);
|
||||
await ctx.render('forgot', {
|
||||
|
@ -136,7 +139,7 @@ export async function logout(ctx) {
|
|||
|
||||
|
||||
export async function activate(ctx) {
|
||||
const code = ctx.params.code;
|
||||
const { code } = ctx.params;
|
||||
if (await activateUser.call(ctx, code)) {
|
||||
ctx.statsd.incr('auth.activation', 1);
|
||||
ctx.redirect('/');
|
||||
|
|
|
@ -3,8 +3,6 @@ import kue from 'kue';
|
|||
import raven from 'raven';
|
||||
import debuglog from 'debug';
|
||||
|
||||
import models from '../models';
|
||||
|
||||
const debug = debuglog('hostr:worker');
|
||||
|
||||
raven.config(process.env.SENTRY_DSN).install();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue