Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"error500": "Server error occured during authentication.",

"invalid_code": "Invalid Code Provided",
"invalid_code_Details": "Try reauthorizing, probably you've spoiled discord provided code.",
"invalid_code_details": "Try reauthorizing, probably you've spoiled discord provided code.",

"unable_exchange_code": "Unable to exchange code",
"unable_exchange_code_details": "Try reauthorizing, probably you've spoiled discord provided code.",
Expand Down
2 changes: 1 addition & 1 deletion locales/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"error500": "Произошла серверная ошибка во время аутентификации.",

"invalid_code": "Предоставлен неверный код",
"invalid_code_Details": "Попробуйте перезапустить процесс авторизации, возможно вы испортили код.",
"invalid_code_details": "Попробуйте перезапустить процесс авторизации, возможно вы испортили код.",

"unable_exchange_code": "Невозможно обменяться кодом",
"unable_exchange_code_details": "Попробуйте перезапустить процесс авторизации, возможно вы испортили код.",
Expand Down
43 changes: 43 additions & 0 deletions src/types/models.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { IAuthorizedRecord } from "./database";

export interface IBaseViewModel {
assetPrefix: string,
title: string,
}

export interface ILoginViewModel extends IBaseViewModel {
description: string,
mainText: string,
authLink?: string,
authBtnText?: string,
}

export interface ISuccessViewModel extends IBaseViewModel {
description: string,
mainText: string,
}

export interface IErrorViewModel extends IBaseViewModel {
errorDescription: string,
errorTitle: string,
statusCode: number,
errorText: string,
errorId?: string,
logsLink?: string,
}

export interface IAdminLoginViewModel extends IBaseViewModel {
loginTitle: string,
loginSubmitBtnText: string,
loginTokenName: string,
}

export interface IAdminPanelViewModel extends IBaseViewModel {
records: IAuthorizedRecord[] | null,
panelDeleteBtnText: string,
panelSubmitBtnText: string,
currentPage: number,
panelTitle: string,
prevPage: string,
nextPage: string,
}
40 changes: 13 additions & 27 deletions src/web/controllers/admin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { LocaleExtendedRequest } from '../../types/web';
import { verifyJWT } from '../middlewares/admin';
import { IAuthorizedRecord } from '../../types/database';
import { Logger } from '../../logging';
import { AdminLoginViewModel, AdminPanelViewModel } from '../models';

const config = Configration.get();
const locales = LocaleManager.get();
Expand Down Expand Up @@ -45,21 +46,14 @@ export class AdminController {
const nextPageLink = `${config.pathBase}/admin/panel?search=${searchText}&page=${page+1}&loc=${locale ?? config.locale}`;
const prevPageLink = `${config.pathBase}/admin/panel?search=${searchText}&page=${page-1 < 1 ? 1 : page-1}&loc=${locale ?? config.locale}`;

const panel_title = locales.loc('panel_title', locale);
const panel_submit_btn = locales.loc('panel_submit_btn', locale);
const panel_delete_btn = locales.loc('panel_delete_btn', locale);

res.render('admin_panel', {
records,
title: "Admin",
panel_title,
panel_submit_btn,
panel_delete_btn,
next_page: nextPageLink,
prev_page: prevPageLink,
cur_page: page,
assetPrefix: config.pathBase
});
new AdminPanelViewModel(
locales,
page,
prevPageLink,
nextPageLink,
records,
locale
).respond(res);
}

