Fix lint issues
This commit is contained in:
parent
f53dc7c63c
commit
3ed93dbefb
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"bundles": {
|
"bundles": {
|
||||||
"app": "ts/app.ts",
|
"app": "ts/app.ts",
|
||||||
"register": "js/register.js",
|
"register": "ts/register.ts",
|
||||||
"layout": "sass/layout.scss",
|
"layout": "sass/layout.scss",
|
||||||
"error": "sass/error.scss",
|
"error": "sass/error.scss",
|
||||||
"logo": "img/logo.svg",
|
"logo": "img/logo.svg",
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
document.addEventListener('DOMContentLoaded', () => {
|
|
||||||
const createEmailAddress = document.getElementById('field-create_email');
|
|
||||||
const username = document.getElementById('field-username');
|
|
||||||
const email_username = document.getElementById('email_username');
|
|
||||||
const domain = document.getElementById('field-domain');
|
|
||||||
const recovery_email = document.getElementById('field-recovery_email');
|
|
||||||
const recovery_email_label = recovery_email.parentElement.querySelector('.hint');
|
|
||||||
|
|
||||||
function updateForm() {
|
|
||||||
if (createEmailAddress.checked) {
|
|
||||||
recovery_email.removeAttribute('required');
|
|
||||||
recovery_email_label.style.display = 'block';
|
|
||||||
domain.disabled = false;
|
|
||||||
} else {
|
|
||||||
recovery_email.setAttribute('required', 'required');
|
|
||||||
recovery_email_label.style.display = 'none';
|
|
||||||
domain.disabled = true;
|
|
||||||
}
|
|
||||||
username.value = username.value.toLowerCase();
|
|
||||||
email_username.innerText = username.value + '@';
|
|
||||||
}
|
|
||||||
|
|
||||||
createEmailAddress.addEventListener('change', updateForm);
|
|
||||||
username.addEventListener('change', updateForm);
|
|
||||||
username.addEventListener('keyup', updateForm);
|
|
||||||
updateForm();
|
|
||||||
});
|
|
41
assets/ts/register.ts
Normal file
41
assets/ts/register.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const createEmailAddress = document.querySelector<HTMLInputElement>('#field-create_email');
|
||||||
|
const username = document.querySelector<HTMLInputElement>('#field-username');
|
||||||
|
const email_username = document.querySelector<HTMLElement>('#email_username');
|
||||||
|
const domain = document.querySelector<HTMLInputElement>('#field-domain');
|
||||||
|
const recovery_email = document.querySelector('#field-recovery_email');
|
||||||
|
const recovery_email_label = recovery_email?.parentElement?.querySelector<HTMLElement>('.hint');
|
||||||
|
|
||||||
|
if (
|
||||||
|
!createEmailAddress ||
|
||||||
|
!recovery_email ||
|
||||||
|
!recovery_email_label ||
|
||||||
|
!domain ||
|
||||||
|
!username ||
|
||||||
|
!email_username
|
||||||
|
) {
|
||||||
|
console.warn('Some elements wern\'t found.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateForm = () => {
|
||||||
|
|
||||||
|
if (createEmailAddress.checked) {
|
||||||
|
recovery_email.removeAttribute('required');
|
||||||
|
recovery_email_label.style.display = 'block';
|
||||||
|
domain.disabled = false;
|
||||||
|
} else {
|
||||||
|
recovery_email.setAttribute('required', 'required');
|
||||||
|
recovery_email_label.style.display = 'none';
|
||||||
|
domain.disabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
username.value = username.value.toLowerCase();
|
||||||
|
email_username.innerText = username.value + '@';
|
||||||
|
};
|
||||||
|
|
||||||
|
createEmailAddress.addEventListener('change', updateForm);
|
||||||
|
username.addEventListener('change', updateForm);
|
||||||
|
username.addEventListener('keyup', updateForm);
|
||||||
|
updateForm();
|
||||||
|
});
|
@ -114,7 +114,7 @@ export default class App extends Application {
|
|||||||
this.use(new AuthComponent(new class extends AuthGuard<PasswordAuthProof | MagicLink> {
|
this.use(new AuthComponent(new class extends AuthGuard<PasswordAuthProof | MagicLink> {
|
||||||
public async getProofForSession(session: Express.Session): Promise<PasswordAuthProof | MagicLink | null> {
|
public async getProofForSession(session: Express.Session): Promise<PasswordAuthProof | MagicLink | null> {
|
||||||
return PasswordAuthProof.getProofForSession(session) ||
|
return PasswordAuthProof.getProofForSession(session) ||
|
||||||
MagicLink.bySessionId(session.id);
|
await MagicLink.bySessionId(session.id);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -133,7 +133,7 @@ export default class App extends Application {
|
|||||||
private registerControllers() {
|
private registerControllers() {
|
||||||
// Priority routes / interrupting middlewares
|
// Priority routes / interrupting middlewares
|
||||||
this.use(new AccountController());
|
this.use(new AccountController());
|
||||||
this.use(new MagicLinkController(this.magicLinkWebSocketListener!));
|
this.use(new MagicLinkController(this.as(MagicLinkWebSocketListener)));
|
||||||
this.use(new BackendController());
|
this.use(new BackendController());
|
||||||
this.use(new MailboxBackendController());
|
this.use(new MailboxBackendController());
|
||||||
this.use(new AuthController());
|
this.use(new AuthController());
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import ApplicationComponent from "wms-core/ApplicationComponent";
|
import ApplicationComponent from "wms-core/ApplicationComponent";
|
||||||
import {Express} from "express";
|
|
||||||
import ldap, {InvalidCredentialsError, Server} from "ldapjs";
|
import ldap, {InvalidCredentialsError, Server} from "ldapjs";
|
||||||
import {log} from "wms-core/Logger";
|
import {log} from "wms-core/Logger";
|
||||||
import UserPasswordComponent from "./models/UserPasswordComponent";
|
import UserPasswordComponent from "./models/UserPasswordComponent";
|
||||||
@ -9,13 +8,13 @@ import User from "wms-core/auth/models/User";
|
|||||||
export default class LDAPServerComponent extends ApplicationComponent {
|
export default class LDAPServerComponent extends ApplicationComponent {
|
||||||
private server?: Server;
|
private server?: Server;
|
||||||
|
|
||||||
public async start(app: Express): Promise<void> {
|
public async start(): Promise<void> {
|
||||||
this.server = ldap.createServer({
|
this.server = ldap.createServer({
|
||||||
log: console
|
log: console,
|
||||||
});
|
});
|
||||||
this.server.bind('ou=users,dc=toot,dc=party', async (req: any, res: any, next: any) => {
|
this.server.bind('ou=users,dc=toot,dc=party', async (req: Record<string, string>, res: Record<string, () => void>, next: (err: unknown) => void) => {
|
||||||
const rdns = req.dn.toString().split(', ').map((rdn: string) => rdn.split('='));
|
const rdns = req.dn.toString().split(', ').map((rdn: string) => rdn.split('='));
|
||||||
let username;
|
let username: string = '';
|
||||||
let email;
|
let email;
|
||||||
for (const rdn of rdns) {
|
for (const rdn of rdns) {
|
||||||
if (rdn[0] === 'cn') {
|
if (rdn[0] === 'cn') {
|
||||||
@ -50,12 +49,12 @@ export default class LDAPServerComponent extends ApplicationComponent {
|
|||||||
log.debug('Fail');
|
log.debug('Fail');
|
||||||
next(new InvalidCredentialsError());
|
next(new InvalidCredentialsError());
|
||||||
});
|
});
|
||||||
this.server.unbind((req: any, res: any, next: any) => {
|
this.server.unbind((req: unknown, res: unknown, next: () => void) => {
|
||||||
log.debug('Unbind', req);
|
log.debug('Unbind', req);
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
this.server.listen(8389, '127.0.0.1', () => {
|
this.server.listen(8389, '127.0.0.1', () => {
|
||||||
log.info(`LDAP server listening on ${this.server!.url}`);
|
log.info(`LDAP server listening on ${this.server?.url}`);
|
||||||
});
|
});
|
||||||
this.server.on('close', () => {
|
this.server.on('close', () => {
|
||||||
log.info('LDAP server closed.');
|
log.info('LDAP server closed.');
|
||||||
@ -66,7 +65,6 @@ export default class LDAPServerComponent extends ApplicationComponent {
|
|||||||
public async stop(): Promise<void> {
|
public async stop(): Promise<void> {
|
||||||
await new Promise(resolve => {
|
await new Promise(resolve => {
|
||||||
if (this.server) {
|
if (this.server) {
|
||||||
// @ts-ignore
|
|
||||||
this.server.close(() => {
|
this.server.close(() => {
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import Controller from "wms-core/Controller";
|
import Controller from "wms-core/Controller";
|
||||||
import {RequireAuthMiddleware} from "wms-core/auth/AuthComponent";
|
import {RequireAuthMiddleware} from "wms-core/auth/AuthComponent";
|
||||||
import {NextFunction, Request, Response} from "express";
|
import {Request, Response} from "express";
|
||||||
import {ADD_RECOVERY_EMAIL_MAIL_TEMPLATE} from "../Mails";
|
import {ADD_RECOVERY_EMAIL_MAIL_TEMPLATE} from "../Mails";
|
||||||
import Validator, {EMAIL_REGEX, InvalidFormatValidationError, ValidationBag} from "wms-core/db/Validator";
|
import Validator, {EMAIL_REGEX, InvalidFormatValidationError, ValidationBag} from "wms-core/db/Validator";
|
||||||
import MagicLinkController from "./MagicLinkController";
|
import MagicLinkController from "./MagicLinkController";
|
||||||
import {MagicLinkActionType} from "./MagicLinkActionType";
|
import {MagicLinkActionType} from "./MagicLinkActionType";
|
||||||
import UserEmail from "wms-core/auth/models/UserEmail";
|
import UserEmail from "wms-core/auth/models/UserEmail";
|
||||||
import {BadRequestError, ForbiddenHttpError, NotFoundHttpError} from "wms-core/HttpError";
|
import {BadRequestError, ForbiddenHttpError, NotFoundHttpError, ServerError} from "wms-core/HttpError";
|
||||||
import MailDomain from "../models/MailDomain";
|
import MailDomain from "../models/MailDomain";
|
||||||
import UserMailIdentityComponent from "../models/UserMailIdentityComponent";
|
import UserMailIdentityComponent from "../models/UserMailIdentityComponent";
|
||||||
import MailIdentity from "../models/MailIdentity";
|
import MailIdentity from "../models/MailIdentity";
|
||||||
@ -18,7 +18,7 @@ export default class AccountController extends Controller {
|
|||||||
return '/account';
|
return '/account';
|
||||||
}
|
}
|
||||||
|
|
||||||
routes(): void {
|
public routes(): void {
|
||||||
this.get('/', this.getAccount, 'account', RequireAuthMiddleware);
|
this.get('/', this.getAccount, 'account', RequireAuthMiddleware);
|
||||||
this.post('/add-recovery-email', this.addRecoveryEmail, 'add-recovery-email', RequireAuthMiddleware);
|
this.post('/add-recovery-email', this.addRecoveryEmail, 'add-recovery-email', RequireAuthMiddleware);
|
||||||
this.post('/set-main-email', this.postSetMainRecoveryEmail, 'set-main-recovery-email', RequireAuthMiddleware);
|
this.post('/set-main-email', this.postSetMainRecoveryEmail, 'set-main-recovery-email', RequireAuthMiddleware);
|
||||||
@ -28,7 +28,7 @@ export default class AccountController extends Controller {
|
|||||||
this.post('/delete-mail-identity', this.postDeleteMailIdentity, 'delete-mail-identity', RequireAuthMiddleware);
|
this.post('/delete-mail-identity', this.postDeleteMailIdentity, 'delete-mail-identity', RequireAuthMiddleware);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async getAccount(req: Request, res: Response, next: NextFunction): Promise<void> {
|
protected async getAccount(req: Request, res: Response): Promise<void> {
|
||||||
const user = req.as(RequireAuthMiddleware).getUser();
|
const user = req.as(RequireAuthMiddleware).getUser();
|
||||||
const userMailIdentity = user.as(UserMailIdentityComponent);
|
const userMailIdentity = user.as(UserMailIdentityComponent);
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ export default class AccountController extends Controller {
|
|||||||
email: await identity.toEmail(),
|
email: await identity.toEmail(),
|
||||||
}))),
|
}))),
|
||||||
domains: (await MailDomain.select()
|
domains: (await MailDomain.select()
|
||||||
.where('user_id', user.id!)
|
.where('user_id', user.id)
|
||||||
.where('user_id', null, WhereTest.EQ, WhereOperator.OR)
|
.where('user_id', null, WhereTest.EQ, WhereOperator.OR)
|
||||||
.sortBy('user_id', 'DESC')
|
.sortBy('user_id', 'DESC')
|
||||||
.get())
|
.get())
|
||||||
@ -51,7 +51,7 @@ export default class AccountController extends Controller {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async addRecoveryEmail(req: Request, res: Response, next: NextFunction): Promise<void> {
|
protected async addRecoveryEmail(req: Request, res: Response): Promise<void> {
|
||||||
await this.validate({
|
await this.validate({
|
||||||
email: new Validator().defined().regexp(EMAIL_REGEX),
|
email: new Validator().defined().regexp(EMAIL_REGEX),
|
||||||
}, req.body);
|
}, req.body);
|
||||||
@ -67,13 +67,15 @@ export default class AccountController extends Controller {
|
|||||||
throw bag;
|
throw bag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!req.sessionID) throw new ServerError('Session not initialized.');
|
||||||
|
|
||||||
await MagicLinkController.sendMagicLink(
|
await MagicLinkController.sendMagicLink(
|
||||||
req.sessionID!,
|
req.sessionID,
|
||||||
MagicLinkActionType.ADD_RECOVERY_EMAIL,
|
MagicLinkActionType.ADD_RECOVERY_EMAIL,
|
||||||
Controller.route('account'),
|
Controller.route('account'),
|
||||||
email,
|
email,
|
||||||
ADD_RECOVERY_EMAIL_MAIL_TEMPLATE,
|
ADD_RECOVERY_EMAIL_MAIL_TEMPLATE,
|
||||||
{}
|
{},
|
||||||
);
|
);
|
||||||
|
|
||||||
res.redirect(Controller.route('magic_link_lobby', undefined, {
|
res.redirect(Controller.route('magic_link_lobby', undefined, {
|
||||||
@ -140,7 +142,9 @@ export default class AccountController extends Controller {
|
|||||||
await this.validate({
|
await this.validate({
|
||||||
name: new Validator<string>().defined().equals(user.as(UserNameComponent).name),
|
name: new Validator<string>().defined().equals(user.as(UserNameComponent).name),
|
||||||
}, req.body);
|
}, req.body);
|
||||||
if ((await mailIdentityComponent.getPublicAddressesCount()) >= mailIdentityComponent.getMaxPublicAddressesCount()) {
|
const actualPublicAddressesCount = await mailIdentityComponent.getPublicAddressesCount();
|
||||||
|
const maxPublicAddressesCount = mailIdentityComponent.getMaxPublicAddressesCount();
|
||||||
|
if (actualPublicAddressesCount >= maxPublicAddressesCount) {
|
||||||
req.flash('error', 'You have reached maximum public email addresses.');
|
req.flash('error', 'You have reached maximum public email addresses.');
|
||||||
res.redirectBack();
|
res.redirectBack();
|
||||||
return;
|
return;
|
||||||
@ -161,7 +165,7 @@ export default class AccountController extends Controller {
|
|||||||
req.flash('info', 'Congratulations! You just created your mailbox.');
|
req.flash('info', 'Congratulations! You just created your mailbox.');
|
||||||
}
|
}
|
||||||
|
|
||||||
req.flash('success', 'Mail identity ' + (await identity.toEmail()) + ' successfully created.')
|
req.flash('success', 'Mail identity ' + await identity.toEmail() + ' successfully created.');
|
||||||
res.redirectBack();
|
res.redirectBack();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,7 +182,7 @@ export default class AccountController extends Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await identity.delete();
|
await identity.delete();
|
||||||
req.flash('success', 'Identity ' + (await identity.toEmail()) + ' successfully deleted.');
|
req.flash('success', 'Identity ' + await identity.toEmail() + ' successfully deleted.');
|
||||||
res.redirectBack();
|
res.redirectBack();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import Controller from "wms-core/Controller";
|
import Controller from "wms-core/Controller";
|
||||||
import AuthComponent, {RequireAuthMiddleware, RequireGuestMiddleware} from "wms-core/auth/AuthComponent";
|
import AuthComponent, {RequireAuthMiddleware, RequireGuestMiddleware} from "wms-core/auth/AuthComponent";
|
||||||
import {NextFunction, Request, Response} from "express";
|
import {Request, Response} from "express";
|
||||||
import Validator, {InvalidFormatValidationError, ValidationBag} from "wms-core/db/Validator";
|
import Validator, {InvalidFormatValidationError, ValidationBag} from "wms-core/db/Validator";
|
||||||
import UserPasswordComponent, {PasswordAuthProof} from "../models/UserPasswordComponent";
|
import UserPasswordComponent, {PasswordAuthProof} from "../models/UserPasswordComponent";
|
||||||
import UserNameComponent, {USERNAME_REGEXP} from "../models/UserNameComponent";
|
import UserNameComponent, {USERNAME_REGEXP} from "../models/UserNameComponent";
|
||||||
@ -11,7 +11,7 @@ import User from "wms-core/auth/models/User";
|
|||||||
import Throttler from "wms-core/Throttler";
|
import Throttler from "wms-core/Throttler";
|
||||||
|
|
||||||
export default class AuthController extends _AuthController {
|
export default class AuthController extends _AuthController {
|
||||||
routes(): void {
|
public routes(): void {
|
||||||
this.get('/login', this.getLogin, 'auth', RequireGuestMiddleware);
|
this.get('/login', this.getLogin, 'auth', RequireGuestMiddleware);
|
||||||
this.post('/login', this.postLogin, 'auth', RequireGuestMiddleware);
|
this.post('/login', this.postLogin, 'auth', RequireGuestMiddleware);
|
||||||
this.get('/register', this.getRegister, 'register', RequireGuestMiddleware);
|
this.get('/register', this.getRegister, 'register', RequireGuestMiddleware);
|
||||||
@ -35,15 +35,17 @@ export default class AuthController extends _AuthController {
|
|||||||
|
|
||||||
if (!user) throw new NotFoundHttpError(`Couldn't find a user with name ${req.body.username}`, req.url);
|
if (!user) throw new NotFoundHttpError(`Couldn't find a user with name ${req.body.username}`, req.url);
|
||||||
|
|
||||||
const passwordAuthProof = PasswordAuthProof.createProofForLogin(req.session!);
|
if (!req.session) throw new ServerError('Session not initialized.');
|
||||||
|
|
||||||
|
const passwordAuthProof = PasswordAuthProof.createProofForLogin(req.session);
|
||||||
passwordAuthProof.setResource(user);
|
passwordAuthProof.setResource(user);
|
||||||
|
|
||||||
await passwordAuthProof.authorize(req.body.password);
|
await passwordAuthProof.authorize(req.body.password);
|
||||||
try {
|
try {
|
||||||
await this.getApp().as(AuthComponent).getAuthGuard().authenticateOrRegister(req.session!, passwordAuthProof);
|
await this.getApp().as(AuthComponent).getAuthGuard().authenticateOrRegister(req.session, passwordAuthProof);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof AuthError) {
|
if (e instanceof AuthError) {
|
||||||
Throttler.throttle('login_failed_attempts_user', 3, 180000, user.as(UserNameComponent).name!, 1000, 60000);
|
Throttler.throttle('login_failed_attempts_user', 3, 180000, <string>user.getOrFail('name'), 1000, 60000);
|
||||||
Throttler.throttle('login_failed_attempts_ip', 5, 60000, req.ip, 1000, 60000);
|
Throttler.throttle('login_failed_attempts_ip', 5, 60000, req.ip, 1000, 60000);
|
||||||
|
|
||||||
if (e instanceof PendingApprovalAuthError) {
|
if (e instanceof PendingApprovalAuthError) {
|
||||||
@ -54,7 +56,7 @@ export default class AuthController extends _AuthController {
|
|||||||
const bag = new ValidationBag();
|
const bag = new ValidationBag();
|
||||||
const err = new InvalidFormatValidationError('Invalid password.');
|
const err = new InvalidFormatValidationError('Invalid password.');
|
||||||
err.thingName = 'password';
|
err.thingName = 'password';
|
||||||
bag.addMessage(err)
|
bag.addMessage(err);
|
||||||
throw bag;
|
throw bag;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -80,9 +82,12 @@ export default class AuthController extends _AuthController {
|
|||||||
terms: new Validator().defined(),
|
terms: new Validator().defined(),
|
||||||
}, req.body);
|
}, req.body);
|
||||||
|
|
||||||
const passwordAuthProof = PasswordAuthProof.createAuthorizedProofForRegistration(req.session!);
|
if(!req.session) throw new ServerError('Session not initialized.');
|
||||||
|
|
||||||
|
const passwordAuthProof = PasswordAuthProof.createAuthorizedProofForRegistration(req.session);
|
||||||
try {
|
try {
|
||||||
await this.getApp().as(AuthComponent).getAuthGuard().authenticateOrRegister(req.session!, passwordAuthProof, undefined, async (connection, user) => {
|
await this.getApp().as(AuthComponent).getAuthGuard().authenticateOrRegister(req.session, passwordAuthProof,
|
||||||
|
undefined, async (connection, user) => {
|
||||||
passwordAuthProof.setResource(user);
|
passwordAuthProof.setResource(user);
|
||||||
|
|
||||||
const callbacks: RegisterCallback[] = [];
|
const callbacks: RegisterCallback[] = [];
|
||||||
@ -105,17 +110,17 @@ export default class AuthController extends _AuthController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const user = (await passwordAuthProof.getResource())!;
|
const user = await passwordAuthProof.getResource();
|
||||||
|
|
||||||
req.flash('success', `Your account was successfully created! Welcome, ${user.as(UserNameComponent).name}.`);
|
req.flash('success', `Your account was successfully created! Welcome, ${user?.as(UserNameComponent).name}.`);
|
||||||
res.redirect(Controller.route('home'));
|
res.redirect(Controller.route('home'));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async getCheckAuth(req: Request, res: Response, next: NextFunction): Promise<void> {
|
protected async getCheckAuth(): Promise<void> {
|
||||||
throw new ServerError('Not implemented.');
|
throw new ServerError('Not implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async postAuth(req: Request, res: Response, next: NextFunction): Promise<void> {
|
protected async postAuth(): Promise<void> {
|
||||||
throw new ServerError('Not implemented.');
|
throw new ServerError('Not implemented.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,28 +10,26 @@ import App from "../App";
|
|||||||
import AuthComponent from "wms-core/auth/AuthComponent";
|
import AuthComponent from "wms-core/auth/AuthComponent";
|
||||||
|
|
||||||
export default class MagicLinkController extends _MagicLinkController<App> {
|
export default class MagicLinkController extends _MagicLinkController<App> {
|
||||||
constructor(magicLinkWebSocketListener: MagicLinkWebSocketListener<App>) {
|
public constructor(magicLinkWebSocketListener: MagicLinkWebSocketListener<App>) {
|
||||||
super(magicLinkWebSocketListener);
|
super(magicLinkWebSocketListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async performAction(magicLink: MagicLink, req: Request, res: Response): Promise<void> {
|
protected async performAction(magicLink: MagicLink, req: Request, res: Response): Promise<void> {
|
||||||
switch (magicLink.action_type) {
|
if (magicLink.action_type === MagicLinkActionType.ADD_RECOVERY_EMAIL) {
|
||||||
case MagicLinkActionType.ADD_RECOVERY_EMAIL:
|
if (!req.session || !req.sessionID || magicLink.session_id !== req.sessionID) throw new BadOwnerMagicLink();
|
||||||
if (magicLink.session_id !== req.sessionID!) throw new BadOwnerMagicLink();
|
|
||||||
await magicLink.delete();
|
await magicLink.delete();
|
||||||
|
|
||||||
const authGuard = this.getApp().as(AuthComponent).getAuthGuard();
|
const authGuard = this.getApp().as(AuthComponent).getAuthGuard();
|
||||||
const proof = await authGuard.isAuthenticated(req.session!);
|
const proof = await authGuard.isAuthenticated(req.session);
|
||||||
const user = await proof?.getResource();
|
const user = await proof?.getResource();
|
||||||
if (!user) break;
|
if (!user) return;
|
||||||
|
|
||||||
const email = await magicLink.getOrFail('email');
|
const email = await magicLink.getOrFail('email');
|
||||||
|
|
||||||
// Existing email
|
|
||||||
if (await UserEmail.select().with('user').where('email', email).first()) {
|
if (await UserEmail.select().with('user').where('email', email).first()) {
|
||||||
req.flash('error', 'An account already exists with this email address. Please first remove it there before adding it here.');
|
req.flash('error', 'An account already exists with this email address. Please first remove it there before adding it here.');
|
||||||
res.redirect(Controller.route('account'));
|
res.redirect(Controller.route('account'));
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const userEmail = UserEmail.create({
|
const userEmail = UserEmail.create({
|
||||||
@ -48,7 +46,6 @@ export default class MagicLinkController extends _MagicLinkController<App> {
|
|||||||
|
|
||||||
req.flash('success', `Recovery email ${userEmail.email} successfully added.`);
|
req.flash('success', `Recovery email ${userEmail.email} successfully added.`);
|
||||||
res.redirect(Controller.route('account'));
|
res.redirect(Controller.route('account'));
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import Controller from "wms-core/Controller";
|
import Controller from "wms-core/Controller";
|
||||||
import {Request, Response} from "express";
|
import {Request, Response} from "express";
|
||||||
import config from "config";
|
|
||||||
import MailDomain from "../models/MailDomain";
|
import MailDomain from "../models/MailDomain";
|
||||||
|
|
||||||
export default class MailAutoConfigController extends Controller {
|
export default class MailAutoConfigController extends Controller {
|
||||||
|
@ -80,16 +80,19 @@ export default class MailboxBackendController extends Controller {
|
|||||||
.first();
|
.first();
|
||||||
if (!user) throw new NotFoundHttpError('User', req.url);
|
if (!user) throw new NotFoundHttpError('User', req.url);
|
||||||
|
|
||||||
|
const mainMailIdentity = await user.as(UserMailIdentityComponent).mainMailIdentity.get();
|
||||||
|
const mailDomains = await MailDomain.select().get();
|
||||||
|
const mailIdentities = await user.as(UserMailIdentityComponent).mailIdentities.get();
|
||||||
res.render('backend/mailbox', {
|
res.render('backend/mailbox', {
|
||||||
mailbox: {
|
mailbox: {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
name: await (await user.as(UserMailIdentityComponent).mainMailIdentity.get())?.toEmail() || 'Not created.',
|
name: await mainMailIdentity?.toEmail() || 'Not created.',
|
||||||
},
|
},
|
||||||
domains: (await MailDomain.select().get()).map(d => ({
|
domains: mailDomains.map(d => ({
|
||||||
display: d.name,
|
display: d.name,
|
||||||
value: d.id,
|
value: d.id,
|
||||||
})),
|
})),
|
||||||
identities: await Promise.all((await user.as(UserMailIdentityComponent).mailIdentities.get()).map(async i => ({
|
identities: await Promise.all(mailIdentities.map(async i => ({
|
||||||
id: i.id,
|
id: i.id,
|
||||||
email: await i.toEmail(),
|
email: await i.toEmail(),
|
||||||
}))),
|
}))),
|
||||||
@ -182,7 +185,7 @@ export default class MailboxBackendController extends Controller {
|
|||||||
req.flash('info', 'Mailbox created.');
|
req.flash('info', 'Mailbox created.');
|
||||||
}
|
}
|
||||||
|
|
||||||
req.flash('success', 'Mail identity ' + (await identity.toEmail()) + ' successfully created.')
|
req.flash('success', 'Mail identity ' + await identity.toEmail() + ' successfully created.');
|
||||||
res.redirectBack();
|
res.redirectBack();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,7 +204,7 @@ export default class MailboxBackendController extends Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await identity.delete();
|
await identity.delete();
|
||||||
req.flash('success', 'Identity ' + (await identity.toEmail()) + ' successfully deleted.');
|
req.flash('success', 'Identity ' + await identity.toEmail() + ' successfully deleted.');
|
||||||
res.redirectBack();
|
res.redirectBack();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import Model from "wms-core/db/Model";
|
import Model from "wms-core/db/Model";
|
||||||
import User from "wms-core/auth/models/User";
|
import User from "wms-core/auth/models/User";
|
||||||
import {ManyModelRelation, OneModelRelation} from "wms-core/db/ModelRelation";
|
import {ManyModelRelation, OneModelRelation} from "wms-core/db/ModelRelation";
|
||||||
import ModelFactory from "wms-core/db/ModelFactory";
|
|
||||||
import MailIdentity from "./MailIdentity";
|
import MailIdentity from "./MailIdentity";
|
||||||
|
|
||||||
export default class MailDomain extends Model {
|
export default class MailDomain extends Model {
|
||||||
@ -14,13 +13,14 @@ export default class MailDomain extends Model {
|
|||||||
foreignKey: 'id',
|
foreignKey: 'id',
|
||||||
});
|
});
|
||||||
|
|
||||||
public readonly identities: ManyModelRelation<MailDomain, MailIdentity> = new ManyModelRelation(this, MailIdentity, {
|
public readonly identities: ManyModelRelation<MailDomain, MailIdentity> = new ManyModelRelation(this, MailIdentity,
|
||||||
|
{
|
||||||
localKey: 'id',
|
localKey: 'id',
|
||||||
foreignKey: 'mail_domain_id',
|
foreignKey: 'mail_domain_id',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
public updateWithData(data: any) {
|
public updateWithData(data: Pick<this, keyof this> | Record<string, unknown>): void {
|
||||||
super.updateWithData(data);
|
super.updateWithData(data);
|
||||||
if (typeof this.user_id !== 'undefined' && this.user_id <= 0) {
|
if (typeof this.user_id !== 'undefined' && this.user_id <= 0) {
|
||||||
this.user_id = undefined;
|
this.user_id = undefined;
|
||||||
|
@ -33,6 +33,6 @@ export default class MailIdentity extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async toEmail(): Promise<string> {
|
public async toEmail(): Promise<string> {
|
||||||
return this.name + '@' + (await this.domain.get())!.name;
|
return this.name + '@' + (await this.domain.getOrFail())?.name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,26 +7,25 @@ import MailDomain from "./MailDomain";
|
|||||||
export default class UserMailIdentityComponent extends ModelComponent<User> {
|
export default class UserMailIdentityComponent extends ModelComponent<User> {
|
||||||
public main_mail_identity_id?: number = undefined;
|
public main_mail_identity_id?: number = undefined;
|
||||||
|
|
||||||
public readonly mailIdentities: ManyModelRelation<User, MailIdentity> = new ManyModelRelation(this._model, MailIdentity, {
|
public readonly mailIdentities: ManyModelRelation<User, MailIdentity> = new ManyModelRelation(this._model,
|
||||||
|
MailIdentity, {
|
||||||
localKey: 'id',
|
localKey: 'id',
|
||||||
foreignKey: 'user_id',
|
foreignKey: 'user_id',
|
||||||
});
|
});
|
||||||
public readonly publicMailIdentities: ManyModelRelation<User, MailIdentity> = this.mailIdentities.clone()
|
public readonly publicMailIdentities: ManyModelRelation<User, MailIdentity> = this.mailIdentities.clone()
|
||||||
.filter(async model => (await model.domain.get())!.isPublic());
|
.filter(async model => !!(await model.domain.getOrFail())?.isPublic());
|
||||||
|
|
||||||
public readonly mailDomains: ManyModelRelation<User, MailDomain> = new ManyModelRelation(this._model, MailDomain, {
|
public readonly mailDomains: ManyModelRelation<User, MailDomain> = new ManyModelRelation(this._model, MailDomain, {
|
||||||
localKey: 'id',
|
localKey: 'id',
|
||||||
foreignKey: 'user_id',
|
foreignKey: 'user_id',
|
||||||
});
|
});
|
||||||
|
|
||||||
public readonly mainMailIdentity: OneModelRelation<User, MailIdentity> = new OneModelRelation(this._model, MailIdentity, {
|
public readonly mainMailIdentity: OneModelRelation<User, MailIdentity> = new OneModelRelation(this._model,
|
||||||
|
MailIdentity, {
|
||||||
foreignKey: 'id',
|
foreignKey: 'id',
|
||||||
localKey: 'main_mail_identity_id',
|
localKey: 'main_mail_identity_id',
|
||||||
});
|
});
|
||||||
|
|
||||||
protected init(): void {
|
|
||||||
}
|
|
||||||
|
|
||||||
public getMaxPublicAddressesCount(): number {
|
public getMaxPublicAddressesCount(): number {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,6 @@ import ModelComponent from "wms-core/db/ModelComponent";
|
|||||||
export default class UserPasswordComponent extends ModelComponent<User> {
|
export default class UserPasswordComponent extends ModelComponent<User> {
|
||||||
private password?: string = undefined;
|
private password?: string = undefined;
|
||||||
|
|
||||||
public constructor(props: any) {
|
|
||||||
super(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
public init(): void {
|
public init(): void {
|
||||||
this.setValidation('password').acceptUndefined().maxLength(128);
|
this.setValidation('password').acceptUndefined().maxLength(128);
|
||||||
}
|
}
|
||||||
@ -51,22 +47,22 @@ export class PasswordAuthProof implements AuthProof<User> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private readonly session: Express.Session;
|
private readonly session: Express.Session;
|
||||||
private userID: number | null;
|
private userId: number | null;
|
||||||
private authorized: boolean;
|
private authorized: boolean;
|
||||||
private userPassword: UserPasswordComponent | null = null;
|
private userPassword: UserPasswordComponent | null = null;
|
||||||
|
|
||||||
private constructor(session: Express.Session) {
|
private constructor(session: Express.Session) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
this.authorized = session.auth_password_proof?.authorized || false;
|
this.authorized = session.auth_password_proof?.authorized || false;
|
||||||
this.userID = session.auth_password_proof?.userID || null;
|
this.userId = session.auth_password_proof?.userId || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getResource(): Promise<User | null> {
|
public async getResource(): Promise<User | null> {
|
||||||
return await User.getById(this.userID);
|
return await User.getById(this.userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public setResource(user: User) {
|
public setResource(user: User): void {
|
||||||
this.userID = user.id!;
|
this.userId = user.getOrFail('id');
|
||||||
this.save();
|
this.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,7 +71,7 @@ export class PasswordAuthProof implements AuthProof<User> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async isValid(): Promise<boolean> {
|
public async isValid(): Promise<boolean> {
|
||||||
if (typeof this.userID === 'number') {
|
if (typeof this.userId === 'number') {
|
||||||
return Boolean(await this.getResource());
|
return Boolean(await this.getResource());
|
||||||
} else {
|
} else {
|
||||||
return await this.isAuthorized();
|
return await this.isAuthorized();
|
||||||
@ -88,7 +84,7 @@ export class PasswordAuthProof implements AuthProof<User> {
|
|||||||
|
|
||||||
private async getUserPassword(): Promise<UserPasswordComponent | null> {
|
private async getUserPassword(): Promise<UserPasswordComponent | null> {
|
||||||
if (!this.userPassword) {
|
if (!this.userPassword) {
|
||||||
this.userPassword = (await User.getById(this.userID))?.as(UserPasswordComponent) || null;
|
this.userPassword = (await User.getById(this.userId))?.as(UserPasswordComponent) || null;
|
||||||
}
|
}
|
||||||
return this.userPassword;
|
return this.userPassword;
|
||||||
}
|
}
|
||||||
@ -105,7 +101,7 @@ export class PasswordAuthProof implements AuthProof<User> {
|
|||||||
private save() {
|
private save() {
|
||||||
this.session.auth_password_proof = {
|
this.session.auth_password_proof = {
|
||||||
authorized: this.authorized,
|
authorized: this.authorized,
|
||||||
userID: this.userID,
|
userID: this.userId,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user