Fix linting errors
This commit is contained in:
parent
5e7d29ab98
commit
83ab56b4ac
@ -104,7 +104,7 @@ export default class App extends Application {
|
|||||||
this.use(redisComponent);
|
this.use(redisComponent);
|
||||||
this.use(new SessionComponent(redisComponent));
|
this.use(new SessionComponent(redisComponent));
|
||||||
this.use(new AuthComponent(new class extends AuthGuard<MagicLink | AuthToken> {
|
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(
|
return await MagicLink.bySessionId(
|
||||||
session.id,
|
session.id,
|
||||||
[MagicLinkActionType.LOGIN, MagicLinkActionType.REGISTER],
|
[MagicLinkActionType.LOGIN, MagicLinkActionType.REGISTER],
|
||||||
@ -122,7 +122,7 @@ export default class App extends Application {
|
|||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.getProofForRequest(req);
|
return await super.getProofForRequest(req);
|
||||||
}
|
}
|
||||||
}(this)));
|
}(this)));
|
||||||
|
|
||||||
|
@ -14,4 +14,4 @@ export default async function generateSlug(tries: number): Promise<string> {
|
|||||||
i++;
|
i++;
|
||||||
} while (i < tries);
|
} while (i < tries);
|
||||||
throw new ServerError('Failed to generate slug; newly generated slug size should be increased by 1.');
|
throw new ServerError('Failed to generate slug; newly generated slug size should be increased by 1.');
|
||||||
};
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export function encodeRFC5987ValueChars(str: string) {
|
export function encodeRFC5987ValueChars(str: string): string {
|
||||||
return encodeURIComponent(str).
|
return encodeURIComponent(str).
|
||||||
// Note that although RFC3986 reserves "!", RFC5987 does not,
|
// Note that although RFC3986 reserves "!", RFC5987 does not,
|
||||||
// so we do not need to escape it
|
// so we do not need to escape it
|
||||||
|
@ -2,7 +2,7 @@ import Controller from "swaf/Controller";
|
|||||||
import {Request, Response} from "express";
|
import {Request, Response} from "express";
|
||||||
|
|
||||||
export default class AboutController extends Controller {
|
export default class AboutController extends Controller {
|
||||||
routes(): void {
|
public routes(): void {
|
||||||
this.get('/', this.getAbout, 'home');
|
this.get('/', this.getAbout, 'home');
|
||||||
this.get('/', this.getAbout, 'about');
|
this.get('/', this.getAbout, 'about');
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import AuthToken from "../models/AuthToken";
|
|||||||
import {BadRequestError, ForbiddenHttpError, NotFoundHttpError} from "swaf/HttpError";
|
import {BadRequestError, ForbiddenHttpError, NotFoundHttpError} from "swaf/HttpError";
|
||||||
|
|
||||||
export default class AuthTokenController extends Controller {
|
export default class AuthTokenController extends Controller {
|
||||||
routes(): void {
|
public routes(): void {
|
||||||
this.post('/gen-auth-token', this.postGenAuthToken, 'generate-token', RequireAuthMiddleware);
|
this.post('/gen-auth-token', this.postGenAuthToken, 'generate-token', RequireAuthMiddleware);
|
||||||
this.post('/revoke-auth-token/:id', this.postRevokeAuthToken, 'revoke-token', RequireAuthMiddleware);
|
this.post('/revoke-auth-token/:id', this.postRevokeAuthToken, 'revoke-token', RequireAuthMiddleware);
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ import FileUploadMiddleware from "swaf/FileUploadMiddleware";
|
|||||||
|
|
||||||
|
|
||||||
export default class FileController extends Controller {
|
export default class FileController extends Controller {
|
||||||
routes(): void {
|
public routes(): void {
|
||||||
this.get('/files/upload', this.getFileUploader, 'file-upload', RequireAuthMiddleware);
|
this.get('/files/upload', this.getFileUploader, 'file-upload', RequireAuthMiddleware);
|
||||||
this.get('/files/upload/script', this.downloadLinuxScript, 'file-linux-script');
|
this.get('/files/upload/script', this.downloadLinuxScript, 'file-linux-script');
|
||||||
this.post('/files/post', this.postFileFrontend, 'post-file-frontend', RequireAuthMiddleware, FileUploadFormMiddleware);
|
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> {
|
protected async postFileFrontend(req: Request, res: Response): Promise<void> {
|
||||||
req.body.type = 'file';
|
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> {
|
public static async handleFileUpload(slug: string, req: Request, res: Response): Promise<void> {
|
||||||
// Check for file upload
|
// 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);
|
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();
|
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')];
|
const domain = req.body.url_domain || config.get<string[]>('allowed_url_domains')[config.get<number>('default_url_domain_for_files')];
|
||||||
res.format({
|
res.format({
|
||||||
@ -122,7 +128,7 @@ export default class FileController extends Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static async deleteFile(file: FileModel): Promise<void> {
|
public static async deleteFile(file: FileModel): Promise<void> {
|
||||||
fs.unlinkSync(file.storage_path!);
|
fs.unlinkSync(file.getOrFail('storage_path'));
|
||||||
await file.delete();
|
await file.delete();
|
||||||
log.info('Deleted', file.storage_path, `(${file.real_name})`);
|
log.info('Deleted', file.storage_path, `(${file.real_name})`);
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ import {promisify} from "util";
|
|||||||
import {log} from "swaf/Logger";
|
import {log} from "swaf/Logger";
|
||||||
|
|
||||||
export default class LinkController extends Controller {
|
export default class LinkController extends Controller {
|
||||||
routes(): void {
|
public routes(): void {
|
||||||
this.post('/', this.postFile, 'post-file', RequireRequestAuthMiddleware, FileUploadFormMiddleware);
|
this.post('/', this.postFile, 'post-file', RequireRequestAuthMiddleware, FileUploadFormMiddleware);
|
||||||
this.delete('/:slug', FileController.deleteFileRoute, 'delete-file', RequireRequestAuthMiddleware);
|
this.delete('/:slug', FileController.deleteFileRoute, 'delete-file', RequireRequestAuthMiddleware);
|
||||||
this.get('/:slug', this.getFile, 'get-file');
|
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> {
|
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);
|
const file = await FileModel.getBySlug(req.params.slug);
|
||||||
if (!file) return next();
|
if (!file) return next();
|
||||||
if (file.shouldBeDeleted()) {
|
if (file.shouldBeDeleted()) {
|
||||||
@ -37,16 +36,16 @@ export default class LinkController extends Controller {
|
|||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileName = file.real_name!;
|
const fileName = file.getOrFail('real_name');
|
||||||
|
|
||||||
switch (file.storage_type) {
|
switch (file.storage_type) {
|
||||||
case 'local':
|
case 'local': {
|
||||||
const stats = await promisify(fs.stat)(file.storage_path!);
|
const stats = await promisify(fs.stat)(file.getOrFail('storage_path'));
|
||||||
|
|
||||||
// If file is bigger than max hotlink size, fallback to express download
|
// If file is bigger than max hotlink size, fallback to express download
|
||||||
if (stats.size > config.get<number>('max_hotlink_size') * 1024 * 1024) {
|
if (stats.size > config.get<number>('max_hotlink_size') * 1024 * 1024) {
|
||||||
log.info(`Fallback to express download for file of size ${stats.size}`);
|
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
|
// File type
|
||||||
@ -56,11 +55,12 @@ export default class LinkController extends Controller {
|
|||||||
// File name
|
// File name
|
||||||
res.header('Content-Disposition', `inline; filename*=UTF-8''${encodeRFC5987ValueChars(fileName)}`);
|
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);
|
if (err) return next(err);
|
||||||
res.send(data);
|
res.send(data);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
throw new ServerError(`This file cannot be served. Download protocol for ${file.storage_type} storage type not implemented.`);
|
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);
|
const url = await URLRedirect.getBySlug(req.params.slug);
|
||||||
if (!url) return next();
|
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> {
|
protected async deleteURL(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||||
@ -94,7 +94,7 @@ export default class LinkController extends Controller {
|
|||||||
throw new BadRequestError(
|
throw new BadRequestError(
|
||||||
'Deleting url redirects is disabled for security reasons.',
|
'Deleting url redirects is disabled for security reasons.',
|
||||||
'If you still want to disable the redirection, please contact us via email.',
|
'If you still want to disable the redirection, please contact us via email.',
|
||||||
req.url
|
req.url,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,16 +9,16 @@ import App from "../App";
|
|||||||
import AuthComponent from "swaf/auth/AuthComponent";
|
import AuthComponent from "swaf/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) {
|
switch (magicLink.action_type) {
|
||||||
case MagicLinkActionType.LOGIN:
|
case MagicLinkActionType.LOGIN:
|
||||||
case MagicLinkActionType.REGISTER:
|
case MagicLinkActionType.REGISTER: {
|
||||||
await AuthController.checkAndAuth(req, res, magicLink);
|
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();
|
const user = await proof?.getResource();
|
||||||
|
|
||||||
if (!res.headersSent && user) {
|
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'));
|
res.redirect(req.query.redirect_uri?.toString() || Controller.route('home'));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import config from "config";
|
|||||||
import AuthToken from "../models/AuthToken";
|
import AuthToken from "../models/AuthToken";
|
||||||
|
|
||||||
export default class URLRedirectController extends Controller {
|
export default class URLRedirectController extends Controller {
|
||||||
routes(): void {
|
public routes(): void {
|
||||||
this.get('/url/shrink', this.getURLShrinker, 'url-shrinker', RequireAuthMiddleware);
|
this.get('/url/shrink', this.getURLShrinker, 'url-shrinker', RequireAuthMiddleware);
|
||||||
this.get('/url/shrink/script', this.downloadLinuxScript, 'url-linux-script');
|
this.get('/url/shrink/script', this.downloadLinuxScript, 'url-linux-script');
|
||||||
this.post('/url/shrink', this.addURLFrontend, 'shrink-url', RequireAuthMiddleware);
|
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> {
|
protected async addURLFrontend(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||||
req.body.type = 'url';
|
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> {
|
public static async addURL(req: Request, res: Response, next: NextFunction, slug?: string): Promise<void> {
|
||||||
|
@ -9,7 +9,4 @@ export default class IncreaseFilesSizeField extends Migration {
|
|||||||
public async rollback(connection: Connection): Promise<void> {
|
public async rollback(connection: Connection): Promise<void> {
|
||||||
await this.query(`ALTER TABLE files MODIFY size INT UNSIGNED`, connection);
|
await this.query(`ALTER TABLE files MODIFY size INT UNSIGNED`, connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
public registerModels(): void {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -6,34 +6,35 @@ import {cryptoRandomDictionary} from "swaf/Utils";
|
|||||||
export default class AuthToken extends Model implements AuthProof<User> {
|
export default class AuthToken extends Model implements AuthProof<User> {
|
||||||
public id?: number = undefined;
|
public id?: number = undefined;
|
||||||
protected readonly user_id?: number = undefined;
|
protected readonly user_id?: number = undefined;
|
||||||
protected readonly secret?: string = undefined;
|
private secret?: string = undefined;
|
||||||
protected created_at?: Date = undefined;
|
protected created_at?: Date = undefined;
|
||||||
protected used_at?: Date = undefined;
|
protected used_at?: Date = undefined;
|
||||||
protected readonly ttl?: number = undefined;
|
protected readonly ttl?: number = undefined;
|
||||||
|
|
||||||
protected init() {
|
protected init(): void {
|
||||||
this.setValidation('user_id').defined().exists(User, 'id');
|
this.setValidation('user_id').defined().exists(User, 'id');
|
||||||
this.setValidation('secret').defined().between(32, 64);
|
this.setValidation('secret').defined().between(32, 64);
|
||||||
this.setValidation('ttl').defined().min(1).max(5 * 365 * 24 * 3600 /* 5 years */);
|
this.setValidation('ttl').defined().min(1).max(5 * 365 * 24 * 3600 /* 5 years */);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async autoFill(): Promise<void> {
|
protected async autoFill(): Promise<void> {
|
||||||
// @ts-ignore
|
if (!this.secret) {
|
||||||
if (!this.secret) this['secret'] = cryptoRandomDictionary(64, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_');
|
this.secret = cryptoRandomDictionary(64, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public use() {
|
public use(): void {
|
||||||
this.used_at = new Date();
|
this.used_at = new Date();
|
||||||
}
|
}
|
||||||
|
|
||||||
public canDelete(user_id: number) {
|
public canDelete(user_id: number): boolean {
|
||||||
return this.user_id === user_id;
|
return this.user_id === user_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getExpirationDate(): Date {
|
public getExpirationDate(): Date {
|
||||||
if (!this.created_at) return new 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> {
|
public async getResource(): Promise<User | null> {
|
||||||
@ -51,4 +52,8 @@ export default class AuthToken extends Model implements AuthProof<User> {
|
|||||||
public async revoke(): Promise<void> {
|
public async revoke(): Promise<void> {
|
||||||
await this.delete();
|
await this.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected getSecret(): string | undefined {
|
||||||
|
return this.secret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ export default class FileModel extends Model {
|
|||||||
public created_at?: Date = undefined;
|
public created_at?: Date = undefined;
|
||||||
public readonly ttl?: number = undefined;
|
public readonly ttl?: number = undefined;
|
||||||
|
|
||||||
protected init() {
|
protected init(): void {
|
||||||
this.setValidation('user_id').defined().exists(User, 'id');
|
this.setValidation('user_id').defined().exists(User, 'id');
|
||||||
this.setValidation('slug').defined().minLength(1).maxLength(259).unique(FileModel, 'slug').unique(URLRedirect, 'slug');
|
this.setValidation('slug').defined().minLength(1).maxLength(259).unique(FileModel, 'slug').unique(URLRedirect, 'slug');
|
||||||
this.setValidation('real_name').defined().minLength(1).maxLength(259);
|
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 {
|
public getURL(domain: string = config.get<string>('base_url')): string {
|
||||||
return (/^https?:\/\//.test(domain) ? '' : 'https://') + domain + Controller.route('get-file', {
|
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.created_at) return new Date();
|
||||||
if (this.ttl === 0) return null;
|
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 {
|
public shouldBeDeleted(): boolean {
|
||||||
|
@ -32,7 +32,7 @@ export default class URLRedirect extends Model {
|
|||||||
|
|
||||||
public getURL(domain: string = config.get<string>('base_url')): string {
|
public getURL(domain: string = config.get<string>('base_url')): string {
|
||||||
return (/^https?:\/\//.test(domain) ? '' : 'https://') + domain + Controller.route('get-url', {
|
return (/^https?:\/\//.test(domain) ? '' : 'https://') + domain + Controller.route('get-url', {
|
||||||
slug: this.slug!,
|
slug: this.getOrFail('slug'),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user