Bug 1976779 - rsclientcerts: make each backend responsible for rate-limiting calls to find_objects r=jschanck
Before this patch, `rsclientcerts::manager` would rate-limit calls to
`find_objects` to once every 3 seconds because the underlying operation can be
time-consuming (in particular, on macOS and Windows, if there are many
certificates/keys available). On Android, keys aren't available until the user
selects one, which means that if a call to `find_objects` happened before the
selection prompt was shown (which is what happens) and the user chose one in
less than 3 seconds, the backend wouldn't search again, thus making it seem like
no keys were available, which would cause Firefox to not send a client
certificate. This patch makes each backend implementation responsible for this
rate-limiting, because only they know if it's appropriate to do so (in particular,
on Android, `find_objects` doesn't have the same performance concern as
on macOS and Windows because rather than searching for certificates and
keys, it asks `ClientAuthCertificateManager` for the cached list of certificates
and keys that have already been approved for use by the user).
Differential Revision: https://phabricator.services.mozilla.com/D257065
<!DOCTYPE html><metacharset=utf-8><title>Cross-realm IDBObjectStore methods from detached iframe work as expected</title><scriptsrc=/resources/testharness.js></script><scriptsrc=/resources/testharnessreport.js></script><scriptsrc=resources/support.js></script><body><script>"use strict";constKEY_EXISTING_LOWER=1000;constKEY_EXISTING_UPPER=1001;constKEY_EXISTING_RANGE=IDBKeyRange.bound(KEY_EXISTING_LOWER,KEY_EXISTING_UPPER);constKEY_NEWLY_ADDED=1002;constVALUE_EXISTING_LOWER="VALUE_EXISTING_LOWER";constVALUE_EXISTING_UPPER="VALUE_EXISTING_UPPER";constVALUE_NEWLY_ADDED="VALUE_NEWLY_ADDED";consttestCases=[{methodName:"put",arguments:[KEY_NEWLY_ADDED,KEY_EXISTING_LOWER],validateResult:(t,e)=>{assert_equals(e.target.result,KEY_EXISTING_LOWER);constrq=e.target.source.getAll();rq.onsuccess=t.step_func_done(e=>{assert_array_equals(e.target.result,[KEY_NEWLY_ADDED,VALUE_EXISTING_UPPER]);});},},{methodName:"add",arguments:[VALUE_NEWLY_ADDED,KEY_NEWLY_ADDED],validateResult:(t,e)=>{assert_equals(e.target.result,KEY_NEWLY_ADDED);constrq=e.target.source.getAll();rq.onsuccess=t.step_func_done(e=>{assert_array_equals(e.target.result,[VALUE_EXISTING_LOWER,VALUE_EXISTING_UPPER,VALUE_NEWLY_ADDED]);});},},{methodName:"delete",arguments:[KEY_EXISTING_LOWER],validateResult:(t,e)=>{assert_equals(e.target.result,undefined);constrq=e.target.source.getAllKeys();rq.onsuccess=t.step_func_done(e=>{assert_array_equals(e.target.result,[KEY_EXISTING_UPPER]);});},},{methodName:"clear",arguments:[],validateResult:(t,e)=>{assert_equals(e.target.result,undefined);constrq=e.target.source.count();rq.onsuccess=t.step_func_done(e=>{assert_equals(e.target.result,0);});},},{methodName:"get",arguments:[KEY_EXISTING_UPPER],validateResult:(t,e)=>{assert_equals(e.target.result,VALUE_EXISTING_UPPER);t.done();},},{methodName:"getKey",arguments:[KEY_EXISTING_LOWER],validateResult:(t,e)=>{assert_equals(e.target.result,KEY_EXISTING_LOWER);t.done();},},{methodName:"getAll",arguments:[KEY_EXISTING_RANGE],validateResult:(t,e)=>{assert_array_equals(e.target.result,[VALUE_EXISTING_LOWER,VALUE_EXISTING_UPPER]);t.done();},},{methodName:"getAllKeys",arguments:[KEY_EXISTING_RANGE],validateResult:(t,e)=>{assert_array_equals(e.target.result,[KEY_EXISTING_LOWER,KEY_EXISTING_UPPER]);t.done();},},{methodName:"count",arguments:[],validateResult:(t,e)=>{assert_equals(e.target.result,2);t.done();},},{methodName:"openCursor",arguments:[],validateResult:(t,e)=>{constcursor=e.target.result;assert_true(cursorinstanceofIDBCursor);assert_equals(cursor.value,VALUE_EXISTING_LOWER);t.done();},},{methodName:"openKeyCursor",arguments:[],validateResult:(t,e)=>{constcursor=e.target.result;assert_true(cursorinstanceofIDBCursor);assert_equals(cursor.key,KEY_EXISTING_LOWER);t.done();},},];for(consttestCaseoftestCases){async_test(t=>{constiframe=document.createElement("iframe");iframe.onload=t.step_func(()=>{constmethod=iframe.contentWindow.IDBObjectStore.prototype[testCase.methodName];iframe.remove();letdb;constopen_rq=createdb(t);open_rq.onupgradeneeded=t.step_func(e=>{db=e.target.result;constobjectStore=db.createObjectStore("store");objectStore.add(VALUE_EXISTING_LOWER,KEY_EXISTING_LOWER);objectStore.add(VALUE_EXISTING_UPPER,KEY_EXISTING_UPPER);});open_rq.onsuccess=t.step_func(()=>{constobjectStore=db.transaction("store","readwrite").objectStore("store");constrq=method.call(objectStore,...testCase.arguments);rq.onsuccess=t.step_func(e=>{testCase.validateResult(t,e);});});});document.body.append(iframe);},`Cross-realm IDBObjectStore::${testCase.methodName}() method from detached <iframe> works as expected`);}</script>