Migrate from koa-route to koa-router
This commit is contained in:
parent
8474cca94c
commit
a4bf3dd51d
17 changed files with 206 additions and 291 deletions
93
api/app.js
93
api/app.js
|
@ -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;
|
||||
|
|
|
@ -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
40
app.js
|
@ -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() {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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)
|
||||
|
|
16
test/fixtures/mongo-file.js
vendored
16
test/fixtures/mongo-file.js
vendored
|
@ -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
|
||||
});
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import app from '../../web/app';
|
||||
import { agent } from 'supertest';
|
||||
import app from '../../app';
|
||||
|
||||
const request = agent(app.listen());
|
||||
|
||||
|
|
132
web/app.js
132
web/app.js
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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']];
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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});
|
||||
|
|
|
@ -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('/');
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue