Merge pull request #4764 from Budibase/feature/rate-limiting
Public API IP rate limiting
This commit is contained in:
commit
987c9ea0c1
|
@ -108,6 +108,7 @@
|
||||||
"koa-send": "5.0.0",
|
"koa-send": "5.0.0",
|
||||||
"koa-session": "5.12.0",
|
"koa-session": "5.12.0",
|
||||||
"koa-static": "5.0.0",
|
"koa-static": "5.0.0",
|
||||||
|
"koa2-ratelimit": "^1.1.0",
|
||||||
"lodash": "4.17.21",
|
"lodash": "4.17.21",
|
||||||
"memorystream": "^0.3.1",
|
"memorystream": "^0.3.1",
|
||||||
"mongodb": "3.6.3",
|
"mongodb": "3.6.3",
|
||||||
|
@ -123,6 +124,7 @@
|
||||||
"pouchdb-all-dbs": "1.0.2",
|
"pouchdb-all-dbs": "1.0.2",
|
||||||
"pouchdb-find": "^7.2.2",
|
"pouchdb-find": "^7.2.2",
|
||||||
"pouchdb-replication-stream": "1.2.9",
|
"pouchdb-replication-stream": "1.2.9",
|
||||||
|
"redis": "4",
|
||||||
"server-destroy": "1.0.1",
|
"server-destroy": "1.0.1",
|
||||||
"svelte": "^3.38.2",
|
"svelte": "^3.38.2",
|
||||||
"swagger-parser": "^10.0.3",
|
"swagger-parser": "^10.0.3",
|
||||||
|
@ -148,6 +150,7 @@
|
||||||
"@types/koa-router": "^7.4.2",
|
"@types/koa-router": "^7.4.2",
|
||||||
"@types/node": "^15.12.4",
|
"@types/node": "^15.12.4",
|
||||||
"@types/oracledb": "^5.2.1",
|
"@types/oracledb": "^5.2.1",
|
||||||
|
"@types/redis": "^4.0.11",
|
||||||
"@typescript-eslint/parser": "4.28.0",
|
"@typescript-eslint/parser": "4.28.0",
|
||||||
"apidoc": "^0.50.2",
|
"apidoc": "^0.50.2",
|
||||||
"babel-jest": "^27.0.2",
|
"babel-jest": "^27.0.2",
|
||||||
|
|
|
@ -58,7 +58,7 @@ module External {
|
||||||
) {
|
) {
|
||||||
const primary = table.primary
|
const primary = table.primary
|
||||||
// if passed in array need to copy for shifting etc
|
// if passed in array need to copy for shifting etc
|
||||||
let idCopy = cloneDeep(id)
|
let idCopy: undefined | string | any[] = cloneDeep(id)
|
||||||
if (filters) {
|
if (filters) {
|
||||||
// need to map over the filters and make sure the _id field isn't present
|
// need to map over the filters and make sure the _id field isn't present
|
||||||
for (let filter of Object.values(filters)) {
|
for (let filter of Object.values(filters)) {
|
||||||
|
|
|
@ -8,18 +8,54 @@ import authorized from "../../../middleware/authorized"
|
||||||
import { paramResource, paramSubResource } from "../../../middleware/resourceId"
|
import { paramResource, paramSubResource } from "../../../middleware/resourceId"
|
||||||
import { CtxFn } from "./utils/Endpoint"
|
import { CtxFn } from "./utils/Endpoint"
|
||||||
import mapperMiddleware from "./middleware/mapper"
|
import mapperMiddleware from "./middleware/mapper"
|
||||||
|
import env from "../../../environment"
|
||||||
|
// below imports don't have declaration files
|
||||||
const Router = require("@koa/router")
|
const Router = require("@koa/router")
|
||||||
|
const { RateLimit, Stores } = require("koa2-ratelimit")
|
||||||
const {
|
const {
|
||||||
PermissionLevels,
|
PermissionLevels,
|
||||||
PermissionTypes,
|
PermissionTypes,
|
||||||
} = require("@budibase/backend-core/permissions")
|
} = require("@budibase/backend-core/permissions")
|
||||||
|
const { getRedisOptions } = require("@budibase/backend-core/redis").utils
|
||||||
|
|
||||||
const PREFIX = "/api/public/v1"
|
const PREFIX = "/api/public/v1"
|
||||||
|
// allow a lot more requests when in test
|
||||||
|
const DEFAULT_API_REQ_LIMIT_PER_SEC = env.isTest() ? 100 : 10
|
||||||
|
|
||||||
|
function getApiLimitPerSecond(): number {
|
||||||
|
if (!env.API_REQ_LIMIT_PER_SEC) {
|
||||||
|
return DEFAULT_API_REQ_LIMIT_PER_SEC
|
||||||
|
}
|
||||||
|
return parseInt(env.API_REQ_LIMIT_PER_SEC)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!env.isTest()) {
|
||||||
|
const REDIS_OPTS = getRedisOptions()
|
||||||
|
RateLimit.defaultOptions({
|
||||||
|
store: new Stores.Redis({
|
||||||
|
// @ts-ignore
|
||||||
|
socket: {
|
||||||
|
host: REDIS_OPTS.host,
|
||||||
|
port: REDIS_OPTS.port,
|
||||||
|
},
|
||||||
|
password: REDIS_OPTS.opts.password,
|
||||||
|
database: 1,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// rate limiting, allows for 2 requests per second
|
||||||
|
const limiter = RateLimit.middleware({
|
||||||
|
interval: { sec: 1 },
|
||||||
|
// per ip, per interval
|
||||||
|
max: getApiLimitPerSecond(),
|
||||||
|
})
|
||||||
|
|
||||||
const publicRouter = new Router({
|
const publicRouter = new Router({
|
||||||
prefix: PREFIX,
|
prefix: PREFIX,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
publicRouter.use(limiter)
|
||||||
|
|
||||||
function addMiddleware(
|
function addMiddleware(
|
||||||
endpoints: any,
|
endpoints: any,
|
||||||
middleware: CtxFn,
|
middleware: CtxFn,
|
||||||
|
|
|
@ -45,6 +45,7 @@ module.exports = {
|
||||||
INTERNAL_API_KEY: process.env.INTERNAL_API_KEY,
|
INTERNAL_API_KEY: process.env.INTERNAL_API_KEY,
|
||||||
MULTI_TENANCY: process.env.MULTI_TENANCY,
|
MULTI_TENANCY: process.env.MULTI_TENANCY,
|
||||||
HTTP_MIGRATIONS: process.env.HTTP_MIGRATIONS,
|
HTTP_MIGRATIONS: process.env.HTTP_MIGRATIONS,
|
||||||
|
API_REQ_LIMIT_PER_SEC: process.env.API_REQ_LIMIT_PER_SEC,
|
||||||
// environment
|
// environment
|
||||||
NODE_ENV: process.env.NODE_ENV,
|
NODE_ENV: process.env.NODE_ENV,
|
||||||
JEST_WORKER_ID: process.env.JEST_WORKER_ID,
|
JEST_WORKER_ID: process.env.JEST_WORKER_ID,
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue