Selaa lähdekoodia

fix: add necessary iframe attributes for co isolation

KernelDeimos 10 kuukautta sitten
vanhempi
säilyke
2a5cec7ee9

+ 24 - 0
package-lock.json

@@ -13032,6 +13032,29 @@
         "node": ">=14.17"
         "node": ">=14.17"
       }
       }
     },
     },
+    "node_modules/ua-parser-js": {
+      "version": "1.0.38",
+      "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.38.tgz",
+      "integrity": "sha512-Aq5ppTOfvrCMgAPneW1HfWj66Xi7XL+/mIy996R1/CLS/rcyJQm6QZdsKrUeivDFQ+Oc9Wyuwor8Ze8peEoUoQ==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/ua-parser-js"
+        },
+        {
+          "type": "paypal",
+          "url": "https://paypal.me/faisalman"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/faisalman"
+        }
+      ],
+      "license": "MIT",
+      "engines": {
+        "node": "*"
+      }
+    },
     "node_modules/uglify-js": {
     "node_modules/uglify-js": {
       "version": "3.17.4",
       "version": "3.17.4",
       "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz",
       "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz",
@@ -14074,6 +14097,7 @@
         "string-length": "^6.0.0",
         "string-length": "^6.0.0",
         "svgo": "^3.0.2",
         "svgo": "^3.0.2",
         "tiktoken": "^1.0.11",
         "tiktoken": "^1.0.11",
+        "ua-parser-js": "^1.0.38",
         "uglify-js": "^3.17.4",
         "uglify-js": "^3.17.4",
         "uuid": "^9.0.0",
         "uuid": "^9.0.0",
         "validator": "^13.9.0",
         "validator": "^13.9.0",

+ 1 - 0
src/backend/package.json

@@ -66,6 +66,7 @@
     "string-length": "^6.0.0",
     "string-length": "^6.0.0",
     "svgo": "^3.0.2",
     "svgo": "^3.0.2",
     "tiktoken": "^1.0.11",
     "tiktoken": "^1.0.11",
+    "ua-parser-js": "^1.0.38",
     "uglify-js": "^3.17.4",
     "uglify-js": "^3.17.4",
     "uuid": "^9.0.0",
     "uuid": "^9.0.0",
     "validator": "^13.9.0",
     "validator": "^13.9.0",

+ 1 - 0
src/backend/src/services/PuterHomepageService.js

@@ -109,6 +109,7 @@ class PuterHomepageService extends BaseService {
                 short_description: config.short_description,
                 short_description: config.short_description,
                 long_description: config.long_description,
                 long_description: config.long_description,
                 disable_temp_users: config.disable_temp_users,
                 disable_temp_users: config.disable_temp_users,
+                co_isolation_enabled: req.co_isolation_enabled,
             },
             },
         }));
         }));
     }
     }

+ 19 - 1
src/backend/src/services/WebServerService.js

@@ -357,11 +357,29 @@ class WebServerService extends BaseService {
         app.use(helmet.xssFilter());
         app.use(helmet.xssFilter());
         // app.use(helmet.referrerPolicy());
         // app.use(helmet.referrerPolicy());
         app.disable('x-powered-by');
         app.disable('x-powered-by');
+    
+        const uaParser = require('ua-parser-js');
+        app.use(function (req, res, next) {
+            const ua_header = req.headers['user-agent'];
+            const ua = uaParser(ua_header);
+            req.ua = ua;
+            console.log('\x1B[26;1m===== UA =====\x1B[0m', ua);
+            next();
+        });
+
+        app.use(function (req, res, next) {
+            req.co_isolation_enabled =
+                ['Chrome', 'Edge'].includes(req.ua.browser.name)
+                && (Number(req.ua.browser.major) >= 110);
+            next();
+        });
 
 
         app.use(function (req, res, next) {
         app.use(function (req, res, next) {
             const origin = req.headers.origin;
             const origin = req.headers.origin;
             
             
             const is_site = req.hostname.endsWith(config.static_hosting_domain);
             const is_site = req.hostname.endsWith(config.static_hosting_domain);
+            
+            const co_isolation_okay = is_site || req.co_isolation_enabled;
 
 
             if ( req.path === '/signup' || req.path === '/login' ) {
             if ( req.path === '/signup' || req.path === '/login' ) {
                 res.setHeader('Access-Control-Allow-Origin', origin ?? '*');
                 res.setHeader('Access-Control-Allow-Origin', origin ?? '*');
@@ -392,7 +410,7 @@ class WebServerService extends BaseService {
             // NOTE: This is put behind a configuration flag because we
             // NOTE: This is put behind a configuration flag because we
             //       need some experimentation to ensure the interface
             //       need some experimentation to ensure the interface
             //       between apps and Puter doesn't break.
             //       between apps and Puter doesn't break.
-            if ( config.cross_origin_isolation && is_site ) {
+            if ( config.cross_origin_isolation && co_isolation_okay ) {
                 res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
                 res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
                 res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp');
                 res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp');
             }
             }

+ 4 - 0
src/gui/src/UI/UIWindow.js

@@ -323,6 +323,10 @@ async function UIWindow(options) {
                         frameborder="0" 
                         frameborder="0" 
                         ${options.iframe_url ? 'src="'+ html_encode(options.iframe_url)+'"' : ''}
                         ${options.iframe_url ? 'src="'+ html_encode(options.iframe_url)+'"' : ''}
                         ${options.iframe_srcdoc ? 'srcdoc="'+ html_encode(options.iframe_srcdoc) +'"' : ''}
                         ${options.iframe_srcdoc ? 'srcdoc="'+ html_encode(options.iframe_srcdoc) +'"' : ''}
+                        ${window.co_isolation_enabled
+                            ? 'credentialless allow="cross-origin-isolated" '
+                            : ''
+                        }
                         allow = "accelerometer; camera; encrypted-media; gamepad; display-capture; geolocation; gyroscope; microphone; midi; clipboard-read; clipboard-write; fullscreen;"
                         allow = "accelerometer; camera; encrypted-media; gamepad; display-capture; geolocation; gyroscope; microphone; midi; clipboard-read; clipboard-write; fullscreen;"
                         allowtransparency="true"
                         allowtransparency="true"
                         allowpaymentrequest="true" 
                         allowpaymentrequest="true" 

+ 1 - 0
src/gui/src/index.js

@@ -56,6 +56,7 @@ window.gui = async function(options){
     window.max_item_name_length = options.max_item_name_length ?? 500;
     window.max_item_name_length = options.max_item_name_length ?? 500;
     window.require_email_verification_to_publish_website = options.require_email_verification_to_publish_website ?? true;
     window.require_email_verification_to_publish_website = options.require_email_verification_to_publish_website ?? true;
     window.disable_temp_users = options.disable_temp_users ?? false;
     window.disable_temp_users = options.disable_temp_users ?? false;
+    window.co_isolation_enabled = options.co_isolation_enabled;
 
 
     // DEV: Load the initgui.js file if we are in development mode
     // DEV: Load the initgui.js file if we are in development mode
     if(!window.gui_env || window.gui_env === "dev"){
     if(!window.gui_env || window.gui_env === "dev"){