summaryrefslogtreecommitdiff
path: root/src/server/api/private/signin.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/api/private/signin.ts')
-rw-r--r--src/server/api/private/signin.ts89
1 files changed, 89 insertions, 0 deletions
diff --git a/src/server/api/private/signin.ts b/src/server/api/private/signin.ts
new file mode 100644
index 0000000000..5450c7ad27
--- /dev/null
+++ b/src/server/api/private/signin.ts
@@ -0,0 +1,89 @@
+import * as Koa from 'koa';
+import * as bcrypt from 'bcryptjs';
+import * as speakeasy from 'speakeasy';
+import User, { ILocalUser } from '../../../models/user';
+import Signin, { pack } from '../../../models/signin';
+import event from '../../../publishers/stream';
+import signin from '../common/signin';
+import config from '../../../config';
+
+export default async (ctx: Koa.Context) => {
+ ctx.set('Access-Control-Allow-Origin', config.url);
+ ctx.set('Access-Control-Allow-Credentials', 'true');
+
+ const username = ctx.request.body['username'];
+ const password = ctx.request.body['password'];
+ const token = ctx.request.body['token'];
+
+ if (typeof username != 'string') {
+ ctx.status = 400;
+ return;
+ }
+
+ if (typeof password != 'string') {
+ ctx.status = 400;
+ return;
+ }
+
+ if (token != null && typeof token != 'string') {
+ ctx.status = 400;
+ return;
+ }
+
+ // Fetch user
+ const user = await User.findOne({
+ usernameLower: username.toLowerCase(),
+ host: null
+ }, {
+ fields: {
+ data: false,
+ profile: false
+ }
+ }) as ILocalUser;
+
+ if (user === null) {
+ ctx.throw(404, {
+ error: 'user not found'
+ });
+ return;
+ }
+
+ // Compare password
+ const same = await bcrypt.compare(password, user.password);
+
+ if (same) {
+ if (user.twoFactorEnabled) {
+ const verified = (speakeasy as any).totp.verify({
+ secret: user.twoFactorSecret,
+ encoding: 'base32',
+ token: token
+ });
+
+ if (verified) {
+ signin(ctx, user);
+ } else {
+ ctx.throw(400, {
+ error: 'invalid token'
+ });
+ }
+ } else {
+ signin(ctx, user);
+ }
+ } else {
+ ctx.throw(400, {
+ error: 'incorrect password'
+ });
+ }
+
+ // Append signin history
+ const record = await Signin.insert({
+ createdAt: new Date(),
+ userId: user._id,
+ ip: ctx.ip,
+ headers: ctx.headers,
+ success: same
+ });
+
+ // Publish signin event
+ event(user._id, 'signin', await pack(record));
+};