public static async postDelete(req: Request, res: Response) {
Expand All @@ -86,18 +80,10 @@ export class AdminController {
}

public static async getLogin(req: LocaleExtendedRequest, res: Response) {
// locales
const locale = req.locale!;
const login_title = locales.loc('login_title', locale);
const login_submit_btn = locales.loc('login_submit_btn', locale);
const login_token_name = locales.loc('login_token_name', locale);

res.render('admin_login', {
login_title,
login_token_name,
login_submit_btn,
assetPrefix: config.pathBase
});
new AdminLoginViewModel(
locales,
req.locale
).respond(res.status(200));
}

public static async postLogin(req: Request, res: Response) {
Expand Down
60 changes: 21 additions & 39 deletions src/web/controllers/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { getLocale } from '../middlewares/auth';
import { Configration } from '../../config';
import { randomUUID } from 'crypto';
import { validateUuid } from '../../validation/uuid';
import { ErrorViewModel, LoginViewModel, SuccessViewModel } from '../models';

// database should be already initialized here
const db = Database.getDbImpl();
Expand All @@ -18,7 +19,6 @@ const logger = Logger.get();
/// Here is the format
/// getPATH_PATH_... - GET /auth/PATH/PATH/...
export class AuthController {

public static collectToRouter() {
const router = Router();
router.get('/login', getLocale, AuthController.getLogin);
Expand All @@ -28,39 +28,29 @@ export class AuthController {

public static async getLogin(req: LocaleExtendedRequest, res: Response) {
let uid = req.query['uid']?.toString() ?? undefined;

const locale = req.locale!;
const auth_required = locales.loc('auth_required', locale);
const auth_required_details = uid ? locales.loc('auth_required_details_uid', locale) : locales.loc('auth_required_details', locale);
const auth_btn = locales.loc('auth_btn', locale);

let authLink: string | undefined;
if (uid) {
if (validateUuid(uid)) {
authLink = WebHelpers.generateAuthLink(uid);
}
}

res.render('login', {
title: "Login",
auth_required,
auth_required_details,
authLink, auth_btn,
assetPrefix: config.pathBase}
);
new LoginViewModel(
locales,
authLink,
locale,
).respond(res.status(200));
}

public static async getLogin_Cb(req: Request, res: Response) {

const query = WebHelpers.parseCodeQuery(req);
if (!query) {
const title = locales.loc("invalid_code", config.locale);
const desc = locales.loc("invalid_code_details", config.locale);

WebHelpers.respondErr(res, title, 400, desc, config.locale);
WebHelpers.respondErr(res, "invalid_code", 400, "invalid_code_details", config.locale);
return;
}

const stateBuf = Buffer.from(query.state, 'base64').toString('utf-8');
const decodedState: IState = JSON.parse(stateBuf);
if (!decodedState.uid) {
Expand All @@ -72,10 +62,13 @@ export class AuthController {

const tokenStruct = await WebHelpers.exchangeCode(query.code, req);
if (!tokenStruct) {
const title = locales.loc("unable_exchange_code", locale);
const desc = locales.loc("unable_exchange_code_details", locale);

WebHelpers.respondErr(res, title, 400, desc, locale);
WebHelpers.respondErr(
res,
"unable_exchange_code",
400,
"unable_exchange_code_details",
locale
);
return;
}

Expand Down Expand Up @@ -115,10 +108,7 @@ export class AuthController {
await foundByUid.save();

// https://github.com/maximal/http-267
const title = locales.loc('ok267', locale);
const desc = locales.loc('ok267_details', locale);

WebHelpers.respondErr(res, title, 267, desc, locale);
WebHelpers.respondErr(res, "ok267", 267, "ok267_details", locale);
logger.warn("Authenticating again, credentials left untouched", {
uid: foundByUid.uid,
duid: foundByUid.discord_uid
Expand All @@ -134,10 +124,7 @@ export class AuthController {
await found.save();

// https://github.com/maximal/http-267
const title = locales.loc('ok267', locale);
const desc = locales.loc('ok267_details', locale);

WebHelpers.respondErr(res, title, 267, desc, locale);
WebHelpers.respondErr(res, "ok267", 267, "ok267_details", locale);
logger.warn("Authenticating again, credentials left untouched", {
uid: found.uid,
duid: found.discord_uid
Expand Down Expand Up @@ -170,15 +157,10 @@ export class AuthController {
await record.save();
}

const auth_success = locales.loc('auth_success', locale);
const auth_success_details = locales.loc('auth_success_details', locale);

res.render('success', {
title: "Success",
auth_success,
auth_success_details,
assetPrefix: config.pathBase}
);
new SuccessViewModel(
locales,
locale
).respond(res.status(200));

logger.debug(`Successfully authenticated new record`, {
discord_uid: identifyScopeData.id,
Expand Down
58 changes: 34 additions & 24 deletions src/web/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { AuthorizedRecord } from '../database/generic';
import { DataParams, DiscordCodeQuery, DiscordCodeResponse, DiscordGuildMemberObject, DiscordPartialGuildObject, DiscordRawCodeQuery, DiscordUserObject, IdentifyQueryParams, LinkQueryParams, RolesQueryParams } from '../types/web';
import { IDatabase } from '../types/database';
import { LocaleManager } from '../locale';
import { ErrorViewModel } from './models';

const locales = LocaleManager.get();
const config = Configration.get();
Expand All @@ -24,32 +25,41 @@ export class WebHelpers {

/// Express helpers

public static respondErr(res: ExResponse, msg: string, code: number, help: string, locale: string | undefined = undefined) {
const errorText = locales.loc("error_title", locale ?? config.locale);

res.status(code).render('error', {
title: 'Error',
statusCode: code,
errorTitle: msg,
errorDescription: help,
errorText,
assetPrefix: config.pathBase}
);
public static respondErr(
res: ExResponse,
errTitleLocKey: string,
statusCode: number,
errDescLocKey: string,
locale: string | undefined = undefined
) {
new ErrorViewModel(
locales,
errDescLocKey,
errTitleLocKey,
statusCode,
undefined,
undefined,
locale,
).respond(res.status(statusCode))
}

public static respondErrWithLogs(res: ExResponse, msg: string, code: number, help: string, id: string, data: string, locale: string | undefined = undefined) {
const errorText = locales.loc("error_title", locale ?? config.locale);

res.status(code).render('error', {
title: "Error",
statusCode: code,
errorId: id,
errorTitle: msg,
errorDescription: help,
errorText,
logsLink: `${config.pathBase}logs?b64=${btoa(data)}`,
assetPrefix: config.pathBase
});
public static respondErrWithLogs(
res: ExResponse,
errTitleLocKey: string,
statusCode: number,
errDescLocKey: string,
errorId: string,
data: string, locale: string | undefined = undefined
) {
new ErrorViewModel(
locales,
errDescLocKey,
errTitleLocKey,
statusCode,
`${config.pathBase}logs?b64=${btoa(data)}`,
errorId,
locale
).respond(res.status(statusCode))

Logger.get().error("500 - Server Error", {err: data});
}
Expand Down
Loading