62 lines
2.9 KiB
JavaScript
62 lines
2.9 KiB
JavaScript
// Fixture tests for pagination, decryption errors, and plaintext redaction.
|
|||
|
|
const assert = require('node:assert/strict');
|
||
|
|
const vm = require('node:vm');
|
||
|
|
const fs = require('node:fs');
|
||
|
|
const probe = JSON.parse(fs.readFileSync(process.argv[2], 'utf8'));
|
||
|
|
const rows = ['a','b','c','d','e'].map(id => ({id, body:'text-'+id, type:'chat', t:123, invisible:id==='b'}));
|
||
|
|
const events = [];
|
||
|
|
function req(result) {
|
||
|
|
const r = {};
|
||
|
|
queueMicrotask(() => {r.result=result; r.onsuccess();});
|
||
|
|
return r;
|
||
|
|
}
|
||
|
|
const store = {
|
||
|
|
count:()=>req(rows.length),
|
||
|
|
openKeyCursor(range,direction) {
|
||
|
|
const selected=rows.filter(r=>!range || ((range.lower===undefined || r.id>range.lower) && r.id<=range.upper));
|
||
|
|
if(direction==='prev')selected.reverse();
|
||
|
|
const request={};let index=0;
|
||
|
|
function next(){queueMicrotask(()=>{
|
||
|
|
request.result=index<selected.length?{primaryKey:selected[index++].id,continue:next}:null;
|
||
|
|
request.onsuccess();
|
||
|
|
});}
|
||
|
|
next();return request;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const db={objectStoreNames:{contains:n=>n==='message'},transaction:(name,mode)=>{
|
||
|
|
assert.equal(name,'message');assert.equal(mode,'readonly');return {objectStore:()=>store};
|
||
|
|
},close:()=>events.push('close')};
|
||
|
|
const modules={
|
||
|
|
WAWebSchemaMessage:{getMessageTable:()=>({get:async key=>{
|
||
|
|
events.push('decrypt:'+key);
|
||
|
|
if(key==='c')throw Error('simulated unavailable decryption key');
|
||
|
|
return {...rows.find(r=>r.id===key)};
|
||
|
|
}})},
|
||
|
|
WAWebDBMessageSerialization:{messageFromDbRow:row=>{
|
||
|
|
events.push('decode:'+row.id);
|
||
|
|
return {...row,id:{id:row.id,remote:'test-chat',fromMe:false}};
|
||
|
|
}}
|
||
|
|
};
|
||
|
|
async function run(options){return vm.runInNewContext(probe.replace('__OPTIONS__',JSON.stringify(options)),{
|
||
|
|
location:{origin:'https://web.whatsapp.com'}, require:n=>modules[n],
|
||
|
|
indexedDB:{databases:async()=>[{name:'model-storage'}],open:()=>req(db)},
|
||
|
|
IDBKeyRange:{upperBound:upper=>({upper}),bound:(lower,upper,openLower,openUpper)=>{
|
||
|
|
assert.equal(openLower,true);assert.equal(openUpper,false);return {lower,upper};
|
||
|
|
}}
|
||
|
|
});}
|
||
|
|
(async()=>{
|
||
|
|
const bounds=await run({mode:'bounds'});assert.equal(bounds.count,5);assert.equal(bounds.upper,'e');
|
||
|
|
let after=null,all=[];
|
||
|
|
while(after!=='e'){
|
||
|
|
const page=await run({mode:'batch',upper:'e',after,batch:2,redact:false});
|
||
|
|
assert.ok(page.keys.length<=2);all.push(...page.messages);after=page.last;
|
||
|
|
}
|
||
|
|
assert.deepEqual(all.map(m=>m.id),['a','b','c','d','e']); // UI-invisible b remains included.
|
||
|
|
assert.equal(all[2].error,'row_decryption_or_decoding_failed');
|
||
|
|
assert.equal(all[1].body,'text-b');
|
||
|
|
const redacted=await run({mode:'batch',upper:'b',after:null,batch:2,redact:true});
|
||
|
|
assert.ok(redacted.messages.every(m=>!('body' in m)&&!('caption' in m)));
|
||
|
|
assert.equal(redacted.messages[0].body_length,6);
|
||
|
|
assert.ok(events.indexOf('decrypt:a')<events.indexOf('decode:a'));
|
||
|
|
console.log('PASS: bounded pagination, upper bound, invisible rows, row errors, decryption order, redaction');
|
||
|
|
})().catch(error=>{console.error(error);process.exitCode=1;});
|