Files
2026-11-09 14:55:36 +03:30

47 خطوط
2.6 KiB
JavaScript

import assert from 'node:assert/strict';
import {test} from 'node:test';
import {iframeCode,viewerURL,mountShare} from './share.js';
const base='https://render.sadentel.net';
for(const path of ['/view/','/compare/','/view/pcb/','/compare/pcb/']){
test(`share ${path} preserves the private capability`,()=>{
const url=viewerURL(path+'a'.repeat(48),'read-token',base);
const code=iframeCode(url,base);
assert.ok(code.includes(`src="${base}${path}${'a'.repeat(48)}#token=read-token"`));
assert.ok(code.includes('width="100%"')&&code.includes('height="800"'));
assert.equal(new URL(url).search,'');
assert.ok(!code.includes('X-API-Key'));
});
}
test('unlisted iframe does not gain a token',()=>{
assert.ok(!iframeCode('/view/'+'a'.repeat(48),base).includes('#token='));
});
test('iframe escapes attributes and rejects executable URL schemes',()=>{
const code=iframeCode(base+'/view/test?x=1&y=2#token=" onload="bad',base);
assert.ok(!code.includes(' onload="bad'));
assert.ok(code.includes('%22') && code.includes('&'));
for(const url of ['javascript:alert(1)','data:text/html,hello','https://user:secret@example.test/view/id'])assert.throws(()=>iframeCode(url,base));
});
test('Share reveals the iframe and copies its read token without sending a request',async t=>{
class Element {
constructor(){this.children=[];this.events={};this.attributes={};}
append(...items){this.children.push(...items);}
setAttribute(key,value){this.attributes[key]=value;}
addEventListener(name,callback){this.events[name]=callback;}
focus(){} select(){}
}
const saved=new Map(['document','location','navigator'].map(key=>[key,Object.getOwnPropertyDescriptor(globalThis,key)]));
let copied='';
Object.defineProperty(globalThis,'document',{configurable:true,value:{createElement:()=>new Element()}});
Object.defineProperty(globalThis,'location',{configurable:true,value:{origin:base}});
Object.defineProperty(globalThis,'navigator',{configurable:true,value:{clipboard:{writeText:async code=>{copied=code;}}}});
t.after(()=>{for(const [key,descriptor]of saved)if(descriptor)Object.defineProperty(globalThis,key,descriptor);else delete globalThis[key];});
const host=new Element();mountShare(host,base+'/view/'+'a'.repeat(48)+'#token=private-read');
const [toggle,panel]=host.children[0].children;
assert.equal(panel.hidden,true);toggle.events.click();assert.equal(panel.hidden,false);
const textarea=panel.children[1],copy=panel.children[3];
assert.ok(textarea.value.includes('#token=private-read'));assert.equal(textarea.readOnly,true);
await copy.events.click();assert.equal(copied,textarea.value);
toggle.events.click();assert.equal(panel.hidden,true);
});