├── bin ├── balls.sh ├── index.d.ts ├── index.cjs └── start.sh ├── fortnite ├── .npmignore ├── .gitignore ├── lib ├── client │ ├── index.ts │ └── client.ts ├── global │ ├── util │ │ ├── error.ts │ │ ├── file.ts │ │ ├── path.ts │ │ ├── clone.ts │ │ ├── class.ts │ │ ├── about.ts │ │ ├── rewritePath.ts │ │ ├── encode.ts │ │ ├── edit.ts │ │ ├── route.ts │ │ ├── resHeader.ts │ │ └── reqHeader.ts │ ├── middleware.ts │ ├── meta │ │ ├── load.ts │ │ └── type.ts │ ├── is │ │ ├── css.ts │ │ ├── js.ts │ │ └── html.ts │ ├── rewrite │ │ ├── js │ │ │ ├── type │ │ │ │ ├── Property.ts │ │ │ │ ├── VariableDeclaractor.ts │ │ │ │ ├── AssignmentExpression.ts │ │ │ │ ├── ThisExpression.ts │ │ │ │ ├── Literal.ts │ │ │ │ ├── Imports.ts │ │ │ │ ├── CallExpression.ts │ │ │ │ ├── Identifier.ts │ │ │ │ └── MemberExpression.ts │ │ │ ├── object │ │ │ │ ├── Eval.ts │ │ │ │ └── PostMessage.ts │ │ │ ├── process.ts │ │ │ ├── iterate.ts │ │ │ ├── types.ts │ │ │ ├── js.ts │ │ │ └── emit.ts │ │ ├── css.ts │ │ ├── html │ │ │ ├── srcset.ts │ │ │ ├── nodewrapper.ts │ │ │ ├── html.ts │ │ │ └── generateHead.ts │ │ └── manifest.ts │ ├── cookie │ │ ├── parse.ts │ │ ├── index.ts │ │ └── db.ts │ ├── meta.ts │ ├── http.ts │ ├── url.ts │ ├── istype.ts │ ├── regex.ts │ ├── client │ │ ├── methods │ │ │ ├── document │ │ │ │ ├── write.ts │ │ │ │ ├── style.ts │ │ │ │ └── cookie.ts │ │ │ ├── window │ │ │ │ ├── policy.ts │ │ │ │ ├── history.ts │ │ │ │ ├── blob.ts │ │ │ │ ├── navigator.ts │ │ │ │ ├── imports.ts │ │ │ │ ├── worker.ts │ │ │ │ ├── rtc.ts │ │ │ │ ├── ws.ts │ │ │ │ ├── storage.ts │ │ │ │ ├── message.ts │ │ │ │ ├── fetch.ts │ │ │ │ └── niche.ts │ │ │ ├── core │ │ │ │ ├── eval.ts │ │ │ │ ├── protocol.ts │ │ │ │ ├── html.ts │ │ │ │ ├── get.ts │ │ │ │ ├── reflect.ts │ │ │ │ ├── function.ts │ │ │ │ ├── location.ts │ │ │ │ └── window.ts │ │ │ ├── wrap.ts │ │ │ └── init.ts │ │ ├── methods.ts │ │ └── index.ts │ ├── rewrite.ts │ ├── headers.ts │ ├── modules.ts │ ├── http │ │ ├── request.ts │ │ └── response.ts │ ├── url │ │ ├── decode.ts │ │ └── encode.ts │ ├── util.ts │ ├── codec.ts │ ├── client.ts │ └── bundle.ts ├── types.d.ts ├── dynamic.config.js ├── handler │ └── index.ts └── html │ └── index.ts ├── static ├── resources │ ├── img │ │ └── logo.png │ ├── scripts │ │ ├── notice.js │ │ ├── index.js │ │ └── settings.js │ └── style.css ├── sw.js └── index.html ├── docs ├── examples │ └── uv-dynamic-multi │ │ ├── resources │ │ ├── img │ │ │ └── logo.png │ │ ├── scripts │ │ │ ├── notice.js │ │ │ └── index.js │ │ └── style.css │ │ ├── uv │ │ ├── uv.bundle.js.LICENSE.txt │ │ ├── uv.config.js │ │ └── uv.sw.js │ │ ├── dynamic │ │ └── dynamic.config.js │ │ ├── sw.js │ │ └── index.html └── configuration │ ├── modes.md │ ├── logging.md │ ├── bare.md │ └── encoding.md ├── tsconfig.json ├── .github └── dependabot.yml ├── esbuild.prod.js ├── esbuild.dev.js ├── package.json ├── README.md ├── index.js └── LICENSE /bin/balls.sh: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /fortnite: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .DS_Store 4 | **/.DS_Store 5 | package-lock.json -------------------------------------------------------------------------------- /bin/index.d.ts: -------------------------------------------------------------------------------- 1 | declare const dynamicPath: string; 2 | 3 | export { dynamicPath }; 4 | -------------------------------------------------------------------------------- /lib/client/index.ts: -------------------------------------------------------------------------------- 1 | import Client from './client'; 2 | 3 | export default Client(self) as Window; -------------------------------------------------------------------------------- /lib/global/util/error.ts: -------------------------------------------------------------------------------- 1 | export default async function Error(request: Request, error: Error) { 2 | 3 | } -------------------------------------------------------------------------------- /static/resources/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NebulaServices/Dynamic/HEAD/static/resources/img/logo.png -------------------------------------------------------------------------------- /docs/examples/uv-dynamic-multi/resources/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NebulaServices/Dynamic/HEAD/docs/examples/uv-dynamic-multi/resources/img/logo.png -------------------------------------------------------------------------------- /bin/index.cjs: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const { resolve } = require("node:path"); 4 | 5 | const dynamicPath = resolve(__dirname, "..", "dist"); 6 | 7 | exports.dynamicPath = dynamicPath; 8 | -------------------------------------------------------------------------------- /docs/examples/uv-dynamic-multi/uv/uv.bundle.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /*! 2 | * mime-db 3 | * Copyright(c) 2014 Jonathan Ong 4 | * Copyright(c) 2015-2022 Douglas Christopher Wilson 5 | * MIT Licensed 6 | */ 7 | -------------------------------------------------------------------------------- /lib/global/util/file.ts: -------------------------------------------------------------------------------- 1 | declare const self: any; 2 | 3 | export default function File(req: Request) { 4 | return req.url.toString().substr(location.origin.length, req.url.toString().length).startsWith(self.__dynamic$config.assets.prefix); 5 | }; -------------------------------------------------------------------------------- /lib/global/middleware.ts: -------------------------------------------------------------------------------- 1 | import { DynamicBundle } from "./client"; 2 | 3 | class DynamicMiddleware { 4 | 5 | ctx: DynamicBundle; 6 | 7 | constructor(ctx: DynamicBundle) { 8 | this.ctx = ctx; 9 | } 10 | } 11 | 12 | export default DynamicMiddleware; -------------------------------------------------------------------------------- /lib/global/util/path.ts: -------------------------------------------------------------------------------- 1 | import DynamicUtil from "../util"; 2 | 3 | export default function path(this: DynamicUtil, { url }: Request) { 4 | return !(url.toString().substr(location.origin.length, this.ctx.config.prefix.length).startsWith(this.ctx.config.prefix)); 5 | } -------------------------------------------------------------------------------- /lib/global/util/clone.ts: -------------------------------------------------------------------------------- 1 | export default function copyInstance(original: any) { 2 | var copied: Object = Object.assign( 3 | Object.create( 4 | Object.getPrototypeOf(original) 5 | ), 6 | original 7 | ); 8 | 9 | return copied; 10 | } -------------------------------------------------------------------------------- /lib/types.d.ts: -------------------------------------------------------------------------------- 1 | declare module '@dynamic-pkg/bare-client'; 2 | declare module '@dynamic-pkg/acorn'; 3 | declare module '@dynamic-pkg/astring'; 4 | declare module '@dynamic-pkg/cookie'; 5 | declare module '@dynamic-pkg/mime'; 6 | declare module '@dynamic-pkg/base64'; 7 | declare module '@dynamic-pkg/mutation'; -------------------------------------------------------------------------------- /lib/global/util/class.ts: -------------------------------------------------------------------------------- 1 | export default function Class(obj: any) { 2 | try { 3 | new (new Proxy(obj, { construct: () => ({}) })); 4 | 5 | if (!Object.getOwnPropertyNames(obj).includes('arguments')) throw new Error(""); 6 | 7 | return true; 8 | } catch (err) { 9 | return false; 10 | } 11 | }; -------------------------------------------------------------------------------- /lib/global/meta/load.ts: -------------------------------------------------------------------------------- 1 | import DynamicMeta from "../meta"; 2 | 3 | declare const self: any; 4 | 5 | export default function loadMeta(this: DynamicMeta | any, url: URL | any) { 6 | url = new URL(url.href); 7 | 8 | for (var prop in url) { 9 | this.ctx.meta[prop] = url[prop]; 10 | } 11 | 12 | return true; 13 | } -------------------------------------------------------------------------------- /lib/global/is/css.ts: -------------------------------------------------------------------------------- 1 | import DynamicTypeFunctions from "../istype"; 2 | import MetaURL from "../meta/type"; 3 | 4 | export default function css(this: DynamicTypeFunctions, url: MetaURL, contentType: string = '') { 5 | return (this.ctx.modules.mime.contentType((contentType || url.pathname)) || 'text/css').split(';')[0] === 'text/css'; 6 | } -------------------------------------------------------------------------------- /lib/global/rewrite/js/type/Property.ts: -------------------------------------------------------------------------------- 1 | // why am i doing this 2 | 3 | import { Node } from "../types"; 4 | 5 | export default function Property(node: Node, parent: Node = {} as any) { 6 | if (node.parent.type == "ObjectPattern") return; 7 | if (node.parent?.parent?.type == "AssignmentExpression") return; 8 | 9 | node.shorthand = false; 10 | } -------------------------------------------------------------------------------- /lib/global/rewrite/js/type/VariableDeclaractor.ts: -------------------------------------------------------------------------------- 1 | import { Node } from "../types"; 2 | 3 | export default function VariableDeclarator(node: Node, parent: Node = {} as any) { 4 | if (node.id.type !== 'Identifier') return false; 5 | if (node.id.__dynamic === true) return; 6 | 7 | if (node.id.name == 'location') return;// node.id.name = '__dynamic$location'; 8 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "./dist/", 4 | "noImplicitAny": true, 5 | "module": "ESNext", 6 | "target": "es6", 7 | "forceConsistentCasingInFileNames": true, 8 | "jsx": "react", 9 | "moduleResolution": "node", 10 | "strict": true 11 | }, 12 | "include": ["./lib/**/*"], 13 | "exclude": ["node_modules"] 14 | } -------------------------------------------------------------------------------- /lib/global/cookie/parse.ts: -------------------------------------------------------------------------------- 1 | import { Cookie } from "set-cookie-parser"; 2 | 3 | export const parse = (str: string) => 4 | str ? str.split(';').map((v: string) => v.split('=')).reduce((acc: any, v: any) => {acc[(v[0].trim())] = (v[1].trim()); return acc; }, {}) : {}; 5 | export const serialize = (obj: Array = []) => 6 | obj.map((k) => `${k.name}=${(k.value)}`).join('; '); -------------------------------------------------------------------------------- /lib/global/meta.ts: -------------------------------------------------------------------------------- 1 | import { DynamicBundle } from './client'; 2 | import load from './meta/load'; 3 | import MetaURL from './meta/type'; 4 | 5 | class DynamicMeta extends MetaURL { 6 | load: Function = load; 7 | 8 | ctx: DynamicBundle; 9 | 10 | constructor(ctx: DynamicBundle) { 11 | super(); 12 | this.ctx = ctx; 13 | } 14 | } 15 | 16 | export default DynamicMeta; -------------------------------------------------------------------------------- /lib/global/meta/type.ts: -------------------------------------------------------------------------------- 1 | export default class MetaURL { 2 | host: string | any; 3 | hostname: string | any; 4 | origin: string | any; 5 | pathname: string | any; 6 | search: string | any; 7 | protocol: string | any; 8 | port: string | any; 9 | href: string | any; 10 | hash: string | any; 11 | referrer: string | undefined; 12 | 13 | constructor() {}; 14 | } -------------------------------------------------------------------------------- /lib/global/http.ts: -------------------------------------------------------------------------------- 1 | import { DynamicBundle } from './client'; 2 | import Request from './http/request'; 3 | import Response from './http/response'; 4 | 5 | class DynamicHttp { 6 | Request = Request; 7 | Response = Response; 8 | 9 | ctx: DynamicBundle; 10 | 11 | constructor(ctx: DynamicBundle) { 12 | this.ctx = ctx; 13 | } 14 | } 15 | 16 | export default DynamicHttp; -------------------------------------------------------------------------------- /lib/global/url.ts: -------------------------------------------------------------------------------- 1 | import Encode from './url/encode'; 2 | import Decode from './url/decode'; 3 | import { DynamicBundle } from './bundle'; 4 | 5 | class DynamicUrlRewriter { 6 | encode: Function = Encode; 7 | decode: Function = Decode; 8 | 9 | ctx: DynamicBundle; 10 | 11 | constructor(ctx: DynamicBundle) { 12 | this.ctx = ctx; 13 | } 14 | } 15 | 16 | export default DynamicUrlRewriter; -------------------------------------------------------------------------------- /lib/global/util/about.ts: -------------------------------------------------------------------------------- 1 | export default class about { 2 | rawHeaders = {}; 3 | headers = new Headers({}); 4 | status = 200; 5 | statusText = 'OK'; 6 | 7 | body: Blob; 8 | 9 | constructor(blob: Blob) { 10 | this.body = blob; 11 | } 12 | 13 | async blob() { 14 | return this.body; 15 | } 16 | 17 | async text() { 18 | return await this.body.text(); 19 | } 20 | } -------------------------------------------------------------------------------- /lib/global/istype.ts: -------------------------------------------------------------------------------- 1 | import { DynamicBundle } from "./client"; 2 | import css from "./is/css"; 3 | import html from "./is/html"; 4 | import js from "./is/js"; 5 | 6 | class DynamicTypeFunctions { 7 | html: Function = html; 8 | js: Function = js; 9 | css: Function = css; 10 | 11 | ctx: DynamicBundle; 12 | 13 | constructor(ctx: DynamicBundle) { 14 | this.ctx = ctx; 15 | } 16 | } 17 | 18 | export default DynamicTypeFunctions; -------------------------------------------------------------------------------- /docs/examples/uv-dynamic-multi/uv/uv.config.js: -------------------------------------------------------------------------------- 1 | /*global Ultraviolet*/ 2 | self.__uv$config = { 3 | prefix: '/service/uv/', 4 | bare: 'https:///', 5 | encodeUrl: Ultraviolet.codec.plain.encode, 6 | decodeUrl: Ultraviolet.codec.plain.decode, 7 | handler: '/dist/uv.handler.js', 8 | client: '/dist/uv.client.js', 9 | bundle: '/dist/uv.bundle.js', 10 | config: '/dist/uv.config.js', 11 | sw: '/dist/uv.sw.js', 12 | }; 13 | -------------------------------------------------------------------------------- /lib/global/regex.ts: -------------------------------------------------------------------------------- 1 | import { DynamicBundle } from "./client"; 2 | 3 | const BypassRegex = /^(#|about:|mailto:|blob:|javascript:)/g; 4 | const DataRegex = /^data:([a-z\/A-Z0-9\-\+]+);?(charset\=[\-A-Za-z0-9]+)?;?(base64)?[;,]*(.*)/g; 5 | const WeirdRegex = /^([\/A-Za-z0-9\-%]+)(http[s]?:\/\/.*)/g 6 | 7 | export default class DynamicRegex { ctx: DynamicBundle; constructor(ctx: DynamicBundle) {this.ctx = ctx;}; BypassRegex: RegExp = BypassRegex; DataRegex: RegExp = DataRegex; WeirdRegex: RegExp = WeirdRegex; }; -------------------------------------------------------------------------------- /lib/global/is/js.ts: -------------------------------------------------------------------------------- 1 | import DynamicTypeFunctions from "../istype"; 2 | import MetaURL from "../meta/type"; 3 | 4 | export default function js(this: DynamicTypeFunctions, url: MetaURL, contentType: string = '') { 5 | if (url.pathname.endsWith('.js')&&contentType=='text/plain') return true; 6 | var type = (this.ctx.modules.mime.contentType((contentType || url.pathname)) || 'application/javascript').split(';')[0]; 7 | return type=='text/javascript'||type=='application/javascript'||type=='application/x-javascript'; 8 | } -------------------------------------------------------------------------------- /static/sw.js: -------------------------------------------------------------------------------- 1 | importScripts('/dynamic/dynamic.config.js'); 2 | importScripts('/dynamic/dynamic.worker.js'); 3 | 4 | const dynamic = new Dynamic(); 5 | 6 | self.dynamic = dynamic; 7 | 8 | self.addEventListener('fetch', 9 | event => { 10 | event.respondWith( 11 | (async function() { 12 | if (await dynamic.route(event)) { 13 | return await dynamic.fetch(event); 14 | } 15 | 16 | return await fetch(event.request); 17 | })() 18 | ); 19 | } 20 | ); -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "npm" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "daily" 12 | -------------------------------------------------------------------------------- /lib/global/util/rewritePath.ts: -------------------------------------------------------------------------------- 1 | import MetaURL from "../meta/type"; 2 | import DynamicUtil from "../util"; 3 | 4 | export default function rewritePath(this: DynamicUtil, request: Request, client: Object | any, meta: MetaURL | URL) { 5 | if (!request.url.startsWith('http')) return request.url; 6 | 7 | let url: any = request.url.toString(); 8 | 9 | if (request.url.startsWith(location.origin)) url = url.substr(self.location.origin.length); 10 | 11 | url = new URL(url, new URL(client.__dynamic$location.href)).href; 12 | 13 | return this.ctx.url.encode(url, meta); 14 | } -------------------------------------------------------------------------------- /lib/global/client/methods/document/write.ts: -------------------------------------------------------------------------------- 1 | export default function write(self: any) { 2 | function handler(this: Document, handler: Function, ...args: Array): undefined { 3 | for (var arg in args) { 4 | args[arg] = self.__dynamic.rewrite.dom(args[arg], self.__dynamic.meta); 5 | } 6 | 7 | return handler.apply(this, args); 8 | }; 9 | 10 | ["write", "writeln"].forEach(method => { 11 | self.document[method] = self.__dynamic.wrap(self.document[method], 12 | handler, 13 | `document.${method}` 14 | ); 15 | }); 16 | } -------------------------------------------------------------------------------- /lib/global/util/encode.ts: -------------------------------------------------------------------------------- 1 | import DynamicUtil from "../util"; 2 | 3 | export default function encode(this: DynamicUtil, self: Window | any) { 4 | var obj = this.ctx.encoding; 5 | 6 | if (typeof this.ctx.config.encoding == 'object') { 7 | obj = { 8 | ...obj, 9 | ...this.ctx.encoding, 10 | } 11 | } else { 12 | obj = { 13 | ...this.ctx.encoding[this.ctx.config.encoding], 14 | } 15 | } 16 | 17 | this.ctx.encoding = { 18 | ...this.ctx.encoding, 19 | ...obj, 20 | } 21 | 22 | return this.ctx.encoding; 23 | } -------------------------------------------------------------------------------- /lib/global/rewrite/css.ts: -------------------------------------------------------------------------------- 1 | import MetaURL from "../meta/type"; 2 | import DynamicRewrites from "../rewrite"; 3 | 4 | export default class css { 5 | 6 | ctx; 7 | 8 | constructor(ctx: DynamicRewrites) { 9 | this.ctx = ctx.ctx; 10 | } 11 | 12 | rewrite(this: css, src: string | URL, meta: MetaURL, config: Object = {}) { 13 | if (!src) return src; 14 | 15 | return src.toString().replace(/(?:@import\s?|url\(?)['"]?(.*?)['")]/gmi, (...args) => { 16 | try { 17 | return args[0].replace(args[3], this.ctx.url.encode(args[3], meta)); 18 | } catch {return args[0];} 19 | }); 20 | } 21 | } -------------------------------------------------------------------------------- /lib/global/rewrite/js/object/Eval.ts: -------------------------------------------------------------------------------- 1 | import { Node } from "../types"; 2 | 3 | export default function Eval(node: Node, parent: Node = {} as any) { 4 | if (node.__dynamic) return; 5 | 6 | if (node.arguments.length) { 7 | node.arguments = [{ 8 | type: 'CallExpression', 9 | callee: { 10 | type: 'Identifier', 11 | name: '__dynamic$wrapEval', 12 | __dynamic: true, 13 | }, 14 | arguments: node.arguments, 15 | __dynamic: true, 16 | }] as Array; 17 | 18 | node.__dynamic = true; 19 | } 20 | 21 | return; 22 | } -------------------------------------------------------------------------------- /lib/dynamic.config.js: -------------------------------------------------------------------------------- 1 | // See documentation for more information 2 | 3 | self.__dynamic$config = { 4 | prefix: '/service/', 5 | encoding: 'xor', 6 | mode: 'production', 7 | logLevel: 0, 8 | bare: { 9 | version: 2, 10 | path: '/bare/', 11 | }, 12 | tab: { 13 | title: 'Service', 14 | icon: null, 15 | ua: null, 16 | }, 17 | assets: { 18 | prefix: '/dynamic/', 19 | files: { 20 | handler: 'dynamic.handler.js', 21 | client: 'dynamic.client.js', 22 | worker: 'dynamic.worker.js', 23 | config: 'dynamic.config.js', 24 | inject: null, 25 | } 26 | }, 27 | block: [ 28 | 29 | ] 30 | }; 31 | -------------------------------------------------------------------------------- /lib/global/rewrite/js/object/PostMessage.ts: -------------------------------------------------------------------------------- 1 | import { Node } from "../types"; 2 | 3 | export default function PostMessage(node: Node, parent: Node = {} as any) { 4 | Object.entries({ 5 | type: 'CallExpression', 6 | callee: { 7 | type: 'MemberExpression', 8 | object: {type: 'Identifier', name: 'self'}, 9 | property: {type: 'Identifier', name: '__dynamic$message'}, 10 | }, 11 | arguments: [ 12 | node.object||node, 13 | {type: 'Identifier', name: 'self', __dynamic: true} 14 | ] 15 | }).forEach(([name,value]) => (node as any)[name] = value) 16 | 17 | return; 18 | } -------------------------------------------------------------------------------- /lib/global/client/methods/window/policy.ts: -------------------------------------------------------------------------------- 1 | export default function policy(self: Window | any) { 2 | // This breaks Google Login 3 | 4 | /*self.TrustedTypePolicy.prototype.createScript = self.__dynamic.wrap(self.TrustedTypePolicy.prototype.createScript, 5 | function(this: any, target: Function, ...args: Array) { 6 | let script = Reflect.apply(target, this, [...args]); 7 | 8 | script = self.__dynamic.rewrite.js.rewrite(script.toString(), {type: 'module'}, false, self.__dynamic); 9 | 10 | return self.__dynamic.trustedTypes.createScript.call(self.__dynamic.trustedTypes.policy, script); 11 | } 12 | );*/ 13 | } -------------------------------------------------------------------------------- /lib/global/is/html.ts: -------------------------------------------------------------------------------- 1 | import DynamicTypeFunctions from "../istype"; 2 | import MetaURL from "../meta/type"; 3 | 4 | export default function html(this: DynamicTypeFunctions, url: MetaURL, contentType: String = '', html: String = '') { 5 | let a; 6 | if (!contentType && this.ctx.modules.mime.contentType(url.pathname) == url.pathname) return html.trim().match(/<(html|script|body)[^>]*>/g) && !!(a = html.trim().indexOf((html.trim().match(/<(html|script|body)[^>]*>/g)||[])[0] as any), a > -1 && a < 100); 7 | return (this.ctx.modules.mime.contentType((contentType || url.pathname)) || 'text/html').split(';')[0] === 'text/html'||html.trim().match(/\<\!(doctype|DOCTYPE) html\>/g); 8 | }; -------------------------------------------------------------------------------- /lib/global/rewrite/html/srcset.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | encode(val: string | undefined, dynamic: Object | any) { 3 | if (!val) return val; 4 | if (!(val.toString())) return val; 5 | 6 | return val.split(', ').map((s: any) => { 7 | return s.split(' ').map((e: any,i: any)=>{ 8 | if (i == 0) { 9 | return dynamic.url.encode(e, dynamic.baseURL || dynamic.meta); 10 | } 11 | 12 | return e; 13 | }).join(' '); 14 | }).join(', '); 15 | }, 16 | decode(val: string | undefined) { 17 | if (!val) return val; 18 | 19 | return val; 20 | }, 21 | } -------------------------------------------------------------------------------- /docs/configuration/modes.md: -------------------------------------------------------------------------------- 1 | # Performance modes 2 | Dynamic provides two performance options to fit your needs. 3 | 4 | ## Development 5 | 6 | When you set your performance mode to `development`, Dynamic will not cache itself or minify at all. 7 | 8 | This mode is recommended when: 9 | * Creating middleware with the Dynamic API 10 | * Testing features that require debugging 11 | 12 | ## Production 13 | 14 | When you set your performance mode to `production`, Dynamic will cache its bundle and configuration file. This is Dynamics peak performance mode. 15 | 16 | This mode is recommended when: 17 | * Production or public use is intended 18 | * When speed is priority over middleware updates. 19 | -------------------------------------------------------------------------------- /lib/global/rewrite.ts: -------------------------------------------------------------------------------- 1 | import html from './rewrite/html/html'; 2 | import css from './rewrite/css'; 3 | import js from './rewrite/js/js'; 4 | import man from './rewrite/manifest'; 5 | import srcset from './rewrite/html/srcset'; 6 | import { DynamicBundle } from './client'; 7 | 8 | class DynamicRewrites { 9 | 10 | html: html; 11 | srcset; 12 | js: js; 13 | css: css; 14 | man: man; 15 | ctx: DynamicBundle; 16 | 17 | constructor(ctx: DynamicBundle) { 18 | this.ctx = ctx; 19 | this.html = new html(this); 20 | this.srcset = srcset; 21 | this.js = new js(this); 22 | this.css = new css(this); 23 | this.man = new man(this); 24 | } 25 | } 26 | 27 | export default DynamicRewrites; -------------------------------------------------------------------------------- /lib/global/rewrite/js/type/AssignmentExpression.ts: -------------------------------------------------------------------------------- 1 | import Eval from '../object/Eval'; 2 | import PostMessage from '../object/PostMessage'; 3 | import { Node } from '../types'; 4 | 5 | export default function AssignmentExpression(node: Node, parent: Node = {} as any) { 6 | if (node.left.type == 'Identifier') { 7 | if (node.left.__dynamic === true) return; 8 | 9 | if (node.left.name == 'location') { 10 | var ol = structuredClone(node.left), or = structuredClone(node.right); 11 | node.right.type = 'CallExpression'; 12 | node.right.callee = {type: 'Identifier', name: 'ds$'} as Node; 13 | node.right.arguments = [ol, or]; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /lib/global/client/methods/window/history.ts: -------------------------------------------------------------------------------- 1 | export default function history(self: Window | any) { 2 | self.__dynamic$history = function(this: History, target: Function, ...args: Array): void { 3 | if (args[2]) args[2] = self.__dynamic.url.encode(args[2], self.__dynamic.meta); 4 | 5 | self.__dynamic.Reflect.apply(target, this, args) as undefined; 6 | 7 | self.__dynamic.client.location(self, true, false); 8 | 9 | return; 10 | } 11 | 12 | self.History.prototype.pushState = self.__dynamic.wrap(self.History.prototype.pushState, self.__dynamic$history); 13 | self.History.prototype.replaceState = self.__dynamic.wrap(self.History.prototype.replaceState, self.__dynamic$history); 14 | } -------------------------------------------------------------------------------- /lib/global/headers.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | csp: [ 3 | 'cross-origin-embedder-policy', 4 | 'cross-origin-opener-policy', 5 | 'cross-origin-resource-policy', 6 | 'content-security-policy', 7 | 'content-security-policy-report-only', 8 | 'expect-ct', 9 | 'feature-policy', 10 | 'origin-isolation', 11 | 'strict-transport-security', 12 | 'upgrade-insecure-requests', 13 | 'x-content-type-options', 14 | 'x-frame-options', 15 | 'x-permitted-cross-domain-policies', 16 | 'x-xss-protection', 17 | ], 18 | status: { 19 | empty: [204, 101, 205, 304], 20 | }, 21 | method: { 22 | body: ['GET', 'HEAD'], 23 | } 24 | } -------------------------------------------------------------------------------- /lib/global/rewrite/js/type/ThisExpression.ts: -------------------------------------------------------------------------------- 1 | import Eval from '../object/Eval'; 2 | import PostMessage from '../object/PostMessage'; 3 | import { Node } from '../types'; 4 | 5 | export default function CallExpression(node: Node, parent: Node = {} as any) { 6 | if (node.go === false) return; 7 | 8 | if (parent.type == 'CallExpression' && parent.arguments.includes(node)) return; 9 | 10 | if (parent.type !== "SequenceExpression" && parent.type !== "VariableDeclarator") return; 11 | 12 | node.type = 'CallExpression'; 13 | node.callee = {type: 'Identifier', name: 'dg$', __dynamic: true} as Node; 14 | node.__dynamic = true; 15 | node.arguments = [{type: 'ThisExpression', go: false, __dynamic: true}] as Array; 16 | } -------------------------------------------------------------------------------- /lib/global/rewrite/js/process.ts: -------------------------------------------------------------------------------- 1 | import DynamicRewrites from "../../rewrite"; 2 | import js from "./js"; 3 | 4 | export default function process(this: js, src: string, config: Object | any = {}, ctx: any, dynamic: Object | any) { 5 | var ast = this.ctx.modules.acorn.parse(src.toString(), { sourceType: config.module ? 'module' : 'script', allowImportExportEverywhere: true, allowAwaitOutsideFunction: true, allowReturnOutsideFunction: true, ecmaVersion: "latest", preserveParens: false, loose: true, allowReserved: true }); 6 | 7 | this.iterate(ast, (node: any, parent: any = null) => { 8 | this.emit(node, node.type, parent, ctx, dynamic, config); 9 | }); 10 | 11 | src = this.ctx.modules.estree.generate(ast); 12 | 13 | return src; 14 | } 15 | -------------------------------------------------------------------------------- /lib/global/client/methods/window/blob.ts: -------------------------------------------------------------------------------- 1 | export default function blob(self: Window | any) { 2 | self.__dynamic.createBlobHandler = async function (blob: Blob, element: HTMLIFrameElement, val: string): Promise { 3 | const sw: ServiceWorker = (await self.__dynamic.sw.ready).active; 4 | 5 | self.__dynamic.sw.addEventListener('message', ({ data: {url} }: MessageEvent) => { 6 | if (url) { 7 | self.__dynamic.elements.iframeSrc.set.call(element, url); 8 | } 9 | }, {once: true}); 10 | 11 | sw.postMessage({type: "createBlobHandler", blob, url: self.__dynamic.modules.base64.encode(val.toString().split('').slice(0, 10)), location: self.__dynamic.location.href}); 12 | 13 | return; 14 | } 15 | } -------------------------------------------------------------------------------- /docs/configuration/logging.md: -------------------------------------------------------------------------------- 1 | # Developer console logging 2 | // 0: none, 1: errors, 2: errors + warnings, 3: errors + warnings + info 3 | Dynamic gives you the option to choose what kind of logs are allowed to appear in the Developer console found in the inspect element menu. 4 | 5 | ## No logging 6 | For absolutely no logging, change the value in your configuration to `0` 7 | 8 | ## Errors only 9 | If you only want errors in console, but want to ignore warnings, this is the level for you! Turn the value in your configuration to `1` 10 | 11 | ## Indecisive 12 | Looking for both Errors and Warnings? Change the value in your configuration to `2` 13 | 14 | ## The everything burger 15 | Exactly what it sounds like, errors + warnings + info. Set the value in your configuration to `2` 16 | -------------------------------------------------------------------------------- /lib/global/client/methods/window/navigator.ts: -------------------------------------------------------------------------------- 1 | export default function navigator(self: Window | any) { 2 | if ('serviceWorker' in self.navigator) { 3 | self.__dynamic.sw = self.navigator.serviceWorker; 4 | 5 | delete self.navigator.serviceWorker; 6 | delete self.Navigator.prototype.serviceWorker; 7 | } 8 | 9 | self.navigator.sendBeacon = self.__dynamic.wrap(self.navigator.sendBeacon, 10 | function(this: Navigator, target: Function, ...args: Array): Boolean { 11 | if (args[0]) { 12 | args[0] = self.__dynamic.url.encode(args[0], self.__dynamic.meta); 13 | } 14 | 15 | return Reflect.apply(target, this, args) as boolean; 16 | }, 17 | 'navigator.sendBeacon' 18 | ); 19 | } -------------------------------------------------------------------------------- /docs/configuration/bare.md: -------------------------------------------------------------------------------- 1 | # Bare version and path 2 | 3 | 4 | You might have noticed this setting in your configuration file: 5 | ```js 6 | bare: { 7 | version: 2, 8 | path: '/bare/', 9 | }, 10 | ``` 11 | This is refering to the Bare endpoint that Dynamic uses. The version is what Dynamic concatonates to the path. It will finally look something like `/path/version/`. There are differences in the versions. Details on the specification can be found here: 12 | 13 | * v1: https://github.com/tomphttp/specifications/blob/master/BareServerV1.md 14 | * v2: https://github.com/tomphttp/specifications/blob/master/BareServerV2.md 15 | * v3: https://github.com/tomphttp/specifications/blob/master/BareServerV3.md 16 | 17 | ## Unsupported versions. 18 | Dynamic does not have stable support v3 as of now. -------------------------------------------------------------------------------- /lib/global/rewrite/js/type/Literal.ts: -------------------------------------------------------------------------------- 1 | import Eval from '../object/Eval'; 2 | import PostMessage from '../object/PostMessage'; 3 | import { Node } from '../types'; 4 | 5 | export default function Literal(node: Node, parent: Node = {} as any) { 6 | if (!((node.value as any) instanceof String)) return false; 7 | 8 | if (node.value==('__dynamic')) node.value = 'undefined'; 9 | 10 | if (!['location', 'parent', 'top', 'postMessage'].includes(node.value)) return false; 11 | 12 | if (node.value=='postMessage' && parent.type != 'AssignmentExpression' && parent.left != node) PostMessage(node, parent); 13 | if (node.value=='location') node.value = '__dynamic$location'; 14 | if (node.value=='__dynamic') node.value = 'undefined'; 15 | if (node.value=='eval') node.value = '__dynamic$eval'; 16 | } -------------------------------------------------------------------------------- /lib/global/modules.ts: -------------------------------------------------------------------------------- 1 | import mime from '@dynamic-pkg/mime'; 2 | import * as path from 'path-browserify'; 3 | import * as idb from 'idb'; 4 | import { parse } from 'acorn'; 5 | import { BareClient, createBareClient } from '@tomphttp/bare-client'; 6 | import * as cookie from 'cookie'; 7 | import { parse as cookieParser } from 'set-cookie-parser' 8 | import { generate } from 'astring'; 9 | 10 | class DynamicModules { 11 | mime = mime; 12 | idb = idb; 13 | path = path; 14 | acorn = { parse }; 15 | bare = {createBareClient, BareClient}; 16 | base64 = { encode: btoa, decode: atob }; 17 | estree = { generate }; 18 | cookie = cookie; 19 | setCookieParser = cookieParser; 20 | 21 | ctx; 22 | 23 | constructor(ctx:any) { 24 | this.ctx = ctx; 25 | } 26 | } 27 | 28 | export default DynamicModules; -------------------------------------------------------------------------------- /static/resources/scripts/notice.js: -------------------------------------------------------------------------------- 1 | const delay = ms => new Promise(res => setTimeout(res, ms)); 2 | 3 | 4 | async function greet(){ 5 | const style = 'background-color: black; color: white; font-style: italic; border: 5px solid red; font-size: 2em; margin-top: -12px;' 6 | let visited = localStorage.getItem('visited') 7 | await delay(500); 8 | console.log("%cPlease, do not put anything in this developer console. You risk your data.", style) 9 | await delay(500); 10 | if (!visited) { 11 | console.log('showing warning') 12 | alert('Hello! Thanks for using Dynamic.\nPlease be aware that this is a public beta version of Dynamic. Please report bugs to our GitHub issues page :)\n\n(we will only show you this announcement once.)') 13 | } 14 | localStorage.setItem("visited", "true") 15 | } 16 | greet() -------------------------------------------------------------------------------- /docs/examples/uv-dynamic-multi/resources/scripts/notice.js: -------------------------------------------------------------------------------- 1 | const delay = ms => new Promise(res => setTimeout(res, ms)); 2 | 3 | 4 | async function greet(){ 5 | const style = 'background-color: black; color: white; font-style: italic; border: 5px solid red; font-size: 2em;' 6 | let visited = localStorage.getItem('visited') 7 | await delay(500); 8 | console.log("%cPlease, do not put anything in this developer console. You risk your data.", style) 9 | await delay(500); 10 | if (!visited) { 11 | console.log('showing warning') 12 | alert('Hello! Thanks for using Dynamic.\nPlease be aware that this is a public beta version of Dynamic. Please report bugs to our GitHub issues page :)\n\n(we will only show you this announcement once.)') 13 | } 14 | localStorage.setItem("visited", "true") 15 | } 16 | greet() -------------------------------------------------------------------------------- /docs/examples/uv-dynamic-multi/dynamic/dynamic.config.js: -------------------------------------------------------------------------------- 1 | self.__dynamic$config = { 2 | prefix: '/service/', 3 | encoding: 'xor', 4 | mode: 'production', // development: zero caching, no minification, production: speed-oriented 5 | logLevel: 0, // 0: none, 1: errors, 2: errors + warnings, 3: errors + warnings + info 6 | bare: { 7 | version: 2, // v3 is bad 8 | path: '/bare/', 9 | }, 10 | tab: { 11 | title: 'Service', 12 | icon: null, 13 | ua: null, 14 | }, 15 | assets: { 16 | prefix: '/dynamic/', 17 | files: { 18 | handler: 'dynamic.handler.js', 19 | client: 'dynamic.client.js', 20 | worker: 'dynamic.worker.js', 21 | config: 'dynamic.config.js', 22 | inject: null, 23 | } 24 | }, 25 | block: [ 26 | 27 | ] 28 | }; -------------------------------------------------------------------------------- /lib/handler/index.ts: -------------------------------------------------------------------------------- 1 | import { DynamicBundle } from '../global/client'; 2 | importScripts('/dynamic/dynamic.config.js'); 3 | 4 | import init from '../global/client/methods/init'; 5 | import wrap from '../global/client/methods/wrap'; 6 | 7 | (function(self: Window | any) { 8 | const __dynamic: DynamicBundle = new DynamicBundle(self.__dynamic$config); 9 | self.__dynamic = __dynamic; 10 | 11 | const __dynamic$baseURL: string = __dynamic.url.decode(location.pathname); 12 | 13 | __dynamic.meta.load(new URL(__dynamic$baseURL)); 14 | 15 | init(self, null), wrap(self); 16 | 17 | __dynamic.client.message(self); 18 | __dynamic.client.location(self, false); 19 | __dynamic.client.window(self); 20 | __dynamic.client.get(self); 21 | __dynamic.client.reflect(self); 22 | __dynamic.client.imports(self); 23 | __dynamic.client.blob(self); 24 | })(self); -------------------------------------------------------------------------------- /lib/global/http/request.ts: -------------------------------------------------------------------------------- 1 | export default class DynamicRequest { 2 | headers: Headers = new Headers({}); 3 | redirect: String = 'manual'; 4 | body: Blob | ReadableStream | null = null; 5 | method: String = 'GET'; 6 | 7 | url: URL | String; 8 | 9 | constructor(url: URL | String = '', init: Request | undefined = new Request('')) { 10 | if (init.headers) this.headers = init.headers; 11 | if (init.redirect) this.redirect = init.redirect; 12 | if (init.body) this.body = init.body; 13 | this.method = init.method || 'GET'; 14 | 15 | this.url = new String(url); 16 | } 17 | 18 | get init() { 19 | return { 20 | headers: this.headers || new Headers({}), 21 | redirect: this.redirect || 'manual', 22 | body: this.body || null, 23 | method: this.method || 'GET', 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /lib/global/client/methods/window/imports.ts: -------------------------------------------------------------------------------- 1 | export default function imports(self: any) { 2 | self.importScripts = new Proxy(self.importScripts, { 3 | apply(t, g, a: Array): void { 4 | [...a].forEach((url, index) => { 5 | a[index] = self.__dynamic.url.encode(url, self.__dynamic.meta); 6 | }); 7 | 8 | return Reflect.apply(t, g, a); 9 | } 10 | }); 11 | 12 | self.__dynamic.define(self.__dynamic, '_location', { 13 | value: self.location as Location, 14 | writable: true 15 | }); 16 | 17 | self.__dynamic.define(self.WorkerGlobalScope.prototype, 'location', { 18 | get(): Location { 19 | return self.__dynamic.location; 20 | }, 21 | set(value: string): string { 22 | return value; 23 | } 24 | }); 25 | 26 | self.location = self.__dynamic.location; 27 | } -------------------------------------------------------------------------------- /docs/examples/uv-dynamic-multi/sw.js: -------------------------------------------------------------------------------- 1 | importScripts('/dynamic/dynamic.config.js'); 2 | importScripts('/dynamic/dynamic.worker.js'); 3 | importScripts('dist/uv.bundle.js'); 4 | importScripts('dist/uv.config.js'); 5 | importScripts(__uv$config.sw || 'dist/uv.sw.js'); 6 | 7 | const uv = new UVServiceWorker(); 8 | const dynamic = new Dynamic(); 9 | 10 | self.dynamic = dynamic; 11 | 12 | self.addEventListener('fetch', 13 | event => { 14 | event.respondWith( 15 | (async function() { 16 | if (await dynamic.route(event)) { 17 | return await dynamic.fetch(event); 18 | } 19 | 20 | if (event.request.url.startsWith(location.origin + "/service/uv/")) { 21 | return await uv.fetch(event); 22 | } 23 | 24 | return await fetch(event.request); 25 | })() 26 | ); 27 | } 28 | ); -------------------------------------------------------------------------------- /lib/global/rewrite/js/iterate.ts: -------------------------------------------------------------------------------- 1 | export default function Iterate(ast: Object, handler: Function) { 2 | if (typeof ast != 'object' || !handler) return; 3 | walk(ast, null, handler); 4 | function walk(node: Object | any, parent: Object | null, handler: Function) { 5 | if (typeof node != 'object' || !handler) return; 6 | node.parent = parent; 7 | handler(node, parent, handler); 8 | for (const child in node) { 9 | if (child === 'parent') continue; 10 | if (Array.isArray(node[child])) { 11 | node[child].forEach((entry: Object | undefined) => { 12 | if (entry) walk(entry, node, handler) 13 | }); 14 | } else { 15 | if (node[child]) walk(node[child], node, handler); 16 | }; 17 | }; 18 | if (typeof node.iterateEnd === 'function') node.iterateEnd(); 19 | }; 20 | }; -------------------------------------------------------------------------------- /lib/global/http/response.ts: -------------------------------------------------------------------------------- 1 | export default class DynamicResponse extends Response { 2 | status: number = 200; 3 | body: ReadableStream | null; 4 | statusText: string = 'OK'; 5 | headers: Headers = new Headers({}); 6 | 7 | constructor(body: string | ReadableStream = '', init: Response | undefined = new Response('')) { 8 | super(body, init) 9 | 10 | this.body = body as ReadableStream; 11 | 12 | if (init.status) this.status = init.status; 13 | if (init.statusText) this.statusText = init.statusText; 14 | if (init.headers) this.headers = init.headers; 15 | } 16 | 17 | get init() { 18 | return { 19 | headers: this.headers || new Headers({}), 20 | statusText: this.statusText || 200, 21 | body: this.body || new Blob([]), 22 | status: this.statusText || 'OK', 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /lib/global/rewrite/js/type/Imports.ts: -------------------------------------------------------------------------------- 1 | import Eval from '../object/Eval'; 2 | import PostMessage from '../object/PostMessage'; 3 | import { Node } from '../types'; 4 | 5 | export default function Imports(node: Node, parent: Node = {} as any, ctx: Object | any = {}, dynamic: Object | any = {}) { 6 | if (node.type=='Literal'&&(parent.type=='ImportDeclaration'||parent.type=='ExportNamedDeclaration'||parent.type=='ExportAllDeclaration')) { 7 | var og = node.value + ''; 8 | node.value = ctx.url.encode(node.value, dynamic.meta); 9 | node.raw = node.raw.replace(og, node.value); 10 | node.__dynamic = true; 11 | } 12 | 13 | if (node.type=='ImportExpression') { 14 | node.source = {type: 'CallExpression', callee: {type: 'Identifier', name: '__dynamic$import'}, arguments: [node.source, {type: 'Literal', __dynamic: true, value: ctx.meta.href}]} as Node; 15 | node.__dynamic = true; 16 | } 17 | } -------------------------------------------------------------------------------- /lib/global/util/edit.ts: -------------------------------------------------------------------------------- 1 | declare const self: any; 2 | 3 | export default async function Edit(req: Request) { 4 | let request: Response; 5 | 6 | if (self.__dynamic$config.mode !== 'development') { 7 | var cache = await caches.open('__dynamic$files'); 8 | 9 | if (!cache) request = await fetch(req); 10 | else 11 | request = await cache.match(req.url) || await fetch(req); 12 | } else request = await fetch(req); 13 | let text = await request.blob(); 14 | 15 | if (req.url.startsWith(location.origin + '/dynamic/dynamic.config.js') || req.url.startsWith(location.origin + '/dynamic/dynamic.client.js')) { 16 | text = new Blob([`${await text.text()}\nself.document?.currentScript?.remove();`], {type: 'application/javascript'}); 17 | } 18 | 19 | return new Response(text, { 20 | headers: request.headers, 21 | status: request.status, 22 | statusText: request.statusText 23 | }); 24 | } -------------------------------------------------------------------------------- /docs/examples/uv-dynamic-multi/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dynamic 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |

