@universis/janitor v1.6.3
@universis/janitor

Universis api plugin for rate limiting requests or slowing down service responses.
Usage
npm i @universis/janitorRateLimitService
RateLimitService is a configurable extension of express-rate-limit for limiting service requests.
Register service under application services:
{
"services": [
{
"serviceType": "@universis/janitor#RateLimitService"
}
]
}and start configuring rate limited endpoints under settings/universis/rateLimit:
{
"settings": {
"universis": {
"rateLimit": {
"profiles": [
[
"userRateLimitProfile",
{
"windowMs": 300000,
"limit": 50,
"legacyHeaders": true
}
]
],
"paths": [
[
"/users/me",
{
"profile": "userRateLimitProfile"
}
]
]
}
}
}
}RateLimitService service configuration consists of a collection of rate limit profiles that are going to used as options during request validation and a collection of paths for defining rate limited route paths.
Read more about rate limit configuration at express-rate-limit documentation
Enable rate limit headers over CORS
Each RateLimitService profile has an option to include a set of headers in the response. This can be done by setting the headers option to true in the profile configuration. This operation will add the following headers to the response:
X-RateLimit-Limit- the maximum number of requests allowed in the current windowX-RateLimit-Remaining- the number of requests remaining in the current windowX-RateLimit-Reset- the number of milliseconds remaining until the window resets
Rate limit headers will be available only if the request is made from the same origin. If the request is made from a different origin, the headers will not be included in the response and should be configured to be exposed by CORS.
{
"settings": {
"cors": {
"exposedHeaders": [
"X-Rate-Limit",
"X-Rate-Remaining",
"X-Rate-Reset"
]
}
}
}SpeedLimitService
SpeedLimitService is a configurable extension of express-slow-down for slowing down service responses.
Register service under application services:
{
"services": [
{
"serviceType": "@universis/janitor#SpeedLimitService"
}
]
}and start configuring speed limited endpoints under settings/universis/speedLimit:
{
"settings": {
"universis": {
"speedLimit": {
"profiles": [
[
"userSpeedLimitProfile",
{
"windowMs": 300000,
"delayAfter": 5,
"delayMs": 500,
"maxDelayMs": 20000,
"headers": true
}
]
],
"paths": [
[
"/users/me",
{
"profile": "userSpeedLimitProfile"
}
]
]
}
}
}
}SpeedLimitService configuration consists of a collection of speed limit profiles that are going to used as options during request validation and a collection of paths for defining speed limited route paths.
Read more about speed limit configuration at express-slow-down documentation
SpeedLimitService offers two additional options for delaying response: randomDelayMs and randomMaxDelayMs. These options are used for adding random delay to the response. They define the range of random delay in milliseconds.
{
"settings": {
"universis": {
"speedLimit": {
"profiles": [
[
"userSpeedLimitProfile",
{
"windowMs": 120000,
"delayAfter": 5,
"randomDelayMs": [
500,
1000
],
"headers": false
}
]
],
"paths": [
[
"/users/me",
{
"profile": "userSpeedLimitProfile"
}
]
]
}
}
}
} If randomDelayMs is set, delayMs is ignored.
randomMaxDelayMs is used for setting the maximum random delay. If randomMaxDelayMs is not set, the maximum delay is set to maxDelayMs is ignored e.g.
{
"settings": {
"universis": {
"speedLimit": {
"profiles": [
[
"userSpeedLimitProfile",
{
"windowMs": 120000,
"delayAfter": 5,
"delayMs": 500,
"randomMaxDelayMs": [
7000,
12000
],
"headers": false
}
]
],
"paths": [
[
"/users/me",
{
"profile": "userSpeedLimitProfile"
}
]
]
}
}
}
}Enable speed limit headers over CORS
Each SpeedLimitService profile has an option to include a set of headers in the response. This can be done by setting the headers option to true in the profile configuration. This operation will add the following headers to the response:
X-SlowDown-Limit- the maximum number of requests allowed in the current windowX-SlowDown-Remaining- the number of requests remaining in the current windowX-SlowDown-Reset- the number of milliseconds remaining until the window resets
Speed limit headers will be available only if the request is made from the same origin. If the request is made from a different origin, the headers will not be included in the response and should be configured to be exposed by CORS.
{
"settings": {
"cors": {
"exposedHeaders": [
"X-SlowDown-Limit",
"X-SlowDown-Remaining",
"X-SlowDown-Reset"
]
}
}
}ScopeAccessConfiguration
ScopeAccessConfiguration is a configurable application service for limiting access to service endpoints based on user scopes.
Register service under application services:
{
"services": [
{
"serviceType": "@universis/janitor#ScopeAccessConfiguration"
}
]
}add <config directory>/scope.access.json and start configuring scope limited endpoints:
[
{
"scope": [
"registrar"
],
"resource": "/api/",
"access": [
"read",
"write"
]
},
{
"scope": [
"students",
"teachers",
"registrar"
],
"resource": "/api/workspaces/locales",
"access": [
"read"
]
}
]Each configuration element consists of scope array, resource string and access array.
If the user has at least one of the scopes from the scope array,
and the user has at least one of the access array, the user will be granted access to the resource.
There are two different access types:
read- grants access to read the resource (GET, HEAD, OPTIONS)write- grants access to write the resource (POST, PUT, PATCH, DELETE)
The resource string can be a path or a regular expression e.g. /api/instructors/me/exams/(\d+)/types
validateScope express.js middleware is available for validating user scope access to the resource:
import { validateScope } from '@universis/janitor';
app.use('/api', passport.authenticate('bearer', {session: false}), validateScope(), (req, res) => {
res.send('Hello World!')
});A 403 - Access denied due to authorization scopes error will be thrown if the user does not have access to the resource.
ExtendScopeAccessConfiguration
ExtendScopeAccessConfiguration is a configurable application service for extending scope access configuration with additional scopes.
Register service under application services:
{
"services": [
{
"serviceType": "@universis/janitor#ExtendScopeAccessConfiguration"
}
]
}add scopeAccess section under settings/universis/janitor configuration and start configuring scope access extension:
{
"settings": {
"universis": {
"janitor": {
"scopeAccess": {
"imports": [
"./custom.scope.access.json"
],
}
}
}
}
}ExtendScopeAccessConfiguration service will import additional scope access configuration from the files listed in the imports array. The file path is relative to the application configuration directory e.g. server/config/ where the main configuration file is located.
The given files should contain an array of scope access configuration elements as described in the ScopeAccessConfiguration section.
RemoteAddressValidator
RemoteAddressValidator is a configurable application service for validating access to service endpoints based on remote address provided by OAuth2 token.
Register service under application services:
{
"services": [
{
"serviceType": "@universis/janitor#RemoteAddressValidator"
}
]
}RemoteAddressValidator validates the remote address of the request with the remote address provided by the OAuth2 token. If the addresses do not match, a 403 - Access denied due to remote address error will be thrown. Token remote address is provided by the remoteAddress claim in the token payload. It can be configured in the OAuth2 server configuration and may have a different name. This name may be configured in the settings/universis/janitor/remoteAddress configuration e.g.
{
"settings": {
"universis": {
"janitor": {
"remoteAddress": {
"claim": "ipAddress"
}
}
}
}
}where claim is the name of the remote address claim in the token payload.
Important Note: If api server is served by a proxy, the remote address may be different from the client address. In this case, the proxy should be configured to forward the client address to the server. This scenario should be configured in application settings under settings/universis/api/ section e.g.
{
"settings": {
"universis": {
"api": {
"proxyAddressForwarding": true
}
}
}
}