@smpx/koa-request 0.2.7 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Request.js +89 -38
- package/basicAuth.js +1 -1
- package/botBanning.js +1 -1
- package/logger.js +22 -0
- package/package.json +5 -5
- package/rateLimit.js +1 -1
- package/staticPaths.js +14 -9
package/Request.js
CHANGED
|
@@ -10,6 +10,8 @@ const enableBasicAuth = require('./basicAuth');
|
|
|
10
10
|
const enableStaticPaths = require('./staticPaths');
|
|
11
11
|
const enableBotBanning = require('./botBanning');
|
|
12
12
|
|
|
13
|
+
const {setLogger, logError} = require('./logger');
|
|
14
|
+
|
|
13
15
|
const uaParser = new UAParser();
|
|
14
16
|
|
|
15
17
|
const ONE_HOUR = 3600 * 1000;
|
|
@@ -37,6 +39,7 @@ const COOKIEID_COOKIE = 'id';
|
|
|
37
39
|
const COOKIE_PARAM_PREFIX = '_ck_';
|
|
38
40
|
const USER_TOKEN_COOKIE = 'utok';
|
|
39
41
|
const FLASH_COOKIE = 'flash';
|
|
42
|
+
const VIEWPORT_WIDTH_COOKIE = 'vw';
|
|
40
43
|
// these cookies are httpOnly, should not be readable from js
|
|
41
44
|
const SENSITIVE_COOKIES = [USER_TOKEN_COOKIE, COOKIEID_COOKIE, SESSIONID_COOKIE];
|
|
42
45
|
|
|
@@ -122,19 +125,25 @@ function getIntegerKey(key) {
|
|
|
122
125
|
}
|
|
123
126
|
|
|
124
127
|
function addQuery(url, query = {}) {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
query
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
try {
|
|
129
|
+
const uri = new URL(url, 'http://localhost');
|
|
130
|
+
if (typeof query === 'string') {
|
|
131
|
+
query = new URLSearchParams(query);
|
|
132
|
+
for (const [key, val] of query) {
|
|
133
|
+
uri.searchParams.set(key, val);
|
|
134
|
+
}
|
|
130
135
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
136
|
+
else {
|
|
137
|
+
for (const [key, val] of Object.entries(query)) {
|
|
138
|
+
uri.searchParams.set(key, val);
|
|
139
|
+
}
|
|
135
140
|
}
|
|
141
|
+
return `${uri.pathname}${uri.search}`;
|
|
142
|
+
}
|
|
143
|
+
catch (e) {
|
|
144
|
+
logError(e);
|
|
145
|
+
return url;
|
|
136
146
|
}
|
|
137
|
-
return `${uri.pathname}${uri.search}`;
|
|
138
147
|
}
|
|
139
148
|
|
|
140
149
|
const isProduction = (process.env.NODE_ENV === 'production');
|
|
@@ -756,9 +765,21 @@ class Request {
|
|
|
756
765
|
return false;
|
|
757
766
|
}
|
|
758
767
|
|
|
759
|
-
if (
|
|
760
|
-
const
|
|
761
|
-
|
|
768
|
+
if (this._isMobileWeb == null) {
|
|
769
|
+
const secHeader = this.ctx.headers['sec-ch-ua-mobile'];
|
|
770
|
+
if (secHeader) {
|
|
771
|
+
this._isMobileWeb = secHeader === '?1';
|
|
772
|
+
}
|
|
773
|
+
else {
|
|
774
|
+
const vwCookie = this.cookie(VIEWPORT_WIDTH_COOKIE);
|
|
775
|
+
if (vwCookie) {
|
|
776
|
+
this._isMobileWeb = Number(vwCookie) <= 750;
|
|
777
|
+
}
|
|
778
|
+
else {
|
|
779
|
+
const ua = this.parseUserAgent();
|
|
780
|
+
this._isMobileWeb = (ua && ua.device && ua.device.type === 'mobile') || false;
|
|
781
|
+
}
|
|
782
|
+
}
|
|
762
783
|
}
|
|
763
784
|
return this._isMobileWeb;
|
|
764
785
|
}
|
|
@@ -767,6 +788,10 @@ class Request {
|
|
|
767
788
|
return this.isMobileApp() || this.isMobileWeb();
|
|
768
789
|
}
|
|
769
790
|
|
|
791
|
+
isAPI() {
|
|
792
|
+
return false;
|
|
793
|
+
}
|
|
794
|
+
|
|
770
795
|
platform() {
|
|
771
796
|
if (!this._platform) {
|
|
772
797
|
if (this.isMobileApp()) {
|
|
@@ -1218,7 +1243,20 @@ class Request {
|
|
|
1218
1243
|
};
|
|
1219
1244
|
}
|
|
1220
1245
|
|
|
1221
|
-
|
|
1246
|
+
let refererUri;
|
|
1247
|
+
try {
|
|
1248
|
+
refererUri = new URL(referer, 'http://localhost');
|
|
1249
|
+
}
|
|
1250
|
+
catch (e) {
|
|
1251
|
+
logError(e);
|
|
1252
|
+
return {
|
|
1253
|
+
name: '',
|
|
1254
|
+
source: 'direct',
|
|
1255
|
+
medium: 'direct',
|
|
1256
|
+
term: '',
|
|
1257
|
+
};
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1222
1260
|
let host = refererUri.hostname;
|
|
1223
1261
|
const baseDomain = this.baseDomain();
|
|
1224
1262
|
|
|
@@ -1271,16 +1309,22 @@ class Request {
|
|
|
1271
1309
|
* sets UTM cookies from a predefined url
|
|
1272
1310
|
*/
|
|
1273
1311
|
setUTMCookieFromUrl(url) {
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1312
|
+
try {
|
|
1313
|
+
const uri = (url instanceof URL) ? url : new URL(url, 'http://localhost');
|
|
1314
|
+
const params = uri.searchParams;
|
|
1315
|
+
this.setUTMCookieFromQuery({
|
|
1316
|
+
utm_source: params.get('utm_source'),
|
|
1317
|
+
utm_medium: params.get('utm_medium'),
|
|
1318
|
+
utm_campaign: params.get('utm_campaign'),
|
|
1319
|
+
utm_term: params.get('utm_term'),
|
|
1320
|
+
utm_content: params.get('utm_content'),
|
|
1321
|
+
gclid: params.get('gclid'),
|
|
1322
|
+
});
|
|
1323
|
+
}
|
|
1324
|
+
catch (e) {
|
|
1325
|
+
logError(e);
|
|
1326
|
+
// ignore error
|
|
1327
|
+
}
|
|
1284
1328
|
}
|
|
1285
1329
|
|
|
1286
1330
|
/**
|
|
@@ -1337,19 +1381,25 @@ class Request {
|
|
|
1337
1381
|
}
|
|
1338
1382
|
|
|
1339
1383
|
setAffidCookieFromUrl(url) {
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1384
|
+
try {
|
|
1385
|
+
const uri = (url instanceof URL) ? url : new URL(url, 'http://localhost');
|
|
1386
|
+
const params = uri.searchParams;
|
|
1387
|
+
const affid = params.get(AFFID_PARAM);
|
|
1388
|
+
if (!affid) return;
|
|
1389
|
+
const subaffid = params.get(SUBAFFID_PARAM);
|
|
1390
|
+
|
|
1391
|
+
this.cookie(
|
|
1392
|
+
AFFID_COOKIE,
|
|
1393
|
+
joinCookieParts([affid, subaffid]), {
|
|
1394
|
+
maxAge: AFFID_COOKIE_DURATION,
|
|
1395
|
+
domain: '*',
|
|
1396
|
+
},
|
|
1397
|
+
);
|
|
1398
|
+
}
|
|
1399
|
+
catch (e) {
|
|
1400
|
+
logError(e);
|
|
1401
|
+
// ignore error
|
|
1402
|
+
}
|
|
1353
1403
|
}
|
|
1354
1404
|
|
|
1355
1405
|
handlePlatformModification() {
|
|
@@ -1479,7 +1529,7 @@ class Request {
|
|
|
1479
1529
|
}
|
|
1480
1530
|
catch (e) {
|
|
1481
1531
|
this._flash = '';
|
|
1482
|
-
|
|
1532
|
+
logError('Error parsing flash message', e);
|
|
1483
1533
|
}
|
|
1484
1534
|
|
|
1485
1535
|
this.cookie(FLASH_COOKIE, null);
|
|
@@ -1561,4 +1611,5 @@ class Request {
|
|
|
1561
1611
|
}
|
|
1562
1612
|
}
|
|
1563
1613
|
|
|
1614
|
+
Request.setLogger = setLogger;
|
|
1564
1615
|
module.exports = Request;
|
package/basicAuth.js
CHANGED
package/botBanning.js
CHANGED
|
@@ -26,7 +26,7 @@ function banned(ctx, email) {
|
|
|
26
26
|
ctx.body = `<pre>Our system has detected unusual traffic from your ip ${ip}. Hence your ip has been banned temporarily.\n${emailStr}</pre>`;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
module.exports = function enableBotBanning(app, options
|
|
29
|
+
module.exports = function enableBotBanning(app, options) {
|
|
30
30
|
if (!options || options.enabled === false) return;
|
|
31
31
|
|
|
32
32
|
let userAgents = [];
|
package/logger.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
let globalLogger;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* set logger
|
|
5
|
+
*/
|
|
6
|
+
function setLogger(logger) {
|
|
7
|
+
globalLogger = logger;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function logError(...args) {
|
|
11
|
+
if (globalLogger !== undefined) {
|
|
12
|
+
if (globalLogger) globalLogger.error(...args);
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
console.error(...args);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
module.exports = {
|
|
20
|
+
setLogger,
|
|
21
|
+
logError,
|
|
22
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smpx/koa-request",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Handle basic tasks for koajs",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -30,12 +30,12 @@
|
|
|
30
30
|
},
|
|
31
31
|
"homepage": "https://github.com/smartprix/koa-request#readme",
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"ip": "^1.1.
|
|
33
|
+
"ip": "^1.1.8",
|
|
34
34
|
"koa-basic-auth": "^4.0.0",
|
|
35
|
-
"koa-body": "^
|
|
35
|
+
"koa-body": "^5.0.0",
|
|
36
36
|
"koa-send": "^5.0.1",
|
|
37
|
-
"koa2-ratelimit": "^
|
|
38
|
-
"maxmind": "^4.3.
|
|
37
|
+
"koa2-ratelimit": "^1.1.1",
|
|
38
|
+
"maxmind": "^4.3.6",
|
|
39
39
|
"tar": "^6.1.11",
|
|
40
40
|
"ua-parser-js": "^1.0.2"
|
|
41
41
|
},
|
package/rateLimit.js
CHANGED
package/staticPaths.js
CHANGED
|
@@ -13,16 +13,15 @@ function getMiddleware(options) {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
return async (ctx, next) => {
|
|
16
|
+
if (options.disabled) {
|
|
17
|
+
await next();
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
16
21
|
if (options.path === '/') {
|
|
17
22
|
// root requires special handling to check if extension denotes a static path
|
|
18
|
-
const
|
|
19
|
-
if (!
|
|
20
|
-
await next();
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// skip the current path
|
|
25
|
-
if (options.skip && options.skip(ctx)) {
|
|
23
|
+
const isStatic = /^\/(.*)\.(jpg|jpeg|gif|png|webp|avif|jxl|ico|css|js|mjs|json|ttf|otf|eot|woff|woff2|svg|svgz|xml|html|txt|ogg|ogv|mp4|av1|webm|rss|atom|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$/.test(ctx.path);
|
|
24
|
+
if (!isStatic) {
|
|
26
25
|
await next();
|
|
27
26
|
return;
|
|
28
27
|
}
|
|
@@ -34,6 +33,12 @@ function getMiddleware(options) {
|
|
|
34
33
|
return;
|
|
35
34
|
}
|
|
36
35
|
|
|
36
|
+
// skip the current path
|
|
37
|
+
if (options.skip && options.skip(ctx)) {
|
|
38
|
+
await next();
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
37
42
|
// only GET or GET like methods are allowed
|
|
38
43
|
if (!['get', 'head', 'options'].includes(ctx.method.toLowerCase())) {
|
|
39
44
|
ctx.body = 'Method Not Allowed';
|
|
@@ -43,7 +48,7 @@ function getMiddleware(options) {
|
|
|
43
48
|
|
|
44
49
|
if (options.immutable) {
|
|
45
50
|
// return a 304 not modified response, as immutables can't be modified
|
|
46
|
-
if (ctx.headers['if-modified-since']) {
|
|
51
|
+
if (ctx.headers['if-modified-since'] && !ctx.response.get('Cache-Control')) {
|
|
47
52
|
ctx.status = 304;
|
|
48
53
|
return;
|
|
49
54
|
}
|