mirror of
https://github.com/servo/servo.git
synced 2025-09-23 13:20:11 +01:00
script: Replace webcrypto-specific macro with trait abstraction. (#39205)
The value_from_js_object macro exists to paper over differences between dictionary types that require rooting (via `RootedTraceableBox`) and those that do not. However, I need to read the macro source every time I look at the code that uses it because I can never remember what it's doing. These changes replace the macro with a trait abstraction that is clearer, and should be a code size win as well. Testing: Existing WPT tests suffice. Signed-off-by: Josh Matthews <josh@joshmatthews.net>
This commit is contained in:
parent
9584b9e57d
commit
e00bfb525b
1 changed files with 126 additions and 32 deletions
|
@ -20,8 +20,8 @@ use dom_struct::dom_struct;
|
||||||
use js::conversions::ConversionResult;
|
use js::conversions::ConversionResult;
|
||||||
use js::jsapi::{JS_NewObject, JSObject};
|
use js::jsapi::{JS_NewObject, JSObject};
|
||||||
use js::jsval::{ObjectValue, UndefinedValue};
|
use js::jsval::{ObjectValue, UndefinedValue};
|
||||||
use js::rust::MutableHandleObject;
|
|
||||||
use js::rust::wrappers::JS_ParseJSON;
|
use js::rust::wrappers::JS_ParseJSON;
|
||||||
|
use js::rust::{HandleValue, MutableHandleObject};
|
||||||
use js::typedarray::ArrayBufferU8;
|
use js::typedarray::ArrayBufferU8;
|
||||||
use servo_rand::{RngCore, ServoRng};
|
use servo_rand::{RngCore, ServoRng};
|
||||||
|
|
||||||
|
@ -1403,15 +1403,103 @@ enum KeyWrapAlgorithm {
|
||||||
AesGcm(SubtleAesGcmParams),
|
AesGcm(SubtleAesGcmParams),
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! value_from_js_object {
|
/// Helper to abstract the conversion process of a JS value into many different WebIDL dictionaries.
|
||||||
($t: ty, $cx: ident, $value: ident) => {{
|
trait DictionaryFromJSVal: Sized {
|
||||||
let params_result =
|
fn create(cx: JSContext, value: HandleValue) -> Result<ConversionResult<Self>, ()>;
|
||||||
<$t>::new($cx, $value.handle(), CanGc::note()).map_err(|_| Error::JSFailed)?;
|
}
|
||||||
|
|
||||||
|
impl DictionaryFromJSVal for Algorithm {
|
||||||
|
fn create(cx: JSContext, value: HandleValue) -> Result<ConversionResult<Self>, ()> {
|
||||||
|
Self::new(cx, value, CanGc::note())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DictionaryFromJSVal for AesDerivedKeyParams {
|
||||||
|
fn create(cx: JSContext, value: HandleValue) -> Result<ConversionResult<Self>, ()> {
|
||||||
|
Self::new(cx, value, CanGc::note())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DictionaryFromJSVal for AesKeyGenParams {
|
||||||
|
fn create(cx: JSContext, value: HandleValue) -> Result<ConversionResult<Self>, ()> {
|
||||||
|
Self::new(cx, value, CanGc::note())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DictionaryFromJSVal for RootedTraceableBox<HmacImportParams> {
|
||||||
|
fn create(cx: JSContext, value: HandleValue) -> Result<ConversionResult<Self>, ()> {
|
||||||
|
HmacImportParams::new(cx, value, CanGc::note())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DictionaryFromJSVal for RootedTraceableBox<HmacKeyGenParams> {
|
||||||
|
fn create(cx: JSContext, value: HandleValue) -> Result<ConversionResult<Self>, ()> {
|
||||||
|
HmacKeyGenParams::new(cx, value, CanGc::note())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DictionaryFromJSVal for HmacKeyAlgorithm {
|
||||||
|
fn create(cx: JSContext, value: HandleValue) -> Result<ConversionResult<Self>, ()> {
|
||||||
|
Self::new(cx, value, CanGc::note())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DictionaryFromJSVal for RootedTraceableBox<AesCbcParams> {
|
||||||
|
fn create(cx: JSContext, value: HandleValue) -> Result<ConversionResult<Self>, ()> {
|
||||||
|
AesCbcParams::new(cx, value, CanGc::note())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DictionaryFromJSVal for RootedTraceableBox<AesCtrParams> {
|
||||||
|
fn create(cx: JSContext, value: HandleValue) -> Result<ConversionResult<Self>, ()> {
|
||||||
|
AesCtrParams::new(cx, value, CanGc::note())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DictionaryFromJSVal for RootedTraceableBox<AesGcmParams> {
|
||||||
|
fn create(cx: JSContext, value: HandleValue) -> Result<ConversionResult<Self>, ()> {
|
||||||
|
AesGcmParams::new(cx, value, CanGc::note())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DictionaryFromJSVal for RootedTraceableBox<Pbkdf2Params> {
|
||||||
|
fn create(cx: JSContext, value: HandleValue) -> Result<ConversionResult<Self>, ()> {
|
||||||
|
Pbkdf2Params::new(cx, value, CanGc::note())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DictionaryFromJSVal for RootedTraceableBox<HkdfParams> {
|
||||||
|
fn create(cx: JSContext, value: HandleValue) -> Result<ConversionResult<Self>, ()> {
|
||||||
|
HkdfParams::new(cx, value, CanGc::note())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_native_dict<T>(converted: Result<ConversionResult<T>, ()>) -> Fallible<T> {
|
||||||
|
let params_result = converted.map_err(|_| Error::JSFailed)?;
|
||||||
let ConversionResult::Success(params) = params_result else {
|
let ConversionResult::Success(params) = params_result else {
|
||||||
return Err(Error::Syntax(None));
|
return Err(Error::Syntax(None));
|
||||||
};
|
};
|
||||||
params
|
Ok(params)
|
||||||
}};
|
}
|
||||||
|
|
||||||
|
fn value_from_js_object<T: DictionaryFromJSVal>(cx: JSContext, value: HandleValue) -> Fallible<T> {
|
||||||
|
extract_native_dict(T::create(cx, value))
|
||||||
|
}
|
||||||
|
|
||||||
|
trait DictionaryFromJSValType: crate::JSTraceable {}
|
||||||
|
impl<T: crate::JSTraceable + 'static> DictionaryFromJSValType for T where
|
||||||
|
RootedTraceableBox<T>: DictionaryFromJSVal
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
fn boxed_value_from_js_object<T: DictionaryFromJSValType>(
|
||||||
|
cx: JSContext,
|
||||||
|
value: HandleValue,
|
||||||
|
) -> Fallible<RootedTraceableBox<T>>
|
||||||
|
where
|
||||||
|
RootedTraceableBox<T>: DictionaryFromJSVal,
|
||||||
|
{
|
||||||
|
extract_native_dict(<RootedTraceableBox<T>>::create(cx, value))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://w3c.github.io/webcrypto/#algorithm-normalization-normalize-an-algorithm> with operation `"get key length"`
|
/// <https://w3c.github.io/webcrypto/#algorithm-normalization-normalize-an-algorithm> with operation `"get key length"`
|
||||||
|
@ -1422,17 +1510,17 @@ fn normalize_algorithm_for_get_key_length(
|
||||||
match algorithm {
|
match algorithm {
|
||||||
AlgorithmIdentifier::Object(obj) => {
|
AlgorithmIdentifier::Object(obj) => {
|
||||||
rooted!(in(*cx) let value = ObjectValue(obj.get()));
|
rooted!(in(*cx) let value = ObjectValue(obj.get()));
|
||||||
let algorithm = value_from_js_object!(Algorithm, cx, value);
|
let algorithm = value_from_js_object::<Algorithm>(cx, value.handle())?;
|
||||||
|
|
||||||
let name = algorithm.name.str();
|
let name = algorithm.name.str();
|
||||||
let normalized_algorithm = if name.eq_ignore_ascii_case(ALG_AES_CBC) ||
|
let normalized_algorithm = if name.eq_ignore_ascii_case(ALG_AES_CBC) ||
|
||||||
name.eq_ignore_ascii_case(ALG_AES_CTR) ||
|
name.eq_ignore_ascii_case(ALG_AES_CTR) ||
|
||||||
name.eq_ignore_ascii_case(ALG_AES_GCM)
|
name.eq_ignore_ascii_case(ALG_AES_GCM)
|
||||||
{
|
{
|
||||||
let params = value_from_js_object!(AesDerivedKeyParams, cx, value);
|
let params = value_from_js_object::<AesDerivedKeyParams>(cx, value.handle())?;
|
||||||
GetKeyLengthAlgorithm::Aes(params.length)
|
GetKeyLengthAlgorithm::Aes(params.length)
|
||||||
} else if name.eq_ignore_ascii_case(ALG_HMAC) {
|
} else if name.eq_ignore_ascii_case(ALG_HMAC) {
|
||||||
let params = value_from_js_object!(HmacImportParams, cx, value);
|
let params = boxed_value_from_js_object::<HmacImportParams>(cx, value.handle())?;
|
||||||
let subtle_params = SubtleHmacImportParams::new(cx, params)?;
|
let subtle_params = SubtleHmacImportParams::new(cx, params)?;
|
||||||
return Ok(GetKeyLengthAlgorithm::Hmac(subtle_params));
|
return Ok(GetKeyLengthAlgorithm::Hmac(subtle_params));
|
||||||
} else {
|
} else {
|
||||||
|
@ -1456,7 +1544,7 @@ fn normalize_algorithm_for_digest(
|
||||||
let name = match algorithm {
|
let name = match algorithm {
|
||||||
AlgorithmIdentifier::Object(obj) => {
|
AlgorithmIdentifier::Object(obj) => {
|
||||||
rooted!(in(*cx) let value = ObjectValue(obj.get()));
|
rooted!(in(*cx) let value = ObjectValue(obj.get()));
|
||||||
let algorithm = value_from_js_object!(Algorithm, cx, value);
|
let algorithm = value_from_js_object::<Algorithm>(cx, value.handle())?;
|
||||||
|
|
||||||
algorithm.name.str().to_uppercase()
|
algorithm.name.str().to_uppercase()
|
||||||
},
|
},
|
||||||
|
@ -1482,11 +1570,11 @@ fn normalize_algorithm_for_import_key(
|
||||||
let name = match algorithm {
|
let name = match algorithm {
|
||||||
AlgorithmIdentifier::Object(obj) => {
|
AlgorithmIdentifier::Object(obj) => {
|
||||||
rooted!(in(*cx) let value = ObjectValue(obj.get()));
|
rooted!(in(*cx) let value = ObjectValue(obj.get()));
|
||||||
let algorithm = value_from_js_object!(Algorithm, cx, value);
|
let algorithm = value_from_js_object::<Algorithm>(cx, value.handle())?;
|
||||||
|
|
||||||
let name = algorithm.name.str().to_uppercase();
|
let name = algorithm.name.str().to_uppercase();
|
||||||
if name == ALG_HMAC {
|
if name == ALG_HMAC {
|
||||||
let params = value_from_js_object!(HmacImportParams, cx, value);
|
let params = boxed_value_from_js_object::<HmacImportParams>(cx, value.handle())?;
|
||||||
let subtle_params = SubtleHmacImportParams::new(cx, params)?;
|
let subtle_params = SubtleHmacImportParams::new(cx, params)?;
|
||||||
return Ok(ImportKeyAlgorithm::Hmac(subtle_params));
|
return Ok(ImportKeyAlgorithm::Hmac(subtle_params));
|
||||||
}
|
}
|
||||||
|
@ -1520,14 +1608,14 @@ fn normalize_algorithm_for_derive_bits(
|
||||||
};
|
};
|
||||||
|
|
||||||
rooted!(in(*cx) let value = ObjectValue(obj.get()));
|
rooted!(in(*cx) let value = ObjectValue(obj.get()));
|
||||||
let algorithm = value_from_js_object!(Algorithm, cx, value);
|
let algorithm = value_from_js_object::<Algorithm>(cx, value.handle())?;
|
||||||
|
|
||||||
let normalized_algorithm = if algorithm.name.str().eq_ignore_ascii_case(ALG_PBKDF2) {
|
let normalized_algorithm = if algorithm.name.str().eq_ignore_ascii_case(ALG_PBKDF2) {
|
||||||
let params = value_from_js_object!(Pbkdf2Params, cx, value);
|
let params = boxed_value_from_js_object::<Pbkdf2Params>(cx, value.handle())?;
|
||||||
let subtle_params = SubtlePbkdf2Params::new(cx, params)?;
|
let subtle_params = SubtlePbkdf2Params::new(cx, params)?;
|
||||||
DeriveBitsAlgorithm::Pbkdf2(subtle_params)
|
DeriveBitsAlgorithm::Pbkdf2(subtle_params)
|
||||||
} else if algorithm.name.str().eq_ignore_ascii_case(ALG_HKDF) {
|
} else if algorithm.name.str().eq_ignore_ascii_case(ALG_HKDF) {
|
||||||
let params = value_from_js_object!(HkdfParams, cx, value);
|
let params = boxed_value_from_js_object::<HkdfParams>(cx, value.handle())?;
|
||||||
let subtle_params = SubtleHkdfParams::new(cx, params)?;
|
let subtle_params = SubtleHkdfParams::new(cx, params)?;
|
||||||
DeriveBitsAlgorithm::Hkdf(subtle_params)
|
DeriveBitsAlgorithm::Hkdf(subtle_params)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1548,17 +1636,17 @@ fn normalize_algorithm_for_encrypt_or_decrypt(
|
||||||
};
|
};
|
||||||
|
|
||||||
rooted!(in(*cx) let value = ObjectValue(obj.get()));
|
rooted!(in(*cx) let value = ObjectValue(obj.get()));
|
||||||
let algorithm = value_from_js_object!(Algorithm, cx, value);
|
let algorithm = value_from_js_object::<Algorithm>(cx, value.handle())?;
|
||||||
|
|
||||||
let name = algorithm.name.str();
|
let name = algorithm.name.str();
|
||||||
let normalized_algorithm = if name.eq_ignore_ascii_case(ALG_AES_CBC) {
|
let normalized_algorithm = if name.eq_ignore_ascii_case(ALG_AES_CBC) {
|
||||||
let params = value_from_js_object!(AesCbcParams, cx, value);
|
let params = boxed_value_from_js_object::<AesCbcParams>(cx, value.handle())?;
|
||||||
EncryptionAlgorithm::AesCbc(params.into())
|
EncryptionAlgorithm::AesCbc(params.into())
|
||||||
} else if name.eq_ignore_ascii_case(ALG_AES_CTR) {
|
} else if name.eq_ignore_ascii_case(ALG_AES_CTR) {
|
||||||
let params = value_from_js_object!(AesCtrParams, cx, value);
|
let params = boxed_value_from_js_object::<AesCtrParams>(cx, value.handle())?;
|
||||||
EncryptionAlgorithm::AesCtr(params.into())
|
EncryptionAlgorithm::AesCtr(params.into())
|
||||||
} else if name.eq_ignore_ascii_case(ALG_AES_GCM) {
|
} else if name.eq_ignore_ascii_case(ALG_AES_GCM) {
|
||||||
let params = value_from_js_object!(AesGcmParams, cx, value);
|
let params = boxed_value_from_js_object::<AesGcmParams>(cx, value.handle())?;
|
||||||
EncryptionAlgorithm::AesGcm(params.into())
|
EncryptionAlgorithm::AesGcm(params.into())
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::NotSupported);
|
return Err(Error::NotSupported);
|
||||||
|
@ -1576,7 +1664,7 @@ fn normalize_algorithm_for_sign_or_verify(
|
||||||
let name = match algorithm {
|
let name = match algorithm {
|
||||||
AlgorithmIdentifier::Object(obj) => {
|
AlgorithmIdentifier::Object(obj) => {
|
||||||
rooted!(in(*cx) let value = ObjectValue(obj.get()));
|
rooted!(in(*cx) let value = ObjectValue(obj.get()));
|
||||||
let algorithm = value_from_js_object!(Algorithm, cx, value);
|
let algorithm = value_from_js_object::<Algorithm>(cx, value.handle())?;
|
||||||
|
|
||||||
algorithm.name.str().to_uppercase()
|
algorithm.name.str().to_uppercase()
|
||||||
},
|
},
|
||||||
|
@ -1602,7 +1690,7 @@ fn normalize_algorithm_for_generate_key(
|
||||||
};
|
};
|
||||||
|
|
||||||
rooted!(in(*cx) let value = ObjectValue(obj.get()));
|
rooted!(in(*cx) let value = ObjectValue(obj.get()));
|
||||||
let algorithm = value_from_js_object!(Algorithm, cx, value);
|
let algorithm = value_from_js_object::<Algorithm>(cx, value.handle())?;
|
||||||
|
|
||||||
let name = algorithm.name.str();
|
let name = algorithm.name.str();
|
||||||
let normalized_algorithm = if name.eq_ignore_ascii_case(ALG_AES_CBC) ||
|
let normalized_algorithm = if name.eq_ignore_ascii_case(ALG_AES_CBC) ||
|
||||||
|
@ -1610,10 +1698,10 @@ fn normalize_algorithm_for_generate_key(
|
||||||
name.eq_ignore_ascii_case(ALG_AES_KW) ||
|
name.eq_ignore_ascii_case(ALG_AES_KW) ||
|
||||||
name.eq_ignore_ascii_case(ALG_AES_GCM)
|
name.eq_ignore_ascii_case(ALG_AES_GCM)
|
||||||
{
|
{
|
||||||
let params = value_from_js_object!(AesKeyGenParams, cx, value);
|
let params = value_from_js_object::<AesKeyGenParams>(cx, value.handle())?;
|
||||||
KeyGenerationAlgorithm::Aes(params.into())
|
KeyGenerationAlgorithm::Aes(params.into())
|
||||||
} else if name.eq_ignore_ascii_case(ALG_HMAC) {
|
} else if name.eq_ignore_ascii_case(ALG_HMAC) {
|
||||||
let params = value_from_js_object!(HmacKeyGenParams, cx, value);
|
let params = boxed_value_from_js_object::<HmacKeyGenParams>(cx, value.handle())?;
|
||||||
let subtle_params = SubtleHmacKeyGenParams::new(cx, params)?;
|
let subtle_params = SubtleHmacKeyGenParams::new(cx, params)?;
|
||||||
KeyGenerationAlgorithm::Hmac(subtle_params)
|
KeyGenerationAlgorithm::Hmac(subtle_params)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1631,7 +1719,7 @@ fn normalize_algorithm_for_key_wrap(
|
||||||
let name = match algorithm {
|
let name = match algorithm {
|
||||||
AlgorithmIdentifier::Object(obj) => {
|
AlgorithmIdentifier::Object(obj) => {
|
||||||
rooted!(in(*cx) let value = ObjectValue(obj.get()));
|
rooted!(in(*cx) let value = ObjectValue(obj.get()));
|
||||||
let algorithm = value_from_js_object!(Algorithm, cx, value);
|
let algorithm = value_from_js_object::<Algorithm>(cx, value.handle())?;
|
||||||
|
|
||||||
algorithm.name.str().to_uppercase()
|
algorithm.name.str().to_uppercase()
|
||||||
},
|
},
|
||||||
|
@ -1645,21 +1733,27 @@ fn normalize_algorithm_for_key_wrap(
|
||||||
return Err(Error::Syntax(None));
|
return Err(Error::Syntax(None));
|
||||||
};
|
};
|
||||||
rooted!(in(*cx) let value = ObjectValue(obj.get()));
|
rooted!(in(*cx) let value = ObjectValue(obj.get()));
|
||||||
KeyWrapAlgorithm::AesCbc(value_from_js_object!(AesCbcParams, cx, value).into())
|
KeyWrapAlgorithm::AesCbc(
|
||||||
|
boxed_value_from_js_object::<AesCbcParams>(cx, value.handle())?.into(),
|
||||||
|
)
|
||||||
},
|
},
|
||||||
ALG_AES_CTR => {
|
ALG_AES_CTR => {
|
||||||
let AlgorithmIdentifier::Object(obj) = algorithm else {
|
let AlgorithmIdentifier::Object(obj) = algorithm else {
|
||||||
return Err(Error::Syntax(None));
|
return Err(Error::Syntax(None));
|
||||||
};
|
};
|
||||||
rooted!(in(*cx) let value = ObjectValue(obj.get()));
|
rooted!(in(*cx) let value = ObjectValue(obj.get()));
|
||||||
KeyWrapAlgorithm::AesCtr(value_from_js_object!(AesCtrParams, cx, value).into())
|
KeyWrapAlgorithm::AesCtr(
|
||||||
|
boxed_value_from_js_object::<AesCtrParams>(cx, value.handle())?.into(),
|
||||||
|
)
|
||||||
},
|
},
|
||||||
ALG_AES_GCM => {
|
ALG_AES_GCM => {
|
||||||
let AlgorithmIdentifier::Object(obj) = algorithm else {
|
let AlgorithmIdentifier::Object(obj) = algorithm else {
|
||||||
return Err(Error::Syntax(None));
|
return Err(Error::Syntax(None));
|
||||||
};
|
};
|
||||||
rooted!(in(*cx) let value = ObjectValue(obj.get()));
|
rooted!(in(*cx) let value = ObjectValue(obj.get()));
|
||||||
KeyWrapAlgorithm::AesGcm(value_from_js_object!(AesGcmParams, cx, value).into())
|
KeyWrapAlgorithm::AesGcm(
|
||||||
|
boxed_value_from_js_object::<AesGcmParams>(cx, value.handle())?.into(),
|
||||||
|
)
|
||||||
},
|
},
|
||||||
_ => return Err(Error::NotSupported),
|
_ => return Err(Error::NotSupported),
|
||||||
};
|
};
|
||||||
|
@ -3005,7 +3099,7 @@ fn sign_hmac(cx: JSContext, key: &CryptoKey, data: &[u8]) -> Result<impl AsRef<[
|
||||||
// using the key represented by [[handle]] internal slot of key, the hash function identified by the hash attribute
|
// using the key represented by [[handle]] internal slot of key, the hash function identified by the hash attribute
|
||||||
// of the [[algorithm]] internal slot of key and message as the input data text.
|
// of the [[algorithm]] internal slot of key and message as the input data text.
|
||||||
rooted!(in(*cx) let mut algorithm_slot = ObjectValue(key.Algorithm(cx).as_ptr()));
|
rooted!(in(*cx) let mut algorithm_slot = ObjectValue(key.Algorithm(cx).as_ptr()));
|
||||||
let params = value_from_js_object!(HmacKeyAlgorithm, cx, algorithm_slot);
|
let params = value_from_js_object::<HmacKeyAlgorithm>(cx, algorithm_slot.handle())?;
|
||||||
|
|
||||||
let hash_algorithm = match params.hash.name.str() {
|
let hash_algorithm = match params.hash.name.str() {
|
||||||
ALG_SHA1 => hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY,
|
ALG_SHA1 => hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue