Files
谢宇宁andClaude Opus 5.5 f65d10e998 Initial commit
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 23:07:59 +07:00

59 lines
4.2 KiB
JavaScript

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {readFile} from 'node:fs/promises';
import ts from 'typescript';
async function moduleUrl(path,transform=code=>code){
const source=await readFile(new URL(path,import.meta.url),'utf8');
const {outputText}=ts.transpileModule(source,{compilerOptions:{target:ts.ScriptTarget.ES2022,module:ts.ModuleKind.ESNext}});
return 'data:text/javascript;base64,'+Buffer.from(transform(outputText)).toString('base64');
}
const protocolUrl=await moduleUrl('../src/lib/api/protocol.ts');
const appDownloadUrl=await moduleUrl('../src/lib/app-download.ts',code=>code.replace(/from ['"]\.\/api\/protocol['"]/,`from '${protocolUrl}'`));
const {downloadUrl}=await import(appDownloadUrl);
const clientUrl=await moduleUrl('../src/lib/client/download.ts',code=>code.replace(/from ['"]\.\.\/app-download['"]/,`from '${appDownloadUrl}'`));
const {configureDownloadLinks,shouldUseDownloadDialog}=await import(clientUrl);
const click={defaultPrevented:false,button:0,metaKey:false,ctrlKey:false,shiftKey:false,altKey:false};
test('download configuration selects the first valid HTTP URL and rejects empty or unsafe values',()=>{
assert.equal(downloadUrl({}),'');
assert.equal(downloadUrl({config:{appAddr:''}}),'');
assert.equal(downloadUrl({config:{officialAppAddr:'javascript:alert(1)',appAddr:'https://example.com/app.apk'}}),'https://example.com/app.apk');
assert.equal(downloadUrl({config:{appAddr:' '},newAddressInfo:{appAddr:'https://example.com/fallback.apk'}}),'https://example.com/fallback.apk');
assert.equal(downloadUrl({config:{officialAppAddr:'https://example.com/official',appAddr:'https://example.com/other'}}),'https://example.com/official');
for(const value of ['javascript:alert(1)','data:text/plain,app','ftp://example.com/app','https://user:password@example.com/app']){
assert.equal(downloadUrl({config:{appAddr:value}}),'');
}
});
test('all download entries stay hidden until configured and are hidden again if configuration is removed',()=>{
const entries=Array.from({length:4},()=>({hidden:true}));
const links=Array.from({length:4},()=>({href:undefined,removeAttribute(name){if(name==='href')this.href=undefined;}}));
const root={querySelectorAll:selector=>selector==='[data-app-download-entry]'?entries:links};
configureDownloadLinks({},root);assert.ok(entries.every(entry=>entry.hidden));assert.ok(links.every(link=>link.href===undefined));
configureDownloadLinks({config:{appAddr:'https://example.com/app.apk'}},root);
assert.ok(entries.every(entry=>!entry.hidden));assert.ok(links.every(link=>link.href==='https://example.com/app.apk'));
const dynamicEntry={hidden:true},dynamicLink={href:undefined,removeAttribute(name){if(name==='href')this.href=undefined;}};
entries.push(dynamicEntry);links.push(dynamicLink);
configureDownloadLinks({config:{appAddr:'https://example.com/new.apk'}},root);
assert.equal(dynamicEntry.hidden,false);assert.equal(dynamicLink.href,'https://example.com/new.apk');
configureDownloadLinks({},root);assert.ok(entries.every(entry=>entry.hidden));assert.ok(links.every(link=>link.href===undefined));
});
test('desktop downloads use the link directly regardless of touch support',()=>{
for(const agent of ['Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)','Mozilla/5.0 (Windows NT 10.0; Win64; x64)','Mozilla/5.0 (X11; Linux x86_64)']){
assert.equal(shouldUseDownloadDialog(click,agent,0),false);
}
assert.equal(shouldUseDownloadDialog(click,'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',5),false);
assert.equal(click.defaultPrevented,false);
});
test('mobile click dialogs preserve modified clicks and other native browser actions',()=>{
const phone='Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) Mobile';
assert.equal(shouldUseDownloadDialog(click,phone,5),true);
assert.equal(shouldUseDownloadDialog(click,'Mozilla/5.0 (Linux; Android 14)',5),true);
assert.equal(shouldUseDownloadDialog(click,'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)',5),true);
for(const key of ['defaultPrevented','metaKey','ctrlKey','shiftKey','altKey'])assert.equal(shouldUseDownloadDialog({...click,[key]:true},phone,5),false);
assert.equal(shouldUseDownloadDialog({...click,button:1},phone,5),false);
});