File tree Expand file tree Collapse file tree 7 files changed +298
-99
lines changed
website/docs/configuration Expand file tree Collapse file tree 7 files changed +298
-99
lines changed Original file line number Diff line number Diff line change 24
24
"description" : " Provide domains to use alternative to the defaults" ,
25
25
"type" : " object"
26
26
},
27
+ "rateLimit" : {
28
+ "description" : " API Rate limiting configuration." ,
29
+ "type" : " object" ,
30
+ "properties" : {
31
+ "windowMs" : {
32
+ "type" : " number" ,
33
+ "description" : " How long to remember requests for, in milliseconds (default 10 mins)."
34
+ },
35
+ "limit" : {
36
+ "type" : " number" ,
37
+ "description" : " How many requests to allow (default 150)."
38
+ },
39
+ "statusCode" : {
40
+ "type" : " number" ,
41
+ "description" : " HTTP status code after limit is reached (default is 429)."
42
+ },
43
+ "message" : {
44
+ "type" : " string" ,
45
+ "description" : " Response to return after limit is reached."
46
+ }
47
+ },
48
+ "required" : [" windowMs" , " limit" ],
49
+ "additionalProperties" : false
50
+ },
27
51
"privateOrganizations" : {
28
52
"description" : " Pattern searches for listed private organizations are disabled" ,
29
53
"type" : " array"
Original file line number Diff line number Diff line change 2
2
"proxyUrl" : " https://github.com" ,
3
3
"cookieSecret" : " cookie secret" ,
4
4
"sessionMaxAgeHours" : 12 ,
5
+ "rateLimit" : {
6
+ "windowMs" : 60000 ,
7
+ "limit" : 150
8
+ },
5
9
"tempPassword" : {
6
10
"sendEmail" : false ,
7
11
"emailConfig" : {}
Original file line number Diff line number Diff line change 6
6
Authentication ,
7
7
AuthorisedRepo ,
8
8
Database ,
9
+ RateLimitConfig ,
9
10
TempPasswordConfig ,
10
11
UserSettings ,
11
12
} from './types' ;
@@ -30,6 +31,8 @@ let _urlShortener: string = defaultSettings.urlShortener;
30
31
let _contactEmail : string = defaultSettings . contactEmail ;
31
32
let _csrfProtection : boolean = defaultSettings . csrfProtection ;
32
33
let _domains : Record < string , unknown > = defaultSettings . domains ;
34
+ let _rateLimit : RateLimitConfig = defaultSettings . rateLimit ;
35
+
33
36
// These are not always present in the default config file, so casting is required
34
37
let _tlsEnabled = defaultSettings . tls . enabled ;
35
38
let _tlsKeyPemPath = defaultSettings . tls . key ;
@@ -99,6 +102,7 @@ export const logConfiguration = () => {
99
102
console . log ( `authorisedList = ${ JSON . stringify ( getAuthorisedList ( ) ) } ` ) ;
100
103
console . log ( `data sink = ${ JSON . stringify ( getDatabase ( ) ) } ` ) ;
101
104
console . log ( `authentication = ${ JSON . stringify ( getAuthentication ( ) ) } ` ) ;
105
+ console . log ( `rateLimit = ${ JSON . stringify ( getRateLimit ( ) ) } ` ) ;
102
106
} ;
103
107
104
108
export const getAPIs = ( ) => {
@@ -217,3 +221,10 @@ export const getDomains = () => {
217
221
}
218
222
return _domains ;
219
223
} ;
224
+
225
+ export const getRateLimit = ( ) => {
226
+ if ( _userSettings && _userSettings . rateLimit ) {
227
+ _rateLimit = _userSettings . rateLimit ;
228
+ }
229
+ return _rateLimit ;
230
+ } ;
Original file line number Diff line number Diff line change
1
+ import { Options as RateLimitOptions } from 'express-rate-limit' ;
2
+
1
3
export interface UserSettings {
2
4
authorisedList : AuthorisedRepo [ ] ;
3
5
sink : Database [ ] ;
@@ -18,6 +20,7 @@ export interface UserSettings {
18
20
contactEmail : string ;
19
21
csrfProtection : boolean ;
20
22
domains : Record < string , unknown > ;
23
+ rateLimit : RateLimitConfig ;
21
24
}
22
25
23
26
export interface TLSConfig {
@@ -50,3 +53,7 @@ export interface TempPasswordConfig {
50
53
sendEmail : boolean ;
51
54
emailConfig : Record < string , unknown > ;
52
55
}
56
+
57
+ export type RateLimitConfig = Partial <
58
+ Pick < RateLimitOptions , 'windowMs' | 'limit' | 'message' | 'statusCode' >
59
+ > ;
Original file line number Diff line number Diff line change @@ -9,10 +9,7 @@ const db = require('../db');
9
9
const rateLimit = require ( 'express-rate-limit' ) ;
10
10
const lusca = require ( 'lusca' ) ;
11
11
12
- const limiter = rateLimit ( {
13
- windowMs : 15 * 60 * 1000 , // 15 minutes
14
- max : 100 , // limit each IP to 100 requests per windowMs
15
- } ) ;
12
+ const limiter = rateLimit ( config . getRateLimit ( ) ) ;
16
13
17
14
const { GIT_PROXY_UI_PORT : uiPort } = require ( '../config/env' ) . serverConfig ;
18
15
Original file line number Diff line number Diff line change @@ -16,6 +16,7 @@ describe('default configuration', function () {
16
16
expect ( config . getDatabase ( ) ) . to . be . eql ( defaultSettings . sink [ 0 ] ) ;
17
17
expect ( config . getTempPasswordConfig ( ) ) . to . be . eql ( defaultSettings . tempPassword ) ;
18
18
expect ( config . getAuthorisedList ( ) ) . to . be . eql ( defaultSettings . authorisedList ) ;
19
+ expect ( config . getRateLimit ( ) ) . to . be . eql ( defaultSettings . rateLimit ) ;
19
20
expect ( config . getTLSKeyPemPath ( ) ) . to . be . eql ( defaultSettings . tls . key ) ;
20
21
expect ( config . getTLSCertPemPath ( ) ) . to . be . eql ( defaultSettings . tls . cert ) ;
21
22
} ) ;
@@ -107,6 +108,21 @@ describe('user configuration', function () {
107
108
expect ( config . getTLSCertPemPath ( ) ) . to . be . eql ( user . tls . cert ) ;
108
109
} ) ;
109
110
111
+ it ( 'should override default settings for rate limiting' , function ( ) {
112
+ const limitConfig = {
113
+ rateLimit : {
114
+ windowMs : 60000 ,
115
+ limit : 1500 ,
116
+ } ,
117
+ } ;
118
+ fs . writeFileSync ( tempUserFile , JSON . stringify ( limitConfig ) ) ;
119
+
120
+ const config = require ( '../src/config' ) ;
121
+
122
+ expect ( config . getRateLimit ( ) . windowMs ) . to . be . eql ( limitConfig . rateLimit . windowMs ) ;
123
+ expect ( config . getRateLimit ( ) . limit ) . to . be . eql ( limitConfig . rateLimit . limit ) ;
124
+ } ) ;
125
+
110
126
afterEach ( function ( ) {
111
127
fs . rmSync ( tempUserFile ) ;
112
128
fs . rmdirSync ( tempDir ) ;
You can’t perform that action at this time.
0 commit comments