Advertisement
xosski

Local cache/persistence red team

Mar 27th, 2025
16
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.25 KB | None | 0 0
  1. Security research & red team persistence
  2.  
  3. Offline-first web apps
  4. Fast-loading precompiled assets
  5. Secure local caching
  6. Web apps with live updates
  7. Browser-based CDNs
  8.  
  9. function createResolvablePromise() {
  10. let resolveFunction, rejectFunction;
  11. const promise = new Promise((resolve, reject) => {
  12. resolveFunction = resolve;
  13. rejectFunction = reject;
  14. });
  15. return { promise, resolve: resolveFunction, reject: rejectFunction };
  16. }
  17.  
  18. const DB_NAME = '__v0';
  19. const DB_VERSION = 1;
  20. const COMPILED_CACHE_NAME = '/__v0_compiled';
  21.  
  22. let compiled = null;
  23. const { promise: compiledPromise, reject: rejectCompiled, resolve: resolveCompiled } = createResolvablePromise();
  24.  
  25. async function getDB() {
  26. return new Promise((resolve, reject) => {
  27. const request = indexedDB.open(DB_NAME, DB_VERSION);
  28. request.onupgradeneeded = event => {
  29. event.target.result.createObjectStore('data');
  30. };
  31. request.onsuccess = event => resolve(event.target.result);
  32. request.onerror = () => reject(request.error);
  33. });
  34. }
  35.  
  36. // Load cached data from IndexedDB
  37. getDB().then(db => {
  38. const tx = db.transaction('data', 'readonly');
  39. const store = tx.objectStore('data');
  40. const request = store.get(COMPILED_CACHE_NAME);
  41. request.onsuccess = event => {
  42. compiled = event.target.result;
  43. if (compiled) resolveCompiled();
  44. };
  45. });
  46.  
  47. self.addEventListener('install', () => self.skipWaiting());
  48. self.addEventListener('activate', () => self.clients.claim());
  49.  
  50. self.addEventListener('fetch', async event => {
  51. event.respondWith(fetchHandler(event));
  52. });
  53.  
  54. let port2 = null;
  55. self.addEventListener('message', async event => {
  56. if (!event.data) return;
  57. if (event.data.type === 'v0_init') {
  58. compiled = event.data.compiled;
  59. if (compiled) resolveCompiled();
  60.  
  61. port2 = event.ports[0];
  62.  
  63. const db = await getDB();
  64. const tx = db.transaction('data', 'readwrite');
  65. const store = tx.objectStore('data');
  66. store.put(compiled, COMPILED_CACHE_NAME);
  67. }
  68. });
  69.  
  70. const currentOrigin = self.location.origin;
  71.  
  72. async function fetchHandler(event) {
  73. await compiledPromise;
  74. if (!compiled || !compiled.staticFiles) return fetch(event.request);
  75.  
  76. const url = new URL(event.request.url);
  77. if (url.origin !== currentOrigin) return fetch(event.request);
  78.  
  79. return handleStaticFile(event, url) || fetch(event.request);
  80. }
  81.  
  82. function handleStaticFile(event, url) {
  83. let resourcePath = url.pathname;
  84. let maybeResource = compiled.staticFiles[resourcePath] || compiled.staticFiles[resourcePath + '.html'];
  85.  
  86. if (!maybeResource) return null;
  87.  
  88. if (typeof maybeResource === 'string' || maybeResource.type === 'raw') {
  89. return new Response(maybeResource.content || maybeResource, {
  90. headers: { 'Content-Type': getMimeType(resourcePath) },
  91. });
  92. }
  93. if (maybeResource.type === 'url') {
  94. return fetch(maybeResource.content);
  95. }
  96. return null;
  97. }
  98.  
  99. function getMimeType(path) {
  100. const ext = path.toLowerCase().split('.').pop();
  101. const mimeTypes = {
  102. html: 'text/html',
  103. js: 'text/javascript',
  104. css: 'text/css',
  105. json: 'application/json',
  106. svg: 'image/svg+xml',
  107. xml: 'application/xml',
  108. txt: 'text/plain',
  109. md: 'text/markdown',
  110. csv: 'text/csv',
  111. };
  112. return mimeTypes[ext] || 'text/plain';
  113. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement