2022-02-25 04:13:14 +13:00
|
|
|
import appEndpoints from "./applications"
|
|
|
|
import queryEndpoints from "./queries"
|
|
|
|
import tableEndpoints from "./tables"
|
|
|
|
import rowEndpoints from "./rows"
|
|
|
|
import userEndpoints from "./users"
|
|
|
|
import usage from "../../../middleware/usageQuota"
|
|
|
|
import authorized from "../../../middleware/authorized"
|
2022-03-16 09:17:41 +13:00
|
|
|
import publicApi from "../../../middleware/publicApi"
|
2022-02-25 04:13:14 +13:00
|
|
|
import { paramResource, paramSubResource } from "../../../middleware/resourceId"
|
|
|
|
import { CtxFn } from "./utils/Endpoint"
|
2022-03-02 07:35:08 +13:00
|
|
|
import mapperMiddleware from "./middleware/mapper"
|
2022-03-03 00:36:30 +13:00
|
|
|
import env from "../../../environment"
|
|
|
|
// below imports don't have declaration files
|
2022-02-18 07:58:09 +13:00
|
|
|
const Router = require("@koa/router")
|
2022-03-04 01:19:12 +13:00
|
|
|
const { RateLimit, Stores } = require("koa2-ratelimit")
|
2022-02-23 07:40:09 +13:00
|
|
|
const {
|
|
|
|
PermissionLevels,
|
|
|
|
PermissionTypes,
|
|
|
|
} = require("@budibase/backend-core/permissions")
|
2022-03-03 01:27:09 +13:00
|
|
|
const { getRedisOptions } = require("@budibase/backend-core/redis").utils
|
2022-02-18 07:58:09 +13:00
|
|
|
|
|
|
|
const PREFIX = "/api/public/v1"
|
2022-03-04 01:31:56 +13:00
|
|
|
// allow a lot more requests when in test
|
|
|
|
const DEFAULT_API_REQ_LIMIT_PER_SEC = env.isTest() ? 100 : 10
|
2022-03-04 01:03:29 +13:00
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
2022-03-03 00:36:30 +13:00
|
|
|
|
2022-03-03 01:50:10 +13:00
|
|
|
if (!env.isTest()) {
|
|
|
|
const REDIS_OPTS = getRedisOptions()
|
2022-03-15 18:44:43 +13:00
|
|
|
let options
|
2022-03-15 23:52:24 +13:00
|
|
|
if (REDIS_OPTS.redisProtocolUrl) {
|
|
|
|
// fully qualified redis URL
|
2022-03-15 18:44:43 +13:00
|
|
|
options = {
|
|
|
|
url: REDIS_OPTS.redisProtocolUrl,
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
options = {
|
2022-03-03 01:50:10 +13:00
|
|
|
socket: {
|
|
|
|
host: REDIS_OPTS.host,
|
|
|
|
port: REDIS_OPTS.port,
|
|
|
|
},
|
|
|
|
password: REDIS_OPTS.opts.password,
|
|
|
|
database: 1,
|
2022-03-15 18:44:43 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
RateLimit.defaultOptions({
|
2022-03-15 23:52:24 +13:00
|
|
|
store: new Stores.Redis(options),
|
2022-03-03 01:50:10 +13:00
|
|
|
})
|
|
|
|
}
|
2022-03-03 00:36:30 +13:00
|
|
|
// rate limiting, allows for 2 requests per second
|
|
|
|
const limiter = RateLimit.middleware({
|
2022-03-04 01:03:29 +13:00
|
|
|
interval: { sec: 1 },
|
2022-03-03 00:36:30 +13:00
|
|
|
// per ip, per interval
|
2022-03-04 01:03:29 +13:00
|
|
|
max: getApiLimitPerSecond(),
|
2022-03-03 00:36:30 +13:00
|
|
|
})
|
2022-02-18 07:58:09 +13:00
|
|
|
|
2022-02-23 07:40:09 +13:00
|
|
|
const publicRouter = new Router({
|
2022-02-18 07:58:09 +13:00
|
|
|
prefix: PREFIX,
|
|
|
|
})
|
2022-02-23 07:40:09 +13:00
|
|
|
|
2022-03-03 00:36:30 +13:00
|
|
|
publicRouter.use(limiter)
|
|
|
|
|
2022-03-02 07:35:08 +13:00
|
|
|
function addMiddleware(
|
|
|
|
endpoints: any,
|
|
|
|
middleware: CtxFn,
|
|
|
|
opts: { output: boolean } = { output: false }
|
|
|
|
) {
|
2022-02-26 04:55:19 +13:00
|
|
|
if (!endpoints) {
|
|
|
|
return
|
|
|
|
}
|
2022-02-25 01:03:46 +13:00
|
|
|
if (!Array.isArray(endpoints)) {
|
|
|
|
endpoints = [endpoints]
|
|
|
|
}
|
2022-02-23 07:40:09 +13:00
|
|
|
for (let endpoint of endpoints) {
|
2022-03-02 07:35:08 +13:00
|
|
|
if (opts?.output) {
|
|
|
|
endpoint.addOutputMiddleware(middleware)
|
|
|
|
} else {
|
|
|
|
endpoint.addMiddleware(middleware)
|
|
|
|
}
|
2022-02-23 07:40:09 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-25 04:13:14 +13:00
|
|
|
function addToRouter(endpoints: any) {
|
2022-02-26 04:55:19 +13:00
|
|
|
if (endpoints) {
|
|
|
|
for (let endpoint of endpoints) {
|
|
|
|
endpoint.apply(publicRouter)
|
|
|
|
}
|
2022-02-23 07:40:09 +13:00
|
|
|
}
|
2022-02-18 07:58:09 +13:00
|
|
|
}
|
|
|
|
|
2022-02-25 04:13:14 +13:00
|
|
|
function applyRoutes(
|
|
|
|
endpoints: any,
|
|
|
|
permType: string,
|
|
|
|
resource: string,
|
|
|
|
subResource?: string
|
|
|
|
) {
|
2022-02-23 07:40:09 +13:00
|
|
|
const paramMiddleware = subResource
|
|
|
|
? paramSubResource(resource, subResource)
|
|
|
|
: paramResource(resource)
|
2022-03-16 09:17:41 +13:00
|
|
|
const publicApiMiddleware = publicApi({
|
|
|
|
requiresAppId:
|
|
|
|
permType !== PermissionTypes.APP && permType !== PermissionTypes.USER,
|
|
|
|
})
|
|
|
|
addMiddleware(endpoints.read, publicApiMiddleware)
|
|
|
|
addMiddleware(endpoints.write, publicApiMiddleware)
|
2022-03-02 07:35:08 +13:00
|
|
|
// add the parameter capture middleware
|
2022-03-16 09:17:41 +13:00
|
|
|
addMiddleware(endpoints.read, paramMiddleware)
|
|
|
|
addMiddleware(endpoints.write, paramMiddleware)
|
2022-03-02 07:35:08 +13:00
|
|
|
// add the authorization middleware, using the correct perm type
|
2022-02-23 07:40:09 +13:00
|
|
|
addMiddleware(endpoints.read, authorized(permType, PermissionLevels.READ))
|
|
|
|
addMiddleware(endpoints.write, authorized(permType, PermissionLevels.WRITE))
|
2022-03-02 07:35:08 +13:00
|
|
|
// add the usage quota middleware
|
2022-02-23 07:40:09 +13:00
|
|
|
addMiddleware(endpoints.write, usage)
|
2022-03-16 09:17:41 +13:00
|
|
|
// add the output mapper middleware
|
|
|
|
addMiddleware(endpoints.read, mapperMiddleware, { output: true })
|
|
|
|
addMiddleware(endpoints.write, mapperMiddleware, { output: true })
|
2022-02-23 07:40:09 +13:00
|
|
|
addToRouter(endpoints.read)
|
|
|
|
addToRouter(endpoints.write)
|
|
|
|
}
|
|
|
|
|
|
|
|
applyRoutes(appEndpoints, PermissionTypes.APP, "appId")
|
|
|
|
applyRoutes(tableEndpoints, PermissionTypes.TABLE, "tableId")
|
|
|
|
applyRoutes(userEndpoints, PermissionTypes.USER, "userId")
|
|
|
|
applyRoutes(queryEndpoints, PermissionTypes.QUERY, "queryId")
|
2022-02-25 04:13:14 +13:00
|
|
|
// needs to be applied last for routing purposes, don't override other endpoints
|
|
|
|
applyRoutes(rowEndpoints, PermissionTypes.TABLE, "tableId", "rowId")
|
2022-02-23 07:40:09 +13:00
|
|
|
|
|
|
|
module.exports = publicRouter
|