Migrate from koa-route to koa-router

This commit is contained in:
Jonathan Cremin 2015-08-22 16:16:15 +01:00
parent 8474cca94c
commit a4bf3dd51d
17 changed files with 206 additions and 291 deletions

View file

@ -1,63 +1,29 @@
import koa from 'koa';
import route from 'koa-route';
import Router from 'koa-router';
import stats from 'koa-statsd';
import websockify from 'koa-websocket';
import logger from 'koa-logger';
import compress from 'koa-compress';
import bodyparser from 'koa-bodyparser';
import cors from 'kcors';
import co from 'co';
import raven from 'raven';
import StatsD from 'statsy';
import auth from './lib/auth';
import mongo from '../lib/mongo';
import redis from '../lib/redis';
import * as user from './routes/user';
import * as file from './routes/file';
import debugname from 'debug';
const debug = debugname('hostr-api');
import StatsD from 'statsy';
if (process.env.SENTRY_DSN) {
const ravenClient = new raven.Client(process.env.SENTRY_DSN);
ravenClient.patchGlobal();
}
const app = websockify(koa());
app.use(function* (next){
this.set('Server', 'Nintendo 64');
if(this.req.headers['x-forwarded-proto'] === 'http'){
return this.redirect('https://' + this.req.headers.host + this.req.url);
}
yield next;
});
const router = new Router();
let statsdOpts = {prefix: 'hostr-api', host: process.env.STATSD_HOST || 'localhost'};
let statsd = new StatsD(statsdOpts);
app.use(function*(next) {
router.use(function*(next) {
this.statsd = statsd;
yield next;
});
app.use(stats(statsdOpts));
router.use(stats(statsdOpts));
app.use(logger());
app.use(cors({
router.use(cors({
origin: '*',
credentials: true
}));
app.use(mongo());
app.use(redis());
app.ws.use(mongo());
app.ws.use(redis());
app.use(route.get('/', function* (){
this.status = 200;
this.body = '';
}));
app.use(function* (next){
router.use('/*',function* (next) {
try {
yield next;
if (this.response.status === 404 && !this.response.body) {
@ -90,34 +56,21 @@ app.use(function* (next){
this.type = 'application/json';
});
app.use(compress());
app.use(bodyparser());
router.get('/user', auth, user.get);
router.get('/user/token', auth, user.token);
router.get('/token', auth, user.token);
router.get('/user/transaction', auth, user.transaction);
router.post('/user/settings', auth, user.settings);
router.get('/file', auth, file.list);
router.post('/file', auth, file.post);
router.get('/file/:id', file.get);
router.put('/file/:id', auth, file.put);
router.delete('/file/:id', auth, file.del);
router.delete('/file/:id', auth, file.del);
app.ws.use(route.all('/file/:id', file.events));
app.ws.use(route.all('/user', user.events));
// Hack, if no route matches here, router does not dispatch at all
router.get('/(.*)', function* () {
this.throw(404);
});
app.use(route.get('/file/:id', file.get));
// Run auth middleware before all other endpoints
app.use(auth);
app.use(route.get('/user', user.get));
app.use(route.get('/user/token', user.token));
app.use(route.get('/token', user.token));
app.use(route.get('/user/transaction', user.transaction));
app.use(route.post('/user/settings', user.settings));
app.use(route.get('/file', file.list));
app.use(route.post('/file', file.post));
app.use(route.put('/file/:id', file.put));
app.use(route.delete('/file/:id', file.del));
if (!module.parent) {
app.listen(process.env.PORT || 4042, function() {
debug('Koa HTTP server listening on port ' + (process.env.PORT || 4042));
});
setInterval(function() {
debug('%sMB', process.memoryUsage().rss / 1024 / 1024);
}, 10000);
}
export default app;
export default router;

View file

@ -224,10 +224,10 @@ export function* list() {
}
export function* get(id) {
export function* get() {
const Files = this.db.Files;
const Users = this.db.Users;
const file = yield Files.findOne({_id: id, status: {'$in': ['active', 'uploading']}});
const file = yield Files.findOne({_id: this.params.id, status: {'$in': ['active', 'uploading']}});
this.assert(file, 404, '{"error": {"message": "File not found", "code": 604}}');
const user = yield Users.findOne({_id: file.owner});
this.assert(user && !user.banned, 404, '{"error": {"message": "File not found", "code": 604}}');
@ -236,22 +236,23 @@ export function* get(id) {
}
export function* put(id) {
export function* put() {
if (this.request.body.trashed) {
const Files = this.db.Files;
const status = this.request.body.trashed ? 'trashed' : 'active';
yield Files.updateOne({'_id': id, owner: this.user.id}, {$set: {status: status}}, {w: 1});
yield Files.updateOne({'_id': this.params.id, owner: this.user.id}, {$set: {status: status}}, {w: 1});
}
}
export function* del(id) {
export function* del() {
const Files = this.db.Files;
yield Files.updateOne({'_id': id, owner: this.user.id}, {$set: {status: 'deleted'}}, {w: 1});
const event = {type: 'file-deleted', data: {'id': id}};
yield Files.updateOne({'_id': this.params.id, owner: this.db.ObjectId(this.user.id)}, {$set: {status: 'deleted'}}, {w: 1});
const event = {type: 'file-deleted', data: {'id': this.params.id}};
yield this.redis.publish('/user/' + this.user.id, JSON.stringify(event));
yield this.redis.publish('/file/' + id, JSON.stringify(event));
yield this.redis.publish('/file/' + this.params.id, JSON.stringify(event));
this.statsd.incr('file.delete', 1);
this.status = 204;
this.body = '';
}

40
app.js
View file

@ -1,31 +1,53 @@
import path from 'path';
import koa from 'koa';
import mount from 'koa-mount';
import route from 'koa-route';
import logger from 'koa-logger';
import Router from 'koa-router';
import serve from 'koa-static';
import favicon from 'koa-favicon';
import compress from 'koa-compress';
import bodyparser from 'koa-bodyparser';
import websockify from 'koa-websocket';
import raven from 'raven';
import mongo from './lib/mongo';
import redis from './lib/redis';
import co from 'co';
import api from './api/app';
import { events as fileEvents } from './api/routes/file';
import { events as userEvents } from './api/routes/user';
import web from './web/app';
import { init as storageInit } from './lib/storage';
storageInit();
import debugname from 'debug';
const debug = debugname('hostr');
storageInit();
if (process.env.SENTRY_DSN) {
const ravenClient = new raven.Client(process.env.SENTRY_DSN);
ravenClient.patchGlobal();
}
const app = websockify(koa());
app.keys = [process.env.KEYS || 'INSECURE'];
app.ws.use(redis());
app.use(function* (next){
this.set('Server', 'Nintendo 64');
if(this.req.headers['x-forwarded-proto'] === 'http'){
return this.redirect('https://' + this.req.headers.host + this.req.url);
}
yield next;
});
app.ws.use(route.all('/api/user', userEvents));
app.ws.use(route.all('/api/file/:id', fileEvents));
app.use(mongo());
app.use(redis());
app.use(logger());
app.use(compress());
app.use(bodyparser());
app.use(mount('/api', api));
app.use(mount('/', web));
app.use(favicon(path.join(__dirname, 'web/public/images/favicon.png')));
app.use(serve(path.join(__dirname, 'web/public/'), {maxage: 31536000000}));
app.use(api.prefix('/api').routes());
app.use(web.prefix('').routes());
if (!module.parent) {
app.listen(process.env.PORT || 4040, function() {

View file

@ -17,6 +17,7 @@ let configuredClient = new Promise(function (resolve, reject) {
client.Reset = client.collection('reset');
client.Remember.ensureIndex({'created': 1}, {expireAfterSeconds: 2592000});
client.Files.ensureIndex({'owner': 1, 'status': 1, 'time_added': -1});
client.ObjectId = mongodb().ObjectId;
return resolve(client);
}).catch((e) => {
reject(e)

View file

@ -47,6 +47,8 @@
"koa-mount": "~1.3.0",
"koa-redis": "~1.0.0",
"koa-route": "~2.4.2",
"koa-router": "^5.1.2",
"koa-static": "^1.4.9",
"koa-statsd": "~0.0.2",
"koa-views": "~3.1.0",
"koa-websocket": "~1.0.0",

View file

@ -1,5 +1,5 @@
import { agent } from 'supertest';
import app from '../../api/app';
import app from '../../app';
const request = agent(app.listen());
@ -8,7 +8,7 @@ describe('hostr-api auth', function(){
describe('with no credentials', function(){
it('should `throw` 401', function(done){
request
.get('/user')
.get('/api/user')
.expect(401, done);
});
});
@ -16,18 +16,19 @@ describe('hostr-api auth', function(){
describe('with invalid credentials', function(){
it('should `throw` 401', function(done){
request
.get('/user')
.get('/api/user')
.auth('user', 'invalid password')
.expect(401, done);
});
});
describe('with valid credentials', function(){
it('should call the next middleware', function(done){
it('should 404', function(done){
request
.get('/')
.get('/api/')
.auth('test@hostr.co', 'test-password')
.expect(200, done);
.expect('Content-type', /application\/json/)
.expect(404, done);
});
});
});

View file

@ -1,6 +1,6 @@
import assert from 'assert';
import { agent } from 'supertest';
import app from '../../api/app';
import app from '../../app';
const request = agent(app.listen());
@ -11,7 +11,7 @@ describe('hostr-api file', function() {
describe('when GET /file', function() {
it('should receive a list of file objects', function(done) {
request
.get('/file')
.get('/api/file')
.auth('test@hostr.co', 'test-password')
.expect(200)
.expect(function(response) {
@ -25,7 +25,7 @@ describe('hostr-api file', function() {
it('should receive a new file object', function(done) {
this.timeout(30000);
request
.post('/file')
.post('/api/file')
.attach('file', 'test/fixtures/utah-arches.jpg')
.auth('test@hostr.co', 'test-password')
.expect(201)
@ -40,7 +40,7 @@ describe('hostr-api file', function() {
describe('when GET /file/:id', function() {
it('should receive the file object', function(done) {
request
.get('/file/' + id)
.get('/api/file/' + id)
.expect(200)
.expect(function(response) {
assert(response.body.name === 'utah-arches.jpg');
@ -52,16 +52,16 @@ describe('hostr-api file', function() {
describe('when DELETE /file/:id', function() {
it('should delete the file object', function(done) {
request
.delete('/file/' + id)
.delete('/api/file/' + id)
.auth('test@hostr.co', 'test-password')
.expect(200, done);
.expect(204, done);
});
});
describe('when GET deleted /file/:id', function() {
it('should not receive the file object', function(done) {
request
.get('/file/' + id)
.get('/api/file/' + id)
.expect(404, done);
});
});

View file

@ -1,6 +1,6 @@
import assert from 'assert';
import { agent } from 'supertest';
import app from '../../api/app';
import app from '../../app';
const request = agent(app.listen());
@ -9,7 +9,7 @@ describe('hostr-api user', function() {
describe('when GET /user', function() {
it('should receive a user object', function(done) {
request
.get('/user')
.get('/api/user')
.auth('test@hostr.co', 'test-password')
.expect(function(response) {
assert(response.body.id === '54fd04a37675bcd06213eac8');
@ -22,7 +22,7 @@ describe('hostr-api user', function() {
describe('when GET /user/token', function() {
it('should receive a user token object', function(done) {
request
.get('/user/token')
.get('/api/user/token')
.auth('test@hostr.co', 'test-password')
.expect(function(response) {
assert(response.body.token);
@ -35,7 +35,7 @@ describe('hostr-api user', function() {
describe('when GET /user/transaction', function() {
it('should receive a user transactions object', function(done) {
request
.get('/user/transaction')
.get('/api/user/transaction')
.auth('test@hostr.co', 'test-password')
.expect(200)
.expect(function(response) {
@ -48,7 +48,7 @@ describe('hostr-api user', function() {
describe('when GET /user/settings', function() {
it('should update user password', function(done) {
request
.post('/user/settings')
.post('/api/user/settings')
.send({'current_password': 'test-password', 'new_password': 'test-password' })
.auth('test@hostr.co', 'test-password')
.expect(200)

View file

@ -3,19 +3,3 @@ db.files.createIndex({
"status": 1,
"time_added": -1
});
db.files.save({"_id": "94U1ruo7anyQ",
"owner": ObjectId("54fd04a37675bcd06213eac8"),
"system_name": "94U1ruo7anyQ",
"file_name": "utah-arches.jpg",
"original_name": "utah-arches.jpg",
"file_size": 194544,
"time_added": 1436223854,
"status": "active",
"last_accessed": null,
"s3": true,
"type": "image",
"ip": "::1",
"md5": "1f4185751b4db05494cbc0aad68d7d77",
"width": 1024,
"height": 683
});

View file

@ -1,19 +1,16 @@
import web from '../../web/app';
import api from '../../api/app';
import assert from 'assert';
import { agent } from 'supertest';
import app from '../../app';
const request = agent(web.listen());
const apiRequest = agent(api.listen());
const request = agent(app.listen());
let file = {};
describe('setup hostr-web file', function() {
describe('when POSTing a file to /file', function() {
it('should receive a new file object', function(done) {
this.timeout(30000);
apiRequest
.post('/file')
request
.post('/api/file')
.attach('file', 'test/fixtures/utah-arches.jpg')
.auth('test@hostr.co', 'test-password')
.expect(201)

View file

@ -1,5 +1,5 @@
import app from '../../web/app';
import { agent } from 'supertest';
import app from '../../app';
const request = agent(app.listen());

View file

@ -1,23 +1,15 @@
import path from 'path';
import koa from 'koa';
import Router from 'koa-router';
import csrf from 'koa-csrf';
import route from 'koa-route';
import views from 'koa-views';
import stats from 'koa-statsd';
import logger from 'koa-logger';
import favicon from 'koa-favicon';
import redisStore from 'koa-redis';
import compress from 'koa-compress';
import bodyparser from 'koa-bodyparser';
import redis from '../lib/redis';
import koaRedis from 'koa-redis'
import session from 'koa-generic-session';
import staticHandler from 'koa-file-server';
import co from 'co';
import raven from 'raven';
import StatsD from 'statsy';
// waiting for PR to be merged, can remove swig dependency when done
import errors from '../lib/koa-error';
import mongo from '../lib/mongo';
import redis from '../lib/redis';
import * as index from './routes/index';
import * as file from './routes/file';
import * as pro from './routes/pro';
@ -26,35 +18,24 @@ import * as user from './routes/user';
import debugname from 'debug';
const debug = debugname('hostr-web');
if (process.env.SENTRY_DSN) {
const ravenClient = new raven.Client(process.env.SENTRY_DSN);
ravenClient.patchGlobal();
}
const redisUrl = process.env.REDIS_URL || process.env.REDISTOGO_URL || 'redis://localhost:6379';
const app = koa();
const router = new Router();
router.use(errors({template: path.join(__dirname, 'public', '404.html')}));
let statsdOpts = {prefix: 'hostr-web', host: process.env.STATSD_HOST || 'localhost'};
let statsd = new StatsD(statsdOpts);
app.use(function*(next) {
router.use(function* (next) {
this.statsd = statsd;
yield next;
});
app.use(stats(statsdOpts));
router.use(stats(statsdOpts));
app.use(errors({template: path.join(__dirname, 'public', '404.html')}));
router.use(session({
store: koaRedis({client: redis().client})
}));
app.use(function*(next){
this.set('Server', 'Nintendo 64');
if(this.req.headers['x-forwarded-proto'] === 'http'){
return this.redirect('https://' + this.request.headers.host + this.request.url);
}
yield next;
});
app.use(function*(next){
router.use(function* (next){
this.state = {
session: this.session,
apiURL: process.env.API_URL,
baseURL: process.env.BASE_URL,
stripePublic: process.env.STRIPE_PUBLIC_KEY
@ -62,70 +43,49 @@ app.use(function*(next){
yield next;
});
app.use(mongo());
app.use(redis());
app.use(compress());
app.use(bodyparser());
app.use(favicon(path.join(__dirname, 'public/images/favicon.png')));
app.use(staticHandler({root: path.join(__dirname, 'public'), maxage: 31536000000}));
app.use(logger());
app.use(views('views', {
router.use(views('views', {
default: 'ejs'
}));
app.keys = [process.env.KEYS || 'INSECURE'];
app.use(session({
store: redisStore({client: redis().client})
}));
router.get('/', index.main);
router.get('/account', index.main);
router.get('/billing', index.main);
router.get('/pro', index.main);
app.use(route.get('/', index.main));
app.use(route.get('/account', index.main));
app.use(route.get('/billing', index.main));
app.use(route.get('/pro', index.main));
router.get('/signin', user.signin);
router.post('/signin', user.signin);
router.get('/signup', user.signup);
router.post('/signup', user.signup);
router.get('/logout', user.logout);
router.post('/logout', user.logout);
router.get('/forgot', user.forgot);
router.get('/forgot/:token', user.forgot);
router.post('/forgot/:token', user.forgot);
router.post('/forgot', user.forgot);
router.get('/activate/:code', user.activate);
app.use(route.get('/signin', user.signin));
app.use(route.post('/signin', user.signin));
app.use(route.get('/signup', user.signup));
app.use(route.post('/signup', user.signup));
app.use(route.get('/logout', user.logout));
app.use(route.post('/logout', user.logout));
app.use(route.get('/forgot', user.forgot));
app.use(route.get('/forgot/:token', user.forgot));
app.use(route.post('/forgot/:token', user.forgot));
app.use(route.post('/forgot', user.forgot));
app.use(route.get('/activate/:code', user.activate));
router.get('/terms', index.staticPage);
router.get('/privacy', index.staticPage);
router.get('/pricing', index.staticPage);
router.get('/apps', index.staticPage);
router.get('/stats', index.staticPage);
app.use(route.get('/terms', index.staticPage));
app.use(route.get('/privacy', index.staticPage));
app.use(route.get('/pricing', index.staticPage));
app.use(route.get('/apps', index.staticPage));
app.use(route.get('/stats', index.staticPage));
router.post('/pro/create', pro.create);
router.post('/pro/cancel', pro.cancel);
app.use(route.post('/pro/create', pro.create));
app.use(route.post('/pro/cancel', pro.cancel));
app.use(route.get('/:id', file.landing));
app.use(route.get('/download/:id/:name', function* (id) {
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* (id) {
this.redirect('/' + id);
}));
app.use(route.get('/file/:id/:name', file.get));
app.use(route.get('/files/:id/:name', file.get));
app.use(route.get('/file/:size/:id/:name', file.resized));
});
app.use(route.get('/updaters/mac', function* () {
router.get('/updaters/mac', function* () {
this.redirect('/updaters/mac.xml');
}));
app.use(route.get('/updaters/mac/changelog', function* () {
});
router.get('/updaters/mac/changelog', function* () {
yield this.render('mac-update-changelog');
}));
});
if (!module.parent) {
app.listen(process.env.PORT || 4041, function() {
debug('Koa HTTP server listening on port ' + (process.env.PORT || 4041));
});
setInterval(function() {
debug('%sMB', process.memoryUsage().rss / 1024 / 1024);
}, 10000);
}
export default app;
export default router;

View file

@ -7,11 +7,12 @@ import debugname from 'debug';
const debug = debugname('hostr-web:auth');
import { Mandrill } from 'mandrill-api/mandrill';
const mandrill = new Mandrill(process.env.MANDRILL_KEY);
import mongo from '../../lib/mongo';
export function* authenticate(ctx, email, password) {
const Users = ctx.db.Users;
const Logins = ctx.db.Logins;
const remoteIp = ctx.headers['x-real-ip'] || ctx.ip;
export function* authenticate(email, password) {
const Users = this.db.Users;
const Logins = this.db.Logins;
const remoteIp = this.headers['x-real-ip'] || this.ip;
if (!password || password.length < 6){
debug('No password, or password too short');
@ -45,10 +46,10 @@ export function* authenticate(ctx, email, password) {
}
export function* setupSession(ctx, user) {
export function* setupSession(user) {
debug('Setting up session');
const token = uuid.v4();
yield ctx.redis.set(token, user._id, 'EX', 604800);
yield this.redis.set(token, user._id, 'EX', 604800);
const sessionUser = {
'id': user._id,
@ -67,19 +68,19 @@ export function* setupSession(ctx, user) {
sessionUser.dailyUploadAllowance = 'unlimited';
}
ctx.session.user = sessionUser;
if (ctx.request.body.remember && ctx.request.body.remember === 'on') {
const Remember = ctx.db.Remember;
this.session.user = sessionUser;
if (this.request.body.remember && this.request.body.remember === 'on') {
const Remember = this.db.Remember;
var rememberToken = uuid();
Remember.save({_id: rememberToken, 'user_id': user.id, created: new Date().getTime()});
ctx.cookies.set('r', rememberToken, { maxAge: 1209600000, httpOnly: true});
this.cookies.set('r', rememberToken, { maxAge: 1209600000, httpOnly: true});
}
debug('Session set up');
}
export function* signup(ctx, email, password, ip) {
const Users = ctx.db.Users;
export function* signup(email, password, ip) {
const Users = this.db.Users;
const existingUser = yield Users.findOne({email: email, status: {'$ne': 'deleted'}});
if (existingUser) {
debug('Email already in use.');
@ -120,9 +121,9 @@ ${process.env.BASE_URL + '/activate/' + user.activationCode}
}
export function* sendResetToken(ctx, email) {
const Users = ctx.db.Users;
const Reset = ctx.db.Reset;
export function* sendResetToken(email) {
const Users = this.db.Users;
const Reset = this.db.Reset;
const user = yield Users.findOne({email: email});
if (user) {
var token = uuid.v4();
@ -155,40 +156,40 @@ Visit ${process.env.BASE_URL + '/forgot/' + token} to set a new one.
}
export function* fromToken(ctx, token) {
const Users = ctx.db.Users;
const reply = yield ctx.redis.get(token);
export function* fromToken(token) {
const Users = this.db.Users;
const reply = yield this.redis.get(token);
return yield Users.findOne({_id: reply});
}
export function* fromCookie(ctx, cookie) {
const Remember = ctx.db.Remember;
const Users = ctx.db.Users;
export function* fromCookie(cookie) {
const Remember = this.db.Remember;
const Users = this.db.Users;
const remember = yield Remember.findOne({_id: cookie});
return yield Users.findOne({_id: remember.user_id});
}
export function* validateResetToken(ctx) {
const Reset = ctx.db.Reset;
return yield Reset.findOne({token: ctx.params.id});
export function* validateResetToken() {
const Reset = this.db.Reset;
return yield Reset.findOne({token: this.params.id});
}
export function* updatePassword(ctx, userId, password) {
const Users = ctx.db.Users;
export function* updatePassword(userId, password) {
const Users = this.db.Users;
const cryptedPassword = yield passwords.crypt(password);
yield Users.update({_id: userId}, {'$set': {'salted_password': cryptedPassword}});
}
export function* activateUser(ctx, code) {
const Users = ctx.db.Users;
export function* activateUser(code) {
const Users = this.db.Users;
const user = yield Users.findOne({activationCode: code});
if (user) {
Users.updateOne({_id: user._id}, {'$unset': {activationCode: ''}});
yield setupSession(ctx, user);
yield setupSession(this, user);
} else {
return false;
}

View file

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html>
<html style='height:100%;'>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
@ -10,29 +10,23 @@
<link href='//fonts.googleapis.com/css?family=Open+Sans:400,300,600' rel='stylesheet' type='text/css'>
<link href="/styles/app.css" rel="stylesheet" />
</head>
<body>
<section class="container header clearfix">
<div class="row">
<div class="col-md-8 col-md-offset-2" style='text-align: center;'>
<div class="logo">
<a href="/"><img src="/images/logo-dark-r.png" height="22" width="26" alt=""></a>
<body class='error'>
<div class='container main'>
<div class='row'>
<div class='col-md-12'>
<div class='error-logo'>
<a href='/'><img src='/images/logo-dark-r.png' width='26' height='22' /></a>
</div>
</div>
</div>
</section>
<section class="jumbotron error-page">
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<h1>Oops!</h1>
<h2>It looks like you've hit an unexpected error :(</h2>
<p class="lead">Refreshing might fix the problem. If not, sit tight! We're on it!</p>
</div>
<div class='row vertical-center'>
<div class='col-md-12'>
<h2><%=err.status%></h2>
<h1>Sorry, It looks like you've hit an unexpected error.</h1>
<p class="lead">Refreshing might fix the problem. If not, sit tight! We're on it!</p>
</div>
</div>
</section>
</div>
<script>
var _gaq=[['_setAccount','UA-66209-2'],['_setDomainName', 'hostr.co'],['_trackPageview']];

View file

@ -34,7 +34,7 @@ export class FileController {
$rootScope.pageTitle = ' - ' + file.name;
if (file.status === 'uploading') {
file.percent = 0;
var ws = new ReconnectingWebSocket('wss://' + window.location.hostname + window.settings.api + '/file/' + file.id);
var ws = new ReconnectingWebSocket(window.settings.apiURL.replace(/^http/, 'ws') + '/file/' + file.id);
ws.onmessage = function (msg) {
var evt = JSON.parse(msg.data);
$rootScope.$broadcast(evt.type, evt.data);

View file

@ -20,39 +20,39 @@ const hotlinkCheck = function(file, userAgent, referrer) {
return !userAgentCheck(userAgent) && !file.width && (!referrer || !(referrer.match(/^https:\/\/hostr.co/) || referrer.match(/^http:\/\/localhost:4040/)))
};
export function* get(id, name, size) {
const file = yield this.db.Files.findOne({_id: id, 'file_name': name, 'status': 'active'});
export function* get() {
const file = yield this.db.Files.findOne({_id: this.params.id, 'file_name': this.params.name, 'status': 'active'});
this.assert(file, 404);
if (hotlinkCheck(file, this.headers['user-agent'], this.headers['referer'])) {
return this.redirect('/' + id);
return this.redirect('/' + file._id);
}
if (!file.width && this.request.query.warning != 'on') {
return this.redirect('/' + id);
return this.redirect('/' + file._id);
}
if (file.malware) {
let alert = this.request.query.alert;
if (!alert || !alert.match(/i want to download malware/i)) {
return this.redirect('/' + id);
return this.redirect('/' + file._id);
}
}
let localPath = path.join(storePath, file._id[0], file._id + '_' + file.file_name);
let remotePath = path.join(file._id[0], file._id + '_' + file.file_name);
if (size > 0) {
localPath = path.join(storePath, file._id[0], size, file._id + '_' + file.file_name);
remotePath = path.join(size, file._id + '_' + file.file_name);
if (this.params.size > 0) {
localPath = path.join(storePath, file._id[0], this.params.size, file._id + '_' + file.file_name);
remotePath = path.join(this.params.size, file._id + '_' + file.file_name);
}
console.log(localPath);
if (file.malware) {
this.statsd.incr('file.malware.download', 1);
}
let type = 'application/octet-stream';
if (file.width > 0) {
if (size) {
if (this.params.size) {
this.statsd.incr('file.view', 1);
}
type = mime.lookup(file.file_name);
@ -71,19 +71,18 @@ export function* get(id, name, size) {
this.body = yield hostrFileStream(localPath, remotePath);
}
export function* resized(size, id, name) {
yield get.call(this, id, name, size);
export function* resized() {
yield get.call(this);
}
export function* landing(id, next) {
if (id === 'config.js') {
return yield next;
}
const file = yield this.db.Files.findOne({_id: id});
export function* landing() {
const file = yield this.db.Files.findOne({_id: this.params.id, status: 'active'});
this.assert(file, 404);
if(userAgentCheck(this.headers['user-agent'])) {
return yield get.call(this, file._id, file.file_name);
this.params.name = file.file_name;
return yield get.call(this);
}
console.log('incr')
this.statsd.incr('file.landing', 1);
const formattedFile = formatFile(file);
yield this.render('file', {file: formattedFile});

View file

@ -6,7 +6,7 @@ export function* signin() {
}
this.statsd.incr('auth.attempt', 1);
const user = yield authenticate(this, this.request.body.email, this.request.body.password);
const user = yield authenticate.call(this, this.request.body.email, this.request.body.password);
if(!user) {
this.statsd.incr('auth.failure', 1);
return yield this.render('signin', {error: 'Invalid login details', csrf: this.csrf});
@ -14,7 +14,7 @@ export function* signin() {
return yield this.render('signin', {error: 'Your account hasn\'t been activated yet. Check your for an activation email.', csrf: this.csrf});
} else {
this.statsd.incr('auth.success', 1);
yield setupSession(this, user);
yield setupSession.call(this, user);
this.redirect('/');
}
}
@ -36,7 +36,7 @@ export function* signup() {
const email = this.request.body.email;
const password = this.request.body.password;
try {
yield signupUser(this, email, password, ip);
yield signupUser.call(this, email, password, ip);
} catch (e) {
return yield this.render('signup', {error: e.message, csrf: this.csrf});
}
@ -50,23 +50,23 @@ export function* forgot(token) {
const Users = this.db.Users;
if (this.request.body.email) {
var email = this.request.body.email;
yield sendResetToken(this, email);
yield sendResetToken.call(this, email);
this.statsd.incr('auth.reset.request', 1);
return yield this.render('forgot', {message: 'We\'ve sent an email with a link to reset your password. Be sure to check your spam folder if you it doesn\'t appear within a few minutes', token: null, csrf: this.csrf});
} else if (token && this.request.body.password) {
if (this.request.body.password.length < 7) {
return yield this.render('forgot', {error: 'Password needs to be at least 7 characters long.', token: token, csrf: this.csrf});
}
const tokenUser = yield validateResetToken(this, token);
const tokenUser = yield validateResetToken.call(this, token);
var userId = tokenUser._id;
yield updatePassword(this, userId, this.request.body.password);
yield updatePassword.call(this, userId, this.request.body.password);
yield Reset.remove({_id: userId});
const user = yield Users.findOne({_id: userId});
yield setupSession(this, user);
yield setupSession.call(this, user);
this.statsd.incr('auth.reset.success', 1);
this.redirect('/');
} else if (token.length) {
const tokenUser = yield validateResetToken(this, token);
const tokenUser = yield validateResetToken.call(this, token);
if (!tokenUser) {
this.statsd.incr('auth.reset.fail', 1);
return yield this.render('forgot', {error: 'Invalid password reset token. It might be expired, or has already been used.', token: null, csrf: this.csrf});
@ -88,7 +88,7 @@ export function* logout() {
export function* activate(code) {
if (yield activateUser(this, code)) {
if (yield activateUser.call(this, code)) {
this.statsd.incr('auth.activation', 1);
}
this.redirect('/');