@smpx/koa-request 0.4.3 → 1.0.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/GeoIP.js +13 -4
- package/IPRange.js +11 -5
- package/Request.js +102 -153
- package/index.js +2 -0
- package/package.json +6 -6
package/GeoIP.js
CHANGED
|
@@ -9,6 +9,7 @@ const fileName = 'GeoLite2-City';
|
|
|
9
9
|
const fileUrl = `https://raw.githubusercontent.com/GitSquared/node-geolite2-redist/master/redist/${fileName}.tar.gz`;
|
|
10
10
|
const fileDir = __dirname;
|
|
11
11
|
const filePath = `${fileDir}/${fileName}.mmdb`;
|
|
12
|
+
let geoInitPromise;
|
|
12
13
|
let geoip;
|
|
13
14
|
|
|
14
15
|
function save(url, outDir) {
|
|
@@ -84,13 +85,21 @@ async function updateDb() {
|
|
|
84
85
|
setTimeout(updateDb, 3 * 24 * 3600 * 1000);
|
|
85
86
|
}
|
|
86
87
|
|
|
88
|
+
async function geoIpInit() {
|
|
89
|
+
await download();
|
|
90
|
+
geoip = await maxmind.open(filePath);
|
|
91
|
+
if (process.env.NODE_ENV === 'production') {
|
|
92
|
+
updateDb();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
87
96
|
async function getGeoIp() {
|
|
88
97
|
if (!geoip) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if (process.env.NODE_ENV === 'production') {
|
|
92
|
-
updateDb();
|
|
98
|
+
if (!geoInitPromise) {
|
|
99
|
+
geoInitPromise = geoIpInit();
|
|
93
100
|
}
|
|
101
|
+
await geoInitPromise;
|
|
102
|
+
geoInitPromise = null;
|
|
94
103
|
}
|
|
95
104
|
return geoip;
|
|
96
105
|
}
|
package/IPRange.js
CHANGED
|
@@ -11,6 +11,7 @@ const PRIVATE_IPS = [
|
|
|
11
11
|
];
|
|
12
12
|
|
|
13
13
|
// Source: https://www.lifewire.com/what-is-the-ip-address-of-google-818153
|
|
14
|
+
// https://developers.google.com/search/apis/ipranges/googlebot.json
|
|
14
15
|
const GOOGLE_IPS = [
|
|
15
16
|
'64.233.160.0 - 64.233.191.255',
|
|
16
17
|
'66.102.0.0 - 66.102.15.255',
|
|
@@ -27,11 +28,16 @@ const GOOGLE_IPS = [
|
|
|
27
28
|
];
|
|
28
29
|
|
|
29
30
|
const SEARCH_IPS = [
|
|
30
|
-
|
|
31
|
-
'
|
|
32
|
-
'
|
|
33
|
-
'
|
|
34
|
-
'
|
|
31
|
+
// BingBot (https://www.bing.com/toolbox/bingbot.json)
|
|
32
|
+
'157.55.0.0/16',
|
|
33
|
+
'207.46.0.0/19',
|
|
34
|
+
'52.167.144.0/24',
|
|
35
|
+
'40.77.128.0/17',
|
|
36
|
+
// YANDAX
|
|
37
|
+
'178.154.128.0/17',
|
|
38
|
+
'87.250.224.0/19',
|
|
39
|
+
// Apple
|
|
40
|
+
'17.0.0.0/8',
|
|
35
41
|
];
|
|
36
42
|
|
|
37
43
|
let compiledPrivateIps;
|
package/Request.js
CHANGED
|
@@ -22,7 +22,6 @@ const TEN_YEARS = 10 * ONE_YEAR;
|
|
|
22
22
|
|
|
23
23
|
const PLATFORM_PARAM = 'platform';
|
|
24
24
|
const PLATFORM_COOKIE = 'platform';
|
|
25
|
-
const PLATFORM_COOKIE_DURATION = 4 * ONE_HOUR;
|
|
26
25
|
const APPINFO_PARAM = 'sm_app';
|
|
27
26
|
const APPINFO_COOKIE = 'sm_app';
|
|
28
27
|
const APPINFO_HEADER = 'sm-app';
|
|
@@ -399,7 +398,6 @@ class Request {
|
|
|
399
398
|
this.ctx.set('Content-Security-Policy', `frame-ancestors https://*.${domain}`);
|
|
400
399
|
}
|
|
401
400
|
|
|
402
|
-
this.handlePlatformModification();
|
|
403
401
|
if (!this.isAjax()) {
|
|
404
402
|
this.setUTMCookie();
|
|
405
403
|
this.setAffidCookie();
|
|
@@ -653,17 +651,17 @@ class Request {
|
|
|
653
651
|
_getAppInfoFromString(infoStr, separator = '#') {
|
|
654
652
|
if (!infoStr) return null;
|
|
655
653
|
// eslint-disable-next-line prefer-const
|
|
656
|
-
let [
|
|
657
|
-
|
|
654
|
+
let [os, appVersion, installId] = infoStr.split(separator);
|
|
655
|
+
os = os.toLowerCase();
|
|
658
656
|
|
|
659
657
|
const appInfo = {
|
|
660
|
-
|
|
658
|
+
os,
|
|
661
659
|
appVersion,
|
|
662
660
|
installId,
|
|
663
661
|
};
|
|
664
662
|
|
|
665
|
-
if (this.appPlatforms().has(
|
|
666
|
-
appInfo.
|
|
663
|
+
if (this.appPlatforms().has(os)) {
|
|
664
|
+
appInfo.appType = 'app';
|
|
667
665
|
}
|
|
668
666
|
|
|
669
667
|
return appInfo;
|
|
@@ -693,17 +691,75 @@ class Request {
|
|
|
693
691
|
return this._getAppInfoFromString(this.ctx.headers[APPINFO_HEADER]);
|
|
694
692
|
}
|
|
695
693
|
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
694
|
+
getAppInfoCustom() {
|
|
695
|
+
return null;
|
|
696
|
+
}
|
|
699
697
|
|
|
700
|
-
|
|
701
|
-
|
|
698
|
+
_getDeviceTypeFromUA() {
|
|
699
|
+
const ua = this.parseUserAgent();
|
|
700
|
+
const deviceType = ua.device?.type;
|
|
701
|
+
if (deviceType === 'mobile') return 'mobile';
|
|
702
|
+
if (deviceType === 'tablet') return 'tablet';
|
|
703
|
+
return 'desktop';
|
|
704
|
+
}
|
|
702
705
|
|
|
703
|
-
|
|
704
|
-
|
|
706
|
+
_getDeviceType() {
|
|
707
|
+
const secHeader = this.ctx.headers['sec-ch-ua-mobile'];
|
|
708
|
+
if (secHeader) {
|
|
709
|
+
if (secHeader === '?1') return 'mobile';
|
|
710
|
+
return this._getDeviceTypeFromUA();
|
|
711
|
+
}
|
|
712
|
+
const vwCookie = this.cookie(VIEWPORT_WIDTH_COOKIE);
|
|
713
|
+
if (vwCookie) {
|
|
714
|
+
if (Number(vwCookie) <= 750) return 'mobile';
|
|
715
|
+
return this._getDeviceTypeFromUA();
|
|
716
|
+
}
|
|
717
|
+
return this._getDeviceTypeFromUA();
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
computeAppInfo() {
|
|
721
|
+
const ctx = this.ctx;
|
|
705
722
|
|
|
706
|
-
|
|
723
|
+
const appInfo1 = this.getAppInfoFromHeader() || {};
|
|
724
|
+
const appInfo2 = this.getAppInfoFromParam() || {};
|
|
725
|
+
const appInfo3 = this.getAppInfoFromUserAgent() || {};
|
|
726
|
+
const appInfo4 = this.getAppInfoCustom() || {};
|
|
727
|
+
|
|
728
|
+
const appInfo = {
|
|
729
|
+
installId: ctx.query.installId,
|
|
730
|
+
appVersion: ctx.query.appVersion,
|
|
731
|
+
...appInfo4,
|
|
732
|
+
...appInfo3,
|
|
733
|
+
...appInfo2,
|
|
734
|
+
...appInfo1,
|
|
735
|
+
};
|
|
736
|
+
|
|
737
|
+
let xPlatform = (
|
|
738
|
+
ctx.query[PLATFORM_PARAM] ||
|
|
739
|
+
this.cookie(PLATFORM_COOKIE) ||
|
|
740
|
+
ctx.headers['x-sm-platform']
|
|
741
|
+
);
|
|
742
|
+
if (xPlatform) {
|
|
743
|
+
xPlatform = xPlatform.toLowerCase();
|
|
744
|
+
if (xPlatform === 'mobile_app') {
|
|
745
|
+
if (!appInfo.deviceType) appInfo.deviceType = 'mobile';
|
|
746
|
+
if (!appInfo.appType) appInfo.appType = 'app';
|
|
747
|
+
}
|
|
748
|
+
else {
|
|
749
|
+
const os = xPlatform.match(/android|ios|wp|tizen|jio/i)?.[0];
|
|
750
|
+
if (os) {
|
|
751
|
+
if (!appInfo.deviceType) appInfo.deviceType = 'mobile';
|
|
752
|
+
if (!appInfo.appType) appInfo.appType = 'app';
|
|
753
|
+
if (!appInfo.os) appInfo.os = os.toLowerCase();
|
|
754
|
+
}
|
|
755
|
+
else if (!appInfo.deviceType) {
|
|
756
|
+
appInfo.deviceType = xPlatform.includes('mobile') ? 'mobile' : 'desktop';
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
else if (!appInfo.deviceType) {
|
|
761
|
+
appInfo.deviceType = this._getDeviceType();
|
|
762
|
+
}
|
|
707
763
|
}
|
|
708
764
|
|
|
709
765
|
/*
|
|
@@ -711,156 +767,71 @@ class Request {
|
|
|
711
767
|
* this means that you can have the url as sm_app=android
|
|
712
768
|
* and it'll automatically identify it as an android app
|
|
713
769
|
*/
|
|
714
|
-
appInfo(
|
|
770
|
+
appInfo() {
|
|
715
771
|
if (!this._appInfo) {
|
|
716
|
-
this._appInfo = this.
|
|
772
|
+
this._appInfo = this.computeAppInfo() || {};
|
|
717
773
|
}
|
|
718
|
-
return
|
|
774
|
+
return this._appInfo;
|
|
719
775
|
}
|
|
720
776
|
|
|
721
777
|
installId() {
|
|
722
|
-
return this.appInfo(
|
|
778
|
+
return this.appInfo().installId || '';
|
|
723
779
|
}
|
|
724
780
|
|
|
725
781
|
appVersion() {
|
|
726
|
-
return this.appInfo(
|
|
782
|
+
return this.appInfo().appVersion || '';
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
isApp() {
|
|
786
|
+
return this.appInfo().type === 'app';
|
|
727
787
|
}
|
|
728
788
|
|
|
729
789
|
isAndroidApp() {
|
|
730
|
-
return this.appInfo(
|
|
790
|
+
return this.isApp() && this.appInfo().os === 'android';
|
|
731
791
|
}
|
|
732
792
|
|
|
733
793
|
isIOSApp() {
|
|
734
|
-
return this.appInfo(
|
|
794
|
+
return this.isApp() && this.appInfo().os === 'ios';
|
|
735
795
|
}
|
|
736
796
|
|
|
737
797
|
isWPApp() {
|
|
738
|
-
return this.appInfo(
|
|
798
|
+
return this.isApp() && this.appInfo().os === 'wp';
|
|
739
799
|
}
|
|
740
800
|
|
|
741
801
|
isTizenApp() {
|
|
742
|
-
return this.appInfo(
|
|
802
|
+
return this.isApp() && this.appInfo().os === 'tizen';
|
|
743
803
|
}
|
|
744
804
|
|
|
745
805
|
isJIOApp() {
|
|
746
|
-
return this.appInfo(
|
|
806
|
+
return this.isApp() && this.appInfo().os === 'jio';
|
|
747
807
|
}
|
|
748
808
|
|
|
749
809
|
isMobileApp() {
|
|
750
|
-
|
|
751
|
-
const platform = this._platform;
|
|
752
|
-
if (platform) {
|
|
753
|
-
if (platform === 'mobile_app') return true;
|
|
754
|
-
return false;
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
return !!this.appInfo('isMobileApp');
|
|
810
|
+
return this.isApp() && this.isMobile();
|
|
758
811
|
}
|
|
759
812
|
|
|
760
813
|
isMobileWeb() {
|
|
761
|
-
|
|
762
|
-
const platform = this._platform;
|
|
763
|
-
if (platform) {
|
|
764
|
-
if (platform === 'mobile_web') return true;
|
|
765
|
-
return false;
|
|
766
|
-
}
|
|
767
|
-
|
|
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
|
-
}
|
|
783
|
-
}
|
|
784
|
-
return this._isMobileWeb;
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
isMobile() {
|
|
788
|
-
return this.isMobileApp() || this.isMobileWeb();
|
|
814
|
+
return this.isMobile() && !this.isApp();
|
|
789
815
|
}
|
|
790
816
|
|
|
791
|
-
|
|
792
|
-
return
|
|
817
|
+
deviceType() {
|
|
818
|
+
return this.appInfo().deviceType || 'desktop';
|
|
793
819
|
}
|
|
794
820
|
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
if (this.isMobileApp()) {
|
|
798
|
-
this._platform = 'mobile_app';
|
|
799
|
-
}
|
|
800
|
-
else if (this.isMobileWeb()) {
|
|
801
|
-
this._platform = 'mobile_web';
|
|
802
|
-
}
|
|
803
|
-
else if (this.isAPI()) {
|
|
804
|
-
this._platform = 'api';
|
|
805
|
-
}
|
|
806
|
-
else {
|
|
807
|
-
this._platform = 'desktop';
|
|
808
|
-
}
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
return this._platform;
|
|
812
|
-
}
|
|
813
|
-
|
|
814
|
-
setPlatform(platform) {
|
|
815
|
-
if (!platform) return false;
|
|
816
|
-
platform = handleArray(platform);
|
|
817
|
-
const appPlatform = platform.replace('_app', '');
|
|
818
|
-
|
|
819
|
-
if (this.appPlatforms().has(appPlatform)) {
|
|
820
|
-
this._platform = 'mobile_app';
|
|
821
|
-
this._subPlatform = `${appPlatform}_app`;
|
|
822
|
-
return false;
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
switch (platform) {
|
|
826
|
-
case 'mobile':
|
|
827
|
-
case 'mobile_web':
|
|
828
|
-
this._platform = 'mobile_web';
|
|
829
|
-
return true;
|
|
830
|
-
case 'www':
|
|
831
|
-
case 'desktop':
|
|
832
|
-
this._platform = 'desktop';
|
|
833
|
-
return true;
|
|
834
|
-
case 'mobile_app':
|
|
835
|
-
this._platform = 'mobile_app';
|
|
836
|
-
return true;
|
|
837
|
-
default:
|
|
838
|
-
return false;
|
|
839
|
-
}
|
|
821
|
+
isMobile() {
|
|
822
|
+
return this.appInfo().deviceType === 'mobile';
|
|
840
823
|
}
|
|
841
824
|
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
const appPlatform = this.appInfo('platform');
|
|
845
|
-
if (appPlatform && this.isMobileApp()) {
|
|
846
|
-
this._subPlatform = `${appPlatform}_app`;
|
|
847
|
-
}
|
|
848
|
-
else {
|
|
849
|
-
this._subPlatform = this.platform();
|
|
850
|
-
}
|
|
851
|
-
}
|
|
852
|
-
return this._subPlatform;
|
|
825
|
+
isTablet() {
|
|
826
|
+
return this.appInfo().deviceType === 'tablet';
|
|
853
827
|
}
|
|
854
828
|
|
|
855
829
|
isDesktop() {
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
if (platform) {
|
|
859
|
-
if (platform === 'desktop') return true;
|
|
860
|
-
return false;
|
|
861
|
-
}
|
|
830
|
+
return !this.isMobile();
|
|
831
|
+
}
|
|
862
832
|
|
|
863
|
-
|
|
833
|
+
isAPI() {
|
|
834
|
+
return false;
|
|
864
835
|
}
|
|
865
836
|
|
|
866
837
|
/**
|
|
@@ -1152,14 +1123,6 @@ class Request {
|
|
|
1152
1123
|
return '/signup?next=' + encodeURIComponent(this.nextUrl());
|
|
1153
1124
|
}
|
|
1154
1125
|
|
|
1155
|
-
mobileUrl() {
|
|
1156
|
-
return addQuery(this.ctx.url, {[PLATFORM_PARAM]: 'mobile'});
|
|
1157
|
-
}
|
|
1158
|
-
|
|
1159
|
-
desktopUrl() {
|
|
1160
|
-
return addQuery(this.ctx.url, {[PLATFORM_PARAM]: 'desktop'});
|
|
1161
|
-
}
|
|
1162
|
-
|
|
1163
1126
|
redirect(url, qs = true) {
|
|
1164
1127
|
if (qs === true) {
|
|
1165
1128
|
url = addQuery(url, this.ctx.querystring);
|
|
@@ -1402,30 +1365,16 @@ class Request {
|
|
|
1402
1365
|
}
|
|
1403
1366
|
}
|
|
1404
1367
|
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
// don't change platform in mobile apps (and ajax requests) from query or cookie
|
|
1409
|
-
const platform = this.ctx.query[PLATFORM_PARAM] || this.cookie(PLATFORM_COOKIE);
|
|
1410
|
-
setPlatformCookie = this.setPlatform(platform);
|
|
1411
|
-
if (setPlatformCookie) {
|
|
1412
|
-
this.cookie(PLATFORM_COOKIE, platform, {
|
|
1413
|
-
maxAge: PLATFORM_COOKIE_DURATION,
|
|
1414
|
-
domain: '*',
|
|
1415
|
-
});
|
|
1416
|
-
}
|
|
1417
|
-
}
|
|
1418
|
-
if (!setPlatformCookie) {
|
|
1419
|
-
const smPlatform = this.header('x-sm-platform');
|
|
1420
|
-
if (smPlatform) {
|
|
1421
|
-
this._platform = smPlatform;
|
|
1422
|
-
}
|
|
1368
|
+
geoipLoc() {
|
|
1369
|
+
if (this._giploc === undefined) {
|
|
1370
|
+
this._giploc = GeoIP.getSync(this.ip()) || {};
|
|
1423
1371
|
}
|
|
1372
|
+
return this._giploc;
|
|
1424
1373
|
}
|
|
1425
1374
|
|
|
1426
1375
|
ipLocation() {
|
|
1427
1376
|
if (this._ipLoc === undefined) {
|
|
1428
|
-
const loc =
|
|
1377
|
+
const loc = this.geoipLoc();
|
|
1429
1378
|
const country = loc.country;
|
|
1430
1379
|
const city = loc.city;
|
|
1431
1380
|
const state = loc.subdivisions && loc.subdivisions[0];
|
package/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smpx/koa-request",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Handle basic tasks for koajs",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -30,14 +30,14 @@
|
|
|
30
30
|
},
|
|
31
31
|
"homepage": "https://github.com/smartprix/koa-request#readme",
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"ip": "^
|
|
33
|
+
"ip": "^2.0.1",
|
|
34
34
|
"koa-basic-auth": "^4.0.0",
|
|
35
35
|
"koa-body": "^5.0.0",
|
|
36
36
|
"koa-send": "^5.0.1",
|
|
37
|
-
"koa2-ratelimit": "^1.1.
|
|
38
|
-
"maxmind": "^4.3.
|
|
39
|
-
"tar": "^6.1
|
|
40
|
-
"ua-parser-js": "^1.0.
|
|
37
|
+
"koa2-ratelimit": "^1.1.3",
|
|
38
|
+
"maxmind": "^4.3.20",
|
|
39
|
+
"tar": "^6.2.1",
|
|
40
|
+
"ua-parser-js": "^1.0.38"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"eslint": "^5.7.0",
|