@abtnode/router-provider 1.16.49-beta-20250827-025603-2bb1a7ee → 1.16.49-beta-20250828-094758-93e69d1f

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.
@@ -0,0 +1,3 @@
1
+ # Security headers for HTTPS responses
2
+ # Note: HSTS must only be sent on HTTPS
3
+ add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
@@ -164,6 +164,7 @@ class NginxProvider extends BaseProvider {
164
164
 
165
165
  this._copyConfigFiles();
166
166
  this._ensureDhparam();
167
+ this._ensureDaemonSecurityHeaders();
167
168
  this.updateProxyPolicy({ enabled: false });
168
169
  this.initialize();
169
170
  }
@@ -303,6 +304,7 @@ class NginxProvider extends BaseProvider {
303
304
  // if match certificate, then add https server
304
305
  this._addHttpsServer({
305
306
  conf,
307
+ serviceType: site.serviceType,
306
308
  locations: rules,
307
309
  certificateFileName: certificate.domain,
308
310
  serverName: parsedServerName,
@@ -314,6 +316,7 @@ class NginxProvider extends BaseProvider {
314
316
  } else {
315
317
  this._addHttpServer({
316
318
  conf,
319
+ serviceType: site.serviceType,
317
320
  locations: rules,
318
321
  serverName: parsedServerName,
319
322
  corsAllowedOrigins,
@@ -581,6 +584,16 @@ class NginxProvider extends BaseProvider {
581
584
  }
582
585
  }
583
586
 
587
+ _addSecurityHeaders(location, serviceType) {
588
+ if (serviceType === 'daemon') {
589
+ if (fs.existsSync(path.join(this.includesDir, 'daemon', 'security'))) {
590
+ location._add('include', 'includes/daemon/security');
591
+ }
592
+
593
+ location._add('include', 'includes/daemon/ssl');
594
+ }
595
+ }
596
+
584
597
  /**
585
598
  * Returns:
586
599
  * server /flash/ {
@@ -605,6 +618,7 @@ class NginxProvider extends BaseProvider {
605
618
  commonHeaders,
606
619
  cacheGroup,
607
620
  pageGroup,
621
+ serviceType,
608
622
  }) {
609
623
  server._add('location', concatPath(prefix, suffix, root));
610
624
 
@@ -637,6 +651,8 @@ class NginxProvider extends BaseProvider {
637
651
  location._add('include', 'includes/cache');
638
652
  }
639
653
 
654
+ this._addSecurityHeaders(location, serviceType);
655
+
640
656
  // Redirect blocklet traffic
641
657
  if (type === ROUTING_RULE_TYPES.BLOCKLET) {
642
658
  // FIXME: logic related to server gateway should not in provider
@@ -680,7 +696,7 @@ class NginxProvider extends BaseProvider {
680
696
  location._add('proxy_pass', `http://${getUpstreamName(port)}`);
681
697
  }
682
698
 
683
- _addRedirectTypeLocation({ server, url, redirectCode, prefix, suffix }) {
699
+ _addRedirectTypeLocation({ server, url, redirectCode, prefix, suffix, serviceType }) {
684
700
  const cleanUrl = trimEndSlash(url);
685
701
  server._add('location', `${concatPath(prefix, suffix)}`);
686
702
  const location = this._getLastLocation(server);
@@ -694,6 +710,8 @@ class NginxProvider extends BaseProvider {
694
710
  // always allow cors here since we are doing a redirect
695
711
  location._add('include', 'includes/cors');
696
712
 
713
+ this._addSecurityHeaders(location, serviceType);
714
+
697
715
  // 如果 prefix 是根路径,则不需要重写,直接将当前的请求附加到设置的重定向地址后面
698
716
  if (prefix === '/') {
699
717
  location._add('return', `${redirectCode} ${cleanUrl}$request_uri`);
@@ -704,24 +722,28 @@ class NginxProvider extends BaseProvider {
704
722
  }
705
723
  }
706
724
 
707
- _addRewriteTypeLocation({ server, url, prefix, suffix }) {
725
+ _addRewriteTypeLocation({ server, url, prefix, suffix, serviceType }) {
708
726
  server._add('location', concatPath(prefix, suffix));
709
727
  const location = this._getLastLocation(server);
728
+
729
+ this._addSecurityHeaders(location, serviceType);
710
730
  location._add('rewrite', `^${prefix}(.*) ${url}$1 last`);
711
731
  }
712
732
 
713
- _addNotFoundLocation({ server, prefix, suffix }) {
733
+ _addNotFoundLocation({ server, prefix, suffix, serviceType }) {
714
734
  server._add('location', concatPath(prefix, suffix));
715
735
  const location = this._getLastLocation(server);
716
- this._addTailSlashRedirection(location, prefix);
717
736
 
737
+ this._addSecurityHeaders(location, serviceType);
738
+ this._addTailSlashRedirection(location, prefix);
718
739
  location._add('try_files', '$uri /404.html break');
719
740
  }
720
741
 
721
- _addGeneralProxyLocation({ server, port, prefix, suffix, blockletDid, targetPrefix }) {
742
+ _addGeneralProxyLocation({ server, port, prefix, suffix, blockletDid, targetPrefix, serviceType }) {
722
743
  server._add('location', concatPath(prefix, suffix));
723
744
  const location = this._getLastLocation(server);
724
745
  this._addCommonHeader(location);
746
+ this._addSecurityHeaders(location, serviceType);
725
747
  location._add('include', 'includes/proxy');
726
748
  if (blockletDid) {
727
749
  location._add('proxy_set_header', `X-Blocklet-Did ${blockletDid}`);
@@ -867,6 +889,67 @@ class NginxProvider extends BaseProvider {
867
889
  }
868
890
  }
869
891
 
892
+ _ensureDaemonSecurityHeaders() {
893
+ const securityFilePath = path.join(this.includesDir, 'daemon', 'security');
894
+ const cspSources = [
895
+ 'https://*.blocklet.dev',
896
+ 'wss://*.blocklet.dev',
897
+ 'https://didnames.io',
898
+ 'https://*.did.abtnet.io',
899
+ 'wss://*.did.abtnet.io',
900
+ 'https://*.ip.abtnet.io',
901
+ 'wss://*.ip.abtnet.io',
902
+ 'data:',
903
+ 'blob:',
904
+ '*/__blocklet__.js',
905
+ '*/.well-known/ping',
906
+ 'https://api.simplesvg.com',
907
+ 'https://api.unisvg.com',
908
+ 'https://api.iconify.design',
909
+ ];
910
+ const cspPolicy = `default-src 'self'; frame-ancestors 'none'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' ${cspSources.join(' ')}; font-src 'self' data:; connect-src 'self' ${cspSources.join(' ')} */.well-known/ping; base-uri 'self'; object-src 'none'`;
911
+ const cspLine = `add_header Content-Security-Policy "${cspPolicy}" always;`;
912
+
913
+ try {
914
+ if (fs.existsSync(securityFilePath)) {
915
+ logger.info('security include file already exists', { path: securityFilePath });
916
+ return;
917
+ }
918
+
919
+ const baseContent = [
920
+ '## Global HTTP security headers (safe baseline)',
921
+ '',
922
+ '# MIME sniffing protection',
923
+ 'add_header X-Content-Type-Options "nosniff" always;',
924
+ '# --- Secure Headers Baseline ---',
925
+ '# Hide headers from upstream (in case the upstream app sets them).',
926
+ '# This prevents duplicate values which may cause overly strict policies.',
927
+ 'proxy_hide_header Content-Security-Policy;',
928
+ 'proxy_hide_header Referrer-Policy;',
929
+ 'proxy_hide_header Permissions-Policy;',
930
+ '# Referrer-Policy:',
931
+ '# Controls how much referrer information is included with requests.',
932
+ '# "strict-origin-when-cross-origin" is a balanced choice: full referrer',
933
+ '# for same-origin, origin only for cross-origin, nothing on downgrade.',
934
+ '# Use "no-referrer" if you want the strictest setting.',
935
+ 'add_header Referrer-Policy "strict-origin-when-cross-origin" always;',
936
+ 'add_header Permissions-Policy "geolocation=(), microphone=(), camera=(), payment=(), usb=(), bluetooth=(), fullscreen=(), xr-spatial-tracking=(), magnetometer=(), gyroscope=(), accelerometer=(), browsing-topics=()" always;',
937
+ 'add_header X-Frame-Options "DENY" always;',
938
+ '# Content-Security-Policy (CSP):',
939
+ '# Mitigates XSS by restricting resource loading.',
940
+ '# This baseline only allows self-hosted resources, blocks framing,',
941
+ '# disallows <base> tag overrides, and disables legacy plugins.',
942
+ '# Adjust sources (script-src, style-src, img-src, etc.) if you need CDNs.',
943
+ cspLine,
944
+ ].join('\n');
945
+
946
+ fs.writeFileSync(securityFilePath, baseContent);
947
+ logger.info('security include file updated', { path: securityFilePath });
948
+ } catch (error) {
949
+ logger.error('Failed to update security include file', { error, path: securityFilePath });
950
+ }
951
+ }
952
+
870
953
  _addCommonResHeaders(block, headers) {
871
954
  if (!headers || Object.prototype.toString.call(headers) !== '[object Object]') {
872
955
  return;
@@ -1019,11 +1102,12 @@ class NginxProvider extends BaseProvider {
1019
1102
  daemonPort,
1020
1103
  commonHeaders,
1021
1104
  blockletDid,
1105
+ serviceType,
1022
1106
  }) {
1023
1107
  const httpServerUnit = this._addHttpServerUnit({ conf, serverName, port });
1024
1108
  this._addDefaultLocations({ server: httpServerUnit, daemonPort, serverName });
1025
1109
  // eslint-disable-next-line max-len
1026
- locations.forEach((x) => this._addReverseProxy({ server: httpServerUnit, ...x, serverName, corsAllowedOrigins, commonHeaders, blockletDid })); // prettier-ignore
1110
+ locations.forEach((x) => this._addReverseProxy({ server: httpServerUnit, ...x, serverName, corsAllowedOrigins, commonHeaders, blockletDid, serviceType })); // prettier-ignore
1027
1111
  }
1028
1112
 
1029
1113
  _addHttpsServer({
@@ -1031,6 +1115,7 @@ class NginxProvider extends BaseProvider {
1031
1115
  locations,
1032
1116
  certificateFileName,
1033
1117
  serverName,
1118
+ serviceType,
1034
1119
  corsAllowedOrigins,
1035
1120
  daemonPort,
1036
1121
  commonHeaders,
@@ -1043,7 +1128,7 @@ class NginxProvider extends BaseProvider {
1043
1128
 
1044
1129
  this._addDefaultLocations({ server: httpsServerUnit, daemonPort, serverName });
1045
1130
  // eslint-disable-next-line max-len
1046
- locations.forEach((x) => this._addReverseProxy({ server: httpsServerUnit, ...x, serverName, corsAllowedOrigins, commonHeaders, blockletDid })); // prettier-ignore
1131
+ locations.forEach((x) => this._addReverseProxy({ server: httpsServerUnit, ...x, serverName, corsAllowedOrigins, commonHeaders, blockletDid, serviceType })); // prettier-ignore
1047
1132
  }
1048
1133
 
1049
1134
  _addHttpServerUnit({ conf, serverName, port = '' }) {
package/lib/util.js CHANGED
@@ -75,6 +75,7 @@ const formatRoutingTable = (routingTable) => {
75
75
  rules: [],
76
76
  port: site.port,
77
77
  corsAllowedOrigins: site.corsAllowedOrigins,
78
+ serviceType: site.serviceType,
78
79
  };
79
80
  }
80
81
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abtnode/router-provider",
3
- "version": "1.16.49-beta-20250827-025603-2bb1a7ee",
3
+ "version": "1.16.49-beta-20250828-094758-93e69d1f",
4
4
  "description": "Routing engine implementations for abt node",
5
5
  "author": "polunzh <polunzh@gmail.com>",
6
6
  "homepage": "https://github.com/ArcBlock/blocklet-server#readme",
@@ -32,11 +32,11 @@
32
32
  "url": "https://github.com/ArcBlock/blocklet-server/issues"
33
33
  },
34
34
  "dependencies": {
35
- "@abtnode/constant": "1.16.49-beta-20250827-025603-2bb1a7ee",
36
- "@abtnode/db-cache": "1.16.49-beta-20250827-025603-2bb1a7ee",
37
- "@abtnode/logger": "1.16.49-beta-20250827-025603-2bb1a7ee",
38
- "@abtnode/router-templates": "1.16.49-beta-20250827-025603-2bb1a7ee",
39
- "@abtnode/util": "1.16.49-beta-20250827-025603-2bb1a7ee",
35
+ "@abtnode/constant": "1.16.49-beta-20250828-094758-93e69d1f",
36
+ "@abtnode/db-cache": "1.16.49-beta-20250828-094758-93e69d1f",
37
+ "@abtnode/logger": "1.16.49-beta-20250828-094758-93e69d1f",
38
+ "@abtnode/router-templates": "1.16.49-beta-20250828-094758-93e69d1f",
39
+ "@abtnode/util": "1.16.49-beta-20250828-094758-93e69d1f",
40
40
  "@arcblock/http-proxy": "^1.19.1",
41
41
  "@arcblock/is-valid-domain": "^1.0.5",
42
42
  "@ocap/util": "^1.23.1",
@@ -62,5 +62,5 @@
62
62
  "bluebird": "^3.7.2",
63
63
  "fs-extra": "^11.2.0"
64
64
  },
65
- "gitHead": "2b70eea34e8bc8546abb09d38935e8906d9586fd"
65
+ "gitHead": "587711a6df767cafaadbb503daeac586e22c3988"
66
66
  }