Path: blob/main/corrosion/lib/browser/document.js
1223 views
function createDocumentRewriter(ctx) {1return function rewriteDocument() {2if (ctx.serviceWorker) return;3const {4HTMLMediaElement,5HTMLScriptElement,6HTMLAudioElement,7HTMLVideoElement,8HTMLInputElement,9HTMLEmbedElement,10HTMLTrackElement,11HTMLAnchorElement,12HTMLIFrameElement,13HTMLAreaElement,14HTMLLinkElement,15HTMLBaseElement,16HTMLFormElement,17HTMLImageElement,18HTMLSourceElement,19} = ctx.window;20const cookie = Object.getOwnPropertyDescriptor(ctx.window.Document.prototype, 'cookie');21const domain = Object.getOwnPropertyDescriptor(ctx.window.Document.prototype, 'domain');22const title = Object.getOwnPropertyDescriptor(ctx.window.Document.prototype, 'title');23const baseURI = Object.getOwnPropertyDescriptor(ctx.window.Node.prototype, 'baseURI');24const cookieEnabled = Object.getOwnPropertyDescriptor(ctx.window.Navigator.prototype, 'cookieEnabled');25let spoofTitle = '';26let spoofDomain = ctx.location.hostname;2728if (ctx.window.Document.prototype.write) {29ctx.window.Document.prototype.write = new Proxy(ctx.window.Document.prototype.write, {30apply: (target, that , args) => {31if (args.length) args = [ ctx.html.process(args.join(''), ctx.meta) ];32return Reflect.apply(target, that, args);33},34});35};36if (ctx.window.Document.prototype.hasOwnProperty('cookie')) {37Object.defineProperty(ctx.window.Document.prototype, 'cookie', {38get: new Proxy(cookie.get, {39apply: (target, that, args) => {40const cookies = Reflect.apply(target, that, args);41return ctx.config.cookie ? ctx.cookies.decode(cookies, ctx.meta) : '';42},43}),44set: new Proxy(cookie.set, {45apply: (target, that, [ val ]) => {46return Reflect.apply(target, that, [ ctx.config.cookie ? ctx.cookies.encode(val, ctx.meta) : '' ]);47},48}),49});50};51if (ctx.window.Document.prototype.writeln) {52ctx.window.Document.prototype.writeln = new Proxy(ctx.window.Document.prototype.writeln, {53apply: (target, that , args) => {54if (args.length) args = [ ctx.html.process(args.join(''), ctx.meta) ];55return Reflect.apply(target, that, args);56},57});58};59if (ctx.window.Element.prototype.setAttribute) {60ctx.window.Element.prototype.setAttribute = new Proxy(ctx.window.Element.prototype.setAttribute, {61apply: (target, that, args) => {62if (args[0] && args[1]) {63const handler = ctx.html.attributeRoute({64name: args[0],65value: args[1],66node: that,67});68switch(handler) {69case 'url':70Reflect.apply(target, that, [`corrosion-${args[0]}`, args[1]]);71//if (that.tagName == 'SCRIPT' && args[0] == 'src') flags.push('js');72args[1] = ctx.url.wrap(args[1], ctx.meta);73break;74case 'srcset':75Reflect.apply(target, that, [`corrosion-${args[0]}`, args[1]]);76args[1] = ctx.html.srcset(args[1], ctx.meta);77break;78case 'css':79Reflect.apply(target, that, [`corrosion-${args[0]}`, args[1]]);80args[1] = ctx.css.process(args[1], { ...ctx.meta, context: 'declarationList' });81break;82case 'html':83Reflect.apply(target, that, [`corrosion-${args[0]}`, args[1]]);84args[1] = ctx.html.process(args[1], ctx.meta);85break;86case 'delete':87return Reflect.apply(target, that, [`corrosion-${args[0]}`, args[1]]);88};89};90return Reflect.apply(target, that, args);91},92});93};94if (ctx.window.Element.prototype.getAttribute) {95ctx.window.Element.prototype.getAttribute = new Proxy(ctx.window.Element.prototype.getAttribute, {96apply: (target, that, args) => {97if (args[0] && that.hasAttribute(`corrosion-${args[0]}`)) args[0] = `corrosion-${args[0]}`;98return Reflect.apply(target, that, args);99},100});101};102ctx.window.CSSStyleDeclaration.prototype.setProperty = new Proxy(ctx.window.CSSStyleDeclaration.prototype.setProperty, {103apply: (target, that, args) => {104if (args[1]) args[1] = ctx.css.process(args[1], { context: 'value', ...ctx.meta, });105return Reflect.apply(target, that, args);106},107});108if (ctx.window.Audio) {109ctx.window.Audio = new Proxy(ctx.window.Audio, {110construct: (target, args) => {111if (args[0]) args[0] = ctx.url.wrap(args[0], ctx.meta);112return Reflect.construct(target, args);113},114});115};116[117'innerHTML',118'outerHTML',119].forEach(html => {120const descriptor = Object.getOwnPropertyDescriptor(ctx.window.Element.prototype, html);121Object.defineProperty(ctx.window.Element.prototype, html, {122get: new Proxy(descriptor.get, {123apply: (target, that, args) => {124const body = Reflect.apply(target, that, args);125if (!body || html == 'innerHTML' && that.tagName == 'SCRIPT') return body;126return ctx.html.source(body, ctx.meta);127},128}),129set: new Proxy(descriptor.set, {130apply(target, that, [ val ]) {131return Reflect.apply(target, that, [ val ? ctx.html.process(val.toString(), ctx.meta) : val, ]);132},133}),134});135});136[137['background', 'background'],138['backgroundImage', 'background-image'],139['listStyleImage', 'list-style-image'],140].forEach(([key, cssProperty]) => {141Object.defineProperty(ctx.window.CSS2Properties ? ctx.window.CSS2Properties.prototype : ctx.window.CSSStyleDeclaration.prototype, key, {142get() {143return this.getPropertyValue(cssProperty);144},145set(val) {146return this.setProperty(cssProperty, val);147},148});149});150Object.defineProperty(ctx.window.Document.prototype, 'domain', {151get: new Proxy(domain.get, {152apply: () => spoofDomain,153}),154set: new Proxy(domain.set, {155apply: (target, that, [ val ]) => {156if (!val.toString().endsWith(ctx.location.hostname.split('.').slice(-2).join('.'))) return Reflect.apply(target, that, ['']);157return spoofDomain = val;158},159}),160});161if (ctx.config.title) Object.defineProperty(ctx.window.Document.prototype, 'title', {162get: new Proxy(title.get, {163apply: () => spoofTitle,164}),165set: new Proxy(title.set, {166apply: (target, that, [ val ]) => spoofTitle = val,167}),168});169Object.defineProperty(ctx.window.Navigator.prototype, 'cookieEnabled', {170get: new Proxy(cookieEnabled.get, {171apply: () => ctx.config.cookie,172}),173});174Object.defineProperty(ctx.window.Node.prototype, 'baseURI', {175get: new Proxy(baseURI.get, {176apply: (target, that, args) => {177const val = Reflect.apply(target, that, args);178return val.startsWith(ctx.meta.origin) ? ctx.url.unwrap(val, ctx.meta) : val;179},180}),181});182[183{184elements: [ HTMLScriptElement, HTMLMediaElement, HTMLImageElement, HTMLAudioElement, HTMLVideoElement, HTMLInputElement, HTMLEmbedElement, HTMLIFrameElement, HTMLTrackElement, HTMLSourceElement],185properties: ['src'],186handler: 'url',187},188{189elements: [ HTMLFormElement ],190properties: ['action'],191handler: 'url',192},193{194elements: [ HTMLAnchorElement, HTMLAreaElement, HTMLLinkElement, HTMLBaseElement ],195properties: ['href'],196handler: 'url',197},198{199elements: [ HTMLImageElement, HTMLSourceElement ],200properties: ['srcset'],201handler: 'srcset',202},203{204elements: [ HTMLScriptElement ],205properties: ['integrity'],206handler: 'delete',207},208{209elements: [ HTMLIFrameElement ],210properties: ['contentWindow'],211handler: 'window',212},213].forEach(entry => {214entry.elements.forEach(element => {215if (!element) return;216entry.properties.forEach(property => {217if (!element.prototype.hasOwnProperty(property)) return;218const descriptor = Object.getOwnPropertyDescriptor(element.prototype, property);219Object.defineProperty(element.prototype, property, {220get: descriptor.get ? new Proxy(descriptor.get, {221apply: (target, that, args) => {222let val = Reflect.apply(target, that, args);223let flags = [];224switch(entry.handler) {225case 'url':226//if (that.tagName == 'SCRIPT' && property == 'src') flags.push('js');227val = ctx.url.unwrap(val, ctx.meta);228break;229case 'srcset':230val = ctx.html.unsrcset(val, ctx.meta);231break;232case 'delete':233val = that.getAttribute(`corrosion-${property}`);234break;235case 'window':236try {237if (!val.$corrosion) {238val.$corrosion = new ctx.constructor({ ...ctx.config, window: val, });239val.$corrosion.init();240val.$corrosion.meta = ctx.meta;241};242} catch(e) {};243};244return val;245},246}) : undefined,247set: descriptor.set ? new Proxy(descriptor.set, {248apply(target, that, [ val ]) {249let newVal = val;250switch(entry.handler) {251case 'url':252newVal = ctx.url.wrap(newVal, ctx.meta);253break;254case 'srcset':255newVal = ctx.html.srcset(newVal, ctx.meta);256break;257case 'delete':258that.setAttribute(property, newVal);259return newVal;260};261return Reflect.apply(target, that, [ newVal ]);262},263}) : undefined,264});265});266});267});268};269};270module.exports = createDocumentRewriter;271272