script: Enable crypto task source at task manager (#39453)

The Web Cryptography API has the "crypto task source"
(https://w3c.github.io/webcrypto/#dfn-crypto-task-source-0) to queue
tasks to resolve or reject promises created in response to calls to
methods of `SubtleCrypto`.

This patch enables this task source at the script task manager, and
queue tasks on this task source from existing steps.

A few WPT error expectations are also added to WPT meta. The related
cryptographic algorithms have not yet implemented, so the errors are
expected. I don't know why WPT test did not capture them before.

Testing: Existing tests suffice.

---------

Signed-off-by: Kingsley Yung <kingsley@kkoyung.dev>
This commit is contained in:
Kingsley Yung 2025-09-25 00:21:03 +08:00 committed by GitHub
parent da221d4045
commit 9d7b438d6b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 48 additions and 17 deletions

View file

@ -132,6 +132,32 @@ impl SubtleCrypto {
pub(crate) fn new(global: &GlobalScope, can_gc: CanGc) -> DomRoot<SubtleCrypto> {
reflect_dom_object(Box::new(SubtleCrypto::new_inherited()), global, can_gc)
}
/// Queue a global task on the crypto task source, given realm's global object, to resolve
/// promise with a CryptoKey.
fn resolve_promise_with_key(&self, promise: Rc<Promise>, key: DomRoot<CryptoKey>) {
let trusted_key = Trusted::new(&*key);
let trusted_promise = TrustedPromise::new(promise);
self.global().task_manager().crypto_task_source().queue(
task!(generate_key_result: move || {
let key = trusted_key.root();
let promise = trusted_promise.root();
promise.resolve_native(&key, CanGc::note());
}),
);
}
/// Queue a global task on the crypto task source, given realm's global object, to reject
/// promise with an error.
fn reject_promise_with_error(&self, promise: Rc<Promise>, error: Error) {
let trusted_promise = TrustedPromise::new(promise);
self.global().task_manager().crypto_task_source().queue(
task!(generate_key_result: move || {
let promise = trusted_promise.root();
promise.reject_error(error, CanGc::note());
}),
);
}
}
impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
@ -556,17 +582,16 @@ impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
},
};
// TODO: Step 10. Queue a global task on the crypto task source, given realm's
// global object, to perform the remaining steps.
// Step 10. Queue a global task on the crypto task source, given realm's global
// object, to perform the remaining steps.
// Step 11. Let result be the result of converting result to an ECMAScript Object
// in realm, as defined by [WebIDL].
// Step 12. Resolve promise with result.
// TODO: Implement CryptoKeyPair case
match key {
CryptoKeyOrCryptoKeyPair::CryptoKey(crypto_key) =>
promise.resolve_native(&crypto_key, CanGc::note()),
};
CryptoKeyOrCryptoKeyPair::CryptoKey(key) => {
subtle.resolve_promise_with_key(promise, key);
},
}
}));
promise
@ -876,10 +901,9 @@ impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
let subtle = this.root();
let promise = trusted_promise.root();
// TODO: Step 8. If the following steps or referenced procedures say to throw an
// error, queue a global task on the crypto task source, given realm's global
// object, to reject promise with the returned error; and then terminate the
// algorithm.
// Step 8. If the following steps or referenced procedures say to throw an error,
// queue a global task on the crypto task source, given realm's global object, to
// reject promise with the returned error; and then terminate the algorithm.
// Step 9. Let result be the CryptoKey object that results from performing the
// import key operation specified by normalizedAlgorithm using keyData, algorithm,
@ -894,7 +918,7 @@ impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
) {
Ok(key) => key,
Err(error) => {
promise.reject_error(error, CanGc::note());
subtle.reject_promise_with_error(promise, error);
return;
},
};
@ -902,7 +926,7 @@ impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
// Step 10. If the [[type]] internal slot of result is "secret" or "private" and
// usages is empty, then throw a SyntaxError.
if matches!(result.Type(), KeyType::Secret | KeyType::Private) && key_usages.is_empty() {
promise.reject_error(Error::Syntax(None), CanGc::note());
subtle.reject_promise_with_error(promise, Error::Syntax(None));
return;
}
@ -912,13 +936,12 @@ impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
// Step 12. Set the [[usages]] internal slot of result to the normalized value of usages.
result.set_usages(&key_usages);
// TODO: Step 13. Queue a global task on the crypto task source, given realm's
// global object, to perform the remaining steps.
// Step 13. Queue a global task on the crypto task source, given realm's global
// object, to perform the remaining steps.
// Step 14. Let result be the result of converting result to an ECMAScript Object
// in realm, as defined by [WebIDL].
// Step 15. Resolve promise with result.
promise.resolve_native(&result, CanGc::note());
subtle.resolve_promise_with_key(promise, result);
}));
promise

View file

@ -135,6 +135,7 @@ impl TaskManager {
task_source_functions!(self, bitmap_task_source, Bitmap);
task_source_functions!(self, canvas_blob_task_source, Canvas);
task_source_functions!(self, clipboard_task_source, Clipboard);
task_source_functions!(self, crypto_task_source, Crypto);
task_source_functions!(self, database_access_task_source, DatabaseAccess);
task_source_functions!(self, dom_manipulation_task_source, DOMManipulation);
task_source_functions!(self, file_reading_task_source, FileReading);

View file

@ -26,6 +26,8 @@ pub(crate) enum TaskSourceName {
Bitmap,
Canvas,
Clipboard,
/// <https://w3c.github.io/webcrypto/#dfn-crypto-task-source-0>
Crypto,
DatabaseAccess,
DOMManipulation,
FileReading,
@ -56,6 +58,7 @@ impl From<TaskSourceName> for ScriptThreadEventCategory {
TaskSourceName::Bitmap => ScriptThreadEventCategory::ScriptEvent,
TaskSourceName::Canvas => ScriptThreadEventCategory::ScriptEvent,
TaskSourceName::Clipboard => ScriptThreadEventCategory::ScriptEvent,
TaskSourceName::Crypto => ScriptThreadEventCategory::ScriptEvent,
TaskSourceName::DatabaseAccess => ScriptThreadEventCategory::ScriptEvent,
TaskSourceName::DOMManipulation => ScriptThreadEventCategory::ScriptEvent,
TaskSourceName::FileReading => ScriptThreadEventCategory::FileRead,

View file

@ -50,6 +50,7 @@
[cfrg_curves_bits_curve25519.https.any.worker.html]
expected: ERROR
[X25519 key derivation checks for all-zero value result with a key of order 0]
expected: FAIL

View file

@ -47,6 +47,7 @@
[cfrg_curves_bits_curve448.tentative.https.any.worker.html]
expected: ERROR
[X448 key derivation checks for all-zero value result with a key of order 0]
expected: FAIL

View file

@ -1,4 +1,5 @@
[cfrg_curves_keys_curve25519.https.any.worker.html]
expected: ERROR
[X25519 deriveBits checks for all-zero value result with a key of order 0]
expected: FAIL

View file

@ -1,4 +1,5 @@
[cfrg_curves_keys_curve448.tentative.https.any.worker.html]
expected: ERROR
[X448 deriveBits checks for all-zero value result with a key of order 0]
expected: FAIL