Fix linting errors

This commit is contained in:
Alice Gaudon 2020-11-22 14:13:57 +01:00
parent 5e7d29ab98
commit 83ab56b4ac
13 changed files with 55 additions and 39 deletions

View File

@ -104,7 +104,7 @@ export default class App extends Application {
this.use(redisComponent);
this.use(new SessionComponent(redisComponent));
this.use(new AuthComponent(new class extends AuthGuard<MagicLink | AuthToken> {
public async getProofForSession(session: Session): Promise<any | null> {
public async getProofForSession(session: Session): Promise<MagicLink | AuthToken | null> {
return await MagicLink.bySessionId(
session.id,
[MagicLinkActionType.LOGIN, MagicLinkActionType.REGISTER],
@ -122,7 +122,7 @@ export default class App extends Application {
return token;
}
return super.getProofForRequest(req);
return await super.getProofForRequest(req);
}
}(this)));

View File

@ -14,4 +14,4 @@ export default async function generateSlug(tries: number): Promise<string> {
i++;
} while (i < tries);
throw new ServerError('Failed to generate slug; newly generated slug size should be increased by 1.');
};
}

View File

@ -1,4 +1,4 @@
export function encodeRFC5987ValueChars(str: string) {
export function encodeRFC5987ValueChars(str: string): string {
return encodeURIComponent(str).
// Note that although RFC3986 reserves "!", RFC5987 does not,
// so we do not need to escape it

View File

@ -2,7 +2,7 @@ import Controller from "swaf/Controller";
import {Request, Response} from "express";
export default class AboutController extends Controller {
routes(): void {
public routes(): void {
this.get('/', this.getAbout, 'home');
this.get('/', this.getAbout, 'about');
}

View File

@ -5,7 +5,7 @@ import AuthToken from "../models/AuthToken";
import {BadRequestError, ForbiddenHttpError, NotFoundHttpError} from "swaf/HttpError";
export default class AuthTokenController extends Controller {
routes(): void {
public routes(): void {
this.post('/gen-auth-token', this.postGenAuthToken, 'generate-token', RequireAuthMiddleware);
this.post('/revoke-auth-token/:id', this.postRevokeAuthToken, 'revoke-token', RequireAuthMiddleware);
}

View File

@ -13,7 +13,7 @@ import FileUploadMiddleware from "swaf/FileUploadMiddleware";
export default class FileController extends Controller {
routes(): void {
public routes(): void {
this.get('/files/upload', this.getFileUploader, 'file-upload', RequireAuthMiddleware);
this.get('/files/upload/script', this.downloadLinuxScript, 'file-linux-script');
this.post('/files/post', this.postFileFrontend, 'post-file-frontend', RequireAuthMiddleware, FileUploadFormMiddleware);
@ -45,12 +45,18 @@ export default class FileController extends Controller {
protected async postFileFrontend(req: Request, res: Response): Promise<void> {
req.body.type = 'file';
await FileController.handleFileUpload(req.body.autogen_url === undefined && req.body.slug ? req.body.slug : await generateSlug(10), req, res);
await FileController.handleFileUpload(
req.body.autogen_url === undefined && req.body.slug ?
req.body.slug :
await generateSlug(10),
req,
res,
);
}
public static async handleFileUpload(slug: string, req: Request, res: Response): Promise<void> {
// Check for file upload
if (!req.files || !req.files['upload']) {
if (Object.keys(req.files).indexOf('upload') < 0) {
throw new BadRequestError('No file received.', 'You must upload exactly one (1) file.', req.url);
}
@ -75,7 +81,7 @@ export default class FileController extends Controller {
});
await file.save();
fs.renameSync(upload.path, file.storage_path!);
fs.renameSync(upload.path, file.getOrFail('storage_path'));
const domain = req.body.url_domain || config.get<string[]>('allowed_url_domains')[config.get<number>('default_url_domain_for_files')];
res.format({
@ -122,7 +128,7 @@ export default class FileController extends Controller {
}
public static async deleteFile(file: FileModel): Promise<void> {
fs.unlinkSync(file.storage_path!);
fs.unlinkSync(file.getOrFail('storage_path'));
await file.delete();
log.info('Deleted', file.storage_path, `(${file.real_name})`);
}

View File

@ -14,7 +14,7 @@ import {promisify} from "util";
import {log} from "swaf/Logger";
export default class LinkController extends Controller {
routes(): void {
public routes(): void {
this.post('/', this.postFile, 'post-file', RequireRequestAuthMiddleware, FileUploadFormMiddleware);
this.delete('/:slug', FileController.deleteFileRoute, 'delete-file', RequireRequestAuthMiddleware);
this.get('/:slug', this.getFile, 'get-file');
@ -29,7 +29,6 @@ export default class LinkController extends Controller {
}
protected async getFile(req: Request, res: Response, next: NextFunction): Promise<void> {
console.log('get file', req.params.slug)
const file = await FileModel.getBySlug(req.params.slug);
if (!file) return next();
if (file.shouldBeDeleted()) {
@ -37,16 +36,16 @@ export default class LinkController extends Controller {
return next();
}
const fileName = file.real_name!;
const fileName = file.getOrFail('real_name');
switch (file.storage_type) {
case 'local':
const stats = await promisify(fs.stat)(file.storage_path!);
case 'local': {
const stats = await promisify(fs.stat)(file.getOrFail('storage_path'));
// If file is bigger than max hotlink size, fallback to express download
if (stats.size > config.get<number>('max_hotlink_size') * 1024 * 1024) {
log.info(`Fallback to express download for file of size ${stats.size}`);
return res.download(file.storage_path!, fileName);
return res.download(file.getOrFail('storage_path'), fileName);
}
// File type
@ -56,11 +55,12 @@ export default class LinkController extends Controller {
// File name
res.header('Content-Disposition', `inline; filename*=UTF-8''${encodeRFC5987ValueChars(fileName)}`);
fs.readFile(file.storage_path!, (err, data) => {
fs.readFile(file.getOrFail('storage_path'), (err, data) => {
if (err) return next(err);
res.send(data);
});
break;
}
default:
throw new ServerError(`This file cannot be served. Download protocol for ${file.storage_type} storage type not implemented.`);
}
@ -84,7 +84,7 @@ export default class LinkController extends Controller {
const url = await URLRedirect.getBySlug(req.params.slug);
if (!url) return next();
res.redirect(url.target_url!, 301);
res.redirect(url.getOrFail('target_url'), 301);
}
protected async deleteURL(req: Request, res: Response, next: NextFunction): Promise<void> {
@ -94,7 +94,7 @@ export default class LinkController extends Controller {
throw new BadRequestError(
'Deleting url redirects is disabled for security reasons.',
'If you still want to disable the redirection, please contact us via email.',
req.url
req.url,
);
}

View File

@ -9,16 +9,16 @@ import App from "../App";
import AuthComponent from "swaf/auth/AuthComponent";
export default class MagicLinkController extends _MagicLinkController<App> {
constructor(magicLinkWebSocketListener: MagicLinkWebSocketListener<App>) {
public constructor(magicLinkWebSocketListener: MagicLinkWebSocketListener<App>) {
super(magicLinkWebSocketListener);
}
protected async performAction(magicLink: MagicLink, req: Request, res: Response): Promise<void> {
switch (magicLink.action_type) {
case MagicLinkActionType.LOGIN:
case MagicLinkActionType.REGISTER:
case MagicLinkActionType.REGISTER: {
await AuthController.checkAndAuth(req, res, magicLink);
const proof = await this.getApp().as(AuthComponent).getAuthGuard().isAuthenticated(req.session!);
const proof = await this.getApp().as(AuthComponent).getAuthGuard().isAuthenticated(req.getSession());
const user = await proof?.getResource();
if (!res.headersSent && user) {
@ -27,6 +27,7 @@ export default class MagicLinkController extends _MagicLinkController<App> {
res.redirect(req.query.redirect_uri?.toString() || Controller.route('home'));
}
break;
}
}
}
}

View File

@ -7,7 +7,7 @@ import config from "config";
import AuthToken from "../models/AuthToken";
export default class URLRedirectController extends Controller {
routes(): void {
public routes(): void {
this.get('/url/shrink', this.getURLShrinker, 'url-shrinker', RequireAuthMiddleware);
this.get('/url/shrink/script', this.downloadLinuxScript, 'url-linux-script');
this.post('/url/shrink', this.addURLFrontend, 'shrink-url', RequireAuthMiddleware);
@ -37,7 +37,14 @@ export default class URLRedirectController extends Controller {
protected async addURLFrontend(req: Request, res: Response, next: NextFunction): Promise<void> {
req.body.type = 'url';
await URLRedirectController.addURL(req, res, next, req.body.autogen_url === undefined && req.body.slug ? req.body.slug : await generateSlug(10));
await URLRedirectController.addURL(
req,
res,
next,
req.body.autogen_url === undefined && req.body.slug ?
req.body.slug :
await generateSlug(10),
);
}
public static async addURL(req: Request, res: Response, next: NextFunction, slug?: string): Promise<void> {

View File

@ -9,7 +9,4 @@ export default class IncreaseFilesSizeField extends Migration {
public async rollback(connection: Connection): Promise<void> {
await this.query(`ALTER TABLE files MODIFY size INT UNSIGNED`, connection);
}
public registerModels(): void {
}
}

View File

@ -6,34 +6,35 @@ import {cryptoRandomDictionary} from "swaf/Utils";
export default class AuthToken extends Model implements AuthProof<User> {
public id?: number = undefined;
protected readonly user_id?: number = undefined;
protected readonly secret?: string = undefined;
private secret?: string = undefined;
protected created_at?: Date = undefined;
protected used_at?: Date = undefined;
protected readonly ttl?: number = undefined;
protected init() {
protected init(): void {
this.setValidation('user_id').defined().exists(User, 'id');
this.setValidation('secret').defined().between(32, 64);
this.setValidation('ttl').defined().min(1).max(5 * 365 * 24 * 3600 /* 5 years */);
}
protected async autoFill(): Promise<void> {
// @ts-ignore
if (!this.secret) this['secret'] = cryptoRandomDictionary(64, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_');
if (!this.secret) {
this.secret = cryptoRandomDictionary(64, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_');
}
}
public use() {
public use(): void {
this.used_at = new Date();
}
public canDelete(user_id: number) {
public canDelete(user_id: number): boolean {
return this.user_id === user_id;
}
public getExpirationDate(): Date {
if (!this.created_at) return new Date();
return new Date(this.created_at.getTime() + this.ttl! * 1000);
return new Date(this.created_at.getTime() + this.getOrFail('ttl') * 1000);
}
public async getResource(): Promise<User | null> {
@ -51,4 +52,8 @@ export default class AuthToken extends Model implements AuthProof<User> {
public async revoke(): Promise<void> {
await this.delete();
}
protected getSecret(): string | undefined {
return this.secret;
}
}

View File

@ -28,7 +28,7 @@ export default class FileModel extends Model {
public created_at?: Date = undefined;
public readonly ttl?: number = undefined;
protected init() {
protected init(): void {
this.setValidation('user_id').defined().exists(User, 'id');
this.setValidation('slug').defined().minLength(1).maxLength(259).unique(FileModel, 'slug').unique(URLRedirect, 'slug');
this.setValidation('real_name').defined().minLength(1).maxLength(259);
@ -40,7 +40,7 @@ export default class FileModel extends Model {
public getURL(domain: string = config.get<string>('base_url')): string {
return (/^https?:\/\//.test(domain) ? '' : 'https://') + domain + Controller.route('get-file', {
slug: this.slug!,
slug: this.getOrFail('slug'),
});
}
@ -48,7 +48,7 @@ export default class FileModel extends Model {
if (!this.created_at) return new Date();
if (this.ttl === 0) return null;
return new Date(this.created_at.getTime() + this.ttl! * 1000);
return new Date(this.created_at.getTime() + this.getOrFail('ttl') * 1000);
}
public shouldBeDeleted(): boolean {

View File

@ -32,7 +32,7 @@ export default class URLRedirect extends Model {
public getURL(domain: string = config.get<string>('base_url')): string {
return (/^https?:\/\//.test(domain) ? '' : 'https://') + domain + Controller.route('get-url', {
slug: this.slug!,
slug: this.getOrFail('slug'),
});
}
}