297 lines
23 KiB
JavaScript
297 lines
23 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import { beginSearchRequestPolicy, beginNoteOpenRequestPolicy, beginReadonlyRequestPolicy, endPlatformRequestPolicy, matchPlatformRequest, SEARCH_POLICY_VERSION, NOTE_POLICY_VERSION, READONLY_POLICY_VERSION, SEARCH_SCROLL_POLICY_VERSION } from './platform-policy.mjs';
|
|
|
|
const official = 'https://www.xiaohongshu.com';
|
|
const observed = { kind: 'fill', tag: 'input', unique: true, search_input: true, sensitive: false };
|
|
const actual = { tag: 'input', search_input: true, sensitive: false, visible: true, in_viewport: true, unobscured: true };
|
|
const action = { sessionOrigin: official, pageUrl: `${official}/explore`, kind: 'fill', observed, actual, matchCount: 1 };
|
|
const policy = beginSearchRequestPolicy(action);
|
|
assert.ok(policy);
|
|
const request = { policy, automating: true, sessionOrigin: official, pageUrl: `${official}/search_result_ai?keyword=fixture`, activeMainFrame: true,
|
|
method: 'POST', resourceType: 'xhr', url: 'https://so.xiaohongshu.com/api/sns/web/v2/search/notes' };
|
|
let assertions = 1;
|
|
function check(value, expected = null) { assert.deepEqual(value, expected); assertions += 1; }
|
|
|
|
for (const [rule, url, resourceType = 'xhr'] of [
|
|
['collect', 'https://t2.xiaohongshu.com/api/v2/collect'],
|
|
['search_history', 'https://so.xiaohongshu.com/api/sns/web/search/history/sync'],
|
|
['search_notes', 'https://so.xiaohongshu.com/api/sns/web/v2/search/notes'],
|
|
['search_onebox', 'https://edith.xiaohongshu.com/api/sns/web/v1/search/onebox'],
|
|
['search_dqa', 'https://so.xiaohongshu.com/api/sns/web/v1/dqa/instant'],
|
|
['apm_data', 'https://apm-fe.xiaohongshu.com/api/data', 'fetch'],
|
|
['apm_data_xhr', 'https://apm-fe.xiaohongshu.com/api/data', 'xhr'],
|
|
]) check(matchPlatformRequest({ ...request, url, resourceType }), { policy_version: SEARCH_POLICY_VERSION, policy_rule: rule });
|
|
|
|
const enter = beginSearchRequestPolicy({ ...action, kind: 'press', key: 'Enter' });
|
|
check(matchPlatformRequest({ ...request, policy: enter }), { policy_version: SEARCH_POLICY_VERSION, policy_rule: 'search_notes' });
|
|
for (const changed of [
|
|
{sessionOrigin:'http://127.0.0.1'}, {sessionOrigin:'https://xiaohongshu.com'}, {pageUrl:'https://www.xiaohongshu.com.evil.test/explore'},
|
|
{pageUrl:'https://user:password@www.xiaohongshu.com/explore'}, {pageUrl:'http://www.xiaohongshu.com/explore'}, {pageUrl:'invalid'},
|
|
{kind:'click'}, {kind:'read'}, {kind:'extract'}, {kind:'wait'}, {kind:'scroll'}, {kind:'press',key:'Tab'},
|
|
{matchCount:0}, {matchCount:2}, {observed:{...observed,unique:false}}, {observed:{...observed,search_input:false}},
|
|
{observed:{...observed,sensitive:true}}, {observed:{...observed,tag:'button'}}, {observed:null},
|
|
{actual:{...actual,sensitive:true}}, {actual:{...actual,search_input:false}}, {actual:{...actual,visible:false}},
|
|
{actual:{...actual,in_viewport:false}}, {actual:{...actual,unobscured:false}}, {actual:null},
|
|
]) check(beginSearchRequestPolicy({ ...action, ...changed }));
|
|
|
|
for (const changed of [
|
|
{policy:null}, {policy:{version:SEARCH_POLICY_VERSION,expiresAt:Date.now()+15000}}, {automating:false}, {activeMainFrame:false},
|
|
{sessionOrigin:'https://xiaohongshu.com'}, {pageUrl:'https://example.com/'}, {pageUrl:'https://user:password@www.xiaohongshu.com/'},
|
|
{method:'GET'}, {method:'PUT'}, {method:'DELETE'}, {resourceType:'fetch'}, {resourceType:'document'}, {resourceType:'other'},
|
|
{url:'https://so.xiaohongshu.com.evil.test/api/sns/web/v2/search/notes'}, {url:'http://so.xiaohongshu.com/api/sns/web/v2/search/notes'},
|
|
{url:'https://user:password@so.xiaohongshu.com/api/sns/web/v2/search/notes'}, {url:'https://so.xiaohongshu.com:8443/api/sns/web/v2/search/notes'},
|
|
{url:'https://so.xiaohongshu.com/api/sns/web/v2/search/notes/'}, {url:'https://so.xiaohongshu.com/api/sns/web/v2/search/notes/delete'},
|
|
{url:'https://so.xiaohongshu.com/api/sns/web/v1/search/notes'}, {url:'https://edith.xiaohongshu.com/api/sns/web/v2/search/notes'},
|
|
{url:'https://so.xiaohongshu.com/api/sns/web/v2/comment/post'}, {url:'https://apm.xiaohongshu.com/api/data'}, {url:'invalid'},
|
|
{url:'https://apm-fe.xiaohongshu.com/api/data/',resourceType:'xhr'},
|
|
{url:'https://apm-fe.xiaohongshu.com.evil.test/api/data',resourceType:'xhr'},
|
|
{url:'https://apm-fe.xiaohongshu.com/api/data',resourceType:'xhr',method:'GET'},
|
|
{url:'https://edith.xiaohongshu.com/api/sns/web/v1/feed'},
|
|
]) check(matchPlatformRequest({ ...request, ...changed }));
|
|
|
|
const noteHref = `${official}/search_result/${'a'.repeat(24)}?xsec_token=FIXTURE-SECRET`;
|
|
const noteObserved = { kind:'click', tag:'a', unique:true, sensitive:false };
|
|
const noteActual = { tag:'a', sensitive:false, visible:true, in_viewport:true, unobscured:true, href:noteHref };
|
|
const noteAction = { sessionOrigin:official, pageUrl:`${official}/search_result_ai?keyword=fixture`, kind:'click',
|
|
observed:noteObserved, actual:noteActual, matchCount:1, href:noteHref };
|
|
const notePolicy = beginNoteOpenRequestPolicy(noteAction);
|
|
assert.ok(notePolicy); assertions += 1;
|
|
const noteRequest = { ...request, policy:notePolicy, url:'https://edith.xiaohongshu.com/api/sns/web/v1/feed' };
|
|
for (const [rule, url, resourceType = 'xhr'] of [
|
|
['collect','https://t2.xiaohongshu.com/api/v2/collect'],
|
|
['note_share_code','https://edith.xiaohongshu.com/api/sns/web/share/code'],
|
|
['note_widgets','https://edith.xiaohongshu.com/api/sns/web/v2/widgets'],
|
|
['note_feed','https://edith.xiaohongshu.com/api/sns/web/v1/feed'],
|
|
['note_seo','https://edith.xiaohongshu.com/api/sns/web/worldcup/note/seo'],
|
|
['note_metrics','https://edith.xiaohongshu.com/api/sns/web/v1/note/metrics_report'],
|
|
['note_history_report','https://edith.xiaohongshu.com/api/sns/v1/history/report_web'],
|
|
['apm_data','https://apm-fe.xiaohongshu.com/api/data','fetch'],
|
|
]) check(matchPlatformRequest({ ...noteRequest, url, resourceType }), { policy_version:NOTE_POLICY_VERSION, policy_rule:rule });
|
|
const targetedCollectionPolicy = beginNoteOpenRequestPolicy({...noteAction,observed:{...noteObserved,unique:false},targetResolvedUnique:true});
|
|
check(matchPlatformRequest({...noteRequest,policy:targetedCollectionPolicy}), {policy_version:NOTE_POLICY_VERSION,policy_rule:'note_feed'});
|
|
check(beginNoteOpenRequestPolicy({...noteAction,observed:{...noteObserved,unique:false},targetResolvedUnique:true,matchCount:2}));
|
|
check(matchPlatformRequest({...request,url:'https://edith.xiaohongshu.com/api/sns/v1/history/report_web'}));
|
|
check(matchPlatformRequest({...noteRequest,url:'https://edith.xiaohongshu.com/api/sns/v1/history/report_web',resourceType:'fetch'}));
|
|
const exploreHref = `${official}/explore/${'b'.repeat(24)}`;
|
|
const explorePolicy = beginNoteOpenRequestPolicy({ ...noteAction, href:exploreHref, actual:{...noteActual,href:exploreHref} });
|
|
check(matchPlatformRequest({...noteRequest,policy:explorePolicy}), { policy_version:NOTE_POLICY_VERSION,policy_rule:'note_feed' });
|
|
for (const changed of [
|
|
{kind:'fill'}, {kind:'press'}, {kind:'read'}, {kind:'extract'}, {kind:'scroll'}, {kind:'wait'},
|
|
{sessionOrigin:'http://127.0.0.1'}, {pageUrl:'https://example.com/'}, {pageUrl:'https://user:pass@www.xiaohongshu.com/'},
|
|
{matchCount:0}, {matchCount:2}, {observed:{...noteObserved,unique:false}}, {observed:{...noteObserved,sensitive:true}},
|
|
{observed:{...noteObserved,tag:'button'}}, {observed:{...noteObserved,kind:'read'}}, {observed:null},
|
|
{actual:{...noteActual,tag:'button'}}, {actual:{...noteActual,sensitive:true}}, {actual:{...noteActual,visible:false}},
|
|
{actual:{...noteActual,in_viewport:false}}, {actual:{...noteActual,unobscured:false}}, {actual:{...noteActual,href:exploreHref}},
|
|
]) check(beginNoteOpenRequestPolicy({...noteAction,...changed}));
|
|
for (const href of [
|
|
`${official}/explore`, `${official}/explore/${'b'.repeat(23)}`, `${official}/explore/${'g'.repeat(24)}`,
|
|
`${official}/Explore/${'b'.repeat(24)}`, `${official}/explore/${'b'.repeat(24)}/`, `${official}/explore/${'b'.repeat(24)}/delete`,
|
|
`${official}/user/profile/${'b'.repeat(24)}`, `https://www.xiaohongshu.com.evil.test/explore/${'b'.repeat(24)}`,
|
|
`https://user:pass@www.xiaohongshu.com/explore/${'b'.repeat(24)}`, `javascript:alert(1)`,
|
|
]) check(beginNoteOpenRequestPolicy({...noteAction,href,actual:{...noteActual,href}}));
|
|
for (const changed of [
|
|
{automating:false}, {activeMainFrame:false}, {pageUrl:'https://example.com/'}, {sessionOrigin:'https://example.com'},
|
|
{method:'GET'}, {method:'DELETE'}, {resourceType:'fetch'},
|
|
{url:'https://edith.xiaohongshu.com/api/sns/web/v1/feed/delete'}, {url:'https://so.xiaohongshu.com/api/sns/web/v1/feed'},
|
|
{url:'https://edith.xiaohongshu.com.evil.test/api/sns/web/v1/feed'},
|
|
{url:'https://user:pass@edith.xiaohongshu.com/api/sns/web/v1/feed'},
|
|
{url:'https://so.xiaohongshu.com/api/sns/web/v2/search/notes'}, {url:'https://apm-fe.xiaohongshu.com/api/data',resourceType:'xhr'},
|
|
]) check(matchPlatformRequest({...noteRequest,...changed}));
|
|
|
|
const expired = beginSearchRequestPolicy({ ...action, now:Date.now()-16000 });
|
|
check(matchPlatformRequest({ ...request, policy:expired }));
|
|
const expiredNote = beginNoteOpenRequestPolicy({...noteAction,now:Date.now()-16000});
|
|
check(matchPlatformRequest({...noteRequest,policy:expiredNote}));
|
|
endPlatformRequestPolicy(policy);
|
|
endPlatformRequestPolicy(enter);
|
|
endPlatformRequestPolicy(notePolicy);
|
|
endPlatformRequestPolicy(explorePolicy);
|
|
endPlatformRequestPolicy(targetedCollectionPolicy);
|
|
check(matchPlatformRequest(request));
|
|
check(matchPlatformRequest({ ...request, policy:enter }));
|
|
check(matchPlatformRequest(noteRequest));
|
|
check(matchPlatformRequest({...noteRequest,policy:explorePolicy}));
|
|
|
|
const readRoot = {tag:'div',readonly_root:true,sensitive:false,forbidden:false};
|
|
const readonlyAction = {sessionOrigin:official,pageUrl:`${official}/explore/${'a'.repeat(24)}`,kind:'scroll',selector:'#comments',selectorObserved:true,actualRoots:[readRoot]};
|
|
for (const kind of ['read','extract','scroll','wait']) {
|
|
const cap = beginReadonlyRequestPolicy({...readonlyAction,kind});
|
|
const readRequest = {...request,policy:cap,url:'https://t2.xiaohongshu.com/api/v2/collect'};
|
|
check(matchPlatformRequest(readRequest),{policy_version:READONLY_POLICY_VERSION,policy_rule:'collect'});
|
|
check(matchPlatformRequest({...readRequest,url:'https://apm-fe.xiaohongshu.com/api/data',resourceType:'fetch'}),{policy_version:READONLY_POLICY_VERSION,policy_rule:'apm_data'});
|
|
for (const changed of [
|
|
{url:'https://so.xiaohongshu.com/api/sns/web/v2/search/notes'}, {url:'https://edith.xiaohongshu.com/api/sns/web/v1/feed'},
|
|
{url:'https://edith.xiaohongshu.com/api/sns/v1/history/report_web'}, {url:'https://so.xiaohongshu.com/api/sns/web/search/history/sync'},
|
|
{url:'https://t2.xiaohongshu.com/api/v2/collect/post'}, {method:'PUT'}, {resourceType:'fetch'}, {activeMainFrame:false}, {automating:false},
|
|
{pageUrl:'https://example.com/'}, {url:'https://apm-fe.xiaohongshu.com/api/data',resourceType:'xhr'},
|
|
]) check(matchPlatformRequest({...readRequest,...changed}));
|
|
endPlatformRequestPolicy(cap);
|
|
check(matchPlatformRequest(readRequest));
|
|
}
|
|
for (const changed of [
|
|
{kind:'click'}, {kind:'fill'}, {kind:'press'}, {selectorObserved:false}, {selector:''}, {selector:'body'},
|
|
{sessionOrigin:'http://127.0.0.1'}, {pageUrl:'https://example.com/'}, {pageUrl:'https://user:pass@www.xiaohongshu.com/'},
|
|
{actualRoots:[]}, {actualRoots:null}, {actualRoots:[{...readRoot,readonly_root:false}]},
|
|
{actualRoots:[{...readRoot,sensitive:true}]}, {actualRoots:[{...readRoot,forbidden:true}]},
|
|
...['input','textarea','select','button','form','script','iframe','body'].map(tag=>({actualRoots:[{...readRoot,tag}]})),
|
|
]) check(beginReadonlyRequestPolicy({...readonlyAction,...changed}));
|
|
for (const kind of ['scroll','wait']) {
|
|
const cap = beginReadonlyRequestPolicy({...readonlyAction,kind,selector:'body',selectorObserved:false,actualRoots:[{...readRoot,tag:'body'}]});
|
|
check(matchPlatformRequest({...request,policy:cap,url:'https://t2.xiaohongshu.com/api/v2/collect'}),{policy_version:READONLY_POLICY_VERSION,policy_rule:'collect'});
|
|
endPlatformRequestPolicy(cap);
|
|
}
|
|
for (const kind of ['read','extract']) check(beginReadonlyRequestPolicy({...readonlyAction,kind,selector:'body',actualRoots:[{...readRoot,tag:'body'}]}));
|
|
const expiredRead = beginReadonlyRequestPolicy({...readonlyAction,now:Date.now()-16000});
|
|
check(matchPlatformRequest({...request,policy:expiredRead,url:'https://t2.xiaohongshu.com/api/v2/collect'}));
|
|
|
|
// A seek within a known search-results root receives only the pagination rule,
|
|
// bound to the exact page and the finite action window. These tests make no
|
|
// browser, API, model or network calls.
|
|
check(SEARCH_SCROLL_POLICY_VERSION, 'xhs-search-scroll-experimental-v1');
|
|
const scrollNow = 10_000;
|
|
const scrollPage = `${official}/search_result_ai?keyword=fixture&source=web`;
|
|
const scrollObserved = {kind:'read',tag:'div',unique:true,sensitive:false};
|
|
const scrollRoot = {...readRoot,visible:true,in_viewport:true};
|
|
const untilTarget = {selector:'section.note-item a.title',field:'text',value:'准备开始装修了,主打一个听劝!'};
|
|
const scrollAction = {sessionOrigin:official,pageUrl:scrollPage,kind:'scroll',selector:'#search-results',selectorObserved:true,
|
|
observed:scrollObserved,actualRoots:[scrollRoot],scrollScope:'viewport',untilTarget,now:scrollNow};
|
|
const scrollPolicy = beginReadonlyRequestPolicy(scrollAction);
|
|
check(scrollPolicy, {version:SEARCH_SCROLL_POLICY_VERSION,scope:'search_scroll',expiresAt:25_000});
|
|
check(Object.isFrozen(scrollPolicy), true);
|
|
check(Object.keys(scrollPolicy).sort(), ['expiresAt','scope','version']);
|
|
const scrollRequest = {policy:scrollPolicy,automating:true,sessionOrigin:official,pageUrl:scrollPage,activeMainFrame:true,
|
|
method:'POST',resourceType:'xhr',url:'https://so.xiaohongshu.com/api/sns/web/v2/search/notes',now:scrollNow};
|
|
for (const [pagePath,tag] of [['/search_result','section'],['/search_result_ai','div']]) {
|
|
const pageUrl = `${official}${pagePath}?keyword=fixture&source=web`;
|
|
const cap = beginReadonlyRequestPolicy({...scrollAction,pageUrl,observed:{...scrollObserved,tag},actualRoots:[{...scrollRoot,tag}]});
|
|
check(cap?.scope, 'search_scroll');
|
|
for (const [rule,url,resourceType] of [
|
|
['collect','https://t2.xiaohongshu.com/api/v2/collect','xhr'],
|
|
['apm_data','https://apm-fe.xiaohongshu.com/api/data','fetch'],
|
|
['search_notes','https://so.xiaohongshu.com/api/sns/web/v2/search/notes','xhr'],
|
|
]) check(matchPlatformRequest({...scrollRequest,policy:cap,pageUrl,url,resourceType}),
|
|
{policy_version:SEARCH_SCROLL_POLICY_VERSION,policy_rule:rule});
|
|
endPlatformRequestPolicy(cap);
|
|
check(matchPlatformRequest({...scrollRequest,policy:cap,pageUrl}));
|
|
}
|
|
const boundedTextPolicy = beginReadonlyRequestPolicy({...scrollAction,untilTarget:{...untilTarget,value:'文'.repeat(2000)}});
|
|
check(boundedTextPolicy?.scope, 'search_scroll');
|
|
endPlatformRequestPolicy(boundedTextPolicy);
|
|
|
|
// Invalid new-scope intent can legitimately retain the old readonly UI policy.
|
|
// The invariant is that it cannot authorize search pagination.
|
|
function noSearchScroll(changed, {fallback = false} = {}) {
|
|
const cap = beginReadonlyRequestPolicy({...scrollAction,...changed});
|
|
check(cap?.scope === 'search_scroll', false);
|
|
check(matchPlatformRequest({...scrollRequest,policy:cap}));
|
|
if (fallback) {
|
|
check(cap?.scope, 'readonly_ui');
|
|
check(matchPlatformRequest({...scrollRequest,policy:cap,url:'https://t2.xiaohongshu.com/api/v2/collect'}),
|
|
{policy_version:READONLY_POLICY_VERSION,policy_rule:'collect'});
|
|
}
|
|
endPlatformRequestPolicy(cap);
|
|
}
|
|
for (const changed of [
|
|
...['read','extract','wait'].map(kind=>({kind})),
|
|
{scrollScope:undefined}, {scrollScope:'container'}, {scrollScope:'Viewport'},
|
|
{observed:undefined}, {observed:null}, {observed:{...scrollObserved,kind:'scroll'}},
|
|
{observed:{...scrollObserved,kind:'click'}}, {observed:{...scrollObserved,unique:false}},
|
|
{observed:{...scrollObserved,unique:undefined}}, {observed:{...scrollObserved,sensitive:true}},
|
|
{observed:{...scrollObserved,sensitive:undefined}}, {observed:{...scrollObserved,tag:undefined}},
|
|
{observed:{...scrollObserved,tag:''}}, {observed:{...scrollObserved,tag:'DIV'}},
|
|
{observed:{...scrollObserved,tag:'section'}},
|
|
{actualRoots:[{...scrollRoot,visible:false}]}, {actualRoots:[{...scrollRoot,visible:undefined}]},
|
|
{actualRoots:[{...scrollRoot,in_viewport:false}]}, {actualRoots:[{...scrollRoot,in_viewport:undefined}]},
|
|
{actualRoots:[scrollRoot,{...scrollRoot}]},
|
|
{actualRoots:[{...scrollRoot,tag:'section'}]},
|
|
{observed:{...scrollObserved,tag:'a'},actualRoots:[{...scrollRoot,tag:'a'}]},
|
|
{untilTarget:undefined}, {untilTarget:null}, {untilTarget:[]}, {untilTarget:'title'},
|
|
{untilTarget:{...untilTarget,field:'href'}}, {untilTarget:{...untilTarget,field:'attribute'}},
|
|
{untilTarget:{...untilTarget,field:undefined}}, {untilTarget:{...untilTarget,value:''}},
|
|
{untilTarget:{...untilTarget,value:' \n\t '}}, {untilTarget:{...untilTarget,value:undefined}},
|
|
{untilTarget:{...untilTarget,value:42}}, {untilTarget:{...untilTarget,value:'文'.repeat(2001)}},
|
|
{untilTarget:{selector:untilTarget.selector,field:'text',parameter:'note_title'}},
|
|
{untilTarget:{...untilTarget,parameter:'note_title'}}, {untilTarget:{...untilTarget,attribute:'title'}},
|
|
{untilTarget:{...untilTarget,unexpected:true}},
|
|
...['','body','html',':root','body .note','html > section','section, body','xpath=//a','text=title',
|
|
'role=link','section >> a','a:has-text("title")','javascript:alert(1)'].map(selector=>({untilTarget:{...untilTarget,selector}})),
|
|
...['html',':root','body .note','section, body','xpath=//section','text=results','css=#results',
|
|
'#results >> section','section:has-text("results")','javascript:alert(1)'].map(selector=>({selector})),
|
|
...['/explore','/explore/'+ 'a'.repeat(24),'/search_result/','/search_result_ai/',
|
|
'/search_result/'+ 'a'.repeat(24),'/search_result_ai/more','/Search_result','/user/profile',
|
|
'/search_result_other'].map(path=>({pageUrl:`${official}${path}?keyword=fixture`})),
|
|
]) noSearchScroll(changed, {fallback:true});
|
|
for (const changed of [
|
|
...['click','fill','press'].map(kind=>({kind})),
|
|
{sessionOrigin:'http://127.0.0.1'}, {sessionOrigin:'https://xiaohongshu.com'},
|
|
{sessionOrigin:'https://www.xiaohongshu.com.evil.test'},
|
|
{pageUrl:'http://www.xiaohongshu.com/search_result?keyword=fixture'},
|
|
{pageUrl:'https://www.xiaohongshu.com.evil.test/search_result?keyword=fixture'},
|
|
{pageUrl:'https://user:password@www.xiaohongshu.com/search_result?keyword=fixture'},
|
|
{pageUrl:'https://www.xiaohongshu.com:8443/search_result?keyword=fixture'}, {pageUrl:'invalid'},
|
|
{selectorObserved:false}, {selectorObserved:undefined}, {selector:''}, {selector:null}, {selector:'x'.repeat(1001)},
|
|
{actualRoots:[]}, {actualRoots:null}, {actualRoots:[null]},
|
|
{actualRoots:[{...scrollRoot,readonly_root:false}]}, {actualRoots:[{...scrollRoot,sensitive:true}]},
|
|
{actualRoots:[{...scrollRoot,forbidden:true}]},
|
|
...['input','textarea','select','button','form','script','style','noscript','iframe','body','html'].map(tag=>
|
|
({observed:{...scrollObserved,tag},actualRoots:[{...scrollRoot,tag}]})),
|
|
{selector:'body',selectorObserved:false,observed:{...scrollObserved,tag:'body'},actualRoots:[{...scrollRoot,tag:'body'}]},
|
|
{now:NaN}, {now:Infinity},
|
|
]) noSearchScroll(changed);
|
|
|
|
for (const changed of [
|
|
{policy:null}, {policy:{}}, {policy:{...scrollPolicy}},
|
|
{policy:Object.freeze({version:SEARCH_SCROLL_POLICY_VERSION,scope:'search_scroll',expiresAt:25_000,pageUrl:scrollPage,startsAt:scrollNow})},
|
|
{automating:false}, {automating:undefined}, {activeMainFrame:false}, {activeMainFrame:undefined},
|
|
{sessionOrigin:'https://xiaohongshu.com'}, {sessionOrigin:'https://www.xiaohongshu.com.evil.test'},
|
|
{pageUrl:`${official}/search_result?keyword=fixture&source=web`},
|
|
{pageUrl:`${official}/search_result_ai?keyword=other&source=web`},
|
|
{pageUrl:`${official}/search_result_ai?source=web&keyword=fixture`},
|
|
{pageUrl:`${scrollPage}#results`}, {pageUrl:`${scrollPage}&page=2`},
|
|
{pageUrl:`${official}/explore?keyword=fixture&source=web`},
|
|
{pageUrl:'https://www.xiaohongshu.com.evil.test/search_result_ai?keyword=fixture&source=web'},
|
|
{pageUrl:'https://user:password@www.xiaohongshu.com/search_result_ai?keyword=fixture&source=web'},
|
|
{pageUrl:'http://www.xiaohongshu.com/search_result_ai?keyword=fixture&source=web'},
|
|
{pageUrl:'https://www.xiaohongshu.com:8443/search_result_ai?keyword=fixture&source=web'},
|
|
{method:'GET'}, {method:'PUT'}, {method:'DELETE'}, {method:'PATCH'}, {method:'post'},
|
|
{resourceType:'fetch'}, {resourceType:'document'}, {resourceType:'other'},
|
|
{url:'https://so.xiaohongshu.com/api/sns/web/v2/search/notes/'},
|
|
{url:'https://so.xiaohongshu.com/api/sns/web/v2/search/notes/delete'},
|
|
{url:'https://so.xiaohongshu.com/api/sns/web/v1/search/notes'},
|
|
{url:'https://edith.xiaohongshu.com/api/sns/web/v2/search/notes'},
|
|
{url:'https://so.xiaohongshu.com.evil.test/api/sns/web/v2/search/notes'},
|
|
{url:'https://user:password@so.xiaohongshu.com/api/sns/web/v2/search/notes'},
|
|
{url:'http://so.xiaohongshu.com/api/sns/web/v2/search/notes'},
|
|
{url:'https://so.xiaohongshu.com:8443/api/sns/web/v2/search/notes'},
|
|
{url:'https://so.xiaohongshu.com/api/sns/web/search/history/sync'},
|
|
{url:'https://edith.xiaohongshu.com/api/sns/web/v1/search/onebox'},
|
|
{url:'https://so.xiaohongshu.com/api/sns/web/v1/dqa/instant'},
|
|
{url:'https://edith.xiaohongshu.com/api/sns/web/v1/feed'},
|
|
{url:'https://edith.xiaohongshu.com/api/sns/v1/history/report_web'},
|
|
{url:'https://t2.xiaohongshu.com/api/v2/collect/post'},
|
|
{url:'https://apm-fe.xiaohongshu.com/api/data',resourceType:'xhr'},
|
|
{url:'https://so.xiaohongshu.com/api/sns/web/v2/comment/post'},
|
|
{url:'https://edith.xiaohongshu.com/api/sns/web/v1/user/follow'},
|
|
{url:'https://edith.xiaohongshu.com/api/sns/web/v1/im/message/send'},
|
|
{url:'https://so.xiaohongshu.com/api/sns/web/v2/unknown'},
|
|
{url:'https://so.xiaohongshu.com/api/security/verify'},
|
|
{url:'javascript:alert(1)'}, {url:'invalid'},
|
|
{now:scrollNow-1}, {now:25_000}, {now:25_001}, {now:NaN}, {now:Infinity},
|
|
]) check(matchPlatformRequest({...scrollRequest,...changed}));
|
|
for (const now of [scrollNow,24_999]) check(matchPlatformRequest({...scrollRequest,now}),
|
|
{policy_version:SEARCH_SCROLL_POLICY_VERSION,policy_rule:'search_notes'});
|
|
|
|
// Mutating the caller's action after creation cannot move the internal page pin.
|
|
const mutableAction = {...scrollAction};
|
|
const pinnedPolicy = beginReadonlyRequestPolicy(mutableAction);
|
|
mutableAction.pageUrl = `${official}/search_result_ai?keyword=changed`;
|
|
check(matchPlatformRequest({...scrollRequest,policy:pinnedPolicy,pageUrl:mutableAction.pageUrl}));
|
|
check(matchPlatformRequest({...scrollRequest,policy:pinnedPolicy}),
|
|
{policy_version:SEARCH_SCROLL_POLICY_VERSION,policy_rule:'search_notes'});
|
|
endPlatformRequestPolicy(pinnedPolicy);
|
|
check(matchPlatformRequest({...scrollRequest,policy:pinnedPolicy}));
|
|
endPlatformRequestPolicy(scrollPolicy);
|
|
check(matchPlatformRequest(scrollRequest));
|
|
console.log(JSON.stringify({ result:'passed', assertions, search_rules:7, note_rules:8, readonly_rules:2, search_scroll_rules:3,
|
|
scoped_page_binding:true, live_requests:0, localhost_exception:false, expiry_and_revocation:true }));
|