Dynamic

16 |
17 | 18 |
19 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /lib/global/client/methods/window/worker.ts: -------------------------------------------------------------------------------- 1 | export default function worker(self: any) { 2 | const XHR = self.XMLHttpRequest; 3 | 4 | self.Worker = new Proxy(self.Worker, { 5 | construct(t: Function, a: Array): Worker { 6 | if (a[0]) { 7 | a[0] = a[0].toString(); 8 | if (a[0].trim().startsWith(`blob:${self.location.origin}`)) { 9 | const xhr: XMLHttpRequest = new XHR; 10 | xhr.open('GET', a[0], false); 11 | xhr.send(); 12 | const script: string = self.__dynamic.rewrite.js.rewrite(xhr.responseText, { type: 'worker' }, true); 13 | const blob: Blob = new Blob([ script ], { type: 'application/javascript' }); 14 | a[0] = URL.createObjectURL(blob); 15 | } else { 16 | a[0] = self.__dynamic.url.encode(a[0], self.__dynamic.meta); 17 | }; 18 | }; 19 | 20 | return Reflect.construct(t, a); 21 | } 22 | }) 23 | } -------------------------------------------------------------------------------- /lib/global/rewrite/js/types.ts: -------------------------------------------------------------------------------- 1 | export type Node = Object & { 2 | type: string; 3 | value: string | Node | any; 4 | name: string; 5 | callee: Node; 6 | arguments: Array; 7 | expression: Node; 8 | property: Node; 9 | operator: string; 10 | left: Node; 11 | right: Node; 12 | body: Node; 13 | param: Node; 14 | source: Node; 15 | test: Node; 16 | consequent: Node; 17 | alternate: Node; 18 | shorthand: boolean; 19 | argument: Node; 20 | declarations: Array; 21 | id: Node; 22 | init: Node; 23 | params: Array; 24 | async: boolean; 25 | generator: boolean; 26 | computed: boolean; 27 | key: Node; 28 | object: Node; 29 | start: number; 30 | end: number; 31 | loc: { 32 | start: { 33 | line: number; 34 | column: number; 35 | }; 36 | end: { 37 | line: number; 38 | column: number; 39 | }; 40 | }; 41 | range: [number, number]; 42 | raw: string; 43 | parent: Node; 44 | __dynamic: boolean; 45 | go?: boolean; 46 | } -------------------------------------------------------------------------------- /lib/global/util/route.ts: -------------------------------------------------------------------------------- 1 | import DynamicUtil from "../util"; 2 | 3 | async function route(this: DynamicUtil, request: Request) { 4 | var url; 5 | 6 | if (request.method === "GET") { 7 | var parsed = new URL(request.url); 8 | url = parsed.searchParams.get('url'); 9 | } else if (request.method === "POST") { 10 | const formData = await request.formData(); 11 | 12 | url = formData.get('url'); 13 | 14 | if (url === null) { 15 | var parsed = new URL(request.url); 16 | url = parsed.searchParams.get('url'); 17 | } 18 | 19 | if (!url) return new Response('Error: Invalid or Unfound url', {status: 400}); 20 | } else { 21 | return new Response('Error: Invalid method', {status: 405}); 22 | } 23 | 24 | return new Response('', {status: 301, headers: {location: location.origin+this.ctx.config.prefix+this.ctx.encoding.encode(url)}}); 25 | } 26 | 27 | function routePath(this: any, { url }: Request) { 28 | return !(url.toString().substr(location.origin.length, (this.ctx.config.prefix+'route').length).startsWith(this.ctx.config.prefix+'route')); 29 | } 30 | 31 | export { route, routePath }; -------------------------------------------------------------------------------- /lib/global/cookie/index.ts: -------------------------------------------------------------------------------- 1 | import { IDBPDatabase } from 'idb'; 2 | import { DynamicBundle } from '../bundle'; 3 | import { DB } from './db'; 4 | import { serialize } from './parse'; 5 | 6 | export default class Cookie { 7 | _db: any; 8 | db: IDBPDatabase | any = DB; 9 | ctx: any; 10 | constructor(ctx: DynamicBundle) {this.ctx = ctx;} 11 | async get(host: string): Promise { 12 | if (!this._db) this._db = this.db.open(); 13 | const cookie = await DB.get(host, this._db); 14 | return serialize(cookie); 15 | } 16 | async set(host: string, raw: any = ''): Promise { 17 | raw = this.ctx.modules.setCookieParser.parse(raw, {decodeValues: false})[0]; 18 | if (!this._db) this._db = this.db.open(); 19 | const cookie = await DB.set(host, raw, this._db); 20 | return cookie; 21 | } 22 | async open(): Promise { 23 | await DB.open(); 24 | 25 | return; 26 | } 27 | async update(host: string): Promise> { 28 | if (!this._db) this._db = this.db.open(); 29 | return await DB.update(host, this._db); 30 | } 31 | } -------------------------------------------------------------------------------- /lib/global/url/decode.ts: -------------------------------------------------------------------------------- 1 | import DynamicUrlRewriter from "../url"; 2 | 3 | declare const self: any; 4 | 5 | export default function decode(this: DynamicUrlRewriter, url: string | URL) { 6 | if (!url) return url; 7 | 8 | url = new String(url).toString(); 9 | 10 | if (url.match(this.ctx.regex.BypassRegex)) return url; 11 | 12 | var index = url.indexOf(this.ctx.config.prefix); 13 | 14 | if(index == -1) 15 | return url; 16 | 17 | try { 18 | url = new URL(url, new URL(self.location.origin)).href; 19 | 20 | index = url.indexOf(this.ctx.config.prefix); 21 | 22 | if (url.slice(index + this.ctx.config.prefix.length).trim() == 'about:blank') 23 | return 'about:blank'; 24 | 25 | var search = (new URL(url).search + new URL(url).hash) || ''; 26 | var base = new URL(this.ctx.encoding.decode(url.slice(index + this.ctx.config.prefix.length) 27 | .replace('https://', 'https:/') 28 | .replace('https:/', 'https://').split('?')[0])); 29 | } catch(e) { 30 | return url; 31 | } 32 | 33 | url = base.origin + base.pathname + search + (new URL(url).search ? base.search.replace('?', '&') : base.search); 34 | 35 | return url; 36 | } -------------------------------------------------------------------------------- /lib/global/util.ts: -------------------------------------------------------------------------------- 1 | import { route, routePath } from './util/route'; 2 | import path from './util/path'; 3 | import resHeader from './util/resHeader'; 4 | import reqHeader from './util/reqHeader'; 5 | import clone from './util/clone'; 6 | import Class from './util/class'; 7 | import file from './util/file'; 8 | import edit from './util/edit'; 9 | import error from './util/error'; 10 | import about from './util/about'; 11 | import encode from './util/encode'; 12 | import rewritePath from './util/rewritePath'; 13 | import { DynamicBundle } from './client'; 14 | 15 | class DynamicUtil { 16 | route: Function = route; 17 | routePath: Function = routePath; 18 | path: Function = path; 19 | resHeader: Function = resHeader; 20 | reqHeader: Function = reqHeader; 21 | clone: Function = clone; 22 | class: Function = Class; 23 | file: Function = file; 24 | edit: Function = edit; 25 | error: Function = error; 26 | encode: Function = encode; 27 | rewritePath: Function = rewritePath; 28 | 29 | about = about; 30 | 31 | ctx: DynamicBundle & { encoding: any }; 32 | 33 | constructor(ctx: DynamicBundle) { 34 | this.ctx = ctx; 35 | } 36 | } 37 | 38 | export default DynamicUtil; -------------------------------------------------------------------------------- /lib/global/client/methods/core/eval.ts: -------------------------------------------------------------------------------- 1 | export default function Eval(self: Window | any) { 2 | self.__dynamic.eval = self.__dynamic.wrap(eval, function(this: Window, handler: Function, ...args: Array): any { 3 | if (!args.length) return; 4 | 5 | var script = args[0].toString(); 6 | script = self.__dynamic.rewrite.js.rewrite(script, {type: 'script'}, false, self.__dynamic); 7 | 8 | return handler.apply(this, [script]); 9 | }, 'eval'); 10 | 11 | self.__dynamic.define(self.Object.prototype, '__dynamic$eval', { 12 | get() { 13 | return this === window ? self.__dynamic.eval : this.eval; 14 | }, 15 | set(val: any) { 16 | return val; 17 | }, 18 | } 19 | ); 20 | 21 | self.__dynamic$wrapEval = function(script: string): string { 22 | if (!arguments.length) return arguments[0]; 23 | 24 | var event: any = self.__dynamic.fire('eval', [self, script]); 25 | if (event) return event; 26 | 27 | script = self.__dynamic.rewrite.js.rewrite(script, {type: 'script'}, false, self.__dynamic); 28 | 29 | return script; 30 | } 31 | } -------------------------------------------------------------------------------- /lib/global/util/resHeader.ts: -------------------------------------------------------------------------------- 1 | import Cookie from "../cookie"; 2 | import MetaURL from "../meta/type"; 3 | import DynamicUtil from "../util"; 4 | 5 | export default async function Header(this: DynamicUtil, headers: Object | any, meta: MetaURL, Cookies: Cookie) { 6 | 7 | for (const header in headers) { 8 | if (this.ctx.headers.csp.indexOf(header.toLowerCase())!==-1) delete headers[header]; 9 | 10 | if (header.toLowerCase() == 'location') { 11 | headers[header] = this.ctx.url.encode(headers[header], meta); 12 | 13 | continue; 14 | } 15 | 16 | if (header.toLowerCase() === 'set-cookie') { 17 | if (!Array.isArray(headers[header])) headers[header] = this.ctx.modules.setCookieParser(headers[header], {decodeValues: false}); else headers[header] = headers[header].map((e: any)=>this.ctx.modules.setCookieParser(e, {decodeValues: false})[0]); 18 | 19 | for await (var cookie of headers[header]) { 20 | await Cookies.set(meta.host, this.ctx.modules.cookie.serialize(cookie.name, cookie.value, {...cookie, encode: (e:any) => e})); 21 | 22 | continue; 23 | } 24 | 25 | delete headers[header]; 26 | 27 | continue; 28 | } 29 | } 30 | 31 | return new Headers(headers); 32 | } -------------------------------------------------------------------------------- /static/resources/scripts/index.js: -------------------------------------------------------------------------------- 1 | let workerLoaded; 2 | 3 | async function worker() { 4 | return await navigator.serviceWorker.register("/sw.js", { 5 | scope: "/service", 6 | }); 7 | } 8 | 9 | document.addEventListener('DOMContentLoaded', async function(){ 10 | await worker(); 11 | workerLoaded = true; 12 | }) 13 | 14 | function prependHttps(url) { 15 | if (!url.startsWith('http://') && !url.startsWith('https://')) { 16 | return 'https://' + url; 17 | } 18 | return url; 19 | } 20 | 21 | function isUrl(val = "") { 22 | const urlPattern = /^(http(s)?:\/\/)?([\w-]+\.)+[\w]{2,}(\/.*)?$/; 23 | return urlPattern.test(val); 24 | } 25 | 26 | const inpbox = document.getElementById("uform"); 27 | inpbox.addEventListener("submit", async (event) => { 28 | event.preventDefault(); 29 | console.log("Connecting to service -> loading"); 30 | if (typeof navigator.serviceWorker === "undefined") { 31 | alert( 32 | "An error occurred registering your service worker. Please contact support - discord.gg/unblocker" 33 | ); 34 | } 35 | if (!workerLoaded) { 36 | await worker(); 37 | } 38 | 39 | const form = document.querySelector("form"); 40 | const formValue = document.querySelector("form input").value; 41 | const url = isUrl(formValue) ? prependHttps(formValue) : 'https://www.google.com/search?q=' + encodeURIComponent(formValue); 42 | 43 | location.href = form.action + "?url=" + encodeURIComponent(url); 44 | }); 45 | -------------------------------------------------------------------------------- /lib/global/client/methods/core/protocol.ts: -------------------------------------------------------------------------------- 1 | const valid_chars = "!#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~"; 2 | const reserved_chars = "%"; 3 | 4 | export function validProtocol(protocol:any){ 5 | protocol = protocol.toString(); 6 | 7 | for(let i = 0; i < protocol.length; i++){ 8 | const char = protocol[i]; 9 | 10 | if(!valid_chars.includes(char)){ 11 | return false; 12 | } 13 | } 14 | 15 | return true; 16 | } 17 | 18 | export function encodeProtocol(protocol:any){ 19 | protocol = protocol.toString(); 20 | 21 | let result = ''; 22 | 23 | for(let i = 0; i < protocol.length; i++){ 24 | const char = protocol[i]; 25 | 26 | if(valid_chars.includes(char) && !reserved_chars.includes(char)){ 27 | result += char; 28 | }else{ 29 | const code = char.charCodeAt(); 30 | result += '%' + code.toString(16).padStart(2, 0); 31 | } 32 | } 33 | 34 | return result; 35 | } 36 | 37 | export function decodeProtocol(protocol:any){ 38 | if(typeof protocol != 'string')throw new TypeError('protocol must be a string'); 39 | 40 | let result = ''; 41 | 42 | for(let i = 0; i < protocol.length; i++){ 43 | const char = protocol[i]; 44 | 45 | if(char == '%'){ 46 | const code = parseInt(protocol.slice(i + 1, i + 3), 16); 47 | const decoded = String.fromCharCode(code); 48 | 49 | result += decoded; 50 | i += 2; 51 | }else{ 52 | result += char; 53 | } 54 | } 55 | 56 | return result; 57 | } 58 | 59 | export default {encodeProtocol, decodeProtocol} -------------------------------------------------------------------------------- /lib/global/rewrite/js/js.ts: -------------------------------------------------------------------------------- 1 | import MetaURL from '../../meta/type'; 2 | import iterate from './iterate'; 3 | import process from './process'; 4 | import emit from './emit'; 5 | import DynamicRewrites from '../../rewrite'; 6 | 7 | export default class js { 8 | iterate = iterate; 9 | process = process; 10 | emit = emit; 11 | 12 | ctx; 13 | 14 | constructor(ctx: DynamicRewrites) { 15 | this.ctx = ctx.ctx; 16 | } 17 | 18 | rewrite(this: js, src: string | Object | any, config: Object | any = {}, inject: Boolean = true, dynamic: Object | any = {}) { 19 | if (!src) return src; 20 | 21 | if (src instanceof Object) return src; 22 | 23 | src = src.toString(); 24 | 25 | if (src.includes('/* dynamic.js */')) return src; 26 | 27 | src = `/* dynamic.js */ \n\n${src}`; 28 | 29 | try { 30 | try { 31 | src = this.process(src, config, {module: true, ...this.ctx}, dynamic); 32 | } catch(e) { 33 | //console.log('module failed',e) 34 | src = this.process(src, config, {module: false, ...this.ctx}, dynamic); 35 | } 36 | } catch(e) { 37 | //console.trace('backup failed', e, src) 38 | } 39 | 40 | if (inject) { 41 | src = ` 42 | if (typeof self !== undefined && typeof self.importScripts == 'function' && typeof self.__dynamic == 'undefined') importScripts('/dynamic/dynamic.config.js', '/dynamic/dynamic.handler.js?'+Math.floor(Math.random()*(99999-10000)+10000)); 43 | 44 | ${src}`; 45 | } 46 | 47 | return src; 48 | } 49 | } -------------------------------------------------------------------------------- /docs/examples/uv-dynamic-multi/resources/scripts/index.js: -------------------------------------------------------------------------------- 1 | let workerLoaded; 2 | 3 | async function worker() { 4 | return await navigator.serviceWorker.register("/sw.js", { 5 | scope: "/service", 6 | }); 7 | } 8 | 9 | document.addEventListener('DOMContentLoaded', async function(){ 10 | await worker(); 11 | workerLoaded = true; 12 | }) 13 | 14 | function prependHttps(url) { 15 | if (!url.startsWith('http://') && !url.startsWith('https://')) { 16 | return 'https://' + url; 17 | } 18 | return url; 19 | } 20 | 21 | function isUrl(val = "") { 22 | // Use a regular expression to check for a valid URL pattern 23 | const urlPattern = /^(http(s)?:\/\/)?([\w-]+\.)+[\w]{2,}(\/.*)?$/; 24 | return urlPattern.test(val); 25 | } 26 | 27 | const inpbox = document.getElementById("uform"); 28 | inpbox.addEventListener("submit", async (event) => { 29 | event.preventDefault(); 30 | console.log("Connecting to service -> loading"); 31 | if (typeof navigator.serviceWorker === "undefined") { 32 | alert( 33 | "An error occurred registering your service worker. Please contact support - discord.gg/unblocker" 34 | ); 35 | } 36 | if (!workerLoaded) { 37 | await worker(); 38 | } 39 | 40 | const form = document.querySelector("form"); 41 | const formValue = document.querySelector("form input").value; 42 | const url = isUrl(formValue) ? prependHttps(formValue) : 'https://www.google.com/search?q=' + encodeURIComponent(formValue); 43 | 44 | location.href = form.action + "?url=" + encodeURIComponent(url); 45 | }); 46 | -------------------------------------------------------------------------------- /esbuild.prod.js: -------------------------------------------------------------------------------- 1 | import * as esbuild from "esbuild"; 2 | import { copyFile } from "fs/promises"; 3 | 4 | console.time("esbuild"); 5 | 6 | const worker = await esbuild.build({ 7 | entryPoints: ["lib/worker/index.ts"], 8 | bundle: true, 9 | outfile: "dist/dynamic.worker.js", 10 | format: "iife", 11 | minify: true, 12 | platform: "browser", 13 | sourcemap: true, 14 | target: ["es2020"], 15 | plugins: [], 16 | metafile: true, 17 | }); 18 | 19 | const handler = await esbuild.build({ 20 | entryPoints: ["lib/handler/index.ts"], 21 | bundle: true, 22 | outfile: "dist/dynamic.handler.js", 23 | format: "iife", 24 | minify: true, 25 | platform: "browser", 26 | sourcemap: true, 27 | target: ["es2020"], 28 | plugins: [], 29 | metafile: true, 30 | }); 31 | 32 | const client = await esbuild.build({ 33 | entryPoints: ["lib/client/index.ts"], 34 | bundle: true, 35 | outfile: "dist/dynamic.client.js", 36 | format: "iife", 37 | minify: true, 38 | platform: "browser", 39 | sourcemap: true, 40 | target: ["es2020"], 41 | plugins: [], 42 | metafile: true, 43 | }); 44 | 45 | const html = await esbuild.build({ 46 | entryPoints: ["lib/html/index.ts"], 47 | bundle: true, 48 | outfile: "dist/dynamic.html.js", 49 | format: "iife", 50 | minify: true, 51 | platform: "browser", 52 | sourcemap: true, 53 | target: ["es2020"], 54 | plugins: [], 55 | metafile: true, 56 | }); 57 | 58 | await copyFile("./lib/dynamic.config.js", "./dist/dynamic.config.js"); 59 | 60 | console.log(await esbuild.analyzeMetafile((worker.metafile))); 61 | 62 | console.timeEnd("esbuild"); 63 | -------------------------------------------------------------------------------- /static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dynamic 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 32 | 33 | 34 | 35 |

Dynamic

36 |
37 | 38 |
39 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /lib/client/client.ts: -------------------------------------------------------------------------------- 1 | import { DynamicBundle } from '../global/client'; 2 | 3 | import init from '../global/client/methods/init'; 4 | import wrap from '../global/client/methods/wrap'; 5 | 6 | export default function(self: Window | any, config: Object = {}, altURL: string = '') { 7 | if (self.hasOwnProperty("__dynamic")) return false; 8 | if (!self.hasOwnProperty("__dynamic$config")) self.__dynamic$config = config; 9 | 10 | if (self.parent?.__dynamic) { 11 | self.__dynamic$bare = self.parent.__dynamic$bare; 12 | } 13 | 14 | const __dynamic: DynamicBundle = new DynamicBundle(self.__dynamic$config); 15 | __dynamic.config.bare.path = (typeof __dynamic.config.bare.path === 'string' || __dynamic.config.bare.path instanceof URL) ? [ new URL(__dynamic.config.bare.path, self.location) ][0] : __dynamic.config.bare.path.map((str:any) => new URL(str, self.location)); 16 | 17 | self.__dynamic$baseURL = altURL || self.__dynamic$url || __dynamic.url.decode(location.pathname + location.search + location.hash) || ""; 18 | self.__dynamic = __dynamic; 19 | self.__dynamic.bare = new self.__dynamic.modules.bare.BareClient(self.__dynamic$config.bare.path, self.__dynamic$bare); 20 | self.__dynamic.meta.load(new URL(self.__dynamic$baseURL)); 21 | 22 | init(self, null), wrap(self); 23 | 24 | for (var method of self.__dynamic.client.methods) { 25 | const name: string = method.name; 26 | const func: Array | any = Object.entries(self.__dynamic.client).find(e=>e[0]==name); 27 | 28 | if (name == 'mutation' && self.frameElement) continue; 29 | 30 | if (method.function=='self') func[1](self); 31 | 32 | continue; 33 | }; 34 | 35 | return self; 36 | }; -------------------------------------------------------------------------------- /esbuild.dev.js: -------------------------------------------------------------------------------- 1 | import * as esbuild from "esbuild"; 2 | import { copyFile } from "fs/promises"; 3 | 4 | await import("./index.js"); 5 | 6 | console.time("esbuild"); 7 | 8 | const worker = await esbuild.context({ 9 | entryPoints: ["lib/worker/index.ts"], 10 | bundle: true, 11 | outfile: "dist/dynamic.worker.js", 12 | format: "iife", 13 | minify: true, 14 | platform: "browser", 15 | sourcemap: true, 16 | target: ["es2020"], 17 | plugins: [], 18 | metafile: true, 19 | }); 20 | 21 | worker.watch(); 22 | 23 | const handler = await esbuild.context({ 24 | entryPoints: ["lib/handler/index.ts"], 25 | bundle: true, 26 | outfile: "dist/dynamic.handler.js", 27 | format: "iife", 28 | minify: true, 29 | platform: "browser", 30 | sourcemap: true, 31 | target: ["es2020"], 32 | plugins: [], 33 | metafile: true, 34 | }); 35 | 36 | handler.watch(); 37 | 38 | const client = await esbuild.context({ 39 | entryPoints: ["lib/client/index.ts"], 40 | bundle: true, 41 | outfile: "dist/dynamic.client.js", 42 | format: "iife", 43 | minify: true, 44 | platform: "browser", 45 | sourcemap: true, 46 | target: ["es2020"], 47 | plugins: [], 48 | metafile: true, 49 | }); 50 | 51 | client.watch(); 52 | 53 | const html = await esbuild.context({ 54 | entryPoints: ["lib/html/index.ts"], 55 | bundle: true, 56 | outfile: "dist/dynamic.html.js", 57 | format: "iife", 58 | minify: true, 59 | platform: "browser", 60 | sourcemap: true, 61 | target: ["es2020"], 62 | plugins: [], 63 | metafile: true, 64 | }); 65 | 66 | html.watch(); 67 | 68 | await copyFile("./lib/dynamic.config.js", "./dist/dynamic.config.js"); 69 | 70 | console.log(await esbuild.analyzeMetafile((await worker.rebuild()).metafile)); 71 | 72 | console.timeEnd("esbuild"); 73 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nebula-services/dynamic", 3 | "version": "0.7.2-patch.2", 4 | "description": "The new generation of interception proxies.", 5 | "main": "./bin/index.cjs", 6 | "types": "./bin/index.d.ts", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/NebulaServices/Dynamic.git" 10 | }, 11 | "scripts": { 12 | "start": "node --max-http-header-size=50000 index", 13 | "build:dev": "node esbuild.dev.js", 14 | "build:prod": "node esbuild.prod.js", 15 | "build": "node esbuild.prod.js", 16 | "webpack": "echo 'Webpack building is no longer a supported build utility.'", 17 | "release": "npm run build && npm publish --access public" 18 | }, 19 | "keywords": [], 20 | "author": "", 21 | "license": "LGPL-2.0-only", 22 | "dependencies": { 23 | "@dynamic-pkg/mime": "^1.0.1", 24 | "@dynamic-pkg/mutation": "^1.0.0", 25 | "@fastify/compress": "^6.4.0", 26 | "@fastify/static": "^6.10.2", 27 | "@tomphttp/bare-client": "^2.2.0-alpha", 28 | "@tomphttp/bare-server-node": "^2.0.1", 29 | "acorn": "^8.10.0", 30 | "astring": "^1.8.6", 31 | "chalk": "^5.3.0", 32 | "cookie": "^0.5.0", 33 | "crypto-js": "^4.2.0", 34 | "domhandler": "^5.0.3", 35 | "esbuild": "^0.19.0", 36 | "fastify": "^4.21.0", 37 | "git-commit-info": "^2.0.2", 38 | "idb": "^7.0.2", 39 | "open": "^9.1.0", 40 | "parse5": "^7.1.2", 41 | "path-browserify": "^1.0.1", 42 | "set-cookie-parser": "^2.6.0" 43 | }, 44 | "type": "module", 45 | "devDependencies": { 46 | "@types/cookie": "^0.5.1", 47 | "@types/crypto-js": "^4.1.1", 48 | "@types/mime-db": "^1.43.1", 49 | "@types/path-browserify": "^1.0.0", 50 | "@types/set-cookie-parser": "^2.4.2", 51 | "execa": "^8.0.1", 52 | "ts-node": "^10.8.1", 53 | "typescript": "^5.1.6" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /lib/global/client/methods.ts: -------------------------------------------------------------------------------- 1 | export default [ 2 | { 3 | name: 'get', 4 | function: 'self', 5 | }, 6 | { 7 | name: 'func', 8 | function: 'self', 9 | }, 10 | { 11 | name: 'location', 12 | function: 'self', 13 | }, 14 | { 15 | name: 'mutation', 16 | function: 'self', 17 | }, 18 | { 19 | name: 'dom', 20 | function: 'self', 21 | }, 22 | { 23 | name: 'write', 24 | function: 'self', 25 | }, 26 | { 27 | name: 'message', 28 | function: 'self', 29 | }, 30 | { 31 | name: 'reflect', 32 | function: 'self', 33 | }, 34 | { 35 | name: 'window', 36 | function: 'self', 37 | }, 38 | { 39 | name: 'eval', 40 | function: 'self', 41 | }, 42 | { 43 | name: 'attr', 44 | function: 'self', 45 | }, 46 | { 47 | name: 'policy', 48 | function: 'self', 49 | }, 50 | { 51 | name: 'worker', 52 | function: 'self', 53 | }, 54 | { 55 | name: 'history', 56 | function: 'self', 57 | }, 58 | { 59 | name: 'ws', 60 | function: 'self', 61 | }, 62 | { 63 | name: 'cookie', 64 | function: 'self', 65 | }, 66 | { 67 | name: 'fetch', 68 | function: 'self', 69 | }, 70 | { 71 | name: 'niche', 72 | function: 'self', 73 | }, 74 | { 75 | name: 'storage', 76 | function: 'self', 77 | }, 78 | { 79 | name: 'style', 80 | function: 'self', 81 | }, 82 | { 83 | name: 'rtc', 84 | function: 'self', 85 | }, 86 | { 87 | name: 'blob', 88 | function: 'self', 89 | }, 90 | { 91 | name: 'navigator', 92 | function: 'self', 93 | } 94 | ] as Array<{name: string, function: string}>; -------------------------------------------------------------------------------- /lib/global/codec.ts: -------------------------------------------------------------------------------- 1 | //@ts-ignore 2 | import AES from '../../node_modules/crypto-js/aes.js'; 3 | //@ts-ignore 4 | import Utf8 from '../../node_modules/crypto-js/enc-utf8.js'; 5 | 6 | var aesKey = location.origin + navigator.userAgent; 7 | 8 | const xor = { 9 | encode: (str: string | undefined, key: number = 2) => { 10 | if (!str) return str; 11 | 12 | return encodeURIComponent(str.split('').map((e, i) => i % key ? String.fromCharCode(e.charCodeAt(0) ^ key) : e).join('')); 13 | }, 14 | decode: (str: string | undefined, key: number = 2) => { 15 | if (!str) return str; 16 | 17 | return decodeURIComponent(str).split('').map((e, i) => i % key ? String.fromCharCode(e.charCodeAt(0) ^ key) : e).join(''); 18 | } 19 | } 20 | 21 | const plain = { 22 | encode: (str: string | undefined) => { 23 | if (!str) return str; 24 | 25 | return encodeURIComponent(str); 26 | }, 27 | decode: (str: string | undefined) => { 28 | if (!str) return str; 29 | 30 | return decodeURIComponent(str); 31 | } 32 | } 33 | 34 | const aes = { 35 | encode: (str: string | undefined) => { 36 | if (!str) return str; 37 | 38 | return AES.encrypt(str, aesKey).toString().substring(10); 39 | }, 40 | decode: (str: string | undefined) => { 41 | if (!str) return str; 42 | 43 | return AES.decrypt('U2FsdGVkX1' + str, aesKey).toString(Utf8); 44 | }, 45 | }; 46 | 47 | const none = { 48 | encode: (str: string | undefined) => str, 49 | decode: (str: string | undefined) => str, 50 | } 51 | 52 | const base64 = { 53 | encode: (str: string | undefined) => { 54 | if (!str) return str; 55 | 56 | return decodeURIComponent(btoa(str)); 57 | }, 58 | decode: (str: string | undefined) => { 59 | if (!str) return str; 60 | 61 | return atob(str); 62 | } 63 | } 64 | 65 | export { xor, plain, none, base64, aes }; 66 | -------------------------------------------------------------------------------- /lib/global/client/methods/wrap.ts: -------------------------------------------------------------------------------- 1 | export default function wrap(self: Window | any) { 2 | self.__dynamic.wrap = function(target: any, handler: any, result: any) { 3 | if (target.__dynamic$target) return target; 4 | 5 | if (target.toString().includes('{ [native code] }') && !target.prototype) { 6 | var g = handler; 7 | var t = target; 8 | var f: any = function(this: any, ...a: any[]) { 9 | if (typeof result == 'string') { 10 | var event = self.__dynamic.fire(result, this ? [this, ...a] : a); 11 | if (event) return event; 12 | } 13 | 14 | var v = g.call(this, t, ...a); 15 | return v; 16 | } 17 | 18 | var func: any = function(this: any, ...a: any[]) {return f.call(this, ...a)}; 19 | 20 | self.__dynamic.define(func, 'name', { 21 | value: target.name, 22 | writable: false, 23 | }); 24 | 25 | func.__dynamic$target = target; 26 | 27 | func.toString = () => {return `function ${target.name}() { [native code] }`} 28 | 29 | return func; 30 | } else { 31 | try { 32 | const p = class extends target { 33 | constructor(...args: any[]) { 34 | var og = [...args]; 35 | 36 | var handled = handler.call(target, target, ...args); 37 | 38 | if (handled) args = handled; 39 | 40 | super(...args); 41 | 42 | if (result) result(this, og) 43 | } 44 | } 45 | 46 | Object.defineProperty(p, 'name', { 47 | value: target.name, 48 | writable: false, 49 | }); 50 | 51 | return p; 52 | } catch(e) { 53 | return target; 54 | } 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /lib/global/rewrite/html/nodewrapper.ts: -------------------------------------------------------------------------------- 1 | export default class Node { 2 | Original: Object | any | null = null; 3 | ctx: any; 4 | 5 | constructor(element: Element, ctx: any) { 6 | this.Original = element; 7 | 8 | var that = this; 9 | 10 | this.Original.attribs = new Proxy(this.Original.attribs||{}, { 11 | set: (target:any, prop: string, value:any): any => { 12 | var a = target[prop] = value; 13 | 14 | that.Original.attrs = Object.keys(target).map((key:any) => { 15 | return { 16 | name: key, 17 | value: target[key] + '' 18 | } 19 | }); 20 | 21 | return a || (a + ' '); 22 | }, 23 | deleteProperty: (target: any, prop: string): any => { 24 | var a = delete target[prop]; 25 | 26 | that.Original.attrs = Object.keys(target).map((key:any) => { 27 | return { 28 | name: key, 29 | value: target[key] 30 | } 31 | }); 32 | 33 | return a; 34 | } 35 | }); 36 | 37 | this.ctx = ctx; 38 | } 39 | 40 | getAttribute(attr: string) { 41 | if (!this.Original.attribs) return false; 42 | 43 | return (typeof this.Original.attribs[attr] == 'undefined' ? null : this.Original.attribs[attr].trim()); 44 | } 45 | 46 | setAttribute(attr: string, value: any) { 47 | if (!this.Original.attribs) return false; 48 | 49 | return this.Original.attribs[attr] = value; 50 | } 51 | 52 | removeAttribute(attr: string) { 53 | if (!this.Original.attribs) return false; 54 | 55 | return delete this.Original.attribs[attr]; 56 | } 57 | 58 | hasAttribute(attr: string) { 59 | if (!this.Original.attribs) return false; 60 | 61 | return this.Original.attribs.hasOwnProperty(attr); 62 | } 63 | } -------------------------------------------------------------------------------- /lib/global/client/methods/core/html.ts: -------------------------------------------------------------------------------- 1 | import MetaURL from "../../../meta/type"; 2 | 3 | export default function html(self: Window | any) { 4 | self.__dynamic.rewrite.dom = function(src: string, meta: MetaURL) { 5 | if (typeof self.DOMParser == 'undefined') return src; 6 | if (!src) return src; 7 | 8 | var parser: DOMParser = new self.DOMParser(); 9 | var doc: Document = parser.parseFromString(src.toString(), 'text/html'); 10 | var html: HTMLElement = doc.documentElement; 11 | 12 | html.querySelectorAll('script').forEach(function(script: HTMLScriptElement) { 13 | if (!script.type || (script.type && script.type !== 'text/javascript' && script.type !== 'application/javascript' && script.type !== 'application/x-javascript')) { 14 | if (script.src) script.src = self.__dynamic.url.encode(script.getAttribute('src'), meta); 15 | } else { 16 | if (script.innerHTML) script.innerHTML = self.__dynamic.js.encode(script.innerHTML, {type: 'script'}, meta, {}); 17 | } 18 | }); 19 | 20 | html.querySelectorAll('link').forEach(function(link: HTMLLinkElement) { 21 | if (link.href && link.getAttribute('rel') !== 'stylesheet') link.href = self.__dynamic.url.encode(link.getAttribute('href'), meta); 22 | }); 23 | 24 | html.querySelectorAll('img').forEach(function(img: HTMLImageElement) { 25 | if (img.src) img.src = self.__dynamic.url.encode(img.getAttribute('src'), meta); 26 | if (img.srcset) img.srcset = self.__dynamic.rewrite.srcset.encode(img.getAttribute('srcset'), self.__dynamic); 27 | }); 28 | 29 | html.querySelectorAll('a').forEach(function(a: HTMLAnchorElement) { 30 | if (a.href) a.href = self.__dynamic.url.encode(a.getAttribute('href'), meta); 31 | }); 32 | 33 | html.querySelectorAll('style').forEach(function(style: HTMLStyleElement) { 34 | if (style.innerHTML) style.innerHTML = self.__dynamic.rewrite.css.rewrite(style.innerHTML, meta); 35 | }); 36 | 37 | return html.outerHTML as string; 38 | } 39 | } -------------------------------------------------------------------------------- /lib/global/rewrite/manifest.ts: -------------------------------------------------------------------------------- 1 | import MetaURL from "../meta/type"; 2 | import DynamicRewrites from "../rewrite"; 3 | 4 | export default class manifest { 5 | 6 | ctx; 7 | 8 | config = { 9 | rewrite: [ 10 | ['icons', 'urlit'], 11 | ['name', ' - Dynamic'], 12 | ['start_url', 'url'], 13 | ['scope', 'url'], 14 | ['short_name', ' - Dynamic'], 15 | ['shortcuts', 'urlev'], 16 | ], 17 | delete: [ 18 | 'serviceworker' 19 | ] 20 | } 21 | 22 | constructor(ctx: DynamicRewrites) { 23 | this.ctx = ctx.ctx; 24 | } 25 | 26 | rewrite(this: manifest, src: string, meta: MetaURL) { 27 | const manifest = JSON.parse(src); 28 | 29 | for (let config in this.config) { 30 | if (config == 'rewrite') { 31 | for (var [name, action] of this.config[config]) { 32 | if (action == 'urlit' && manifest[name]) { 33 | for (var i = 0; i < manifest[name].length; i++) { 34 | manifest[name][i].src = this.ctx.url.encode(manifest[name][i].src, meta); 35 | } 36 | 37 | continue; 38 | } 39 | 40 | if (action == 'urlev' && manifest[name]) { 41 | for (var i = 0; i < manifest[name].length; i++) { 42 | manifest[name][i].url = this.ctx.url.encode(manifest[name][i].url, meta); 43 | } 44 | 45 | continue; 46 | } 47 | 48 | if (action == 'url' && manifest[name]) { 49 | manifest[name] = this.ctx.url.encode(manifest[name], meta); 50 | 51 | continue; 52 | } 53 | 54 | if (action == 'url' || action == 'urlit' || action == 'urlev') continue; 55 | 56 | manifest[name] = manifest[name] + action; 57 | } 58 | } else if (config == 'delete') { 59 | for (var name of this.config[config]) { 60 | if (manifest[name]) delete manifest[name]; 61 | } 62 | } 63 | } 64 | 65 | return JSON.stringify(manifest) as string; 66 | } 67 | } -------------------------------------------------------------------------------- /lib/global/client.ts: -------------------------------------------------------------------------------- 1 | import DynamicModules from './modules'; 2 | import DynamicRewrites from './rewrite'; 3 | import DynamicUtil from './util'; 4 | import DynamicUrlRewriter from './url'; 5 | import DynamicRegex from './regex'; 6 | import DynamicMeta from './meta'; 7 | import HeaderData from './headers'; 8 | import DynamicTypeFunctions from './istype'; 9 | import DynamicClient from './client/index'; 10 | import DynamicCookies from './cookie'; 11 | import * as DynamicEncoding from './codec'; 12 | 13 | class DynamicBundle { 14 | _location: any; 15 | bare: any; 16 | http: any; 17 | middleware: any; 18 | 19 | modules: DynamicModules = new DynamicModules(this); 20 | util: DynamicUtil = new DynamicUtil(this); 21 | meta: DynamicMeta = new DynamicMeta(this); 22 | regex: DynamicRegex = new DynamicRegex(this); 23 | rewrite: DynamicRewrites = new DynamicRewrites(this); 24 | url: DynamicUrlRewriter = new DynamicUrlRewriter(this); 25 | is: DynamicTypeFunctions = new DynamicTypeFunctions(this); 26 | cookies: DynamicCookies = new DynamicCookies(this); 27 | client: DynamicClient = new DynamicClient(this); 28 | encoding: typeof DynamicEncoding = DynamicEncoding; 29 | headers: typeof HeaderData = HeaderData; 30 | 31 | parent: Window | any; 32 | top: Window | any; 33 | 34 | define: Function | undefined; 35 | config: any; 36 | 37 | listeners: Array<{ event: string; cb: Function }> = []; 38 | 39 | on(event: string, cb: Function) { 40 | this.listeners.push({ event, cb }); 41 | } 42 | 43 | fire(event: string, data: Array) { 44 | let found = false; 45 | 46 | for (const listener of this.listeners) { 47 | if (listener.event === event) { 48 | data = (found = true, listener.cb(...data)); 49 | } 50 | } 51 | 52 | if (found && data) { 53 | return data; 54 | } 55 | 56 | return null; 57 | } 58 | 59 | constructor(config: any) { 60 | if (config && !this.config) { 61 | this.config = config; 62 | } 63 | if (config) { 64 | this.util.encode(self); 65 | } 66 | } 67 | } 68 | 69 | export { 70 | DynamicBundle, 71 | DynamicModules, 72 | DynamicRewrites, 73 | DynamicUtil, 74 | DynamicMeta, 75 | DynamicUrlRewriter, 76 | }; -------------------------------------------------------------------------------- /lib/global/rewrite/js/emit.ts: -------------------------------------------------------------------------------- 1 | import Identifier from './type/Identifier'; 2 | import MemberExpression from "./type/MemberExpression"; 3 | import Literal from './type/Literal'; 4 | import CallExpression from './type/CallExpression'; 5 | import AssignmentExpression from './type/AssignmentExpression'; 6 | import ThisExpression from './type/ThisExpression'; 7 | import Property from './type/Property'; 8 | import Imports from './type/Imports'; 9 | import VariableDeclarator from './type/VariableDeclaractor'; 10 | 11 | function Emit(node: Object | any, type: string, parent: Object | any = {}, ctx: Object | any = {}, dynamic: Object | any = {}, config: Object | any = {}) { 12 | if (node.__dynamic) return; 13 | 14 | switch(type) { 15 | case "Identifier": 16 | Identifier(node, parent); 17 | break; 18 | case "MemberExpression": 19 | MemberExpression(node, parent, config); 20 | break; 21 | case "Literal": 22 | Literal(node, parent); 23 | break; 24 | case "CallExpression": 25 | CallExpression(node, parent); 26 | break; 27 | case "AssignmentExpression": 28 | AssignmentExpression(node, parent); 29 | break; 30 | case "ThisExpression": 31 | //ThisExpression(node, parent); 32 | break; 33 | case "Property": 34 | Property(node, parent); 35 | break; 36 | case "VariableDeclarator": 37 | VariableDeclarator(node, parent); 38 | break; 39 | case "CatchClause": 40 | //node.body.body.unshift({"type":"ExpressionStatement","start":21,"end":37,"expression":{"type":"CallExpression","start":21,"end":36,"callee":{"type":"MemberExpression","start":21,"end":34,"object":{"type":"Identifier","start":21,"end":28,"name":"console"},"property":{"type":"Identifier","start":29,"end":34,"name":"error"},"computed":false,"optional":false},"arguments":[{type: "Identifier", name: "typeof E == 'undefined' ? typeof d == 'undefined' ? null : d : E"}],"optional":false}}); 41 | break; 42 | default: 43 | break; 44 | } 45 | 46 | Imports(node, parent, ctx, dynamic); 47 | } 48 | 49 | export default Emit; -------------------------------------------------------------------------------- /lib/global/bundle.ts: -------------------------------------------------------------------------------- 1 | import { BareClient } from '@tomphttp/bare-client'; 2 | import DynamicModules from './modules'; 3 | import DynamicRewrites from './rewrite'; 4 | import DynamicUtil from './util'; 5 | import DynamicUrlRewriter from './url'; 6 | import DynamicMeta from './meta'; 7 | import DynamicHttp from './http'; 8 | import DynamicRegex from './regex'; 9 | import DynamicMiddleware from './middleware'; 10 | import DynamicTypeFunctions from './istype'; 11 | import DynamicCookies from './cookie'; 12 | import HeaderData from './headers'; 13 | import * as DynamicEncoding from './codec'; 14 | 15 | class DynamicBundle { 16 | _location: any; 17 | client: any; 18 | parent: any; 19 | top: any; 20 | define: Function | undefined; 21 | config: any; 22 | listeners: Array<{ event: string; cb: Function }> = []; 23 | 24 | modules: DynamicModules = new DynamicModules(this); 25 | util: DynamicUtil = new DynamicUtil(this); 26 | http: DynamicHttp = new DynamicHttp(this); 27 | meta: DynamicMeta = new DynamicMeta(this); 28 | rewrite: DynamicRewrites = new DynamicRewrites(this); 29 | url: DynamicUrlRewriter = new DynamicUrlRewriter(this); 30 | is: DynamicTypeFunctions = new DynamicTypeFunctions(this); 31 | cookies: DynamicCookies = new DynamicCookies(this); 32 | regex: DynamicRegex = new DynamicRegex(this); 33 | headers: typeof HeaderData = HeaderData; 34 | encoding: typeof DynamicEncoding = DynamicEncoding; 35 | bare!: Promise; 36 | middleware: DynamicMiddleware = new DynamicMiddleware(this); 37 | 38 | constructor(config: any) { 39 | if (config && !this.config) { 40 | this.config = config; 41 | } 42 | if (config) { 43 | this.util.encode(self); 44 | } 45 | } 46 | 47 | on(event: string, cb: Function) { 48 | this.listeners.push({ event, cb }); 49 | } 50 | 51 | fire(event: string, data: Array) { 52 | for (const listener of this.listeners) { 53 | if (listener.event === event) { 54 | data = listener.cb(...data); 55 | return data; 56 | } 57 | } 58 | return null; 59 | } 60 | } 61 | 62 | export { 63 | DynamicBundle, 64 | DynamicModules, 65 | DynamicRewrites, 66 | DynamicUtil, 67 | DynamicMiddleware, 68 | DynamicHttp, 69 | DynamicMeta, 70 | DynamicUrlRewriter, 71 | }; -------------------------------------------------------------------------------- /lib/global/client/methods/core/get.ts: -------------------------------------------------------------------------------- 1 | export default function Get(self: Window | any) { 2 | self.__dynamic$get = function(object: any) { 3 | var data: any = self.__dynamic.fire('get', [object]); 4 | if (data) return data; 5 | 6 | try { 7 | if (object==self.parent) return self.parent.__dynamic$window; 8 | if (object==self.top) return self.top.__dynamic$window; 9 | 10 | if (object == self.location) { 11 | return self.__dynamic$location; 12 | } 13 | 14 | if (self.Location || self.WorkerLocation) if (object instanceof (self.Location || self.WorkerLocation)) { 15 | return self.__dynamic$location; 16 | } 17 | 18 | if (self.Document) if (object instanceof self.Document) { 19 | return self.__dynamic$document; 20 | } 21 | 22 | if (object == self) return self.__dynamic$window; 23 | 24 | if (typeof object == 'function') { 25 | if (object.name == '__d$Send') return self.__dynamic$message(object.target, self); 26 | } 27 | 28 | return object; 29 | } catch(e) { 30 | return object; 31 | } 32 | } 33 | 34 | self.__dynamic$property = function(prop: any) { 35 | if (typeof prop !== "string") { 36 | return prop; 37 | } 38 | 39 | if (prop == 'location') return '__dynamic$location'; 40 | if (prop == 'eval') return '__dynamic$eval'; 41 | 42 | return prop; 43 | } 44 | 45 | self.__dynamic$set = function(object: any, value: any) { 46 | if (!object) return value; 47 | 48 | return self.__dynamic.url.encode(self.__dynamic.meta.href.replace(self.__dynamic.property['href'], value), self.__dynamic.property); 49 | } 50 | 51 | self.__dynamic$var = function(object: any, value: any) { 52 | return window[value] = object; 53 | } 54 | 55 | self.dg$ = self.__dynamic$get; 56 | self.ds$ = self.__dynamic$set; 57 | self.dp$ = self.__dynamic$property; 58 | self.dv$ = self.__dynamic$var; 59 | self.d$g_ = self.__dynamic$get; 60 | self.d$s_ = self.__dynamic$set; 61 | self.d$p_ = self.__dynamic$property; 62 | self.d$v_ = self.__dynamic$var; 63 | } -------------------------------------------------------------------------------- /lib/global/client/methods/document/style.ts: -------------------------------------------------------------------------------- 1 | export default function style(self: any) { 2 | self.CSSStyleDeclaration.prototype._setProperty = self.CSSStyleDeclaration.prototype.setProperty; 3 | 4 | self.CSSStyleDeclaration.prototype.setProperty = self.__dynamic.wrap(self.CSSStyleDeclaration.prototype.setProperty, 5 | function(this: CSSStyleDeclaration, handler: Function, ...args: Array): undefined { 6 | if (args[0] == 'background-image' || args[0] == 'background' || args[0] == 'backgroundImage') args[1] = self.__dynamic.rewrite.css.rewrite(args[1], self.__dynamic.meta); 7 | 8 | return handler.apply(this, args); 9 | }, 10 | 'CSSStyleDeclaration.prototype.setProperty' 11 | ); 12 | 13 | self.__dynamic.define(self.CSSStyleDeclaration.prototype, 'background', { 14 | get(): string | null { 15 | if (this._background) return this._background; 16 | 17 | return this.getPropertyValue('background'); 18 | }, 19 | set(val: string): string | null { 20 | this._background = val; 21 | 22 | return this._setProperty('background', self.__dynamic.rewrite.css.rewrite(val, self.__dynamic.meta)); 23 | } 24 | }); 25 | 26 | self.__dynamic.define(self.CSSStyleDeclaration.prototype, 'backgroundImage', { 27 | get(): string | null { 28 | if (this._backgroundImage) return this._backgroundImage; 29 | 30 | return this.getPropertyValue('background-image'); 31 | }, 32 | set(val: string): string | null { 33 | this._backgroundImage = val; 34 | 35 | return this._setProperty('background-image', self.__dynamic.rewrite.css.rewrite(val, self.__dynamic.meta)); 36 | } 37 | }); 38 | 39 | self.__dynamic.define(self.CSSStyleDeclaration.prototype, 'background-image', { 40 | get(): string | null { 41 | if (this._backgroundImage) return this._backgroundImage; 42 | 43 | return this.getPropertyValue('background-image'); 44 | }, 45 | set(val: string): string | null { 46 | this._backgroundImage = val; 47 | 48 | return this._setProperty('background-image', self.__dynamic.rewrite.css.rewrite(val, self.__dynamic.meta)); 49 | } 50 | }); 51 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ![Frame_1_6](https://github.com/NebulaServices/Dynamic/assets/81369743/373dc333-ff38-46c7-90f7-bd34899a6807) 4 | ![Version](https://img.shields.io/badge/status-BETA-build) 5 | [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://GitHub.com/Naereen/StrapDown.js/graphs/commit-activity) 6 | [![License](https://img.shields.io/github/license/NebulaServices/Dynamic.svg)](https://github.com/NebulaServices/Dynamic/blob/main/LICENSE) 7 | [![TypeScript](https://badgen.net/badge/icon/typescript?icon=typescript&label)](https://typescriptlang.org) 8 | [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) 9 | 10 | ## Features 11 | 12 | - Customizable and easily configurable 13 | - Seriously Simple to use 14 | - Highly supportive, and supports your favorite sites: 15 | - Google (login and suite apps) 16 | - Youtube 17 | - Discord 18 | - TikTok 19 | - And so much more 20 | - Diabolically fast 21 | - Written in TypeScript 22 | 23 | ## Implementation 24 | See [Examples](https://github.com/NebulaServices/Dynamic/tree/main/examples); 25 | 26 | ## Getting started (How to run) 27 | 28 | ### Method 1 29 | 30 | 1. Clone and change directory into Dynamic 31 | ```bash 32 | git clone https://github,com/NebulaServices/Dynamic.git && cd Dynamic 33 | ``` 34 | 35 | 2. Run bash script and follow the instructions in the script 36 | ```bash 37 | ./bin/start.sh 38 | ``` 39 | 40 | 41 | ### Method 2 42 | 43 | 1. Clone and change directory into Dynamic 44 | ```bash 45 | git clone https://GitHub.com/NebulaServices/Dynamic.git && cd Dynamic 46 | ``` 47 | 48 | 2. Install dependencies 49 | ```bash 50 | npm i 51 | ``` 52 | 53 | 3. Build Dynamic Bundles 54 | ```bash 55 | npm run build 56 | ``` 57 | 58 | 4. Run the server 59 | ```bash 60 | npm start 61 | ``` 62 | 63 | ## Notice 64 | 65 | Hi there, we're launching this project in **early public beta**. Behind the scenes we're working hard at rewriting and bug fixes. Thanks for understanding. 66 | 67 | ## Developer support 68 | We have our very own developer support server! Join with this link: https://discord.gg/shESgmwt3M 69 | 70 | ## Authors 71 | 72 | - [@Sylvie](https://www.github.com/Sylvie-TN) - Lead developer 73 | - [@GreenyDev](https://github.com/GreenyDEV) - Documentation, project manager 74 | 75 | 76 | Made with ❤️ By Nebula Services 77 | 78 | -------------------------------------------------------------------------------- /lib/global/rewrite/js/type/CallExpression.ts: -------------------------------------------------------------------------------- 1 | import Eval from '../object/Eval'; 2 | import PostMessage from '../object/PostMessage'; 3 | import { Node } from '../types'; 4 | 5 | export default function CallExpression(node: Node, parent: Node = {} as any) { 6 | if (parent.type=='AssignmentExpression'&&parent.left==node) return; 7 | 8 | if (node.callee.type=='Identifier') { 9 | if (node.callee.name=='postMessage') { 10 | let original = 'undefined'; 11 | node.callee.type = 'CallExpression'; 12 | node.callee.callee = {type: 'Identifier', name: '__dynamic$message'} as Node; 13 | node.callee.arguments = [{type: 'Identifier', name: original}, {type: 'Identifier', name: 'self', __dynamic: true}] as Array; 14 | 15 | return; 16 | } 17 | 18 | if (node.callee.name=='eval') { 19 | //node.callee.name = '__dynamic$eval'; 20 | Eval(node); 21 | } 22 | } 23 | 24 | if (node.callee.type=='MemberExpression') { 25 | if (node.callee.property.name=='postMessage' && node.callee.object.type!=='Super') { 26 | let original: Node = node.callee.object; 27 | node.callee.type = 'CallExpression'; 28 | node.callee.callee = {type: 'Identifier', name: '__dynamic$message'} as Node; 29 | node.callee.arguments = [original, {type: 'Identifier', name: 'self', __dynamic: true}] as Array; 30 | 31 | return; 32 | } 33 | 34 | if (node.callee.object.name=='eval') { 35 | //node.callee.object.name = '__dynamic$eval'; 36 | Eval(node); 37 | } 38 | } 39 | 40 | if (node.arguments.length > 0 && node.arguments.length < 4) { 41 | // fallback postmessage rewriting 42 | /*if (node.callee?.object?.type !== 'Literal') 43 | if (node.arguments[1] && node.arguments[1].type == "Literal" && node.arguments[1].value == '*') { 44 | node.callee = { 45 | type: 'CallExpression', 46 | callee: { 47 | type: 'Identifier', 48 | name: 'dg$', 49 | __dynamic: true, 50 | }, 51 | arguments: [ node.callee ], 52 | __dynamic: true, 53 | } 54 | }*/ 55 | } 56 | 57 | try {} catch {} 58 | } -------------------------------------------------------------------------------- /lib/global/client/methods/core/reflect.ts: -------------------------------------------------------------------------------- 1 | export default function reflect(self: Window | any) { 2 | var get = self.Reflect.get.bind({}); 3 | var set = self.Reflect.set.bind({}); 4 | 5 | self.Reflect.set = self.__dynamic.wrap(self.Reflect.set, 6 | function(this: Object, target: Function, ...a: Array): any { 7 | if (a[0].constructor.name=='Window') { 8 | if (a[1]=='location') { 9 | a[0].__dynamic$location = a[2]; 10 | return true; 11 | } 12 | } 13 | 14 | if (a[0].constructor.name=='Location') { 15 | self.__dynamic$location[a[1]] = a[2]; 16 | return true; 17 | } 18 | 19 | return Reflect.apply(set, this, a); 20 | }, 21 | 'Reflect.set' 22 | ); 23 | 24 | self.Reflect.get = self.__dynamic.wrap(self.Reflect.get, 25 | function(this: Object, target: Function, ...a: Array) { 26 | if (typeof a[0] == 'object') { 27 | if (a[0].constructor.name=='Window') { 28 | if (a[1]=='location') return a[0].__dynamic ? a[0].__dynamic$location : Reflect.apply(get, this, a); 29 | 30 | if (a[0][a[1]] && a[0][a[1]].constructor.name=='Window') { 31 | return a[0][a[1]].__dynamic$window; 32 | } 33 | } 34 | 35 | if (a[0].constructor.name=='Location') { 36 | return self.__dynamic$location[a[1]]; 37 | } 38 | } 39 | 40 | return Reflect.apply(get, this, a); 41 | }, 42 | 'Reflect.get' 43 | ); 44 | 45 | self.__dynamic.Reflect = { 46 | get, 47 | set, 48 | apply: self.Reflect.apply.bind({}), 49 | construct: self.Reflect.construct.bind({}), 50 | defineProperty: self.Reflect.defineProperty.bind({}), 51 | deleteProperty: self.Reflect.deleteProperty.bind({}), 52 | getOwnPropertyDescriptor: self.Reflect.getOwnPropertyDescriptor.bind({}), 53 | getPrototypeOf: self.Reflect.getPrototypeOf.bind({}), 54 | has: self.Reflect.has.bind({}), 55 | isExtensible: self.Reflect.isExtensible.bind({}), 56 | ownKeys: self.Reflect.ownKeys.bind({}), 57 | preventExtensions: self.Reflect.preventExtensions.bind({}), 58 | setPrototypeOf: self.Reflect.setPrototypeOf.bind({}) 59 | } 60 | } -------------------------------------------------------------------------------- /lib/global/client/methods/window/rtc.ts: -------------------------------------------------------------------------------- 1 | export default function rtc(self: Window | any) { 2 | // rip 3 | 4 | /*self.RTCPeerConnection = self.__dynamic.wrap(self.RTCPeerConnection, 5 | function(this: RTCPeerConnection, target: Function, ...args: Array) { 6 | if (args[0]) { 7 | if (args[0].iceServers) { 8 | for (var i = 0; i < args[0].iceServers.length; i++) { 9 | if (args[0].iceServers[i].urls) { 10 | for (var j = 0; j < args[0].iceServers[i].urls.length; j++) { 11 | if (args[0].iceServers[i].urls[j].startsWith('stun:') || args[0].iceServers[i].urls[j].startsWith('turn:')) { 12 | args[0].iceServers[i].urls[j] = self.__dynamic.rtc.endpoints[0]; 13 | } 14 | } 15 | } 16 | } 17 | } 18 | } 19 | 20 | console.log('rtcpeer', args[0]); 21 | 22 | return args; 23 | }, 24 | function() { 25 | arguments[0].onicecandidate = function(this: RTCPeerConnection, ev: RTCPeerConnectionIceEvent) { 26 | if (ev.candidate) { 27 | console.log('ice', ev.candidate); 28 | } 29 | 30 | console.log(ev); 31 | }; 32 | 33 | console.log(arguments[0]); 34 | } 35 | ); 36 | 37 | self.RTCPeerConnection.prototype.addIceCandidate = self.__dynamic.wrap(self.RTCPeerConnection.prototype.addIceCandidate, 38 | function(this: RTCPeerConnection, target: Function, ...args: Array) { 39 | console.log('addice', args); 40 | 41 | return Reflect.apply(target, this, args); 42 | } 43 | ); 44 | 45 | self.RTCIceCandidate = self.__dynamic.wrap(self.RTCIceCandidate, 46 | function(this: RTCPeerConnection, target: Function, ...args: Array) { 47 | console.log('rtcice', args); 48 | 49 | return args; 50 | } 51 | ); 52 | 53 | self.RTCPeerConnection.prototype.setConfiguration = self.__dynamic.wrap(self.RTCPeerConnection.prototype.setConfiguration, 54 | function(this: RTCPeerConnection, target: Function, ...args: Array) { 55 | console.log('rtcconfig', args); 56 | 57 | return Reflect.apply(target, this, args); 58 | } 59 | );*/ 60 | } -------------------------------------------------------------------------------- /lib/global/rewrite/js/type/Identifier.ts: -------------------------------------------------------------------------------- 1 | import Eval from '../object/Eval'; 2 | import PostMessage from '../object/PostMessage'; 3 | import { Node } from '../types'; 4 | 5 | export default function Identifier(node: Node, parent: Node = {} as any) { 6 | if (typeof node.name !== 'string') return false; 7 | 8 | if (node.__dynamic === true) return; 9 | 10 | if (!['parent', 'top', 'postMessage', 'opener', 'window', 'self', 'globalThis', 'parent', 'location'].includes(node.name)) return false; 11 | 12 | //if (parent.type=='AssignmentExpression'&&parent.left==node&&node.name=='location') return; //node.name = '__dynamic$location' 13 | 14 | if (parent.type=='CallExpression'&&(parent.callee==node)) return; 15 | if (parent.type=='MemberExpression'&&(parent.object!==node&&(!['document', 'window', 'self', 'globalThis'].includes(parent.object.name)))) return; 16 | if (parent.type=='FunctionDeclaration') return; 17 | if (parent.type=='VariableDeclaration') return; 18 | if (parent.type=='VariableDeclarator'&&parent.id==node) return; 19 | if (parent.type=='LabeledStatement') return; 20 | if (parent.type=='Property'&&parent.key==node) return; 21 | if (parent.type=='ArrowFunctionExpression'&&parent.params.includes(node)) return; 22 | if (parent.type=='FunctionExpression'&&parent.params.includes(node)) return; 23 | if (parent.type=='FunctionExpression'&&parent.id==node) return; 24 | if (parent.type=='CatchClause'&&parent.param==node) return; 25 | if (parent.type=='ContinueStatement') return; 26 | if (parent.type=='BreakStatement') return; 27 | if (parent.type=='AssignmentExpression'&&parent.left==node) return; 28 | if (parent.type=='UpdateExpression') return; 29 | if (parent.type=='UpdateExpression') return; 30 | if (parent.type=='ForInStatement'&&parent.left==node) return; 31 | if (parent.type=='MethodDefinition'&&parent.key==node) return; 32 | if (parent.type=='AssignmentPattern'&&parent.left==node) return; 33 | if (parent.type=='NewExpression') return; 34 | if (parent?.parent?.type=='NewExpression') return; 35 | if (parent.type=='UnaryExpression'&&parent.argument==node) return; 36 | if (parent.type=='Property' && parent.shorthand == true && parent.value == node) return; 37 | 38 | //if (node.name=='location') return node.name = '__dynamic$location' 39 | if (node.name == '__dynamic') return node.name = 'undefined'; 40 | 41 | if (node.name=='eval' && parent.right !== node) return node.name = '__dynamic$eval'; 42 | 43 | node.name = `dg$(${node.name})`; 44 | } -------------------------------------------------------------------------------- /lib/global/client/methods/document/cookie.ts: -------------------------------------------------------------------------------- 1 | import Cookie from '../../../cookie'; 2 | import { parse, serialize } from '../../../cookie/parse'; 3 | 4 | export default function cookie(self: any) { 5 | delete self.Document.prototype.cookie; 6 | 7 | self.__dynamic.define(self.document, 'cookie', { 8 | get(): string { 9 | var event = self.__dynamic.fire('getCookies', [self.__dynamic.location.host, self.__dynamic.cookie.str || '']); 10 | if (event) return event; 11 | 12 | self.__dynamic.cookies.update(self.__dynamic.location.host); 13 | return self.__dynamic.cookie.str || self.__dynamic.cookie.desc.get.call(this) || ''; 14 | }, 15 | set(val: any): void { 16 | var parsed = self.__dynamic.modules.setCookieParser.parse(val, {decodeValues: false})[0]; 17 | 18 | var event = self.__dynamic.fire('setCookie', [self.__dynamic.location.host, val, parsed]); 19 | if (event) return event; 20 | 21 | parsed.name = parsed.name.replace(/^\./g, ''); 22 | 23 | Promise.resolve(self.__dynamic.cookies.set(self.__dynamic.location.host, self.__dynamic.modules.cookie.serialize(parsed.name, parsed.value, {...parsed, encode: (e:any) => e}))).then(async (e:any)=>{ 24 | await self.__dynamic.cookies.update(self.__dynamic.location.host) 25 | self.__dynamic.cookie.str = await self.__dynamic.cookies.get(self.__dynamic.location.host); 26 | }); 27 | 28 | var cookies = parse(self.__dynamic.cookie.str || ''); 29 | 30 | cookies[parsed.name] = parsed.value; 31 | 32 | self.__dynamic.cookie.str = serialize(Object.entries(cookies).map(e=>({ name: e[0], value: e[1] })) as Array); 33 | } 34 | }); 35 | 36 | if (self.navigator.serviceWorker) try { 37 | self.navigator.serviceWorker.onmessage = ({ data }: any) => { 38 | if (data.host==self.__dynamic.location.host && data.type == 'set-cookie') { 39 | var parsed = self.__dynamic.modules.cookie.parse(data.val); 40 | var cookies = parse(self.__dynamic.cookie.str || ''); 41 | 42 | cookies[Object.entries(parsed)[0][0]] = Object.entries(parsed)[0][1]; 43 | 44 | self.__dynamic.cookie.str = serialize(Object.entries(cookies).map(e=>({ name: e[0], value: e[1] })) as Array); 45 | } 46 | 47 | if (data.host==self.__dynamic.location.host && data.type == 'cookies') { 48 | self.__dynamic.cookie.str = data.cookies; 49 | } 50 | }; 51 | } catch {}; 52 | } -------------------------------------------------------------------------------- /docs/examples/uv-dynamic-multi/resources/style.css: -------------------------------------------------------------------------------- 1 | html { 2 | width: 100%; 3 | height: 100%; 4 | } 5 | body { 6 | background-color: #080808; 7 | color: #ffffff; 8 | font-family: 'Roboto', sans-serif; 9 | font-size: 16px; 10 | line-height: 1.5; 11 | margin: 0; 12 | padding: 0; 13 | width: 100%; 14 | height: 100%; 15 | display: flex; 16 | align-items: center; 17 | justify-content: center; 18 | align-content: center; 19 | flex-direction: column; 20 | position: absolute; 21 | z-index: 1; 22 | } 23 | h1 { 24 | font-size: 72px; 25 | font-weight: 700; 26 | margin: 0 0 -43px 0; 27 | font-style: italic; 28 | } 29 | form { 30 | display: flex; 31 | flex-direction: row; 32 | align-items: flex-start; 33 | margin: 64px auto; 34 | max-width: 480px; 35 | width: 100%; 36 | justify-content: center; 37 | align-content: center; 38 | } 39 | input[name="url"] { 40 | background-color: #0f0f0fbf; 41 | border: 1px solid #ffffff24; 42 | color: #ffffff; 43 | font-size: 16px; 44 | border-radius: 9px; 45 | margin: 0 0 16px 0; 46 | font-family: 'Roboto', sans-serif; 47 | padding: 16px; 48 | text-align: center; 49 | width: 100%; 50 | outline: transparent; 51 | } 52 | input[name="url"]::placeholder { 53 | color: #bfbfbf; 54 | } 55 | input[type="submit"] { 56 | background-color: #daff46; 57 | color: black; 58 | border: none; 59 | font-size: 16px; 60 | font-weight: 700; 61 | padding: 16px; 62 | text-align: center; 63 | text-transform: uppercase; 64 | transition: background-color 0.2s ease-in-out; 65 | width: 100%; 66 | } 67 | input[type="submit"]:hover { 68 | background-color: #00c853; 69 | cursor: pointer; 70 | } 71 | 72 | 73 | svg { 74 | position: absolute; 75 | top: 0; 76 | left: 0; 77 | z-index: -1; 78 | filter: blur(97px); 79 | } 80 | 81 | 82 | .footer { 83 | display: flex; 84 | align-items: flex-end; 85 | justify-content: center; 86 | flex-direction: row; 87 | align-content: center; 88 | flex-wrap: nowrap; 89 | position: absolute; 90 | bottom: 0; 91 | width: 100%; 92 | 93 | } 94 | 95 | .copyright { 96 | position: absolute; 97 | left: 17px; 98 | } 99 | 100 | canvas { 101 | width: 100%; 102 | height: 100%; 103 | position: absolute; 104 | z-index: -2; 105 | } -------------------------------------------------------------------------------- /lib/global/client/methods/window/ws.ts: -------------------------------------------------------------------------------- 1 | /*export default function websocket(self: Window | any) { 2 | // ty divide i love you 3 | 4 | const createSocket = (url: string, protocols?: string | string[]): WebSocket => {'' 5 | return self.__dynamic.bare.createWebSocket.apply( 6 | self.__dynamic.bare, 7 | [url, protocols || [], {}], 8 | ); 9 | } 10 | 11 | self.WebSocket = new Proxy(self.WebSocket, { 12 | construct(target: Function, args: Array): any { 13 | return createSocket(args[0], args[1]); 14 | } 15 | }); 16 | }*/ 17 | 18 | import { encodeProtocol as encode_protocol } from "../core/protocol"; 19 | 20 | export default function websocket(self: Window | any) { 21 | const target = () => 22 | self.location.protocol.replace('http', 'ws') + '//' + new URL((self.__dynamic$config.bare.path + '/' || '/bare/') + 'v1/', new URL(location.origin)).href 23 | .replace(/http(s?):\/\//g, '') 24 | .replace(/\/\//g, '/') as string; 25 | 26 | const WSUrl: PropertyDescriptor | any = Object.getOwnPropertyDescriptor( 27 | self.WebSocket.prototype, 28 | "url" 29 | ); 30 | 31 | self.__dynamic.define(self.WebSocket.prototype, "url", { 32 | get() { 33 | const url = WSUrl.get.call(this); 34 | 35 | return self.__dynamic.url.decode(url) as string; 36 | }, 37 | set(val: any) { 38 | return false; 39 | }, 40 | }); 41 | 42 | self.WebSocket = self.__dynamic.wrap( 43 | self.WebSocket, 44 | (e: any, ...args: Array>) => { 45 | console.log(args); 46 | const url: URL = new URL(args[0] as string); 47 | 48 | const r: any = { 49 | remote: { 50 | host: url.hostname, 51 | port: url.port || (url.protocol === "wss:" ? "443" : "80"), 52 | path: url.pathname + url.search, 53 | protocol: url.protocol, 54 | }, 55 | headers: { 56 | Host: url.hostname + (url.port ? ":" + url.port : ""), 57 | Origin: self.__dynamic$location.origin, 58 | Pragma: "no-cache", 59 | "Cache-Control": "no-cache", 60 | Upgrade: "websocket", 61 | Connection: "Upgrade", 62 | }, 63 | forward_headers: [ 64 | "accept-encoding", 65 | "accept-language", 66 | "sec-websocket-extensions", 67 | "sec-websocket-key", 68 | "sec-websocket-version", 69 | "sec-websocket-accept", 70 | ], 71 | }; 72 | 73 | if (args[1]) { 74 | r.headers["sec-websocket-protocol"] = args[1].toString(); 75 | } 76 | 77 | return [ 78 | target(), 79 | ["bare", encode_protocol(JSON.stringify(r))], 80 | ]; 81 | } 82 | ); 83 | } -------------------------------------------------------------------------------- /docs/configuration/encoding.md: -------------------------------------------------------------------------------- 1 | # URL Encoding and Decoding 2 | 3 | In the context of Dynamic, and other popular Interception proxies, URL Encoding and Decoding is the way Dynamic changes the URLs, specifically to hide them. 4 | 5 | ## Encoding types 6 | There's a few types of encodings that Dynamic currently supports. 7 | 8 | ### XOR 9 | The XOR encryption algorithm is an example of symmetric encryption where the same key is used to both encrypt and decrypt a message. Symmetric Encryption: The same cryptographic key is used both to encrypt and decrypt messages 10 | 11 | Okay, yes, XOR is a cipher not an encoding. But for the purpose of simplicity, we're going to refer to it as an encoding. 12 | 13 | Example: 14 | * `https://google.com` 15 | * `hvtrs8%2F-wuw%2Cgmoelg.aoo%2F` 16 | * `https://www.youtube.com` 17 | * `hvtrs8%2F-wuw%2Cymuvu%60e%2Ccmm-` 18 | 19 | Want to use XOR? Change your `encoding` value to `xor` 20 | 21 | ### AES 22 | Similar to the XOR encoding, AES (Advanced Encryption Standard) encoding is a type of symmetric encryption where the same key is used to both encrypt and decrypt a message, however AES doesn't settle for a one-byte affair; it operates with much longer key lengths (up to 256 bits) compared to the 8 bits of XOR. Like XOR, it is also a cipher and not an encoding. If you're trying to hide your activity the best, AES is the way to go. While the URL may not be readable, it will be **very** difficult for a third party to decrypt the URL without the key. 23 | 24 | Example: 25 | * `https://google.com` 26 | * `88b1yAJnVf99jJZjWhNiho+l5CUg1PRDZGg0Dn005/MseDO3Sn2Mzs` 27 | * `https://www.youtube.com` 28 | * `+Bu/h2WhD6UXm5YAYzOuiiPEmA5l/gEZC0CUtY4jb3h6f4Cgwzsm/i` 29 | 30 | If this fits your need, Change your `encoding` value to `aes` 31 | 32 | ### Plain 33 | In computing, plain encoding is a loose term for data (e.g. file contents) that represent *only characters* of readable material but not its graphical representation nor other objects (floating-point numbers, images, etc.). It may also include a limited number of "whitespace" characters that affect simple arrangement of text. 34 | Note that this provides very little URL cloaking. 35 | 36 | Example: 37 | * `https://google.com` 38 | * `https%3A%2F%2Fgoogle.com` 39 | * `https://www.youtube.com` 40 | * `https%3A%2F%2Fwww.youtube.com` 41 | 42 | If this fits your need, Change your `encoding` value to `plain` 43 | 44 | ### Base64 45 | Base64 is a encoding algorithm that allows you to transform any characters into an alphabet which consists of Latin letters, digits, plus, and slash. Thanks to it, Dynamic can hide URLs by turning the letters of the URL into numbers. 46 | 47 | Example: 48 | * `https://google.com` 49 | * `aHR0cHM6Ly9nb29nbGUuY29t` 50 | * `https://www.youtube.com` 51 | * `aHR0cHM6Ly93d3cueW91dHViZS5jb20=` 52 | 53 | If this fits your need, Change your `encoding` value to `base64` 54 | 55 | 56 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import Fastify from 'fastify'; 2 | import fastifyStatic from '@fastify/static'; 3 | import fastifyCompress from '@fastify/compress'; 4 | import { createBareServer } from '@tomphttp/bare-server-node'; 5 | import { createServer } from 'http'; 6 | import chalk from 'chalk'; 7 | import open from 'open'; 8 | import { existsSync } from 'fs'; 9 | import { join, dirname } from 'path'; 10 | import { fileURLToPath } from 'url'; 11 | import { createRequire } from 'module'; 12 | const require = createRequire(import.meta.url); 13 | const gitCommitInfo = require('git-commit-info'); 14 | 15 | 16 | if (!existsSync("./dist")) await import("./esbuild.prod.js"); 17 | 18 | const __dirname = dirname(fileURLToPath(import.meta.url)); 19 | 20 | const port = process.env.PORT || 3000; 21 | const _v = process.env.npm_package_version; 22 | const info = { 23 | hashShort: `${JSON.stringify(gitCommitInfo().shortHash).replace('"', "").replace("/", "").replace('\"', "")}`, 24 | hash: `${JSON.stringify(gitCommitInfo().hash).replace('"', "").replace("/", "").replace('\"', "")}`, 25 | version: _v, 26 | } 27 | 28 | const bare = createBareServer('/bare/'); 29 | const serverFactory = (handler, opts) => { 30 | return createServer() 31 | .on("request", (req, res) => { 32 | if (req.url === "/info") { 33 | res.writeHead(200, { 'Content-Type': 'application/json' }); 34 | res.end(JSON.stringify(info)); 35 | } else if (bare.shouldRoute(req)) { 36 | bare.routeRequest(req, res); 37 | } else { 38 | handler(req, res) 39 | } 40 | }).on("upgrade", (req, socket, head) => { 41 | if (bare.shouldRoute(req)) { 42 | bare.routeUpgrade(req, socket, head); 43 | } else { 44 | socket.end(); 45 | } 46 | }); 47 | } 48 | const fastify = Fastify({ serverFactory }); 49 | fastify.register(fastifyStatic, { 50 | root: join(__dirname, "./static"), 51 | decorateReply: false 52 | }); 53 | fastify.register(fastifyStatic, { 54 | root: join(__dirname, "./dist"), 55 | prefix: "/dynamic/", 56 | decorateReply: false 57 | }); 58 | fastify.register(fastifyCompress, { 59 | encodings: ["br"] 60 | }); 61 | 62 | const URL = `http://localhost:${port}/`; 63 | fastify.listen({ port }, async (err) => { 64 | if (err && err.code === "EADDRINUSE") { 65 | console.log(chalk.red.bold(`[Dynamic ${_v}] `) + "Port is already in use! Please close any apps using port " + chalk.bold.underline.red(port) + " and try again."); 66 | process.exit(1); 67 | } else if (err) { 68 | console.log(chalk.bold.red(`[Dynamic ${_v}] `) + "An error occurred while starting the server! \n" + err); 69 | process.exit(1); 70 | } 71 | console.log(chalk.bold('Thanks for using Dynamic!'), chalk.red(`Please notice that ${chalk.red.bold('dynamic is currently in public BETA')}. please report all issues to the GitHub page. `)) 72 | console.log(chalk.green.bold(`Dynamic ${_v} `) + "live at port " + chalk.bold.green(port)); 73 | try { 74 | await open(URL); 75 | } catch (ERR) { 76 | console.error(ERR); 77 | } 78 | }); -------------------------------------------------------------------------------- /lib/global/util/reqHeader.ts: -------------------------------------------------------------------------------- 1 | import MetaURL from "../meta/type"; 2 | import DynamicUtil from "../util"; 3 | 4 | export default function Header(this: DynamicUtil, headers: Object | any, meta: MetaURL, request: Request & { client: any }, cookies: string) { 5 | let { referrer }: any = request; 6 | 7 | [ 8 | 'origin', 9 | 'Origin', 10 | 'host', 11 | 'Host', 12 | 'referer', 13 | 'Referer' 14 | ].forEach((header: string) => { 15 | if (headers[header]) delete headers[header]; 16 | }); 17 | 18 | headers['Origin'] = `${meta.protocol}//${meta.host}${meta.port ? ':'+meta.port : ''}`; 19 | headers['Host'] = meta.host + (meta.port ? ':'+meta.port : ''); 20 | headers['Referer'] = meta.href; 21 | 22 | if (request.referrerPolicy == 'strict-origin-when-cross-origin') headers['Referer'] = `${meta.protocol}//${meta.host}/`; 23 | 24 | if (request.referrerPolicy == 'origin' && meta.origin) { 25 | referrer = meta.origin+'/'; 26 | } 27 | 28 | if (cookies) { 29 | switch(request.credentials) { 30 | case 'omit': 31 | break; 32 | case 'same-origin': 33 | if (request.client) if (meta.origin == request.client.__dynamic$location.origin) headers['Cookie'] = cookies; 34 | if (!request.client) headers['Cookie'] = cookies; 35 | break; 36 | case 'include': 37 | headers['Cookie'] = cookies; 38 | break; 39 | default: 40 | break; 41 | } 42 | headers['Cookie'] = cookies; 43 | } 44 | 45 | if (referrer && referrer != location.origin+'/') { 46 | try { 47 | headers['Referer'] = this.ctx.url.decode(referrer); 48 | if (request.referrerPolicy=='strict-origin-when-cross-origin') headers['Referer'] = new URL(this.ctx.url.decode(referrer)).origin; 49 | headers['Origin'] = new URL(this.ctx.url.decode(referrer)).origin; 50 | } catch {} 51 | } 52 | 53 | if (request.client) { 54 | headers['Origin'] = request.client.__dynamic$location.origin; 55 | headers['Referer'] = request.client.__dynamic$location.href; 56 | 57 | if (request.referrerPolicy=='strict-origin-when-cross-origin') headers['Referer'] = request.client.__dynamic$location.origin; 58 | } 59 | 60 | if (this.ctx.config.tab) { 61 | if (this.ctx.config.tab.ua) { 62 | delete headers['user-agent']; 63 | delete headers['User-Agent']; 64 | 65 | headers['user-agent'] = this.ctx.config.tab.ua; 66 | } 67 | } 68 | 69 | headers['sec-fetch-dest'] = request.destination || 'empty'; 70 | headers['sec-fetch-mode'] = request.mode || 'cors'; 71 | headers['sec-fetch-site'] = request.client ? request.client.__dynamic$location.origin == meta.origin ? request.client.__dynamic$location.port == meta.port ? 'same-origin' : 'same-site' : 'cross-origin' : 'none'; 72 | if (request.mode == 'navigate') headers['sec-fetch-site'] = 'same-origin'; 73 | headers['sec-fetch-user'] = '?1'; 74 | 75 | return new Headers(headers); 76 | } -------------------------------------------------------------------------------- /lib/global/client/methods/core/function.ts: -------------------------------------------------------------------------------- 1 | export default function Function(self: Window | any) { 2 | var _toString: Function = self.Function.prototype.toString; 3 | 4 | self.__dynamic.Function = self.Function.bind({}); 5 | 6 | self.__dynamic.define(self.Function.prototype, '_toString', { 7 | get(this: any) { 8 | return _toString; 9 | }, 10 | set: () => {} 11 | }); 12 | 13 | var string = function(this: Function): string { 14 | try { 15 | var string: string | any = Reflect.apply(_toString, this, []); 16 | } catch(e) { 17 | return `function ${this.name}() { [native code] }`; 18 | } 19 | 20 | if (string.includes('[native code]')) { 21 | return `function ${this.name}() { [native code] }`; 22 | } 23 | 24 | return string; 25 | } 26 | 27 | self.__dynamic.define(self.Function.prototype, 'toString', { 28 | get(this: any) { 29 | return this.__toString || string; 30 | }, 31 | set(val: any) { this.__toString = val; } 32 | }); 33 | 34 | self.Function = new Proxy(self.Function, { 35 | apply(t, g, a: Array): Function { 36 | var args: Array = [...a]; 37 | var body: string | undefined = args.pop(); 38 | 39 | body = `(function anonymous(${args.toString()}) {${body}})`; 40 | body = self.__dynamic.rewrite.js.rewrite(body, {type: 'script'}, false, self.__dynamic); 41 | 42 | return self.eval(body); 43 | }, 44 | construct(t, a: Array): Function { 45 | var args: Array = [...a]; 46 | var body: string | undefined = args.pop(); 47 | 48 | body = `(function anonymous(${args.toString()}) {${body}})`; 49 | body = self.__dynamic.rewrite.js.rewrite(body, {type: 'script'}, false, self.__dynamic); 50 | 51 | return self.eval(body); 52 | } 53 | }); 54 | 55 | self.Function.prototype.apply = self.__dynamic.wrap(self.Function.prototype.apply, 56 | function(this: any, handler: Function, ...args: Array): any { 57 | if (args[0] == self.__dynamic$window) args[0] = args[0].__dynamic$self; 58 | if (args[0] == self.__dynamic$document) args[0] = self.document; 59 | 60 | return Reflect.apply(handler, this, args); 61 | }, 62 | 'Function.prototype.apply' 63 | ); 64 | 65 | self.Function.prototype.call = new Proxy(self.Function.prototype.call, { 66 | apply(t, g, a: any): any { 67 | if (a[0] == self.__dynamic$window) a[0] = a[0].__dynamic$self; 68 | if (a[0] == self.__dynamic$document) a[0] = self.document; 69 | 70 | return Reflect.apply(t, g, a); 71 | } 72 | }); 73 | 74 | self.Function.prototype.bind = self.__dynamic.wrap(self.Function.prototype.bind, 75 | function(this: any, handler: Function, ...args: Array): Function { 76 | if (args[0] == self.__dynamic$window) args[0] = args[0].__dynamic$self; 77 | if (args[0] == self.__dynamic$document) args[0] = self.document; 78 | 79 | return handler.apply(this, args); 80 | }, 81 | 'Function.prototype.bind' 82 | ); 83 | } -------------------------------------------------------------------------------- /lib/global/client/index.ts: -------------------------------------------------------------------------------- 1 | import location from './methods/core/location'; 2 | import get from './methods/core/get'; 3 | import window from './methods/core/window'; 4 | import dom from './methods/core/html'; 5 | import attr from './methods/document/attr'; 6 | import worker from './methods/window/worker'; 7 | import history from './methods/window/history'; 8 | import ws from './methods/window/ws'; 9 | import fetch from './methods/window/fetch'; 10 | import message from './methods/window/message'; 11 | import write from './methods/document/write'; 12 | import imports from './methods/window/imports'; 13 | import reflect from './methods/core/reflect'; 14 | import niche from './methods/window/niche'; 15 | import storage from './methods/window/storage'; 16 | import navigator from './methods/window/navigator'; 17 | import cookie from './methods/document/cookie'; 18 | import style from './methods/document/style'; 19 | import blob from './methods/window/blob'; 20 | import mutation from './methods/document/mutation'; 21 | import _eval from './methods/core/eval'; 22 | import func from './methods/core/function'; 23 | import policy from './methods/window/policy'; 24 | import rtc from './methods/window/rtc'; 25 | 26 | import DynamicClientMethods from './methods'; 27 | 28 | export default class DynamicClient { 29 | location; 30 | get; 31 | window; 32 | attr; 33 | worker; 34 | history; 35 | ws; 36 | fetch; 37 | message; 38 | policy; 39 | write; 40 | imports; 41 | reflect; 42 | niche; 43 | storage; 44 | navigator; 45 | cookie; 46 | style; 47 | blob; 48 | mutation; 49 | eval; 50 | func; 51 | rtc; 52 | dom; 53 | 54 | define: any; 55 | wrap: any; 56 | 57 | methods = DynamicClientMethods; 58 | 59 | ctx; 60 | 61 | constructor(ctx: any) { 62 | if (self.constructor.name == "DedicatedWorkerGlobalScope" || self.constructor.name == "SharedWorkerGlobalScope") { 63 | this.message = message; 64 | this.location = location; 65 | this.window = window; 66 | this.get = get; 67 | this.reflect = reflect; 68 | this.imports = imports; 69 | this.blob = blob; 70 | this.mutation = mutation; 71 | } else { 72 | this.location = location; 73 | this.get = get; 74 | this.window = window; 75 | this.attr = attr; 76 | this.worker = worker; 77 | this.history = history; 78 | this.ws = ws; 79 | this.fetch = fetch; 80 | this.message = message; 81 | this.policy = policy; 82 | this.write = write; 83 | this.imports = imports; 84 | this.reflect = reflect; 85 | this.niche = niche; 86 | this.storage = storage; 87 | this.navigator = navigator; 88 | this.cookie = cookie; 89 | this.style = style; 90 | this.blob = blob; 91 | this.mutation = mutation; 92 | this.eval = _eval; 93 | this.func = func; 94 | this.rtc = rtc; 95 | this.dom = dom; 96 | } 97 | 98 | this.ctx = ctx; 99 | } 100 | } -------------------------------------------------------------------------------- /lib/global/url/encode.ts: -------------------------------------------------------------------------------- 1 | import MetaURL from "../meta/type"; 2 | import DynamicUrlRewriter from "../url"; 3 | 4 | export default function encode(this: DynamicUrlRewriter, url: URL | string | any, meta: MetaURL) { 5 | if (!url) return url; 6 | url = new String(url).toString(); 7 | 8 | if (url.startsWith('about:blank')) return location.origin + this.ctx.config.prefix + url; 9 | 10 | if (!url.match(this.ctx.regex.ProtocolRegex) && url.match(/^([a-zA-Z0-9\-]+)\:\/\//g)) return url; 11 | if (url.startsWith('chrome-extension://')) return url; 12 | 13 | if(url.startsWith('javascript:') 14 | && !url.startsWith('javascript:__dynamic$eval') // for some reason the tag gets called multiple times 15 | ) 16 | { 17 | let urlData = new URL(url); 18 | 19 | return `javascript:__dynamic$eval(${JSON.stringify(urlData.pathname)})` 20 | } 21 | 22 | if (url.match(this.ctx.regex.WeirdRegex)) { 23 | var data = this.ctx.regex.WeirdRegex.exec(url); 24 | 25 | if (data) url = data[2]; 26 | } 27 | 28 | if (url.startsWith(location.origin+this.ctx.config.prefix) || url.startsWith(this.ctx.config.prefix)) return url; 29 | if (url.startsWith(location.origin+this.ctx.config.assets.prefix+'dynamic.')) return url; 30 | if (url.match(this.ctx.regex.BypassRegex)) return url; 31 | 32 | if (url.match(this.ctx.regex.DataRegex)) { 33 | try { 34 | var data = this.ctx.regex.DataRegex.exec(url); 35 | 36 | if (data) { 37 | var [_, type, charset, base64, content] = data; 38 | 39 | if (base64=='base64') 40 | content = (this.ctx.modules.base64.atob(decodeURIComponent(content))); 41 | else 42 | content = decodeURIComponent(content); 43 | 44 | if (type) { 45 | if (type=='text/html') { 46 | content = this.ctx.rewrite.html.rewrite(content, meta, this.ctx.rewrite.html.generateHead(location.origin+'/dynamic/dynamic.client.js', location.origin+'/dynamic/dynamic.config.js', '', `window.__dynamic$url = "${meta.href}"; window.__dynamic$parentURL = "${location.href}";`)); 47 | } else if (type=='text/css') { 48 | content = this.ctx.rewrite.css.rewrite(content, meta); 49 | } else if (type=='text/javascript'||type=='application/javascript') { 50 | content = this.ctx.rewrite.js.rewrite(content, meta); 51 | } 52 | } 53 | 54 | if (base64=='base64') 55 | content = this.ctx.modules.base64.btoa(content); 56 | else 57 | content = encodeURIComponent(content); 58 | 59 | if (charset) { 60 | if (base64) 61 | url = `data:${type};${charset};${base64},${content}`; 62 | else 63 | url = `data:${type};${charset},${content}`; 64 | } else { 65 | if (base64) 66 | url = `data:${type};${base64},${content}`; 67 | else 68 | url = `data:${type},${content}`; 69 | } 70 | } 71 | } catch {}; 72 | 73 | return url; 74 | } 75 | 76 | url = new String(url).toString(); 77 | 78 | if (meta.href.match(this.ctx.regex.BypassRegex)) ( 79 | url = new URL(url, new URL((this.ctx.parent.__dynamic || this.ctx).meta.href)).href 80 | ); 81 | 82 | url = new URL(url, meta.href); 83 | 84 | return (this.ctx._location?.origin||(location.origin=='null'?location.ancestorOrigins[0]:location.origin))+this.ctx.config.prefix+(this.ctx.encoding.encode(url.origin + url.pathname) + url.search + url.hash); 85 | } 86 | -------------------------------------------------------------------------------- /lib/global/rewrite/html/html.ts: -------------------------------------------------------------------------------- 1 | import Srcset from './srcset'; 2 | import Node from './nodewrapper'; 3 | import MetaURL from '../../meta/type'; 4 | import generateHead from './generateHead'; 5 | import { Element } from 'parse5/dist/tree-adapters/default'; 6 | import DynamicRewrites from '../../rewrite'; 7 | 8 | export default class html { 9 | 10 | ctx: any; 11 | 12 | generateHead: Function = generateHead; 13 | 14 | config: Array = [ 15 | { 16 | "elements": "all", 17 | "tags": ['style'], 18 | "action": "css" 19 | }, 20 | { 21 | "elements": ['script', 'iframe', 'embed', 'input', 'track', 'media', 'source', 'img', 'a', 'link', 'area', 'form', 'object'], 22 | "tags": ['src', 'href', 'action', 'data'], 23 | "action": "url" 24 | }, 25 | { 26 | "elements": ['source', 'img'], 27 | "tags": ['srcset'], 28 | "action": "srcset" 29 | }, 30 | /*{ 31 | "elements": ['a', 'link', 'area'], 32 | "tags": ['href'], 33 | "action": "url" 34 | }, 35 | { 36 | "elements": ['form'], 37 | "tags": ['action'], 38 | "action": "url" 39 | }, 40 | { 41 | "elements": ['object'], 42 | "tags": ['data'], 43 | "action": "url", 44 | },*/ 45 | { 46 | "elements": ['script', 'link'], 47 | "tags": ['integrity'], 48 | "action": "rewrite", 49 | "new": "nointegrity", 50 | }, 51 | { 52 | "elements": ['script', 'link'], 53 | "tags": ['nonce'], 54 | "action": "rewrite", 55 | "new": "nononce", 56 | }, 57 | { 58 | "elements": ['meta'], 59 | "tags": ['http-equiv'], 60 | "action": "http-equiv", 61 | }, 62 | { 63 | "elements": ['iframe'], 64 | "tags": ['srcdoc'], 65 | "action": "html", 66 | }, 67 | { 68 | "elements": ['link'], 69 | "tags": ["imagesrcset"], 70 | "action": "srcset", 71 | }, 72 | { 73 | "elements": 'all', 74 | "tags": ['onclick'], 75 | "action": "js", 76 | } 77 | ]; 78 | 79 | constructor(ctx: DynamicRewrites) { 80 | this.ctx = ctx.ctx; 81 | } 82 | 83 | generateRedirect(url: string) { 84 | return ` 85 | 86 | 301 Moved 87 |

301 Moved

88 | The document has moved 89 | here. 90 | 91 | ` 92 | } 93 | 94 | iterate(_dom: Object, cb: Function) { 95 | function it(dom: Object | any = _dom) { 96 | for (var i = 0; i < dom.childNodes.length; i++) { 97 | cb(dom.childNodes[i]); 98 | 99 | if (dom.childNodes[i].childNodes) if (dom.childNodes[i].childNodes.length) { 100 | it(dom.childNodes[i]); 101 | }; 102 | } 103 | } 104 | 105 | it(_dom); 106 | } 107 | 108 | rewrite(src: string, meta: MetaURL, head: Array = []) { 109 | if (Array.isArray(src)) src = src[0]; 110 | 111 | if (!src) return src; 112 | 113 | src = src.toString(); 114 | 115 | if (!src.match(/<\!DOCTYPE[^>]*>/gi)) { 116 | src = "" + src 117 | } 118 | 119 | return src.replace(/(|)/im, `$1${head.join(``)}\n`).replace(/<(script|link)\b[^>]*>/g, (e, n) => e.replace(/\snonce\s*=\s*"[^"]*"/, e => e.replace("nonce", "nononce")).replace(/\sintegrity\s*=\s*"[^"]*"/, e => e.replace("integrity", "nointegrity"))); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /lib/global/cookie/db.ts: -------------------------------------------------------------------------------- 1 | import * as idb from 'idb'; 2 | import { Cookie } from 'set-cookie-parser'; 3 | 4 | function createObject(input: Array | undefined, newobj: Cookie) { 5 | if (!input) input = []; 6 | 7 | if (input.find((e:any)=>e.name==newobj.name)) input[input.findIndex((e:any)=>e.name==newobj.name)] = { name: newobj.name, value: newobj.value, expires: newobj.expires } 8 | else input.push({ name: newobj.name, value: newobj.value, expires: newobj.expires }); 9 | 10 | return input as Array; 11 | } 12 | 13 | export const DB = { 14 | open: async () => { 15 | return idb.openDB('__dynamic$cookies', 1, { 16 | async upgrade(db) { 17 | await db.createObjectStore('__dynamic$cookies'); 18 | } 19 | }); 20 | }, 21 | set: async (host: string, raw: Cookie & { raw: any }, db: Promise) => { 22 | if (raw.domain) host = raw.domain as string; 23 | if (host.startsWith('.')) host = host.slice(1); 24 | 25 | if (raw.expires) { 26 | var expires: Date = new Date(raw.expires); 27 | 28 | if (expires < new Date()) return DB.remove(host, raw, db); 29 | } 30 | 31 | await (await db).put('__dynamic$cookies', createObject((await (await db).get('__dynamic$cookies', host)), raw), host); 32 | 33 | return true; 34 | }, 35 | get: async (host: string, db: Promise) => { 36 | var baseHost: string = host.replace(/^(.*\.)?([^.]*\..*)$/g, "$2"); 37 | var first: Array = await (await db).get('__dynamic$cookies', host) || []; 38 | 39 | if (host !== baseHost && host !== '.' + baseHost) { 40 | var cookies: Array = await (await db).get('__dynamic$cookies', baseHost); 41 | 42 | if (cookies) { 43 | for (var {name, value, expires} of cookies) { 44 | if (expires) { 45 | var target: Date = new Date(expires); 46 | 47 | if (target <= new Date()) { DB.remove(host, cookies.find((e:any)=>e.name==name&&e.value==value&&e.expires==expires), db); continue; }; 48 | } 49 | 50 | if (!first.find((e:any)=>e.name==name && e.value==value)) first.push({ name, value, expires: expires || new Date(10e+12) }); 51 | } 52 | } 53 | } 54 | 55 | return first as Array; 56 | }, 57 | remove: async (host: string, raw: Cookie, db: Promise) => { 58 | if (raw.domain) host = raw.domain; 59 | 60 | if (host.startsWith('.')) host = host.slice(1); 61 | 62 | var cookies: Array = await (await db).get('__dynamic$cookies', host); 63 | 64 | if (!cookies) return false; 65 | 66 | cookies = cookies.filter((e:any)=>e.name!==raw.name); 67 | 68 | await (await db).put('__dynamic$cookies', cookies, host); 69 | 70 | return true; 71 | }, 72 | update: async (host: string, db: Promise) => { 73 | var baseHost: string = host.replace(/^(.*\.)?([^.]*\..*)$/g, "$2"); 74 | 75 | var cookies: Array = await (await db).get('__dynamic$cookies', baseHost); 76 | 77 | if (cookies) { 78 | for (var {name, value, expires} of cookies) { 79 | if (expires) { 80 | var target: Date = new Date(expires); 81 | 82 | if (target <= new Date()) { DB.remove(host, {name, value, expires}, db); continue; }; 83 | } 84 | } 85 | } 86 | 87 | return cookies as Array; 88 | } 89 | } -------------------------------------------------------------------------------- /static/resources/scripts/settings.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | class Modal { 3 | 4 | constructor() { 5 | this.triggers = document.querySelectorAll('.js-modal'); 6 | this.close = document.querySelectorAll('.js-close-modal'); 7 | this.modals = document.querySelectorAll('.modal'); 8 | this.modalInners = document.querySelectorAll('.modal-inner'); 9 | 10 | this.listeners(); 11 | } 12 | 13 | listeners() { 14 | window.addEventListener('keydown', this.keyDown); 15 | 16 | this.triggers.forEach(el => { 17 | el.addEventListener('click', this.openModal, false); 18 | }); 19 | 20 | this.modals.forEach(el => { 21 | el.addEventListener('transitionend', this.revealModal, false); 22 | el.addEventListener('click', this.backdropClose, false); 23 | }); 24 | 25 | this.close.forEach(el => { 26 | el.addEventListener('click', Modal.hideModal, false); 27 | }); 28 | 29 | this.modalInners.forEach(el => { 30 | el.addEventListener('transitionend', this.closeModal, false); 31 | }); 32 | } 33 | 34 | keyDown(e) { 35 | if (27 === e.keyCode && document.body.classList.contains('modal-body')) { 36 | Modal.hideModal(); 37 | } 38 | } 39 | 40 | backdropClose(el) { 41 | if (!el.target.classList.contains('modal-visible')) { 42 | return; 43 | } 44 | 45 | let backdrop = el.currentTarget.dataset.backdrop !== undefined ? el.currentTarget.dataset.backdrop : true; 46 | 47 | if (backdrop === true) { 48 | Modal.hideModal(); 49 | } 50 | } 51 | 52 | static hideModal() { 53 | let modalOpen = document.querySelector('.modal.modal-visible'); 54 | 55 | modalOpen.querySelector('.modal-inner').classList.remove('modal-reveal'); 56 | document.querySelector('.modal-body').addEventListener('transitionend', Modal.modalBody, false); 57 | document.body.classList.add('modal-fadeOut'); 58 | } 59 | 60 | closeModal(el) { 61 | if ('opacity' === el.propertyName && !el.target.classList.contains('modal-reveal')) { 62 | document.querySelector('.modal.modal-visible').classList.remove('modal-visible'); 63 | } 64 | } 65 | 66 | openModal(el) { 67 | if (!el.currentTarget.dataset.modal) { 68 | console.error('No data-modal attribute defined!'); 69 | return; 70 | } 71 | 72 | let modalID = el.currentTarget.dataset.modal; 73 | let modal = document.getElementById(modalID); 74 | 75 | document.body.classList.add('modal-body'); 76 | modal.classList.add('modal-visible'); 77 | } 78 | 79 | revealModal(el) { 80 | if ('opacity' === el.propertyName && el.target.classList.contains('modal-visible')) { 81 | el.target.querySelector('.modal-inner').classList.add('modal-reveal'); 82 | } 83 | } 84 | 85 | static modalBody(el) { 86 | if ('opacity' === el.propertyName && el.target.classList.contains('modal') && !el.target.classList.contains('modal-visible')) { 87 | document.body.classList.remove('modal-body', 'modal-fadeOut'); 88 | } 89 | }} 90 | new Modal(); 91 | 92 | window.addEventListener('DOMContentLoaded', function (){ 93 | 94 | const versionInd = document.getElementById('settings-version') 95 | const xhr = new XMLHttpRequest(); 96 | xhr.open("GET", '/info'); 97 | xhr.send(); 98 | xhr.responseType = "json"; 99 | xhr.onload = () => { 100 | if (xhr.readyState == 4 && xhr.status == 200) { 101 | const response = xhr.response; 102 | versionInd.innerHTML = `Dynamic v${response.version} (${response.hashShort}) ` 103 | const hashHover = document.getElementById('hashHover') 104 | hashHover.onclick = function displayFullHash(){ 105 | console.log('cool') 106 | hashHover.innerText = `(${response.hash})` 107 | hashHover.style.fontSize = `10px` 108 | } 109 | } else { 110 | versionInd.innerText = 'Unable to get version' 111 | } 112 | }; 113 | 114 | }) 115 | 116 | -------------------------------------------------------------------------------- /bin/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | tput setaf 33; echo "Thanks for using Dynamic!"; tput sgr0 3 | 4 | #Navigating to the project root 5 | scriptDir="${0%/*}" 6 | cd $scriptDir 7 | cd ../ 8 | echo "Project Directory: $(pwd)" 9 | 10 | tput bold; echo "Dev build is currently still being working on, choose at your own risk"; tput sgr0 11 | 12 | while [[ $devAns != "dev" ]] || [[ $devAns != "prod" ]] 13 | do 14 | echo "Dev or Prod? dev/prod" 15 | read devAns 16 | if [[ $devAns == "dev" ]] || [[ $devAns == "prod" ]] 17 | then 18 | break 19 | else 20 | tput setaf 124; echo "Invalid Input"; tput sgr0 21 | fi 22 | done 23 | 24 | echo "Checking if packages are installed" 25 | if ls | grep -q node_modules 26 | then 27 | echo "node_modules found" 28 | 29 | while [[ $cleanAns != "y" ]] || [[ $cleanAns != "n" ]] 30 | do 31 | echo "Would you like to reinstall? y/n" 32 | read cleanAns 33 | if [[ $cleanAns == "y" ]] || [[ $cleanAns == "n" ]] 34 | then 35 | break 36 | else 37 | tput setaf 124; echo "Invalid Input"; tput sgr0 38 | fi 39 | done 40 | 41 | if [[ $cleanAns = "y" ]] 42 | then 43 | echo "Cleaning node_modules" 44 | rm -rf node_modules 45 | echo "Installing node_modules" 46 | npm install 47 | elif [[ $cleanAns = "n" ]] 48 | then 49 | echo "Skipping packages" 50 | fi 51 | 52 | else 53 | echo "node_modules not found" 54 | 55 | while [[ $installAns != "y" ]] || [[ $installAns != "n" ]] 56 | do 57 | echo "Would you like to install? y/n" 58 | read installAns 59 | if [[ $installAns == "y" ]] || [[ $installAns == "n" ]] 60 | then 61 | break 62 | else 63 | tput setaf 124; echo "Invalid Input"; tput sgr0 64 | fi 65 | done 66 | 67 | if [[ $installAns == "y" ]] 68 | then 69 | echo "Installing node_modules" 70 | npm install 71 | elif [[ $installAns == "n" ]] 72 | then 73 | echo "Skipping packages" 74 | fi 75 | fi 76 | 77 | if [[ $devAns == "dev" ]] 78 | then 79 | while [[ $buildAns != "y" ]] || [[ $buildAns != "n" ]] 80 | do 81 | echo "Would you like to build and start? y/n" 82 | read buildAns 83 | if [[ $buildAns == "y" ]] || [[ $buildAns == "n" ]] 84 | then 85 | break 86 | else 87 | tput setaf 124; echo "Invalid Input"; tput sgr0 88 | fi 89 | done 90 | 91 | if [[ $buildAns == 'y' ]] 92 | then 93 | echo "Running Dynamic" 94 | npm run build:dev 95 | elif [[ $buildAns == 'n' ]] 96 | then 97 | tput setaf 124; echo "Exiting Dynamic"; tpur sgr0 98 | fi 99 | 100 | elif [[ $devAns == "prod" ]] 101 | then 102 | 103 | while [[ $buildAns != "build" ]] || [[ $buildAns != "start" ]] || [[ $buildAns != "both" ]] 104 | do 105 | tput sitm; echo "Hint: ctrl + c to exit"; tput sgr0 106 | echo "Would you like to build, start, or both? build/start/both" 107 | read buildAns 108 | if [[ $buildAns == "build" ]] || [[ $buildAns == "start" ]] || [[ $buildAns == "both" ]] 109 | then 110 | break 111 | else 112 | tput setaf 124; echo "Invalid Input"; tput sgr0 113 | fi 114 | done 115 | 116 | if [[ $buildAns == "build" ]] 117 | then 118 | echo "Building Dynamic" 119 | npm run build:$devAns 120 | elif [[ $buildAns == "start" ]] 121 | then 122 | echo "Starting Dynamic" 123 | npm run start 124 | elif [[ $buildAns == "both" ]] 125 | then 126 | echo "Doing Both!" 127 | echo "Building Dynamic" 128 | npm run build:$devAns 129 | echo "Starting Dynamic :)" 130 | npm run start 131 | fi 132 | fi 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /lib/global/client/methods/window/storage.ts: -------------------------------------------------------------------------------- 1 | export default function storage(self: Window | any) { 2 | 3 | self.Storage.prototype.setItem = self.__dynamic.wrap(self.Storage.prototype.setItem, 4 | function(this: Storage, target: Function, ...args: Array): void { 5 | if (args[0]) args[0] = '__dynamic$' + self.__dynamic$location.host + '$' + args[0].toString(); 6 | 7 | return Reflect.apply(target, this, args) as undefined; 8 | }, 9 | 'Storage.prototype.setItem' 10 | ); 11 | 12 | self.Storage.prototype.getItem = self.__dynamic.wrap(self.Storage.prototype.getItem, 13 | function(this: Storage, target: Function, ...args: Array): string | null { 14 | if (args[0]) args[0] = '__dynamic$' + self.__dynamic$location.host + '$' + args[0].toString(); 15 | 16 | return (Reflect.apply(target, this, args) as string || null); 17 | }, 18 | 'Storage.prototype.getItem' 19 | ); 20 | 21 | self.Storage.prototype.removeItem = self.__dynamic.wrap(self.Storage.prototype.removeItem, 22 | function(this: Storage, target: Function, ...args: Array): void { 23 | if (args[0]) args[0] = '__dynamic$' + self.__dynamic$location.host + '$' + args[0].toString(); 24 | 25 | return Reflect.apply(target, this, args) as undefined; 26 | }, 27 | 'Storage.prototype.removeItem' 28 | ); 29 | 30 | self.Storage.prototype.clear = self.__dynamic.wrap(self.Storage.prototype.clear, 31 | function(this: Storage, target: Function, ...args: Array): void { 32 | var keys: Array = []; 33 | 34 | for (var i = 0; i < this.length; i++) { 35 | if (target.call(this, i)?.startsWith('__dynamic$' + self.__dynamic$location.host + '$')) keys.push(target.call(this, i)?.replace('__dynamic$' + self.__dynamic$location.host + '$', '')); 36 | } 37 | 38 | for (var key in keys) { 39 | target.call(this, keys[key]); 40 | } 41 | 42 | return; 43 | }, 44 | 'Storage.prototype.clear' 45 | ); 46 | 47 | self.Storage.prototype.key = self.__dynamic.wrap(self.Storage.prototype.key, 48 | function(this: Storage, target: Function, ...args: Array): string | null { 49 | var keys: Array = []; 50 | 51 | for (var i = 0; i < this.length; i++) { 52 | if (target.call(this, i)?.startsWith('__dynamic$' + self.__dynamic$location.host + '$')) keys.push(target.call(this, i)?.replace('__dynamic$' + self.__dynamic$location.host + '$', '')); 53 | } 54 | 55 | if (keys[args[0]]) return keys[args[0]]; 56 | 57 | return null; 58 | }, 59 | 'Storage.prototype.key' 60 | ); 61 | 62 | ["localStorage", "sessionStorage"].forEach((storage: any) => { 63 | self['__dynamic$'+storage] = new Proxy(self[storage], { 64 | get(target, prop: any): any { 65 | if (prop == 'length') { 66 | var keys = []; 67 | 68 | for (var i = 0; i < Object.keys(self.__dynamic.storage[storage]).length; i++) { 69 | if (Object.keys(self.__dynamic.storage[storage])[i].startsWith('__dynamic$' + self.__dynamic$location.host + '$')) keys.push(Object.keys(self.__dynamic.storage[storage])[i].replace('__dynamic$' + self.__dynamic$location.host + '$', '')); 70 | } 71 | 72 | return keys.length; 73 | } 74 | 75 | if (self.__dynamic.storage.methods.includes(prop)) return self.__dynamic.storage.cloned[storage][prop].bind(self.__dynamic.storage[storage]) 76 | 77 | return self.__dynamic.storage[storage].getItem('__dynamic$' + self.__dynamic$location.host + '$' + prop.toString()); 78 | }, 79 | set(target, prop: any, value: any): any { 80 | self.__dynamic.storage[storage].setItem('__dynamic$' + self.__dynamic$location.host + '$' + prop.toString(), value); 81 | 82 | return value || true; 83 | }, 84 | deleteProperty(target, prop: any): any { 85 | return self.__dynamic.storage[storage].removeItem('__dynamic$' + self.__dynamic$location.host + '$' + prop.toString()); 86 | } 87 | }); 88 | 89 | delete self[storage]; 90 | 91 | self[storage] = self['__dynamic$'+storage]; 92 | }); 93 | } -------------------------------------------------------------------------------- /lib/global/client/methods/window/message.ts: -------------------------------------------------------------------------------- 1 | export default function message(self: Window | any) { 2 | const isWorker = (s: any) => s.constructor.name=='Worker' || s.constructor.name=='MessagePort' || self.constructor.name=='DedicatedWorkerGlobalScope'; 3 | const isTarget = (s: any) => s.constructor.name=="Window" || s.constructor.name=='global'; 4 | const getWindow = (name: any, location: any) => Object.keys(window || {}).map(e=>parseInt(e)).filter(e=>isFinite(e)).map(e=>window[e]).filter(e=>e||false).find((e: any)=>{try{return e.name == name && e.location.href == location} catch {return false;}}); 5 | 6 | self.__dynamic$message = function(target: Window & any, origin: Window | null & any = top) { 7 | if (!target) target = self; 8 | 9 | function __d$Send(): void { 10 | var args = arguments; 11 | 12 | if (isWorker(target) || !isTarget(target)) 13 | return target.postMessage.call(target, ...args); 14 | 15 | if (target.__dynamic$self) target = target.__dynamic$self; 16 | 17 | return (target._postMessage || target.postMessage).call(target, ...[[args[0], origin.__dynamic$location.origin, origin.location.href, origin.name, origin !== self], '*', args[2]||[]]); 18 | } 19 | 20 | return __d$Send; 21 | } 22 | 23 | if (self.constructor.name == 'Window') { 24 | if (self.addEventListener) self.addEventListener = new Proxy(self.addEventListener, { 25 | apply(t, g, a: Array): void { 26 | if (g==self.__dynamic$window) g = self; 27 | if (!a[1] || !a[0] || typeof a[1] != 'function') return Reflect.apply(t, g, a); 28 | 29 | if (a[0]=='message') { 30 | var o = a[1].bind({}); 31 | 32 | a[1] = function(event: MessageEvent | any) { 33 | return o(cloneEvent(event)); 34 | } 35 | } 36 | 37 | return Reflect.apply(t, g, a); 38 | } 39 | }); 40 | 41 | if (self.constructor.name == 'Window') self.__dynamic.define(self, 'onmessage', { 42 | get(): Function | null { 43 | return self._onmessage || null; 44 | }, 45 | set(val: Function | null): Function | null { 46 | if (self._onmessage) {self.removeEventListener('message', self._onmessage)} 47 | 48 | self.addEventListener('message', val);; 49 | return self._onmessage = val; 50 | } 51 | }); 52 | } 53 | 54 | function cloneEvent(event: MessageEvent | any): MessageEvent { 55 | const cloned = self.__dynamic.util.clone(event); 56 | 57 | let _window: any; 58 | 59 | if (event.source) _window = getWindow(event.data[3], event.data[2]) || event.currentTarget; 60 | 61 | self.__dynamic.define(cloned, 'isTrusted', { 62 | value: true, 63 | writable: false, 64 | }); 65 | 66 | if (event.origin) { 67 | if (Array.isArray(event.data) && event.data.length == 5) self.__dynamic.define(cloned, 'origin', { 68 | value: event.data[1], 69 | writable: false, 70 | }); else self.__dynamic.define(cloned, 'origin', { 71 | value: event.origin, 72 | writable: false, 73 | }); 74 | } 75 | 76 | if (event.data) { 77 | if (Array.isArray(event.data) && event.data.length == 5) self.__dynamic.define(cloned, 'data', { 78 | value: event.data[0], 79 | writable: false, 80 | }); else self.__dynamic.define(cloned, 'data', { 81 | value: event.data, 82 | writable: false, 83 | }); 84 | } 85 | 86 | if (event.source) { 87 | if (_window) { 88 | self.__dynamic.define(cloned, 'source', { 89 | value: _window?.__dynamic$window || _window, 90 | writable: true, 91 | }); 92 | } else { 93 | self.__dynamic.define(cloned, 'source', { 94 | value: _window || (Array.isArray(event.data) && event.data.length == 3 && event.data[2] === true) ? event.source : event.currentTarget, 95 | writable: true, 96 | }); 97 | }; 98 | } 99 | 100 | for (var i in event) { 101 | switch(i) { 102 | default: 103 | if (i !== 'isTrusted' && i !== 'origin' && i !== 'data' && i !== 'source') { 104 | self.__dynamic.define(cloned, i, { 105 | value: event[i], 106 | writable: false, 107 | }); 108 | } 109 | 110 | break; 111 | } 112 | } 113 | 114 | return cloned; 115 | } 116 | } -------------------------------------------------------------------------------- /lib/global/client/methods/window/fetch.ts: -------------------------------------------------------------------------------- 1 | export default function fetch(self: Window | any) { 2 | self.Request = self.__dynamic.wrap(self.Request, 3 | function(target: Function, ...args: Array): Request | Array { 4 | if (args[0] instanceof target) { 5 | const request: Request | any = Reflect.construct(target, args); 6 | 7 | if (args[0].mode === 'navigate') { 8 | request.mode = 'same-origin'; 9 | } 10 | 11 | return request as Request; 12 | } 13 | 14 | if (args[0]) { 15 | args[0] = self.__dynamic.url.encode(args[0], self.__dynamic.meta); 16 | } 17 | 18 | return args as Array; 19 | } 20 | ); 21 | 22 | self.__dynamic.define(self.Request.prototype, 'url', { 23 | get(): string { 24 | return self.__dynamic.url.decode(self.__dynamic.http.RequestURL.get.call(this)); 25 | }, 26 | set(value: string): string { 27 | return value; 28 | } 29 | }); 30 | 31 | self.fetch = self.__dynamic.wrap(self.fetch, 32 | function(this: Window, target: Function, ...args: Array): Promise { 33 | if (self.Request) if (args[0].constructor.name === 'Request' || args[0] instanceof self.Request) { 34 | console.log(args[0]); 35 | return Reflect.apply(target, self, args) as Promise; 36 | } 37 | 38 | if (args[0] && self.__dynamic) { 39 | args[0] = self.__dynamic.url.encode(args[0], self.__dynamic.meta); 40 | } 41 | 42 | return Reflect.apply(target, self, args) as Promise; 43 | }, 44 | 'fetch' 45 | ); 46 | 47 | self.XMLHttpRequest.prototype.open = self.__dynamic.wrap(self.XMLHttpRequest.prototype.open, 48 | function(this: XMLHttpRequest, target: Function, ...args: Array): undefined { 49 | if (args[1]) { 50 | args[1] = self.__dynamic.url.encode(args[1], self.__dynamic.meta); 51 | } 52 | 53 | if (args[2] === false) { 54 | args[2] = true; 55 | } 56 | 57 | return Reflect.apply(target, this, args) as undefined; 58 | }, 59 | 'XMLHttpRequest.prototype.open' 60 | ); 61 | 62 | Object.defineProperty(self.XMLHttpRequest.prototype, 'responseURL', { 63 | get(): string { 64 | return self.__dynamic.url.decode(self.__dynamic.http.XMLResponseURL.get.call(this)); 65 | }, 66 | set(value: string): string { 67 | return value; 68 | } 69 | }); 70 | 71 | Object.defineProperty(self.Response.prototype, 'url', { 72 | get(): string { 73 | return self.__dynamic.url.decode(self.__dynamic.http.ResponseURL.get.call(this)); 74 | }, 75 | set(value: string): string { 76 | return value; 77 | } 78 | }); 79 | 80 | self.open = self.__dynamic.wrap(self.open, 81 | function(this: Window, target: Function, ...args: Array): Window | null { 82 | if (args[0] != '') { 83 | if (args[0]) { 84 | args[0] = self.__dynamic.url.encode(args[0], self.__dynamic.meta); 85 | } 86 | } 87 | 88 | if (args[0] == '') { 89 | args[0] = 'about:blank'; 90 | } 91 | 92 | const win: Window | any = Reflect.apply(target, this, args); 93 | 94 | win.opener = self.__dynamic$window; 95 | 96 | try { 97 | if (new URL(args[0]).protocol === 'about:') { 98 | win.__dynamic$url = 'about:srcdoc'; 99 | } else { 100 | win.__dynamic$url = self.__dynamic.url.decode(args[0]); 101 | } 102 | } catch { 103 | win.__dynamic$url = 'about:srcdoc'; 104 | } 105 | 106 | self.__dynamic.elements.client(win, self.__dynamic$config, win.__dynamic$url); 107 | 108 | return win.__dynamic$window as Window; 109 | }, 110 | 'window.open' 111 | ); 112 | 113 | self.__dynamic.define(self, '__dynamic$import', { 114 | get(): Function { 115 | return function(url: any, path: any): string { 116 | try { 117 | return self.__dynamic.url.encode(url, new URL(path)); 118 | } catch { 119 | return self.__dynamic.url.encode(url, self.__dynamic.meta); 120 | } 121 | } 122 | }, 123 | set: () => {}, 124 | }); 125 | } -------------------------------------------------------------------------------- /lib/global/client/methods/core/location.ts: -------------------------------------------------------------------------------- 1 | export default function Location(self: any, doc: Boolean = true) { 2 | const cloneAncestor: Function = (ancestor: DOMStringList) => { 3 | let cloned: DOMStringList = self.__dynamic.util.clone(ancestor); 4 | 5 | for (var i = 0; i < ancestor.length; i++) { 6 | self.__dynamic.define(cloned, i, { 7 | value: (self.top.__dynamic$location || self.__dynamic$location).origin, 8 | configurable: true, 9 | enumerable: true, 10 | writable: false 11 | }); 12 | } 13 | 14 | self.__dynamic.define(cloned, 'length', { 15 | value: ancestor.length, 16 | configurable: true, 17 | enumerable: true, 18 | writable: false 19 | }); 20 | 21 | return cloned as DOMStringList; 22 | } 23 | 24 | const ancestor: DOMStringList | Array = self.location.ancestorOrigins || []; 25 | 26 | const descriptors: Array = [ 27 | self.Window, 28 | self.Location, 29 | self.WorkerLocation, 30 | self.Document, 31 | ].filter(object => object); 32 | 33 | [...descriptors, self.Object].forEach(object => { 34 | delete object['prototype']['__dynamic$location']; 35 | }); 36 | 37 | const descriptor: PropertyDescriptor = { 38 | get() { 39 | return self.__dynamic.location; 40 | }, 41 | set(value: Location | string) { 42 | if (value instanceof self.Location) return self.__dynamic.location = value; 43 | 44 | self.__dynamic.location.href = value; 45 | }, 46 | configurable: true, 47 | }; 48 | 49 | const props: Array = [ 50 | "href", 51 | "host", 52 | "hash", 53 | "origin", 54 | "hostname", 55 | "port", 56 | "pathname", 57 | "protocol", 58 | "search", 59 | ]; 60 | 61 | const funcs: Array = [ 62 | "assign", 63 | "replace", 64 | "toString", 65 | "reload" 66 | ]; 67 | 68 | try { 69 | var property: URL = new URL(self.__dynamic$url || self.__dynamic.url.decode(self.location.pathname + self.location.search + self.location.hash)); 70 | } catch { 71 | self.__dynamic$url = 'about:blank' 72 | var property: URL = new URL('about:blank'); 73 | } 74 | 75 | self.__dynamic.property = property; 76 | self.__dynamic.meta.load(property as URL); 77 | self.__dynamic.location = self.__dynamic.util.clone(self.location) as Location 78 | 79 | props.forEach(prop => { 80 | self.__dynamic.define(self.__dynamic.location, prop, { 81 | get: () => 82 | (prop == 'search' && (self.location[prop] + (self.location.search ? property.search.replace('?', '&') : property.search))) || (prop == 'hash' ? location[prop] : (property as any)[prop] as string), 83 | set: (e: any) => { 84 | if (prop === "href") { 85 | (self.location[prop] = self.__dynamic.url.encode(self.__dynamic.meta.href.replace((property as any)[prop], e), property)) as string 86 | } 87 | else { 88 | self.location[prop] = e.toString(); 89 | } 90 | } 91 | }); 92 | }); 93 | 94 | self.__dynamic.define(self.Object.prototype, '__dynamic$location', { 95 | get() { 96 | if (this === self || this === self.__dynamic$window || this === self.document || this === self.__dynamic$document) return this.__dynamic?.location; 97 | 98 | return this.location; 99 | }, 100 | set(value: string) { 101 | if (this === self || this === self.__dynamic$window || this === self.document || this === self.__dynamic$document) return this.__dynamic.location.href = value; 102 | 103 | return this.location = value; 104 | }, 105 | configurable: true 106 | }) 107 | 108 | funcs.forEach(func => { 109 | self.__dynamic.define(self.__dynamic.location, func, { 110 | get: () => { 111 | if (func == 'toString') return () => property['href'] as string; 112 | 113 | return new self.__dynamic.Function("arg", `return window.location.${func}(arg?${"reload" !== func && "toString" !== func ? "(self.__dynamic).url.encode(arg, new URL('" + property.href + "'))" : "arg"}:null)`) as Function; 114 | }, 115 | set: () => null 116 | }); 117 | }); 118 | 119 | if (ancestor.length) { 120 | self.__dynamic.define(self.__dynamic.location, 'ancestorOrigins', { 121 | get: () => cloneAncestor(ancestor) as DOMStringList, 122 | set: () => null 123 | }); 124 | } 125 | 126 | descriptors.forEach((object: Location & { prototype: Object } | Window & { prototype: Object } | Document & { prototype: Object }) => { 127 | self.__dynamic.define(object.prototype, '__dynamic$location', descriptor); 128 | }); 129 | 130 | if (!self.__dynamic.hashchange) self.__dynamic.hashchange = (self.addEventListener("hashchange", (event: HashChangeEvent) => { 131 | //property["hash"] = "#" + (event.newURL.split("#")[1] || ""); 132 | 133 | //self.history.pushState(null, null, self.__dynamic.location.href); 134 | }), true); 135 | 136 | return self.__dynamic.location; 137 | }; 138 | -------------------------------------------------------------------------------- /lib/global/client/methods/core/window.ts: -------------------------------------------------------------------------------- 1 | export default function window(self: any) { 2 | self.__dynamic.util.CreateDocumentProxy = function CreateDocumentProxy(document: any): ProxyHandler { 3 | return new Proxy(document, { 4 | get(obj, prop): any { 5 | const val = obj[prop]; 6 | if (prop=='location') if (document.defaultView) return document.defaultView.__dynamic$location; 7 | else return self.__dynamic$location; 8 | if (prop=='documentURI' && document.defaultView) return document.defaultView.__dynamic.location.toString(); 9 | if (prop=='baseURI' && document.defaultView) return document.defaultView.__dynamic.location.toString(); 10 | 11 | if (!val) return val; 12 | 13 | if (typeof val == 'function' && val.toString == self.Object.toString) return new Proxy(val, {apply(t, g, a) {if (document.defaultView && a[0] == document.defaultView.__dynamic$document) a[0] = document; else if (a[0] == self.__dynamic$document) a[0] = document; return val.apply(document, a)}}); 14 | 15 | return val; 16 | }, 17 | set(obj, prop, value): any { 18 | try { 19 | try { 20 | if (document.defaultView.__dynamic) document.defaultView.__dynamic.Reflect.set(obj, prop, value); 21 | else obj[prop] = value; 22 | } catch(e) { 23 | return value||obj[prop]||true; 24 | } 25 | 26 | return value||obj[prop]||true; 27 | } catch(e) { 28 | return value||obj[prop]||true; 29 | } 30 | } 31 | }); 32 | } 33 | 34 | self.__dynamic.util.CreateWindowProxy = function CreateWindowProxy(window: any): ProxyHandler { 35 | return new Proxy(window, { 36 | get(obj, prop): any { 37 | const val = self.__dynamic.Reflect.get(obj, prop); 38 | 39 | if (Object.getOwnPropertyDescriptor(obj, prop)) { 40 | var desc = Object.getOwnPropertyDescriptor(obj, prop); 41 | 42 | if (desc?.configurable === false && desc?.writable === false && desc?.hasOwnProperty('enumerable')) 43 | return desc?.value || desc?.get?.call(obj); 44 | } 45 | 46 | if (prop=='__dynamic$self') return window.window; 47 | 48 | //if (window.document) if (prop=='document') return window.__dynamic.util.CreateDocumentProxy(val); 49 | if (prop=='location') return window.__dynamic$location; 50 | if (prop=='parent') return window.parent.__dynamic$window || window.parent; 51 | if (prop=='top') 52 | if (!window.top.__dynamic) return window.parent.__dynamic$window; 53 | else return window.top.__dynamic$window; 54 | if (prop=='self') return window.__dynamic$window; 55 | if (prop=='globalThis') return window.__dynamic$window; 56 | 57 | if (!val) return val; 58 | 59 | if (typeof val == 'function' && val.toString == self.Object.toString) return new Proxy(val, {apply(t, g, a) {return Reflect.apply(t, window, a)}}); 60 | 61 | return val; 62 | }, 63 | set(obj, prop, value): any { 64 | try { 65 | var desc = Object.getOwnPropertyDescriptor(obj, prop); 66 | 67 | if (desc?.writable === false && desc?.enumerable === false) { 68 | return false; 69 | } 70 | 71 | if ((prop as any).constructor == self.Symbol) { 72 | return (Reflect.set(obj, prop, value), obj[prop]); 73 | } 74 | 75 | if (obj.hasOwnProperty('undefined') && obj[prop]+''==prop) return obj[prop] || value || true; 76 | if (prop=='location') return window.__dynamic$location = value; 77 | 78 | if (obj.hasOwnProperty(prop) && !obj.propertyIsEnumerable(prop) && !desc?.writable) return obj[prop]; 79 | 80 | try { 81 | if (window.__dynamic) window.__dynamic.Reflect.set(obj, prop, value); 82 | else obj[prop] = value; 83 | } catch(e) { 84 | return obj[prop]||true; 85 | } 86 | 87 | return obj[prop]||true; 88 | } catch(e) { 89 | return obj[prop]||true; 90 | } 91 | }, 92 | }) 93 | } 94 | 95 | self.__dynamic.define(self, '__dynamic$window', { 96 | value: self.__dynamic.util.CreateWindowProxy(self), 97 | configurable: false, 98 | enumerable: false, 99 | writable: false, 100 | }); 101 | 102 | if (self.document) self.__dynamic.define(self, '__dynamic$document', { 103 | value: self.__dynamic.util.CreateDocumentProxy(self.document), 104 | configurable: false, 105 | enumerable: false, 106 | writable: false, 107 | }); 108 | 109 | self.__dynamic$globalThis = self.__dynamic$window; 110 | self.__dynamic$self = self.__dynamic$window; 111 | } -------------------------------------------------------------------------------- /lib/global/rewrite/html/generateHead.ts: -------------------------------------------------------------------------------- 1 | import { Element } from "domhandler"; 2 | import html from "./html"; 3 | 4 | declare const self: Window | any; 5 | 6 | export default function GenerateHead(this: html, scriptURL: string, configURL: string, mutationURL: string, cookies: string | null, script: string = '', object: boolean = false, bare: string = '') { 7 | if (self.__dynamic$config) { 8 | var cache = self.__dynamic$config.mode == 'development'; 9 | } else var cache = false; 10 | 11 | if (object) { 12 | var head: Array = [ 13 | {nodeName: 'script', tagName: 'script', namespaceURI: 'http://www.w3.org/1999/xhtml', childNodes: [], attrs: [{name: 'src', value: scriptURL+(cache?'?'+Math.floor(Math.random()*(99999-10000)+10000):'')}]}, 14 | {nodeName: 'script', tagName: 'script', namespaceURI: 'http://www.w3.org/1999/xhtml', childNodes: [], attrs: [{name: 'src', value: configURL+(cache?'?'+Math.floor(Math.random()*(99999-10000)+10000):'')}]}, 15 | ]; 16 | 17 | if (this.ctx.config.assets.files.inject) head.unshift({nodeName: 'script', tagName: 'script', namespaceURI: 'http://www.w3.org/1999/xhtml', childNodes: [], attrs: [{name: 'src', value: this.ctx.config.assets.files.inject+(cache?'?'+Math.floor(Math.random()*(99999-10000)+10000):'')}]}); 18 | if (cookies) head.unshift({nodeName: 'script', tagName: 'script', namespaceURI: 'http://www.w3.org/1999/xhtml', childNodes: [], attrs: [{name: 'src', value: 'data:application/javascript;base64,'+btoa(`self.__dynamic$cookies = atob("${btoa(cookies)}");document.currentScript?.remove();`)}]}); 19 | if (script) head.unshift({nodeName: 'script', tagName: 'script', namespaceURI: 'http://www.w3.org/1999/xhtml', childNodes: [], attrs: [{name: 'src', value: 'data:application/javascript;base64,'+btoa(script+';document.currentScript?.remove();')}]}); 20 | if (bare) head.unshift({nodeName: 'script', tagName: 'script', namespaceURI: 'http://www.w3.org/1999/xhtml', childNodes: [], attrs: [{name: 'src', value: 'data:application/javascript;base64,'+btoa(bare+';document.currentScript?.remove();')}]}); 21 | 22 | return head; 23 | } else { 24 | var array: Array = [ 25 | ``, 26 | //``, 27 | ``, 28 | ] 29 | 30 | if (this.ctx.config.assets.files.inject) array.unshift(``); 31 | if (cookies) array.unshift(``); 32 | if (script) array.unshift(``); 33 | if (bare) array.unshift(``); 34 | 35 | return array; 36 | } 37 | 38 | /*if (self.__dynamic$config) { 39 | var cache = self.__dynamic$config.mode == 'development'; 40 | } else var cache = false; 41 | 42 | var head: Array = [ 43 | {nodeName: 'script', tagName: 'script', namespaceURI: 'http://www.w3.org/1999/xhtml', childNodes: [], attrs: [{name: 'src', value: scriptURL+(cache?'?'+Math.floor(Math.random()*(99999-10000)+10000):'')}]}, 44 | {nodeName: 'script', tagName: 'script', namespaceURI: 'http://www.w3.org/1999/xhtml', childNodes: [], attrs: [{name: 'src', value: configURL+(cache?'?'+Math.floor(Math.random()*(99999-10000)+10000):'')}]}, 45 | ]; 46 | 47 | if (this.ctx.config.assets.files.inject) head.unshift({nodeName: 'script', tagName: 'script', namespaceURI: 'http://www.w3.org/1999/xhtml', childNodes: [], attrs: [{name: 'src', value: this.ctx.config.assets.files.inject+(cache?'?'+Math.floor(Math.random()*(99999-10000)+10000):'')}]}); 48 | if (cookies) head.unshift({nodeName: 'script', tagName: 'script', namespaceURI: 'http://www.w3.org/1999/xhtml', childNodes: [], attrs: [{name: 'src', value: 'data:application/javascript;base64,'+btoa(`self.__dynamic$cookies = atob("${btoa(cookies)}");document.currentScript?.remove();`)}]}); 49 | if (script) head.unshift({nodeName: 'script', tagName: 'script', namespaceURI: 'http://www.w3.org/1999/xhtml', childNodes: [], attrs: [{name: 'src', value: 'data:application/javascript;base64,'+btoa(script+';document.currentScript?.remove();')}]}); 50 | 51 | return head;*/ 52 | 53 | 54 | /*var array: Array = [ 55 | new Element('script', {src: scriptURL+(cache?'?'+Math.floor(Math.random()*(99999-10000)+10000):'')}), 56 | new Element('script', {src: configURL+(cache?'?'+Math.floor(Math.random()*(99999-10000)+10000):'')}), 57 | ] 58 | 59 | if (cookies) array.unshift(new Element('script', {src: 'data:application/javascript;base64,'+btoa(`self.__dynamic$cookies = atob("${btoa(cookies)}");document.currentScript?.remove();`)}, [])); 60 | if (script) array.unshift(new Element('script', {src: 'data:application/javascript;base64,'+btoa(script+';document.currentScript?.remove();')}, [])); 61 | 62 | return array;*/ 63 | } -------------------------------------------------------------------------------- /lib/global/client/methods/window/niche.ts: -------------------------------------------------------------------------------- 1 | export default function niche(self: any) { 2 | // self explanatory 3 | 4 | self.__dynamic.define(self.document, 'origin', { 5 | value: self.__dynamic$location.origin as string, 6 | configurable: false, 7 | enumerable: false, 8 | }); 9 | 10 | self.__dynamic.define(self.document, 'domain', { 11 | value: self.__dynamic$location.hostname as string, 12 | configurable: false, 13 | enumerable: false, 14 | }); 15 | 16 | ['referrer', 'URL', 'documentURI'].forEach(prop => { 17 | self.__dynamic.define(self.document, prop, { 18 | value: self.__dynamic$location.toString() as string, 19 | configurable: false, 20 | enumerable: false, 21 | }); 22 | }); 23 | 24 | [self.document, self.HTMLElement.prototype].forEach(obj => { 25 | self.__dynamic.define(obj, 'baseURI', { 26 | get(): string { 27 | return (self.__dynamic.baseURL || self.__dynamic$location).href as string; 28 | } 29 | }); 30 | }); 31 | 32 | // storage.getEntries can leak page location 33 | 34 | ['getEntries', 'getEntriesByName', 'getEntriesByType'].forEach(prop => { 35 | self.performance[prop] = new Proxy(self.performance[prop], { 36 | apply(t, g, a: Array): Array { 37 | return (Reflect.apply(t, g, a) as any).filter((e:any)=>!e.name?.includes(self.location.origin+'/dynamic/dynamic.')).filter((e:any)=>!e.name.includes(self.location.origin+self.__dynamic.config.prefix+'caches/')).map((e:any)=>{ 38 | if (e.name) { 39 | var cloned: PerformanceEntry | any = self.__dynamic.util.clone(e); 40 | 41 | cloned.__defineGetter__('name', function(this: any) { 42 | return this._name; 43 | }); 44 | 45 | cloned.__defineSetter__('name', function(this: any, value: any) { 46 | this._name = value; 47 | }); 48 | 49 | cloned.name = self.__dynamic.url.decode(e.name); 50 | 51 | self.__dynamic.define(cloned, 'name', { 52 | get: undefined, 53 | set: undefined, 54 | }); 55 | 56 | self.__dynamic.define(cloned, 'name', { 57 | value: cloned._name as string, 58 | writable: false, 59 | }); 60 | 61 | delete cloned._name; 62 | 63 | for (var i in e) { 64 | if (i=='name') continue; 65 | 66 | if (typeof e[i] == 'function') var val = new Proxy(e[i], {apply(t, g, a) {if (t.name=='toJSON') {var b: any = {}; for (var c in cloned) b[c] = cloned[c]; return b;}; return Reflect.apply(t, e, a)}}); 67 | else var val = e[i]; 68 | 69 | Object.defineProperty(cloned, i, { 70 | value: val, 71 | writable: true, 72 | }); 73 | } 74 | 75 | e = cloned; 76 | } 77 | 78 | return e as PerformanceEntry; 79 | }); 80 | } 81 | }); 82 | }); 83 | 84 | // initEvent things 85 | 86 | if (self.MouseEvent) self.MouseEvent.prototype.initMouseEvent = self.__dynamic.wrap(self.MouseEvent.prototype.initMouseEvent, 87 | function(this: MouseEvent, target: Function, ...args: Array): void { 88 | if (args.length) args = args.map(e=>e==self.__dynamic$window?self:e); 89 | 90 | return Reflect.apply(target, this, args); 91 | } 92 | ); 93 | 94 | if (self.KeyboardEvent) self.KeyboardEvent.prototype.initKeyboardEvent = self.__dynamic.wrap(self.KeyboardEvent.prototype.initKeyboardEvent, 95 | function(this: KeyboardEvent, target: Function, ...args: Array): void { 96 | if (args.length) args = args.map(e=>e==self.__dynamic$window?self:e); 97 | 98 | return Reflect.apply(target, this, args); 99 | } 100 | ); 101 | 102 | if (self.StorageEvent) self.StorageEvent.prototype.initStorageEvent = self.__dynamic.wrap(self.StorageEvent.prototype.initStorageEvent, 103 | function(this: StorageEvent, target: Function, ...args: Array): void { 104 | if (args.length) args = args.map(e=>e==self.localStorage?self.__dynamic.storage.localStorage:e==self.sessionStorage?self.__dynamic.storage.sessionStorage:e); 105 | 106 | return Reflect.apply(target, this, args); 107 | } 108 | ); 109 | 110 | self.Object.defineProperty = self.__dynamic.wrap(self.Object.defineProperty, 111 | function(this: any, target: Function, ...args: Array): any { 112 | try { 113 | return Reflect.apply(target, this, args); 114 | } catch(e: any) { 115 | if (e.toString().includes('Cannot redefine property:')) { 116 | if (!args[0].__defined) args[0].__defined = {}; 117 | 118 | args[0].__defined[args[1]] = args[2]; 119 | } 120 | } 121 | } 122 | ); 123 | 124 | if (self.__dynamic.meta.origin == 'https://www.google.com') self.setInterval = new Proxy(self.setInterval, {apply(t: Function, g: Window, a: Array) { return a[1] == 500 ? null : Reflect.apply(t, g, a) }}); 125 | } -------------------------------------------------------------------------------- /lib/global/rewrite/js/type/MemberExpression.ts: -------------------------------------------------------------------------------- 1 | import Eval from '../object/Eval'; 2 | import PostMessage from '../object/PostMessage'; 3 | import { Node } from '../types'; 4 | 5 | export default function MemberExpression(node: Node, parent: Node = {} as any, config: any = {}) { 6 | /*if (config.destination !== 'worker') if (node.object.type!=='Identifier') { 7 | if (node.object.type == 'MemberExpression') return node.object = { 8 | type: 'CallExpression', 9 | callee: {type: 'Identifier', name: '__dynamic$get'}, 10 | arguments: [node.object] 11 | } 12 | } 13 | 14 | if (config.destination !== 'worker') if (node.object.type=='Identifier') { 15 | node.object = { 16 | type: 'CallExpression', 17 | callee: {type: 'Identifier', name: '__dynamic$get'}, 18 | arguments: [node.object] 19 | } 20 | }*/ 21 | 22 | node.object.name+=''; 23 | 24 | if (parent.type!=='AssignmentExpression'&&parent.left!==node) { 25 | if (node.property.value == 'postMessage' && (parent.type=='CallExpression'&&parent.callee==node)) return PostMessage(node, parent); 26 | if (node.object.value == 'postMessage' && (parent.type=='CallExpression'&&parent.callee==node)) return PostMessage(node, parent); 27 | 28 | if ((node.property.name=='postMessage'||node.object.name=='postMessage') && node.object.type!=='Super') { 29 | var original:string = node.object?.name 30 | node.type = 'CallExpression'; 31 | node.callee = {type: 'Identifier', name: '__dynamic$message'} as Node; 32 | node.arguments = [{type: 'Identifier', name: original} as Node, {type: 'Identifier', name: 'self', __dynamic: true} as Node] 33 | if (parent.type=='CallExpression') { 34 | parent.arguments = parent.arguments 35 | } 36 | 37 | return; 38 | } 39 | } 40 | 41 | if (node.property.name=='eval') node.property.name = '__dynamic$eval'; 42 | if (node.object.name=='eval') node.object.name = '__dynamic$eval'; 43 | 44 | if (config.destination!=='worker') { 45 | if (node.property.name=='window'&&node.object.name!='top'&&(node.object.name=='self'||node.object.name=='globalThis')) if (parent.type!=='NewExpression'&&(parent.type!=='CallExpression'||((parent.type=='CallExpression')&&node!==parent.callee))) node.property.name = '__dynamic$window'; 46 | if (node.object.name=='top') if (parent.type!=='NewExpression'&&(parent.type!=='CallExpression'||((parent.type=='CallExpression')&&node!==parent.callee))) node.object.name = 'top.__dynamic$window'; 47 | if (node.property.name=='top'&&(node.object.name=='self'||node.object.name=='globalThis')) if (parent.type!=='NewExpression'&&(parent.type!=='CallExpression'||((parent.type=='CallExpression')&&node!==parent.callee))) node.property.name = 'top.__dynamic$window'; 48 | if (parent.type!=='NewExpression'&&(parent.type!=='CallExpression'||((parent.type=='CallExpression')&&node!==parent.callee))) { 49 | if (node.object.name=='window') { 50 | node.object = { 51 | type: 'CallExpression', 52 | callee: {type: 'Identifier', name: 'dg$'} as Node, 53 | arguments: [node.object], 54 | __dynamic: true 55 | } as Node; 56 | }; 57 | if (node.object.name=='parent') { 58 | node.object = { 59 | type: 'CallExpression', 60 | callee: {type: 'Identifier', name: 'dg$'}, 61 | arguments: [node.object], 62 | __dynamic: true 63 | } as Node; 64 | }; 65 | if (node.property.name == '__dynamic') node.property.name = 'undefined'; 66 | if (node.object.name=='self') { 67 | node.object = { 68 | type: 'CallExpression', 69 | callee: {type: 'Identifier', name: 'dg$'}, 70 | arguments: [node.object], 71 | __dynamic: true 72 | } as Node; 73 | }; 74 | if (node.object.name=='document') { 75 | node.object = { 76 | type: 'CallExpression', 77 | callee: {type: 'Identifier', name: 'dg$'}, 78 | arguments: [node.object], 79 | __dynamic: true 80 | } as Node; 81 | }; 82 | if (node.object.name=='globalThis') { 83 | node.object = { 84 | type: 'CallExpression', 85 | callee: {type: 'Identifier', name: 'dg$'}, 86 | arguments: [node.object], 87 | __dynamic: true 88 | } as Node; 89 | }; 90 | } 91 | if (node.object.name=='location') { 92 | node.object = { 93 | type: 'CallExpression', 94 | callee: {type: 'Identifier', name: 'dg$'}, 95 | arguments: [node.object], 96 | __dynamic: true 97 | } as Node; 98 | }; 99 | if (node.property.name=='location' && parent.type !== "BinaryExpression" && parent.type !== "AssignmentExpression") { 100 | node.property.__dynamic = true; 101 | 102 | node.__dynamic = true; 103 | let original: any = Object.assign({}, node); 104 | 105 | node.type = "CallExpression"; 106 | node.callee = {type: 'Identifier', name: 'dg$', __dynamic: true} as Node; 107 | node.arguments = [original]; 108 | node.__dynamic = true; 109 | } 110 | } 111 | 112 | if (node.computed && config.destination !== 'worker') { 113 | node.property = { 114 | type: "CallExpression", 115 | callee: {type: 'Identifier', name: 'dp$'}, 116 | arguments: [node.property], 117 | __dynamic: true, 118 | } as Node; 119 | } 120 | 121 | //if (!['self', 'globalThis'].includes(node.object.name)) return false; 122 | 123 | //if (parent.type=='CallExpression'&&parent.callee==node) return; 124 | 125 | //if (node.object.name=='document') return node.object.name = `d$g_(${node.object.name})`; 126 | 127 | //return node.object.name = '__dynamic$'+node.object.name; 128 | } -------------------------------------------------------------------------------- /static/resources/style.css: -------------------------------------------------------------------------------- 1 | html { 2 | width: 100%; 3 | height: 100%; 4 | } 5 | body { 6 | background-color: #080808; 7 | color: #ffffff; 8 | font-family: 'Roboto', sans-serif; 9 | font-size: 16px; 10 | line-height: 1.5; 11 | margin: 0; 12 | padding: 0; 13 | width: 100%; 14 | height: 100%; 15 | display: flex; 16 | align-items: center; 17 | justify-content: center; 18 | align-content: center; 19 | flex-direction: column; 20 | position: absolute; 21 | z-index: 1; 22 | } 23 | h1 { 24 | font-size: 72px; 25 | font-weight: 700; 26 | margin: 0 0 -43px 0; 27 | font-style: italic; 28 | pointer-events: none; 29 | color: white; 30 | /* backdrop-filter: invert(1); */ 31 | } 32 | form { 33 | display: flex; 34 | flex-direction: row; 35 | align-items: flex-start; 36 | margin: 72px auto; 37 | max-width: 477px; 38 | width: 100%; 39 | justify-content: center; 40 | align-content: center; 41 | background: #000000ad; 42 | backdrop-filter: invert(1); 43 | height: 52px; 44 | border-radius: 9px; 45 | } 46 | input[name="url"] { 47 | background-color: #0f0f0fbf; 48 | border: 1px solid #ffffff24; 49 | color: #ffffff; 50 | font-size: 16px; 51 | border-radius: 9px; 52 | margin: 0 0 16px 0; 53 | font-family: 'Roboto', sans-serif; 54 | padding: 16px; 55 | text-align: center; 56 | width: 100%; 57 | outline: transparent; 58 | } 59 | input[name="url"]::placeholder { 60 | color: #bfbfbf; 61 | } 62 | input[type="submit"] { 63 | background-color: #daff46; 64 | color: black; 65 | border: none; 66 | font-size: 16px; 67 | font-weight: 700; 68 | padding: 16px; 69 | text-align: center; 70 | text-transform: uppercase; 71 | transition: background-color 0.2s ease-in-out; 72 | width: 100%; 73 | } 74 | input[type="submit"]:hover { 75 | background-color: #00c853; 76 | cursor: pointer; 77 | } 78 | 79 | 80 | svg { 81 | position: absolute; 82 | top: 0; 83 | left: 0; 84 | z-index: -1; 85 | filter: blur(97px); 86 | } 87 | 88 | 89 | .footer { 90 | display: flex; 91 | align-items: flex-end; 92 | justify-content: center; 93 | flex-direction: row; 94 | align-content: center; 95 | flex-wrap: nowrap; 96 | position: absolute; 97 | bottom: 0; 98 | width: 100%; 99 | 100 | } 101 | 102 | .copyright { 103 | position: absolute; 104 | left: 17px; 105 | } 106 | 107 | canvas { 108 | width: 100%; 109 | height: 100%; 110 | position: absolute; 111 | z-index: -2; 112 | } 113 | @-webkit-keyframes fadeIn { 114 | 0% { 115 | opacity: 0; 116 | } 117 | 100% { 118 | opacity: 1; 119 | } 120 | } 121 | @keyframes fadeIn { 122 | 0% { 123 | opacity: 0; 124 | } 125 | 100% { 126 | opacity: 1; 127 | } 128 | } 129 | @-webkit-keyframes fadeOut { 130 | 0% { 131 | opacity: 1; 132 | } 133 | 100% { 134 | opacity: 0; 135 | } 136 | } 137 | @keyframes fadeOut { 138 | 0% { 139 | opacity: 1; 140 | } 141 | 100% { 142 | opacity: 0; 143 | } 144 | } 145 | .modal-body { 146 | overflow: hidden; 147 | position: relative; 148 | } 149 | .modal-body:before { 150 | position: fixed; 151 | display: block; 152 | content: ""; 153 | top: 0px; 154 | bottom: 0px; 155 | right: 0px; 156 | left: 0px; 157 | background-color: rgba(0, 0, 0, 0.75); 158 | z-index: 10; 159 | } 160 | .modal-body:before { 161 | -webkit-animation: fadeIn 320ms ease; 162 | animation: fadeIn 320ms ease; 163 | transition: opacity ease 320ms; 164 | } 165 | .modal-body.modal-fadeOut:before { 166 | opacity: 0; 167 | } 168 | 169 | .modal { 170 | transition: all ease 0.01s; 171 | display: block; 172 | opacity: 0; 173 | height: 0; 174 | position: fixed; 175 | content: ""; 176 | top: 0; 177 | left: 0; 178 | right: 0; 179 | z-index: 999; 180 | text-align: center; 181 | overflow: hidden; 182 | overflow-y: auto; 183 | -webkit-overflow-scrolling: touch; 184 | } 185 | .modal.modal-visible { 186 | opacity: 1; 187 | height: auto; 188 | bottom: 0; 189 | } 190 | 191 | .modal-inner { 192 | transition: all ease 320ms; 193 | transform: translateY(-50px); 194 | position: relative; 195 | display: inline-block; 196 | background-color: #1a1a1a; 197 | width: 90%; 198 | max-width: 625px; 199 | opacity: 0; 200 | margin: 40px 0; 201 | border-radius: 4px; 202 | box-shadow: 0 30px 18px -20px #020202; 203 | } 204 | .modal-inner.modal-reveal { 205 | transform: translateY(0); 206 | opacity: 1; 207 | } 208 | 209 | .js-close-modal { 210 | transition: color 320ms ease; 211 | color: #9e9e9e; 212 | opacity: 0.75; 213 | position: absolute; 214 | z-index: 2; 215 | right: 0px; 216 | top: 0px; 217 | width: 30px; 218 | height: 30px; 219 | line-height: 30px; 220 | font-size: 20px; 221 | cursor: pointer; 222 | text-align: center; 223 | } 224 | 225 | .js-close-modal:hover { 226 | color: #000; 227 | } 228 | 229 | #settings-version { 230 | position: absolute; 231 | left: 0; 232 | bottom: 0; 233 | margin-left: 11px; 234 | margin-bottom: 5px; 235 | color: #b4b4b482; 236 | } 237 | .settings-connected { 238 | position: absolute; 239 | right: 0; 240 | bottom: 0; 241 | margin-right: 13px; 242 | margin-bottom: 5px; 243 | color: #b4b4b482; 244 | display: flex; 245 | } 246 | 247 | .connectedindicator { 248 | width: 20px; 249 | height: 20px; 250 | background: #30ff30; 251 | border-radius: 53px; 252 | margin-right: 13px; 253 | margin-top: 2px; 254 | } 255 | 256 | button { 257 | position: absolute; 258 | right: 4px; 259 | top: 4px; 260 | background: transparent; 261 | border: transparent; 262 | color: #ffffff30; 263 | } -------------------------------------------------------------------------------- /lib/global/client/methods/init.ts: -------------------------------------------------------------------------------- 1 | import Client from "../../../client/client"; 2 | 3 | export default function init(self: Window | any, __dynamic: any) { 4 | if (!__dynamic) __dynamic = self.__dynamic; 5 | 6 | __dynamic.define = new self.Proxy(self.Object.defineProperty, { 7 | apply(t: any, g: any, a: any) { 8 | try { 9 | return Reflect.apply(t, g, a); 10 | } catch(e) { 11 | return a[2]; 12 | } 13 | } 14 | }), __dynamic.defines = new self.Proxy(self.Object.defineProperties, { 15 | apply(t: any, g: any, a: any) { 16 | try { 17 | return Reflect.apply(t, g, a); 18 | } catch(e) { 19 | return a[1]; 20 | } 21 | } 22 | }); 23 | 24 | if (self.parent) __dynamic.parent = self.parent; 25 | if (self.top) __dynamic.top = self.top; 26 | 27 | if (self.document) __dynamic.elements = { 28 | attributes: ['src', 'href', 'srcset', 'action', 'data', 'integrity', 'nonce', 'imagesrcset'], 29 | iframeSrc: Object.getOwnPropertyDescriptor(self.HTMLIFrameElement.prototype, 'src'), 30 | contentWindow: Object.getOwnPropertyDescriptor(self.HTMLIFrameElement.prototype, 'contentWindow'), 31 | innerHTML: Object.getOwnPropertyDescriptor(self.Element.prototype, 'innerHTML'), 32 | outerHTML: Object.getOwnPropertyDescriptor(self.Element.prototype, 'outerHTML'), 33 | attrValue: Object.getOwnPropertyDescriptor(self.Attr.prototype, 'value'), 34 | 35 | setAttribute: self.Element.prototype.setAttribute, 36 | getAttribute: self.Element.prototype.getAttribute, 37 | removeAttribute: self.Element.prototype.removeAttribute, 38 | hasAttribute: self.Element.prototype.hasAttribute, 39 | cloneNode: self.Node.prototype.cloneNode, 40 | addEventListener: self.Node.prototype.addEventListener, 41 | 42 | config: [ 43 | { 44 | "elements": [self.HTMLScriptElement, self.HTMLIFrameElement, self.HTMLEmbedElement, self.HTMLInputElement, self.HTMLTrackElement, self.HTMLMediaElement,self.HTMLSourceElement, self.Image, self.HTMLImageElement], 45 | "tags": ['src'], 46 | "action": "url" 47 | }, 48 | { 49 | "elements": [self.HTMLSourceElement, self.HTMLImageElement], 50 | "tags": ['srcset'], 51 | "action": "srcset" 52 | }, 53 | { 54 | "elements": [self.HTMLAnchorElement, self.HTMLLinkElement, self.HTMLAreaElement, self.SVGImageElement, self.HTMLBaseElement], 55 | "tags": ['href'], 56 | "action": "url" 57 | }, 58 | { 59 | "elements": [self.HTMLIFrameElement], 60 | "tags": ['contentWindow', 'contentDocument'], 61 | "action": "window" 62 | }, 63 | { 64 | "elements": [self.HTMLFormElement], 65 | "tags": ['action'], 66 | "action": "url" 67 | }, 68 | { 69 | "elements": [self.HTMLObjectElement], 70 | "tags": ['data'], 71 | "action": "url", 72 | }, 73 | { 74 | "elements": [self.HTMLScriptElement, self.HTMLLinkElement], 75 | "tags": ['integrity'], 76 | "action": "rewrite", 77 | "new": "nointegrity", 78 | }, 79 | { 80 | "elements": [self.HTMLScriptElement, self.HTMLLinkElement], 81 | "tags": ['nonce'], 82 | "action": "rewrite", 83 | "new": "nononce", 84 | }, 85 | { 86 | "elements": [self.HTMLIFrameElement], 87 | "tags": ['srcdoc'], 88 | "action": "html", 89 | }, 90 | { 91 | "elements": [self.HTMLElement], 92 | "tags": ['style'], 93 | "action": "css" 94 | }, 95 | { 96 | "elements": [self.HTMLLinkElement], 97 | "tags": ['imageSrcset'], 98 | "action": "srcset" 99 | }, 100 | ], 101 | 102 | createGetter: (prop: any) => {return {get(this: any): any {return (new URL(this.href||self.__dynamic$location.href) as any)[prop];},set(val: any) {return;}}}, 103 | client: Client 104 | }, self.__dynamic.baseURL = self.document ? new URL(self.__dynamic.url.decode(self.document.baseURI)) : null; 105 | 106 | if (self.document) __dynamic.cookie = { 107 | str: self.__dynamic$cookie||'', 108 | desc: Object.getOwnPropertyDescriptor(self.Document.prototype, 'cookie') 109 | }; 110 | 111 | if (self.XMLHttpRequest) __dynamic.http = { 112 | XMLResponseURL: Object.getOwnPropertyDescriptor(self.XMLHttpRequest.prototype, 'responseURL'), 113 | ResponseURL: Object.getOwnPropertyDescriptor(self.Response.prototype, 'url'), 114 | RequestURL: Object.getOwnPropertyDescriptor(self.Request.prototype, 'url'), 115 | XMLHttpRequest: self.XMLHttpRequest, 116 | } 117 | 118 | if (self.Storage) (__dynamic.storage = { 119 | localStorage: self.localStorage, 120 | sessionStorage: self.sessionStorage, 121 | keys: { 122 | localStorage: Object.keys(self.localStorage), 123 | sessionStorage: Object.keys(self.sessionStorage) 124 | }, 125 | methods: ['getItem', 'setItem', 'removeItem', 'clear', 'length', 'keys', 'values', 'entries', 'forEach', 'hasOwnProperty', 'toString', 'toLocaleString', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor', 'key'], 126 | }, __dynamic.storage.cloned = { 127 | localStorage: __dynamic.util.clone(__dynamic.storage.localStorage), 128 | sessionStorage: __dynamic.util.clone(__dynamic.storage.sessionStorage) 129 | }); 130 | 131 | if (self.RTCPeerConnection) __dynamic.webrtc = { 132 | endpoints: [ 133 | 'stun:stun.webice.org' 134 | ] 135 | } 136 | 137 | if (self.trustedTypes) __dynamic.trustedTypes = { 138 | policy: self.trustedTypes.createPolicy('dynamic', { 139 | createHTML: (s: any) => s, 140 | createScript: (s: any) => s, 141 | createScriptURL: (s: any) => s, 142 | createURL: (s: any) => s, 143 | }), 144 | createScript: self.TrustedTypePolicy.prototype.createScript, 145 | } 146 | 147 | if (self.__dynamic$config.tab) { 148 | if (self.document && self.__dynamic$config.tab['title']) { 149 | document.title = self.__dynamic$config.tab.title; 150 | __dynamic.define(self.document, 'title', { 151 | get() { 152 | return self.__dynamic$config.tab.title; 153 | }, 154 | set(val: any) { 155 | return val; 156 | } 157 | }); 158 | } 159 | 160 | if (self.__dynamic$config.tab['icon']) { 161 | self.__dynamic$icon = self.__dynamic$config.tab.icon; 162 | } 163 | 164 | if (self.Navigator && self.__dynamic$config.tab['ua']) { 165 | __dynamic.define(self.navigator, 'userAgent', { 166 | get() { 167 | return self.__dynamic$config.tab.ua; 168 | }, 169 | set() {} 170 | }); 171 | } 172 | } 173 | } -------------------------------------------------------------------------------- /docs/examples/uv-dynamic-multi/uv/uv.sw.js: -------------------------------------------------------------------------------- 1 | (()=>{"use strict";const e=self.Ultraviolet,t=["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"],r=["GET","HEAD"];class i extends e.EventEmitter{constructor(t=__uv$config){super(),t.bare||(t.bare="/bare/"),t.prefix||(t.prefix="/service/"),this.config=t;const r=(Array.isArray(t.bare)?t.bare:[t.bare]).map((e=>new URL(e,location).toString()));this.address=r[~~(Math.random()*r.length)],this.bareClient=new e.BareClient(this.address)}async fetch({request:i}){let a;try{if(!i.url.startsWith(location.origin+this.config.prefix))return await fetch(i);const c=new e(this.config,this.address);"function"==typeof this.config.construct&&this.config.construct(c,"service");const l=await c.cookie.db();c.meta.origin=location.origin,c.meta.base=c.meta.url=new URL(c.sourceUrl(i.url));const d=new o(i,this,c,r.includes(i.method.toUpperCase())?null:await i.blob());if("blob:"===c.meta.url.protocol&&(d.blob=!0,d.base=d.url=new URL(d.url.pathname)),i.referrer&&i.referrer.startsWith(location.origin)){const e=new URL(c.sourceUrl(i.referrer));(d.headers.origin||c.meta.url.origin!==e.origin&&"cors"===i.mode)&&(d.headers.origin=e.origin),d.headers.referer=e.href}const h=await c.cookie.getCookies(l)||[],u=c.cookie.serialize(h,c.meta,!1);d.headers["user-agent"]=navigator.userAgent,u&&(d.headers.cookie=u);const p=new n(d,null,null);if(this.emit("request",p),p.intercepted)return p.returnValue;a=d.blob?"blob:"+location.origin+d.url.pathname:d.url;const m=await this.bareClient.fetch(a,{headers:d.headers,method:d.method,body:d.body,credentials:d.credentials,mode:location.origin!==d.address.origin?"cors":d.mode,cache:d.cache,redirect:d.redirect}),f=new s(d,m),b=new n(f,null,null);if(this.emit("beforemod",b),b.intercepted)return b.returnValue;for(const e of t)f.headers[e]&&delete f.headers[e];if(f.headers.location&&(f.headers.location=c.rewriteUrl(f.headers.location)),"document"===i.destination){const e=f.headers["content-disposition"];if(!/\s*?((inline|attachment);\s*?)filename=/i.test(e)){const t=/^\s*?attachment/i.test(e)?"attachment":"inline",[r]=new URL(m.finalURL).pathname.split("/").slice(-1);f.headers["content-disposition"]=`${t}; filename=${JSON.stringify(r)}`}}if(f.headers["set-cookie"]&&(Promise.resolve(c.cookie.setCookies(f.headers["set-cookie"],l,c.meta)).then((()=>{self.clients.matchAll().then((function(e){e.forEach((function(e){e.postMessage({msg:"updateCookies",url:c.meta.url.href})}))}))})),delete f.headers["set-cookie"]),f.body)switch(i.destination){case"script":case"worker":{const e=[c.bundleScript,c.clientScript,c.configScript,c.handlerScript].map((e=>JSON.stringify(e))).join(",");f.body=`if (!self.__uv && self.importScripts) { ${c.createJsInject(this.address,this.bareClient.manfiest,c.cookie.serialize(h,c.meta,!0),i.referrer)} importScripts(${e}); }\n`,f.body+=c.js.rewrite(await m.text())}break;case"style":f.body=c.rewriteCSS(await m.text());break;case"iframe":case"document":(function(t,r=""){return"text/html"===(e.mime.contentType(r||t.pathname)||"text/html").split(";")[0]})(c.meta.url,f.headers["content-type"]||"")&&(f.body=c.rewriteHtml(await m.text(),{document:!0,injectHead:c.createHtmlInject(c.handlerScript,c.bundleScript,c.clientScript,c.configScript,this.address,this.bareClient.manfiest,c.cookie.serialize(h,c.meta,!0),i.referrer)}))}return"text/event-stream"===d.headers.accept&&(f.headers["content-type"]="text/event-stream"),crossOriginIsolated&&(f.headers["Cross-Origin-Embedder-Policy"]="require-corp"),this.emit("response",b),b.intercepted?b.returnValue:new Response(f.body,{headers:f.headers,status:f.status,statusText:f.statusText})}catch(e){return["document","iframe"].includes(i.destination)?(console.error(e),function(e,t,r){let i,s,o,n,a="";!function(e){return e instanceof Error&&"object"==typeof e.body}(e)?(i=500,s="Error processing your request",n="Internal Server Error",o=e instanceof Error?e.name:"UNKNOWN"):(i=e.status,s="Error communicating with the Bare server",n=e.body.message,o=e.body.code,a=e.body.id);return new Response(function(e,t,r,i,s,o,n){if("The specified host could not be resolved."===i)return function(e,t){const r=new URL(e),i=`remoteHostname.textContent = ${JSON.stringify(r.hostname)};bareServer.href = ${JSON.stringify(t)};uvHostname.textContent = ${JSON.stringify(location.hostname)};reload.addEventListener("click", () => location.reload());uvVersion.textContent = ${JSON.stringify("2.0.0")};`;return`Error

This site can’t be reached


’s server IP address could not be found.

Try:

  • Verifying you entered the correct address
  • Clearing the site data
  • Contacting 's administrator
  • Verifying the Bare server isn't censored

Ultraviolet v