summaryrefslogtreecommitdiff
path: root/src/api/api-handler.ts
blob: fb603a0e2aa7526a6eeedd29816d132f09e291c8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import * as express from 'express';

import { Endpoint } from './endpoints';
import authenticate from './authenticate';
import { IAuthContext } from './authenticate';
import _reply from './reply';
import limitter from './limitter';

export default async (endpoint: Endpoint, req: express.Request, res: express.Response) => {
	const reply = _reply.bind(null, res);
	let ctx: IAuthContext;

	// Authentication
	try {
		ctx = await authenticate(req);
	} catch (e) {
		return reply(403, 'AUTHENTICATION_FAILED');
	}

	if (endpoint.secure && !ctx.isSecure) {
		return reply(403, 'ACCESS_DENIED');
	}

	if (endpoint.withCredential && ctx.user == null) {
		return reply(401, 'PLZ_SIGNIN');
	}

	if (ctx.app && endpoint.kind) {
		if (!ctx.app.permission.some(p => p === endpoint.kind)) {
			return reply(403, 'ACCESS_DENIED');
		}
	}

	if (endpoint.withCredential && endpoint.limit) {
		try {
			await limitter(endpoint, ctx); // Rate limit
		} catch (e) {
			// drop request if limit exceeded
			return reply(429);
		}
	}

	let exec = require(`${__dirname}/endpoints/${endpoint.name}`);

	if (endpoint.withFile) {
		exec = exec.bind(null, req.file);
	}

	// API invoking
	try {
		const res = await exec(req.body, ctx.user, ctx.app, ctx.isSecure);
		reply(res);
	} catch (e) {
		reply(400, e);
	}
};