122 lines
3.1 KiB
JavaScript

import jwt from 'jsonwebtoken';
import { syllableRequired, parameterRequired, loginRequired } from '../../middlewares/index.mjs';
import { loadAccount } from './middlewares.mjs';
import { ACCOUNT_TYPE, Account } from './model.mjs';
import { isValidUUID } from '@og/uuid';
import * as config from '../../config.mjs';
/** @typedef {import('koa').Context} Context */
/** @typedef {import('koa').Next} Next */
export const login_view = [
syllableRequired('handle', 'string'),
syllableRequired('passwd', 'string'),
/**
* @param {Context} ctx
* @param {Next} next
*/
async function(ctx, next) {
/** @type {{handle: string, passwd: string}} */
const {handle, passwd} = ctx.request.body;
const account = await Account.loadByHandle(handle);
if (account == null || !account.checkPassword(passwd)) {
ctx.status = 400; // Bad Request.
ctx.body = { error: 'Authentication failed: handle or password is incorrect.' };
} else if (!account.canLogin()) {
ctx.status = 400; // Bad Request.
ctx.body = { error: 'Your account is banned or restricted.' };
} else {
const token = jwt.sign({
uid: account.uid.toString(),
handle: account.handle,
auth_step: 'done',
}, config.secret, { expiresIn: config.jwt_expire });
ctx.status = 200;
ctx.body = { uid: account.uid.toString(), token, auth_step: 'done' };
}
}
];
export const whoami_view = [
loginRequired,
loadAccount,
/**
* @param {Context} ctx
* @param {Next} next
*/
async function(ctx, next) {
const account = ctx.state.account;
ctx.status = 200;
ctx.body = { handle: account.handle, name: account.name };
}
];
export const refresh_token_view = [
loginRequired,
/**
* @param {Context} ctx
* @param {Next} next
*/
async function(ctx, next) {
/** @type {Account?} */
const old_token = ctx.state.user;
const new_token = jwt.sign({
uid: old_token.uid,
handle: old_token.handle,
auth_step: 'done',
}, config.secret, { expiresIn: config.jwt_expire });
ctx.status = 200;
ctx.body = { uid: old_token.uid, token: new_token, auth_step: 'done'};
}
];
export const signup_view = [
syllableRequired('handle', 'string'),
syllableRequired('name', 'string'),
syllableRequired('passwd', 'string'),
/**
* @param {Context} ctx
* @param {Next} next
*/
async function(ctx, next) {
/** @type {{handle: string, name: string, passwd: string}} */
const {handle, name, passwd} = ctx.request.body;
let account = Account.create({
handle, name,
type: ACCOUNT_TYPE.normal,
plaintext_password: passwd,
});
if (!await account.canCreate()) {
ctx.status = 400;
ctx.body = { error: 'Handle is taken or cannot be used.' };
return;
}
await account.save();
ctx.status = 204;
}
];
export const account_info_view = [
parameterRequired('uid', isValidUUID),
/**
* @param {Context} ctx
* @param {Next} next
*/
async function(ctx, next) {
/** @type {Account?} */
let account = await Account.load(ctx.params.uid);
if (account == null) {
ctx.status = 404; // 404 Not Found
ctx.body = { error: 'requested user is not found' };
} else {
ctx.status = 200;
ctx.body = account.asInfo();
}
}
];