Postgres.
This commit is contained in:
parent
695644c260
commit
806f42e3f8
25 changed files with 501 additions and 294 deletions
|
@ -1,63 +1,88 @@
|
|||
import passwords from 'passwords';
|
||||
import auth from 'basic-auth';
|
||||
import models from '../../models';
|
||||
import debugname from 'debug';
|
||||
const debug = debugname('hostr-api:auth');
|
||||
|
||||
const badLoginMsg = '{"error": {"message": "Incorrect login details.", "code": 607}}';
|
||||
|
||||
export default function* (next) {
|
||||
const Users = this.db.Users;
|
||||
const Files = this.db.Files;
|
||||
const Logins = this.db.Logins;
|
||||
let user = false;
|
||||
|
||||
const remoteIp = this.req.headers['x-real-ip'] || this.req.connection.remoteAddress;
|
||||
const login = yield models.login.create({
|
||||
ip: remoteIp,
|
||||
successful: false,
|
||||
});
|
||||
if (this.req.headers.authorization && this.req.headers.authorization[0] === ':') {
|
||||
debug('Logging in with token');
|
||||
const userToken = yield this.redis.get(this.req.headers.authorization.substr(1));
|
||||
this.assert(userToken, 401, '{"error": {"message": "Invalid token.", "code": 606}}');
|
||||
debug('Token found');
|
||||
user = yield Users.findOne({ _id: this.db.objectId(userToken) });
|
||||
user = yield models.user.findById(userToken);
|
||||
if (!user) {
|
||||
login.save();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
const authUser = auth(this);
|
||||
this.assert(authUser, 401, badLoginMsg);
|
||||
const remoteIp = this.req.headers['x-real-ip'] || this.req.connection.remoteAddress;
|
||||
const count = yield Logins.count({
|
||||
ip: remoteIp,
|
||||
successful: false,
|
||||
at: { $gt: Math.ceil(Date.now() / 1000) - 600 },
|
||||
const count = yield models.login.count({
|
||||
where: {
|
||||
ip: remoteIp,
|
||||
successful: false,
|
||||
createdAt: {
|
||||
$gt: new Date(Math.ceil(Date.now()) - 600000),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
this.assert(count < 25, 401,
|
||||
'{"error": {"message": "Too many incorrect logins.", "code": 608}}');
|
||||
|
||||
yield Logins.insertOne({ ip: remoteIp, at: Math.ceil(Date.now() / 1000), successful: null });
|
||||
user = yield Users.findOne({
|
||||
email: authUser.name,
|
||||
banned: { $exists: false },
|
||||
status: { $ne: 'deleted' },
|
||||
user = yield models.user.findOne({
|
||||
where: {
|
||||
email: authUser.name,
|
||||
activated: true,
|
||||
},
|
||||
});
|
||||
this.assert(user, 401, badLoginMsg);
|
||||
const authenticated = yield passwords.match(authUser.pass, user.salted_password);
|
||||
this.assert(authenticated, 401, badLoginMsg);
|
||||
|
||||
if (!user || !(yield passwords.match(authUser.pass, user.password))) {
|
||||
login.save();
|
||||
this.throw(401, badLoginMsg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
debug('Checking user');
|
||||
this.assert(user, 401, badLoginMsg);
|
||||
debug('Checking user is activated');
|
||||
this.assert(!user.activationCode, 401,
|
||||
debug(user.activated);
|
||||
this.assert(user.activated === true, 401,
|
||||
'{"error": {"message": "Account has not been activated.", "code": 603}}');
|
||||
|
||||
const uploadedTotal = yield Files.count({ owner: user._id, status: { $ne: 'deleted' } });
|
||||
const uploadedToday = yield Files.count({
|
||||
owner: user._id,
|
||||
time_added: { $gt: Math.ceil(Date.now() / 1000) - 86400 },
|
||||
login.successful = true;
|
||||
yield login.save();
|
||||
|
||||
const uploadedTotal = yield models.file.count({
|
||||
where: {
|
||||
userId: user.id,
|
||||
},
|
||||
});
|
||||
const uploadedToday = yield models.file.count({
|
||||
where: {
|
||||
userId: user.id,
|
||||
createdAt: {
|
||||
$gt: Math.ceil(Date.now() / 1000) - 86400,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const normalisedUser = {
|
||||
id: user._id,
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
daily_upload_allowance: user.type === 'Pro' ? 'unlimited' : 15,
|
||||
daily_upload_allowance: user.plan === 'Pro' ? 'unlimited' : 15,
|
||||
file_count: uploadedTotal,
|
||||
max_filesize: user.type === 'Pro' ? 524288000 : 20971520,
|
||||
plan: user.type || 'Free',
|
||||
max_filesize: user.plan === 'Pro' ? 524288000 : 20971520,
|
||||
plan: user.plan,
|
||||
uploads_today: uploadedToday,
|
||||
};
|
||||
this.response.set('Daily-Uploads-Remaining',
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import redis from 'redis';
|
||||
|
||||
import models from '../../models';
|
||||
import { formatFile } from '../../lib/format';
|
||||
import Uploader from '../../lib/uploader';
|
||||
|
||||
|
@ -20,7 +21,6 @@ export function* post(next) {
|
|||
|
||||
uploader.receive();
|
||||
|
||||
yield uploader.save();
|
||||
yield uploader.promise;
|
||||
|
||||
uploader.processingEvent();
|
||||
|
@ -31,7 +31,7 @@ export function* post(next) {
|
|||
yield uploader.finalise();
|
||||
|
||||
this.status = 201;
|
||||
this.body = uploader.toJSON();
|
||||
this.body = formatFile(uploader.file);
|
||||
|
||||
uploader.completeEvent();
|
||||
uploader.malwareScan();
|
||||
|
@ -39,48 +39,44 @@ export function* post(next) {
|
|||
|
||||
|
||||
export function* list() {
|
||||
const Files = this.db.Files;
|
||||
|
||||
let status = 'active';
|
||||
if (this.request.query.trashed) {
|
||||
status = 'trashed';
|
||||
} else if (this.request.query.all) {
|
||||
status = { $in: ['active', 'trashed'] };
|
||||
}
|
||||
|
||||
let limit = 20;
|
||||
if (this.request.query.perpage === '0') {
|
||||
limit = false;
|
||||
limit = 1000;
|
||||
} else if (this.request.query.perpage > 0) {
|
||||
limit = parseInt(this.request.query.perpage / 1, 10);
|
||||
}
|
||||
|
||||
let skip = 0;
|
||||
let offset = 0;
|
||||
if (this.request.query.page) {
|
||||
skip = parseInt(this.request.query.page - 1, 10) * limit;
|
||||
offset = parseInt(this.request.query.page - 1, 10) * limit;
|
||||
}
|
||||
|
||||
const queryOptions = {
|
||||
limit, skip, sort: [['time_added', 'desc']],
|
||||
hint: {
|
||||
owner: 1, status: 1, time_added: -1,
|
||||
const files = yield models.file.findAll({
|
||||
where: {
|
||||
userId: this.user.id,
|
||||
status: 'active',
|
||||
},
|
||||
};
|
||||
order: '"createdAt" DESC',
|
||||
offset,
|
||||
limit,
|
||||
});
|
||||
|
||||
const userFiles = yield Files.find({
|
||||
owner: this.user.id, status }, queryOptions).toArray();
|
||||
this.statsd.incr('file.list', 1);
|
||||
this.body = userFiles.map(formatFile);
|
||||
this.body = files.map(formatFile);
|
||||
}
|
||||
|
||||
|
||||
export function* get() {
|
||||
const Files = this.db.Files;
|
||||
const Users = this.db.Users;
|
||||
const file = yield Files.findOne({ _id: this.params.id,
|
||||
status: { $in: ['active', 'uploading'] } });
|
||||
const file = yield models.file.findOne({
|
||||
where: {
|
||||
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 });
|
||||
const user = yield file.getUser();
|
||||
this.assert(user && !user.banned, 404, '{"error": {"message": "File not found", "code": 604}}');
|
||||
this.statsd.incr('file.get', 1);
|
||||
this.body = formatFile(file);
|
||||
|
@ -89,17 +85,28 @@ export function* get() {
|
|||
|
||||
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: this.params.id, owner: this.user.id },
|
||||
{ $set: { status } }, { w: 1 });
|
||||
const file = yield models.file.findOne({
|
||||
where: {
|
||||
id: this.params.id,
|
||||
userId: this.user.id,
|
||||
},
|
||||
});
|
||||
file.status = this.request.body.trashed ? 'trashed' : 'active';
|
||||
yield file.save();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function* del() {
|
||||
yield this.db.Files.updateOne({ _id: this.params.id, owner: this.db.objectId(this.user.id) },
|
||||
{ $set: { status: 'deleted' } }, { w: 1 });
|
||||
const file = yield models.file.findOne({
|
||||
where: {
|
||||
id: this.params.id,
|
||||
userId: this.user.id,
|
||||
},
|
||||
});
|
||||
this.assert(file, 401, '{"error": {"message": "File not found", "code": 604}}');
|
||||
file.status = 'deleted';
|
||||
yield file.save();
|
||||
const event = { type: 'file-deleted', data: { id: this.params.id } };
|
||||
yield this.redis.publish(`/file/${this.params.id}`, JSON.stringify(event));
|
||||
yield this.redis.publish(`/user/${this.user.id}`, JSON.stringify(event));
|
||||
|
|
|
@ -2,6 +2,7 @@ import uuid from 'node-uuid';
|
|||
import redis from 'redis';
|
||||
import co from 'co';
|
||||
import passwords from 'passwords';
|
||||
import models from '../../models';
|
||||
|
||||
import debugname from 'debug';
|
||||
const debug = debugname('hostr-api:user');
|
||||
|
@ -19,17 +20,15 @@ export function* token() {
|
|||
}
|
||||
|
||||
export function* transaction() {
|
||||
const Transactions = this.db.Transactions;
|
||||
const transactions = yield Transactions.find({ user_id: this.user.id }).toArray();
|
||||
const transactions = yield models.transaction.findAll({ userId: this.user.id });
|
||||
|
||||
this.body = transactions.map((transaction) => { // eslint-disable-line no-shadow
|
||||
const type = transaction.paypal ? 'paypal' : 'direct';
|
||||
this.body = transactions.map((item) => {
|
||||
return {
|
||||
id: transaction._id,
|
||||
amount: transaction.paypal ? transaction.amount : transaction.amount / 100,
|
||||
date: transaction.date,
|
||||
description: transaction.desc,
|
||||
type,
|
||||
id: item.id,
|
||||
amount: item.amount / 100,
|
||||
date: item.date,
|
||||
description: item.description,
|
||||
type: 'direct',
|
||||
};
|
||||
});
|
||||
}
|
||||
|
@ -39,23 +38,18 @@ export function* settings() {
|
|||
'{"error": {"message": "Current Password required to update account.", "code": 612}}');
|
||||
this.assert(this.request.body.current_password, 400,
|
||||
'{"error": {"message": "Current Password required to update account.", "code": 612}}');
|
||||
const Users = this.db.Users;
|
||||
const user = yield Users.findOne({ _id: this.user.id });
|
||||
this.assert(yield passwords.match(this.request.body.current_password, user.salted_password), 400,
|
||||
const user = yield models.user.findById(this.user.id);
|
||||
this.assert(yield passwords.match(this.request.body.current_password, user.password), 400,
|
||||
'{"error": {"message": "Incorrect password", "code": 606}}');
|
||||
const data = {};
|
||||
if (this.request.body.email && this.request.body.email !== user.email) {
|
||||
data.email = this.request.body.email;
|
||||
if (!user.activated_email) {
|
||||
data.activated_email = user.email; // eslint-disable-line camelcase
|
||||
}
|
||||
user.email = this.request.body.email;
|
||||
}
|
||||
if (this.request.body.new_password) {
|
||||
this.assert(this.request.body.new_password.length >= 7, 400,
|
||||
'{"error": {"message": "Password must be 7 or more characters long.", "code": 606}}');
|
||||
data.salted_password = yield passwords.hash(this.request.body.new_password);
|
||||
user.password = yield passwords.hash(this.request.body.new_password);
|
||||
}
|
||||
Users.updateOne({ _id: user._id }, { $set: data });
|
||||
yield user.save();
|
||||
this.body = {};
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue