diff --git a/PROXY_SETUP.md b/PROXY_SETUP.md new file mode 100644 index 00000000..3a3a1b2c --- /dev/null +++ b/PROXY_SETUP.md @@ -0,0 +1,129 @@ +# SlowGuardian Dual Proxy System + +SlowGuardian now supports two proxy systems for different user tiers: + +## Proxy Systems + +### 1. Ultraviolet (All Users) +- **URL Prefix**: `/a/` +- **Access**: Available to all users +- **Repository**: https://github.com/titaniumnetwork-dev/Ultraviolet +- **Status**: ✅ Always enabled + +### 2. Scramjet (Premium Users Only) +- **URL Prefix**: `/scram/` +- **Access**: Premium users only (requires `sg_premium=1` cookie) +- **Repository**: https://github.com/MercuryWorkshop/scramjet +- **Status**: ✅ Enabled for premium users + +## Setup + +### Automatic Setup (Recommended) +When you run `npm install`, the Scramjet files are automatically set up via the `postinstall` script. + +### Manual Setup +If you need to manually set up Scramjet: + +```bash +npm run setup:scramjet +``` + +This copies the necessary Scramjet files from `node_modules/@mercuryworkshop/scramjet` to `static/scram/`. + +## Premium User Detection + +The service worker checks for the `sg_premium` cookie to determine if a user has premium access: + +- **Premium users** (`sg_premium=1`): Can access both `/scram/` and `/a/` proxies +- **Non-premium users**: Can only access `/a/` proxy +- If a non-premium user tries to access `/scram/`, they are automatically redirected to `/a/` + +## Service Worker Architecture + +The service worker (`static/sw.js`) handles routing for all proxy systems: + +1. **Dynamic** (`/dy/`) - Base proxy system +2. **Scramjet** (`/scram/`) - Premium only, loaded conditionally +3. **Ultraviolet** (`/a/`) - Available to all users + +```javascript +// Premium detection +function isPremiumUser(request) { + const cookies = request.headers.get('cookie') || ''; + return cookies.includes('sg_premium=1'); +} +``` + +## File Structure + +``` +static/ +├── scram/ # Scramjet files (gitignored, built on install) +│ ├── config.js +│ ├── scramjet.worker.js +│ ├── scramjet.client.js +│ └── scramjet.codecs.js +├── m/ # Ultraviolet files +│ ├── config.js +│ ├── bundle.js +│ ├── handler.js +│ └── sw.js +└── sw.js # Main service worker with dual proxy support +``` + +## External Scripts + +The service worker is configured to NOT intercept external scripts (AdSense, Analytics, Cookie Consent): + +```javascript +// Don't intercept external requests - let browser handle them +if (url.origin !== location.origin) { + return; // Browser handles it naturally +} +``` + +## Testing + +To verify both proxies are working: + +1. **Test Ultraviolet** (all users): + - Navigate to: `http://localhost:8080/a/hvtrs8%2F-gmoelg.aoo%2F` + +2. **Test Scramjet** (premium only): + - Set cookie: `sg_premium=1` + - Navigate to: `http://localhost:8080/scram/[encoded-url]` + +## Troubleshooting + +### Scramjet files not found +Run the setup script manually: +```bash +npm run setup:scramjet +``` + +### Service worker not loading Scramjet +Check browser console for errors. Scramjet will log: +- `✓ Scramjet loaded for premium users` - Success +- `⚠ Scramjet not available` - Failed to load (will fallback to UV only) + +### Non-premium user trying to access Scramjet +Users without `sg_premium=1` cookie will be automatically redirected to Ultraviolet. + +## Development + +When developing, ensure: +1. Run `npm install` to set up all dependencies +2. The `static/scram/` directory is automatically created +3. Check that all proxy files are accessible (should return 200): + - `/sw.js` + - `/m/config.js` + - `/scram/config.js` + - `/scram/scramjet.worker.js` + +## Production Deployment + +For production: +1. Ensure `npm install` runs during deployment +2. The postinstall script will automatically set up Scramjet +3. Verify both proxies are accessible +4. Configure premium user authentication as needed diff --git a/package-lock.json b/package-lock.json index 9bcf2a4c..35be5a73 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,7 @@ "": { "name": "slowguardian", "version": "9.0.0", + "hasInstallScript": true, "license": "GPL-3.0-or-later", "dependencies": { "@mercuryworkshop/epoxy-transport": "^2.1.28", @@ -406,6 +407,8 @@ }, "node_modules/@mercuryworkshop/scramjet": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@mercuryworkshop/scramjet/-/scramjet-1.0.2.tgz", + "integrity": "sha512-65k+TXYlMAnqTrcTyVlXyG+CVymOSHMW4a8ofJtX6yHDKmWGHL4LVzls+ukoTqth6JyqOk7OoT3iQdufZMoE7g==", "license": "ISC", "dependencies": { "@mercuryworkshop/bare-mux": "^1.1.2", diff --git a/package.json b/package.json index f91c79a4..520b7c43 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,8 @@ "test-sw-headless": "node scripts/test-sw-puppeteer.js", "test-sw-simple": "node scripts/test-sw-simple.js", "build": "npm run build:version && npm run format", + "postinstall": "node scripts/setup-scramjet.cjs", + "setup:scramjet": "node scripts/setup-scramjet.cjs", "build:production": "NODE_ENV=production npm run build:version && npm run format && npm run audit-fix", "build:version": "node scripts/build-version.js", "audit-fix": "npm audit fix", diff --git a/scripts/setup-scramjet.cjs b/scripts/setup-scramjet.cjs new file mode 100755 index 00000000..2f842ed9 --- /dev/null +++ b/scripts/setup-scramjet.cjs @@ -0,0 +1,74 @@ +#!/usr/bin/env node + +/** + * Script to set up Scramjet proxy for premium users + * Copies necessary files from node_modules to static directory + */ + +const fs = require('fs'); +const path = require('path'); + +const scramjetSrc = path.join(__dirname, '../node_modules/@mercuryworkshop/scramjet'); +const scramjetDest = path.join(__dirname, '../static/scram'); + +console.log('Setting up Scramjet for premium users...'); + +// Create destination directory +if (!fs.existsSync(scramjetDest)) { + fs.mkdirSync(scramjetDest, { recursive: true }); + console.log('✓ Created /static/scram directory'); +} + +// Check if Scramjet package exists +if (!fs.existsSync(scramjetSrc)) { + console.error('✗ Scramjet package not found in node_modules'); + console.log(' Run: npm install @mercuryworkshop/scramjet'); + process.exit(1); +} + +// List of files to copy (based on Scramjet documentation) +const filesToCopy = [ + 'scramjet.bundle.js', + 'scramjet.worker.js', + 'scramjet.client.js', + 'scramjet.codecs.js' +]; + +let copiedCount = 0; + +// Try to copy files from various possible locations +const possiblePaths = ['dist', 'lib', '', 'dist/']; + +for (const file of filesToCopy) { + let found = false; + + for (const subPath of possiblePaths) { + const srcPath = path.join(scramjetSrc, subPath, file); + const destPath = path.join(scramjetDest, file); + + if (fs.existsSync(srcPath)) { + try { + fs.copyFileSync(srcPath, destPath); + console.log(`✓ Copied ${file}`); + copiedCount++; + found = true; + break; + } catch (err) { + console.error(`✗ Error copying ${file}:`, err.message); + } + } + } + + if (!found) { + console.log(`⚠ ${file} not found (may not be needed)`); + } +} + +if (copiedCount > 0) { + console.log(`\n✓ Successfully set up Scramjet with ${copiedCount} files`); + console.log(' Scramjet will be available for premium users at /scram/ prefix'); +} else { + console.log('\n⚠ No Scramjet files were copied'); + console.log(' Please check the Scramjet package installation'); + console.log(' or refer to: https://github.com/MercuryWorkshop/scramjet'); +} diff --git a/static/404.html b/static/404.html index 89ab9b50..26f74931 100644 --- a/static/404.html +++ b/static/404.html @@ -214,6 +214,9 @@ } } + + + diff --git a/static/apps.html b/static/apps.html index 83e87e96..7ed6c217 100644 --- a/static/apps.html +++ b/static/apps.html @@ -44,6 +44,22 @@ + + + + + + + + + + @@ -98,10 +114,48 @@

