Fix linting
This commit is contained in:
parent
553ba9db9a
commit
bb5189c9ed
35 changed files with 157 additions and 866 deletions
|
@ -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' });
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue