summaryrefslogtreecommitdiff
path: root/src/server/api/limitter.ts
diff options
context:
space:
mode:
authorAkihiko Odaki <nekomanma@pixiv.co.jp>2018-03-29 01:20:40 +0900
committerAkihiko Odaki <nekomanma@pixiv.co.jp>2018-03-29 01:54:41 +0900
commit90f8fe7e538bb7e52d2558152a0390e693f39b11 (patch)
tree0f830887053c8f352b1cd0c13ca715fd14c1f030 /src/server/api/limitter.ts
parentImplement remote account resolution (diff)
downloadsharkey-90f8fe7e538bb7e52d2558152a0390e693f39b11.tar.gz
sharkey-90f8fe7e538bb7e52d2558152a0390e693f39b11.tar.bz2
sharkey-90f8fe7e538bb7e52d2558152a0390e693f39b11.zip
Introduce processor
Diffstat (limited to 'src/server/api/limitter.ts')
-rw-r--r--src/server/api/limitter.ts83
1 files changed, 83 insertions, 0 deletions
diff --git a/src/server/api/limitter.ts b/src/server/api/limitter.ts
new file mode 100644
index 0000000000..33337fbb1b
--- /dev/null
+++ b/src/server/api/limitter.ts
@@ -0,0 +1,83 @@
+import * as Limiter from 'ratelimiter';
+import * as debug from 'debug';
+import limiterDB from '../../db/redis';
+import { Endpoint } from './endpoints';
+import { IAuthContext } from './authenticate';
+import getAcct from '../common/user/get-acct';
+
+const log = debug('misskey:limitter');
+
+export default (endpoint: Endpoint, ctx: IAuthContext) => new Promise((ok, reject) => {
+ const limitation = endpoint.limit;
+
+ const key = limitation.hasOwnProperty('key')
+ ? limitation.key
+ : endpoint.name;
+
+ const hasShortTermLimit =
+ limitation.hasOwnProperty('minInterval');
+
+ const hasLongTermLimit =
+ limitation.hasOwnProperty('duration') &&
+ limitation.hasOwnProperty('max');
+
+ if (hasShortTermLimit) {
+ min();
+ } else if (hasLongTermLimit) {
+ max();
+ } else {
+ ok();
+ }
+
+ // Short-term limit
+ function min() {
+ const minIntervalLimiter = new Limiter({
+ id: `${ctx.user._id}:${key}:min`,
+ duration: limitation.minInterval,
+ max: 1,
+ db: limiterDB
+ });
+
+ minIntervalLimiter.get((err, info) => {
+ if (err) {
+ return reject('ERR');
+ }
+
+ log(`@${getAcct(ctx.user)} ${endpoint.name} min remaining: ${info.remaining}`);
+
+ if (info.remaining === 0) {
+ reject('BRIEF_REQUEST_INTERVAL');
+ } else {
+ if (hasLongTermLimit) {
+ max();
+ } else {
+ ok();
+ }
+ }
+ });
+ }
+
+ // Long term limit
+ function max() {
+ const limiter = new Limiter({
+ id: `${ctx.user._id}:${key}`,
+ duration: limitation.duration,
+ max: limitation.max,
+ db: limiterDB
+ });
+
+ limiter.get((err, info) => {
+ if (err) {
+ return reject('ERR');
+ }
+
+ log(`@${getAcct(ctx.user)} ${endpoint.name} max remaining: ${info.remaining}`);
+
+ if (info.remaining === 0) {
+ reject('RATE_LIMIT_EXCEEDED');
+ } else {
+ ok();
+ }
+ });
+ }
+});