Selaa lähdekoodia

setup to get the WebVM installed as IWA, changes to src/app.html and vite.config.js to point to placeholder icon to pass install checks. Tweaked the post-processing from the hello world to be more robust, it fixes the same CSP violation issues of inline scripts, also copy .well-known/ to build/ after build is complete. Added CSP headers to nginx.conf

oscar 3 kuukautta sitten
vanhempi
commit
496bfcb95c
6 muutettua tiedostoa jossa 115 lisäystä ja 3 poistoa
  1. BIN
      favicon.png
  2. 14 0
      nginx.conf
  3. 2 1
      package.json
  4. 97 0
      post_process.cjs
  5. 1 1
      src/app.html
  6. 1 1
      vite.config.js

BIN
favicon.png


+ 14 - 0
nginx.conf

@@ -48,5 +48,19 @@ http {
             add_header 'Cross-Origin-Embedder-Policy' 'require-corp' always;
             add_header 'Cross-Origin-Resource-Policy' 'cross-origin' always;
         }
+        add_header Content-Security-Policy "
+            script-src 'self', 'wasm-unsafe-eval';
+            connect-src 'self', 'https:', 'blob:', 'data:', 'wss:';
+            require-trusted-types-for 'script';
+            frame-src 'self', 'https:', 'blob:', 'data:';
+            img-src 'self', 'https:', 'blob:', 'data:';
+            media-src 'self', 'https:', 'blob:', 'data:';
+            font-src 'self', 'blob:', 'data:';
+            style-src 'self', 'unsafe-inline';
+            object-src 'none';
+            base-uri 'none';
+            default-src 'self';
+            frame-ancestors 'self';
+        " always;
     }
 }

+ 2 - 1
package.json

@@ -4,7 +4,8 @@
 	"private": true,
 	"scripts": {
 		"dev": "vite dev",
-		"build": "vite build"
+		"build": "vite build",
+		"postbuild": "node ./post_process.cjs && cp -r .well-known/ build/"
 	},
 	"devDependencies": {
 		"@anthropic-ai/sdk": "^0.33.0",

+ 97 - 0
post_process.cjs

@@ -0,0 +1,97 @@
+const fs = require('fs');
+const path = require('path');
+
+const directoryPath = path.resolve(__dirname, 'build');
+
+function postProcess() {
+  fs.readdir(directoryPath, (err, files) => {
+    if (err) {
+      console.error("Error reading directory: ", err);
+      return;
+    }
+
+    //
+    // debug
+    // 
+    // files.forEach(file => {
+    //   console.log(file);
+    // });
+
+    // console.log(directoryPath);
+    // console.log(outputFilePath);
+
+    const htmlFiles = files.filter(file => file.endsWith('html'));
+    htmlFiles.forEach(htmlFile => {
+      console.log(htmlFile);
+      const filePath = path.join(directoryPath, htmlFile);
+      const fileContent = fs.readFileSync(filePath, 'utf-8');
+
+      const scriptContent = extractScript(fileContent);
+      if (scriptContent === '') {
+        console.log(`Warning: no script content for ${filePath}`);
+        return;
+      }
+      const scriptName = createJsFile(htmlFile, scriptContent);
+      if (scriptName === '') {
+        console.log(`Warning: no scriptName for ${filePath}`);
+        return;
+      }
+      replaceScript(fileContent, filePath, scriptName);
+      console.log(`Successfully extracted scripts from [${htmlFile}] into separate [${scriptName}].`);
+    });
+  });
+}
+
+function extractScript(fileContent) {
+  const scriptStart = fileContent.indexOf('__sveltekit_');
+  if (scriptStart === -1)  {
+    console.log("Could not find __sveltekit_ script start in generated HTML files");
+    return '';
+  }
+  var scriptEnd = fileContent.lastIndexOf('</script>');
+  scriptEnd -= 6; // getting rid of extra } closing bracket. Will find a better solution than this.
+  if (scriptEnd === -1) {
+    console.log("Could not match the closing <script> tag");
+    return '';
+  }
+  console.log("script start: ", scriptStart);
+  const scriptContent = fileContent.substring(scriptStart, scriptEnd);
+  const containsPromiseAll = scriptContent.indexOf('Promise.all');
+  if (containsPromiseAll !== -1) {
+    return scriptContent;
+  } else {
+    console.log("Could not find Promise.all call in generated __sveltekit_ script");
+    return '';
+  }
+}
+
+function createJsFile(ogFileName, fileContent) {
+  const name = path.parse(ogFileName).name;
+  const filename = name + '_extracted_script.js'
+  fs.writeFileSync(directoryPath + '/' + filename, fileContent, (err) => {
+    if (err) {
+      console.log("Error writing extracted script into .js file: ", err);
+      return '';
+    }
+  });
+
+  return filename;
+}
+
+function replaceScript(fileContent, filePath, scriptName) {
+  const updatedContent = fileContent.replace(/<script>[\s\S]*?<\/script>/, `<script src="${scriptName}" defer></script>`);
+  //
+  // debug
+  //
+  // console.log(`Updated content: \n ${updatedContent}`);
+
+  fs.writeFileSync(filePath, updatedContent, 'utf-8', (err) =>{
+    if (err) {
+      console.log("Failed to write replacedContent instead of inlined script: ", err);
+    }
+  });
+}
+
+postProcess();
+
+

+ 1 - 1
src/app.html

@@ -23,7 +23,7 @@
 		<meta name="apple-mobile-web-app-capable" content="yes" />
 		<meta name="mobile-web-app-capable" content="yes" />
 		<meta name="apple-mobile-web-app-status-bar-style" content="black" />
-		<link rel="shortcut icon" href="tower.ico">
+		<link rel="shortcut icon" href="favicon.png">
 		<link rel="preconnect" href="https://fonts.googleapis.com">
 		<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
 		<link rel='stylesheet' href='scrollbar.css'>

+ 1 - 1
vite.config.js

@@ -16,7 +16,7 @@ export default defineConfig({
 		sveltekit(),
 		viteStaticCopy({
 			targets: [
-				{ src: 'tower.ico', dest: '' },
+				{ src: 'favicon.png', dest: '' },
 				{ src: 'scrollbar.css', dest: '' },
 				{ src: 'serviceWorker.js', dest: '' },
 				{ src: 'login.html', dest: '' },