Applications

+ +
+ + +
+
+ + +
+ + +
+ + +
+ + +
diff --git a/static/assets/scripts/frame.js b/static/assets/scripts/frame.js index d4b7b144..93f769a3 100644 --- a/static/assets/scripts/frame.js +++ b/static/assets/scripts/frame.js @@ -99,7 +99,14 @@ window.addEventListener("load", function () { } if (!GoUrl.startsWith("/e/")) { - if (dyValue === "true" || dyValue === "auto") { + // Check proxy service preference + const proxyService = localStorage.getItem("proxy-service") || "ultraviolet"; + + if (proxyService === "scramjet") { + // Use Scramjet proxy encoding + GoUrl = "/scram/" + GoUrl; + console.log("🔄 Using Scramjet proxy for:", GoUrl); + } else if (dyValue === "true" || dyValue === "auto" || proxyService === "dynamic") { // Use Dynamic proxy encoding GoUrl = "/dy/q/" + GoUrl; console.log("🔄 Using Dynamic proxy for:", GoUrl); diff --git a/static/assets/styles/v9/games.css b/static/assets/styles/v9/games.css index f5217948..fa005923 100644 --- a/static/assets/styles/v9/games.css +++ b/static/assets/styles/v9/games.css @@ -1,14 +1,16 @@ /* Games page styles for SlowGuardian v9 */ -/* Games Grid */ +/* Games/Apps Grid - ID selector to override .content-grid */ +#games-grid, +#apps-grid, .games-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); - gap: var(--space-3); - padding: var(--space-4) 0; - width: 100%; - max-width: none; - min-height: calc(100vh - 300px); + display: grid !important; + grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)) !important; + gap: var(--space-3) !important; + padding: var(--space-4) 0 !important; + width: 100% !important; + max-width: none !important; + min-height: calc(100vh - 300px) !important; } /* Game Item */ diff --git a/static/assets/styles/v9/main.css b/static/assets/styles/v9/main.css index b972d850..fe6272a6 100644 --- a/static/assets/styles/v9/main.css +++ b/static/assets/styles/v9/main.css @@ -387,10 +387,6 @@ body { #suggestions:empty { display: none !important; } - display: none; - max-height: 300px; - overflow-y: auto; -} .suggestion-item { display: flex; diff --git a/static/developer.html b/static/developer.html index d2637d8c..513601ea 100644 --- a/static/developer.html +++ b/static/developer.html @@ -102,6 +102,9 @@ color: var(--text-primary) !important; } + + + diff --git a/static/games.html b/static/games.html index a312236a..c2a9e7c5 100644 --- a/static/games.html +++ b/static/games.html @@ -44,6 +44,22 @@ + + + + + + + + + + @@ -148,11 +164,49 @@

+ +
+ + +
+
+ +
+ + +
+ + +
+ + +
+