Update codebase to latest wms-core and add recovery email add form
This commit is contained in:
parent
3c2d408428
commit
cb9d28128f
|
@ -24,7 +24,8 @@ export default Object.assign(require("wms-core/config/default").default, {
|
|||
session: {
|
||||
secret: "very_secret_not_known",
|
||||
cookie: {
|
||||
secure: false
|
||||
secure: false,
|
||||
maxAge: 30 * 24 * 3600 * 1000,
|
||||
}
|
||||
},
|
||||
mail: {
|
||||
|
@ -41,5 +42,4 @@ export default Object.assign(require("wms-core/config/default").default, {
|
|||
cache: false
|
||||
},
|
||||
approval_mode: false,
|
||||
'prelaunch-password': '$argon2i$v=19$m=4096,t=3,p=1$V7njt+IBmIQ/epc7tuQcfA$ypJCNauYSPrjOhtb5UqTbRlqCHkEGikBApOrYmbdYC0',
|
||||
});
|
|
@ -1,9 +1,8 @@
|
|||
export default Object.assign(require("wms-core/config/production").default, {
|
||||
'prelaunch-password': 'CHANGE ME',
|
||||
log_level: "DEBUG",
|
||||
db_log_level: "ERROR",
|
||||
public_url: "https://watch-my.stream",
|
||||
public_websocket_url: "wss://watch-my.stream",
|
||||
public_url: "https://aldap.toot.party",
|
||||
public_websocket_url: "wss://aldap.toot.party",
|
||||
session: {
|
||||
cookie: {
|
||||
secure: true
|
||||
|
|
101
src/Aldap.ts
101
src/Aldap.ts
|
@ -1,101 +0,0 @@
|
|||
import Application from "wms-core/Application";
|
||||
import {Type} from "wms-core/Utils";
|
||||
import Migration from "wms-core/db/Migration";
|
||||
import ExpressAppComponent from "wms-core/components/ExpressAppComponent";
|
||||
import NunjucksComponent from "wms-core/components/NunjucksComponent";
|
||||
import MysqlComponent from "wms-core/components/MysqlComponent";
|
||||
import LogRequestsComponent from "wms-core/components/LogRequestsComponent";
|
||||
import RedisComponent from "wms-core/components/RedisComponent";
|
||||
import ServeStaticDirectoryComponent from "wms-core/components/ServeStaticDirectoryComponent";
|
||||
import MaintenanceComponent from "wms-core/components/MaintenanceComponent";
|
||||
import MailComponent from "wms-core/components/MailComponent";
|
||||
import SessionComponent from "wms-core/components/SessionComponent";
|
||||
import RedirectBackComponent from "wms-core/components/RedirectBackComponent";
|
||||
import FormHelperComponent from "wms-core/components/FormHelperComponent";
|
||||
import CsrfProtectionComponent from "wms-core/components/CsrfProtectionComponent";
|
||||
import WebSocketServerComponent from "wms-core/components/WebSocketServerComponent";
|
||||
import HomeController from "./controllers/HomeController";
|
||||
import AuthController from "./controllers/AuthController";
|
||||
import AuthComponent from "wms-core/auth/AuthComponent";
|
||||
import AuthGuard from "wms-core/auth/AuthGuard";
|
||||
import {PasswordAuthProof} from "./models/UserPassword";
|
||||
import {MIGRATIONS} from "./migrations";
|
||||
import LDAPServerComponent from "./LDAPServerComponent";
|
||||
import PreLaunchWall from "./controllers/PreLaunchWall";
|
||||
import AutoUpdateComponent from "wms-core/components/AutoUpdateComponent";
|
||||
|
||||
export default class Aldap extends Application {
|
||||
private readonly port: number;
|
||||
|
||||
constructor(port: number) {
|
||||
super(require('../package.json').version);
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
protected getMigrations(): Type<Migration>[] {
|
||||
return MIGRATIONS;
|
||||
}
|
||||
|
||||
protected async init(): Promise<void> {
|
||||
this.registerComponents();
|
||||
this.registerWebSocketListeners();
|
||||
this.registerControllers();
|
||||
}
|
||||
|
||||
private registerComponents() {
|
||||
const redisComponent = new RedisComponent();
|
||||
const mysqlComponent = new MysqlComponent();
|
||||
|
||||
const expressAppComponent = new ExpressAppComponent(this.port);
|
||||
this.use(expressAppComponent);
|
||||
this.use(new NunjucksComponent());
|
||||
this.use(new LogRequestsComponent());
|
||||
|
||||
// Static files
|
||||
this.use(new ServeStaticDirectoryComponent('public'));
|
||||
this.use(new ServeStaticDirectoryComponent('node_modules/feather-icons/dist', '/icons'));
|
||||
|
||||
// Maintenance
|
||||
this.use(new MaintenanceComponent(this, () => {
|
||||
return redisComponent.canServe() && mysqlComponent.canServe();
|
||||
}));
|
||||
this.use(new AutoUpdateComponent());
|
||||
|
||||
// Services
|
||||
this.use(mysqlComponent);
|
||||
this.use(new MailComponent());
|
||||
|
||||
// Session
|
||||
this.use(redisComponent);
|
||||
this.use(new SessionComponent(redisComponent));
|
||||
|
||||
// Utils
|
||||
this.use(new RedirectBackComponent());
|
||||
this.use(new FormHelperComponent());
|
||||
|
||||
// Middlewares
|
||||
this.use(new CsrfProtectionComponent());
|
||||
|
||||
// Auth
|
||||
this.use(new AuthComponent(new class extends AuthGuard<PasswordAuthProof> {
|
||||
public async getProofForSession(session: Express.Session): Promise<any | null> {
|
||||
return PasswordAuthProof.getProofForSession(session);
|
||||
}
|
||||
}));
|
||||
|
||||
// WebSocket server
|
||||
this.use(new WebSocketServerComponent(this, expressAppComponent, redisComponent));
|
||||
|
||||
// LDAP server
|
||||
this.use(new LDAPServerComponent());
|
||||
}
|
||||
|
||||
private registerWebSocketListeners() {
|
||||
}
|
||||
|
||||
private registerControllers() {
|
||||
this.use(new PreLaunchWall());
|
||||
this.use(new HomeController());
|
||||
this.use(new AuthController());
|
||||
}
|
||||
}
|
47
src/App.ts
47
src/App.ts
|
@ -1,8 +1,6 @@
|
|||
import Application from "wms-core/Application";
|
||||
import {Type} from "wms-core/Utils";
|
||||
import Migration from "wms-core/db/Migration";
|
||||
import CreateMigrationsTable from "wms-core/migrations/CreateMigrationsTable";
|
||||
import CreateLogsTable from "wms-core/migrations/CreateLogsTable";
|
||||
import ExpressAppComponent from "wms-core/components/ExpressAppComponent";
|
||||
import NunjucksComponent from "wms-core/components/NunjucksComponent";
|
||||
import MysqlComponent from "wms-core/components/MysqlComponent";
|
||||
|
@ -12,15 +10,30 @@ import ServeStaticDirectoryComponent from "wms-core/components/ServeStaticDirect
|
|||
import MaintenanceComponent from "wms-core/components/MaintenanceComponent";
|
||||
import MailComponent from "wms-core/components/MailComponent";
|
||||
import SessionComponent from "wms-core/components/SessionComponent";
|
||||
import RedirectBackComponent from "wms-core/components/RedirectBackComponent";
|
||||
import FormHelperComponent from "wms-core/components/FormHelperComponent";
|
||||
import CsrfProtectionComponent from "wms-core/components/CsrfProtectionComponent";
|
||||
import WebSocketServerComponent from "wms-core/components/WebSocketServerComponent";
|
||||
import HomeController from "./controllers/HomeController";
|
||||
import AuthController from "./controllers/AuthController";
|
||||
import AuthComponent from "wms-core/auth/AuthComponent";
|
||||
import AuthGuard from "wms-core/auth/AuthGuard";
|
||||
import {PasswordAuthProof} from "./models/UserPassword";
|
||||
import LDAPServerComponent from "./LDAPServerComponent";
|
||||
import AutoUpdateComponent from "wms-core/components/AutoUpdateComponent";
|
||||
import AccountController from "./controllers/AccountController";
|
||||
import CreateMigrationsTable from "wms-core/migrations/CreateMigrationsTable";
|
||||
import CreateLogsTable from "wms-core/migrations/CreateLogsTable";
|
||||
import CreateUsersAndUserEmailsTable from "wms-core/auth/migrations/CreateUsersAndUserEmailsTable";
|
||||
import CreateUserPasswordsTable from "./migrations/CreateUserPasswordsTable";
|
||||
import CreateUsernamesTable from "./migrations/CreateUsernamesTable";
|
||||
import CreateMagicLinksTable from "wms-core/auth/migrations/CreateMagicLinksTable";
|
||||
import MailController from "wms-core/auth/MailController";
|
||||
import MagicLinkController from "./controllers/MagicLinkController";
|
||||
import MagicLinkWebSocketListener from "wms-core/auth/magic_link/MagicLinkWebSocketListener";
|
||||
|
||||
export default class App extends Application {
|
||||
private readonly port: number;
|
||||
private magicLinkWebSocketListener?: MagicLinkWebSocketListener;
|
||||
|
||||
constructor(port: number) {
|
||||
super(require('../package.json').version);
|
||||
|
@ -31,6 +44,10 @@ export default class App extends Application {
|
|||
return [
|
||||
CreateMigrationsTable,
|
||||
CreateLogsTable,
|
||||
CreateUsersAndUserEmailsTable,
|
||||
CreateUserPasswordsTable,
|
||||
CreateUsernamesTable,
|
||||
CreateMagicLinksTable,
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -68,20 +85,42 @@ export default class App extends Application {
|
|||
this.use(new SessionComponent(redisComponent));
|
||||
|
||||
// Utils
|
||||
this.use(new RedirectBackComponent());
|
||||
this.use(new FormHelperComponent());
|
||||
|
||||
// Middlewares
|
||||
this.use(new CsrfProtectionComponent());
|
||||
|
||||
// Auth
|
||||
this.use(new AuthComponent(new class extends AuthGuard<PasswordAuthProof> {
|
||||
public async getProofForSession(session: Express.Session): Promise<any | null> {
|
||||
return PasswordAuthProof.getProofForSession(session);
|
||||
}
|
||||
}));
|
||||
|
||||
// WebSocket server
|
||||
this.use(new WebSocketServerComponent(this, expressAppComponent, redisComponent));
|
||||
|
||||
// LDAP server
|
||||
this.use(new LDAPServerComponent());
|
||||
}
|
||||
|
||||
private registerWebSocketListeners() {
|
||||
this.magicLinkWebSocketListener = new MagicLinkWebSocketListener();
|
||||
this.use(this.magicLinkWebSocketListener);
|
||||
}
|
||||
|
||||
private registerControllers() {
|
||||
// Priority routes / interrupting middlewares
|
||||
this.use(new AuthController());
|
||||
this.use(new AccountController());
|
||||
this.use(new MagicLinkController(this.magicLinkWebSocketListener!))
|
||||
|
||||
// Core functionality
|
||||
this.use(new MailController());
|
||||
|
||||
// Other functionnality
|
||||
|
||||
// Semi-static routes
|
||||
this.use(new HomeController());
|
||||
}
|
||||
}
|
|
@ -1,27 +1,18 @@
|
|||
import ApplicationComponent from "wms-core/ApplicationComponent";
|
||||
import {Express, Router} from "express";
|
||||
import ldap, {InsufficientAccessRightsError, InvalidCredentialsError, Server} from "ldapjs";
|
||||
import {Express} from "express";
|
||||
import ldap, {InvalidCredentialsError, Server} from "ldapjs";
|
||||
import Logger from "wms-core/Logger";
|
||||
import Username from "./models/Username";
|
||||
import UserEmail from "wms-core/auth/models/UserEmail";
|
||||
import {PasswordAuthProof} from "./models/UserPassword";
|
||||
import Throttler from "wms-core/Throttler";
|
||||
|
||||
export default class LDAPServerComponent extends ApplicationComponent<void> {
|
||||
private server?: Server;
|
||||
|
||||
public async start(app: Express, router: Router): Promise<void> {
|
||||
public async start(app: Express): Promise<void> {
|
||||
this.server = ldap.createServer({
|
||||
log: console
|
||||
});
|
||||
let authorize = (req: any, res: any, next: any) => {
|
||||
Logger.debug(req);
|
||||
|
||||
if (!req.connection.ldap.bindDN.equals('cn=root'))
|
||||
return next(new InsufficientAccessRightsError());
|
||||
|
||||
return next();
|
||||
};
|
||||
this.server.bind('ou=users,dc=toot,dc=party', async (req: any, res: any, next: any) => {
|
||||
const rdns = req.dn.toString().split(', ').map((rdn: string) => rdn.split('='));
|
||||
let username;
|
||||
|
@ -46,7 +37,7 @@ export default class LDAPServerComponent extends ApplicationComponent<void> {
|
|||
|
||||
const user = await Username.getUserFromUsername(username);
|
||||
if (user) {
|
||||
const email = await UserEmail.getMainFromUser(user.id!);
|
||||
const email = await user.mainEmail.get();
|
||||
if (email) {
|
||||
const authProof = new PasswordAuthProof(email.email!);
|
||||
if (await authProof.authorize(req.credentials)) {
|
||||
|
@ -68,7 +59,4 @@ export default class LDAPServerComponent extends ApplicationComponent<void> {
|
|||
Logger.info(`LDAP server listening on ${this.server!.url}`);
|
||||
});
|
||||
}
|
||||
|
||||
public async stop(): Promise<void> {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
import Controller from "wms-core/Controller";
|
||||
import {REQUIRE_AUTH_MIDDLEWARE} from "wms-core/auth/AuthComponent";
|
||||
import {NextFunction, Request, Response} from "express";
|
||||
|
||||
export default class AccountController extends Controller {
|
||||
routes(): void {
|
||||
this.get('/account', this.getAccount, 'account', REQUIRE_AUTH_MIDDLEWARE);
|
||||
this.post('/add-recovery-email', this.addRecoveryEmail, 'add-recovery-email', REQUIRE_AUTH_MIDDLEWARE);
|
||||
}
|
||||
|
||||
protected async getAccount(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
res.render('account', {
|
||||
emails: await req.models.user!.emails.get(),
|
||||
});
|
||||
}
|
||||
|
||||
protected async addRecoveryEmail(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
req.flash('warn', 'Not implemented');
|
||||
res.redirectBack();
|
||||
}
|
||||
}
|
|
@ -1,26 +1,28 @@
|
|||
import Controller from "wms-core/Controller";
|
||||
import {REQUIRE_AUTH_MIDDLEWARE, REQUIRE_GUEST_MIDDLEWARE} from "wms-core/auth/AuthComponent";
|
||||
import {Request, Response} from "express";
|
||||
import {NextFunction, Request, Response} from "express";
|
||||
import Validator from "wms-core/db/Validator";
|
||||
import {EMAIL_REGEX} from "wms-core/db/Model";
|
||||
import {PasswordAuthProof} from "../models/UserPassword";
|
||||
import UserEmail from "wms-core/auth/models/UserEmail";
|
||||
import Username, {USERNAME_REGEXP} from "../models/Username";
|
||||
import _AuthController from "wms-core/auth/AuthController";
|
||||
import {ServerError} from "wms-core/HttpError";
|
||||
|
||||
export default class AuthController extends Controller {
|
||||
export default class AuthController extends _AuthController {
|
||||
routes(): void {
|
||||
this.get('/login', this.getLogin, 'login', REQUIRE_GUEST_MIDDLEWARE);
|
||||
this.post('/login', this.postLogin, 'login', REQUIRE_GUEST_MIDDLEWARE);
|
||||
this.get('/register', this.getRegister, 'register', REQUIRE_GUEST_MIDDLEWARE);
|
||||
this.post('/register', this.postRegister, 'register', REQUIRE_GUEST_MIDDLEWARE);
|
||||
this.get('/logout', this.getLogout, 'logout', REQUIRE_AUTH_MIDDLEWARE);
|
||||
this.post('/logout', this.postLogout, 'logout', REQUIRE_AUTH_MIDDLEWARE);
|
||||
}
|
||||
|
||||
private async getLogin(req: Request, res: Response): Promise<void> {
|
||||
protected async getLogin(req: Request, res: Response): Promise<void> {
|
||||
res.render('login');
|
||||
}
|
||||
|
||||
private async postLogin(req: Request, res: Response): Promise<void> {
|
||||
protected async postLogin(req: Request, res: Response): Promise<void> {
|
||||
await this.validate({
|
||||
email: new Validator().defined().regexp(EMAIL_REGEX),
|
||||
password: new Validator().acceptUndefined(),
|
||||
|
@ -41,11 +43,11 @@ export default class AuthController extends Controller {
|
|||
res.redirect(Controller.route('home'));
|
||||
}
|
||||
|
||||
private async getRegister(req: Request, res: Response): Promise<void> {
|
||||
protected async getRegister(req: Request, res: Response): Promise<void> {
|
||||
res.render('register');
|
||||
}
|
||||
|
||||
private async postRegister(req: Request, res: Response): Promise<void> {
|
||||
protected async postRegister(req: Request, res: Response): Promise<void> {
|
||||
const validationMap: any = {
|
||||
username: new Validator().defined().between(3, 64).regexp(USERNAME_REGEXP).unique(Username),
|
||||
password: new Validator().defined().minLength(8),
|
||||
|
@ -96,8 +98,11 @@ export default class AuthController extends Controller {
|
|||
res.redirect(Controller.route('home'));
|
||||
}
|
||||
|
||||
private async getLogout(req: Request, res: Response): Promise<void> {
|
||||
await req.authGuard.logout(req.session!);
|
||||
res.redirect(Controller.route('home'));
|
||||
protected async getCheckAuth(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
throw new ServerError('Not implemented.');
|
||||
}
|
||||
|
||||
protected async postAuth(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
throw new ServerError('Not implemented.');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export enum MagicLinkActionType {
|
||||
ADD_RECOVERY_EMAIL = 'Add a recovery email',
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
import _MagicLinkController from "wms-core/auth/magic_link/MagicLinkController";
|
||||
import MagicLink from "wms-core/auth/models/MagicLink";
|
||||
import {Request, Response} from "express";
|
||||
import MagicLinkWebSocketListener from "wms-core/auth/magic_link/MagicLinkWebSocketListener";
|
||||
import {MagicLinkActionType} from "./MagicLinkActionType";
|
||||
import Controller from "wms-core/Controller";
|
||||
import {BadOwnerMagicLink} from "wms-core/auth/magic_link/MagicLinkAuthController";
|
||||
import UserEmail from "wms-core/auth/models/UserEmail";
|
||||
|
||||
export default class MagicLinkController extends _MagicLinkController {
|
||||
constructor(magicLinkWebSocketListener: MagicLinkWebSocketListener) {
|
||||
super(magicLinkWebSocketListener);
|
||||
}
|
||||
|
||||
protected async performAction(magicLink: MagicLink, req: Request, res: Response): Promise<void> {
|
||||
switch (magicLink.getActionType()) {
|
||||
case MagicLinkActionType.ADD_RECOVERY_EMAIL:
|
||||
if (magicLink.getSessionID() !== req.sessionID!) throw new BadOwnerMagicLink();
|
||||
|
||||
const user = await req.authGuard.getUserForSession(req.session!);
|
||||
if (!user || !(await magicLink.isOwnedBy(user.id!))) throw new BadOwnerMagicLink();
|
||||
|
||||
let userEmail;
|
||||
await (userEmail = new UserEmail({
|
||||
user_id: user.id,
|
||||
email: await magicLink.getEmail(),
|
||||
main: false,
|
||||
})).save();
|
||||
|
||||
req.flash('success', `Recovery email ${userEmail.email} successfully added.`);
|
||||
res.redirect(Controller.route('home'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
import Controller from "wms-core/Controller";
|
||||
import {Request, RequestHandler, Response} from "express";
|
||||
import {ForbiddenHttpError} from "wms-core/HttpError";
|
||||
import Validator from "wms-core/db/Validator";
|
||||
import argon2 from "argon2";
|
||||
import config from "config";
|
||||
|
||||
export default class PreLaunchWall extends Controller {
|
||||
public getGlobalHandlers(): RequestHandler[] {
|
||||
return [
|
||||
(req, res, next) => {
|
||||
if (!req.session) throw new ForbiddenHttpError('page', req.url);
|
||||
|
||||
if (!req.session.authorized) {
|
||||
const route = Controller.route('prelaunch-wall');
|
||||
if (req.url !== route) {
|
||||
res.redirect(route);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
next();
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
routes(): void {
|
||||
this.get('/prelaunch-wall', this.getWall, 'prelaunch-wall');
|
||||
this.post('/prelaunch-wall', this.postWall, 'prelaunch-wall');
|
||||
}
|
||||
|
||||
private async getWall(req: Request, res: Response) {
|
||||
res.render('prelaunch-wall');
|
||||
}
|
||||
|
||||
private async postWall(req: Request, res: Response) {
|
||||
await this.validate({
|
||||
password: new Validator().defined(),
|
||||
}, req.body);
|
||||
|
||||
if (await argon2.verify(config.get<string>('prelaunch-password'), req.body.password)) {
|
||||
req.session!.authorized = true;
|
||||
req.flash('success', 'Authentication success!');
|
||||
res.redirect(Controller.route('home'));
|
||||
return;
|
||||
}
|
||||
|
||||
req.flash('error', 'Invalid password.');
|
||||
res.redirectBack();
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
import CreateMigrationsTable from "wms-core/migrations/CreateMigrationsTable";
|
||||
import CreateLogsTable from "wms-core/migrations/CreateLogsTable";
|
||||
import CreateUsersAndUserEmailsTable from "wms-core/auth/migrations/CreateUsersAndUserEmailsTable";
|
||||
import CreateUserPasswordsTable from "./migrations/CreateUserPasswordsTable";
|
||||
import CreateUsernamesTable from "./migrations/CreateUsernamesTable";
|
||||
|
||||
export const MIGRATIONS = [
|
||||
CreateMigrationsTable,
|
||||
CreateLogsTable,
|
||||
CreateUsersAndUserEmailsTable,
|
||||
CreateUserPasswordsTable,
|
||||
CreateUsernamesTable,
|
||||
];
|
|
@ -4,22 +4,26 @@ import User from "wms-core/auth/models/User";
|
|||
import argon2 from "argon2";
|
||||
import AuthProof from "wms-core/auth/AuthProof";
|
||||
import {UserAlreadyExistsAuthError} from "wms-core/auth/AuthGuard";
|
||||
import UserEmail from "wms-core/auth/models/UserEmail";
|
||||
|
||||
export default class UserPassword extends Model {
|
||||
public static async getByEmail(email: string): Promise<UserPassword | null> {
|
||||
const user = await User.fromEmail(email);
|
||||
if (!user) return null;
|
||||
|
||||
const result = await this.models<UserPassword>(this.select().where('user_id', user.id).first());
|
||||
return result && result.length > 0 ? result[0] : null;
|
||||
const userEmail = await UserEmail.select('user_id')
|
||||
.where('email', email)
|
||||
.first();
|
||||
return userEmail ? await UserPassword.select().where('user_id', userEmail.user_id).first() : null;
|
||||
}
|
||||
|
||||
private user_id?: number;
|
||||
private password?: string;
|
||||
private user_id!: number;
|
||||
private password!: string;
|
||||
|
||||
protected defineProperties(): void {
|
||||
this.defineProperty<number>('user_id', new Validator().defined().unique(this).exists(User, 'id'));
|
||||
this.defineProperty<string>('password', new Validator().defined());
|
||||
public constructor(props: any) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
protected init(): void {
|
||||
this.addProperty<number>('user_id', new Validator().defined().unique(this).exists(User, 'id'));
|
||||
this.addProperty<string>('password', new Validator().defined());
|
||||
}
|
||||
|
||||
public async setUser(userID: number): Promise<void> {
|
||||
|
@ -67,7 +71,11 @@ export class PasswordAuthProof implements AuthProof {
|
|||
}
|
||||
|
||||
public async getUser(): Promise<User | null> {
|
||||
return await User.fromEmail(await this.getEmail());
|
||||
const userEmail = await UserEmail.select()
|
||||
.where('email', await this.getEmail())
|
||||
.with('user')
|
||||
.first();
|
||||
return userEmail ? await userEmail.user.get() : null;
|
||||
}
|
||||
|
||||
public async isAuthorized(): Promise<boolean> {
|
||||
|
|
|
@ -1,32 +1,38 @@
|
|||
import Model from "wms-core/db/Model";
|
||||
import Validator from "wms-core/db/Validator";
|
||||
import User from "wms-core/auth/models/User";
|
||||
import {OneModelRelation} from "wms-core/db/ModelRelation";
|
||||
|
||||
export const USERNAME_REGEXP = /^[0-9a-z_-]+$/;
|
||||
|
||||
export default class Username extends Model {
|
||||
public static async fromUser(userID: number): Promise<Username | null> {
|
||||
const models = await this.models<Username>(this.select().where('user_id', userID));
|
||||
return models && models.length > 0 ? models[0] : null;
|
||||
return await this.select().where('user_id', userID).first();
|
||||
}
|
||||
|
||||
public static async getUserFromUsername(username: string): Promise<User | null> {
|
||||
const models = await this.models<Username>(this.select().where('username', username.toLowerCase()));
|
||||
if (!models || models.length === 0) return null;
|
||||
return await User.getById<User>(models[0].user_id!);
|
||||
let model = await this.select()
|
||||
.with('user')
|
||||
.where('username', username.toLowerCase())
|
||||
.first();
|
||||
return model ? await model.user.get() : null;
|
||||
}
|
||||
|
||||
private user_id?: number;
|
||||
public username?: string;
|
||||
private readonly user_id!: number;
|
||||
public readonly user: OneModelRelation<this, User> = new OneModelRelation<this, User>(this, User, {
|
||||
localKey: 'user_id',
|
||||
foreignKey: 'id'
|
||||
});
|
||||
public username!: string;
|
||||
|
||||
|
||||
constructor(data: any) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
protected defineProperties(): void {
|
||||
this.defineProperty<number>('user_id', new Validator().defined().exists(User, 'id').unique(this));
|
||||
this.defineProperty<number>('username', new Validator().defined().between(3, 64).regexp(USERNAME_REGEXP).unique(this));
|
||||
protected init(): void {
|
||||
this.addProperty<number>('user_id', new Validator().defined().exists(User, 'id').unique(this));
|
||||
this.addProperty<number>('username', new Validator().defined().between(3, 64).regexp(USERNAME_REGEXP).unique(this));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
{% extends 'layouts/base.njk' %}
|
||||
|
||||
{% set title = 'ALDAP - Welcome to the toot.party auth center!' %}
|
||||
|
||||
{% block body %}
|
||||
<div class="container">
|
||||
<main class="panel">
|
||||
<h1>My account</h1>
|
||||
|
||||
<p>Name: {{ user.name }}</p>
|
||||
|
||||
<section class="sub-panel">
|
||||
<h2>Email addresses</h2>
|
||||
|
||||
{% for email in emails %}
|
||||
{% if email.main %}
|
||||
<p>Main email: {{ email.email }}</p>
|
||||
{% else %}
|
||||
<p>Recovery email: {{ email.email }}</p>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
<form action="{{ route('add-recovery-email') }}" method="POST">
|
||||
{{ macros.field(_locals, 'email', 'email', null, 'Choose a safe email address', 'An email we can use to identify you in case you lose access to your account', 'required') }}
|
||||
|
||||
<button type="submit">Add recovery email</button>
|
||||
</form>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -16,15 +16,21 @@
|
|||
<nav>
|
||||
<button id="menu-button"><i data-feather="menu"></i></button>
|
||||
<ul id="main-menu">
|
||||
<li><a href="{{ route('about') }}"><i data-feather="info"></i> About</a></li>
|
||||
{% if user %}
|
||||
<li><a href="{{ route('home') }}"><i data-feather="user"></i> {{ user.name }}</a></li>
|
||||
<li><a href="{{ route('logout') }}"><i data-feather="log-out"></i> Logout</a></li>
|
||||
{% else %}
|
||||
<li><a href="{{ route('login') }}"><i data-feather="log-in"></i> Login</a></li>
|
||||
<li><a href="{{ route('register') }}"><i data-feather="user-plus"></i> Register</a></li>
|
||||
{% endif %}
|
||||
<li><a href="{{ route('about') }}"><i data-feather="info"></i> <span class="tip">About</span></a></li>
|
||||
{% if user %}
|
||||
<li><a href="{{ route('account') }}"><i data-feather="user"></i>
|
||||
<span class="tip">{{ user.name }}</span></a></li>
|
||||
<li>
|
||||
<form action="{{ route('logout') }}" method="POST">
|
||||
<button><i data-feather="log-out"></i> <span class="tip">Logout</span></button>
|
||||
{{ macros.csrf(getCSRFToken) }}
|
||||
</form>
|
||||
</li>
|
||||
{% else %}
|
||||
<li><a href="{{ route('login') }}"><i data-feather="log-in"></i> <span class="tip">Login</span></a></li>
|
||||
<li><a href="{{ route('register') }}"><i data-feather="user-plus"></i>
|
||||
<span class="tip">Register</span></a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% endblock %}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
{{ macros.field(_locals, 'email', 'email', null, 'Your email address', null, 'required') }}
|
||||
{{ macros.field(_locals, 'password', 'password', null, 'Your password', null, 'required') }}
|
||||
|
||||
<button type="submit">Login</button>
|
||||
<button type="submit"><i data-feather="log-in"></i> Login</button>
|
||||
|
||||
{{ macros.csrf(getCSRFToken) }}
|
||||
</form>
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
{% extends 'layouts/base.njk' %}
|
||||
|
||||
{% set title = 'ALDAP - Early access' %}
|
||||
|
||||
{% block body %}
|
||||
<div class="container">
|
||||
<div class="panel">
|
||||
<h1>{{ title }}</h1>
|
||||
|
||||
<form action="{{ route('prelaunch-wall') }}" method="POST">
|
||||
{{ macros.field(_locals, 'password', 'password', null, 'Enter password') }}
|
||||
|
||||
<button type="submit">Authenticate</button>
|
||||
|
||||
{{ macros.csrf(getCSRFToken) }}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -26,7 +26,7 @@
|
|||
{{ macros.field(_locals, 'select', 'domain', null, 'Choose your domain', null, 'disabled', ['toot.party']) }}
|
||||
</div>
|
||||
{{ macros.fieldError(_locals, 'email') }}
|
||||
<div class="hint"><i data-feather="info"></i> This cannot be changed later.</div>
|
||||
<div class="hint"><i data-feather="info"></i> You won't be able to change this again.</div>
|
||||
</section>
|
||||
|
||||
<section class="sub-panel">
|
||||
|
@ -42,7 +42,7 @@
|
|||
|
||||
{{ macros.field(_locals, 'checkbox', 'terms', null, 'I accept the terms of services', null, 'required') }}
|
||||
|
||||
<button type="submit">Register</button>
|
||||
<button type="submit"><i data-feather="user-plus"></i>Register</button>
|
||||
|
||||
{{ macros.csrf(getCSRFToken) }}
|
||||
</form>
|
||||
|
|
Loading…
Reference in New Issue