diff --git a/.eslintrc.json b/.eslintrc.json index e0f2ca6..0e45e8e 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,27 +1,27 @@ -{ - "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], - "parser": "@typescript-eslint/parser", - "plugins": ["@typescript-eslint"], - "rules": { - "no-await-in-loop": "warn", - "no-unused-labels": "error", - "no-unused-vars": "error", - "quotes": ["error", "double"], - "max-lines-per-function": ["error", { - "max": 200, - "skipComments": true - }], - "getter-return": "error", - "newline-before-return": "error", - "no-multiple-empty-lines": "error", - "no-var": "error", - "indent": ["warn", 4], - "no-this-before-super": "warn", - "no-useless-return": "error", - "no-shadow": "error", - "prefer-const": "warn", - "no-unreachable": "warn", - "no-undef": "off", - "@typescript-eslint/ban-ts-comment": "off" - } +{ + "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint"], + "rules": { + "no-await-in-loop": "warn", + "no-unused-labels": "error", + "no-unused-vars": "error", + "quotes": ["error", "double"], + "max-lines-per-function": ["error", { + "max": 200, + "skipComments": true + }], + "getter-return": "error", + "newline-before-return": "error", + "no-multiple-empty-lines": "error", + "no-var": "error", + "indent": ["warn", 4], + "no-this-before-super": "warn", + "no-useless-return": "error", + "no-shadow": "error", + "prefer-const": "warn", + "no-unreachable": "warn", + "no-undef": "off", + "@typescript-eslint/ban-ts-comment": "off" + } } \ No newline at end of file diff --git a/.gitignore b/.gitignore index c4c863b..e13e08c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,9 @@ -node_modules -dist -static/scramjet* -static/bare-mux.js -static/bare-client.js -static/curl-client.js -static/epoxy-client.js -static/bare-mux-worker.js -meta.json +node_modules +dist +static/scramjet* +static/bare-mux.js +static/bare-client.js +static/curl-client.js +static/epoxy-client.js +static/bare-mux-worker.js +meta.json diff --git a/README.md b/README.md index fa5e320..8355567 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,21 @@ -# Scramjet - -Scramjet is an experimental web proxy that aims to be the successor to Ultraviolet. - -It currently does not support most websites due to it being very early in the development stage. - -The UI is not finalized and only used as a means to test the web proxy. - -## How to build -Running `pnpm dev` will build Scramjet and start a dev server on localhost:1337. If you only want to build the proxy without using the dev server, run `pnpm build`. - - - -## TODO -- Finish HTML rewriting - - `` rewriting - - Make an array of all possible import values and pass the array onto the JS rewriter, then rewrite all the URLs inside of it -- Finish JS rewriting - - Only thing rewritten currently are imports and exports - - Check imports/exports for values contained in the `importmap` array, don't rewrite the node value if present -- Write client APIs +# Scramjet + +Scramjet is an experimental web proxy that aims to be the successor to Ultraviolet. + +It currently does not support most websites due to it being very early in the development stage. + +The UI is not finalized and only used as a means to test the web proxy. + +## How to build +Running `pnpm dev` will build Scramjet and start a dev server on localhost:1337. If you only want to build the proxy without using the dev server, run `pnpm build`. + + + +## TODO +- Finish HTML rewriting + - `` rewriting + - Make an array of all possible import values and pass the array onto the JS rewriter, then rewrite all the URLs inside of it +- Finish JS rewriting + - Only thing rewritten currently are imports and exports + - Check imports/exports for values contained in the `importmap` array, don't rewrite the node value if present +- Write client APIs diff --git a/esbuild.dev.js b/esbuild.dev.js deleted file mode 100644 index 7b18738..0000000 --- a/esbuild.dev.js +++ /dev/null @@ -1,97 +0,0 @@ -// import { createServer } from "esbuild-server"; -import copy from "esbuild-plugin-copy"; -import time from "esbuild-plugin-time"; -import { createBareServer } from "@tomphttp/bare-server-node"; -import Fastify from "fastify"; -import { context } from "esbuild"; -import { createServer } from "http"; -import fastifyStatic from "@fastify/static"; -import { join } from "path"; -import { fileURLToPath } from "url"; -import "dotenv/config"; - -const bare = createBareServer("/bare/", { - logErrors: true -}); - -const fastify = Fastify({ - serverFactory: (handler) => { - return createServer() - .on("request", (req, res) => { - if (bare.shouldRoute(req)) { - bare.routeRequest(req, res); - } else { - handler(req, res); - } - }).on("upgrade", (req, socket, head) => { - if (bare.shouldRoute(req)) { - bare.routeUpgrade(req, socket, head); - } else { - socket.end(); - } - }) - } -}); - -fastify.register(fastifyStatic, { - root: join(fileURLToPath(new URL(".", import.meta.url)), "./static"), - decorateReply: false -}); - -//fastify.get("/", { - -// }) - -fastify.listen({ - port: 1337 -}); - -const devServer = await context({ - entryPoints: { - client: "./src/client/index.ts", - bundle: "./src/bundle/index.ts", - worker: "./src/worker/index.ts", - codecs: "./src/codecs/index.ts", - config: "./src/scramjet.config.ts", - }, - entryNames: "scramjet.[name]", - outdir: "./dist", - bundle: true, - sourcemap: true, - logLevel: "info", - format: "esm", - plugins: [ - copy({ - resolveFrom: "cwd", - assets: [ - { - from: ["./node_modules/@mercuryworkshop/bare-mux/dist/index.js"], - to: ["./static/bare-mux.js"], - }, - { - from: ["./node_modules/@mercuryworkshop/bare-as-module3/dist/index.mjs"], - to: ["./static/bare-client.js"], - }, - { - from: ["./node_modules/@mercuryworkshop/libcurl-transport/dist/index.mjs"], - to: ["./static/curl-client.js"], - }, - { - from: ["./node_modules/@mercuryworkshop/epoxy-transport/dist/index.mjs"], - to: ["./static/epoxy-client.js"], - }, - { - from: ["./node_modules/@mercuryworkshop/bare-mux/dist/worker.js"], - to: ["./static/bare-mux-worker.js"], - }, - { - from: ["./dist/*"], - to: ["./static"] - }, - ], - }), - time() - ], -}); - -await devServer.watch(); diff --git a/esbuild.js b/esbuild.js deleted file mode 100644 index 61cdc86..0000000 --- a/esbuild.js +++ /dev/null @@ -1,26 +0,0 @@ -import { build } from "esbuild"; -import time from "esbuild-plugin-time"; -import { writeFileSync } from "fs" - -const scramjetBuild = await build({ - entryPoints: { - client: "./src/client/index.ts", - bundle: "./src/bundle/index.ts", - worker: "./src/worker/index.ts", - codecs: "./src/codecs/index.ts", - config: "./src/scramjet.config.ts", - }, - entryNames: "scramjet.[name]", - outdir: "./dist", - bundle: true, - plugins: [ - time() - ], - logLevel: "info", - metafile: true, - treeShaking: true, - minify: true, - format: "esm" -}); - -writeFileSync("./meta.json", JSON.stringify(scramjetBuild.metafile)); diff --git a/lib/index.cjs b/lib/index.cjs index 1eaaca9..3f71e05 100644 --- a/lib/index.cjs +++ b/lib/index.cjs @@ -1,7 +1,7 @@ -"use strict"; - -const { resolve } = require("node:path"); - -const scramjetPath = resolve(__dirname, "..", "dist"); - -exports.scramjetPath = scramjetPath; +"use strict"; + +const { resolve } = require("node:path"); + +const scramjetPath = resolve(__dirname, "..", "dist"); + +exports.scramjetPath = scramjetPath; diff --git a/lib/index.d.ts b/lib/index.d.ts index eb8f014..340adfa 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1,3 +1,3 @@ -declare const scramjetPath: string; - -export { scramjetPath }; +declare const scramjetPath: string; + +export { scramjetPath }; diff --git a/package.json b/package.json index 96d7863..4388c15 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,8 @@ "url": "https://github.com/MercuryWorkshop/scramjet" }, "scripts": { - "build": "node esbuild.js", - "dev": "node esbuild.dev.js", + "build": "rollup -c", + "dev": "node server.js", "prepublish": "pnpm build", "pub": "pnpm publish --no-git-checks --access public" }, @@ -26,18 +26,20 @@ "@mercuryworkshop/bare-as-module3": "^2.2.2", "@mercuryworkshop/epoxy-transport": "^2.1.3", "@mercuryworkshop/libcurl-transport": "^1.3.6", + "@rollup/plugin-inject": "^5.0.5", + "@rollup/plugin-replace": "^5.0.5", "@tomphttp/bare-server-node": "^2.0.3", "@types/eslint": "^8.56.10", - "@types/estraverse": "^5.1.7", + "@types/estree": "^1.0.5", + "@types/node": "^20.14.10", "@types/serviceworker": "^0.0.85", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", "dotenv": "^16.4.5", - "esbuild": "^0.20.2", - "esbuild-plugin-copy": "^2.1.1", - "esbuild-plugin-time": "^1.0.0", "eslint": "^8.57.0", "fastify": "^4.26.2", + "rollup": "^4.17.2", + "rollup-plugin-typescript2": "^0.36.0", "tslib": "^2.6.2", "typescript": "^5.4.5" }, @@ -45,11 +47,11 @@ "dependencies": { "@mercuryworkshop/bare-mux": "^2.0.2", "@webreflection/idb-map": "^0.3.1", + "astravel": "^0.6.1", "astring": "^1.8.6", "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", "domutils": "^3.1.0", - "estraverse": "^5.3.0", "htmlparser2": "^9.1.0", "meriyah": "^4.4.2" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6baa3ad..12f2fab 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: '@webreflection/idb-map': specifier: ^0.3.1 version: 0.3.1 + astravel: + specifier: ^0.6.1 + version: 0.6.1 astring: specifier: ^1.8.6 version: 1.8.6 @@ -26,9 +29,6 @@ importers: domutils: specifier: ^3.1.0 version: 3.1.0 - estraverse: - specifier: ^5.3.0 - version: 5.3.0 htmlparser2: specifier: ^9.1.0 version: 9.1.0 @@ -48,15 +48,24 @@ importers: '@mercuryworkshop/libcurl-transport': specifier: ^1.3.6 version: 1.3.6(typescript@5.4.5) + '@rollup/plugin-inject': + specifier: ^5.0.5 + version: 5.0.5(rollup@4.17.2) + '@rollup/plugin-replace': + specifier: ^5.0.5 + version: 5.0.7(rollup@4.17.2) '@tomphttp/bare-server-node': specifier: ^2.0.3 version: 2.0.3 '@types/eslint': specifier: ^8.56.10 version: 8.56.10 - '@types/estraverse': - specifier: ^5.1.7 - version: 5.1.7 + '@types/estree': + specifier: ^1.0.5 + version: 1.0.5 + '@types/node': + specifier: ^20.14.10 + version: 20.14.10 '@types/serviceworker': specifier: ^0.0.85 version: 0.0.85 @@ -69,21 +78,18 @@ importers: dotenv: specifier: ^16.4.5 version: 16.4.5 - esbuild: - specifier: ^0.20.2 - version: 0.20.2 - esbuild-plugin-copy: - specifier: ^2.1.1 - version: 2.1.1(esbuild@0.20.2) - esbuild-plugin-time: - specifier: ^1.0.0 - version: 1.0.0 eslint: specifier: ^8.57.0 version: 8.57.0 fastify: specifier: ^4.26.2 version: 4.26.2 + rollup: + specifier: ^4.17.2 + version: 4.17.2 + rollup-plugin-typescript2: + specifier: ^0.36.0 + version: 0.36.0(rollup@4.17.2)(typescript@5.4.5) tslib: specifier: ^2.6.2 version: 2.6.2 @@ -93,144 +99,6 @@ importers: packages: - '@esbuild/aix-ppc64@0.20.2': - resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.20.2': - resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.20.2': - resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.20.2': - resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.20.2': - resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.20.2': - resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.20.2': - resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.20.2': - resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.20.2': - resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.20.2': - resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.20.2': - resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.20.2': - resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.20.2': - resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.20.2': - resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.20.2': - resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.20.2': - resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.20.2': - resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-x64@0.20.2': - resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-x64@0.20.2': - resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - - '@esbuild/sunos-x64@0.20.2': - resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.20.2': - resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.20.2': - resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.20.2': - resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - '@eslint-community/eslint-utils@4.4.0': resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -286,6 +154,9 @@ packages: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + '@lukeed/ms@2.0.2': resolution: {integrity: sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA==} engines: {node: '>=8'} @@ -321,10 +192,37 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} + '@rollup/plugin-inject@5.0.5': + resolution: {integrity: sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-replace@5.0.7': + resolution: {integrity: sha512-PqxSfuorkHz/SPpyngLyg5GCEkOcee9M1bkxiVDr41Pd61mqP1PLOoDPbpl44SB2mQGKwV/In74gqQmGITOhEQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + '@rollup/pluginutils@4.2.1': resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} engines: {node: '>= 8.0.0'} + '@rollup/pluginutils@5.1.0': + resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + '@rollup/rollup-android-arm-eabi@4.17.2': resolution: {integrity: sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ==} cpu: [arm] @@ -413,17 +311,14 @@ packages: '@types/eslint@8.56.10': resolution: {integrity: sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==} - '@types/estraverse@5.1.7': - resolution: {integrity: sha512-JRVtdKYZz7VkNp7hMC/WKoiZ8DS3byw20ZGoMZ1R8eBrBPIY7iBaDAS1zcrnXQCwK44G4vbXkimeU7R0VLG8UQ==} - '@types/estree@1.0.5': resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/node@20.12.11': - resolution: {integrity: sha512-vDg9PZ/zi+Nqp6boSOT7plNuthRugEKixDv5sFTIpkE89MmNtEArAShI4mxuX2+UrLEe9pxC1vm2cjm9YlWbJw==} + '@types/node@20.14.10': + resolution: {integrity: sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==} '@types/resolve@0.0.8': resolution: {integrity: sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==} @@ -553,10 +448,6 @@ packages: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} - anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} - archy@1.0.0: resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} @@ -567,6 +458,9 @@ packages: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} + astravel@0.6.1: + resolution: {integrity: sha512-ZIkgWFIV0Yo423Vqalz7VcF+BAiISvSgplnkV2abPGACPFKofsWTcvr9SFyYM/t/vMZWqmdP/Eze6ATX7r84Dg==} + astring@1.8.6: resolution: {integrity: sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==} hasBin: true @@ -588,10 +482,6 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} - brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -620,10 +510,6 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} - chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} - color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -707,22 +593,9 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} - esbuild-plugin-copy@2.1.1: - resolution: {integrity: sha512-Bk66jpevTcV8KMFzZI1P7MZKZ+uDcrZm2G2egZ2jNIvVnivDpodZI+/KnpL3Jnap0PBdIHU7HwFGB8r+vV5CVw==} - peerDependencies: - esbuild: '>= 0.14.0' - - esbuild-plugin-time@1.0.0: - resolution: {integrity: sha512-I4Shhi0fpgXxSoc34djTHIuhbEzkcBbKKiNtb3LhZe2JEE1vSxXilW+KE0M/KZ4kqORLGgdGCKuJh9CNUL55yw==} - esbuild-plugin-umd-wrapper@2.0.0: resolution: {integrity: sha512-pcu2/lcm29S85VCnSJuValrQ8FqeFJs5VWEwfp7vBRsOHjxZypcxgwXjxDIxDRo17uOcENZIbgz2szjln029eQ==} - esbuild@0.20.2: - resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==} - engines: {node: '>=12'} - hasBin: true - escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} @@ -946,10 +819,6 @@ packages: resolution: {integrity: sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==} engines: {node: '>= 10'} - is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} - is-core-module@2.13.1: resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} @@ -1037,6 +906,9 @@ packages: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} + magic-string@0.30.10: + resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==} + make-dir@3.1.0: resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} engines: {node: '>=8'} @@ -1075,10 +947,6 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - on-exit-leak-free@2.1.2: resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} engines: {node: '>=14.0.0'} @@ -1184,10 +1052,6 @@ packages: resolution: {integrity: sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} - real-require@0.2.0: resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} engines: {node: '>= 12.13.0'} @@ -1431,75 +1295,6 @@ packages: snapshots: - '@esbuild/aix-ppc64@0.20.2': - optional: true - - '@esbuild/android-arm64@0.20.2': - optional: true - - '@esbuild/android-arm@0.20.2': - optional: true - - '@esbuild/android-x64@0.20.2': - optional: true - - '@esbuild/darwin-arm64@0.20.2': - optional: true - - '@esbuild/darwin-x64@0.20.2': - optional: true - - '@esbuild/freebsd-arm64@0.20.2': - optional: true - - '@esbuild/freebsd-x64@0.20.2': - optional: true - - '@esbuild/linux-arm64@0.20.2': - optional: true - - '@esbuild/linux-arm@0.20.2': - optional: true - - '@esbuild/linux-ia32@0.20.2': - optional: true - - '@esbuild/linux-loong64@0.20.2': - optional: true - - '@esbuild/linux-mips64el@0.20.2': - optional: true - - '@esbuild/linux-ppc64@0.20.2': - optional: true - - '@esbuild/linux-riscv64@0.20.2': - optional: true - - '@esbuild/linux-s390x@0.20.2': - optional: true - - '@esbuild/linux-x64@0.20.2': - optional: true - - '@esbuild/netbsd-x64@0.20.2': - optional: true - - '@esbuild/openbsd-x64@0.20.2': - optional: true - - '@esbuild/sunos-x64@0.20.2': - optional: true - - '@esbuild/win32-arm64@0.20.2': - optional: true - - '@esbuild/win32-ia32@0.20.2': - optional: true - - '@esbuild/win32-x64@0.20.2': - optional: true - '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)': dependencies: eslint: 8.57.0 @@ -1579,6 +1374,8 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@jridgewell/sourcemap-codec@1.5.0': {} + '@lukeed/ms@2.0.2': {} '@mercuryworkshop/bare-as-module3@2.2.2': @@ -1624,11 +1421,34 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true + '@rollup/plugin-inject@5.0.5(rollup@4.17.2)': + dependencies: + '@rollup/pluginutils': 5.1.0(rollup@4.17.2) + estree-walker: 2.0.2 + magic-string: 0.30.10 + optionalDependencies: + rollup: 4.17.2 + + '@rollup/plugin-replace@5.0.7(rollup@4.17.2)': + dependencies: + '@rollup/pluginutils': 5.1.0(rollup@4.17.2) + magic-string: 0.30.10 + optionalDependencies: + rollup: 4.17.2 + '@rollup/pluginutils@4.2.1': dependencies: estree-walker: 2.0.2 picomatch: 2.3.1 + '@rollup/pluginutils@5.1.0(rollup@4.17.2)': + dependencies: + '@types/estree': 1.0.5 + estree-walker: 2.0.2 + picomatch: 2.3.1 + optionalDependencies: + rollup: 4.17.2 + '@rollup/rollup-android-arm-eabi@4.17.2': optional: true @@ -1695,21 +1515,17 @@ snapshots: '@types/estree': 1.0.5 '@types/json-schema': 7.0.15 - '@types/estraverse@5.1.7': - dependencies: - '@types/estree': 1.0.5 - '@types/estree@1.0.5': {} '@types/json-schema@7.0.15': {} - '@types/node@20.12.11': + '@types/node@20.14.10': dependencies: undici-types: 5.26.5 '@types/resolve@0.0.8': dependencies: - '@types/node': 20.12.11 + '@types/node': 20.14.10 '@types/semver@7.5.8': {} @@ -1849,17 +1665,14 @@ snapshots: ansi-styles@6.2.1: {} - anymatch@3.1.3: - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.1 - archy@1.0.0: {} argparse@2.0.1: {} array-union@2.1.0: {} + astravel@0.6.1: {} + astring@1.8.6: {} async-exit-hook@2.0.1: {} @@ -1879,8 +1692,6 @@ snapshots: base64-js@1.5.1: {} - binary-extensions@2.3.0: {} - brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 @@ -1910,18 +1721,6 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 - chokidar@3.6.0: - dependencies: - anymatch: 3.1.3 - braces: 3.0.2 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 - color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -1990,46 +1789,8 @@ snapshots: entities@4.5.0: {} - esbuild-plugin-copy@2.1.1(esbuild@0.20.2): - dependencies: - chalk: 4.1.2 - chokidar: 3.6.0 - esbuild: 0.20.2 - fs-extra: 10.1.0 - globby: 11.1.0 - - esbuild-plugin-time@1.0.0: - dependencies: - chalk: 4.1.2 - esbuild-plugin-umd-wrapper@2.0.0: {} - esbuild@0.20.2: - optionalDependencies: - '@esbuild/aix-ppc64': 0.20.2 - '@esbuild/android-arm': 0.20.2 - '@esbuild/android-arm64': 0.20.2 - '@esbuild/android-x64': 0.20.2 - '@esbuild/darwin-arm64': 0.20.2 - '@esbuild/darwin-x64': 0.20.2 - '@esbuild/freebsd-arm64': 0.20.2 - '@esbuild/freebsd-x64': 0.20.2 - '@esbuild/linux-arm': 0.20.2 - '@esbuild/linux-arm64': 0.20.2 - '@esbuild/linux-ia32': 0.20.2 - '@esbuild/linux-loong64': 0.20.2 - '@esbuild/linux-mips64el': 0.20.2 - '@esbuild/linux-ppc64': 0.20.2 - '@esbuild/linux-riscv64': 0.20.2 - '@esbuild/linux-s390x': 0.20.2 - '@esbuild/linux-x64': 0.20.2 - '@esbuild/netbsd-x64': 0.20.2 - '@esbuild/openbsd-x64': 0.20.2 - '@esbuild/sunos-x64': 0.20.2 - '@esbuild/win32-arm64': 0.20.2 - '@esbuild/win32-ia32': 0.20.2 - '@esbuild/win32-x64': 0.20.2 - escape-html@1.0.3: {} escape-string-regexp@4.0.0: {} @@ -2316,10 +2077,6 @@ snapshots: ipaddr.js@2.2.0: {} - is-binary-path@2.1.0: - dependencies: - binary-extensions: 2.3.0 - is-core-module@2.13.1: dependencies: hasown: 2.0.2 @@ -2401,6 +2158,10 @@ snapshots: dependencies: yallist: 4.0.0 + magic-string@0.30.10: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + make-dir@3.1.0: dependencies: semver: 6.3.1 @@ -2430,8 +2191,6 @@ snapshots: natural-compare@1.4.0: {} - normalize-path@3.0.0: {} - on-exit-leak-free@2.1.2: {} once@1.4.0: @@ -2536,10 +2295,6 @@ snapshots: process: 0.11.10 string_decoder: 1.3.0 - readdirp@3.6.0: - dependencies: - picomatch: 2.3.1 - real-require@0.2.0: {} require-from-string@2.0.2: {} diff --git a/rollup.config.js b/rollup.config.js new file mode 100644 index 0000000..4237c21 --- /dev/null +++ b/rollup.config.js @@ -0,0 +1,35 @@ +import typescript from "rollup-plugin-typescript2"; +import { join } from "node:path"; +import fs from "node:fs" +import { fileURLToPath } from "node:url"; + +// check if its +const production = !process.env.ROLLUP_WATCH; +console.log(production) +fs.rmSync(join(fileURLToPath(new URL(".", import.meta.url)), "./dist"), { recursive: true, force: true }) + +const commonPlugins = () => [ + typescript({ + tsconfig: "tsconfig.json", + }), +] + +export default { + plugins: commonPlugins(), + input: { + client: "./src/client/index.ts", + bundle: "./src/bundle/index.ts", + worker: "./src/worker/index.ts", + codecs: "./src/codecs/index.ts", + config: "./src/scramjet.config.ts" + }, + output: { + entryFileNames: "scramjet.[name].js", + dir: "./dist", + format: "esm", + bundle: true, + minify: production, + sourcemap: true, + treeshake: "recommended", + }, +}; diff --git a/server.js b/server.js new file mode 100644 index 0000000..48fcb71 --- /dev/null +++ b/server.js @@ -0,0 +1,74 @@ +// Dev server imports +import { createBareServer } from "@tomphttp/bare-server-node"; +import { createServer } from "http"; +import Fastify from "fastify"; +import fastifyStatic from "@fastify/static"; +import { join } from "node:path"; +import fs from "node:fs" +import { fileURLToPath } from "node:url"; +import { watch } from "rollup" +import { loadConfigFile } from "rollup/loadConfigFile" + +//transports +import { baremuxPath } from "@mercuryworkshop/bare-mux/node" +import { epoxyPath } from "@mercuryworkshop/epoxy-transport" +import { libcurlPath } from "@mercuryworkshop/libcurl-transport" +import { bareModulePath } from "@mercuryworkshop/bare-as-module3" + +let watcher = watch() + +const bare = createBareServer("/bare/", { + logErrors: true +}); + +const fastify = Fastify({ + serverFactory: (handler) => { + return createServer() + .on("request", (req, res) => { + if (bare.shouldRoute(req)) { + bare.routeRequest(req, res); + } else { + handler(req, res); + } + }).on("upgrade", (req, socket, head) => { + if (bare.shouldRoute(req)) { + bare.routeUpgrade(req, socket, head); + } else { + socket.end(); + } + }) + } +}); + +fastify.register(fastifyStatic, { + root: join(fileURLToPath(new URL(".", import.meta.url)), "./static"), + decorateReply: false +}); +fastify.register(fastifyStatic, { + root: join(fileURLToPath(new URL(".", import.meta.url)), "./dist"), + prefix: "/dist/", + decorateReply: false +}) +fastify.register(fastifyStatic, { + root: baremuxPath, + prefix: "/baremux/", + decorateReply: false +}) +fastify.register(fastifyStatic, { + root: epoxyPath, + prefix: "/epoxy/", + decorateReply: false +}) +fastify.register(fastifyStatic, { + root: libcurlPath, + prefix: "/libcurl/", + decorateReply: false +}) +fastify.register(fastifyStatic, { + root: bareModulePath, + prefix: "/baremod/", + decorateReply: false +}) +fastify.listen({ + port: process.env.PORT || 1337 +}); \ No newline at end of file diff --git a/src/bundle/index.ts b/src/bundle/index.ts index 394f79a..6df878a 100644 --- a/src/bundle/index.ts +++ b/src/bundle/index.ts @@ -1,14 +1,14 @@ -export { encodeUrl, decodeUrl } from "./rewriters/url"; -export { rewriteCss } from "./rewriters/css"; -export { rewriteHtml, rewriteSrcset } from "./rewriters/html"; -export { rewriteJs } from "./rewriters/js"; -export { rewriteHeaders } from "./rewriters/headers"; - -export function isScramjetFile(src: string) { - let bool = false; - ["codecs", "client", "bundle", "worker", "config"].forEach((file) => { - if (src === self.__scramjet$config[file]) bool = true; - }); - - return bool; +export { encodeUrl, decodeUrl } from "./rewriters/url"; +export { rewriteCss } from "./rewriters/css"; +export { rewriteHtml, rewriteSrcset } from "./rewriters/html"; +export { rewriteJs } from "./rewriters/js"; +export { rewriteHeaders } from "./rewriters/headers"; + +export function isScramjetFile(src: string) { + let bool = false; + ["codecs", "client", "bundle", "worker", "config"].forEach((file) => { + if (src === self.__scramjet$config[file]) bool = true; + }); + + return bool; } \ No newline at end of file diff --git a/src/bundle/rewriters/css.ts b/src/bundle/rewriters/css.ts index 17b9ecf..088d9c8 100644 --- a/src/bundle/rewriters/css.ts +++ b/src/bundle/rewriters/css.ts @@ -1,35 +1,35 @@ -// This CSS rewriter uses code from Meteor -// You can find the original source code at https://github.com/MeteorProxy/Meteor - -import { encodeUrl } from "./url"; - -export function rewriteCss(css: string, origin?: URL) { - const regex = - /(@import\s+(?!url\())?\s*url\(\s*(['"]?)([^'")]+)\2\s*\)|@import\s+(['"])([^'"]+)\4/g - - return css.replace( - regex, - ( - match, - importStatement, - urlQuote, - urlContent, - importQuote, - importContent - ) => { - const url = urlContent || importContent - const encodedUrl = encodeUrl(url.trim(), origin) - - if (importStatement) { - return `@import url(${urlQuote}${encodedUrl}${urlQuote})` - } - - if (importQuote) { - return `@import ${importQuote}${encodedUrl}${importQuote}` - } - - return `url(${urlQuote}${encodedUrl}${urlQuote})` - } - ) - -} +// This CSS rewriter uses code from Meteor +// You can find the original source code at https://github.com/MeteorProxy/Meteor + +import { encodeUrl } from "./url"; + +export function rewriteCss(css: string, origin?: URL) { + const regex = + /(@import\s+(?!url\())?\s*url\(\s*(['"]?)([^'")]+)\2\s*\)|@import\s+(['"])([^'"]+)\4/g + + return css.replace( + regex, + ( + match, + importStatement, + urlQuote, + urlContent, + importQuote, + importContent + ) => { + const url = urlContent || importContent + const encodedUrl = encodeUrl(url.trim(), origin) + + if (importStatement) { + return `@import url(${urlQuote}${encodedUrl}${urlQuote})` + } + + if (importQuote) { + return `@import ${importQuote}${encodedUrl}${importQuote}` + } + + return `url(${urlQuote}${encodedUrl}${urlQuote})` + } + ) + +} diff --git a/src/bundle/rewriters/headers.ts b/src/bundle/rewriters/headers.ts index cef1044..fb83bcf 100644 --- a/src/bundle/rewriters/headers.ts +++ b/src/bundle/rewriters/headers.ts @@ -1,53 +1,53 @@ -import { encodeUrl } from "./url"; -import { BareHeaders } from "@mercuryworkshop/bare-mux"; - -const cspHeaders = [ - "cross-origin-embedder-policy", - "cross-origin-opener-policy", - "cross-origin-resource-policy", - "content-security-policy", - "content-security-policy-report-only", - "expect-ct", - "feature-policy", - "origin-isolation", - "strict-transport-security", - "upgrade-insecure-requests", - "x-content-type-options", - "x-download-options", - "x-frame-options", - "x-permitted-cross-domain-policies", - "x-powered-by", - "x-xss-protection", - // This needs to be emulated, but for right now it isn't that important of a feature to be worried about - // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Clear-Site-Data - "clear-site-data" -]; - -const urlHeaders = [ - "location", - "content-location", - "referer" -]; - -export function rewriteHeaders(rawHeaders: BareHeaders, origin?: URL) { - const headers = {}; - - for (const key in rawHeaders) { - headers[key.toLowerCase()] = rawHeaders[key]; - } - - cspHeaders.forEach((header) => { - delete headers[header]; - }); - - urlHeaders.forEach((header) => { - if (headers[header]) - headers[header] = encodeUrl(headers[header] as string, origin); - }); - - if (headers["link"]) { - headers["link"] = headers["link"].replace(/<(.*?)>/gi, (match) => encodeUrl(match, origin)); - } - - return headers; +import { encodeUrl } from "./url"; +import { BareHeaders } from "@mercuryworkshop/bare-mux"; + +const cspHeaders = [ + "cross-origin-embedder-policy", + "cross-origin-opener-policy", + "cross-origin-resource-policy", + "content-security-policy", + "content-security-policy-report-only", + "expect-ct", + "feature-policy", + "origin-isolation", + "strict-transport-security", + "upgrade-insecure-requests", + "x-content-type-options", + "x-download-options", + "x-frame-options", + "x-permitted-cross-domain-policies", + "x-powered-by", + "x-xss-protection", + // This needs to be emulated, but for right now it isn't that important of a feature to be worried about + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Clear-Site-Data + "clear-site-data" +]; + +const urlHeaders = [ + "location", + "content-location", + "referer" +]; + +export function rewriteHeaders(rawHeaders: BareHeaders, origin?: URL) { + const headers = {}; + + for (const key in rawHeaders) { + headers[key.toLowerCase()] = rawHeaders[key]; + } + + cspHeaders.forEach((header) => { + delete headers[header]; + }); + + urlHeaders.forEach((header) => { + if (headers[header]) + headers[header] = encodeUrl(headers[header] as string, origin); + }); + + if (headers["link"]) { + headers["link"] = headers["link"].replace(/<(.*?)>/gi, (match) => encodeUrl(match, origin)); + } + + return headers; } \ No newline at end of file diff --git a/src/bundle/rewriters/html.ts b/src/bundle/rewriters/html.ts index cf3ceee..388360f 100644 --- a/src/bundle/rewriters/html.ts +++ b/src/bundle/rewriters/html.ts @@ -1,97 +1,97 @@ -import { Parser } from "htmlparser2"; -import { DomHandler, Element } from "domhandler"; -import { hasAttrib } from "domutils"; -import render from "dom-serializer"; -import { encodeUrl } from "./url"; -import { rewriteCss } from "./css"; -import { rewriteJs } from "./js"; -import { isScramjetFile } from "../"; - -export function rewriteHtml(html: string, origin?: URL) { - const handler = new DomHandler((err, dom) => dom); - const parser = new Parser(handler); - - parser.write(html); - parser.end(); - - return render(traverseParsedHtml(handler.root, origin)); -} - -// i need to add the attributes in during rewriting - -function traverseParsedHtml(node, origin?: URL) { - /* csp attributes */ - for (const cspAttr of ["nonce", "integrity", "csp"]) { - if (hasAttrib(node, cspAttr)) { - node.attribs[`data-${cspAttr}`] = node.attribs[cspAttr]; - delete node.attribs[cspAttr]; - } - } - - /* url attributes */ - for (const urlAttr of ["src", "href", "data", "action", "formaction"]) { - if (hasAttrib(node, urlAttr) && !isScramjetFile(node.attribs[urlAttr])) { - const value = node.attribs[urlAttr]; - node.attribs[`data-${urlAttr}`] = value; - node.attribs[urlAttr] = encodeUrl(value, origin); - } - } - - /* other */ - for (const srcsetAttr of ["srcset", "imagesrcset"]) { - if (hasAttrib(node, srcsetAttr)) { - const value = node.attribs[srcsetAttr]; - node.attribs[`data-${srcsetAttr}`] = value; - node.attribs[srcsetAttr] = rewriteSrcset(value, origin); - } - } - - if (hasAttrib(node, "srcdoc")) node.attribs.srcdoc = rewriteHtml(node.attribs.srcdoc, origin); - if (hasAttrib(node, "style")) node.attribs.style = rewriteCss(node.attribs.style, origin); - - if (node.name === "style" && node.children[0] !== undefined) node.children[0].data = rewriteCss(node.children[0].data, origin); - if (node.name === "script" && /(application|text)\/javascript|importmap|undefined/.test(node.attribs.type) && node.children[0] !== undefined) node.children[0].data = rewriteJs(node.children[0].data, origin); - if (node.name === "meta" && hasAttrib(node, "http-equiv")) { - if (node.attribs["http-equiv"] === "content-security-policy") { - node = {}; - } else if (node.attribs["http-equiv"] === "refresh" && node.attribs.content.includes("url")) { - const contentArray = node.attribs.content.split("url="); - contentArray[1] = encodeUrl(contentArray[1].trim(), origin); - node.attribs.content = contentArray.join("url="); - } - } - - if (node.name === "head") { - const scramjetScripts = []; - ["codecs", "config", "bundle", "client"].forEach((script) => { - scramjetScripts.push(new Element("script", { - src: self.__scramjet$config[script], - type: "module" - })); - }); - - node.children.unshift(...scramjetScripts); - } - - if (node.childNodes) { - for (const childNode in node.childNodes) { - node.childNodes[childNode] = traverseParsedHtml(node.childNodes[childNode], origin); - } - } - - return node; -} - -export function rewriteSrcset(srcset: string, origin?: URL) { - const urls = srcset.split(/ [0-9]+x,? ?/g); - if (!urls) return ""; - const sufixes = srcset.match(/ [0-9]+x,? ?/g); - if (!sufixes) return ""; - const rewrittenUrls = urls.map((url, i) => { - if (url && sufixes[i]) { - return encodeUrl(url, origin) + sufixes[i]; - } - }); - - return rewrittenUrls.join(""); +import { Parser } from "htmlparser2"; +import { DomHandler, Element } from "domhandler"; +import { hasAttrib } from "domutils"; +import render from "dom-serializer"; +import { encodeUrl } from "./url"; +import { rewriteCss } from "./css"; +import { rewriteJs } from "./js"; +import { isScramjetFile } from "../"; + +export function rewriteHtml(html: string, origin?: URL) { + const handler = new DomHandler((err, dom) => dom); + const parser = new Parser(handler); + + parser.write(html); + parser.end(); + + return render(traverseParsedHtml(handler.root, origin)); +} + +// i need to add the attributes in during rewriting + +function traverseParsedHtml(node, origin?: URL) { + /* csp attributes */ + for (const cspAttr of ["nonce", "integrity", "csp"]) { + if (hasAttrib(node, cspAttr)) { + node.attribs[`data-${cspAttr}`] = node.attribs[cspAttr]; + delete node.attribs[cspAttr]; + } + } + + /* url attributes */ + for (const urlAttr of ["src", "href", "data", "action", "formaction"]) { + if (hasAttrib(node, urlAttr) && !isScramjetFile(node.attribs[urlAttr])) { + const value = node.attribs[urlAttr]; + node.attribs[`data-${urlAttr}`] = value; + node.attribs[urlAttr] = encodeUrl(value, origin); + } + } + + /* other */ + for (const srcsetAttr of ["srcset", "imagesrcset"]) { + if (hasAttrib(node, srcsetAttr)) { + const value = node.attribs[srcsetAttr]; + node.attribs[`data-${srcsetAttr}`] = value; + node.attribs[srcsetAttr] = rewriteSrcset(value, origin); + } + } + + if (hasAttrib(node, "srcdoc")) node.attribs.srcdoc = rewriteHtml(node.attribs.srcdoc, origin); + if (hasAttrib(node, "style")) node.attribs.style = rewriteCss(node.attribs.style, origin); + + if (node.name === "style" && node.children[0] !== undefined) node.children[0].data = rewriteCss(node.children[0].data, origin); + if (node.name === "script" && /(application|text)\/javascript|importmap|undefined/.test(node.attribs.type) && node.children[0] !== undefined) node.children[0].data = rewriteJs(node.children[0].data, origin); + if (node.name === "meta" && hasAttrib(node, "http-equiv")) { + if (node.attribs["http-equiv"] === "content-security-policy") { + node = {}; + } else if (node.attribs["http-equiv"] === "refresh" && node.attribs.content.includes("url")) { + const contentArray = node.attribs.content.split("url="); + contentArray[1] = encodeUrl(contentArray[1].trim(), origin); + node.attribs.content = contentArray.join("url="); + } + } + + if (node.name === "head") { + const scramjetScripts = []; + ["codecs", "config", "bundle", "client"].forEach((script) => { + scramjetScripts.push(new Element("script", { + src: self.__scramjet$config[script], + type: "module" + })); + }); + + node.children.unshift(...scramjetScripts); + } + + if (node.childNodes) { + for (const childNode in node.childNodes) { + node.childNodes[childNode] = traverseParsedHtml(node.childNodes[childNode], origin); + } + } + + return node; +} + +export function rewriteSrcset(srcset: string, origin?: URL) { + const urls = srcset.split(/ [0-9]+x,? ?/g); + if (!urls) return ""; + const sufixes = srcset.match(/ [0-9]+x,? ?/g); + if (!sufixes) return ""; + const rewrittenUrls = urls.map((url, i) => { + if (url && sufixes[i]) { + return encodeUrl(url, origin) + sufixes[i]; + } + }); + + return rewrittenUrls.join(""); } \ No newline at end of file diff --git a/src/bundle/rewriters/js.ts b/src/bundle/rewriters/js.ts index 2435a1f..1e9cf1f 100644 --- a/src/bundle/rewriters/js.ts +++ b/src/bundle/rewriters/js.ts @@ -1,49 +1,78 @@ -import { parseModule } from "meriyah"; -import { generate } from "astring"; -import { encodeUrl } from "./url"; -import { replace } from "estraverse"; - -// i am a cat. i like to be petted. i like to be fed. i like to be - -// js rewiter is NOT finished - -// location -// window -// self -// globalThis -// this -// top -// parent - - -export function rewriteJs(js: string, origin?: URL) { - try { - const ast = parseModule(js); - - // const identifierList = [ - // "window", - // "self", - // "globalThis", - // "parent", - // "top", - // "location", - // "" - // ] - - replace(ast, { - enter: (node, parent) => { - if (["ImportDeclaration", "ImportExpression", "ExportAllDeclaration", "ExportNamedDeclaration"].includes(node.type) && node.source) { - node.source.value = encodeUrl(node.source.value, origin); - } - - return node; - }, - - fallback: "iteration" - }) - - return generate(ast); - } catch (err) { - throw new Error(err); - } +import { parseModule } from "meriyah"; +import { generate } from "astring"; +import { makeTraveler } from "astravel"; +import { encodeUrl } from "./url"; +import * as ESTree from "estree"; + +// i am a cat. i like to be petted. i like to be fed. i like to be + +// js rewiter is NOT finished + +// location +// window +// self +// globalThis +// this +// top +// parent + + +export function rewriteJs(js: string, origin?: URL) { + try { + const ast = parseModule(js, { + module: true, + webcompat: true + }); + + const identifierList = [ + "window", + "self", + "globalThis", + "this", + "parent", + "top", + "location" + ] + + const customTraveler = makeTraveler({ + ImportDeclaration: (node: ESTree.ImportDeclaration) => { + node.source.value = encodeUrl(node.source.value as string, origin); + }, + + ImportExpression: (node: ESTree.ImportExpression) => { + if (node.source.type === "Literal") { + node.source.value = encodeUrl(node.source.value as string, origin); + } else if (node.source.type === "Identifier") { + // this is for things that import something like + // const moduleName = "name"; + // await import(moduleName); + node.source.name = `__wrapImport(${node.source.name})`; + } + }, + + ExportAllDeclaration: (node: ESTree.ExportAllDeclaration) => { + node.source.value = encodeUrl(node.source.value as string, origin); + }, + + ExportNamedDeclaration: (node: ESTree.ExportNamedDeclaration) => { + // strings are Literals in ESTree syntax but these will always be strings + if (node.source) node.source.value = encodeUrl(node.source.value as string, origin); + }, + + // js rweriting notrdone + MemberExpression: (node: ESTree.MemberExpression) => { + if (node.object.type === "Identifier" && identifierList.includes(node.object.name)) { + node.object.name = "__" + node.object.name; + } + } + }); + + customTraveler.go(ast); + + return generate(ast); + } catch { + console.log(js); + + return js; + } } \ No newline at end of file diff --git a/src/bundle/rewriters/url.ts b/src/bundle/rewriters/url.ts index c7f8d11..47a4077 100644 --- a/src/bundle/rewriters/url.ts +++ b/src/bundle/rewriters/url.ts @@ -1,37 +1,37 @@ -import { rewriteJs } from "./js"; - -function canParseUrl(url: string, origin?: URL) { - try { - new URL(url, origin); - - return true; - } catch { - return false; - } -} - -// something is broken with this but i didn't debug it -export function encodeUrl(url: string, origin?: URL) { - if (!origin) { - origin = new URL(self.__scramjet$config.codec.decode(location.href.slice((location.origin + self.__scramjet$config.prefix).length))); - } - - if (url.startsWith("javascript:")) { - return "javascript:" + rewriteJs(url.slice("javascript:".length)); - } else if (/^(#|mailto|about|data)/.test(url)) { - return url; - } else if (canParseUrl(url, origin)) { - return location.origin + self.__scramjet$config.prefix + self.__scramjet$config.codec.encode(new URL(url, origin).href); - } -} - -// something is also broken with this but i didn't debug it -export function decodeUrl(url: string) { - if (/^(#|about|data|mailto|javascript)/.test(url)) { - return url; - } else if (canParseUrl(url)) { - return self.__scramjet$config.codec.decode(url.slice((location.origin + self.__scramjet$config.prefix).length)) - } else { - return url; - } +import { rewriteJs } from "./js"; + +function canParseUrl(url: string, origin?: URL) { + try { + new URL(url, origin); + + return true; + } catch { + return false; + } +} + +// something is broken with this but i didn't debug it +export function encodeUrl(url: string, origin?: URL) { + if (!origin) { + origin = new URL(self.__scramjet$config.codec.decode(location.href.slice((location.origin + self.__scramjet$config.prefix).length))); + } + + if (url.startsWith("javascript:")) { + return "javascript:" + rewriteJs(url.slice("javascript:".length)); + } else if (/^(#|mailto|about|data)/.test(url)) { + return url; + } else if (canParseUrl(url, origin)) { + return location.origin + self.__scramjet$config.prefix + self.__scramjet$config.codec.encode(new URL(url, origin).href); + } +} + +// something is also broken with this but i didn't debug it +export function decodeUrl(url: string) { + if (/^(#|about|data|mailto|javascript)/.test(url)) { + return url; + } else if (canParseUrl(url)) { + return self.__scramjet$config.codec.decode(url.slice((location.origin + self.__scramjet$config.prefix).length)) + } else { + return url; + } } \ No newline at end of file diff --git a/src/client/beacon.ts b/src/client/beacon.ts index bf377eb..e50c72f 100644 --- a/src/client/beacon.ts +++ b/src/client/beacon.ts @@ -1,9 +1,9 @@ -import { encodeUrl } from "../bundle"; - -navigator.sendBeacon = new Proxy(navigator.sendBeacon, { - apply(target, thisArg, argArray) { - argArray[0] = encodeUrl(argArray[0]); - - return Reflect.apply(target, thisArg, argArray); - }, +import { encodeUrl } from "../bundle"; + +navigator.sendBeacon = new Proxy(navigator.sendBeacon, { + apply(target, thisArg, argArray) { + argArray[0] = encodeUrl(argArray[0]); + + return Reflect.apply(target, thisArg, argArray); + }, }); \ No newline at end of file diff --git a/src/client/css.ts b/src/client/css.ts index f499ba2..520f762 100644 --- a/src/client/css.ts +++ b/src/client/css.ts @@ -1,26 +1,26 @@ -import { rewriteCss } from "../bundle"; - -const cssProperties = ["background", "background-image", "mask", "mask-image", "list-style", "list-style-image", "border-image", "border-image-source", "cursor"]; -const jsProperties = ["background", "backgroundImage", "mask", "maskImage", "listStyle", "listStyleImage", "borderImage", "borderImageSource", "cursor"]; - - -CSSStyleDeclaration.prototype.setProperty = new Proxy(CSSStyleDeclaration.prototype.setProperty, { - apply(target, thisArg, argArray) { - if (cssProperties.includes(argArray[0])) argArray[1] = rewriteCss(argArray[1]); - - return Reflect.apply(target, thisArg, argArray); - }, -}); - -jsProperties.forEach((prop) => { - const propDescriptor = Object.getOwnPropertyDescriptor(CSSStyleDeclaration.prototype, prop); - - Object.defineProperty(CSSStyleDeclaration.prototype, prop, { - get() { - return propDescriptor.get.call(this); - }, - set(v) { - return propDescriptor.set.call(this, rewriteCss(v)); - }, - }) +import { rewriteCss } from "../bundle"; + +const cssProperties = ["background", "background-image", "mask", "mask-image", "list-style", "list-style-image", "border-image", "border-image-source", "cursor"]; +const jsProperties = ["background", "backgroundImage", "mask", "maskImage", "listStyle", "listStyleImage", "borderImage", "borderImageSource", "cursor"]; + + +CSSStyleDeclaration.prototype.setProperty = new Proxy(CSSStyleDeclaration.prototype.setProperty, { + apply(target, thisArg, argArray) { + if (cssProperties.includes(argArray[0])) argArray[1] = rewriteCss(argArray[1]); + + return Reflect.apply(target, thisArg, argArray); + }, +}); + +jsProperties.forEach((prop) => { + const propDescriptor = Object.getOwnPropertyDescriptor(CSSStyleDeclaration.prototype, prop); + + Object.defineProperty(CSSStyleDeclaration.prototype, prop, { + get() { + return propDescriptor.get.call(this); + }, + set(v) { + return propDescriptor.set.call(this, rewriteCss(v)); + }, + }) }); \ No newline at end of file diff --git a/src/client/element.ts b/src/client/element.ts index 8bc58cc..a03451e 100644 --- a/src/client/element.ts +++ b/src/client/element.ts @@ -1,98 +1,98 @@ -import { encodeUrl, rewriteCss, rewriteHtml, rewriteJs, rewriteSrcset } from "../bundle"; - -const attrObject = { - "nonce": [HTMLElement], - "integrity": [HTMLScriptElement, HTMLLinkElement], - "csp": [HTMLIFrameElement], - "src": [HTMLImageElement, HTMLMediaElement, HTMLIFrameElement, HTMLEmbedElement, HTMLScriptElement], - "href": [HTMLAnchorElement, HTMLLinkElement], - "data": [HTMLObjectElement], - "action": [HTMLFormElement], - "formaction": [HTMLButtonElement, HTMLInputElement], - "srcdoc": [HTMLIFrameElement], - "srcset": [HTMLImageElement, HTMLSourceElement], - "imagesrcset": [HTMLLinkElement] -} - -const attrs = Object.keys(attrObject); - -for (const attr of attrs) { - for (const element of attrObject[attr]) { - const descriptor = Object.getOwnPropertyDescriptor(element.prototype, attr); - Object.defineProperty(element.prototype, attr, { - get() { - return this.dataset[attr]; - }, - - set(value) { - this.dataset[attr] = value; - if (/nonce|integrity|csp/.test(attr)) { - return; - } else if (/src|href|data|action|formaction/.test(attr)) { - // @ts-expect-error - if (value instanceof TrustedScriptURL) { - return; - } - - value = encodeUrl(value); - } else if (attr === "srcdoc") { - value = rewriteHtml(value); - } else if (/(image)?srcset/.test(attr)) { - value = rewriteSrcset(value); - } - - descriptor.set.call(this, value); - }, - }); - } -} - -Element.prototype.getAttribute = new Proxy(Element.prototype.getAttribute, { - apply(target, thisArg, argArray) { - if (attrs.includes(argArray[0]) && thisArg.dataset[argArray[0]]) { - return thisArg.dataset[argArray[0]]; - } - - return Reflect.apply(target, thisArg, argArray); - }, -}); - -Element.prototype.setAttribute = new Proxy(Element.prototype.setAttribute, { - apply(target, thisArg, argArray) { - if (attrs.includes(argArray[0])) { - thisArg.dataset[argArray[0]] = argArray[1]; - if (/nonce|integrity|csp/.test(argArray[0])) { - return; - } else if (/src|href|data|action|formaction/.test(argArray[0])) { - console.log(thisArg); - argArray[1] = encodeUrl(argArray[1]); - } else if (argArray[0] === "srcdoc") { - argArray[1] = rewriteHtml(argArray[1]); - } else if (/(image)?srcset/.test(argArray[0])) { - argArray[1] = rewriteSrcset(argArray[1]); - } else if (argArray[1] === "style") { - argArray[1] = rewriteCss(argArray[1]); - } - } - - return Reflect.apply(target, thisArg, argArray); - }, -}); - -const innerHTML = Object.getOwnPropertyDescriptor(Element.prototype, "innerHTML"); - -Object.defineProperty(Element.prototype, "innerHTML", { - set(value) { - // @ts-expect-error - if (this instanceof HTMLScriptElement && !(value instanceof TrustedScript)) { - value = rewriteJs(value); - } else if (this instanceof HTMLStyleElement) { - value = rewriteCss(value); - // @ts-expect-error - } else if (!(value instanceof TrustedHTML)) { - value = rewriteHtml(value); - } - - return innerHTML.set.call(this, value); - }, +import { encodeUrl, rewriteCss, rewriteHtml, rewriteJs, rewriteSrcset } from "../bundle"; + +const attrObject = { + "nonce": [HTMLElement], + "integrity": [HTMLScriptElement, HTMLLinkElement], + "csp": [HTMLIFrameElement], + "src": [HTMLImageElement, HTMLMediaElement, HTMLIFrameElement, HTMLEmbedElement, HTMLScriptElement], + "href": [HTMLAnchorElement, HTMLLinkElement], + "data": [HTMLObjectElement], + "action": [HTMLFormElement], + "formaction": [HTMLButtonElement, HTMLInputElement], + "srcdoc": [HTMLIFrameElement], + "srcset": [HTMLImageElement, HTMLSourceElement], + "imagesrcset": [HTMLLinkElement] +} + +const attrs = Object.keys(attrObject); + +for (const attr of attrs) { + for (const element of attrObject[attr]) { + const descriptor = Object.getOwnPropertyDescriptor(element.prototype, attr); + Object.defineProperty(element.prototype, attr, { + get() { + return this.dataset[attr]; + }, + + set(value) { + this.dataset[attr] = value; + if (/nonce|integrity|csp/.test(attr)) { + return; + } else if (/src|href|data|action|formaction/.test(attr)) { + // @ts-expect-error + if (value instanceof TrustedScriptURL) { + return; + } + + value = encodeUrl(value); + } else if (attr === "srcdoc") { + value = rewriteHtml(value); + } else if (/(image)?srcset/.test(attr)) { + value = rewriteSrcset(value); + } + + descriptor.set.call(this, value); + }, + }); + } +} + +Element.prototype.getAttribute = new Proxy(Element.prototype.getAttribute, { + apply(target, thisArg, argArray) { + if (attrs.includes(argArray[0]) && thisArg.dataset[argArray[0]]) { + return thisArg.dataset[argArray[0]]; + } + + return Reflect.apply(target, thisArg, argArray); + }, +}); + +Element.prototype.setAttribute = new Proxy(Element.prototype.setAttribute, { + apply(target, thisArg, argArray) { + if (attrs.includes(argArray[0])) { + thisArg.dataset[argArray[0]] = argArray[1]; + if (/nonce|integrity|csp/.test(argArray[0])) { + return; + } else if (/src|href|data|action|formaction/.test(argArray[0])) { + console.log(thisArg); + argArray[1] = encodeUrl(argArray[1]); + } else if (argArray[0] === "srcdoc") { + argArray[1] = rewriteHtml(argArray[1]); + } else if (/(image)?srcset/.test(argArray[0])) { + argArray[1] = rewriteSrcset(argArray[1]); + } else if (argArray[1] === "style") { + argArray[1] = rewriteCss(argArray[1]); + } + } + + return Reflect.apply(target, thisArg, argArray); + }, +}); + +const innerHTML = Object.getOwnPropertyDescriptor(Element.prototype, "innerHTML"); + +Object.defineProperty(Element.prototype, "innerHTML", { + set(value) { + // @ts-expect-error + if (this instanceof HTMLScriptElement && !(value instanceof TrustedScript)) { + value = rewriteJs(value); + } else if (this instanceof HTMLStyleElement) { + value = rewriteCss(value); + // @ts-expect-error + } else if (!(value instanceof TrustedHTML)) { + value = rewriteHtml(value); + } + + return innerHTML.set.call(this, value); + }, }) \ No newline at end of file diff --git a/src/client/history.ts b/src/client/history.ts new file mode 100644 index 0000000..d0b8aa7 --- /dev/null +++ b/src/client/history.ts @@ -0,0 +1 @@ +// forgot aobut this api diff --git a/src/client/index.ts b/src/client/index.ts index d0616d8..0ea155c 100644 --- a/src/client/index.ts +++ b/src/client/index.ts @@ -1,16 +1,16 @@ -import "./native/eval.ts"; -import "./location.ts"; -import "./trustedTypes.ts"; -import "./requests/fetch.ts"; -import "./requests/xmlhttprequest.ts"; -import "./requests/websocket.ts" -import "./element.ts"; -import "./storage.ts"; -import "./css.ts"; -import "./worker.ts"; - -declare global { - interface Window { - __location: Location; - } -} +import "./native/eval.ts"; +import "./location.ts"; +import "./trustedTypes.ts"; +import "./requests/fetch.ts"; +import "./requests/xmlhttprequest.ts"; +import "./requests/websocket.ts" +import "./element.ts"; +import "./storage.ts"; +import "./css.ts"; +import "./worker.ts"; + +declare global { + interface Window { + __location: Location; + } +} diff --git a/src/client/location.ts b/src/client/location.ts index 85554f6..a78561c 100644 --- a/src/client/location.ts +++ b/src/client/location.ts @@ -1,34 +1,34 @@ -// @ts-nocheck -import { encodeUrl, decodeUrl } from "../bundle"; - -function urlLocation() { - const loc = new URL(decodeUrl(location.href)); - loc.assign = (url: string) => location.assign(encodeUrl(url)); - loc.reload = () => location.reload(); - loc.replace = (url: string) => location.replace(encodeUrl(url)); - loc.toString = () => loc.href; - - return loc; -} - -export function LocationProxy() { - const loc = urlLocation(); - - return new Proxy(window.location, { - get(target, prop) { - return loc[prop]; - }, - - set(obj, prop, value) { - if (prop === "href") { - location.href = encodeUrl(value); - } else { - loc[prop] = value; - } - - return true; - } - }) -} - +// @ts-nocheck +import { encodeUrl, decodeUrl } from "../bundle"; + +function urlLocation() { + const loc = new URL(decodeUrl(location.href)); + loc.assign = (url: string) => location.assign(encodeUrl(url)); + loc.reload = () => location.reload(); + loc.replace = (url: string) => location.replace(encodeUrl(url)); + loc.toString = () => loc.href; + + return loc; +} + +export function LocationProxy() { + const loc = urlLocation(); + + return new Proxy(window.location, { + get(target, prop) { + return loc[prop]; + }, + + set(obj, prop, value) { + if (prop === "href") { + location.href = encodeUrl(value); + } else { + loc[prop] = value; + } + + return true; + } + }) +} + window.__location = LocationProxy(); \ No newline at end of file diff --git a/src/client/native/eval.ts b/src/client/native/eval.ts index 8f7f8d1..35a4783 100644 --- a/src/client/native/eval.ts +++ b/src/client/native/eval.ts @@ -1,28 +1,28 @@ -import { rewriteJs } from "../../bundle"; - -const FunctionProxy = new Proxy(Function, { - construct(target, argArray) { - if (argArray.length === 1) { - return Reflect.construct(target, rewriteJs(argArray[0])); - } else { - return Reflect.construct(target, rewriteJs(argArray[argArray.length - 1])) - } - }, - apply(target, thisArg, argArray) { - if (argArray.length === 1) { - return Reflect.apply(target, undefined, rewriteJs(argArray[0])); - } else { - return Reflect.apply(target, undefined, [...argArray.map((x, index) => index === argArray.length - 1), rewriteJs(argArray[argArray.length - 1])]) - } - }, -}); - -delete window.Function; - -window.Function = FunctionProxy; - -delete window.eval; - -// since the function proxy is already rewriting the js we can just reuse it for the eval proxy - +import { rewriteJs } from "../../bundle"; + +const FunctionProxy = new Proxy(Function, { + construct(target, argArray) { + if (argArray.length === 1) { + return Reflect.construct(target, rewriteJs(argArray[0])); + } else { + return Reflect.construct(target, rewriteJs(argArray[argArray.length - 1])) + } + }, + apply(target, thisArg, argArray) { + if (argArray.length === 1) { + return Reflect.apply(target, undefined, rewriteJs(argArray[0])); + } else { + return Reflect.apply(target, undefined, [...argArray.map((x, index) => index === argArray.length - 1), rewriteJs(argArray[argArray.length - 1])]) + } + }, +}); + +delete window.Function; + +window.Function = FunctionProxy; + +delete window.eval; + +// since the function proxy is already rewriting the js we can just reuse it for the eval proxy + window.eval = (str: string) => window.Function(str); \ No newline at end of file diff --git a/src/client/requests/fetch.ts b/src/client/requests/fetch.ts index 9dfa6a2..372e682 100644 --- a/src/client/requests/fetch.ts +++ b/src/client/requests/fetch.ts @@ -1,35 +1,35 @@ -// ts throws an error if you dont do window.fetch - -import { encodeUrl, rewriteHeaders } from "../../bundle"; - -window.fetch = new Proxy(window.fetch, { - apply(target, thisArg, argArray) { - argArray[0] = encodeUrl(argArray[0]); - - return Reflect.apply(target, thisArg, argArray); - }, -}); - -Headers = new Proxy(Headers, { - construct(target, argArray, newTarget) { - argArray[0] = rewriteHeaders(argArray[0]); - - return Reflect.construct(target, argArray, newTarget); - }, -}) - -Request = new Proxy(Request, { - construct(target, argArray, newTarget) { - if (typeof argArray[0] === "string") argArray[0] = encodeUrl(argArray[0]); - - return Reflect.construct(target, argArray, newTarget); - }, -}); - -Response.redirect = new Proxy(Response.redirect, { - apply(target, thisArg, argArray) { - argArray[0] = encodeUrl(argArray[0]); - - return Reflect.apply(target, thisArg, argArray); - }, +// ts throws an error if you dont do window.fetch + +import { encodeUrl, rewriteHeaders } from "../../bundle"; + +window.fetch = new Proxy(window.fetch, { + apply(target, thisArg, argArray) { + argArray[0] = encodeUrl(argArray[0]); + + return Reflect.apply(target, thisArg, argArray); + }, +}); + +Headers = new Proxy(Headers, { + construct(target, argArray, newTarget) { + argArray[0] = rewriteHeaders(argArray[0]); + + return Reflect.construct(target, argArray, newTarget); + }, +}) + +Request = new Proxy(Request, { + construct(target, argArray, newTarget) { + if (typeof argArray[0] === "string") argArray[0] = encodeUrl(argArray[0]); + + return Reflect.construct(target, argArray, newTarget); + }, +}); + +Response.redirect = new Proxy(Response.redirect, { + apply(target, thisArg, argArray) { + argArray[0] = encodeUrl(argArray[0]); + + return Reflect.apply(target, thisArg, argArray); + }, }); \ No newline at end of file diff --git a/src/client/requests/websocket.ts b/src/client/requests/websocket.ts index ef0453a..5a034b7 100644 --- a/src/client/requests/websocket.ts +++ b/src/client/requests/websocket.ts @@ -1,17 +1,16 @@ -import { BareClient } from "@mercuryworkshop/bare-mux" -const client = new BareClient() -const RealWebSocket = WebSocket -WebSocket = new Proxy(WebSocket, { - construct(_target, args) { - return client.createWebSocket( - args[0], - args[1], - RealWebSocket, - { - "User-Agent": navigator.userAgent - }, - // @ts-expect-error - ArrayBuffer.prototype - ) - } +import { BareClient } from "@mercuryworkshop/bare-mux" +const client = new BareClient() +const RealWebSocket = WebSocket +WebSocket = new Proxy(WebSocket, { + construct(_target, args) { + return client.createWebSocket( + args[0], + args[1], + RealWebSocket, + { + "User-Agent": navigator.userAgent + }, + ArrayBuffer.prototype + ) + } }) \ No newline at end of file diff --git a/src/client/requests/xmlhttprequest.ts b/src/client/requests/xmlhttprequest.ts index dc6ac0e..463623b 100644 --- a/src/client/requests/xmlhttprequest.ts +++ b/src/client/requests/xmlhttprequest.ts @@ -1,20 +1,20 @@ -import { encodeUrl, rewriteHeaders } from "../../bundle"; - -XMLHttpRequest.prototype.open = new Proxy(XMLHttpRequest.prototype.open, { - apply(target, thisArg, argArray) { - if (argArray[1]) argArray[1] = encodeUrl(argArray[1]); - - return Reflect.apply(target, thisArg, argArray); - }, -}); - -XMLHttpRequest.prototype.setRequestHeader = new Proxy(XMLHttpRequest.prototype.setRequestHeader, { - apply(target, thisArg, argArray) { - let headerObject = Object.fromEntries([argArray]); - headerObject = rewriteHeaders(headerObject); - - argArray = Object.entries(headerObject)[0]; - - return Reflect.apply(target, thisArg, argArray); - }, -}); +import { encodeUrl, rewriteHeaders } from "../../bundle"; + +XMLHttpRequest.prototype.open = new Proxy(XMLHttpRequest.prototype.open, { + apply(target, thisArg, argArray) { + if (argArray[1]) argArray[1] = encodeUrl(argArray[1]); + + return Reflect.apply(target, thisArg, argArray); + }, +}); + +XMLHttpRequest.prototype.setRequestHeader = new Proxy(XMLHttpRequest.prototype.setRequestHeader, { + apply(target, thisArg, argArray) { + let headerObject = Object.fromEntries([argArray]); + headerObject = rewriteHeaders(headerObject); + + argArray = Object.entries(headerObject)[0]; + + return Reflect.apply(target, thisArg, argArray); + }, +}); diff --git a/src/client/storage.ts b/src/client/storage.ts index e618b9b..28142fd 100644 --- a/src/client/storage.ts +++ b/src/client/storage.ts @@ -1,68 +1,69 @@ -import IDBMapSync from "@webreflection/idb-map/sync"; -const store = new IDBMapSync(window.__location.host, { - prefix: "Storage", - durability: "relaxed" -}); - -await store.sync(); - -function storageProxy(scope: Storage): Storage { - - return new Proxy(scope, { - get(target, prop) { - switch (prop) { - case "getItem": - return (key: string) => { - return store.get(key); - } - - case "setItem": - return (key: string, value: string) => { - store.set(key, value); - store.sync(); - } - - case "removeItem": - return (key: string) => { - store.delete(key); - store.sync(); - } - - case "clear": - return () => { - store.clear(); - store.sync(); - } - - case "key": - return (index: number) => { - store.keys()[index]; - } - case "length": - return store.size; - default: - return store.get(prop); - } - }, - - set(target, prop, value) { - store.set(prop, value); - store.sync(); - }, - - defineProperty(target, property, attributes) { - store.set(property as string, attributes.value); - - return true; - }, - }) -} - -const localStorageProxy = storageProxy(window.localStorage); -const sessionStorageProxy = storageProxy(window.sessionStorage); - -delete window.localStorage; -delete window.sessionStorage; - -window.localStorage = localStorageProxy; -window.sessionStorage = sessionStorageProxy; +import IDBMapSync from "@webreflection/idb-map/sync"; +const store = new IDBMapSync(window.__location.host, { + prefix: "Storage", + durability: "relaxed" +}); + +await store.sync(); + +function storageProxy(scope: Storage): Storage { + + return new Proxy(scope, { + get(target, prop) { + switch (prop) { + case "getItem": + return (key: string) => { + return store.get(key); + } + + case "setItem": + return (key: string, value: string) => { + store.set(key, value); + store.sync(); + } + + case "removeItem": + return (key: string) => { + store.delete(key); + store.sync(); + } + + case "clear": + return () => { + store.clear(); + store.sync(); + } + + case "key": + return (index: number) => { + store.keys()[index]; + } + case "length": + return store.size; + default: + return store.get(prop); + } + }, + + //@ts-ignore + set(target, prop, value) { + store.set(prop, value); + store.sync(); + }, + + defineProperty(target, property, attributes) { + store.set(property as string, attributes.value); + + return true; + }, + }) +} + +const localStorageProxy = storageProxy(window.localStorage); +const sessionStorageProxy = storageProxy(window.sessionStorage); + +delete window.localStorage; +delete window.sessionStorage; + +window.localStorage = localStorageProxy; +window.sessionStorage = sessionStorageProxy; diff --git a/src/client/trustedTypes.ts b/src/client/trustedTypes.ts index 339eb3c..09f45dc 100644 --- a/src/client/trustedTypes.ts +++ b/src/client/trustedTypes.ts @@ -1,32 +1,32 @@ -import { rewriteHtml, rewriteJs, encodeUrl } from "../bundle"; - -// @ts-expect-error -trustedTypes.createPolicy = new Proxy(trustedTypes.createPolicy, { - apply(target, thisArg, argArray) { - if (argArray[1].createHTML) { - argArray[1].createHTML = new Proxy(argArray[1].createHTML, { - apply(target1, thisArg1, argArray1) { - return rewriteHtml(target1(...argArray1)); - }, - }); - } - - if (argArray[1].createScript) { - argArray[1].createScript = new Proxy(argArray[1].createScript, { - apply(target1, thisArg1, argArray1) { - return rewriteJs(target1(...argArray1)); - }, - }); - } - - if (argArray[1].createScriptURL) { - argArray[1].createScriptURL = new Proxy(argArray[1].createScriptURL, { - apply(target1, thisArg1, argArray1) { - return encodeUrl(target1(...argArray1)); - }, - }) - } - - return Reflect.apply(target, thisArg, argArray); - }, +import { rewriteHtml, rewriteJs, encodeUrl } from "../bundle"; + +// @ts-expect-error +trustedTypes.createPolicy = new Proxy(trustedTypes.createPolicy, { + apply(target, thisArg, argArray) { + if (argArray[1].createHTML) { + argArray[1].createHTML = new Proxy(argArray[1].createHTML, { + apply(target1, thisArg1, argArray1) { + return rewriteHtml(target1(...argArray1)); + }, + }); + } + + if (argArray[1].createScript) { + argArray[1].createScript = new Proxy(argArray[1].createScript, { + apply(target1, thisArg1, argArray1) { + return rewriteJs(target1(...argArray1)); + }, + }); + } + + if (argArray[1].createScriptURL) { + argArray[1].createScriptURL = new Proxy(argArray[1].createScriptURL, { + apply(target1, thisArg1, argArray1) { + return encodeUrl(target1(...argArray1)); + }, + }) + } + + return Reflect.apply(target, thisArg, argArray); + }, }) \ No newline at end of file diff --git a/src/client/window.ts b/src/client/window.ts new file mode 100644 index 0000000..288d600 --- /dev/null +++ b/src/client/window.ts @@ -0,0 +1 @@ +// the DAMN WINDOW PROXY \ No newline at end of file diff --git a/src/client/worker.ts b/src/client/worker.ts index a4506e6..0d16c7b 100644 --- a/src/client/worker.ts +++ b/src/client/worker.ts @@ -1,7 +1,7 @@ -import { encodeUrl } from "../bundle"; -const RealWorker = Worker -Worker = new Proxy(Worker, { - construct(_target, args) { - return new RealWorker(encodeUrl(args[0]), args[1]) - } +import { encodeUrl } from "../bundle"; +const RealWorker = Worker +Worker = new Proxy(Worker, { + construct(_target, args) { + return new RealWorker(encodeUrl(args[0]), args[1]) + } }) \ No newline at end of file diff --git a/src/codecs/aes.ts b/src/codecs/aes.ts index 016a9f3..98767d4 100644 --- a/src/codecs/aes.ts +++ b/src/codecs/aes.ts @@ -1,805 +1,805 @@ -/* eslint-disable */ - -var Nr = 14; -var Nk = 8; -var Decrypt = false; -function enc_utf8(s) { - try { - return unescape(encodeURIComponent(s)); - } catch (e) { - throw "Error on UTF-8 encode"; - } -}; -function dec_utf8(s) { - try { - return decodeURIComponent(escape(s)); - } catch (e) { - throw "Bad Key"; - } -}; -function padBlock(byteArr) { - var array = [], - cpad, - i; - if (byteArr.length < 16) { - cpad = 16 - byteArr.length; - array = [ - cpad, - cpad, - cpad, - cpad, - cpad, - cpad, - cpad, - cpad, - cpad, - cpad, - cpad, - cpad, - cpad, - cpad, - cpad, - cpad, - ]; - } - for (i = 0; i < byteArr.length; i++) { - array[i] = byteArr[i]; - } - return array; -}; -function block2s(block, lastBlock) { - var string = "", - padding, - i; - if (lastBlock) { - padding = block[15]; - if (padding > 16) { - throw "Decryption error: Maybe bad key"; - } - if (padding === 16) { - return ""; - } - for (i = 0; i < 16 - padding; i++) { - string += String.fromCharCode(block[i]); - } - } else { - for (i = 0; i < 16; i++) { - string += String.fromCharCode(block[i]); - } - } - return string; -}; -function a2h(numArr) { - var string = "", - i; - for (i = 0; i < numArr.length; i++) { - string += (numArr[i] < 16 ? "0" : "") + numArr[i].toString(16); - } - return string; -}; -function h2a(s) { - var ret = []; - s.replace(/(..)/g, function (s) { - ret.push(parseInt(s, 16)); - }); - return ret; -}; -function s2a(string, binary) { - var array = [], - i; - - if (!binary) { - string = enc_utf8(string); - } - - for (i = 0; i < string.length; i++) { - array[i] = string.charCodeAt(i); - } - - return array; -}; -function size(newsize) { - switch (newsize) { - case 128: - Nr = 10; - Nk = 4; - break; - case 192: - Nr = 12; - Nk = 6; - break; - case 256: - Nr = 14; - Nk = 8; - break; - default: - throw "Invalid Key Size Specified:" + newsize; - } -}; -function randArr(num) { - var result = [], - i; - for (i = 0; i < num; i++) { - result = result.concat(Math.floor(Math.random() * 256)); - } - return result; -}; -function openSSLKey(passwordArr, saltArr) { - var rounds = Nr >= 12 ? 3 : 2, - key = [], - iv = [], - md5_hash = [], - result = [], - data00 = passwordArr.concat(saltArr), - i; - md5_hash[0] = MD5(data00); - result = md5_hash[0]; - for (i = 1; i < rounds; i++) { - md5_hash[i] = MD5(md5_hash[i - 1].concat(data00)); - result = result.concat(md5_hash[i]); - } - key = result.slice(0, 4 * Nk); - iv = result.slice(4 * Nk, 4 * Nk + 16); - return { - key: key, - iv: iv, - }; -}; -function rawEncrypt(plaintext, key, iv) { - key = expandKey(key); - var numBlocks = Math.ceil(plaintext.length / 16), - blocks = [], - i, - cipherBlocks = []; - for (i = 0; i < numBlocks; i++) { - blocks[i] = padBlock(plaintext.slice(i * 16, i * 16 + 16)); - } - if (plaintext.length % 16 === 0) { - blocks.push([ - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - ]); - numBlocks++; - } - for (i = 0; i < blocks.length; i++) { - blocks[i] = - i === 0 - ? xorBlocks(blocks[i], iv) - : xorBlocks(blocks[i], cipherBlocks[i - 1]); - cipherBlocks[i] = encryptBlock(blocks[i], key); - } - return cipherBlocks; -}; -function rawDecrypt(cryptArr, key, iv, binary) { - key = expandKey(key); - var numBlocks = cryptArr.length / 16, - cipherBlocks = [], - i, - plainBlocks = [], - string = ""; - for (i = 0; i < numBlocks; i++) { - cipherBlocks.push(cryptArr.slice(i * 16, (i + 1) * 16)); - } - for (i = cipherBlocks.length - 1; i >= 0; i--) { - plainBlocks[i] = decryptBlock(cipherBlocks[i], key); - plainBlocks[i] = - i === 0 - ? xorBlocks(plainBlocks[i], iv) - : xorBlocks(plainBlocks[i], cipherBlocks[i - 1]); - } - for (i = 0; i < numBlocks - 1; i++) { - string += block2s(plainBlocks[i], false); - } - string += block2s(plainBlocks[i], true); - return binary ? string : dec_utf8(string); -}; -function encryptBlock(block, words) { - Decrypt = false; - var state = addRoundKey(block, words, 0), - round; - for (round = 1; round < Nr + 1; round++) { - state = subBytes(state); - state = shiftRows(state); - if (round < Nr) { - state = mixColumns(state); - } - state = addRoundKey(state, words, round); - } - - return state; -}; -function decryptBlock(block, words) { - Decrypt = true; - var state = addRoundKey(block, words, Nr), - round; - for (round = Nr - 1; round > -1; round--) { - state = shiftRows(state); - state = subBytes(state); - state = addRoundKey(state, words, round); - if (round > 0) { - state = mixColumns(state); - } - } - - return state; -}; -function subBytes(state) { - var S = Decrypt ? SBoxInv : SBox, - temp = [], - i; - for (i = 0; i < 16; i++) { - temp[i] = S[state[i]]; - } - return temp; -}; -function shiftRows(state) { - var temp = [], - shiftBy = Decrypt - ? [0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3] - : [0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11], - i; - for (i = 0; i < 16; i++) { - temp[i] = state[shiftBy[i]]; - } - return temp; -}; -function mixColumns(state) { - var t = [], - c; - if (!Decrypt) { - for (c = 0; c < 4; c++) { - t[c * 4] = - G2X[state[c * 4]] ^ - G3X[state[1 + c * 4]] ^ - state[2 + c * 4] ^ - state[3 + c * 4]; - t[1 + c * 4] = - state[c * 4] ^ - G2X[state[1 + c * 4]] ^ - G3X[state[2 + c * 4]] ^ - state[3 + c * 4]; - t[2 + c * 4] = - state[c * 4] ^ - state[1 + c * 4] ^ - G2X[state[2 + c * 4]] ^ - G3X[state[3 + c * 4]]; - t[3 + c * 4] = - G3X[state[c * 4]] ^ - state[1 + c * 4] ^ - state[2 + c * 4] ^ - G2X[state[3 + c * 4]]; - } - } else { - for (c = 0; c < 4; c++) { - t[c * 4] = - GEX[state[c * 4]] ^ - GBX[state[1 + c * 4]] ^ - GDX[state[2 + c * 4]] ^ - G9X[state[3 + c * 4]]; - t[1 + c * 4] = - G9X[state[c * 4]] ^ - GEX[state[1 + c * 4]] ^ - GBX[state[2 + c * 4]] ^ - GDX[state[3 + c * 4]]; - t[2 + c * 4] = - GDX[state[c * 4]] ^ - G9X[state[1 + c * 4]] ^ - GEX[state[2 + c * 4]] ^ - GBX[state[3 + c * 4]]; - t[3 + c * 4] = - GBX[state[c * 4]] ^ - GDX[state[1 + c * 4]] ^ - G9X[state[2 + c * 4]] ^ - GEX[state[3 + c * 4]]; - } - } - - return t; -}; -function addRoundKey(state, words, round) { - var temp = [], - i; - for (i = 0; i < 16; i++) { - temp[i] = state[i] ^ words[round][i]; - } - return temp; -}; -function xorBlocks(block1, block2) { - var temp = [], - i; - for (i = 0; i < 16; i++) { - temp[i] = block1[i] ^ block2[i]; - } - return temp; -}; -function expandKey(key) { - var w = [], - temp = [], - i, - r, - t, - flat = [], - j; - - for (i = 0; i < Nk; i++) { - r = [key[4 * i], key[4 * i + 1], key[4 * i + 2], key[4 * i + 3]]; - w[i] = r; - } - - for (i = Nk; i < 4 * (Nr + 1); i++) { - w[i] = []; - for (t = 0; t < 4; t++) { - temp[t] = w[i - 1][t]; - } - if (i % Nk === 0) { - temp = subWord(rotWord(temp)); - temp[0] ^= Rcon[i / Nk - 1]; - } else if (Nk > 6 && i % Nk === 4) { - temp = subWord(temp); - } - for (t = 0; t < 4; t++) { - w[i][t] = w[i - Nk][t] ^ temp[t]; - } - } - for (i = 0; i < Nr + 1; i++) { - flat[i] = []; - for (j = 0; j < 4; j++) { - flat[i].push( - w[i * 4 + j][0], - w[i * 4 + j][1], - w[i * 4 + j][2], - w[i * 4 + j][3] - ); - } - } - return flat; -}; -function subWord(w) { - for (var i = 0; i < 4; i++) { - w[i] = SBox[w[i]]; - } - return w; -}; -function rotWord(w) { - var tmp = w[0], - i; - for (i = 0; i < 3; i++) { - w[i] = w[i + 1]; - } - w[3] = tmp; - return w; -}; -function strhex(str, size) { - var i, - ret = []; - for (i = 0; i < str.length; i += size) { - ret[i / size] = parseInt(str.substr(i, size), 16); - } - return ret; -}; -function invertArr(arr) { - var i, - ret = []; - for (i = 0; i < arr.length; i++) { - ret[arr[i]] = i; - } - return ret; -}; -function Gxx(a, b) { - var i, ret; - - ret = 0; - for (i = 0; i < 8; i++) { - ret = (b & 1) === 1 ? ret ^ a : ret; - a = a > 0x7f ? 0x11b ^ (a << 1) : a << 1; - b >>>= 1; - } - - return ret; -}; -function Gx(x) { - var i, - r = []; - for (i = 0; i < 256; i++) { - r[i] = Gxx(x, i); - } - return r; -}; -var SBox = strhex( - "637c777bf26b6fc53001672bfed7ab76ca82c97dfa5947f0add4a2af9ca472c0b7fd9326363ff7cc34a5e5f171d8311504c723c31896059a071280e2eb27b27509832c1a1b6e5aa0523bd6b329e32f8453d100ed20fcb15b6acbbe394a4c58cfd0efaafb434d338545f9027f503c9fa851a3408f929d38f5bcb6da2110fff3d2cd0c13ec5f974417c4a77e3d645d197360814fdc222a908846eeb814de5e0bdbe0323a0a4906245cc2d3ac629195e479e7c8376d8dd54ea96c56f4ea657aae08ba78252e1ca6b4c6e8dd741f4bbd8b8a703eb5664803f60e613557b986c11d9ee1f8981169d98e949b1e87e9ce5528df8ca1890dbfe6426841992d0fb054bb16", - 2 -); -var SBoxInv = invertArr(SBox); -var Rcon = strhex( - "01020408102040801b366cd8ab4d9a2f5ebc63c697356ad4b37dfaefc591", - 2 -); -var G2X = Gx(2); -var G3X = Gx(3); -var G9X = Gx(9); -var GBX = Gx(0xb); -var GDX = Gx(0xd); -var GEX = Gx(0xe); -function enc(string, pass, binary) { - var salt = randArr(8), - pbe = openSSLKey(s2a(pass, binary), salt), - key = pbe.key, - iv = pbe.iv, - cipherBlocks, - saltBlock = [[83, 97, 108, 116, 101, 100, 95, 95].concat(salt)]; - string = s2a(string, binary); - cipherBlocks = rawEncrypt(string, key, iv); - - cipherBlocks = saltBlock.concat(cipherBlocks); - return Base64.encode(cipherBlocks); -}; -function dec(string, pass, binary) { - var cryptArr = Base64.decode(string), - salt = cryptArr.slice(8, 16), - pbe = openSSLKey(s2a(pass, binary), salt), - key = pbe.key, - iv = pbe.iv; - cryptArr = cryptArr.slice(16, cryptArr.length); - - string = rawDecrypt(cryptArr, key, iv, binary); - return string; -}; -function MD5(numArr) { - function rotateLeft(lValue, iShiftBits) { - return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits)); - } - - function addUnsigned(lX, lY) { - var lX4, lY4, lX8, lY8, lResult; - lX8 = lX & 0x80000000; - lY8 = lY & 0x80000000; - lX4 = lX & 0x40000000; - lY4 = lY & 0x40000000; - lResult = (lX & 0x3fffffff) + (lY & 0x3fffffff); - if (lX4 & lY4) { - return lResult ^ 0x80000000 ^ lX8 ^ lY8; - } - if (lX4 | lY4) { - if (lResult & 0x40000000) { - return lResult ^ 0xc0000000 ^ lX8 ^ lY8; - } else { - return lResult ^ 0x40000000 ^ lX8 ^ lY8; - } - } else { - return lResult ^ lX8 ^ lY8; - } - } - - function f(x, y, z) { - return (x & y) | (~x & z); - } - function g(x, y, z) { - return (x & z) | (y & ~z); - } - function h(x, y, z) { - return x ^ y ^ z; - } - function funcI(x, y, z) { - return y ^ (x | ~z); - } - - function ff(a, b, c, d, x, s, ac) { - a = addUnsigned(a, addUnsigned(addUnsigned(f(b, c, d), x), ac)); - return addUnsigned(rotateLeft(a, s), b); - } - - function gg(a, b, c, d, x, s, ac) { - a = addUnsigned(a, addUnsigned(addUnsigned(g(b, c, d), x), ac)); - return addUnsigned(rotateLeft(a, s), b); - } - - function hh(a, b, c, d, x, s, ac) { - a = addUnsigned(a, addUnsigned(addUnsigned(h(b, c, d), x), ac)); - return addUnsigned(rotateLeft(a, s), b); - } - - function ii(a, b, c, d, x, s, ac) { - a = addUnsigned(a, addUnsigned(addUnsigned(funcI(b, c, d), x), ac)); - return addUnsigned(rotateLeft(a, s), b); - } - - function convertToWordArray(numArr) { - var lWordCount, - lMessageLength = numArr.length, - lNumberOfWords_temp1 = lMessageLength + 8, - lNumberOfWords_temp2 = - (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64, - lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16, - lWordArray = [], - lBytePosition = 0, - lByteCount = 0; - while (lByteCount < lMessageLength) { - lWordCount = (lByteCount - (lByteCount % 4)) / 4; - lBytePosition = (lByteCount % 4) * 8; - lWordArray[lWordCount] = - lWordArray[lWordCount] | (numArr[lByteCount] << lBytePosition); - lByteCount++; - } - lWordCount = (lByteCount - (lByteCount % 4)) / 4; - lBytePosition = (lByteCount % 4) * 8; - lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition); - lWordArray[lNumberOfWords - 2] = lMessageLength << 3; - lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29; - return lWordArray; - } - - function wordToHex(lValue) { - var lByte, - lCount, - wordToHexArr = []; - for (lCount = 0; lCount <= 3; lCount++) { - lByte = (lValue >>> (lCount * 8)) & 255; - wordToHexArr = wordToHexArr.concat(lByte); - } - return wordToHexArr; - } - - var x = [], - k, - AA, - BB, - CC, - DD, - a, - b, - c, - d, - rnd = strhex( - "67452301efcdab8998badcfe10325476d76aa478e8c7b756242070dbc1bdceeef57c0faf4787c62aa8304613fd469501698098d88b44f7afffff5bb1895cd7be6b901122fd987193a679438e49b40821f61e2562c040b340265e5a51e9b6c7aad62f105d02441453d8a1e681e7d3fbc821e1cde6c33707d6f4d50d87455a14eda9e3e905fcefa3f8676f02d98d2a4c8afffa39428771f6816d9d6122fde5380ca4beea444bdecfa9f6bb4b60bebfbc70289b7ec6eaa127fad4ef308504881d05d9d4d039e6db99e51fa27cf8c4ac5665f4292244432aff97ab9423a7fc93a039655b59c38f0ccc92ffeff47d85845dd16fa87e4ffe2ce6e0a30143144e0811a1f7537e82bd3af2352ad7d2bbeb86d391", - 8 - ); - - x = convertToWordArray(numArr); - - a = rnd[0]; - b = rnd[1]; - c = rnd[2]; - d = rnd[3]; - - for (k = 0; k < x.length; k += 16) { - AA = a; - BB = b; - CC = c; - DD = d; - a = ff(a, b, c, d, x[k + 0], 7, rnd[4]); - d = ff(d, a, b, c, x[k + 1], 12, rnd[5]); - c = ff(c, d, a, b, x[k + 2], 17, rnd[6]); - b = ff(b, c, d, a, x[k + 3], 22, rnd[7]); - a = ff(a, b, c, d, x[k + 4], 7, rnd[8]); - d = ff(d, a, b, c, x[k + 5], 12, rnd[9]); - c = ff(c, d, a, b, x[k + 6], 17, rnd[10]); - b = ff(b, c, d, a, x[k + 7], 22, rnd[11]); - a = ff(a, b, c, d, x[k + 8], 7, rnd[12]); - d = ff(d, a, b, c, x[k + 9], 12, rnd[13]); - c = ff(c, d, a, b, x[k + 10], 17, rnd[14]); - b = ff(b, c, d, a, x[k + 11], 22, rnd[15]); - a = ff(a, b, c, d, x[k + 12], 7, rnd[16]); - d = ff(d, a, b, c, x[k + 13], 12, rnd[17]); - c = ff(c, d, a, b, x[k + 14], 17, rnd[18]); - b = ff(b, c, d, a, x[k + 15], 22, rnd[19]); - a = gg(a, b, c, d, x[k + 1], 5, rnd[20]); - d = gg(d, a, b, c, x[k + 6], 9, rnd[21]); - c = gg(c, d, a, b, x[k + 11], 14, rnd[22]); - b = gg(b, c, d, a, x[k + 0], 20, rnd[23]); - a = gg(a, b, c, d, x[k + 5], 5, rnd[24]); - d = gg(d, a, b, c, x[k + 10], 9, rnd[25]); - c = gg(c, d, a, b, x[k + 15], 14, rnd[26]); - b = gg(b, c, d, a, x[k + 4], 20, rnd[27]); - a = gg(a, b, c, d, x[k + 9], 5, rnd[28]); - d = gg(d, a, b, c, x[k + 14], 9, rnd[29]); - c = gg(c, d, a, b, x[k + 3], 14, rnd[30]); - b = gg(b, c, d, a, x[k + 8], 20, rnd[31]); - a = gg(a, b, c, d, x[k + 13], 5, rnd[32]); - d = gg(d, a, b, c, x[k + 2], 9, rnd[33]); - c = gg(c, d, a, b, x[k + 7], 14, rnd[34]); - b = gg(b, c, d, a, x[k + 12], 20, rnd[35]); - a = hh(a, b, c, d, x[k + 5], 4, rnd[36]); - d = hh(d, a, b, c, x[k + 8], 11, rnd[37]); - c = hh(c, d, a, b, x[k + 11], 16, rnd[38]); - b = hh(b, c, d, a, x[k + 14], 23, rnd[39]); - a = hh(a, b, c, d, x[k + 1], 4, rnd[40]); - d = hh(d, a, b, c, x[k + 4], 11, rnd[41]); - c = hh(c, d, a, b, x[k + 7], 16, rnd[42]); - b = hh(b, c, d, a, x[k + 10], 23, rnd[43]); - a = hh(a, b, c, d, x[k + 13], 4, rnd[44]); - d = hh(d, a, b, c, x[k + 0], 11, rnd[45]); - c = hh(c, d, a, b, x[k + 3], 16, rnd[46]); - b = hh(b, c, d, a, x[k + 6], 23, rnd[47]); - a = hh(a, b, c, d, x[k + 9], 4, rnd[48]); - d = hh(d, a, b, c, x[k + 12], 11, rnd[49]); - c = hh(c, d, a, b, x[k + 15], 16, rnd[50]); - b = hh(b, c, d, a, x[k + 2], 23, rnd[51]); - a = ii(a, b, c, d, x[k + 0], 6, rnd[52]); - d = ii(d, a, b, c, x[k + 7], 10, rnd[53]); - c = ii(c, d, a, b, x[k + 14], 15, rnd[54]); - b = ii(b, c, d, a, x[k + 5], 21, rnd[55]); - a = ii(a, b, c, d, x[k + 12], 6, rnd[56]); - d = ii(d, a, b, c, x[k + 3], 10, rnd[57]); - c = ii(c, d, a, b, x[k + 10], 15, rnd[58]); - b = ii(b, c, d, a, x[k + 1], 21, rnd[59]); - a = ii(a, b, c, d, x[k + 8], 6, rnd[60]); - d = ii(d, a, b, c, x[k + 15], 10, rnd[61]); - c = ii(c, d, a, b, x[k + 6], 15, rnd[62]); - b = ii(b, c, d, a, x[k + 13], 21, rnd[63]); - a = ii(a, b, c, d, x[k + 4], 6, rnd[64]); - d = ii(d, a, b, c, x[k + 11], 10, rnd[65]); - c = ii(c, d, a, b, x[k + 2], 15, rnd[66]); - b = ii(b, c, d, a, x[k + 9], 21, rnd[67]); - a = addUnsigned(a, AA); - b = addUnsigned(b, BB); - c = addUnsigned(c, CC); - d = addUnsigned(d, DD); - } - - return wordToHex(a).concat(wordToHex(b), wordToHex(c), wordToHex(d)); -}; -// function encString (plaintext, key, iv) { -// var i; -// plaintext = s2a(plaintext, false); - -// key = s2a(key, false); -// for (i = key.length; i < 32; i++) { -// key[i] = 0; -// } - -// if (iv === undefined) { -// } else { -// iv = s2a(iv, false); -// for (i = iv.length; i < 16; i++) { -// iv[i] = 0; -// } -// } - -// var ct = rawEncrypt(plaintext, key, iv); -// var ret = [iv]; -// for (i = 0; i < ct.length; i++) { -// ret[ret.length] = ct[i]; -// } -// return Base64.encode(ret); -// }; -// function decString (ciphertext, key) { -// // var tmp = Base64.decode(ciphertext); -// var tmp = atob(ciphertext); -// var iv = tmp.slice(0, 16); -// var ct = tmp.slice(16, tmp.length); -// var i; - -// key = s2a(key, false); -// for (i = key.length; i < 32; i++) { -// key[i] = 0; -// } - -// var pt = rawDecrypt(ct, key, iv, false); -// return pt; -// }; -// function Base64() { -// var _chars = -// "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", -// chars = _chars.split(""), -// encode = function (b, withBreaks) { -// var flatArr = [], -// b64 = "", -// i, -// broken_b64, -// totalChunks = Math.floor((b.length * 16) / 3); -// for (i = 0; i < b.length * 16; i++) { -// flatArr.push(b[Math.floor(i / 16)][i % 16]); -// } -// for (i = 0; i < flatArr.length; i = i + 3) { -// b64 += chars[flatArr[i] >> 2]; -// b64 += chars[((flatArr[i] & 3) << 4) | (flatArr[i + 1] >> 4)]; -// if (flatArr[i + 1] !== undefined) { -// b64 += chars[((flatArr[i + 1] & 15) << 2) | (flatArr[i + 2] >> 6)]; -// } else { -// b64 += "="; -// } -// if (flatArr[i + 2] !== undefined) { -// b64 += chars[flatArr[i + 2] & 63]; -// } else { -// b64 += "="; -// } -// } -// broken_b64 = b64.slice(0, 64) + "\n"; -// for (i = 1; i < Math.ceil(b64.length / 64); i++) { -// broken_b64 += -// b64.slice(i * 64, i * 64 + 64) + -// (Math.ceil(b64.length / 64) === i + 1 ? "" : "\n"); -// } -// return broken_b64; -// }, -// decode = function (string) { -// string = string.replace(/\n/g, ""); -// var flatArr = [], -// c = [], -// b = [], -// i; -// for (i = 0; i < string.length; i = i + 4) { -// c[0] = _chars.indexOf(string.charAt(i)); -// c[1] = _chars.indexOf(string.charAt(i + 1)); -// c[2] = _chars.indexOf(string.charAt(i + 2)); -// c[3] = _chars.indexOf(string.charAt(i + 3)); - -// b[0] = (c[0] << 2) | (c[1] >> 4); -// b[1] = ((c[1] & 15) << 4) | (c[2] >> 2); -// b[2] = ((c[2] & 3) << 6) | c[3]; -// flatArr.push(b[0], b[1], b[2]); -// } -// flatArr = flatArr.slice(0, flatArr.length - (flatArr.length % 16)); -// return flatArr; -// }; - -// if (typeof Array.indexOf === "function") { -// _chars = chars; -// } - -// return { -// encode: encode, -// decode: decode, -// }; -// } - -const Base64 = { - encode: function (b) { - var _chars = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", - chars = _chars.split(""), - flatArr = [], - b64 = "", - i, - broken_b64, - totalChunks = Math.floor((b.length * 16) / 3); - for (i = 0; i < b.length * 16; i++) { - flatArr.push(b[Math.floor(i / 16)][i % 16]); - } - for (i = 0; i < flatArr.length; i = i + 3) { - b64 += chars[flatArr[i] >> 2]; - b64 += chars[((flatArr[i] & 3) << 4) | (flatArr[i + 1] >> 4)]; - if (flatArr[i + 1] !== undefined) { - b64 += chars[((flatArr[i + 1] & 15) << 2) | (flatArr[i + 2] >> 6)]; - } else { - b64 += "="; - } - if (flatArr[i + 2] !== undefined) { - b64 += chars[flatArr[i + 2] & 63]; - } else { - b64 += "="; - } - } - broken_b64 = b64.slice(0, 64) + "\n"; - for (i = 1; i < Math.ceil(b64.length / 64); i++) { - broken_b64 += - b64.slice(i * 64, i * 64 + 64) + - (Math.ceil(b64.length / 64) === i + 1 ? "" : "\n"); - } - return broken_b64; - }, - decode: function (string) { - string = string.replace(/\n/g, ""); - var _chars = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", - chars = _chars.split(""), - flatArr = [], - c = [], - b = [], - i; - for (i = 0; i < string.length; i = i + 4) { - c[0] = _chars.indexOf(string.charAt(i)); - c[1] = _chars.indexOf(string.charAt(i + 1)); - c[2] = _chars.indexOf(string.charAt(i + 2)); - c[3] = _chars.indexOf(string.charAt(i + 3)); - - b[0] = (c[0] << 2) | (c[1] >> 4); - b[1] = ((c[1] & 15) << 4) | (c[2] >> 2); - b[2] = ((c[2] & 3) << 6) | c[3]; - flatArr.push(b[0], b[1], b[2]); - } - flatArr = flatArr.slice(0, flatArr.length - (flatArr.length % 16)); - return flatArr; - } -} - +/* eslint-disable */ + +var Nr = 14; +var Nk = 8; +var Decrypt = false; +function enc_utf8(s) { + try { + return unescape(encodeURIComponent(s)); + } catch (e) { + throw "Error on UTF-8 encode"; + } +}; +function dec_utf8(s) { + try { + return decodeURIComponent(escape(s)); + } catch (e) { + throw "Bad Key"; + } +}; +function padBlock(byteArr) { + var array = [], + cpad, + i; + if (byteArr.length < 16) { + cpad = 16 - byteArr.length; + array = [ + cpad, + cpad, + cpad, + cpad, + cpad, + cpad, + cpad, + cpad, + cpad, + cpad, + cpad, + cpad, + cpad, + cpad, + cpad, + cpad, + ]; + } + for (i = 0; i < byteArr.length; i++) { + array[i] = byteArr[i]; + } + return array; +}; +function block2s(block, lastBlock) { + var string = "", + padding, + i; + if (lastBlock) { + padding = block[15]; + if (padding > 16) { + throw "Decryption error: Maybe bad key"; + } + if (padding === 16) { + return ""; + } + for (i = 0; i < 16 - padding; i++) { + string += String.fromCharCode(block[i]); + } + } else { + for (i = 0; i < 16; i++) { + string += String.fromCharCode(block[i]); + } + } + return string; +}; +function a2h(numArr) { + var string = "", + i; + for (i = 0; i < numArr.length; i++) { + string += (numArr[i] < 16 ? "0" : "") + numArr[i].toString(16); + } + return string; +}; +function h2a(s) { + var ret = []; + s.replace(/(..)/g, function (s) { + ret.push(parseInt(s, 16)); + }); + return ret; +}; +function s2a(string, binary) { + var array = [], + i; + + if (!binary) { + string = enc_utf8(string); + } + + for (i = 0; i < string.length; i++) { + array[i] = string.charCodeAt(i); + } + + return array; +}; +function size(newsize) { + switch (newsize) { + case 128: + Nr = 10; + Nk = 4; + break; + case 192: + Nr = 12; + Nk = 6; + break; + case 256: + Nr = 14; + Nk = 8; + break; + default: + throw "Invalid Key Size Specified:" + newsize; + } +}; +function randArr(num) { + var result = [], + i; + for (i = 0; i < num; i++) { + result = result.concat(Math.floor(Math.random() * 256)); + } + return result; +}; +function openSSLKey(passwordArr, saltArr) { + var rounds = Nr >= 12 ? 3 : 2, + key = [], + iv = [], + md5_hash = [], + result = [], + data00 = passwordArr.concat(saltArr), + i; + md5_hash[0] = MD5(data00); + result = md5_hash[0]; + for (i = 1; i < rounds; i++) { + md5_hash[i] = MD5(md5_hash[i - 1].concat(data00)); + result = result.concat(md5_hash[i]); + } + key = result.slice(0, 4 * Nk); + iv = result.slice(4 * Nk, 4 * Nk + 16); + return { + key: key, + iv: iv, + }; +}; +function rawEncrypt(plaintext, key, iv) { + key = expandKey(key); + var numBlocks = Math.ceil(plaintext.length / 16), + blocks = [], + i, + cipherBlocks = []; + for (i = 0; i < numBlocks; i++) { + blocks[i] = padBlock(plaintext.slice(i * 16, i * 16 + 16)); + } + if (plaintext.length % 16 === 0) { + blocks.push([ + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + ]); + numBlocks++; + } + for (i = 0; i < blocks.length; i++) { + blocks[i] = + i === 0 + ? xorBlocks(blocks[i], iv) + : xorBlocks(blocks[i], cipherBlocks[i - 1]); + cipherBlocks[i] = encryptBlock(blocks[i], key); + } + return cipherBlocks; +}; +function rawDecrypt(cryptArr, key, iv, binary) { + key = expandKey(key); + var numBlocks = cryptArr.length / 16, + cipherBlocks = [], + i, + plainBlocks = [], + string = ""; + for (i = 0; i < numBlocks; i++) { + cipherBlocks.push(cryptArr.slice(i * 16, (i + 1) * 16)); + } + for (i = cipherBlocks.length - 1; i >= 0; i--) { + plainBlocks[i] = decryptBlock(cipherBlocks[i], key); + plainBlocks[i] = + i === 0 + ? xorBlocks(plainBlocks[i], iv) + : xorBlocks(plainBlocks[i], cipherBlocks[i - 1]); + } + for (i = 0; i < numBlocks - 1; i++) { + string += block2s(plainBlocks[i], false); + } + string += block2s(plainBlocks[i], true); + return binary ? string : dec_utf8(string); +}; +function encryptBlock(block, words) { + Decrypt = false; + var state = addRoundKey(block, words, 0), + round; + for (round = 1; round < Nr + 1; round++) { + state = subBytes(state); + state = shiftRows(state); + if (round < Nr) { + state = mixColumns(state); + } + state = addRoundKey(state, words, round); + } + + return state; +}; +function decryptBlock(block, words) { + Decrypt = true; + var state = addRoundKey(block, words, Nr), + round; + for (round = Nr - 1; round > -1; round--) { + state = shiftRows(state); + state = subBytes(state); + state = addRoundKey(state, words, round); + if (round > 0) { + state = mixColumns(state); + } + } + + return state; +}; +function subBytes(state) { + var S = Decrypt ? SBoxInv : SBox, + temp = [], + i; + for (i = 0; i < 16; i++) { + temp[i] = S[state[i]]; + } + return temp; +}; +function shiftRows(state) { + var temp = [], + shiftBy = Decrypt + ? [0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3] + : [0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11], + i; + for (i = 0; i < 16; i++) { + temp[i] = state[shiftBy[i]]; + } + return temp; +}; +function mixColumns(state) { + var t = [], + c; + if (!Decrypt) { + for (c = 0; c < 4; c++) { + t[c * 4] = + G2X[state[c * 4]] ^ + G3X[state[1 + c * 4]] ^ + state[2 + c * 4] ^ + state[3 + c * 4]; + t[1 + c * 4] = + state[c * 4] ^ + G2X[state[1 + c * 4]] ^ + G3X[state[2 + c * 4]] ^ + state[3 + c * 4]; + t[2 + c * 4] = + state[c * 4] ^ + state[1 + c * 4] ^ + G2X[state[2 + c * 4]] ^ + G3X[state[3 + c * 4]]; + t[3 + c * 4] = + G3X[state[c * 4]] ^ + state[1 + c * 4] ^ + state[2 + c * 4] ^ + G2X[state[3 + c * 4]]; + } + } else { + for (c = 0; c < 4; c++) { + t[c * 4] = + GEX[state[c * 4]] ^ + GBX[state[1 + c * 4]] ^ + GDX[state[2 + c * 4]] ^ + G9X[state[3 + c * 4]]; + t[1 + c * 4] = + G9X[state[c * 4]] ^ + GEX[state[1 + c * 4]] ^ + GBX[state[2 + c * 4]] ^ + GDX[state[3 + c * 4]]; + t[2 + c * 4] = + GDX[state[c * 4]] ^ + G9X[state[1 + c * 4]] ^ + GEX[state[2 + c * 4]] ^ + GBX[state[3 + c * 4]]; + t[3 + c * 4] = + GBX[state[c * 4]] ^ + GDX[state[1 + c * 4]] ^ + G9X[state[2 + c * 4]] ^ + GEX[state[3 + c * 4]]; + } + } + + return t; +}; +function addRoundKey(state, words, round) { + var temp = [], + i; + for (i = 0; i < 16; i++) { + temp[i] = state[i] ^ words[round][i]; + } + return temp; +}; +function xorBlocks(block1, block2) { + var temp = [], + i; + for (i = 0; i < 16; i++) { + temp[i] = block1[i] ^ block2[i]; + } + return temp; +}; +function expandKey(key) { + var w = [], + temp = [], + i, + r, + t, + flat = [], + j; + + for (i = 0; i < Nk; i++) { + r = [key[4 * i], key[4 * i + 1], key[4 * i + 2], key[4 * i + 3]]; + w[i] = r; + } + + for (i = Nk; i < 4 * (Nr + 1); i++) { + w[i] = []; + for (t = 0; t < 4; t++) { + temp[t] = w[i - 1][t]; + } + if (i % Nk === 0) { + temp = subWord(rotWord(temp)); + temp[0] ^= Rcon[i / Nk - 1]; + } else if (Nk > 6 && i % Nk === 4) { + temp = subWord(temp); + } + for (t = 0; t < 4; t++) { + w[i][t] = w[i - Nk][t] ^ temp[t]; + } + } + for (i = 0; i < Nr + 1; i++) { + flat[i] = []; + for (j = 0; j < 4; j++) { + flat[i].push( + w[i * 4 + j][0], + w[i * 4 + j][1], + w[i * 4 + j][2], + w[i * 4 + j][3] + ); + } + } + return flat; +}; +function subWord(w) { + for (var i = 0; i < 4; i++) { + w[i] = SBox[w[i]]; + } + return w; +}; +function rotWord(w) { + var tmp = w[0], + i; + for (i = 0; i < 3; i++) { + w[i] = w[i + 1]; + } + w[3] = tmp; + return w; +}; +function strhex(str, size) { + var i, + ret = []; + for (i = 0; i < str.length; i += size) { + ret[i / size] = parseInt(str.substr(i, size), 16); + } + return ret; +}; +function invertArr(arr) { + var i, + ret = []; + for (i = 0; i < arr.length; i++) { + ret[arr[i]] = i; + } + return ret; +}; +function Gxx(a, b) { + var i, ret; + + ret = 0; + for (i = 0; i < 8; i++) { + ret = (b & 1) === 1 ? ret ^ a : ret; + a = a > 0x7f ? 0x11b ^ (a << 1) : a << 1; + b >>>= 1; + } + + return ret; +}; +function Gx(x) { + var i, + r = []; + for (i = 0; i < 256; i++) { + r[i] = Gxx(x, i); + } + return r; +}; +var SBox = strhex( + "637c777bf26b6fc53001672bfed7ab76ca82c97dfa5947f0add4a2af9ca472c0b7fd9326363ff7cc34a5e5f171d8311504c723c31896059a071280e2eb27b27509832c1a1b6e5aa0523bd6b329e32f8453d100ed20fcb15b6acbbe394a4c58cfd0efaafb434d338545f9027f503c9fa851a3408f929d38f5bcb6da2110fff3d2cd0c13ec5f974417c4a77e3d645d197360814fdc222a908846eeb814de5e0bdbe0323a0a4906245cc2d3ac629195e479e7c8376d8dd54ea96c56f4ea657aae08ba78252e1ca6b4c6e8dd741f4bbd8b8a703eb5664803f60e613557b986c11d9ee1f8981169d98e949b1e87e9ce5528df8ca1890dbfe6426841992d0fb054bb16", + 2 +); +var SBoxInv = invertArr(SBox); +var Rcon = strhex( + "01020408102040801b366cd8ab4d9a2f5ebc63c697356ad4b37dfaefc591", + 2 +); +var G2X = Gx(2); +var G3X = Gx(3); +var G9X = Gx(9); +var GBX = Gx(0xb); +var GDX = Gx(0xd); +var GEX = Gx(0xe); +function enc(string, pass, binary) { + var salt = randArr(8), + pbe = openSSLKey(s2a(pass, binary), salt), + key = pbe.key, + iv = pbe.iv, + cipherBlocks, + saltBlock = [[83, 97, 108, 116, 101, 100, 95, 95].concat(salt)]; + string = s2a(string, binary); + cipherBlocks = rawEncrypt(string, key, iv); + + cipherBlocks = saltBlock.concat(cipherBlocks); + return Base64.encode(cipherBlocks); +}; +function dec(string, pass, binary) { + var cryptArr = Base64.decode(string), + salt = cryptArr.slice(8, 16), + pbe = openSSLKey(s2a(pass, binary), salt), + key = pbe.key, + iv = pbe.iv; + cryptArr = cryptArr.slice(16, cryptArr.length); + + string = rawDecrypt(cryptArr, key, iv, binary); + return string; +}; +function MD5(numArr) { + function rotateLeft(lValue, iShiftBits) { + return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits)); + } + + function addUnsigned(lX, lY) { + var lX4, lY4, lX8, lY8, lResult; + lX8 = lX & 0x80000000; + lY8 = lY & 0x80000000; + lX4 = lX & 0x40000000; + lY4 = lY & 0x40000000; + lResult = (lX & 0x3fffffff) + (lY & 0x3fffffff); + if (lX4 & lY4) { + return lResult ^ 0x80000000 ^ lX8 ^ lY8; + } + if (lX4 | lY4) { + if (lResult & 0x40000000) { + return lResult ^ 0xc0000000 ^ lX8 ^ lY8; + } else { + return lResult ^ 0x40000000 ^ lX8 ^ lY8; + } + } else { + return lResult ^ lX8 ^ lY8; + } + } + + function f(x, y, z) { + return (x & y) | (~x & z); + } + function g(x, y, z) { + return (x & z) | (y & ~z); + } + function h(x, y, z) { + return x ^ y ^ z; + } + function funcI(x, y, z) { + return y ^ (x | ~z); + } + + function ff(a, b, c, d, x, s, ac) { + a = addUnsigned(a, addUnsigned(addUnsigned(f(b, c, d), x), ac)); + return addUnsigned(rotateLeft(a, s), b); + } + + function gg(a, b, c, d, x, s, ac) { + a = addUnsigned(a, addUnsigned(addUnsigned(g(b, c, d), x), ac)); + return addUnsigned(rotateLeft(a, s), b); + } + + function hh(a, b, c, d, x, s, ac) { + a = addUnsigned(a, addUnsigned(addUnsigned(h(b, c, d), x), ac)); + return addUnsigned(rotateLeft(a, s), b); + } + + function ii(a, b, c, d, x, s, ac) { + a = addUnsigned(a, addUnsigned(addUnsigned(funcI(b, c, d), x), ac)); + return addUnsigned(rotateLeft(a, s), b); + } + + function convertToWordArray(numArr) { + var lWordCount, + lMessageLength = numArr.length, + lNumberOfWords_temp1 = lMessageLength + 8, + lNumberOfWords_temp2 = + (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64, + lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16, + lWordArray = [], + lBytePosition = 0, + lByteCount = 0; + while (lByteCount < lMessageLength) { + lWordCount = (lByteCount - (lByteCount % 4)) / 4; + lBytePosition = (lByteCount % 4) * 8; + lWordArray[lWordCount] = + lWordArray[lWordCount] | (numArr[lByteCount] << lBytePosition); + lByteCount++; + } + lWordCount = (lByteCount - (lByteCount % 4)) / 4; + lBytePosition = (lByteCount % 4) * 8; + lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition); + lWordArray[lNumberOfWords - 2] = lMessageLength << 3; + lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29; + return lWordArray; + } + + function wordToHex(lValue) { + var lByte, + lCount, + wordToHexArr = []; + for (lCount = 0; lCount <= 3; lCount++) { + lByte = (lValue >>> (lCount * 8)) & 255; + wordToHexArr = wordToHexArr.concat(lByte); + } + return wordToHexArr; + } + + var x = [], + k, + AA, + BB, + CC, + DD, + a, + b, + c, + d, + rnd = strhex( + "67452301efcdab8998badcfe10325476d76aa478e8c7b756242070dbc1bdceeef57c0faf4787c62aa8304613fd469501698098d88b44f7afffff5bb1895cd7be6b901122fd987193a679438e49b40821f61e2562c040b340265e5a51e9b6c7aad62f105d02441453d8a1e681e7d3fbc821e1cde6c33707d6f4d50d87455a14eda9e3e905fcefa3f8676f02d98d2a4c8afffa39428771f6816d9d6122fde5380ca4beea444bdecfa9f6bb4b60bebfbc70289b7ec6eaa127fad4ef308504881d05d9d4d039e6db99e51fa27cf8c4ac5665f4292244432aff97ab9423a7fc93a039655b59c38f0ccc92ffeff47d85845dd16fa87e4ffe2ce6e0a30143144e0811a1f7537e82bd3af2352ad7d2bbeb86d391", + 8 + ); + + x = convertToWordArray(numArr); + + a = rnd[0]; + b = rnd[1]; + c = rnd[2]; + d = rnd[3]; + + for (k = 0; k < x.length; k += 16) { + AA = a; + BB = b; + CC = c; + DD = d; + a = ff(a, b, c, d, x[k + 0], 7, rnd[4]); + d = ff(d, a, b, c, x[k + 1], 12, rnd[5]); + c = ff(c, d, a, b, x[k + 2], 17, rnd[6]); + b = ff(b, c, d, a, x[k + 3], 22, rnd[7]); + a = ff(a, b, c, d, x[k + 4], 7, rnd[8]); + d = ff(d, a, b, c, x[k + 5], 12, rnd[9]); + c = ff(c, d, a, b, x[k + 6], 17, rnd[10]); + b = ff(b, c, d, a, x[k + 7], 22, rnd[11]); + a = ff(a, b, c, d, x[k + 8], 7, rnd[12]); + d = ff(d, a, b, c, x[k + 9], 12, rnd[13]); + c = ff(c, d, a, b, x[k + 10], 17, rnd[14]); + b = ff(b, c, d, a, x[k + 11], 22, rnd[15]); + a = ff(a, b, c, d, x[k + 12], 7, rnd[16]); + d = ff(d, a, b, c, x[k + 13], 12, rnd[17]); + c = ff(c, d, a, b, x[k + 14], 17, rnd[18]); + b = ff(b, c, d, a, x[k + 15], 22, rnd[19]); + a = gg(a, b, c, d, x[k + 1], 5, rnd[20]); + d = gg(d, a, b, c, x[k + 6], 9, rnd[21]); + c = gg(c, d, a, b, x[k + 11], 14, rnd[22]); + b = gg(b, c, d, a, x[k + 0], 20, rnd[23]); + a = gg(a, b, c, d, x[k + 5], 5, rnd[24]); + d = gg(d, a, b, c, x[k + 10], 9, rnd[25]); + c = gg(c, d, a, b, x[k + 15], 14, rnd[26]); + b = gg(b, c, d, a, x[k + 4], 20, rnd[27]); + a = gg(a, b, c, d, x[k + 9], 5, rnd[28]); + d = gg(d, a, b, c, x[k + 14], 9, rnd[29]); + c = gg(c, d, a, b, x[k + 3], 14, rnd[30]); + b = gg(b, c, d, a, x[k + 8], 20, rnd[31]); + a = gg(a, b, c, d, x[k + 13], 5, rnd[32]); + d = gg(d, a, b, c, x[k + 2], 9, rnd[33]); + c = gg(c, d, a, b, x[k + 7], 14, rnd[34]); + b = gg(b, c, d, a, x[k + 12], 20, rnd[35]); + a = hh(a, b, c, d, x[k + 5], 4, rnd[36]); + d = hh(d, a, b, c, x[k + 8], 11, rnd[37]); + c = hh(c, d, a, b, x[k + 11], 16, rnd[38]); + b = hh(b, c, d, a, x[k + 14], 23, rnd[39]); + a = hh(a, b, c, d, x[k + 1], 4, rnd[40]); + d = hh(d, a, b, c, x[k + 4], 11, rnd[41]); + c = hh(c, d, a, b, x[k + 7], 16, rnd[42]); + b = hh(b, c, d, a, x[k + 10], 23, rnd[43]); + a = hh(a, b, c, d, x[k + 13], 4, rnd[44]); + d = hh(d, a, b, c, x[k + 0], 11, rnd[45]); + c = hh(c, d, a, b, x[k + 3], 16, rnd[46]); + b = hh(b, c, d, a, x[k + 6], 23, rnd[47]); + a = hh(a, b, c, d, x[k + 9], 4, rnd[48]); + d = hh(d, a, b, c, x[k + 12], 11, rnd[49]); + c = hh(c, d, a, b, x[k + 15], 16, rnd[50]); + b = hh(b, c, d, a, x[k + 2], 23, rnd[51]); + a = ii(a, b, c, d, x[k + 0], 6, rnd[52]); + d = ii(d, a, b, c, x[k + 7], 10, rnd[53]); + c = ii(c, d, a, b, x[k + 14], 15, rnd[54]); + b = ii(b, c, d, a, x[k + 5], 21, rnd[55]); + a = ii(a, b, c, d, x[k + 12], 6, rnd[56]); + d = ii(d, a, b, c, x[k + 3], 10, rnd[57]); + c = ii(c, d, a, b, x[k + 10], 15, rnd[58]); + b = ii(b, c, d, a, x[k + 1], 21, rnd[59]); + a = ii(a, b, c, d, x[k + 8], 6, rnd[60]); + d = ii(d, a, b, c, x[k + 15], 10, rnd[61]); + c = ii(c, d, a, b, x[k + 6], 15, rnd[62]); + b = ii(b, c, d, a, x[k + 13], 21, rnd[63]); + a = ii(a, b, c, d, x[k + 4], 6, rnd[64]); + d = ii(d, a, b, c, x[k + 11], 10, rnd[65]); + c = ii(c, d, a, b, x[k + 2], 15, rnd[66]); + b = ii(b, c, d, a, x[k + 9], 21, rnd[67]); + a = addUnsigned(a, AA); + b = addUnsigned(b, BB); + c = addUnsigned(c, CC); + d = addUnsigned(d, DD); + } + + return wordToHex(a).concat(wordToHex(b), wordToHex(c), wordToHex(d)); +}; +// function encString (plaintext, key, iv) { +// var i; +// plaintext = s2a(plaintext, false); + +// key = s2a(key, false); +// for (i = key.length; i < 32; i++) { +// key[i] = 0; +// } + +// if (iv === undefined) { +// } else { +// iv = s2a(iv, false); +// for (i = iv.length; i < 16; i++) { +// iv[i] = 0; +// } +// } + +// var ct = rawEncrypt(plaintext, key, iv); +// var ret = [iv]; +// for (i = 0; i < ct.length; i++) { +// ret[ret.length] = ct[i]; +// } +// return Base64.encode(ret); +// }; +// function decString (ciphertext, key) { +// // var tmp = Base64.decode(ciphertext); +// var tmp = atob(ciphertext); +// var iv = tmp.slice(0, 16); +// var ct = tmp.slice(16, tmp.length); +// var i; + +// key = s2a(key, false); +// for (i = key.length; i < 32; i++) { +// key[i] = 0; +// } + +// var pt = rawDecrypt(ct, key, iv, false); +// return pt; +// }; +// function Base64() { +// var _chars = +// "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", +// chars = _chars.split(""), +// encode = function (b, withBreaks) { +// var flatArr = [], +// b64 = "", +// i, +// broken_b64, +// totalChunks = Math.floor((b.length * 16) / 3); +// for (i = 0; i < b.length * 16; i++) { +// flatArr.push(b[Math.floor(i / 16)][i % 16]); +// } +// for (i = 0; i < flatArr.length; i = i + 3) { +// b64 += chars[flatArr[i] >> 2]; +// b64 += chars[((flatArr[i] & 3) << 4) | (flatArr[i + 1] >> 4)]; +// if (flatArr[i + 1] !== undefined) { +// b64 += chars[((flatArr[i + 1] & 15) << 2) | (flatArr[i + 2] >> 6)]; +// } else { +// b64 += "="; +// } +// if (flatArr[i + 2] !== undefined) { +// b64 += chars[flatArr[i + 2] & 63]; +// } else { +// b64 += "="; +// } +// } +// broken_b64 = b64.slice(0, 64) + "\n"; +// for (i = 1; i < Math.ceil(b64.length / 64); i++) { +// broken_b64 += +// b64.slice(i * 64, i * 64 + 64) + +// (Math.ceil(b64.length / 64) === i + 1 ? "" : "\n"); +// } +// return broken_b64; +// }, +// decode = function (string) { +// string = string.replace(/\n/g, ""); +// var flatArr = [], +// c = [], +// b = [], +// i; +// for (i = 0; i < string.length; i = i + 4) { +// c[0] = _chars.indexOf(string.charAt(i)); +// c[1] = _chars.indexOf(string.charAt(i + 1)); +// c[2] = _chars.indexOf(string.charAt(i + 2)); +// c[3] = _chars.indexOf(string.charAt(i + 3)); + +// b[0] = (c[0] << 2) | (c[1] >> 4); +// b[1] = ((c[1] & 15) << 4) | (c[2] >> 2); +// b[2] = ((c[2] & 3) << 6) | c[3]; +// flatArr.push(b[0], b[1], b[2]); +// } +// flatArr = flatArr.slice(0, flatArr.length - (flatArr.length % 16)); +// return flatArr; +// }; + +// if (typeof Array.indexOf === "function") { +// _chars = chars; +// } + +// return { +// encode: encode, +// decode: decode, +// }; +// } + +const Base64 = { + encode: function (b) { + var _chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", + chars = _chars.split(""), + flatArr = [], + b64 = "", + i, + broken_b64, + totalChunks = Math.floor((b.length * 16) / 3); + for (i = 0; i < b.length * 16; i++) { + flatArr.push(b[Math.floor(i / 16)][i % 16]); + } + for (i = 0; i < flatArr.length; i = i + 3) { + b64 += chars[flatArr[i] >> 2]; + b64 += chars[((flatArr[i] & 3) << 4) | (flatArr[i + 1] >> 4)]; + if (flatArr[i + 1] !== undefined) { + b64 += chars[((flatArr[i + 1] & 15) << 2) | (flatArr[i + 2] >> 6)]; + } else { + b64 += "="; + } + if (flatArr[i + 2] !== undefined) { + b64 += chars[flatArr[i + 2] & 63]; + } else { + b64 += "="; + } + } + broken_b64 = b64.slice(0, 64) + "\n"; + for (i = 1; i < Math.ceil(b64.length / 64); i++) { + broken_b64 += + b64.slice(i * 64, i * 64 + 64) + + (Math.ceil(b64.length / 64) === i + 1 ? "" : "\n"); + } + return broken_b64; + }, + decode: function (string) { + string = string.replace(/\n/g, ""); + var _chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", + chars = _chars.split(""), + flatArr = [], + c = [], + b = [], + i; + for (i = 0; i < string.length; i = i + 4) { + c[0] = _chars.indexOf(string.charAt(i)); + c[1] = _chars.indexOf(string.charAt(i + 1)); + c[2] = _chars.indexOf(string.charAt(i + 2)); + c[3] = _chars.indexOf(string.charAt(i + 3)); + + b[0] = (c[0] << 2) | (c[1] >> 4); + b[1] = ((c[1] & 15) << 4) | (c[2] >> 2); + b[2] = ((c[2] & 3) << 6) | c[3]; + flatArr.push(b[0], b[1], b[2]); + } + flatArr = flatArr.slice(0, flatArr.length - (flatArr.length % 16)); + return flatArr; + } +} + export { enc, dec }; \ No newline at end of file diff --git a/src/codecs/index.ts b/src/codecs/index.ts index a4db063..2069396 100644 --- a/src/codecs/index.ts +++ b/src/codecs/index.ts @@ -1,82 +1,83 @@ -import { enc, dec } from "./aes.ts"; - -// for some reason eslint was parsing the type inside of the function params as a variable -export interface Codec { - // eslint-disable-next-line - encode: (str: string | undefined) => string; - // eslint-disable-next-line - decode: (str: string | undefined) => string; -} - -const xor = { - encode: (str: string | undefined, key: number = 2) => { - if (!str) return str; - - return encodeURIComponent(str.split("").map((e, i) => i % key ? String.fromCharCode(e.charCodeAt(0) ^ key) : e).join("")); - }, - decode: (str: string | undefined, key: number = 2) => { - if (!str) return str; - - return decodeURIComponent(str).split("").map((e, i) => i % key ? String.fromCharCode(e.charCodeAt(0) ^ key) : e).join(""); - } -} - -const plain = { - encode: (str: string | undefined) => { - if (!str) return str; - - return encodeURIComponent(str); - }, - decode: (str: string | undefined) => { - if (!str) return str; - - return decodeURIComponent(str); - } -} - -const aes = { - encode: (str: string | undefined) => { - if (!str) return str; - - return encodeURIComponent(enc(str, "dynamic").substring(10)); - }, - decode: (str: string | undefined) => { - if (!str) return str; - - return dec("U2FsdGVkX1" + decodeURIComponent(str), "dynamic"); - } -} - -const none = { - encode: (str: string | undefined) => str, - decode: (str: string | undefined) => str, -} - -const base64 = { - encode: (str: string | undefined) => { - if (!str) return str; - - return decodeURIComponent(btoa(str)); - }, - decode: (str: string | undefined) => { - if (!str) return str; - - return atob(str); - } -} - -declare global { - interface Window { - __scramjet$codecs: { - none: Codec; - plain: Codec; - base64: Codec; - xor: Codec; - aes: Codec; - } - } -} - -self.__scramjet$codecs = { - none, plain, base64, xor, aes +import { enc, dec } from "./aes"; + +// for some reason eslint was parsing the type inside of the function params as a variable +export interface Codec { + // eslint-disable-next-line + encode: (str: string | undefined) => string; + // eslint-disable-next-line + decode: (str: string | undefined) => string; +} + +const xor = { + encode: (str: string | undefined, key: number = 2) => { + if (!str) return str; + + return encodeURIComponent(str.split("").map((e, i) => i % key ? String.fromCharCode(e.charCodeAt(0) ^ key) : e).join("")); + }, + decode: (str: string | undefined, key: number = 2) => { + if (!str) return str; + + return decodeURIComponent(str).split("").map((e, i) => i % key ? String.fromCharCode(e.charCodeAt(0) ^ key) : e).join(""); + } +} + +const plain = { + encode: (str: string | undefined) => { + if (!str) return str; + + return encodeURIComponent(str); + }, + decode: (str: string | undefined) => { + if (!str) return str; + + return decodeURIComponent(str); + } +} + +/* +const aes = { + encode: (str: string | undefined) => { + if (!str) return str; + + return encodeURIComponent(enc(str, "dynamic").substring(10)); + }, + decode: (str: string | undefined) => { + if (!str) return str; + + return dec("U2FsdGVkX1" + decodeURIComponent(str), "dynamic"); + } +} +*/ + +const none = { + encode: (str: string | undefined) => str, + decode: (str: string | undefined) => str, +} + +const base64 = { + encode: (str: string | undefined) => { + if (!str) return str; + + return decodeURIComponent(btoa(str)); + }, + decode: (str: string | undefined) => { + if (!str) return str; + + return atob(str); + } +} + +declare global { + interface Window { + __scramjet$codecs: { + none: Codec; + plain: Codec; + base64: Codec; + xor: Codec; + } + } +} + +self.__scramjet$codecs = { + none, plain, base64, xor } \ No newline at end of file diff --git a/src/scramjet.config.ts b/src/scramjet.config.ts index ffc27fc..e50f9ed 100644 --- a/src/scramjet.config.ts +++ b/src/scramjet.config.ts @@ -1,25 +1,25 @@ -import { Codec } from "./codecs"; - -declare global { - interface Window { - __scramjet$config: { - prefix: string; - codec: Codec - config: string; - bundle: string; - worker: string; - client: string; - codecs: string; - } - } -} - -self.__scramjet$config = { - prefix: "/scramjet/", - codec: self.__scramjet$codecs.plain, - config: "/scramjet.config.js", - bundle: "/scramjet.bundle.js", - worker: "/scramjet.worker.js", - client: "/scramjet.client.js", - codecs: "/scramjet.codecs.js" +import { Codec } from "./codecs"; + +declare global { + interface Window { + __scramjet$config: { + prefix: string; + codec: Codec + config: string; + bundle: string; + worker: string; + client: string; + codecs: string; + } + } +} + +self.__scramjet$config = { + prefix: "/scramjet/", + codec: self.__scramjet$codecs.plain, + config: "/scramjet.config.js", + bundle: "/scramjet.bundle.js", + worker: "/scramjet.worker.js", + client: "/scramjet.client.js", + codecs: "/scramjet.codecs.js" } \ No newline at end of file diff --git a/src/worker/index.ts b/src/worker/index.ts index 9a19f1d..d950dc3 100644 --- a/src/worker/index.ts +++ b/src/worker/index.ts @@ -1,194 +1,194 @@ -import { BareClient } from "@mercuryworkshop/bare-mux"; -import { BareResponseFetch } from "@mercuryworkshop/bare-mux"; -import { encodeUrl, decodeUrl, rewriteCss, rewriteHeaders, rewriteHtml, rewriteJs } from "../bundle"; - -declare global { - interface Window { - ScramjetServiceWorker; - } -} - -export default class ScramjetServiceWorker { - client: typeof BareClient.prototype; - config: typeof self.__scramjet$config; - constructor(config = self.__scramjet$config) { - this.client = new BareClient(); - if (!config.prefix) config.prefix = "/scramjet/"; - this.config = config; - } - - route({ request }: FetchEvent) { - if (request.url.startsWith(location.origin + this.config.prefix)) return true; - else return false; - } - - async fetch({ request }: FetchEvent) { - const urlParam = new URLSearchParams(new URL(request.url).search); - - if (urlParam.has("url")) { - return Response.redirect(encodeUrl(urlParam.get("url"), new URL(urlParam.get("url")))) - } - - try { - const url = new URL(decodeUrl(request.url)); - - const response: BareResponseFetch = await this.client.fetch(url, { - method: request.method, - body: request.body, - headers: request.headers, - credentials: "omit", - mode: request.mode === "cors" ? request.mode : "same-origin", - cache: request.cache, - redirect: request.redirect, - }); - - let responseBody; - const responseHeaders = rewriteHeaders(response.rawHeaders, url); - if (response.body) { - switch (request.destination) { - case "iframe": - case "document": - responseBody = rewriteHtml(await response.text(), url); - break; - case "script": - responseBody = rewriteJs(await response.text(), url); - break; - case "style": - responseBody = rewriteCss(await response.text(), url); - break; - case "sharedworker": - case "worker": - break; - default: - responseBody = response.body; - break; - } - } - // downloads - if (["document", "iframe"].includes(request.destination)) { - const header = responseHeaders["content-disposition"]; - - // validate header and test for filename - if (!/\s*?((inline|attachment);\s*?)filename=/i.test(header)) { - // if filename= wasn"t specified then maybe the remote specified to download this as an attachment? - // if it"s invalid then we can still possibly test for the attachment/inline type - const type = /^\s*?attachment/i.test(header) - ? "attachment" - : "inline"; - - // set the filename - const [filename] = new URL(response.finalURL).pathname - .split("/") - .slice(-1); - - responseHeaders[ - "content-disposition" - ] = `${type}; filename=${JSON.stringify(filename)}`; - } - } - if (responseHeaders["accept"] === "text/event-stream") { - responseHeaders["content-type"] = "text/event-stream"; - } - if (crossOriginIsolated) { - responseHeaders["Cross-Origin-Embedder-Policy"] = "require-corp"; - } - - return new Response(responseBody, { - headers: responseHeaders as HeadersInit, - status: response.status, - statusText: response.statusText - }) - } catch (err) { - if (!["document", "iframe"].includes(request.destination)) - return new Response(undefined, { status: 500 }); - - console.error(err); - - return renderError(err, decodeUrl(request.url)); - } - } -} - - -function errorTemplate( - trace: string, - fetchedURL: string, -) { - // turn script into a data URI so we don"t have to escape any HTML values - const script = ` - errorTrace.value = ${JSON.stringify(trace)}; - fetchedURL.textContent = ${JSON.stringify(fetchedURL)}; - for (const node of document.querySelectorAll("#hostname")) node.textContent = ${JSON.stringify( - location.hostname - )}; - reload.addEventListener("click", () => location.reload()); - version.textContent = "0.0.1"; - ` - - return ( - ` - -
- -Failed to load
-Internal Server Error
- -Try:
-If you"re the administrator of , try:
-Scramjet v
- - - - ` - ); -} - -/** - * - * @param {unknown} err - * @param {string} fetchedURL - */ -function renderError(err, fetchedURL) { - const headers = { - "content-type": "text/html", - }; - if (crossOriginIsolated) { - headers["Cross-Origin-Embedd'er-Policy"] = "require-corp"; - } - - return new Response( - errorTemplate( - String(err), - fetchedURL - ), - { - status: 500, - headers: headers - } - ); -} - +import { BareClient } from "@mercuryworkshop/bare-mux"; +import { BareResponseFetch } from "@mercuryworkshop/bare-mux"; +import { encodeUrl, decodeUrl, rewriteCss, rewriteHeaders, rewriteHtml, rewriteJs } from "../bundle"; + +declare global { + interface Window { + ScramjetServiceWorker; + } +} + +export default class ScramjetServiceWorker { + client: typeof BareClient.prototype; + config: typeof self.__scramjet$config; + constructor(config = self.__scramjet$config) { + this.client = new BareClient(); + if (!config.prefix) config.prefix = "/scramjet/"; + this.config = config; + } + + route({ request }: FetchEvent) { + if (request.url.startsWith(location.origin + this.config.prefix)) return true; + else return false; + } + + async fetch({ request }: FetchEvent) { + const urlParam = new URLSearchParams(new URL(request.url).search); + + if (urlParam.has("url")) { + return Response.redirect(encodeUrl(urlParam.get("url"), new URL(urlParam.get("url")))) + } + + try { + const url = new URL(decodeUrl(request.url)); + + const response: BareResponseFetch = await this.client.fetch(url, { + method: request.method, + body: request.body, + headers: request.headers, + credentials: "omit", + mode: request.mode === "cors" ? request.mode : "same-origin", + cache: request.cache, + redirect: request.redirect, + }); + + let responseBody; + const responseHeaders = rewriteHeaders(response.rawHeaders, url); + if (response.body) { + switch (request.destination) { + case "iframe": + case "document": + responseBody = rewriteHtml(await response.text(), url); + break; + case "script": + responseBody = rewriteJs(await response.text(), url); + break; + case "style": + responseBody = rewriteCss(await response.text(), url); + break; + case "sharedworker": + case "worker": + break; + default: + responseBody = response.body; + break; + } + } + // downloads + if (["document", "iframe"].includes(request.destination)) { + const header = responseHeaders["content-disposition"]; + + // validate header and test for filename + if (!/\s*?((inline|attachment);\s*?)filename=/i.test(header)) { + // if filename= wasn"t specified then maybe the remote specified to download this as an attachment? + // if it"s invalid then we can still possibly test for the attachment/inline type + const type = /^\s*?attachment/i.test(header) + ? "attachment" + : "inline"; + + // set the filename + const [filename] = new URL(response.finalURL).pathname + .split("/") + .slice(-1); + + responseHeaders[ + "content-disposition" + ] = `${type}; filename=${JSON.stringify(filename)}`; + } + } + if (responseHeaders["accept"] === "text/event-stream") { + responseHeaders["content-type"] = "text/event-stream"; + } + if (crossOriginIsolated) { + responseHeaders["Cross-Origin-Embedder-Policy"] = "require-corp"; + } + + return new Response(responseBody, { + headers: responseHeaders as HeadersInit, + status: response.status, + statusText: response.statusText + }) + } catch (err) { + if (!["document", "iframe"].includes(request.destination)) + return new Response(undefined, { status: 500 }); + + console.error(err); + + return renderError(err, decodeUrl(request.url)); + } + } +} + + +function errorTemplate( + trace: string, + fetchedURL: string, +) { + // turn script into a data URI so we don"t have to escape any HTML values + const script = ` + errorTrace.value = ${JSON.stringify(trace)}; + fetchedURL.textContent = ${JSON.stringify(fetchedURL)}; + for (const node of document.querySelectorAll("#hostname")) node.textContent = ${JSON.stringify( + location.hostname + )}; + reload.addEventListener("click", () => location.reload()); + version.textContent = "0.0.1"; + ` + + return ( + ` + + + +Failed to load
+Internal Server Error
+ +Try:
+If you"re the administrator of , try:
+Scramjet v
+ + + + ` + ); +} + +/** + * + * @param {unknown} err + * @param {string} fetchedURL + */ +function renderError(err, fetchedURL) { + const headers = { + "content-type": "text/html", + }; + if (crossOriginIsolated) { + headers["Cross-Origin-Embedd'er-Policy"] = "require-corp"; + } + + return new Response( + errorTemplate( + String(err), + fetchedURL + ), + { + status: 500, + headers: headers + } + ); +} + diff --git a/static/index.html b/static/index.html index bc6c5e2..2259a5a 100644 --- a/static/index.html +++ b/static/index.html @@ -1,29 +1,29 @@ - - - - - -surf the unblocked and mostly buggy web
- -surf the unblocked and mostly buggy web
+ +