mirror of
https://github.com/denoland/deno.git
synced 2024-12-01 16:51:13 -05:00
Merge branch 'main' into support_create_connection
This commit is contained in:
commit
f62bb6ff1b
199 changed files with 2716 additions and 1428 deletions
57
Cargo.lock
generated
57
Cargo.lock
generated
|
@ -769,7 +769,7 @@ dependencies = [
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"hyper 1.4.1",
|
"hyper 1.4.1",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"nix 0.26.2",
|
"nix",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"os_pipe",
|
"os_pipe",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
|
@ -1223,7 +1223,7 @@ dependencies = [
|
||||||
"memmem",
|
"memmem",
|
||||||
"monch",
|
"monch",
|
||||||
"napi_sym",
|
"napi_sym",
|
||||||
"nix 0.26.2",
|
"nix",
|
||||||
"node_resolver",
|
"node_resolver",
|
||||||
"notify",
|
"notify",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
@ -1423,9 +1423,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deno_core"
|
name = "deno_core"
|
||||||
version = "0.314.1"
|
version = "0.314.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1fcd11ab87426c611b7170138a768dad7170c8fb66d8095b773d25e58fd254ea"
|
checksum = "83138917579676069b423c3eb9be3c1e579f60dc022d85f6ded4c792456255ff"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bincode",
|
"bincode",
|
||||||
|
@ -1438,7 +1438,7 @@ dependencies = [
|
||||||
"deno_unsync",
|
"deno_unsync",
|
||||||
"futures",
|
"futures",
|
||||||
"libc",
|
"libc",
|
||||||
"memoffset 0.9.1",
|
"memoffset",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pin-project",
|
"pin-project",
|
||||||
|
@ -1503,6 +1503,8 @@ dependencies = [
|
||||||
"sha2",
|
"sha2",
|
||||||
"signature",
|
"signature",
|
||||||
"spki",
|
"spki",
|
||||||
|
"thiserror",
|
||||||
|
"tokio",
|
||||||
"uuid",
|
"uuid",
|
||||||
"x25519-dalek",
|
"x25519-dalek",
|
||||||
]
|
]
|
||||||
|
@ -1555,6 +1557,7 @@ dependencies = [
|
||||||
"rustls-webpki",
|
"rustls-webpki",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-rustls",
|
"tokio-rustls",
|
||||||
"tokio-socks",
|
"tokio-socks",
|
||||||
|
@ -1596,10 +1599,11 @@ dependencies = [
|
||||||
"filetime",
|
"filetime",
|
||||||
"junction",
|
"junction",
|
||||||
"libc",
|
"libc",
|
||||||
"nix 0.26.2",
|
"nix",
|
||||||
"rand",
|
"rand",
|
||||||
"rayon",
|
"rayon",
|
||||||
"serde",
|
"serde",
|
||||||
|
"thiserror",
|
||||||
"winapi",
|
"winapi",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
@ -1916,9 +1920,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deno_ops"
|
name = "deno_ops"
|
||||||
version = "0.190.0"
|
version = "0.190.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a48a3e06cace18a2c49e148da067678c6af80e70757a8c3991301397cf6b9919"
|
checksum = "26f46d4e4f52f26c882b74a9b58810ea75252b807cf0966166ec333077cdfd85"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro-rules",
|
"proc-macro-rules",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
@ -2031,7 +2035,7 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"netif",
|
"netif",
|
||||||
"nix 0.26.2",
|
"nix",
|
||||||
"node_resolver",
|
"node_resolver",
|
||||||
"notify",
|
"notify",
|
||||||
"ntapi",
|
"ntapi",
|
||||||
|
@ -2193,6 +2197,7 @@ dependencies = [
|
||||||
"deno_core",
|
"deno_core",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
"serde",
|
"serde",
|
||||||
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"wgpu-core",
|
"wgpu-core",
|
||||||
"wgpu-types",
|
"wgpu-types",
|
||||||
|
@ -2224,6 +2229,7 @@ dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustls-tokio-stream",
|
"rustls-tokio-stream",
|
||||||
"serde",
|
"serde",
|
||||||
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -4391,15 +4397,6 @@ version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a64a92489e2744ce060c349162be1c5f33c6969234104dbd99ddb5feb08b8c15"
|
checksum = "a64a92489e2744ce060c349162be1c5f33c6969234104dbd99ddb5feb08b8c15"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memoffset"
|
|
||||||
version = "0.7.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memoffset"
|
name = "memoffset"
|
||||||
version = "0.9.1"
|
version = "0.9.1"
|
||||||
|
@ -4557,20 +4554,6 @@ dependencies = [
|
||||||
"smallvec",
|
"smallvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nix"
|
|
||||||
version = "0.26.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"memoffset 0.7.1",
|
|
||||||
"pin-utils",
|
|
||||||
"static_assertions",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nix"
|
name = "nix"
|
||||||
version = "0.27.1"
|
version = "0.27.1"
|
||||||
|
@ -5770,7 +5753,7 @@ checksum = "32a58fa8a7ccff2aec4f39cc45bf5f985cec7125ab271cf681c279fd00192b49"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"countme",
|
"countme",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
"memoffset 0.9.1",
|
"memoffset",
|
||||||
"rustc-hash 1.1.0",
|
"rustc-hash 1.1.0",
|
||||||
"text-size",
|
"text-size",
|
||||||
]
|
]
|
||||||
|
@ -5978,7 +5961,7 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"memchr",
|
"memchr",
|
||||||
"nix 0.27.1",
|
"nix",
|
||||||
"radix_trie",
|
"radix_trie",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
"unicode-width",
|
"unicode-width",
|
||||||
|
@ -6215,9 +6198,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_v8"
|
name = "serde_v8"
|
||||||
version = "0.223.0"
|
version = "0.223.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c127bb9f2024433d06789b242477c808fd7f7dc4c3278576dd5bc99c4e5c75ff"
|
checksum = "9cf3d859dda87ee96423c01244f10af864fa6d6a9fcdc2b77e0595078ea0ea11"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -7181,7 +7164,7 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"lsp-types",
|
"lsp-types",
|
||||||
"monch",
|
"monch",
|
||||||
"nix 0.26.2",
|
"nix",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"os_pipe",
|
"os_pipe",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
|
|
|
@ -46,7 +46,7 @@ repository = "https://github.com/denoland/deno"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
deno_ast = { version = "=0.42.2", features = ["transpiling"] }
|
deno_ast = { version = "=0.42.2", features = ["transpiling"] }
|
||||||
deno_core = { version = "0.314.1" }
|
deno_core = { version = "0.314.2" }
|
||||||
|
|
||||||
deno_bench_util = { version = "0.167.0", path = "./bench_util" }
|
deno_bench_util = { version = "0.167.0", path = "./bench_util" }
|
||||||
deno_lockfile = "=0.23.1"
|
deno_lockfile = "=0.23.1"
|
||||||
|
@ -221,7 +221,7 @@ quote = "1"
|
||||||
syn = { version = "2", features = ["full", "extra-traits"] }
|
syn = { version = "2", features = ["full", "extra-traits"] }
|
||||||
|
|
||||||
# unix
|
# unix
|
||||||
nix = "=0.26.2"
|
nix = "=0.27.1"
|
||||||
|
|
||||||
# windows deps
|
# windows deps
|
||||||
junction = "=0.2.0"
|
junction = "=0.2.0"
|
||||||
|
|
|
@ -1178,7 +1178,7 @@ static DENO_HELP: &str = cstr!(
|
||||||
|
|
||||||
<y>Dependency management:</>
|
<y>Dependency management:</>
|
||||||
<g>add</> Add dependencies
|
<g>add</> Add dependencies
|
||||||
<p(245)>deno add @std/assert | deno add npm:express</>
|
<p(245)>deno add jsr:@std/assert | deno add npm:express</>
|
||||||
<g>install</> Install script as an executable
|
<g>install</> Install script as an executable
|
||||||
<g>uninstall</> Uninstall a script previously installed with deno install
|
<g>uninstall</> Uninstall a script previously installed with deno install
|
||||||
<g>remove</> Remove dependencies from the configuration file
|
<g>remove</> Remove dependencies from the configuration file
|
||||||
|
|
15
cli/npm/managed/cache/registry_info.rs
vendored
15
cli/npm/managed/cache/registry_info.rs
vendored
|
@ -242,6 +242,14 @@ impl RegistryInfoDownloader {
|
||||||
|
|
||||||
fn get_package_url(&self, name: &str) -> Url {
|
fn get_package_url(&self, name: &str) -> Url {
|
||||||
let registry_url = self.npmrc.get_registry_url(name);
|
let registry_url = self.npmrc.get_registry_url(name);
|
||||||
|
// The '/' character in scoped package names "@scope/name" must be
|
||||||
|
// encoded for older third party registries. Newer registries and
|
||||||
|
// npm itself support both ways
|
||||||
|
// - encoded: https://registry.npmjs.org/@rollup%2fplugin-json
|
||||||
|
// - non-ecoded: https://registry.npmjs.org/@rollup/plugin-json
|
||||||
|
// To support as many third party registries as possible we'll
|
||||||
|
// always encode the '/' character.
|
||||||
|
|
||||||
// list of all characters used in npm packages:
|
// list of all characters used in npm packages:
|
||||||
// !, ', (, ), *, -, ., /, [0-9], @, [A-Za-z], _, ~
|
// !, ', (, ), *, -, ., /, [0-9], @, [A-Za-z], _, ~
|
||||||
const ASCII_SET: percent_encoding::AsciiSet =
|
const ASCII_SET: percent_encoding::AsciiSet =
|
||||||
|
@ -253,11 +261,14 @@ impl RegistryInfoDownloader {
|
||||||
.remove(b'*')
|
.remove(b'*')
|
||||||
.remove(b'-')
|
.remove(b'-')
|
||||||
.remove(b'.')
|
.remove(b'.')
|
||||||
.remove(b'/')
|
|
||||||
.remove(b'@')
|
.remove(b'@')
|
||||||
.remove(b'_')
|
.remove(b'_')
|
||||||
.remove(b'~');
|
.remove(b'~');
|
||||||
let name = percent_encoding::utf8_percent_encode(name, &ASCII_SET);
|
let name = percent_encoding::utf8_percent_encode(name, &ASCII_SET);
|
||||||
registry_url.join(&name.to_string()).unwrap()
|
registry_url
|
||||||
|
// Ensure that scoped package name percent encoding is lower cased
|
||||||
|
// to match npm.
|
||||||
|
.join(&name.to_string().replace("%2F", "%2f"))
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ use deno_core::anyhow::bail;
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_core::resolve_url_or_path;
|
use deno_core::resolve_url_or_path;
|
||||||
use deno_core::serde_json;
|
use deno_core::serde_json;
|
||||||
|
use deno_core::url;
|
||||||
use deno_graph::Dependency;
|
use deno_graph::Dependency;
|
||||||
use deno_graph::GraphKind;
|
use deno_graph::GraphKind;
|
||||||
use deno_graph::Module;
|
use deno_graph::Module;
|
||||||
|
@ -51,18 +52,20 @@ pub async fn info(
|
||||||
let npmrc = cli_options.npmrc();
|
let npmrc = cli_options.npmrc();
|
||||||
let resolver = factory.workspace_resolver().await?;
|
let resolver = factory.workspace_resolver().await?;
|
||||||
|
|
||||||
let maybe_import_specifier =
|
let cwd_url =
|
||||||
if let Some(import_map) = resolver.maybe_import_map() {
|
url::Url::from_directory_path(cli_options.initial_cwd()).unwrap();
|
||||||
if let Ok(imports_specifier) =
|
|
||||||
import_map.resolve(&specifier, import_map.base_url())
|
let maybe_import_specifier = if let Some(import_map) =
|
||||||
{
|
resolver.maybe_import_map()
|
||||||
Some(imports_specifier)
|
{
|
||||||
} else {
|
if let Ok(imports_specifier) = import_map.resolve(&specifier, &cwd_url) {
|
||||||
None
|
Some(imports_specifier)
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let specifier = match maybe_import_specifier {
|
let specifier = match maybe_import_specifier {
|
||||||
Some(specifier) => specifier,
|
Some(specifier) => specifier,
|
||||||
|
|
|
@ -41,5 +41,7 @@ sha1.workspace = true
|
||||||
sha2.workspace = true
|
sha2.workspace = true
|
||||||
signature.workspace = true
|
signature.workspace = true
|
||||||
spki.workspace = true
|
spki.workspace = true
|
||||||
|
thiserror.workspace = true
|
||||||
|
tokio.workspace = true
|
||||||
uuid.workspace = true
|
uuid.workspace = true
|
||||||
x25519-dalek = "2.0.0"
|
x25519-dalek = "2.0.0"
|
||||||
|
|
|
@ -16,9 +16,6 @@ use ctr::cipher::StreamCipher;
|
||||||
use ctr::Ctr128BE;
|
use ctr::Ctr128BE;
|
||||||
use ctr::Ctr32BE;
|
use ctr::Ctr32BE;
|
||||||
use ctr::Ctr64BE;
|
use ctr::Ctr64BE;
|
||||||
use deno_core::error::custom_error;
|
|
||||||
use deno_core::error::type_error;
|
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::op2;
|
use deno_core::op2;
|
||||||
use deno_core::unsync::spawn_blocking;
|
use deno_core::unsync::spawn_blocking;
|
||||||
use deno_core::JsBuffer;
|
use deno_core::JsBuffer;
|
||||||
|
@ -73,12 +70,36 @@ pub enum DecryptAlgorithm {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum DecryptError {
|
||||||
|
#[error(transparent)]
|
||||||
|
General(#[from] SharedError),
|
||||||
|
#[error(transparent)]
|
||||||
|
Pkcs1(#[from] rsa::pkcs1::Error),
|
||||||
|
#[error("Decryption failed")]
|
||||||
|
Failed,
|
||||||
|
#[error("invalid length")]
|
||||||
|
InvalidLength,
|
||||||
|
#[error("invalid counter length. Currently supported 32/64/128 bits")]
|
||||||
|
InvalidCounterLength,
|
||||||
|
#[error("tag length not equal to 128")]
|
||||||
|
InvalidTagLength,
|
||||||
|
#[error("invalid key or iv")]
|
||||||
|
InvalidKeyOrIv,
|
||||||
|
#[error("tried to decrypt too much data")]
|
||||||
|
TooMuchData,
|
||||||
|
#[error("iv length not equal to 12 or 16")]
|
||||||
|
InvalidIvLength,
|
||||||
|
#[error("{0}")]
|
||||||
|
Rsa(rsa::Error),
|
||||||
|
}
|
||||||
|
|
||||||
#[op2(async)]
|
#[op2(async)]
|
||||||
#[serde]
|
#[serde]
|
||||||
pub async fn op_crypto_decrypt(
|
pub async fn op_crypto_decrypt(
|
||||||
#[serde] opts: DecryptOptions,
|
#[serde] opts: DecryptOptions,
|
||||||
#[buffer] data: JsBuffer,
|
#[buffer] data: JsBuffer,
|
||||||
) -> Result<ToJsBuffer, AnyError> {
|
) -> Result<ToJsBuffer, DecryptError> {
|
||||||
let key = opts.key;
|
let key = opts.key;
|
||||||
let fun = move || match opts.algorithm {
|
let fun = move || match opts.algorithm {
|
||||||
DecryptAlgorithm::RsaOaep { hash, label } => {
|
DecryptAlgorithm::RsaOaep { hash, label } => {
|
||||||
|
@ -108,7 +129,7 @@ fn decrypt_rsa_oaep(
|
||||||
hash: ShaHash,
|
hash: ShaHash,
|
||||||
label: Vec<u8>,
|
label: Vec<u8>,
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
) -> Result<Vec<u8>, deno_core::anyhow::Error> {
|
) -> Result<Vec<u8>, DecryptError> {
|
||||||
let key = key.as_rsa_private_key()?;
|
let key = key.as_rsa_private_key()?;
|
||||||
|
|
||||||
let private_key = rsa::RsaPrivateKey::from_pkcs1_der(key)?;
|
let private_key = rsa::RsaPrivateKey::from_pkcs1_der(key)?;
|
||||||
|
@ -139,7 +160,7 @@ fn decrypt_rsa_oaep(
|
||||||
|
|
||||||
private_key
|
private_key
|
||||||
.decrypt(padding, data)
|
.decrypt(padding, data)
|
||||||
.map_err(|e| custom_error("DOMExceptionOperationError", e.to_string()))
|
.map_err(DecryptError::Rsa)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decrypt_aes_cbc(
|
fn decrypt_aes_cbc(
|
||||||
|
@ -147,7 +168,7 @@ fn decrypt_aes_cbc(
|
||||||
length: usize,
|
length: usize,
|
||||||
iv: Vec<u8>,
|
iv: Vec<u8>,
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
) -> Result<Vec<u8>, deno_core::anyhow::Error> {
|
) -> Result<Vec<u8>, DecryptError> {
|
||||||
let key = key.as_secret_key()?;
|
let key = key.as_secret_key()?;
|
||||||
|
|
||||||
// 2.
|
// 2.
|
||||||
|
@ -155,53 +176,32 @@ fn decrypt_aes_cbc(
|
||||||
128 => {
|
128 => {
|
||||||
// Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315
|
// Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315
|
||||||
type Aes128CbcDec = cbc::Decryptor<aes::Aes128>;
|
type Aes128CbcDec = cbc::Decryptor<aes::Aes128>;
|
||||||
let cipher = Aes128CbcDec::new_from_slices(key, &iv).map_err(|_| {
|
let cipher = Aes128CbcDec::new_from_slices(key, &iv)
|
||||||
custom_error(
|
.map_err(|_| DecryptError::InvalidKeyOrIv)?;
|
||||||
"DOMExceptionOperationError",
|
|
||||||
"Invalid key or iv".to_string(),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
cipher.decrypt_padded_vec_mut::<Pkcs7>(data).map_err(|_| {
|
cipher
|
||||||
custom_error(
|
.decrypt_padded_vec_mut::<Pkcs7>(data)
|
||||||
"DOMExceptionOperationError",
|
.map_err(|_| DecryptError::Failed)?
|
||||||
"Decryption failed".to_string(),
|
|
||||||
)
|
|
||||||
})?
|
|
||||||
}
|
}
|
||||||
192 => {
|
192 => {
|
||||||
// Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315
|
// Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315
|
||||||
type Aes192CbcDec = cbc::Decryptor<aes::Aes192>;
|
type Aes192CbcDec = cbc::Decryptor<aes::Aes192>;
|
||||||
let cipher = Aes192CbcDec::new_from_slices(key, &iv).map_err(|_| {
|
let cipher = Aes192CbcDec::new_from_slices(key, &iv)
|
||||||
custom_error(
|
.map_err(|_| DecryptError::InvalidKeyOrIv)?;
|
||||||
"DOMExceptionOperationError",
|
|
||||||
"Invalid key or iv".to_string(),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
cipher.decrypt_padded_vec_mut::<Pkcs7>(data).map_err(|_| {
|
cipher
|
||||||
custom_error(
|
.decrypt_padded_vec_mut::<Pkcs7>(data)
|
||||||
"DOMExceptionOperationError",
|
.map_err(|_| DecryptError::Failed)?
|
||||||
"Decryption failed".to_string(),
|
|
||||||
)
|
|
||||||
})?
|
|
||||||
}
|
}
|
||||||
256 => {
|
256 => {
|
||||||
// Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315
|
// Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315
|
||||||
type Aes256CbcDec = cbc::Decryptor<aes::Aes256>;
|
type Aes256CbcDec = cbc::Decryptor<aes::Aes256>;
|
||||||
let cipher = Aes256CbcDec::new_from_slices(key, &iv).map_err(|_| {
|
let cipher = Aes256CbcDec::new_from_slices(key, &iv)
|
||||||
custom_error(
|
.map_err(|_| DecryptError::InvalidKeyOrIv)?;
|
||||||
"DOMExceptionOperationError",
|
|
||||||
"Invalid key or iv".to_string(),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
cipher.decrypt_padded_vec_mut::<Pkcs7>(data).map_err(|_| {
|
cipher
|
||||||
custom_error(
|
.decrypt_padded_vec_mut::<Pkcs7>(data)
|
||||||
"DOMExceptionOperationError",
|
.map_err(|_| DecryptError::Failed)?
|
||||||
"Decryption failed".to_string(),
|
|
||||||
)
|
|
||||||
})?
|
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
@ -214,7 +214,7 @@ fn decrypt_aes_ctr_gen<B>(
|
||||||
key: &[u8],
|
key: &[u8],
|
||||||
counter: &[u8],
|
counter: &[u8],
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
) -> Result<Vec<u8>, AnyError>
|
) -> Result<Vec<u8>, DecryptError>
|
||||||
where
|
where
|
||||||
B: KeyIvInit + StreamCipher,
|
B: KeyIvInit + StreamCipher,
|
||||||
{
|
{
|
||||||
|
@ -223,7 +223,7 @@ where
|
||||||
let mut plaintext = data.to_vec();
|
let mut plaintext = data.to_vec();
|
||||||
cipher
|
cipher
|
||||||
.try_apply_keystream(&mut plaintext)
|
.try_apply_keystream(&mut plaintext)
|
||||||
.map_err(|_| operation_error("tried to decrypt too much data"))?;
|
.map_err(|_| DecryptError::TooMuchData)?;
|
||||||
|
|
||||||
Ok(plaintext)
|
Ok(plaintext)
|
||||||
}
|
}
|
||||||
|
@ -235,12 +235,12 @@ fn decrypt_aes_gcm_gen<N: ArrayLength<u8>>(
|
||||||
length: usize,
|
length: usize,
|
||||||
additional_data: Vec<u8>,
|
additional_data: Vec<u8>,
|
||||||
plaintext: &mut [u8],
|
plaintext: &mut [u8],
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), DecryptError> {
|
||||||
let nonce = Nonce::from_slice(nonce);
|
let nonce = Nonce::from_slice(nonce);
|
||||||
match length {
|
match length {
|
||||||
128 => {
|
128 => {
|
||||||
let cipher = aes_gcm::AesGcm::<Aes128, N>::new_from_slice(key)
|
let cipher = aes_gcm::AesGcm::<Aes128, N>::new_from_slice(key)
|
||||||
.map_err(|_| operation_error("Decryption failed"))?;
|
.map_err(|_| DecryptError::Failed)?;
|
||||||
cipher
|
cipher
|
||||||
.decrypt_in_place_detached(
|
.decrypt_in_place_detached(
|
||||||
nonce,
|
nonce,
|
||||||
|
@ -248,11 +248,11 @@ fn decrypt_aes_gcm_gen<N: ArrayLength<u8>>(
|
||||||
plaintext,
|
plaintext,
|
||||||
tag,
|
tag,
|
||||||
)
|
)
|
||||||
.map_err(|_| operation_error("Decryption failed"))?
|
.map_err(|_| DecryptError::Failed)?
|
||||||
}
|
}
|
||||||
192 => {
|
192 => {
|
||||||
let cipher = aes_gcm::AesGcm::<Aes192, N>::new_from_slice(key)
|
let cipher = aes_gcm::AesGcm::<Aes192, N>::new_from_slice(key)
|
||||||
.map_err(|_| operation_error("Decryption failed"))?;
|
.map_err(|_| DecryptError::Failed)?;
|
||||||
cipher
|
cipher
|
||||||
.decrypt_in_place_detached(
|
.decrypt_in_place_detached(
|
||||||
nonce,
|
nonce,
|
||||||
|
@ -260,11 +260,11 @@ fn decrypt_aes_gcm_gen<N: ArrayLength<u8>>(
|
||||||
plaintext,
|
plaintext,
|
||||||
tag,
|
tag,
|
||||||
)
|
)
|
||||||
.map_err(|_| operation_error("Decryption failed"))?
|
.map_err(|_| DecryptError::Failed)?
|
||||||
}
|
}
|
||||||
256 => {
|
256 => {
|
||||||
let cipher = aes_gcm::AesGcm::<Aes256, N>::new_from_slice(key)
|
let cipher = aes_gcm::AesGcm::<Aes256, N>::new_from_slice(key)
|
||||||
.map_err(|_| operation_error("Decryption failed"))?;
|
.map_err(|_| DecryptError::Failed)?;
|
||||||
cipher
|
cipher
|
||||||
.decrypt_in_place_detached(
|
.decrypt_in_place_detached(
|
||||||
nonce,
|
nonce,
|
||||||
|
@ -272,9 +272,9 @@ fn decrypt_aes_gcm_gen<N: ArrayLength<u8>>(
|
||||||
plaintext,
|
plaintext,
|
||||||
tag,
|
tag,
|
||||||
)
|
)
|
||||||
.map_err(|_| operation_error("Decryption failed"))?
|
.map_err(|_| DecryptError::Failed)?
|
||||||
}
|
}
|
||||||
_ => return Err(type_error("invalid length")),
|
_ => return Err(DecryptError::InvalidLength),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -286,7 +286,7 @@ fn decrypt_aes_ctr(
|
||||||
counter: &[u8],
|
counter: &[u8],
|
||||||
ctr_length: usize,
|
ctr_length: usize,
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
) -> Result<Vec<u8>, deno_core::anyhow::Error> {
|
) -> Result<Vec<u8>, DecryptError> {
|
||||||
let key = key.as_secret_key()?;
|
let key = key.as_secret_key()?;
|
||||||
|
|
||||||
match ctr_length {
|
match ctr_length {
|
||||||
|
@ -294,23 +294,21 @@ fn decrypt_aes_ctr(
|
||||||
128 => decrypt_aes_ctr_gen::<Ctr32BE<aes::Aes128>>(key, counter, data),
|
128 => decrypt_aes_ctr_gen::<Ctr32BE<aes::Aes128>>(key, counter, data),
|
||||||
192 => decrypt_aes_ctr_gen::<Ctr32BE<aes::Aes192>>(key, counter, data),
|
192 => decrypt_aes_ctr_gen::<Ctr32BE<aes::Aes192>>(key, counter, data),
|
||||||
256 => decrypt_aes_ctr_gen::<Ctr32BE<aes::Aes256>>(key, counter, data),
|
256 => decrypt_aes_ctr_gen::<Ctr32BE<aes::Aes256>>(key, counter, data),
|
||||||
_ => Err(type_error("invalid length")),
|
_ => Err(DecryptError::InvalidLength),
|
||||||
},
|
},
|
||||||
64 => match key_length {
|
64 => match key_length {
|
||||||
128 => decrypt_aes_ctr_gen::<Ctr64BE<aes::Aes128>>(key, counter, data),
|
128 => decrypt_aes_ctr_gen::<Ctr64BE<aes::Aes128>>(key, counter, data),
|
||||||
192 => decrypt_aes_ctr_gen::<Ctr64BE<aes::Aes192>>(key, counter, data),
|
192 => decrypt_aes_ctr_gen::<Ctr64BE<aes::Aes192>>(key, counter, data),
|
||||||
256 => decrypt_aes_ctr_gen::<Ctr64BE<aes::Aes256>>(key, counter, data),
|
256 => decrypt_aes_ctr_gen::<Ctr64BE<aes::Aes256>>(key, counter, data),
|
||||||
_ => Err(type_error("invalid length")),
|
_ => Err(DecryptError::InvalidLength),
|
||||||
},
|
},
|
||||||
128 => match key_length {
|
128 => match key_length {
|
||||||
128 => decrypt_aes_ctr_gen::<Ctr128BE<aes::Aes128>>(key, counter, data),
|
128 => decrypt_aes_ctr_gen::<Ctr128BE<aes::Aes128>>(key, counter, data),
|
||||||
192 => decrypt_aes_ctr_gen::<Ctr128BE<aes::Aes192>>(key, counter, data),
|
192 => decrypt_aes_ctr_gen::<Ctr128BE<aes::Aes192>>(key, counter, data),
|
||||||
256 => decrypt_aes_ctr_gen::<Ctr128BE<aes::Aes256>>(key, counter, data),
|
256 => decrypt_aes_ctr_gen::<Ctr128BE<aes::Aes256>>(key, counter, data),
|
||||||
_ => Err(type_error("invalid length")),
|
_ => Err(DecryptError::InvalidLength),
|
||||||
},
|
},
|
||||||
_ => Err(type_error(
|
_ => Err(DecryptError::InvalidCounterLength),
|
||||||
"invalid counter length. Currently supported 32/64/128 bits",
|
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,7 +319,7 @@ fn decrypt_aes_gcm(
|
||||||
iv: Vec<u8>,
|
iv: Vec<u8>,
|
||||||
additional_data: Option<Vec<u8>>,
|
additional_data: Option<Vec<u8>>,
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
) -> Result<Vec<u8>, AnyError> {
|
) -> Result<Vec<u8>, DecryptError> {
|
||||||
let key = key.as_secret_key()?;
|
let key = key.as_secret_key()?;
|
||||||
let additional_data = additional_data.unwrap_or_default();
|
let additional_data = additional_data.unwrap_or_default();
|
||||||
|
|
||||||
|
@ -330,7 +328,7 @@ fn decrypt_aes_gcm(
|
||||||
// Note that encryption won't fail, it instead truncates the tag
|
// Note that encryption won't fail, it instead truncates the tag
|
||||||
// to the specified tag length as specified in the spec.
|
// to the specified tag length as specified in the spec.
|
||||||
if tag_length != 128 {
|
if tag_length != 128 {
|
||||||
return Err(type_error("tag length not equal to 128"));
|
return Err(DecryptError::InvalidTagLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
let sep = data.len() - (tag_length / 8);
|
let sep = data.len() - (tag_length / 8);
|
||||||
|
@ -357,7 +355,7 @@ fn decrypt_aes_gcm(
|
||||||
additional_data,
|
additional_data,
|
||||||
&mut plaintext,
|
&mut plaintext,
|
||||||
)?,
|
)?,
|
||||||
_ => return Err(type_error("iv length not equal to 12 or 16")),
|
_ => return Err(DecryptError::InvalidIvLength),
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(plaintext)
|
Ok(plaintext)
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
use base64::prelude::BASE64_URL_SAFE_NO_PAD;
|
use base64::prelude::BASE64_URL_SAFE_NO_PAD;
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
use deno_core::error::custom_error;
|
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::op2;
|
use deno_core::op2;
|
||||||
use deno_core::ToJsBuffer;
|
use deno_core::ToJsBuffer;
|
||||||
use elliptic_curve::pkcs8::PrivateKeyInfo;
|
use elliptic_curve::pkcs8::PrivateKeyInfo;
|
||||||
|
@ -15,6 +13,16 @@ use spki::der::asn1::BitString;
|
||||||
use spki::der::Decode;
|
use spki::der::Decode;
|
||||||
use spki::der::Encode;
|
use spki::der::Encode;
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum Ed25519Error {
|
||||||
|
#[error("Failed to export key")]
|
||||||
|
FailedExport,
|
||||||
|
#[error(transparent)]
|
||||||
|
Der(#[from] rsa::pkcs1::der::Error),
|
||||||
|
#[error(transparent)]
|
||||||
|
KeyRejected(#[from] ring::error::KeyRejected),
|
||||||
|
}
|
||||||
|
|
||||||
#[op2(fast)]
|
#[op2(fast)]
|
||||||
pub fn op_crypto_generate_ed25519_keypair(
|
pub fn op_crypto_generate_ed25519_keypair(
|
||||||
#[buffer] pkey: &mut [u8],
|
#[buffer] pkey: &mut [u8],
|
||||||
|
@ -116,7 +124,7 @@ pub fn op_crypto_import_pkcs8_ed25519(
|
||||||
#[serde]
|
#[serde]
|
||||||
pub fn op_crypto_export_spki_ed25519(
|
pub fn op_crypto_export_spki_ed25519(
|
||||||
#[buffer] pubkey: &[u8],
|
#[buffer] pubkey: &[u8],
|
||||||
) -> Result<ToJsBuffer, AnyError> {
|
) -> Result<ToJsBuffer, Ed25519Error> {
|
||||||
let key_info = spki::SubjectPublicKeyInfo {
|
let key_info = spki::SubjectPublicKeyInfo {
|
||||||
algorithm: spki::AlgorithmIdentifierOwned {
|
algorithm: spki::AlgorithmIdentifierOwned {
|
||||||
// id-Ed25519
|
// id-Ed25519
|
||||||
|
@ -128,9 +136,7 @@ pub fn op_crypto_export_spki_ed25519(
|
||||||
Ok(
|
Ok(
|
||||||
key_info
|
key_info
|
||||||
.to_der()
|
.to_der()
|
||||||
.map_err(|_| {
|
.map_err(|_| Ed25519Error::FailedExport)?
|
||||||
custom_error("DOMExceptionOperationError", "Failed to export key")
|
|
||||||
})?
|
|
||||||
.into(),
|
.into(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -139,7 +145,7 @@ pub fn op_crypto_export_spki_ed25519(
|
||||||
#[serde]
|
#[serde]
|
||||||
pub fn op_crypto_export_pkcs8_ed25519(
|
pub fn op_crypto_export_pkcs8_ed25519(
|
||||||
#[buffer] pkey: &[u8],
|
#[buffer] pkey: &[u8],
|
||||||
) -> Result<ToJsBuffer, AnyError> {
|
) -> Result<ToJsBuffer, Ed25519Error> {
|
||||||
use rsa::pkcs1::der::Encode;
|
use rsa::pkcs1::der::Encode;
|
||||||
|
|
||||||
// This should probably use OneAsymmetricKey instead
|
// This should probably use OneAsymmetricKey instead
|
||||||
|
@ -164,7 +170,7 @@ pub fn op_crypto_export_pkcs8_ed25519(
|
||||||
#[string]
|
#[string]
|
||||||
pub fn op_crypto_jwk_x_ed25519(
|
pub fn op_crypto_jwk_x_ed25519(
|
||||||
#[buffer] pkey: &[u8],
|
#[buffer] pkey: &[u8],
|
||||||
) -> Result<String, AnyError> {
|
) -> Result<String, Ed25519Error> {
|
||||||
let pair = Ed25519KeyPair::from_seed_unchecked(pkey)?;
|
let pair = Ed25519KeyPair::from_seed_unchecked(pkey)?;
|
||||||
Ok(BASE64_URL_SAFE_NO_PAD.encode(pair.public_key().as_ref()))
|
Ok(BASE64_URL_SAFE_NO_PAD.encode(pair.public_key().as_ref()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,6 @@ use aes_gcm::Nonce;
|
||||||
use ctr::Ctr128BE;
|
use ctr::Ctr128BE;
|
||||||
use ctr::Ctr32BE;
|
use ctr::Ctr32BE;
|
||||||
use ctr::Ctr64BE;
|
use ctr::Ctr64BE;
|
||||||
use deno_core::error::type_error;
|
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::op2;
|
use deno_core::op2;
|
||||||
use deno_core::unsync::spawn_blocking;
|
use deno_core::unsync::spawn_blocking;
|
||||||
use deno_core::JsBuffer;
|
use deno_core::JsBuffer;
|
||||||
|
@ -73,12 +71,30 @@ pub enum EncryptAlgorithm {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum EncryptError {
|
||||||
|
#[error(transparent)]
|
||||||
|
General(#[from] SharedError),
|
||||||
|
#[error("invalid length")]
|
||||||
|
InvalidLength,
|
||||||
|
#[error("invalid key or iv")]
|
||||||
|
InvalidKeyOrIv,
|
||||||
|
#[error("iv length not equal to 12 or 16")]
|
||||||
|
InvalidIvLength,
|
||||||
|
#[error("invalid counter length. Currently supported 32/64/128 bits")]
|
||||||
|
InvalidCounterLength,
|
||||||
|
#[error("tried to encrypt too much data")]
|
||||||
|
TooMuchData,
|
||||||
|
#[error("Encryption failed")]
|
||||||
|
Failed,
|
||||||
|
}
|
||||||
|
|
||||||
#[op2(async)]
|
#[op2(async)]
|
||||||
#[serde]
|
#[serde]
|
||||||
pub async fn op_crypto_encrypt(
|
pub async fn op_crypto_encrypt(
|
||||||
#[serde] opts: EncryptOptions,
|
#[serde] opts: EncryptOptions,
|
||||||
#[buffer] data: JsBuffer,
|
#[buffer] data: JsBuffer,
|
||||||
) -> Result<ToJsBuffer, AnyError> {
|
) -> Result<ToJsBuffer, EncryptError> {
|
||||||
let key = opts.key;
|
let key = opts.key;
|
||||||
let fun = move || match opts.algorithm {
|
let fun = move || match opts.algorithm {
|
||||||
EncryptAlgorithm::RsaOaep { hash, label } => {
|
EncryptAlgorithm::RsaOaep { hash, label } => {
|
||||||
|
@ -108,12 +124,12 @@ fn encrypt_rsa_oaep(
|
||||||
hash: ShaHash,
|
hash: ShaHash,
|
||||||
label: Vec<u8>,
|
label: Vec<u8>,
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
) -> Result<Vec<u8>, AnyError> {
|
) -> Result<Vec<u8>, EncryptError> {
|
||||||
let label = String::from_utf8_lossy(&label).to_string();
|
let label = String::from_utf8_lossy(&label).to_string();
|
||||||
|
|
||||||
let public_key = key.as_rsa_public_key()?;
|
let public_key = key.as_rsa_public_key()?;
|
||||||
let public_key = rsa::RsaPublicKey::from_pkcs1_der(&public_key)
|
let public_key = rsa::RsaPublicKey::from_pkcs1_der(&public_key)
|
||||||
.map_err(|_| operation_error("failed to decode public key"))?;
|
.map_err(|_| SharedError::FailedDecodePublicKey)?;
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
let padding = match hash {
|
let padding = match hash {
|
||||||
ShaHash::Sha1 => rsa::Oaep {
|
ShaHash::Sha1 => rsa::Oaep {
|
||||||
|
@ -139,7 +155,7 @@ fn encrypt_rsa_oaep(
|
||||||
};
|
};
|
||||||
let encrypted = public_key
|
let encrypted = public_key
|
||||||
.encrypt(&mut rng, padding, data)
|
.encrypt(&mut rng, padding, data)
|
||||||
.map_err(|_| operation_error("Encryption failed"))?;
|
.map_err(|_| EncryptError::Failed)?;
|
||||||
Ok(encrypted)
|
Ok(encrypted)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +164,7 @@ fn encrypt_aes_cbc(
|
||||||
length: usize,
|
length: usize,
|
||||||
iv: Vec<u8>,
|
iv: Vec<u8>,
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
) -> Result<Vec<u8>, AnyError> {
|
) -> Result<Vec<u8>, EncryptError> {
|
||||||
let key = key.as_secret_key()?;
|
let key = key.as_secret_key()?;
|
||||||
let ciphertext = match length {
|
let ciphertext = match length {
|
||||||
128 => {
|
128 => {
|
||||||
|
@ -156,7 +172,7 @@ fn encrypt_aes_cbc(
|
||||||
type Aes128CbcEnc = cbc::Encryptor<aes::Aes128>;
|
type Aes128CbcEnc = cbc::Encryptor<aes::Aes128>;
|
||||||
|
|
||||||
let cipher = Aes128CbcEnc::new_from_slices(key, &iv)
|
let cipher = Aes128CbcEnc::new_from_slices(key, &iv)
|
||||||
.map_err(|_| operation_error("invalid key or iv".to_string()))?;
|
.map_err(|_| EncryptError::InvalidKeyOrIv)?;
|
||||||
cipher.encrypt_padded_vec_mut::<Pkcs7>(data)
|
cipher.encrypt_padded_vec_mut::<Pkcs7>(data)
|
||||||
}
|
}
|
||||||
192 => {
|
192 => {
|
||||||
|
@ -164,7 +180,7 @@ fn encrypt_aes_cbc(
|
||||||
type Aes192CbcEnc = cbc::Encryptor<aes::Aes192>;
|
type Aes192CbcEnc = cbc::Encryptor<aes::Aes192>;
|
||||||
|
|
||||||
let cipher = Aes192CbcEnc::new_from_slices(key, &iv)
|
let cipher = Aes192CbcEnc::new_from_slices(key, &iv)
|
||||||
.map_err(|_| operation_error("invalid key or iv".to_string()))?;
|
.map_err(|_| EncryptError::InvalidKeyOrIv)?;
|
||||||
cipher.encrypt_padded_vec_mut::<Pkcs7>(data)
|
cipher.encrypt_padded_vec_mut::<Pkcs7>(data)
|
||||||
}
|
}
|
||||||
256 => {
|
256 => {
|
||||||
|
@ -172,10 +188,10 @@ fn encrypt_aes_cbc(
|
||||||
type Aes256CbcEnc = cbc::Encryptor<aes::Aes256>;
|
type Aes256CbcEnc = cbc::Encryptor<aes::Aes256>;
|
||||||
|
|
||||||
let cipher = Aes256CbcEnc::new_from_slices(key, &iv)
|
let cipher = Aes256CbcEnc::new_from_slices(key, &iv)
|
||||||
.map_err(|_| operation_error("invalid key or iv".to_string()))?;
|
.map_err(|_| EncryptError::InvalidKeyOrIv)?;
|
||||||
cipher.encrypt_padded_vec_mut::<Pkcs7>(data)
|
cipher.encrypt_padded_vec_mut::<Pkcs7>(data)
|
||||||
}
|
}
|
||||||
_ => return Err(type_error("invalid length")),
|
_ => return Err(EncryptError::InvalidLength),
|
||||||
};
|
};
|
||||||
Ok(ciphertext)
|
Ok(ciphertext)
|
||||||
}
|
}
|
||||||
|
@ -186,31 +202,31 @@ fn encrypt_aes_gcm_general<N: ArrayLength<u8>>(
|
||||||
length: usize,
|
length: usize,
|
||||||
ciphertext: &mut [u8],
|
ciphertext: &mut [u8],
|
||||||
additional_data: Vec<u8>,
|
additional_data: Vec<u8>,
|
||||||
) -> Result<aes_gcm::Tag, AnyError> {
|
) -> Result<aes_gcm::Tag, EncryptError> {
|
||||||
let nonce = Nonce::<N>::from_slice(&iv);
|
let nonce = Nonce::<N>::from_slice(&iv);
|
||||||
let tag = match length {
|
let tag = match length {
|
||||||
128 => {
|
128 => {
|
||||||
let cipher = aes_gcm::AesGcm::<Aes128, N>::new_from_slice(key)
|
let cipher = aes_gcm::AesGcm::<Aes128, N>::new_from_slice(key)
|
||||||
.map_err(|_| operation_error("Encryption failed"))?;
|
.map_err(|_| EncryptError::Failed)?;
|
||||||
cipher
|
cipher
|
||||||
.encrypt_in_place_detached(nonce, &additional_data, ciphertext)
|
.encrypt_in_place_detached(nonce, &additional_data, ciphertext)
|
||||||
.map_err(|_| operation_error("Encryption failed"))?
|
.map_err(|_| EncryptError::Failed)?
|
||||||
}
|
}
|
||||||
192 => {
|
192 => {
|
||||||
let cipher = aes_gcm::AesGcm::<Aes192, N>::new_from_slice(key)
|
let cipher = aes_gcm::AesGcm::<Aes192, N>::new_from_slice(key)
|
||||||
.map_err(|_| operation_error("Encryption failed"))?;
|
.map_err(|_| EncryptError::Failed)?;
|
||||||
cipher
|
cipher
|
||||||
.encrypt_in_place_detached(nonce, &additional_data, ciphertext)
|
.encrypt_in_place_detached(nonce, &additional_data, ciphertext)
|
||||||
.map_err(|_| operation_error("Encryption failed"))?
|
.map_err(|_| EncryptError::Failed)?
|
||||||
}
|
}
|
||||||
256 => {
|
256 => {
|
||||||
let cipher = aes_gcm::AesGcm::<Aes256, N>::new_from_slice(key)
|
let cipher = aes_gcm::AesGcm::<Aes256, N>::new_from_slice(key)
|
||||||
.map_err(|_| operation_error("Encryption failed"))?;
|
.map_err(|_| EncryptError::Failed)?;
|
||||||
cipher
|
cipher
|
||||||
.encrypt_in_place_detached(nonce, &additional_data, ciphertext)
|
.encrypt_in_place_detached(nonce, &additional_data, ciphertext)
|
||||||
.map_err(|_| operation_error("Encryption failed"))?
|
.map_err(|_| EncryptError::Failed)?
|
||||||
}
|
}
|
||||||
_ => return Err(type_error("invalid length")),
|
_ => return Err(EncryptError::InvalidLength),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(tag)
|
Ok(tag)
|
||||||
|
@ -223,7 +239,7 @@ fn encrypt_aes_gcm(
|
||||||
iv: Vec<u8>,
|
iv: Vec<u8>,
|
||||||
additional_data: Option<Vec<u8>>,
|
additional_data: Option<Vec<u8>>,
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
) -> Result<Vec<u8>, AnyError> {
|
) -> Result<Vec<u8>, EncryptError> {
|
||||||
let key = key.as_secret_key()?;
|
let key = key.as_secret_key()?;
|
||||||
let additional_data = additional_data.unwrap_or_default();
|
let additional_data = additional_data.unwrap_or_default();
|
||||||
|
|
||||||
|
@ -244,7 +260,7 @@ fn encrypt_aes_gcm(
|
||||||
&mut ciphertext,
|
&mut ciphertext,
|
||||||
additional_data,
|
additional_data,
|
||||||
)?,
|
)?,
|
||||||
_ => return Err(type_error("iv length not equal to 12 or 16")),
|
_ => return Err(EncryptError::InvalidIvLength),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Truncated tag to the specified tag length.
|
// Truncated tag to the specified tag length.
|
||||||
|
@ -261,7 +277,7 @@ fn encrypt_aes_ctr_gen<B>(
|
||||||
key: &[u8],
|
key: &[u8],
|
||||||
counter: &[u8],
|
counter: &[u8],
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
) -> Result<Vec<u8>, AnyError>
|
) -> Result<Vec<u8>, EncryptError>
|
||||||
where
|
where
|
||||||
B: KeyIvInit + StreamCipher,
|
B: KeyIvInit + StreamCipher,
|
||||||
{
|
{
|
||||||
|
@ -270,7 +286,7 @@ where
|
||||||
let mut ciphertext = data.to_vec();
|
let mut ciphertext = data.to_vec();
|
||||||
cipher
|
cipher
|
||||||
.try_apply_keystream(&mut ciphertext)
|
.try_apply_keystream(&mut ciphertext)
|
||||||
.map_err(|_| operation_error("tried to encrypt too much data"))?;
|
.map_err(|_| EncryptError::TooMuchData)?;
|
||||||
|
|
||||||
Ok(ciphertext)
|
Ok(ciphertext)
|
||||||
}
|
}
|
||||||
|
@ -281,7 +297,7 @@ fn encrypt_aes_ctr(
|
||||||
counter: &[u8],
|
counter: &[u8],
|
||||||
ctr_length: usize,
|
ctr_length: usize,
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
) -> Result<Vec<u8>, AnyError> {
|
) -> Result<Vec<u8>, EncryptError> {
|
||||||
let key = key.as_secret_key()?;
|
let key = key.as_secret_key()?;
|
||||||
|
|
||||||
match ctr_length {
|
match ctr_length {
|
||||||
|
@ -289,22 +305,20 @@ fn encrypt_aes_ctr(
|
||||||
128 => encrypt_aes_ctr_gen::<Ctr32BE<aes::Aes128>>(key, counter, data),
|
128 => encrypt_aes_ctr_gen::<Ctr32BE<aes::Aes128>>(key, counter, data),
|
||||||
192 => encrypt_aes_ctr_gen::<Ctr32BE<aes::Aes192>>(key, counter, data),
|
192 => encrypt_aes_ctr_gen::<Ctr32BE<aes::Aes192>>(key, counter, data),
|
||||||
256 => encrypt_aes_ctr_gen::<Ctr32BE<aes::Aes256>>(key, counter, data),
|
256 => encrypt_aes_ctr_gen::<Ctr32BE<aes::Aes256>>(key, counter, data),
|
||||||
_ => Err(type_error("invalid length")),
|
_ => Err(EncryptError::InvalidLength),
|
||||||
},
|
},
|
||||||
64 => match key_length {
|
64 => match key_length {
|
||||||
128 => encrypt_aes_ctr_gen::<Ctr64BE<aes::Aes128>>(key, counter, data),
|
128 => encrypt_aes_ctr_gen::<Ctr64BE<aes::Aes128>>(key, counter, data),
|
||||||
192 => encrypt_aes_ctr_gen::<Ctr64BE<aes::Aes192>>(key, counter, data),
|
192 => encrypt_aes_ctr_gen::<Ctr64BE<aes::Aes192>>(key, counter, data),
|
||||||
256 => encrypt_aes_ctr_gen::<Ctr64BE<aes::Aes256>>(key, counter, data),
|
256 => encrypt_aes_ctr_gen::<Ctr64BE<aes::Aes256>>(key, counter, data),
|
||||||
_ => Err(type_error("invalid length")),
|
_ => Err(EncryptError::InvalidLength),
|
||||||
},
|
},
|
||||||
128 => match key_length {
|
128 => match key_length {
|
||||||
128 => encrypt_aes_ctr_gen::<Ctr128BE<aes::Aes128>>(key, counter, data),
|
128 => encrypt_aes_ctr_gen::<Ctr128BE<aes::Aes128>>(key, counter, data),
|
||||||
192 => encrypt_aes_ctr_gen::<Ctr128BE<aes::Aes192>>(key, counter, data),
|
192 => encrypt_aes_ctr_gen::<Ctr128BE<aes::Aes192>>(key, counter, data),
|
||||||
256 => encrypt_aes_ctr_gen::<Ctr128BE<aes::Aes256>>(key, counter, data),
|
256 => encrypt_aes_ctr_gen::<Ctr128BE<aes::Aes256>>(key, counter, data),
|
||||||
_ => Err(type_error("invalid length")),
|
_ => Err(EncryptError::InvalidLength),
|
||||||
},
|
},
|
||||||
_ => Err(type_error(
|
_ => Err(EncryptError::InvalidCounterLength),
|
||||||
"invalid counter length. Currently supported 32/64/128 bits",
|
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,6 @@ use base64::prelude::BASE64_URL_SAFE_NO_PAD;
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
use const_oid::AssociatedOid;
|
use const_oid::AssociatedOid;
|
||||||
use const_oid::ObjectIdentifier;
|
use const_oid::ObjectIdentifier;
|
||||||
use deno_core::error::custom_error;
|
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::op2;
|
use deno_core::op2;
|
||||||
use deno_core::ToJsBuffer;
|
use deno_core::ToJsBuffer;
|
||||||
use elliptic_curve::sec1::ToEncodedPoint;
|
use elliptic_curve::sec1::ToEncodedPoint;
|
||||||
|
@ -22,6 +20,16 @@ use spki::AlgorithmIdentifierOwned;
|
||||||
|
|
||||||
use crate::shared::*;
|
use crate::shared::*;
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum ExportKeyError {
|
||||||
|
#[error(transparent)]
|
||||||
|
General(#[from] SharedError),
|
||||||
|
#[error(transparent)]
|
||||||
|
Der(#[from] spki::der::Error),
|
||||||
|
#[error("Unsupported named curve")]
|
||||||
|
UnsupportedNamedCurve,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ExportKeyOptions {
|
pub struct ExportKeyOptions {
|
||||||
|
@ -99,7 +107,7 @@ pub enum ExportKeyResult {
|
||||||
pub fn op_crypto_export_key(
|
pub fn op_crypto_export_key(
|
||||||
#[serde] opts: ExportKeyOptions,
|
#[serde] opts: ExportKeyOptions,
|
||||||
#[serde] key_data: V8RawKeyData,
|
#[serde] key_data: V8RawKeyData,
|
||||||
) -> Result<ExportKeyResult, AnyError> {
|
) -> Result<ExportKeyResult, ExportKeyError> {
|
||||||
match opts.algorithm {
|
match opts.algorithm {
|
||||||
ExportKeyAlgorithm::RsassaPkcs1v15 {}
|
ExportKeyAlgorithm::RsassaPkcs1v15 {}
|
||||||
| ExportKeyAlgorithm::RsaPss {}
|
| ExportKeyAlgorithm::RsaPss {}
|
||||||
|
@ -125,7 +133,7 @@ fn bytes_to_b64(bytes: &[u8]) -> String {
|
||||||
fn export_key_rsa(
|
fn export_key_rsa(
|
||||||
format: ExportKeyFormat,
|
format: ExportKeyFormat,
|
||||||
key_data: V8RawKeyData,
|
key_data: V8RawKeyData,
|
||||||
) -> Result<ExportKeyResult, deno_core::anyhow::Error> {
|
) -> Result<ExportKeyResult, ExportKeyError> {
|
||||||
match format {
|
match format {
|
||||||
ExportKeyFormat::Spki => {
|
ExportKeyFormat::Spki => {
|
||||||
let subject_public_key = &key_data.as_rsa_public_key()?;
|
let subject_public_key = &key_data.as_rsa_public_key()?;
|
||||||
|
@ -181,12 +189,7 @@ fn export_key_rsa(
|
||||||
ExportKeyFormat::JwkPublic => {
|
ExportKeyFormat::JwkPublic => {
|
||||||
let public_key = key_data.as_rsa_public_key()?;
|
let public_key = key_data.as_rsa_public_key()?;
|
||||||
let public_key = rsa::pkcs1::RsaPublicKey::from_der(&public_key)
|
let public_key = rsa::pkcs1::RsaPublicKey::from_der(&public_key)
|
||||||
.map_err(|_| {
|
.map_err(|_| SharedError::FailedDecodePublicKey)?;
|
||||||
custom_error(
|
|
||||||
"DOMExceptionOperationError",
|
|
||||||
"failed to decode public key",
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(ExportKeyResult::JwkPublicRsa {
|
Ok(ExportKeyResult::JwkPublicRsa {
|
||||||
n: uint_to_b64(public_key.modulus),
|
n: uint_to_b64(public_key.modulus),
|
||||||
|
@ -196,12 +199,7 @@ fn export_key_rsa(
|
||||||
ExportKeyFormat::JwkPrivate => {
|
ExportKeyFormat::JwkPrivate => {
|
||||||
let private_key = key_data.as_rsa_private_key()?;
|
let private_key = key_data.as_rsa_private_key()?;
|
||||||
let private_key = rsa::pkcs1::RsaPrivateKey::from_der(private_key)
|
let private_key = rsa::pkcs1::RsaPrivateKey::from_der(private_key)
|
||||||
.map_err(|_| {
|
.map_err(|_| SharedError::FailedDecodePrivateKey)?;
|
||||||
custom_error(
|
|
||||||
"DOMExceptionOperationError",
|
|
||||||
"failed to decode private key",
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(ExportKeyResult::JwkPrivateRsa {
|
Ok(ExportKeyResult::JwkPrivateRsa {
|
||||||
n: uint_to_b64(private_key.modulus),
|
n: uint_to_b64(private_key.modulus),
|
||||||
|
@ -214,14 +212,14 @@ fn export_key_rsa(
|
||||||
qi: uint_to_b64(private_key.coefficient),
|
qi: uint_to_b64(private_key.coefficient),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
_ => Err(unsupported_format()),
|
_ => Err(SharedError::UnsupportedFormat.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn export_key_symmetric(
|
fn export_key_symmetric(
|
||||||
format: ExportKeyFormat,
|
format: ExportKeyFormat,
|
||||||
key_data: V8RawKeyData,
|
key_data: V8RawKeyData,
|
||||||
) -> Result<ExportKeyResult, deno_core::anyhow::Error> {
|
) -> Result<ExportKeyResult, ExportKeyError> {
|
||||||
match format {
|
match format {
|
||||||
ExportKeyFormat::JwkSecret => {
|
ExportKeyFormat::JwkSecret => {
|
||||||
let bytes = key_data.as_secret_key()?;
|
let bytes = key_data.as_secret_key()?;
|
||||||
|
@ -230,7 +228,7 @@ fn export_key_symmetric(
|
||||||
k: bytes_to_b64(bytes),
|
k: bytes_to_b64(bytes),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
_ => Err(unsupported_format()),
|
_ => Err(SharedError::UnsupportedFormat.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,7 +237,7 @@ fn export_key_ec(
|
||||||
key_data: V8RawKeyData,
|
key_data: V8RawKeyData,
|
||||||
algorithm: ExportKeyAlgorithm,
|
algorithm: ExportKeyAlgorithm,
|
||||||
named_curve: EcNamedCurve,
|
named_curve: EcNamedCurve,
|
||||||
) -> Result<ExportKeyResult, deno_core::anyhow::Error> {
|
) -> Result<ExportKeyResult, ExportKeyError> {
|
||||||
match format {
|
match format {
|
||||||
ExportKeyFormat::Raw => {
|
ExportKeyFormat::Raw => {
|
||||||
let subject_public_key = match named_curve {
|
let subject_public_key = match named_curve {
|
||||||
|
@ -332,10 +330,7 @@ fn export_key_ec(
|
||||||
y: bytes_to_b64(y),
|
y: bytes_to_b64(y),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(custom_error(
|
Err(SharedError::FailedDecodePublicKey.into())
|
||||||
"DOMExceptionOperationError",
|
|
||||||
"failed to decode public key",
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EcNamedCurve::P384 => {
|
EcNamedCurve::P384 => {
|
||||||
|
@ -350,10 +345,7 @@ fn export_key_ec(
|
||||||
y: bytes_to_b64(y),
|
y: bytes_to_b64(y),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(custom_error(
|
Err(SharedError::FailedDecodePublicKey.into())
|
||||||
"DOMExceptionOperationError",
|
|
||||||
"failed to decode public key",
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EcNamedCurve::P521 => {
|
EcNamedCurve::P521 => {
|
||||||
|
@ -368,10 +360,7 @@ fn export_key_ec(
|
||||||
y: bytes_to_b64(y),
|
y: bytes_to_b64(y),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(custom_error(
|
Err(SharedError::FailedDecodePublicKey.into())
|
||||||
"DOMExceptionOperationError",
|
|
||||||
"failed to decode public key",
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -380,13 +369,8 @@ fn export_key_ec(
|
||||||
|
|
||||||
match named_curve {
|
match named_curve {
|
||||||
EcNamedCurve::P256 => {
|
EcNamedCurve::P256 => {
|
||||||
let ec_key =
|
let ec_key = p256::SecretKey::from_pkcs8_der(private_key)
|
||||||
p256::SecretKey::from_pkcs8_der(private_key).map_err(|_| {
|
.map_err(|_| SharedError::FailedDecodePrivateKey)?;
|
||||||
custom_error(
|
|
||||||
"DOMExceptionOperationError",
|
|
||||||
"failed to decode private key",
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let point = ec_key.public_key().to_encoded_point(false);
|
let point = ec_key.public_key().to_encoded_point(false);
|
||||||
if let elliptic_curve::sec1::Coordinates::Uncompressed { x, y } =
|
if let elliptic_curve::sec1::Coordinates::Uncompressed { x, y } =
|
||||||
|
@ -398,18 +382,13 @@ fn export_key_ec(
|
||||||
d: bytes_to_b64(&ec_key.to_bytes()),
|
d: bytes_to_b64(&ec_key.to_bytes()),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(data_error("expected valid public EC key"))
|
Err(SharedError::ExpectedValidPublicECKey.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EcNamedCurve::P384 => {
|
EcNamedCurve::P384 => {
|
||||||
let ec_key =
|
let ec_key = p384::SecretKey::from_pkcs8_der(private_key)
|
||||||
p384::SecretKey::from_pkcs8_der(private_key).map_err(|_| {
|
.map_err(|_| SharedError::FailedDecodePrivateKey)?;
|
||||||
custom_error(
|
|
||||||
"DOMExceptionOperationError",
|
|
||||||
"failed to decode private key",
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let point = ec_key.public_key().to_encoded_point(false);
|
let point = ec_key.public_key().to_encoded_point(false);
|
||||||
if let elliptic_curve::sec1::Coordinates::Uncompressed { x, y } =
|
if let elliptic_curve::sec1::Coordinates::Uncompressed { x, y } =
|
||||||
|
@ -421,12 +400,12 @@ fn export_key_ec(
|
||||||
d: bytes_to_b64(&ec_key.to_bytes()),
|
d: bytes_to_b64(&ec_key.to_bytes()),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(data_error("expected valid public EC key"))
|
Err(SharedError::ExpectedValidPublicECKey.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => Err(not_supported_error("Unsupported namedCurve")),
|
_ => Err(ExportKeyError::UnsupportedNamedCurve),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExportKeyFormat::JwkSecret => Err(unsupported_format()),
|
ExportKeyFormat::JwkSecret => Err(SharedError::UnsupportedFormat.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::op2;
|
use deno_core::op2;
|
||||||
use deno_core::unsync::spawn_blocking;
|
use deno_core::unsync::spawn_blocking;
|
||||||
use deno_core::ToJsBuffer;
|
use deno_core::ToJsBuffer;
|
||||||
|
@ -16,6 +15,26 @@ use serde::Deserialize;
|
||||||
|
|
||||||
use crate::shared::*;
|
use crate::shared::*;
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum GenerateKeyError {
|
||||||
|
#[error(transparent)]
|
||||||
|
General(#[from] SharedError),
|
||||||
|
#[error("Bad public exponent")]
|
||||||
|
BadPublicExponent,
|
||||||
|
#[error("Invalid HMAC key length")]
|
||||||
|
InvalidHMACKeyLength,
|
||||||
|
#[error("Failed to serialize RSA key")]
|
||||||
|
FailedRSAKeySerialization,
|
||||||
|
#[error("Invalid AES key length")]
|
||||||
|
InvalidAESKeyLength,
|
||||||
|
#[error("Failed to generate RSA key")]
|
||||||
|
FailedRSAKeyGeneration,
|
||||||
|
#[error("Failed to generate EC key")]
|
||||||
|
FailedECKeyGeneration,
|
||||||
|
#[error("Failed to generate key")]
|
||||||
|
FailedKeyGeneration,
|
||||||
|
}
|
||||||
|
|
||||||
// Allowlist for RSA public exponents.
|
// Allowlist for RSA public exponents.
|
||||||
static PUB_EXPONENT_1: Lazy<BigUint> =
|
static PUB_EXPONENT_1: Lazy<BigUint> =
|
||||||
Lazy::new(|| BigUint::from_u64(3).unwrap());
|
Lazy::new(|| BigUint::from_u64(3).unwrap());
|
||||||
|
@ -46,7 +65,7 @@ pub enum GenerateKeyOptions {
|
||||||
#[serde]
|
#[serde]
|
||||||
pub async fn op_crypto_generate_key(
|
pub async fn op_crypto_generate_key(
|
||||||
#[serde] opts: GenerateKeyOptions,
|
#[serde] opts: GenerateKeyOptions,
|
||||||
) -> Result<ToJsBuffer, AnyError> {
|
) -> Result<ToJsBuffer, GenerateKeyError> {
|
||||||
let fun = || match opts {
|
let fun = || match opts {
|
||||||
GenerateKeyOptions::Rsa {
|
GenerateKeyOptions::Rsa {
|
||||||
modulus_length,
|
modulus_length,
|
||||||
|
@ -65,21 +84,21 @@ pub async fn op_crypto_generate_key(
|
||||||
fn generate_key_rsa(
|
fn generate_key_rsa(
|
||||||
modulus_length: u32,
|
modulus_length: u32,
|
||||||
public_exponent: &[u8],
|
public_exponent: &[u8],
|
||||||
) -> Result<Vec<u8>, AnyError> {
|
) -> Result<Vec<u8>, GenerateKeyError> {
|
||||||
let exponent = BigUint::from_bytes_be(public_exponent);
|
let exponent = BigUint::from_bytes_be(public_exponent);
|
||||||
if exponent != *PUB_EXPONENT_1 && exponent != *PUB_EXPONENT_2 {
|
if exponent != *PUB_EXPONENT_1 && exponent != *PUB_EXPONENT_2 {
|
||||||
return Err(operation_error("Bad public exponent"));
|
return Err(GenerateKeyError::BadPublicExponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
|
|
||||||
let private_key =
|
let private_key =
|
||||||
RsaPrivateKey::new_with_exp(&mut rng, modulus_length as usize, &exponent)
|
RsaPrivateKey::new_with_exp(&mut rng, modulus_length as usize, &exponent)
|
||||||
.map_err(|_| operation_error("Failed to generate RSA key"))?;
|
.map_err(|_| GenerateKeyError::FailedRSAKeyGeneration)?;
|
||||||
|
|
||||||
let private_key = private_key
|
let private_key = private_key
|
||||||
.to_pkcs1_der()
|
.to_pkcs1_der()
|
||||||
.map_err(|_| operation_error("Failed to serialize RSA key"))?;
|
.map_err(|_| GenerateKeyError::FailedRSAKeySerialization)?;
|
||||||
|
|
||||||
Ok(private_key.as_bytes().to_vec())
|
Ok(private_key.as_bytes().to_vec())
|
||||||
}
|
}
|
||||||
|
@ -90,7 +109,9 @@ fn generate_key_ec_p521() -> Vec<u8> {
|
||||||
key.to_nonzero_scalar().to_bytes().to_vec()
|
key.to_nonzero_scalar().to_bytes().to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_key_ec(named_curve: EcNamedCurve) -> Result<Vec<u8>, AnyError> {
|
fn generate_key_ec(
|
||||||
|
named_curve: EcNamedCurve,
|
||||||
|
) -> Result<Vec<u8>, GenerateKeyError> {
|
||||||
let curve = match named_curve {
|
let curve = match named_curve {
|
||||||
EcNamedCurve::P256 => &ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING,
|
EcNamedCurve::P256 => &ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING,
|
||||||
EcNamedCurve::P384 => &ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING,
|
EcNamedCurve::P384 => &ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING,
|
||||||
|
@ -100,21 +121,21 @@ fn generate_key_ec(named_curve: EcNamedCurve) -> Result<Vec<u8>, AnyError> {
|
||||||
let rng = ring::rand::SystemRandom::new();
|
let rng = ring::rand::SystemRandom::new();
|
||||||
|
|
||||||
let pkcs8 = EcdsaKeyPair::generate_pkcs8(curve, &rng)
|
let pkcs8 = EcdsaKeyPair::generate_pkcs8(curve, &rng)
|
||||||
.map_err(|_| operation_error("Failed to generate EC key"))?;
|
.map_err(|_| GenerateKeyError::FailedECKeyGeneration)?;
|
||||||
|
|
||||||
Ok(pkcs8.as_ref().to_vec())
|
Ok(pkcs8.as_ref().to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_key_aes(length: usize) -> Result<Vec<u8>, AnyError> {
|
fn generate_key_aes(length: usize) -> Result<Vec<u8>, GenerateKeyError> {
|
||||||
if length % 8 != 0 || length > 256 {
|
if length % 8 != 0 || length > 256 {
|
||||||
return Err(operation_error("Invalid AES key length"));
|
return Err(GenerateKeyError::InvalidAESKeyLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut key = vec![0u8; length / 8];
|
let mut key = vec![0u8; length / 8];
|
||||||
let rng = ring::rand::SystemRandom::new();
|
let rng = ring::rand::SystemRandom::new();
|
||||||
rng
|
rng
|
||||||
.fill(&mut key)
|
.fill(&mut key)
|
||||||
.map_err(|_| operation_error("Failed to generate key"))?;
|
.map_err(|_| GenerateKeyError::FailedKeyGeneration)?;
|
||||||
|
|
||||||
Ok(key)
|
Ok(key)
|
||||||
}
|
}
|
||||||
|
@ -122,7 +143,7 @@ fn generate_key_aes(length: usize) -> Result<Vec<u8>, AnyError> {
|
||||||
fn generate_key_hmac(
|
fn generate_key_hmac(
|
||||||
hash: ShaHash,
|
hash: ShaHash,
|
||||||
length: Option<usize>,
|
length: Option<usize>,
|
||||||
) -> Result<Vec<u8>, AnyError> {
|
) -> Result<Vec<u8>, GenerateKeyError> {
|
||||||
let hash = match hash {
|
let hash = match hash {
|
||||||
ShaHash::Sha1 => &ring::hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY,
|
ShaHash::Sha1 => &ring::hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY,
|
||||||
ShaHash::Sha256 => &ring::hmac::HMAC_SHA256,
|
ShaHash::Sha256 => &ring::hmac::HMAC_SHA256,
|
||||||
|
@ -132,12 +153,12 @@ fn generate_key_hmac(
|
||||||
|
|
||||||
let length = if let Some(length) = length {
|
let length = if let Some(length) = length {
|
||||||
if length % 8 != 0 {
|
if length % 8 != 0 {
|
||||||
return Err(operation_error("Invalid HMAC key length"));
|
return Err(GenerateKeyError::InvalidHMACKeyLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
let length = length / 8;
|
let length = length / 8;
|
||||||
if length > ring::digest::MAX_BLOCK_LEN {
|
if length > ring::digest::MAX_BLOCK_LEN {
|
||||||
return Err(operation_error("Invalid HMAC key length"));
|
return Err(GenerateKeyError::InvalidHMACKeyLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
length
|
length
|
||||||
|
@ -149,7 +170,7 @@ fn generate_key_hmac(
|
||||||
let mut key = vec![0u8; length];
|
let mut key = vec![0u8; length];
|
||||||
rng
|
rng
|
||||||
.fill(&mut key)
|
.fill(&mut key)
|
||||||
.map_err(|_| operation_error("Failed to generate key"))?;
|
.map_err(|_| GenerateKeyError::FailedKeyGeneration)?;
|
||||||
|
|
||||||
Ok(key)
|
Ok(key)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::op2;
|
use deno_core::op2;
|
||||||
use deno_core::JsBuffer;
|
use deno_core::JsBuffer;
|
||||||
use deno_core::ToJsBuffer;
|
use deno_core::ToJsBuffer;
|
||||||
|
@ -15,6 +14,70 @@ use spki::der::Decode;
|
||||||
|
|
||||||
use crate::shared::*;
|
use crate::shared::*;
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum ImportKeyError {
|
||||||
|
#[error(transparent)]
|
||||||
|
General(#[from] SharedError),
|
||||||
|
#[error("invalid modulus")]
|
||||||
|
InvalidModulus,
|
||||||
|
#[error("invalid public exponent")]
|
||||||
|
InvalidPublicExponent,
|
||||||
|
#[error("invalid private exponent")]
|
||||||
|
InvalidPrivateExponent,
|
||||||
|
#[error("invalid first prime factor")]
|
||||||
|
InvalidFirstPrimeFactor,
|
||||||
|
#[error("invalid second prime factor")]
|
||||||
|
InvalidSecondPrimeFactor,
|
||||||
|
#[error("invalid first CRT exponent")]
|
||||||
|
InvalidFirstCRTExponent,
|
||||||
|
#[error("invalid second CRT exponent")]
|
||||||
|
InvalidSecondCRTExponent,
|
||||||
|
#[error("invalid CRT coefficient")]
|
||||||
|
InvalidCRTCoefficient,
|
||||||
|
#[error("invalid b64 coordinate")]
|
||||||
|
InvalidB64Coordinate,
|
||||||
|
#[error("invalid RSA public key")]
|
||||||
|
InvalidRSAPublicKey,
|
||||||
|
#[error("invalid RSA private key")]
|
||||||
|
InvalidRSAPrivateKey,
|
||||||
|
#[error("unsupported algorithm")]
|
||||||
|
UnsupportedAlgorithm,
|
||||||
|
#[error("public key is invalid (too long)")]
|
||||||
|
PublicKeyTooLong,
|
||||||
|
#[error("private key is invalid (too long)")]
|
||||||
|
PrivateKeyTooLong,
|
||||||
|
#[error("invalid P-256 elliptic curve point")]
|
||||||
|
InvalidP256ECPoint,
|
||||||
|
#[error("invalid P-384 elliptic curve point")]
|
||||||
|
InvalidP384ECPoint,
|
||||||
|
#[error("invalid P-521 elliptic curve point")]
|
||||||
|
InvalidP521ECPoint,
|
||||||
|
#[error("invalid P-256 elliptic curve SPKI data")]
|
||||||
|
InvalidP256ECSPKIData,
|
||||||
|
#[error("invalid P-384 elliptic curve SPKI data")]
|
||||||
|
InvalidP384ECSPKIData,
|
||||||
|
#[error("invalid P-521 elliptic curve SPKI data")]
|
||||||
|
InvalidP521ECSPKIData,
|
||||||
|
#[error("curve mismatch")]
|
||||||
|
CurveMismatch,
|
||||||
|
#[error("Unsupported named curve")]
|
||||||
|
UnsupportedNamedCurve,
|
||||||
|
#[error("invalid key data")]
|
||||||
|
InvalidKeyData,
|
||||||
|
#[error("invalid JWK private key")]
|
||||||
|
InvalidJWKPrivateKey,
|
||||||
|
#[error(transparent)]
|
||||||
|
EllipticCurve(#[from] elliptic_curve::Error),
|
||||||
|
#[error("expected valid PKCS#8 data")]
|
||||||
|
ExpectedValidPkcs8Data,
|
||||||
|
#[error("malformed parameters")]
|
||||||
|
MalformedParameters,
|
||||||
|
#[error(transparent)]
|
||||||
|
Spki(#[from] spki::Error),
|
||||||
|
#[error(transparent)]
|
||||||
|
Der(#[from] rsa::pkcs1::der::Error),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub enum KeyData {
|
pub enum KeyData {
|
||||||
|
@ -93,7 +156,7 @@ pub enum ImportKeyResult {
|
||||||
pub fn op_crypto_import_key(
|
pub fn op_crypto_import_key(
|
||||||
#[serde] opts: ImportKeyOptions,
|
#[serde] opts: ImportKeyOptions,
|
||||||
#[serde] key_data: KeyData,
|
#[serde] key_data: KeyData,
|
||||||
) -> Result<ImportKeyResult, AnyError> {
|
) -> Result<ImportKeyResult, ImportKeyError> {
|
||||||
match opts {
|
match opts {
|
||||||
ImportKeyOptions::RsassaPkcs1v15 {} => import_key_rsassa(key_data),
|
ImportKeyOptions::RsassaPkcs1v15 {} => import_key_rsassa(key_data),
|
||||||
ImportKeyOptions::RsaPss {} => import_key_rsapss(key_data),
|
ImportKeyOptions::RsaPss {} => import_key_rsapss(key_data),
|
||||||
|
@ -117,21 +180,21 @@ const BASE64_URL_SAFE_FORGIVING:
|
||||||
);
|
);
|
||||||
|
|
||||||
macro_rules! jwt_b64_int_or_err {
|
macro_rules! jwt_b64_int_or_err {
|
||||||
($name:ident, $b64:expr, $err:expr) => {
|
($name:ident, $b64:expr, $err:tt) => {
|
||||||
let bytes = BASE64_URL_SAFE_FORGIVING
|
let bytes = BASE64_URL_SAFE_FORGIVING
|
||||||
.decode($b64)
|
.decode($b64)
|
||||||
.map_err(|_| data_error($err))?;
|
.map_err(|_| ImportKeyError::$err)?;
|
||||||
let $name = UintRef::new(&bytes).map_err(|_| data_error($err))?;
|
let $name = UintRef::new(&bytes).map_err(|_| ImportKeyError::$err)?;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_key_rsa_jwk(
|
fn import_key_rsa_jwk(
|
||||||
key_data: KeyData,
|
key_data: KeyData,
|
||||||
) -> Result<ImportKeyResult, deno_core::anyhow::Error> {
|
) -> Result<ImportKeyResult, ImportKeyError> {
|
||||||
match key_data {
|
match key_data {
|
||||||
KeyData::JwkPublicRsa { n, e } => {
|
KeyData::JwkPublicRsa { n, e } => {
|
||||||
jwt_b64_int_or_err!(modulus, &n, "invalid modulus");
|
jwt_b64_int_or_err!(modulus, &n, InvalidModulus);
|
||||||
jwt_b64_int_or_err!(public_exponent, &e, "invalid public exponent");
|
jwt_b64_int_or_err!(public_exponent, &e, InvalidPublicExponent);
|
||||||
|
|
||||||
let public_key = rsa::pkcs1::RsaPublicKey {
|
let public_key = rsa::pkcs1::RsaPublicKey {
|
||||||
modulus,
|
modulus,
|
||||||
|
@ -141,7 +204,7 @@ fn import_key_rsa_jwk(
|
||||||
let mut data = Vec::new();
|
let mut data = Vec::new();
|
||||||
public_key
|
public_key
|
||||||
.encode_to_vec(&mut data)
|
.encode_to_vec(&mut data)
|
||||||
.map_err(|_| data_error("invalid rsa public key"))?;
|
.map_err(|_| ImportKeyError::InvalidRSAPublicKey)?;
|
||||||
|
|
||||||
let public_exponent =
|
let public_exponent =
|
||||||
public_key.public_exponent.as_bytes().to_vec().into();
|
public_key.public_exponent.as_bytes().to_vec().into();
|
||||||
|
@ -163,14 +226,14 @@ fn import_key_rsa_jwk(
|
||||||
dq,
|
dq,
|
||||||
qi,
|
qi,
|
||||||
} => {
|
} => {
|
||||||
jwt_b64_int_or_err!(modulus, &n, "invalid modulus");
|
jwt_b64_int_or_err!(modulus, &n, InvalidModulus);
|
||||||
jwt_b64_int_or_err!(public_exponent, &e, "invalid public exponent");
|
jwt_b64_int_or_err!(public_exponent, &e, InvalidPublicExponent);
|
||||||
jwt_b64_int_or_err!(private_exponent, &d, "invalid private exponent");
|
jwt_b64_int_or_err!(private_exponent, &d, InvalidPrivateExponent);
|
||||||
jwt_b64_int_or_err!(prime1, &p, "invalid first prime factor");
|
jwt_b64_int_or_err!(prime1, &p, InvalidFirstPrimeFactor);
|
||||||
jwt_b64_int_or_err!(prime2, &q, "invalid second prime factor");
|
jwt_b64_int_or_err!(prime2, &q, InvalidSecondPrimeFactor);
|
||||||
jwt_b64_int_or_err!(exponent1, &dp, "invalid first CRT exponent");
|
jwt_b64_int_or_err!(exponent1, &dp, InvalidFirstCRTExponent);
|
||||||
jwt_b64_int_or_err!(exponent2, &dq, "invalid second CRT exponent");
|
jwt_b64_int_or_err!(exponent2, &dq, InvalidSecondCRTExponent);
|
||||||
jwt_b64_int_or_err!(coefficient, &qi, "invalid CRT coefficient");
|
jwt_b64_int_or_err!(coefficient, &qi, InvalidCRTCoefficient);
|
||||||
|
|
||||||
let private_key = rsa::pkcs1::RsaPrivateKey {
|
let private_key = rsa::pkcs1::RsaPrivateKey {
|
||||||
modulus,
|
modulus,
|
||||||
|
@ -187,7 +250,7 @@ fn import_key_rsa_jwk(
|
||||||
let mut data = Vec::new();
|
let mut data = Vec::new();
|
||||||
private_key
|
private_key
|
||||||
.encode_to_vec(&mut data)
|
.encode_to_vec(&mut data)
|
||||||
.map_err(|_| data_error("invalid rsa private key"))?;
|
.map_err(|_| ImportKeyError::InvalidRSAPrivateKey)?;
|
||||||
|
|
||||||
let public_exponent =
|
let public_exponent =
|
||||||
private_key.public_exponent.as_bytes().to_vec().into();
|
private_key.public_exponent.as_bytes().to_vec().into();
|
||||||
|
@ -205,37 +268,33 @@ fn import_key_rsa_jwk(
|
||||||
|
|
||||||
fn import_key_rsassa(
|
fn import_key_rsassa(
|
||||||
key_data: KeyData,
|
key_data: KeyData,
|
||||||
) -> Result<ImportKeyResult, deno_core::anyhow::Error> {
|
) -> Result<ImportKeyResult, ImportKeyError> {
|
||||||
match key_data {
|
match key_data {
|
||||||
KeyData::Spki(data) => {
|
KeyData::Spki(data) => {
|
||||||
// 2-3.
|
// 2-3.
|
||||||
let pk_info = spki::SubjectPublicKeyInfoRef::try_from(&*data)
|
let pk_info = spki::SubjectPublicKeyInfoRef::try_from(&*data)?;
|
||||||
.map_err(|e| data_error(e.to_string()))?;
|
|
||||||
|
|
||||||
// 4-5.
|
// 4-5.
|
||||||
let alg = pk_info.algorithm.oid;
|
let alg = pk_info.algorithm.oid;
|
||||||
|
|
||||||
// 6-7. (skipped, only support rsaEncryption for interoperability)
|
// 6-7. (skipped, only support rsaEncryption for interoperability)
|
||||||
if alg != RSA_ENCRYPTION_OID {
|
if alg != RSA_ENCRYPTION_OID {
|
||||||
return Err(data_error("unsupported algorithm"));
|
return Err(ImportKeyError::UnsupportedAlgorithm);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 8-9.
|
// 8-9.
|
||||||
let public_key = rsa::pkcs1::RsaPublicKey::from_der(
|
let public_key = rsa::pkcs1::RsaPublicKey::from_der(
|
||||||
pk_info.subject_public_key.raw_bytes(),
|
pk_info.subject_public_key.raw_bytes(),
|
||||||
)
|
)?;
|
||||||
.map_err(|e| data_error(e.to_string()))?;
|
|
||||||
|
|
||||||
let bytes_consumed = public_key
|
let bytes_consumed = public_key.encoded_len()?;
|
||||||
.encoded_len()
|
|
||||||
.map_err(|e| data_error(e.to_string()))?;
|
|
||||||
|
|
||||||
if bytes_consumed
|
if bytes_consumed
|
||||||
!= rsa::pkcs1::der::Length::new(
|
!= rsa::pkcs1::der::Length::new(
|
||||||
pk_info.subject_public_key.raw_bytes().len() as u16,
|
pk_info.subject_public_key.raw_bytes().len() as u16,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return Err(data_error("public key is invalid (too long)"));
|
return Err(ImportKeyError::PublicKeyTooLong);
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = pk_info.subject_public_key.raw_bytes().to_vec().into();
|
let data = pk_info.subject_public_key.raw_bytes().to_vec().into();
|
||||||
|
@ -251,30 +310,26 @@ fn import_key_rsassa(
|
||||||
}
|
}
|
||||||
KeyData::Pkcs8(data) => {
|
KeyData::Pkcs8(data) => {
|
||||||
// 2-3.
|
// 2-3.
|
||||||
let pk_info = PrivateKeyInfo::from_der(&data)
|
let pk_info = PrivateKeyInfo::from_der(&data)?;
|
||||||
.map_err(|e| data_error(e.to_string()))?;
|
|
||||||
|
|
||||||
// 4-5.
|
// 4-5.
|
||||||
let alg = pk_info.algorithm.oid;
|
let alg = pk_info.algorithm.oid;
|
||||||
|
|
||||||
// 6-7. (skipped, only support rsaEncryption for interoperability)
|
// 6-7. (skipped, only support rsaEncryption for interoperability)
|
||||||
if alg != RSA_ENCRYPTION_OID {
|
if alg != RSA_ENCRYPTION_OID {
|
||||||
return Err(data_error("unsupported algorithm"));
|
return Err(ImportKeyError::UnsupportedAlgorithm);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 8-9.
|
// 8-9.
|
||||||
let private_key =
|
let private_key =
|
||||||
rsa::pkcs1::RsaPrivateKey::from_der(pk_info.private_key)
|
rsa::pkcs1::RsaPrivateKey::from_der(pk_info.private_key)?;
|
||||||
.map_err(|e| data_error(e.to_string()))?;
|
|
||||||
|
|
||||||
let bytes_consumed = private_key
|
let bytes_consumed = private_key.encoded_len()?;
|
||||||
.encoded_len()
|
|
||||||
.map_err(|e| data_error(e.to_string()))?;
|
|
||||||
|
|
||||||
if bytes_consumed
|
if bytes_consumed
|
||||||
!= rsa::pkcs1::der::Length::new(pk_info.private_key.len() as u16)
|
!= rsa::pkcs1::der::Length::new(pk_info.private_key.len() as u16)
|
||||||
{
|
{
|
||||||
return Err(data_error("private key is invalid (too long)"));
|
return Err(ImportKeyError::PrivateKeyTooLong);
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = pk_info.private_key.to_vec().into();
|
let data = pk_info.private_key.to_vec().into();
|
||||||
|
@ -291,43 +346,39 @@ fn import_key_rsassa(
|
||||||
KeyData::JwkPublicRsa { .. } | KeyData::JwkPrivateRsa { .. } => {
|
KeyData::JwkPublicRsa { .. } | KeyData::JwkPrivateRsa { .. } => {
|
||||||
import_key_rsa_jwk(key_data)
|
import_key_rsa_jwk(key_data)
|
||||||
}
|
}
|
||||||
_ => Err(unsupported_format()),
|
_ => Err(SharedError::UnsupportedFormat.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_key_rsapss(
|
fn import_key_rsapss(
|
||||||
key_data: KeyData,
|
key_data: KeyData,
|
||||||
) -> Result<ImportKeyResult, deno_core::anyhow::Error> {
|
) -> Result<ImportKeyResult, ImportKeyError> {
|
||||||
match key_data {
|
match key_data {
|
||||||
KeyData::Spki(data) => {
|
KeyData::Spki(data) => {
|
||||||
// 2-3.
|
// 2-3.
|
||||||
let pk_info = spki::SubjectPublicKeyInfoRef::try_from(&*data)
|
let pk_info = spki::SubjectPublicKeyInfoRef::try_from(&*data)?;
|
||||||
.map_err(|e| data_error(e.to_string()))?;
|
|
||||||
|
|
||||||
// 4-5.
|
// 4-5.
|
||||||
let alg = pk_info.algorithm.oid;
|
let alg = pk_info.algorithm.oid;
|
||||||
|
|
||||||
// 6-7. (skipped, only support rsaEncryption for interoperability)
|
// 6-7. (skipped, only support rsaEncryption for interoperability)
|
||||||
if alg != RSA_ENCRYPTION_OID {
|
if alg != RSA_ENCRYPTION_OID {
|
||||||
return Err(data_error("unsupported algorithm"));
|
return Err(ImportKeyError::UnsupportedAlgorithm);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 8-9.
|
// 8-9.
|
||||||
let public_key = rsa::pkcs1::RsaPublicKey::from_der(
|
let public_key = rsa::pkcs1::RsaPublicKey::from_der(
|
||||||
pk_info.subject_public_key.raw_bytes(),
|
pk_info.subject_public_key.raw_bytes(),
|
||||||
)
|
)?;
|
||||||
.map_err(|e| data_error(e.to_string()))?;
|
|
||||||
|
|
||||||
let bytes_consumed = public_key
|
let bytes_consumed = public_key.encoded_len()?;
|
||||||
.encoded_len()
|
|
||||||
.map_err(|e| data_error(e.to_string()))?;
|
|
||||||
|
|
||||||
if bytes_consumed
|
if bytes_consumed
|
||||||
!= rsa::pkcs1::der::Length::new(
|
!= rsa::pkcs1::der::Length::new(
|
||||||
pk_info.subject_public_key.raw_bytes().len() as u16,
|
pk_info.subject_public_key.raw_bytes().len() as u16,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return Err(data_error("public key is invalid (too long)"));
|
return Err(ImportKeyError::PublicKeyTooLong);
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = pk_info.subject_public_key.raw_bytes().to_vec().into();
|
let data = pk_info.subject_public_key.raw_bytes().to_vec().into();
|
||||||
|
@ -343,30 +394,26 @@ fn import_key_rsapss(
|
||||||
}
|
}
|
||||||
KeyData::Pkcs8(data) => {
|
KeyData::Pkcs8(data) => {
|
||||||
// 2-3.
|
// 2-3.
|
||||||
let pk_info = PrivateKeyInfo::from_der(&data)
|
let pk_info = PrivateKeyInfo::from_der(&data)?;
|
||||||
.map_err(|e| data_error(e.to_string()))?;
|
|
||||||
|
|
||||||
// 4-5.
|
// 4-5.
|
||||||
let alg = pk_info.algorithm.oid;
|
let alg = pk_info.algorithm.oid;
|
||||||
|
|
||||||
// 6-7. (skipped, only support rsaEncryption for interoperability)
|
// 6-7. (skipped, only support rsaEncryption for interoperability)
|
||||||
if alg != RSA_ENCRYPTION_OID {
|
if alg != RSA_ENCRYPTION_OID {
|
||||||
return Err(data_error("unsupported algorithm"));
|
return Err(ImportKeyError::UnsupportedAlgorithm);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 8-9.
|
// 8-9.
|
||||||
let private_key =
|
let private_key =
|
||||||
rsa::pkcs1::RsaPrivateKey::from_der(pk_info.private_key)
|
rsa::pkcs1::RsaPrivateKey::from_der(pk_info.private_key)?;
|
||||||
.map_err(|e| data_error(e.to_string()))?;
|
|
||||||
|
|
||||||
let bytes_consumed = private_key
|
let bytes_consumed = private_key.encoded_len()?;
|
||||||
.encoded_len()
|
|
||||||
.map_err(|e| data_error(e.to_string()))?;
|
|
||||||
|
|
||||||
if bytes_consumed
|
if bytes_consumed
|
||||||
!= rsa::pkcs1::der::Length::new(pk_info.private_key.len() as u16)
|
!= rsa::pkcs1::der::Length::new(pk_info.private_key.len() as u16)
|
||||||
{
|
{
|
||||||
return Err(data_error("private key is invalid (too long)"));
|
return Err(ImportKeyError::PrivateKeyTooLong);
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = pk_info.private_key.to_vec().into();
|
let data = pk_info.private_key.to_vec().into();
|
||||||
|
@ -383,43 +430,39 @@ fn import_key_rsapss(
|
||||||
KeyData::JwkPublicRsa { .. } | KeyData::JwkPrivateRsa { .. } => {
|
KeyData::JwkPublicRsa { .. } | KeyData::JwkPrivateRsa { .. } => {
|
||||||
import_key_rsa_jwk(key_data)
|
import_key_rsa_jwk(key_data)
|
||||||
}
|
}
|
||||||
_ => Err(unsupported_format()),
|
_ => Err(SharedError::UnsupportedFormat.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_key_rsaoaep(
|
fn import_key_rsaoaep(
|
||||||
key_data: KeyData,
|
key_data: KeyData,
|
||||||
) -> Result<ImportKeyResult, deno_core::anyhow::Error> {
|
) -> Result<ImportKeyResult, ImportKeyError> {
|
||||||
match key_data {
|
match key_data {
|
||||||
KeyData::Spki(data) => {
|
KeyData::Spki(data) => {
|
||||||
// 2-3.
|
// 2-3.
|
||||||
let pk_info = spki::SubjectPublicKeyInfoRef::try_from(&*data)
|
let pk_info = spki::SubjectPublicKeyInfoRef::try_from(&*data)?;
|
||||||
.map_err(|e| data_error(e.to_string()))?;
|
|
||||||
|
|
||||||
// 4-5.
|
// 4-5.
|
||||||
let alg = pk_info.algorithm.oid;
|
let alg = pk_info.algorithm.oid;
|
||||||
|
|
||||||
// 6-7. (skipped, only support rsaEncryption for interoperability)
|
// 6-7. (skipped, only support rsaEncryption for interoperability)
|
||||||
if alg != RSA_ENCRYPTION_OID {
|
if alg != RSA_ENCRYPTION_OID {
|
||||||
return Err(data_error("unsupported algorithm"));
|
return Err(ImportKeyError::UnsupportedAlgorithm);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 8-9.
|
// 8-9.
|
||||||
let public_key = rsa::pkcs1::RsaPublicKey::from_der(
|
let public_key = rsa::pkcs1::RsaPublicKey::from_der(
|
||||||
pk_info.subject_public_key.raw_bytes(),
|
pk_info.subject_public_key.raw_bytes(),
|
||||||
)
|
)?;
|
||||||
.map_err(|e| data_error(e.to_string()))?;
|
|
||||||
|
|
||||||
let bytes_consumed = public_key
|
let bytes_consumed = public_key.encoded_len()?;
|
||||||
.encoded_len()
|
|
||||||
.map_err(|e| data_error(e.to_string()))?;
|
|
||||||
|
|
||||||
if bytes_consumed
|
if bytes_consumed
|
||||||
!= rsa::pkcs1::der::Length::new(
|
!= rsa::pkcs1::der::Length::new(
|
||||||
pk_info.subject_public_key.raw_bytes().len() as u16,
|
pk_info.subject_public_key.raw_bytes().len() as u16,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return Err(data_error("public key is invalid (too long)"));
|
return Err(ImportKeyError::PublicKeyTooLong);
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = pk_info.subject_public_key.raw_bytes().to_vec().into();
|
let data = pk_info.subject_public_key.raw_bytes().to_vec().into();
|
||||||
|
@ -435,30 +478,26 @@ fn import_key_rsaoaep(
|
||||||
}
|
}
|
||||||
KeyData::Pkcs8(data) => {
|
KeyData::Pkcs8(data) => {
|
||||||
// 2-3.
|
// 2-3.
|
||||||
let pk_info = PrivateKeyInfo::from_der(&data)
|
let pk_info = PrivateKeyInfo::from_der(&data)?;
|
||||||
.map_err(|e| data_error(e.to_string()))?;
|
|
||||||
|
|
||||||
// 4-5.
|
// 4-5.
|
||||||
let alg = pk_info.algorithm.oid;
|
let alg = pk_info.algorithm.oid;
|
||||||
|
|
||||||
// 6-7. (skipped, only support rsaEncryption for interoperability)
|
// 6-7. (skipped, only support rsaEncryption for interoperability)
|
||||||
if alg != RSA_ENCRYPTION_OID {
|
if alg != RSA_ENCRYPTION_OID {
|
||||||
return Err(data_error("unsupported algorithm"));
|
return Err(ImportKeyError::UnsupportedAlgorithm);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 8-9.
|
// 8-9.
|
||||||
let private_key =
|
let private_key =
|
||||||
rsa::pkcs1::RsaPrivateKey::from_der(pk_info.private_key)
|
rsa::pkcs1::RsaPrivateKey::from_der(pk_info.private_key)?;
|
||||||
.map_err(|e| data_error(e.to_string()))?;
|
|
||||||
|
|
||||||
let bytes_consumed = private_key
|
let bytes_consumed = private_key.encoded_len()?;
|
||||||
.encoded_len()
|
|
||||||
.map_err(|e| data_error(e.to_string()))?;
|
|
||||||
|
|
||||||
if bytes_consumed
|
if bytes_consumed
|
||||||
!= rsa::pkcs1::der::Length::new(pk_info.private_key.len() as u16)
|
!= rsa::pkcs1::der::Length::new(pk_info.private_key.len() as u16)
|
||||||
{
|
{
|
||||||
return Err(data_error("private key is invalid (too long)"));
|
return Err(ImportKeyError::PrivateKeyTooLong);
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = pk_info.private_key.to_vec().into();
|
let data = pk_info.private_key.to_vec().into();
|
||||||
|
@ -475,14 +514,14 @@ fn import_key_rsaoaep(
|
||||||
KeyData::JwkPublicRsa { .. } | KeyData::JwkPrivateRsa { .. } => {
|
KeyData::JwkPublicRsa { .. } | KeyData::JwkPrivateRsa { .. } => {
|
||||||
import_key_rsa_jwk(key_data)
|
import_key_rsa_jwk(key_data)
|
||||||
}
|
}
|
||||||
_ => Err(unsupported_format()),
|
_ => Err(SharedError::UnsupportedFormat.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_b64url_to_field_bytes<C: elliptic_curve::Curve>(
|
fn decode_b64url_to_field_bytes<C: elliptic_curve::Curve>(
|
||||||
b64: &str,
|
b64: &str,
|
||||||
) -> Result<elliptic_curve::FieldBytes<C>, deno_core::anyhow::Error> {
|
) -> Result<elliptic_curve::FieldBytes<C>, ImportKeyError> {
|
||||||
jwt_b64_int_or_err!(val, b64, "invalid b64 coordinate");
|
jwt_b64_int_or_err!(val, b64, InvalidB64Coordinate);
|
||||||
|
|
||||||
let mut bytes = elliptic_curve::FieldBytes::<C>::default();
|
let mut bytes = elliptic_curve::FieldBytes::<C>::default();
|
||||||
let original_bytes = val.as_bytes();
|
let original_bytes = val.as_bytes();
|
||||||
|
@ -495,7 +534,7 @@ fn decode_b64url_to_field_bytes<C: elliptic_curve::Curve>(
|
||||||
let val = new_bytes.as_slice();
|
let val = new_bytes.as_slice();
|
||||||
|
|
||||||
if val.len() != bytes.len() {
|
if val.len() != bytes.len() {
|
||||||
return Err(data_error("invalid b64 coordinate"));
|
return Err(ImportKeyError::InvalidB64Coordinate);
|
||||||
}
|
}
|
||||||
bytes.copy_from_slice(val);
|
bytes.copy_from_slice(val);
|
||||||
|
|
||||||
|
@ -506,7 +545,7 @@ fn import_key_ec_jwk_to_point(
|
||||||
x: String,
|
x: String,
|
||||||
y: String,
|
y: String,
|
||||||
named_curve: EcNamedCurve,
|
named_curve: EcNamedCurve,
|
||||||
) -> Result<Vec<u8>, deno_core::anyhow::Error> {
|
) -> Result<Vec<u8>, ImportKeyError> {
|
||||||
let point_bytes = match named_curve {
|
let point_bytes = match named_curve {
|
||||||
EcNamedCurve::P256 => {
|
EcNamedCurve::P256 => {
|
||||||
let x = decode_b64url_to_field_bytes::<p256::NistP256>(&x)?;
|
let x = decode_b64url_to_field_bytes::<p256::NistP256>(&x)?;
|
||||||
|
@ -534,7 +573,7 @@ fn import_key_ec_jwk_to_point(
|
||||||
fn import_key_ec_jwk(
|
fn import_key_ec_jwk(
|
||||||
key_data: KeyData,
|
key_data: KeyData,
|
||||||
named_curve: EcNamedCurve,
|
named_curve: EcNamedCurve,
|
||||||
) -> Result<ImportKeyResult, deno_core::anyhow::Error> {
|
) -> Result<ImportKeyResult, ImportKeyError> {
|
||||||
match key_data {
|
match key_data {
|
||||||
KeyData::JwkPublicEc { x, y } => {
|
KeyData::JwkPublicEc { x, y } => {
|
||||||
let point_bytes = import_key_ec_jwk_to_point(x, y, named_curve)?;
|
let point_bytes = import_key_ec_jwk_to_point(x, y, named_curve)?;
|
||||||
|
@ -550,21 +589,21 @@ fn import_key_ec_jwk(
|
||||||
let pk = p256::SecretKey::from_bytes(&d)?;
|
let pk = p256::SecretKey::from_bytes(&d)?;
|
||||||
|
|
||||||
pk.to_pkcs8_der()
|
pk.to_pkcs8_der()
|
||||||
.map_err(|_| data_error("invalid JWK private key"))?
|
.map_err(|_| ImportKeyError::InvalidJWKPrivateKey)?
|
||||||
}
|
}
|
||||||
EcNamedCurve::P384 => {
|
EcNamedCurve::P384 => {
|
||||||
let d = decode_b64url_to_field_bytes::<p384::NistP384>(&d)?;
|
let d = decode_b64url_to_field_bytes::<p384::NistP384>(&d)?;
|
||||||
let pk = p384::SecretKey::from_bytes(&d)?;
|
let pk = p384::SecretKey::from_bytes(&d)?;
|
||||||
|
|
||||||
pk.to_pkcs8_der()
|
pk.to_pkcs8_der()
|
||||||
.map_err(|_| data_error("invalid JWK private key"))?
|
.map_err(|_| ImportKeyError::InvalidJWKPrivateKey)?
|
||||||
}
|
}
|
||||||
EcNamedCurve::P521 => {
|
EcNamedCurve::P521 => {
|
||||||
let d = decode_b64url_to_field_bytes::<p521::NistP521>(&d)?;
|
let d = decode_b64url_to_field_bytes::<p521::NistP521>(&d)?;
|
||||||
let pk = p521::SecretKey::from_bytes(&d)?;
|
let pk = p521::SecretKey::from_bytes(&d)?;
|
||||||
|
|
||||||
pk.to_pkcs8_der()
|
pk.to_pkcs8_der()
|
||||||
.map_err(|_| data_error("invalid JWK private key"))?
|
.map_err(|_| ImportKeyError::InvalidJWKPrivateKey)?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -595,7 +634,7 @@ impl<'a> TryFrom<spki::der::asn1::AnyRef<'a>> for ECParametersSpki {
|
||||||
fn import_key_ec(
|
fn import_key_ec(
|
||||||
key_data: KeyData,
|
key_data: KeyData,
|
||||||
named_curve: EcNamedCurve,
|
named_curve: EcNamedCurve,
|
||||||
) -> Result<ImportKeyResult, AnyError> {
|
) -> Result<ImportKeyResult, ImportKeyError> {
|
||||||
match key_data {
|
match key_data {
|
||||||
KeyData::Raw(data) => {
|
KeyData::Raw(data) => {
|
||||||
// The point is parsed and validated, ultimately the original data is
|
// The point is parsed and validated, ultimately the original data is
|
||||||
|
@ -604,28 +643,28 @@ fn import_key_ec(
|
||||||
EcNamedCurve::P256 => {
|
EcNamedCurve::P256 => {
|
||||||
// 1-2.
|
// 1-2.
|
||||||
let point = p256::EncodedPoint::from_bytes(&data)
|
let point = p256::EncodedPoint::from_bytes(&data)
|
||||||
.map_err(|_| data_error("invalid P-256 elliptic curve point"))?;
|
.map_err(|_| ImportKeyError::InvalidP256ECPoint)?;
|
||||||
// 3.
|
// 3.
|
||||||
if point.is_identity() {
|
if point.is_identity() {
|
||||||
return Err(data_error("invalid P-256 elliptic curve point"));
|
return Err(ImportKeyError::InvalidP256ECPoint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EcNamedCurve::P384 => {
|
EcNamedCurve::P384 => {
|
||||||
// 1-2.
|
// 1-2.
|
||||||
let point = p384::EncodedPoint::from_bytes(&data)
|
let point = p384::EncodedPoint::from_bytes(&data)
|
||||||
.map_err(|_| data_error("invalid P-384 elliptic curve point"))?;
|
.map_err(|_| ImportKeyError::InvalidP384ECPoint)?;
|
||||||
// 3.
|
// 3.
|
||||||
if point.is_identity() {
|
if point.is_identity() {
|
||||||
return Err(data_error("invalid P-384 elliptic curve point"));
|
return Err(ImportKeyError::InvalidP384ECPoint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EcNamedCurve::P521 => {
|
EcNamedCurve::P521 => {
|
||||||
// 1-2.
|
// 1-2.
|
||||||
let point = p521::EncodedPoint::from_bytes(&data)
|
let point = p521::EncodedPoint::from_bytes(&data)
|
||||||
.map_err(|_| data_error("invalid P-521 elliptic curve point"))?;
|
.map_err(|_| ImportKeyError::InvalidP521ECPoint)?;
|
||||||
// 3.
|
// 3.
|
||||||
if point.is_identity() {
|
if point.is_identity() {
|
||||||
return Err(data_error("invalid P-521 elliptic curve point"));
|
return Err(ImportKeyError::InvalidP521ECPoint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -635,11 +674,11 @@ fn import_key_ec(
|
||||||
}
|
}
|
||||||
KeyData::Pkcs8(data) => {
|
KeyData::Pkcs8(data) => {
|
||||||
let pk = PrivateKeyInfo::from_der(data.as_ref())
|
let pk = PrivateKeyInfo::from_der(data.as_ref())
|
||||||
.map_err(|_| data_error("expected valid PKCS#8 data"))?;
|
.map_err(|_| ImportKeyError::ExpectedValidPkcs8Data)?;
|
||||||
let named_curve_alg = pk
|
let named_curve_alg = pk
|
||||||
.algorithm
|
.algorithm
|
||||||
.parameters
|
.parameters
|
||||||
.ok_or_else(|| data_error("malformed parameters"))?
|
.ok_or(ImportKeyError::MalformedParameters)?
|
||||||
.try_into()
|
.try_into()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -654,7 +693,7 @@ fn import_key_ec(
|
||||||
};
|
};
|
||||||
|
|
||||||
if pk_named_curve != Some(named_curve) {
|
if pk_named_curve != Some(named_curve) {
|
||||||
return Err(data_error("curve mismatch"));
|
return Err(ImportKeyError::CurveMismatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ImportKeyResult::Ec {
|
Ok(ImportKeyResult::Ec {
|
||||||
|
@ -663,14 +702,13 @@ fn import_key_ec(
|
||||||
}
|
}
|
||||||
KeyData::Spki(data) => {
|
KeyData::Spki(data) => {
|
||||||
// 2-3.
|
// 2-3.
|
||||||
let pk_info = spki::SubjectPublicKeyInfoRef::try_from(&*data)
|
let pk_info = spki::SubjectPublicKeyInfoRef::try_from(&*data)?;
|
||||||
.map_err(|e| data_error(e.to_string()))?;
|
|
||||||
|
|
||||||
// 4.
|
// 4.
|
||||||
let alg = pk_info.algorithm.oid;
|
let alg = pk_info.algorithm.oid;
|
||||||
// id-ecPublicKey
|
// id-ecPublicKey
|
||||||
if alg != elliptic_curve::ALGORITHM_OID {
|
if alg != elliptic_curve::ALGORITHM_OID {
|
||||||
return Err(data_error("unsupported algorithm"));
|
return Err(ImportKeyError::UnsupportedAlgorithm);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5-7.
|
// 5-7.
|
||||||
|
@ -678,9 +716,9 @@ fn import_key_ec(
|
||||||
pk_info
|
pk_info
|
||||||
.algorithm
|
.algorithm
|
||||||
.parameters
|
.parameters
|
||||||
.ok_or_else(|| data_error("malformed parameters"))?,
|
.ok_or(ImportKeyError::MalformedParameters)?,
|
||||||
)
|
)
|
||||||
.map_err(|_| data_error("malformed parameters"))?;
|
.map_err(|_| ImportKeyError::MalformedParameters)?;
|
||||||
|
|
||||||
// 8-9.
|
// 8-9.
|
||||||
let named_curve_alg = params.named_curve_alg;
|
let named_curve_alg = params.named_curve_alg;
|
||||||
|
@ -704,36 +742,30 @@ fn import_key_ec(
|
||||||
|
|
||||||
let bytes_consumed = match named_curve {
|
let bytes_consumed = match named_curve {
|
||||||
EcNamedCurve::P256 => {
|
EcNamedCurve::P256 => {
|
||||||
let point =
|
let point = p256::EncodedPoint::from_bytes(&*encoded_key)
|
||||||
p256::EncodedPoint::from_bytes(&*encoded_key).map_err(|_| {
|
.map_err(|_| ImportKeyError::InvalidP256ECSPKIData)?;
|
||||||
data_error("invalid P-256 elliptic curve SPKI data")
|
|
||||||
})?;
|
|
||||||
if point.is_identity() {
|
if point.is_identity() {
|
||||||
return Err(data_error("invalid P-256 elliptic curve point"));
|
return Err(ImportKeyError::InvalidP256ECPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
point.as_bytes().len()
|
point.as_bytes().len()
|
||||||
}
|
}
|
||||||
EcNamedCurve::P384 => {
|
EcNamedCurve::P384 => {
|
||||||
let point =
|
let point = p384::EncodedPoint::from_bytes(&*encoded_key)
|
||||||
p384::EncodedPoint::from_bytes(&*encoded_key).map_err(|_| {
|
.map_err(|_| ImportKeyError::InvalidP384ECSPKIData)?;
|
||||||
data_error("invalid P-384 elliptic curve SPKI data")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
if point.is_identity() {
|
if point.is_identity() {
|
||||||
return Err(data_error("invalid P-384 elliptic curve point"));
|
return Err(ImportKeyError::InvalidP384ECPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
point.as_bytes().len()
|
point.as_bytes().len()
|
||||||
}
|
}
|
||||||
EcNamedCurve::P521 => {
|
EcNamedCurve::P521 => {
|
||||||
let point =
|
let point = p521::EncodedPoint::from_bytes(&*encoded_key)
|
||||||
p521::EncodedPoint::from_bytes(&*encoded_key).map_err(|_| {
|
.map_err(|_| ImportKeyError::InvalidP521ECSPKIData)?;
|
||||||
data_error("invalid P-521 elliptic curve SPKI data")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
if point.is_identity() {
|
if point.is_identity() {
|
||||||
return Err(data_error("invalid P-521 elliptic curve point"));
|
return Err(ImportKeyError::InvalidP521ECPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
point.as_bytes().len()
|
point.as_bytes().len()
|
||||||
|
@ -741,15 +773,15 @@ fn import_key_ec(
|
||||||
};
|
};
|
||||||
|
|
||||||
if bytes_consumed != pk_info.subject_public_key.raw_bytes().len() {
|
if bytes_consumed != pk_info.subject_public_key.raw_bytes().len() {
|
||||||
return Err(data_error("public key is invalid (too long)"));
|
return Err(ImportKeyError::PublicKeyTooLong);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 11.
|
// 11.
|
||||||
if named_curve != pk_named_curve {
|
if named_curve != pk_named_curve {
|
||||||
return Err(data_error("curve mismatch"));
|
return Err(ImportKeyError::CurveMismatch);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(data_error("Unsupported named curve"));
|
return Err(ImportKeyError::UnsupportedNamedCurve);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ImportKeyResult::Ec {
|
Ok(ImportKeyResult::Ec {
|
||||||
|
@ -759,34 +791,38 @@ fn import_key_ec(
|
||||||
KeyData::JwkPublicEc { .. } | KeyData::JwkPrivateEc { .. } => {
|
KeyData::JwkPublicEc { .. } | KeyData::JwkPrivateEc { .. } => {
|
||||||
import_key_ec_jwk(key_data, named_curve)
|
import_key_ec_jwk(key_data, named_curve)
|
||||||
}
|
}
|
||||||
_ => Err(unsupported_format()),
|
_ => Err(SharedError::UnsupportedFormat.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_key_aes(key_data: KeyData) -> Result<ImportKeyResult, AnyError> {
|
fn import_key_aes(
|
||||||
|
key_data: KeyData,
|
||||||
|
) -> Result<ImportKeyResult, ImportKeyError> {
|
||||||
Ok(match key_data {
|
Ok(match key_data {
|
||||||
KeyData::JwkSecret { k } => {
|
KeyData::JwkSecret { k } => {
|
||||||
let data = BASE64_URL_SAFE_FORGIVING
|
let data = BASE64_URL_SAFE_FORGIVING
|
||||||
.decode(k)
|
.decode(k)
|
||||||
.map_err(|_| data_error("invalid key data"))?;
|
.map_err(|_| ImportKeyError::InvalidKeyData)?;
|
||||||
ImportKeyResult::Hmac {
|
ImportKeyResult::Hmac {
|
||||||
raw_data: RustRawKeyData::Secret(data.into()),
|
raw_data: RustRawKeyData::Secret(data.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => return Err(unsupported_format()),
|
_ => return Err(SharedError::UnsupportedFormat.into()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_key_hmac(key_data: KeyData) -> Result<ImportKeyResult, AnyError> {
|
fn import_key_hmac(
|
||||||
|
key_data: KeyData,
|
||||||
|
) -> Result<ImportKeyResult, ImportKeyError> {
|
||||||
Ok(match key_data {
|
Ok(match key_data {
|
||||||
KeyData::JwkSecret { k } => {
|
KeyData::JwkSecret { k } => {
|
||||||
let data = BASE64_URL_SAFE_FORGIVING
|
let data = BASE64_URL_SAFE_FORGIVING
|
||||||
.decode(k)
|
.decode(k)
|
||||||
.map_err(|_| data_error("invalid key data"))?;
|
.map_err(|_| ImportKeyError::InvalidKeyData)?;
|
||||||
ImportKeyResult::Hmac {
|
ImportKeyResult::Hmac {
|
||||||
raw_data: RustRawKeyData::Secret(data.into()),
|
raw_data: RustRawKeyData::Secret(data.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => return Err(unsupported_format()),
|
_ => return Err(SharedError::UnsupportedFormat.into()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,7 @@ use aes_kw::KekAes256;
|
||||||
|
|
||||||
use base64::prelude::BASE64_URL_SAFE_NO_PAD;
|
use base64::prelude::BASE64_URL_SAFE_NO_PAD;
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
use deno_core::error::custom_error;
|
|
||||||
use deno_core::error::not_supported;
|
use deno_core::error::not_supported;
|
||||||
use deno_core::error::type_error;
|
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::op2;
|
use deno_core::op2;
|
||||||
use deno_core::ToJsBuffer;
|
use deno_core::ToJsBuffer;
|
||||||
|
|
||||||
|
@ -17,7 +14,6 @@ use deno_core::unsync::spawn_blocking;
|
||||||
use deno_core::JsBuffer;
|
use deno_core::JsBuffer;
|
||||||
use deno_core::OpState;
|
use deno_core::OpState;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use shared::operation_error;
|
|
||||||
|
|
||||||
use p256::elliptic_curve::sec1::FromEncodedPoint;
|
use p256::elliptic_curve::sec1::FromEncodedPoint;
|
||||||
use p256::pkcs8::DecodePrivateKey;
|
use p256::pkcs8::DecodePrivateKey;
|
||||||
|
@ -67,15 +63,24 @@ mod x25519;
|
||||||
mod x448;
|
mod x448;
|
||||||
|
|
||||||
pub use crate::decrypt::op_crypto_decrypt;
|
pub use crate::decrypt::op_crypto_decrypt;
|
||||||
|
pub use crate::decrypt::DecryptError;
|
||||||
|
pub use crate::ed25519::Ed25519Error;
|
||||||
pub use crate::encrypt::op_crypto_encrypt;
|
pub use crate::encrypt::op_crypto_encrypt;
|
||||||
|
pub use crate::encrypt::EncryptError;
|
||||||
pub use crate::export_key::op_crypto_export_key;
|
pub use crate::export_key::op_crypto_export_key;
|
||||||
|
pub use crate::export_key::ExportKeyError;
|
||||||
pub use crate::generate_key::op_crypto_generate_key;
|
pub use crate::generate_key::op_crypto_generate_key;
|
||||||
|
pub use crate::generate_key::GenerateKeyError;
|
||||||
pub use crate::import_key::op_crypto_import_key;
|
pub use crate::import_key::op_crypto_import_key;
|
||||||
|
pub use crate::import_key::ImportKeyError;
|
||||||
use crate::key::Algorithm;
|
use crate::key::Algorithm;
|
||||||
use crate::key::CryptoHash;
|
use crate::key::CryptoHash;
|
||||||
use crate::key::CryptoNamedCurve;
|
use crate::key::CryptoNamedCurve;
|
||||||
use crate::key::HkdfOutput;
|
use crate::key::HkdfOutput;
|
||||||
|
pub use crate::shared::SharedError;
|
||||||
use crate::shared::V8RawKeyData;
|
use crate::shared::V8RawKeyData;
|
||||||
|
pub use crate::x25519::X25519Error;
|
||||||
|
pub use crate::x448::X448Error;
|
||||||
|
|
||||||
deno_core::extension!(deno_crypto,
|
deno_core::extension!(deno_crypto,
|
||||||
deps = [ deno_webidl, deno_web ],
|
deps = [ deno_webidl, deno_web ],
|
||||||
|
@ -127,11 +132,63 @@ deno_core::extension!(deno_crypto,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error(transparent)]
|
||||||
|
General(#[from] SharedError),
|
||||||
|
#[error(transparent)]
|
||||||
|
JoinError(#[from] tokio::task::JoinError),
|
||||||
|
#[error(transparent)]
|
||||||
|
Der(#[from] rsa::pkcs1::der::Error),
|
||||||
|
#[error("Missing argument hash")]
|
||||||
|
MissingArgumentHash,
|
||||||
|
#[error("Missing argument saltLength")]
|
||||||
|
MissingArgumentSaltLength,
|
||||||
|
#[error("unsupported algorithm")]
|
||||||
|
UnsupportedAlgorithm,
|
||||||
|
#[error(transparent)]
|
||||||
|
KeyRejected(#[from] ring::error::KeyRejected),
|
||||||
|
#[error(transparent)]
|
||||||
|
RSA(#[from] rsa::Error),
|
||||||
|
#[error(transparent)]
|
||||||
|
Pkcs1(#[from] rsa::pkcs1::Error),
|
||||||
|
#[error(transparent)]
|
||||||
|
Unspecified(#[from] ring::error::Unspecified),
|
||||||
|
#[error("Invalid key format")]
|
||||||
|
InvalidKeyFormat,
|
||||||
|
#[error(transparent)]
|
||||||
|
P256Ecdsa(#[from] p256::ecdsa::Error),
|
||||||
|
#[error("Unexpected error decoding private key")]
|
||||||
|
DecodePrivateKey,
|
||||||
|
#[error("Missing argument publicKey")]
|
||||||
|
MissingArgumentPublicKey,
|
||||||
|
#[error("Missing argument namedCurve")]
|
||||||
|
MissingArgumentNamedCurve,
|
||||||
|
#[error("Missing argument info")]
|
||||||
|
MissingArgumentInfo,
|
||||||
|
#[error("The length provided for HKDF is too large")]
|
||||||
|
HKDFLengthTooLarge,
|
||||||
|
#[error(transparent)]
|
||||||
|
Base64Decode(#[from] base64::DecodeError),
|
||||||
|
#[error("Data must be multiple of 8 bytes")]
|
||||||
|
DataInvalidSize,
|
||||||
|
#[error("Invalid key length")]
|
||||||
|
InvalidKeyLength,
|
||||||
|
#[error("encryption error")]
|
||||||
|
EncryptionError,
|
||||||
|
#[error("decryption error - integrity check failed")]
|
||||||
|
DecryptionError,
|
||||||
|
#[error("The ArrayBufferView's byte length ({0}) exceeds the number of bytes of entropy available via this API (65536)")]
|
||||||
|
ArrayBufferViewLengthExceeded(usize),
|
||||||
|
#[error(transparent)]
|
||||||
|
Other(deno_core::error::AnyError),
|
||||||
|
}
|
||||||
|
|
||||||
#[op2]
|
#[op2]
|
||||||
#[serde]
|
#[serde]
|
||||||
pub fn op_crypto_base64url_decode(
|
pub fn op_crypto_base64url_decode(
|
||||||
#[string] data: String,
|
#[string] data: String,
|
||||||
) -> Result<ToJsBuffer, AnyError> {
|
) -> Result<ToJsBuffer, Error> {
|
||||||
let data: Vec<u8> = BASE64_URL_SAFE_NO_PAD.decode(data)?;
|
let data: Vec<u8> = BASE64_URL_SAFE_NO_PAD.decode(data)?;
|
||||||
Ok(data.into())
|
Ok(data.into())
|
||||||
}
|
}
|
||||||
|
@ -147,9 +204,9 @@ pub fn op_crypto_base64url_encode(#[buffer] data: JsBuffer) -> String {
|
||||||
pub fn op_crypto_get_random_values(
|
pub fn op_crypto_get_random_values(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[buffer] out: &mut [u8],
|
#[buffer] out: &mut [u8],
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), Error> {
|
||||||
if out.len() > 65536 {
|
if out.len() > 65536 {
|
||||||
return Err(custom_error("DOMExceptionQuotaExceededError", format!("The ArrayBufferView's byte length ({}) exceeds the number of bytes of entropy available via this API (65536)", out.len())));
|
return Err(Error::ArrayBufferViewLengthExceeded(out.len()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let maybe_seeded_rng = state.try_borrow_mut::<StdRng>();
|
let maybe_seeded_rng = state.try_borrow_mut::<StdRng>();
|
||||||
|
@ -201,7 +258,7 @@ pub struct SignArg {
|
||||||
pub async fn op_crypto_sign_key(
|
pub async fn op_crypto_sign_key(
|
||||||
#[serde] args: SignArg,
|
#[serde] args: SignArg,
|
||||||
#[buffer] zero_copy: JsBuffer,
|
#[buffer] zero_copy: JsBuffer,
|
||||||
) -> Result<ToJsBuffer, AnyError> {
|
) -> Result<ToJsBuffer, Error> {
|
||||||
deno_core::unsync::spawn_blocking(move || {
|
deno_core::unsync::spawn_blocking(move || {
|
||||||
let data = &*zero_copy;
|
let data = &*zero_copy;
|
||||||
let algorithm = args.algorithm;
|
let algorithm = args.algorithm;
|
||||||
|
@ -210,10 +267,7 @@ pub async fn op_crypto_sign_key(
|
||||||
Algorithm::RsassaPkcs1v15 => {
|
Algorithm::RsassaPkcs1v15 => {
|
||||||
use rsa::pkcs1v15::SigningKey;
|
use rsa::pkcs1v15::SigningKey;
|
||||||
let private_key = RsaPrivateKey::from_pkcs1_der(&args.key.data)?;
|
let private_key = RsaPrivateKey::from_pkcs1_der(&args.key.data)?;
|
||||||
match args
|
match args.hash.ok_or_else(|| Error::MissingArgumentHash)? {
|
||||||
.hash
|
|
||||||
.ok_or_else(|| type_error("Missing argument hash".to_string()))?
|
|
||||||
{
|
|
||||||
CryptoHash::Sha1 => {
|
CryptoHash::Sha1 => {
|
||||||
let signing_key = SigningKey::<Sha1>::new(private_key);
|
let signing_key = SigningKey::<Sha1>::new(private_key);
|
||||||
signing_key.sign(data)
|
signing_key.sign(data)
|
||||||
|
@ -236,15 +290,13 @@ pub async fn op_crypto_sign_key(
|
||||||
Algorithm::RsaPss => {
|
Algorithm::RsaPss => {
|
||||||
let private_key = RsaPrivateKey::from_pkcs1_der(&args.key.data)?;
|
let private_key = RsaPrivateKey::from_pkcs1_der(&args.key.data)?;
|
||||||
|
|
||||||
let salt_len = args.salt_length.ok_or_else(|| {
|
let salt_len = args
|
||||||
type_error("Missing argument saltLength".to_string())
|
.salt_length
|
||||||
})? as usize;
|
.ok_or_else(|| Error::MissingArgumentSaltLength)?
|
||||||
|
as usize;
|
||||||
|
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
match args
|
match args.hash.ok_or_else(|| Error::MissingArgumentHash)? {
|
||||||
.hash
|
|
||||||
.ok_or_else(|| type_error("Missing argument hash".to_string()))?
|
|
||||||
{
|
|
||||||
CryptoHash::Sha1 => {
|
CryptoHash::Sha1 => {
|
||||||
let signing_key = Pss::new_with_salt::<Sha1>(salt_len);
|
let signing_key = Pss::new_with_salt::<Sha1>(salt_len);
|
||||||
let hashed = Sha1::digest(data);
|
let hashed = Sha1::digest(data);
|
||||||
|
@ -269,8 +321,10 @@ pub async fn op_crypto_sign_key(
|
||||||
.to_vec()
|
.to_vec()
|
||||||
}
|
}
|
||||||
Algorithm::Ecdsa => {
|
Algorithm::Ecdsa => {
|
||||||
let curve: &EcdsaSigningAlgorithm =
|
let curve: &EcdsaSigningAlgorithm = args
|
||||||
args.named_curve.ok_or_else(not_supported)?.into();
|
.named_curve
|
||||||
|
.ok_or_else(|| Error::Other(not_supported()))?
|
||||||
|
.into();
|
||||||
|
|
||||||
let rng = RingRand::SystemRandom::new();
|
let rng = RingRand::SystemRandom::new();
|
||||||
let key_pair = EcdsaKeyPair::from_pkcs8(curve, &args.key.data, &rng)?;
|
let key_pair = EcdsaKeyPair::from_pkcs8(curve, &args.key.data, &rng)?;
|
||||||
|
@ -279,7 +333,7 @@ pub async fn op_crypto_sign_key(
|
||||||
if let Some(hash) = args.hash {
|
if let Some(hash) = args.hash {
|
||||||
match hash {
|
match hash {
|
||||||
CryptoHash::Sha256 | CryptoHash::Sha384 => (),
|
CryptoHash::Sha256 | CryptoHash::Sha384 => (),
|
||||||
_ => return Err(type_error("Unsupported algorithm")),
|
_ => return Err(Error::UnsupportedAlgorithm),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -289,14 +343,17 @@ pub async fn op_crypto_sign_key(
|
||||||
signature.as_ref().to_vec()
|
signature.as_ref().to_vec()
|
||||||
}
|
}
|
||||||
Algorithm::Hmac => {
|
Algorithm::Hmac => {
|
||||||
let hash: HmacAlgorithm = args.hash.ok_or_else(not_supported)?.into();
|
let hash: HmacAlgorithm = args
|
||||||
|
.hash
|
||||||
|
.ok_or_else(|| Error::Other(not_supported()))?
|
||||||
|
.into();
|
||||||
|
|
||||||
let key = HmacKey::new(hash, &args.key.data);
|
let key = HmacKey::new(hash, &args.key.data);
|
||||||
|
|
||||||
let signature = ring::hmac::sign(&key, data);
|
let signature = ring::hmac::sign(&key, data);
|
||||||
signature.as_ref().to_vec()
|
signature.as_ref().to_vec()
|
||||||
}
|
}
|
||||||
_ => return Err(type_error("Unsupported algorithm".to_string())),
|
_ => return Err(Error::UnsupportedAlgorithm),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(signature.into())
|
Ok(signature.into())
|
||||||
|
@ -319,7 +376,7 @@ pub struct VerifyArg {
|
||||||
pub async fn op_crypto_verify_key(
|
pub async fn op_crypto_verify_key(
|
||||||
#[serde] args: VerifyArg,
|
#[serde] args: VerifyArg,
|
||||||
#[buffer] zero_copy: JsBuffer,
|
#[buffer] zero_copy: JsBuffer,
|
||||||
) -> Result<bool, AnyError> {
|
) -> Result<bool, Error> {
|
||||||
deno_core::unsync::spawn_blocking(move || {
|
deno_core::unsync::spawn_blocking(move || {
|
||||||
let data = &*zero_copy;
|
let data = &*zero_copy;
|
||||||
let algorithm = args.algorithm;
|
let algorithm = args.algorithm;
|
||||||
|
@ -330,10 +387,7 @@ pub async fn op_crypto_verify_key(
|
||||||
use rsa::pkcs1v15::VerifyingKey;
|
use rsa::pkcs1v15::VerifyingKey;
|
||||||
let public_key = read_rsa_public_key(args.key)?;
|
let public_key = read_rsa_public_key(args.key)?;
|
||||||
let signature: Signature = args.signature.as_ref().try_into()?;
|
let signature: Signature = args.signature.as_ref().try_into()?;
|
||||||
match args
|
match args.hash.ok_or_else(|| Error::MissingArgumentHash)? {
|
||||||
.hash
|
|
||||||
.ok_or_else(|| type_error("Missing argument hash".to_string()))?
|
|
||||||
{
|
|
||||||
CryptoHash::Sha1 => {
|
CryptoHash::Sha1 => {
|
||||||
let verifying_key = VerifyingKey::<Sha1>::new(public_key);
|
let verifying_key = VerifyingKey::<Sha1>::new(public_key);
|
||||||
verifying_key.verify(data, &signature).is_ok()
|
verifying_key.verify(data, &signature).is_ok()
|
||||||
|
@ -356,14 +410,12 @@ pub async fn op_crypto_verify_key(
|
||||||
let public_key = read_rsa_public_key(args.key)?;
|
let public_key = read_rsa_public_key(args.key)?;
|
||||||
let signature = args.signature.as_ref();
|
let signature = args.signature.as_ref();
|
||||||
|
|
||||||
let salt_len = args.salt_length.ok_or_else(|| {
|
let salt_len = args
|
||||||
type_error("Missing argument saltLength".to_string())
|
.salt_length
|
||||||
})? as usize;
|
.ok_or_else(|| Error::MissingArgumentSaltLength)?
|
||||||
|
as usize;
|
||||||
|
|
||||||
match args
|
match args.hash.ok_or_else(|| Error::MissingArgumentHash)? {
|
||||||
.hash
|
|
||||||
.ok_or_else(|| type_error("Missing argument hash".to_string()))?
|
|
||||||
{
|
|
||||||
CryptoHash::Sha1 => {
|
CryptoHash::Sha1 => {
|
||||||
let pss = Pss::new_with_salt::<Sha1>(salt_len);
|
let pss = Pss::new_with_salt::<Sha1>(salt_len);
|
||||||
let hashed = Sha1::digest(data);
|
let hashed = Sha1::digest(data);
|
||||||
|
@ -387,15 +439,22 @@ pub async fn op_crypto_verify_key(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Algorithm::Hmac => {
|
Algorithm::Hmac => {
|
||||||
let hash: HmacAlgorithm = args.hash.ok_or_else(not_supported)?.into();
|
let hash: HmacAlgorithm = args
|
||||||
|
.hash
|
||||||
|
.ok_or_else(|| Error::Other(not_supported()))?
|
||||||
|
.into();
|
||||||
let key = HmacKey::new(hash, &args.key.data);
|
let key = HmacKey::new(hash, &args.key.data);
|
||||||
ring::hmac::verify(&key, data, &args.signature).is_ok()
|
ring::hmac::verify(&key, data, &args.signature).is_ok()
|
||||||
}
|
}
|
||||||
Algorithm::Ecdsa => {
|
Algorithm::Ecdsa => {
|
||||||
let signing_alg: &EcdsaSigningAlgorithm =
|
let signing_alg: &EcdsaSigningAlgorithm = args
|
||||||
args.named_curve.ok_or_else(not_supported)?.into();
|
.named_curve
|
||||||
let verify_alg: &EcdsaVerificationAlgorithm =
|
.ok_or_else(|| Error::Other(not_supported()))?
|
||||||
args.named_curve.ok_or_else(not_supported)?.into();
|
.into();
|
||||||
|
let verify_alg: &EcdsaVerificationAlgorithm = args
|
||||||
|
.named_curve
|
||||||
|
.ok_or_else(|| Error::Other(not_supported()))?
|
||||||
|
.into();
|
||||||
|
|
||||||
let private_key;
|
let private_key;
|
||||||
|
|
||||||
|
@ -408,7 +467,7 @@ pub async fn op_crypto_verify_key(
|
||||||
private_key.public_key().as_ref()
|
private_key.public_key().as_ref()
|
||||||
}
|
}
|
||||||
KeyType::Public => &*args.key.data,
|
KeyType::Public => &*args.key.data,
|
||||||
_ => return Err(type_error("Invalid Key format".to_string())),
|
_ => return Err(Error::InvalidKeyFormat),
|
||||||
};
|
};
|
||||||
|
|
||||||
let public_key =
|
let public_key =
|
||||||
|
@ -416,7 +475,7 @@ pub async fn op_crypto_verify_key(
|
||||||
|
|
||||||
public_key.verify(data, &args.signature).is_ok()
|
public_key.verify(data, &args.signature).is_ok()
|
||||||
}
|
}
|
||||||
_ => return Err(type_error("Unsupported algorithm".to_string())),
|
_ => return Err(Error::UnsupportedAlgorithm),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(verification)
|
Ok(verification)
|
||||||
|
@ -444,70 +503,68 @@ pub struct DeriveKeyArg {
|
||||||
pub async fn op_crypto_derive_bits(
|
pub async fn op_crypto_derive_bits(
|
||||||
#[serde] args: DeriveKeyArg,
|
#[serde] args: DeriveKeyArg,
|
||||||
#[buffer] zero_copy: Option<JsBuffer>,
|
#[buffer] zero_copy: Option<JsBuffer>,
|
||||||
) -> Result<ToJsBuffer, AnyError> {
|
) -> Result<ToJsBuffer, Error> {
|
||||||
deno_core::unsync::spawn_blocking(move || {
|
deno_core::unsync::spawn_blocking(move || {
|
||||||
let algorithm = args.algorithm;
|
let algorithm = args.algorithm;
|
||||||
match algorithm {
|
match algorithm {
|
||||||
Algorithm::Pbkdf2 => {
|
Algorithm::Pbkdf2 => {
|
||||||
let zero_copy = zero_copy.ok_or_else(not_supported)?;
|
let zero_copy =
|
||||||
|
zero_copy.ok_or_else(|| Error::Other(not_supported()))?;
|
||||||
let salt = &*zero_copy;
|
let salt = &*zero_copy;
|
||||||
// The caller must validate these cases.
|
// The caller must validate these cases.
|
||||||
assert!(args.length > 0);
|
assert!(args.length > 0);
|
||||||
assert!(args.length % 8 == 0);
|
assert!(args.length % 8 == 0);
|
||||||
|
|
||||||
let algorithm = match args.hash.ok_or_else(not_supported)? {
|
let algorithm =
|
||||||
CryptoHash::Sha1 => pbkdf2::PBKDF2_HMAC_SHA1,
|
match args.hash.ok_or_else(|| Error::Other(not_supported()))? {
|
||||||
CryptoHash::Sha256 => pbkdf2::PBKDF2_HMAC_SHA256,
|
CryptoHash::Sha1 => pbkdf2::PBKDF2_HMAC_SHA1,
|
||||||
CryptoHash::Sha384 => pbkdf2::PBKDF2_HMAC_SHA384,
|
CryptoHash::Sha256 => pbkdf2::PBKDF2_HMAC_SHA256,
|
||||||
CryptoHash::Sha512 => pbkdf2::PBKDF2_HMAC_SHA512,
|
CryptoHash::Sha384 => pbkdf2::PBKDF2_HMAC_SHA384,
|
||||||
};
|
CryptoHash::Sha512 => pbkdf2::PBKDF2_HMAC_SHA512,
|
||||||
|
};
|
||||||
|
|
||||||
// This will never panic. We have already checked length earlier.
|
// This will never panic. We have already checked length earlier.
|
||||||
let iterations =
|
let iterations = NonZeroU32::new(
|
||||||
NonZeroU32::new(args.iterations.ok_or_else(not_supported)?).unwrap();
|
args
|
||||||
|
.iterations
|
||||||
|
.ok_or_else(|| Error::Other(not_supported()))?,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
let secret = args.key.data;
|
let secret = args.key.data;
|
||||||
let mut out = vec![0; args.length / 8];
|
let mut out = vec![0; args.length / 8];
|
||||||
pbkdf2::derive(algorithm, iterations, salt, &secret, &mut out);
|
pbkdf2::derive(algorithm, iterations, salt, &secret, &mut out);
|
||||||
Ok(out.into())
|
Ok(out.into())
|
||||||
}
|
}
|
||||||
Algorithm::Ecdh => {
|
Algorithm::Ecdh => {
|
||||||
let named_curve = args.named_curve.ok_or_else(|| {
|
let named_curve = args
|
||||||
type_error("Missing argument namedCurve".to_string())
|
.named_curve
|
||||||
})?;
|
.ok_or_else(|| Error::MissingArgumentNamedCurve)?;
|
||||||
|
|
||||||
let public_key = args
|
let public_key = args
|
||||||
.public_key
|
.public_key
|
||||||
.ok_or_else(|| type_error("Missing argument publicKey"))?;
|
.ok_or_else(|| Error::MissingArgumentPublicKey)?;
|
||||||
|
|
||||||
match named_curve {
|
match named_curve {
|
||||||
CryptoNamedCurve::P256 => {
|
CryptoNamedCurve::P256 => {
|
||||||
let secret_key = p256::SecretKey::from_pkcs8_der(&args.key.data)
|
let secret_key = p256::SecretKey::from_pkcs8_der(&args.key.data)
|
||||||
.map_err(|_| {
|
.map_err(|_| Error::DecodePrivateKey)?;
|
||||||
type_error("Unexpected error decoding private key")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let public_key = match public_key.r#type {
|
let public_key = match public_key.r#type {
|
||||||
KeyType::Private => {
|
KeyType::Private => {
|
||||||
p256::SecretKey::from_pkcs8_der(&public_key.data)
|
p256::SecretKey::from_pkcs8_der(&public_key.data)
|
||||||
.map_err(|_| {
|
.map_err(|_| Error::DecodePrivateKey)?
|
||||||
type_error("Unexpected error decoding private key")
|
|
||||||
})?
|
|
||||||
.public_key()
|
.public_key()
|
||||||
}
|
}
|
||||||
KeyType::Public => {
|
KeyType::Public => {
|
||||||
let point = p256::EncodedPoint::from_bytes(public_key.data)
|
let point = p256::EncodedPoint::from_bytes(public_key.data)
|
||||||
.map_err(|_| {
|
.map_err(|_| Error::DecodePrivateKey)?;
|
||||||
type_error("Unexpected error decoding private key")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let pk = p256::PublicKey::from_encoded_point(&point);
|
let pk = p256::PublicKey::from_encoded_point(&point);
|
||||||
// pk is a constant time Option.
|
// pk is a constant time Option.
|
||||||
if pk.is_some().into() {
|
if pk.is_some().into() {
|
||||||
pk.unwrap()
|
pk.unwrap()
|
||||||
} else {
|
} else {
|
||||||
return Err(type_error(
|
return Err(Error::DecodePrivateKey);
|
||||||
"Unexpected error decoding private key",
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
@ -523,32 +580,24 @@ pub async fn op_crypto_derive_bits(
|
||||||
}
|
}
|
||||||
CryptoNamedCurve::P384 => {
|
CryptoNamedCurve::P384 => {
|
||||||
let secret_key = p384::SecretKey::from_pkcs8_der(&args.key.data)
|
let secret_key = p384::SecretKey::from_pkcs8_der(&args.key.data)
|
||||||
.map_err(|_| {
|
.map_err(|_| Error::DecodePrivateKey)?;
|
||||||
type_error("Unexpected error decoding private key")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let public_key = match public_key.r#type {
|
let public_key = match public_key.r#type {
|
||||||
KeyType::Private => {
|
KeyType::Private => {
|
||||||
p384::SecretKey::from_pkcs8_der(&public_key.data)
|
p384::SecretKey::from_pkcs8_der(&public_key.data)
|
||||||
.map_err(|_| {
|
.map_err(|_| Error::DecodePrivateKey)?
|
||||||
type_error("Unexpected error decoding private key")
|
|
||||||
})?
|
|
||||||
.public_key()
|
.public_key()
|
||||||
}
|
}
|
||||||
KeyType::Public => {
|
KeyType::Public => {
|
||||||
let point = p384::EncodedPoint::from_bytes(public_key.data)
|
let point = p384::EncodedPoint::from_bytes(public_key.data)
|
||||||
.map_err(|_| {
|
.map_err(|_| Error::DecodePrivateKey)?;
|
||||||
type_error("Unexpected error decoding private key")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let pk = p384::PublicKey::from_encoded_point(&point);
|
let pk = p384::PublicKey::from_encoded_point(&point);
|
||||||
// pk is a constant time Option.
|
// pk is a constant time Option.
|
||||||
if pk.is_some().into() {
|
if pk.is_some().into() {
|
||||||
pk.unwrap()
|
pk.unwrap()
|
||||||
} else {
|
} else {
|
||||||
return Err(type_error(
|
return Err(Error::DecodePrivateKey);
|
||||||
"Unexpected error decoding private key",
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
@ -565,18 +614,18 @@ pub async fn op_crypto_derive_bits(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Algorithm::Hkdf => {
|
Algorithm::Hkdf => {
|
||||||
let zero_copy = zero_copy.ok_or_else(not_supported)?;
|
let zero_copy =
|
||||||
|
zero_copy.ok_or_else(|| Error::Other(not_supported()))?;
|
||||||
let salt = &*zero_copy;
|
let salt = &*zero_copy;
|
||||||
let algorithm = match args.hash.ok_or_else(not_supported)? {
|
let algorithm =
|
||||||
CryptoHash::Sha1 => hkdf::HKDF_SHA1_FOR_LEGACY_USE_ONLY,
|
match args.hash.ok_or_else(|| Error::Other(not_supported()))? {
|
||||||
CryptoHash::Sha256 => hkdf::HKDF_SHA256,
|
CryptoHash::Sha1 => hkdf::HKDF_SHA1_FOR_LEGACY_USE_ONLY,
|
||||||
CryptoHash::Sha384 => hkdf::HKDF_SHA384,
|
CryptoHash::Sha256 => hkdf::HKDF_SHA256,
|
||||||
CryptoHash::Sha512 => hkdf::HKDF_SHA512,
|
CryptoHash::Sha384 => hkdf::HKDF_SHA384,
|
||||||
};
|
CryptoHash::Sha512 => hkdf::HKDF_SHA512,
|
||||||
|
};
|
||||||
|
|
||||||
let info = args
|
let info = args.info.ok_or_else(|| Error::MissingArgumentInfo)?;
|
||||||
.info
|
|
||||||
.ok_or_else(|| type_error("Missing argument info".to_string()))?;
|
|
||||||
// IKM
|
// IKM
|
||||||
let secret = args.key.data;
|
let secret = args.key.data;
|
||||||
// L
|
// L
|
||||||
|
@ -585,23 +634,20 @@ pub async fn op_crypto_derive_bits(
|
||||||
let salt = hkdf::Salt::new(algorithm, salt);
|
let salt = hkdf::Salt::new(algorithm, salt);
|
||||||
let prk = salt.extract(&secret);
|
let prk = salt.extract(&secret);
|
||||||
let info = &[&*info];
|
let info = &[&*info];
|
||||||
let okm = prk.expand(info, HkdfOutput(length)).map_err(|_e| {
|
let okm = prk
|
||||||
custom_error(
|
.expand(info, HkdfOutput(length))
|
||||||
"DOMExceptionOperationError",
|
.map_err(|_e| Error::HKDFLengthTooLarge)?;
|
||||||
"The length provided for HKDF is too large",
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
let mut r = vec![0u8; length];
|
let mut r = vec![0u8; length];
|
||||||
okm.fill(&mut r)?;
|
okm.fill(&mut r)?;
|
||||||
Ok(r.into())
|
Ok(r.into())
|
||||||
}
|
}
|
||||||
_ => Err(type_error("Unsupported algorithm".to_string())),
|
_ => Err(Error::UnsupportedAlgorithm),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.await?
|
.await?
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_rsa_public_key(key_data: KeyData) -> Result<RsaPublicKey, AnyError> {
|
fn read_rsa_public_key(key_data: KeyData) -> Result<RsaPublicKey, Error> {
|
||||||
let public_key = match key_data.r#type {
|
let public_key = match key_data.r#type {
|
||||||
KeyType::Private => {
|
KeyType::Private => {
|
||||||
RsaPrivateKey::from_pkcs1_der(&key_data.data)?.to_public_key()
|
RsaPrivateKey::from_pkcs1_der(&key_data.data)?.to_public_key()
|
||||||
|
@ -614,7 +660,7 @@ fn read_rsa_public_key(key_data: KeyData) -> Result<RsaPublicKey, AnyError> {
|
||||||
|
|
||||||
#[op2]
|
#[op2]
|
||||||
#[string]
|
#[string]
|
||||||
pub fn op_crypto_random_uuid(state: &mut OpState) -> Result<String, AnyError> {
|
pub fn op_crypto_random_uuid(state: &mut OpState) -> Result<String, Error> {
|
||||||
let maybe_seeded_rng = state.try_borrow_mut::<StdRng>();
|
let maybe_seeded_rng = state.try_borrow_mut::<StdRng>();
|
||||||
let uuid = if let Some(seeded_rng) = maybe_seeded_rng {
|
let uuid = if let Some(seeded_rng) = maybe_seeded_rng {
|
||||||
let mut bytes = [0u8; 16];
|
let mut bytes = [0u8; 16];
|
||||||
|
@ -635,7 +681,7 @@ pub fn op_crypto_random_uuid(state: &mut OpState) -> Result<String, AnyError> {
|
||||||
pub async fn op_crypto_subtle_digest(
|
pub async fn op_crypto_subtle_digest(
|
||||||
#[serde] algorithm: CryptoHash,
|
#[serde] algorithm: CryptoHash,
|
||||||
#[buffer] data: JsBuffer,
|
#[buffer] data: JsBuffer,
|
||||||
) -> Result<ToJsBuffer, AnyError> {
|
) -> Result<ToJsBuffer, Error> {
|
||||||
let output = spawn_blocking(move || {
|
let output = spawn_blocking(move || {
|
||||||
digest::digest(algorithm.into(), &data)
|
digest::digest(algorithm.into(), &data)
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
@ -659,7 +705,7 @@ pub struct WrapUnwrapKeyArg {
|
||||||
pub fn op_crypto_wrap_key(
|
pub fn op_crypto_wrap_key(
|
||||||
#[serde] args: WrapUnwrapKeyArg,
|
#[serde] args: WrapUnwrapKeyArg,
|
||||||
#[buffer] data: JsBuffer,
|
#[buffer] data: JsBuffer,
|
||||||
) -> Result<ToJsBuffer, AnyError> {
|
) -> Result<ToJsBuffer, Error> {
|
||||||
let algorithm = args.algorithm;
|
let algorithm = args.algorithm;
|
||||||
|
|
||||||
match algorithm {
|
match algorithm {
|
||||||
|
@ -667,20 +713,20 @@ pub fn op_crypto_wrap_key(
|
||||||
let key = args.key.as_secret_key()?;
|
let key = args.key.as_secret_key()?;
|
||||||
|
|
||||||
if data.len() % 8 != 0 {
|
if data.len() % 8 != 0 {
|
||||||
return Err(type_error("Data must be multiple of 8 bytes"));
|
return Err(Error::DataInvalidSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
let wrapped_key = match key.len() {
|
let wrapped_key = match key.len() {
|
||||||
16 => KekAes128::new(key.into()).wrap_vec(&data),
|
16 => KekAes128::new(key.into()).wrap_vec(&data),
|
||||||
24 => KekAes192::new(key.into()).wrap_vec(&data),
|
24 => KekAes192::new(key.into()).wrap_vec(&data),
|
||||||
32 => KekAes256::new(key.into()).wrap_vec(&data),
|
32 => KekAes256::new(key.into()).wrap_vec(&data),
|
||||||
_ => return Err(type_error("Invalid key length")),
|
_ => return Err(Error::InvalidKeyLength),
|
||||||
}
|
}
|
||||||
.map_err(|_| operation_error("encryption error"))?;
|
.map_err(|_| Error::EncryptionError)?;
|
||||||
|
|
||||||
Ok(wrapped_key.into())
|
Ok(wrapped_key.into())
|
||||||
}
|
}
|
||||||
_ => Err(type_error("Unsupported algorithm")),
|
_ => Err(Error::UnsupportedAlgorithm),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -689,29 +735,27 @@ pub fn op_crypto_wrap_key(
|
||||||
pub fn op_crypto_unwrap_key(
|
pub fn op_crypto_unwrap_key(
|
||||||
#[serde] args: WrapUnwrapKeyArg,
|
#[serde] args: WrapUnwrapKeyArg,
|
||||||
#[buffer] data: JsBuffer,
|
#[buffer] data: JsBuffer,
|
||||||
) -> Result<ToJsBuffer, AnyError> {
|
) -> Result<ToJsBuffer, Error> {
|
||||||
let algorithm = args.algorithm;
|
let algorithm = args.algorithm;
|
||||||
match algorithm {
|
match algorithm {
|
||||||
Algorithm::AesKw => {
|
Algorithm::AesKw => {
|
||||||
let key = args.key.as_secret_key()?;
|
let key = args.key.as_secret_key()?;
|
||||||
|
|
||||||
if data.len() % 8 != 0 {
|
if data.len() % 8 != 0 {
|
||||||
return Err(type_error("Data must be multiple of 8 bytes"));
|
return Err(Error::DataInvalidSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
let unwrapped_key = match key.len() {
|
let unwrapped_key = match key.len() {
|
||||||
16 => KekAes128::new(key.into()).unwrap_vec(&data),
|
16 => KekAes128::new(key.into()).unwrap_vec(&data),
|
||||||
24 => KekAes192::new(key.into()).unwrap_vec(&data),
|
24 => KekAes192::new(key.into()).unwrap_vec(&data),
|
||||||
32 => KekAes256::new(key.into()).unwrap_vec(&data),
|
32 => KekAes256::new(key.into()).unwrap_vec(&data),
|
||||||
_ => return Err(type_error("Invalid key length")),
|
_ => return Err(Error::InvalidKeyLength),
|
||||||
}
|
}
|
||||||
.map_err(|_| {
|
.map_err(|_| Error::DecryptionError)?;
|
||||||
operation_error("decryption error - integrity check failed")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(unwrapped_key.into())
|
Ok(unwrapped_key.into())
|
||||||
}
|
}
|
||||||
_ => Err(type_error("Unsupported algorithm")),
|
_ => Err(Error::UnsupportedAlgorithm),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,6 @@
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use deno_core::error::custom_error;
|
|
||||||
use deno_core::error::type_error;
|
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::JsBuffer;
|
use deno_core::JsBuffer;
|
||||||
use deno_core::ToJsBuffer;
|
use deno_core::ToJsBuffer;
|
||||||
use elliptic_curve::sec1::ToEncodedPoint;
|
use elliptic_curve::sec1::ToEncodedPoint;
|
||||||
|
@ -63,47 +60,73 @@ pub enum RustRawKeyData {
|
||||||
Public(ToJsBuffer),
|
Public(ToJsBuffer),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum SharedError {
|
||||||
|
#[error("expected valid private key")]
|
||||||
|
ExpectedValidPrivateKey,
|
||||||
|
#[error("expected valid public key")]
|
||||||
|
ExpectedValidPublicKey,
|
||||||
|
#[error("expected valid private EC key")]
|
||||||
|
ExpectedValidPrivateECKey,
|
||||||
|
#[error("expected valid public EC key")]
|
||||||
|
ExpectedValidPublicECKey,
|
||||||
|
#[error("expected private key")]
|
||||||
|
ExpectedPrivateKey,
|
||||||
|
#[error("expected public key")]
|
||||||
|
ExpectedPublicKey,
|
||||||
|
#[error("expected secret key")]
|
||||||
|
ExpectedSecretKey,
|
||||||
|
#[error("failed to decode private key")]
|
||||||
|
FailedDecodePrivateKey,
|
||||||
|
#[error("failed to decode public key")]
|
||||||
|
FailedDecodePublicKey,
|
||||||
|
#[error("unsupported format")]
|
||||||
|
UnsupportedFormat,
|
||||||
|
}
|
||||||
|
|
||||||
impl V8RawKeyData {
|
impl V8RawKeyData {
|
||||||
pub fn as_rsa_public_key(&self) -> Result<Cow<'_, [u8]>, AnyError> {
|
pub fn as_rsa_public_key(&self) -> Result<Cow<'_, [u8]>, SharedError> {
|
||||||
match self {
|
match self {
|
||||||
V8RawKeyData::Public(data) => Ok(Cow::Borrowed(data)),
|
V8RawKeyData::Public(data) => Ok(Cow::Borrowed(data)),
|
||||||
V8RawKeyData::Private(data) => {
|
V8RawKeyData::Private(data) => {
|
||||||
let private_key = RsaPrivateKey::from_pkcs1_der(data)
|
let private_key = RsaPrivateKey::from_pkcs1_der(data)
|
||||||
.map_err(|_| type_error("expected valid private key"))?;
|
.map_err(|_| SharedError::ExpectedValidPrivateKey)?;
|
||||||
|
|
||||||
let public_key_doc = private_key
|
let public_key_doc = private_key
|
||||||
.to_public_key()
|
.to_public_key()
|
||||||
.to_pkcs1_der()
|
.to_pkcs1_der()
|
||||||
.map_err(|_| type_error("expected valid public key"))?;
|
.map_err(|_| SharedError::ExpectedValidPublicKey)?;
|
||||||
|
|
||||||
Ok(Cow::Owned(public_key_doc.as_bytes().into()))
|
Ok(Cow::Owned(public_key_doc.as_bytes().into()))
|
||||||
}
|
}
|
||||||
_ => Err(type_error("expected public key")),
|
_ => Err(SharedError::ExpectedPublicKey),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_rsa_private_key(&self) -> Result<&[u8], AnyError> {
|
pub fn as_rsa_private_key(&self) -> Result<&[u8], SharedError> {
|
||||||
match self {
|
match self {
|
||||||
V8RawKeyData::Private(data) => Ok(data),
|
V8RawKeyData::Private(data) => Ok(data),
|
||||||
_ => Err(type_error("expected private key")),
|
_ => Err(SharedError::ExpectedPrivateKey),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_secret_key(&self) -> Result<&[u8], AnyError> {
|
pub fn as_secret_key(&self) -> Result<&[u8], SharedError> {
|
||||||
match self {
|
match self {
|
||||||
V8RawKeyData::Secret(data) => Ok(data),
|
V8RawKeyData::Secret(data) => Ok(data),
|
||||||
_ => Err(type_error("expected secret key")),
|
_ => Err(SharedError::ExpectedSecretKey),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_ec_public_key_p256(&self) -> Result<p256::EncodedPoint, AnyError> {
|
pub fn as_ec_public_key_p256(
|
||||||
|
&self,
|
||||||
|
) -> Result<p256::EncodedPoint, SharedError> {
|
||||||
match self {
|
match self {
|
||||||
V8RawKeyData::Public(data) => p256::PublicKey::from_sec1_bytes(data)
|
V8RawKeyData::Public(data) => p256::PublicKey::from_sec1_bytes(data)
|
||||||
.map(|p| p.to_encoded_point(false))
|
.map(|p| p.to_encoded_point(false))
|
||||||
.map_err(|_| type_error("expected valid public EC key")),
|
.map_err(|_| SharedError::ExpectedValidPublicECKey),
|
||||||
V8RawKeyData::Private(data) => {
|
V8RawKeyData::Private(data) => {
|
||||||
let signing_key = p256::SecretKey::from_pkcs8_der(data)
|
let signing_key = p256::SecretKey::from_pkcs8_der(data)
|
||||||
.map_err(|_| type_error("expected valid private EC key"))?;
|
.map_err(|_| SharedError::ExpectedValidPrivateECKey)?;
|
||||||
Ok(signing_key.public_key().to_encoded_point(false))
|
Ok(signing_key.public_key().to_encoded_point(false))
|
||||||
}
|
}
|
||||||
// Should never reach here.
|
// Should never reach here.
|
||||||
|
@ -111,14 +134,16 @@ impl V8RawKeyData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_ec_public_key_p384(&self) -> Result<p384::EncodedPoint, AnyError> {
|
pub fn as_ec_public_key_p384(
|
||||||
|
&self,
|
||||||
|
) -> Result<p384::EncodedPoint, SharedError> {
|
||||||
match self {
|
match self {
|
||||||
V8RawKeyData::Public(data) => p384::PublicKey::from_sec1_bytes(data)
|
V8RawKeyData::Public(data) => p384::PublicKey::from_sec1_bytes(data)
|
||||||
.map(|p| p.to_encoded_point(false))
|
.map(|p| p.to_encoded_point(false))
|
||||||
.map_err(|_| type_error("expected valid public EC key")),
|
.map_err(|_| SharedError::ExpectedValidPublicECKey),
|
||||||
V8RawKeyData::Private(data) => {
|
V8RawKeyData::Private(data) => {
|
||||||
let signing_key = p384::SecretKey::from_pkcs8_der(data)
|
let signing_key = p384::SecretKey::from_pkcs8_der(data)
|
||||||
.map_err(|_| type_error("expected valid private EC key"))?;
|
.map_err(|_| SharedError::ExpectedValidPrivateECKey)?;
|
||||||
Ok(signing_key.public_key().to_encoded_point(false))
|
Ok(signing_key.public_key().to_encoded_point(false))
|
||||||
}
|
}
|
||||||
// Should never reach here.
|
// Should never reach here.
|
||||||
|
@ -126,16 +151,18 @@ impl V8RawKeyData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_ec_public_key_p521(&self) -> Result<p521::EncodedPoint, AnyError> {
|
pub fn as_ec_public_key_p521(
|
||||||
|
&self,
|
||||||
|
) -> Result<p521::EncodedPoint, SharedError> {
|
||||||
match self {
|
match self {
|
||||||
V8RawKeyData::Public(data) => {
|
V8RawKeyData::Public(data) => {
|
||||||
// public_key is a serialized EncodedPoint
|
// public_key is a serialized EncodedPoint
|
||||||
p521::EncodedPoint::from_bytes(data)
|
p521::EncodedPoint::from_bytes(data)
|
||||||
.map_err(|_| type_error("expected valid public EC key"))
|
.map_err(|_| SharedError::ExpectedValidPublicECKey)
|
||||||
}
|
}
|
||||||
V8RawKeyData::Private(data) => {
|
V8RawKeyData::Private(data) => {
|
||||||
let signing_key = p521::SecretKey::from_pkcs8_der(data)
|
let signing_key = p521::SecretKey::from_pkcs8_der(data)
|
||||||
.map_err(|_| type_error("expected valid private EC key"))?;
|
.map_err(|_| SharedError::ExpectedValidPrivateECKey)?;
|
||||||
Ok(signing_key.public_key().to_encoded_point(false))
|
Ok(signing_key.public_key().to_encoded_point(false))
|
||||||
}
|
}
|
||||||
// Should never reach here.
|
// Should never reach here.
|
||||||
|
@ -143,26 +170,10 @@ impl V8RawKeyData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_ec_private_key(&self) -> Result<&[u8], AnyError> {
|
pub fn as_ec_private_key(&self) -> Result<&[u8], SharedError> {
|
||||||
match self {
|
match self {
|
||||||
V8RawKeyData::Private(data) => Ok(data),
|
V8RawKeyData::Private(data) => Ok(data),
|
||||||
_ => Err(type_error("expected private key")),
|
_ => Err(SharedError::ExpectedPrivateKey),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn data_error(msg: impl Into<Cow<'static, str>>) -> AnyError {
|
|
||||||
custom_error("DOMExceptionDataError", msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn not_supported_error(msg: impl Into<Cow<'static, str>>) -> AnyError {
|
|
||||||
custom_error("DOMExceptionNotSupportedError", msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn operation_error(msg: impl Into<Cow<'static, str>>) -> AnyError {
|
|
||||||
custom_error("DOMExceptionOperationError", msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unsupported_format() -> AnyError {
|
|
||||||
not_supported_error("unsupported format")
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use curve25519_dalek::montgomery::MontgomeryPoint;
|
use curve25519_dalek::montgomery::MontgomeryPoint;
|
||||||
use deno_core::error::custom_error;
|
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::op2;
|
use deno_core::op2;
|
||||||
use deno_core::ToJsBuffer;
|
use deno_core::ToJsBuffer;
|
||||||
use elliptic_curve::pkcs8::PrivateKeyInfo;
|
use elliptic_curve::pkcs8::PrivateKeyInfo;
|
||||||
|
@ -13,6 +11,14 @@ use spki::der::asn1::BitString;
|
||||||
use spki::der::Decode;
|
use spki::der::Decode;
|
||||||
use spki::der::Encode;
|
use spki::der::Encode;
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum X25519Error {
|
||||||
|
#[error("Failed to export key")]
|
||||||
|
FailedExport,
|
||||||
|
#[error(transparent)]
|
||||||
|
Der(#[from] spki::der::Error),
|
||||||
|
}
|
||||||
|
|
||||||
#[op2(fast)]
|
#[op2(fast)]
|
||||||
pub fn op_crypto_generate_x25519_keypair(
|
pub fn op_crypto_generate_x25519_keypair(
|
||||||
#[buffer] pkey: &mut [u8],
|
#[buffer] pkey: &mut [u8],
|
||||||
|
@ -113,7 +119,7 @@ pub fn op_crypto_import_pkcs8_x25519(
|
||||||
#[serde]
|
#[serde]
|
||||||
pub fn op_crypto_export_spki_x25519(
|
pub fn op_crypto_export_spki_x25519(
|
||||||
#[buffer] pubkey: &[u8],
|
#[buffer] pubkey: &[u8],
|
||||||
) -> Result<ToJsBuffer, AnyError> {
|
) -> Result<ToJsBuffer, X25519Error> {
|
||||||
let key_info = spki::SubjectPublicKeyInfo {
|
let key_info = spki::SubjectPublicKeyInfo {
|
||||||
algorithm: spki::AlgorithmIdentifierRef {
|
algorithm: spki::AlgorithmIdentifierRef {
|
||||||
// id-X25519
|
// id-X25519
|
||||||
|
@ -125,9 +131,7 @@ pub fn op_crypto_export_spki_x25519(
|
||||||
Ok(
|
Ok(
|
||||||
key_info
|
key_info
|
||||||
.to_der()
|
.to_der()
|
||||||
.map_err(|_| {
|
.map_err(|_| X25519Error::FailedExport)?
|
||||||
custom_error("DOMExceptionOperationError", "Failed to export key")
|
|
||||||
})?
|
|
||||||
.into(),
|
.into(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -136,7 +140,7 @@ pub fn op_crypto_export_spki_x25519(
|
||||||
#[serde]
|
#[serde]
|
||||||
pub fn op_crypto_export_pkcs8_x25519(
|
pub fn op_crypto_export_pkcs8_x25519(
|
||||||
#[buffer] pkey: &[u8],
|
#[buffer] pkey: &[u8],
|
||||||
) -> Result<ToJsBuffer, AnyError> {
|
) -> Result<ToJsBuffer, X25519Error> {
|
||||||
use rsa::pkcs1::der::Encode;
|
use rsa::pkcs1::der::Encode;
|
||||||
|
|
||||||
// This should probably use OneAsymmetricKey instead
|
// This should probably use OneAsymmetricKey instead
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
use deno_core::error::custom_error;
|
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::op2;
|
use deno_core::op2;
|
||||||
use deno_core::ToJsBuffer;
|
use deno_core::ToJsBuffer;
|
||||||
use ed448_goldilocks::curve::MontgomeryPoint;
|
use ed448_goldilocks::curve::MontgomeryPoint;
|
||||||
|
@ -13,6 +12,14 @@ use spki::der::asn1::BitString;
|
||||||
use spki::der::Decode;
|
use spki::der::Decode;
|
||||||
use spki::der::Encode;
|
use spki::der::Encode;
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum X448Error {
|
||||||
|
#[error("Failed to export key")]
|
||||||
|
FailedExport,
|
||||||
|
#[error(transparent)]
|
||||||
|
Der(#[from] spki::der::Error),
|
||||||
|
}
|
||||||
|
|
||||||
#[op2(fast)]
|
#[op2(fast)]
|
||||||
pub fn op_crypto_generate_x448_keypair(
|
pub fn op_crypto_generate_x448_keypair(
|
||||||
#[buffer] pkey: &mut [u8],
|
#[buffer] pkey: &mut [u8],
|
||||||
|
@ -56,7 +63,7 @@ const X448_OID: const_oid::ObjectIdentifier =
|
||||||
#[serde]
|
#[serde]
|
||||||
pub fn op_crypto_export_spki_x448(
|
pub fn op_crypto_export_spki_x448(
|
||||||
#[buffer] pubkey: &[u8],
|
#[buffer] pubkey: &[u8],
|
||||||
) -> Result<ToJsBuffer, AnyError> {
|
) -> Result<ToJsBuffer, X448Error> {
|
||||||
let key_info = spki::SubjectPublicKeyInfo {
|
let key_info = spki::SubjectPublicKeyInfo {
|
||||||
algorithm: spki::AlgorithmIdentifierRef {
|
algorithm: spki::AlgorithmIdentifierRef {
|
||||||
oid: X448_OID,
|
oid: X448_OID,
|
||||||
|
@ -67,9 +74,7 @@ pub fn op_crypto_export_spki_x448(
|
||||||
Ok(
|
Ok(
|
||||||
key_info
|
key_info
|
||||||
.to_der()
|
.to_der()
|
||||||
.map_err(|_| {
|
.map_err(|_| X448Error::FailedExport)?
|
||||||
custom_error("DOMExceptionOperationError", "Failed to export key")
|
|
||||||
})?
|
|
||||||
.into(),
|
.into(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -78,7 +83,7 @@ pub fn op_crypto_export_spki_x448(
|
||||||
#[serde]
|
#[serde]
|
||||||
pub fn op_crypto_export_pkcs8_x448(
|
pub fn op_crypto_export_pkcs8_x448(
|
||||||
#[buffer] pkey: &[u8],
|
#[buffer] pkey: &[u8],
|
||||||
) -> Result<ToJsBuffer, AnyError> {
|
) -> Result<ToJsBuffer, X448Error> {
|
||||||
use rsa::pkcs1::der::Encode;
|
use rsa::pkcs1::der::Encode;
|
||||||
|
|
||||||
let pk_info = rsa::pkcs8::PrivateKeyInfo {
|
let pk_info = rsa::pkcs8::PrivateKeyInfo {
|
||||||
|
|
|
@ -32,6 +32,7 @@ percent-encoding.workspace = true
|
||||||
rustls-webpki.workspace = true
|
rustls-webpki.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
|
thiserror.workspace = true
|
||||||
tokio.workspace = true
|
tokio.workspace = true
|
||||||
tokio-rustls.workspace = true
|
tokio-rustls.workspace = true
|
||||||
tokio-socks.workspace = true
|
tokio-socks.workspace = true
|
||||||
|
|
|
@ -4,7 +4,6 @@ use crate::CancelHandle;
|
||||||
use crate::CancelableResponseFuture;
|
use crate::CancelableResponseFuture;
|
||||||
use crate::FetchHandler;
|
use crate::FetchHandler;
|
||||||
|
|
||||||
use deno_core::error::type_error;
|
|
||||||
use deno_core::futures::FutureExt;
|
use deno_core::futures::FutureExt;
|
||||||
use deno_core::futures::TryFutureExt;
|
use deno_core::futures::TryFutureExt;
|
||||||
use deno_core::futures::TryStreamExt;
|
use deno_core::futures::TryStreamExt;
|
||||||
|
@ -42,9 +41,7 @@ impl FetchHandler for FsFetchHandler {
|
||||||
.map_err(|_| ())?;
|
.map_err(|_| ())?;
|
||||||
Ok::<_, ()>(response)
|
Ok::<_, ()>(response)
|
||||||
}
|
}
|
||||||
.map_err(move |_| {
|
.map_err(move |_| super::FetchError::NetworkError)
|
||||||
type_error("NetworkError when attempting to fetch resource")
|
|
||||||
})
|
|
||||||
.or_cancel(&cancel_handle)
|
.or_cancel(&cancel_handle)
|
||||||
.boxed_local();
|
.boxed_local();
|
||||||
|
|
||||||
|
|
244
ext/fetch/lib.rs
244
ext/fetch/lib.rs
|
@ -17,10 +17,6 @@ use std::sync::Arc;
|
||||||
use std::task::Context;
|
use std::task::Context;
|
||||||
use std::task::Poll;
|
use std::task::Poll;
|
||||||
|
|
||||||
use deno_core::anyhow::anyhow;
|
|
||||||
use deno_core::anyhow::Error;
|
|
||||||
use deno_core::error::type_error;
|
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::futures::stream::Peekable;
|
use deno_core::futures::stream::Peekable;
|
||||||
use deno_core::futures::Future;
|
use deno_core::futures::Future;
|
||||||
use deno_core::futures::FutureExt;
|
use deno_core::futures::FutureExt;
|
||||||
|
@ -28,6 +24,7 @@ use deno_core::futures::Stream;
|
||||||
use deno_core::futures::StreamExt;
|
use deno_core::futures::StreamExt;
|
||||||
use deno_core::futures::TryFutureExt;
|
use deno_core::futures::TryFutureExt;
|
||||||
use deno_core::op2;
|
use deno_core::op2;
|
||||||
|
use deno_core::url;
|
||||||
use deno_core::url::Url;
|
use deno_core::url::Url;
|
||||||
use deno_core::AsyncRefCell;
|
use deno_core::AsyncRefCell;
|
||||||
use deno_core::AsyncResult;
|
use deno_core::AsyncResult;
|
||||||
|
@ -87,15 +84,18 @@ pub struct Options {
|
||||||
pub root_cert_store_provider: Option<Arc<dyn RootCertStoreProvider>>,
|
pub root_cert_store_provider: Option<Arc<dyn RootCertStoreProvider>>,
|
||||||
pub proxy: Option<Proxy>,
|
pub proxy: Option<Proxy>,
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
pub request_builder_hook:
|
pub request_builder_hook: Option<
|
||||||
Option<fn(&mut http::Request<ReqBody>) -> Result<(), AnyError>>,
|
fn(&mut http::Request<ReqBody>) -> Result<(), deno_core::error::AnyError>,
|
||||||
|
>,
|
||||||
pub unsafely_ignore_certificate_errors: Option<Vec<String>>,
|
pub unsafely_ignore_certificate_errors: Option<Vec<String>>,
|
||||||
pub client_cert_chain_and_key: TlsKeys,
|
pub client_cert_chain_and_key: TlsKeys,
|
||||||
pub file_fetch_handler: Rc<dyn FetchHandler>,
|
pub file_fetch_handler: Rc<dyn FetchHandler>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Options {
|
impl Options {
|
||||||
pub fn root_cert_store(&self) -> Result<Option<RootCertStore>, AnyError> {
|
pub fn root_cert_store(
|
||||||
|
&self,
|
||||||
|
) -> Result<Option<RootCertStore>, deno_core::error::AnyError> {
|
||||||
Ok(match &self.root_cert_store_provider {
|
Ok(match &self.root_cert_store_provider {
|
||||||
Some(provider) => Some(provider.get_or_try_init()?.clone()),
|
Some(provider) => Some(provider.get_or_try_init()?.clone()),
|
||||||
None => None,
|
None => None,
|
||||||
|
@ -144,6 +144,51 @@ deno_core::extension!(deno_fetch,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum FetchError {
|
||||||
|
#[error(transparent)]
|
||||||
|
Resource(deno_core::error::AnyError),
|
||||||
|
#[error(transparent)]
|
||||||
|
Permission(deno_core::error::AnyError),
|
||||||
|
#[error("NetworkError when attempting to fetch resource")]
|
||||||
|
NetworkError,
|
||||||
|
#[error("Fetching files only supports the GET method: received {0}")]
|
||||||
|
FsNotGet(Method),
|
||||||
|
#[error("Invalid URL {0}")]
|
||||||
|
InvalidUrl(Url),
|
||||||
|
#[error(transparent)]
|
||||||
|
InvalidHeaderName(#[from] http::header::InvalidHeaderName),
|
||||||
|
#[error(transparent)]
|
||||||
|
InvalidHeaderValue(#[from] http::header::InvalidHeaderValue),
|
||||||
|
#[error("{0:?}")]
|
||||||
|
DataUrl(data_url::DataUrlError),
|
||||||
|
#[error("{0:?}")]
|
||||||
|
Base64(data_url::forgiving_base64::InvalidBase64),
|
||||||
|
#[error("Blob for the given URL not found.")]
|
||||||
|
BlobNotFound,
|
||||||
|
#[error("Url scheme '{0}' not supported")]
|
||||||
|
SchemeNotSupported(String),
|
||||||
|
#[error("Request was cancelled")]
|
||||||
|
RequestCanceled,
|
||||||
|
#[error(transparent)]
|
||||||
|
Http(#[from] http::Error),
|
||||||
|
#[error(transparent)]
|
||||||
|
ClientCreate(#[from] HttpClientCreateError),
|
||||||
|
#[error(transparent)]
|
||||||
|
Url(#[from] url::ParseError),
|
||||||
|
#[error(transparent)]
|
||||||
|
Method(#[from] http::method::InvalidMethod),
|
||||||
|
#[error(transparent)]
|
||||||
|
ClientSend(#[from] ClientSendError),
|
||||||
|
#[error(transparent)]
|
||||||
|
RequestBuilderHook(deno_core::error::AnyError),
|
||||||
|
#[error(transparent)]
|
||||||
|
Io(#[from] std::io::Error),
|
||||||
|
// Only used for node upgrade
|
||||||
|
#[error(transparent)]
|
||||||
|
Hyper(#[from] hyper::Error),
|
||||||
|
}
|
||||||
|
|
||||||
pub type CancelableResponseFuture =
|
pub type CancelableResponseFuture =
|
||||||
Pin<Box<dyn Future<Output = CancelableResponseResult>>>;
|
Pin<Box<dyn Future<Output = CancelableResponseResult>>>;
|
||||||
|
|
||||||
|
@ -170,11 +215,7 @@ impl FetchHandler for DefaultFileFetchHandler {
|
||||||
_state: &mut OpState,
|
_state: &mut OpState,
|
||||||
_url: &Url,
|
_url: &Url,
|
||||||
) -> (CancelableResponseFuture, Option<Rc<CancelHandle>>) {
|
) -> (CancelableResponseFuture, Option<Rc<CancelHandle>>) {
|
||||||
let fut = async move {
|
let fut = async move { Ok(Err(FetchError::NetworkError)) };
|
||||||
Ok(Err(type_error(
|
|
||||||
"NetworkError when attempting to fetch resource",
|
|
||||||
)))
|
|
||||||
};
|
|
||||||
(Box::pin(fut), None)
|
(Box::pin(fut), None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,7 +232,7 @@ pub struct FetchReturn {
|
||||||
|
|
||||||
pub fn get_or_create_client_from_state(
|
pub fn get_or_create_client_from_state(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
) -> Result<Client, AnyError> {
|
) -> Result<Client, HttpClientCreateError> {
|
||||||
if let Some(client) = state.try_borrow::<Client>() {
|
if let Some(client) = state.try_borrow::<Client>() {
|
||||||
Ok(client.clone())
|
Ok(client.clone())
|
||||||
} else {
|
} else {
|
||||||
|
@ -204,11 +245,13 @@ pub fn get_or_create_client_from_state(
|
||||||
|
|
||||||
pub fn create_client_from_options(
|
pub fn create_client_from_options(
|
||||||
options: &Options,
|
options: &Options,
|
||||||
) -> Result<Client, AnyError> {
|
) -> Result<Client, HttpClientCreateError> {
|
||||||
create_http_client(
|
create_http_client(
|
||||||
&options.user_agent,
|
&options.user_agent,
|
||||||
CreateHttpClientOptions {
|
CreateHttpClientOptions {
|
||||||
root_cert_store: options.root_cert_store()?,
|
root_cert_store: options
|
||||||
|
.root_cert_store()
|
||||||
|
.map_err(HttpClientCreateError::RootCertStore)?,
|
||||||
ca_certs: vec![],
|
ca_certs: vec![],
|
||||||
proxy: options.proxy.clone(),
|
proxy: options.proxy.clone(),
|
||||||
unsafely_ignore_certificate_errors: options
|
unsafely_ignore_certificate_errors: options
|
||||||
|
@ -230,7 +273,9 @@ pub fn create_client_from_options(
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
pub struct ResourceToBodyAdapter(
|
pub struct ResourceToBodyAdapter(
|
||||||
Rc<dyn Resource>,
|
Rc<dyn Resource>,
|
||||||
Option<Pin<Box<dyn Future<Output = Result<BufView, Error>>>>>,
|
Option<
|
||||||
|
Pin<Box<dyn Future<Output = Result<BufView, deno_core::error::AnyError>>>>,
|
||||||
|
>,
|
||||||
);
|
);
|
||||||
|
|
||||||
impl ResourceToBodyAdapter {
|
impl ResourceToBodyAdapter {
|
||||||
|
@ -246,7 +291,7 @@ unsafe impl Send for ResourceToBodyAdapter {}
|
||||||
unsafe impl Sync for ResourceToBodyAdapter {}
|
unsafe impl Sync for ResourceToBodyAdapter {}
|
||||||
|
|
||||||
impl Stream for ResourceToBodyAdapter {
|
impl Stream for ResourceToBodyAdapter {
|
||||||
type Item = Result<Bytes, Error>;
|
type Item = Result<Bytes, deno_core::error::AnyError>;
|
||||||
|
|
||||||
fn poll_next(
|
fn poll_next(
|
||||||
self: Pin<&mut Self>,
|
self: Pin<&mut Self>,
|
||||||
|
@ -276,7 +321,7 @@ impl Stream for ResourceToBodyAdapter {
|
||||||
|
|
||||||
impl hyper::body::Body for ResourceToBodyAdapter {
|
impl hyper::body::Body for ResourceToBodyAdapter {
|
||||||
type Data = Bytes;
|
type Data = Bytes;
|
||||||
type Error = Error;
|
type Error = deno_core::error::AnyError;
|
||||||
|
|
||||||
fn poll_frame(
|
fn poll_frame(
|
||||||
self: Pin<&mut Self>,
|
self: Pin<&mut Self>,
|
||||||
|
@ -301,13 +346,13 @@ pub trait FetchPermissions {
|
||||||
&mut self,
|
&mut self,
|
||||||
url: &Url,
|
url: &Url,
|
||||||
api_name: &str,
|
api_name: &str,
|
||||||
) -> Result<(), AnyError>;
|
) -> Result<(), deno_core::error::AnyError>;
|
||||||
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||||
fn check_read<'a>(
|
fn check_read<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
p: &'a Path,
|
p: &'a Path,
|
||||||
api_name: &str,
|
api_name: &str,
|
||||||
) -> Result<Cow<'a, Path>, AnyError>;
|
) -> Result<Cow<'a, Path>, deno_core::error::AnyError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FetchPermissions for deno_permissions::PermissionsContainer {
|
impl FetchPermissions for deno_permissions::PermissionsContainer {
|
||||||
|
@ -316,7 +361,7 @@ impl FetchPermissions for deno_permissions::PermissionsContainer {
|
||||||
&mut self,
|
&mut self,
|
||||||
url: &Url,
|
url: &Url,
|
||||||
api_name: &str,
|
api_name: &str,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), deno_core::error::AnyError> {
|
||||||
deno_permissions::PermissionsContainer::check_net_url(self, url, api_name)
|
deno_permissions::PermissionsContainer::check_net_url(self, url, api_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,7 +370,7 @@ impl FetchPermissions for deno_permissions::PermissionsContainer {
|
||||||
&mut self,
|
&mut self,
|
||||||
path: &'a Path,
|
path: &'a Path,
|
||||||
api_name: &str,
|
api_name: &str,
|
||||||
) -> Result<Cow<'a, Path>, AnyError> {
|
) -> Result<Cow<'a, Path>, deno_core::error::AnyError> {
|
||||||
deno_permissions::PermissionsContainer::check_read_path(
|
deno_permissions::PermissionsContainer::check_read_path(
|
||||||
self,
|
self,
|
||||||
path,
|
path,
|
||||||
|
@ -346,12 +391,15 @@ pub fn op_fetch<FP>(
|
||||||
has_body: bool,
|
has_body: bool,
|
||||||
#[buffer] data: Option<JsBuffer>,
|
#[buffer] data: Option<JsBuffer>,
|
||||||
#[smi] resource: Option<ResourceId>,
|
#[smi] resource: Option<ResourceId>,
|
||||||
) -> Result<FetchReturn, AnyError>
|
) -> Result<FetchReturn, FetchError>
|
||||||
where
|
where
|
||||||
FP: FetchPermissions + 'static,
|
FP: FetchPermissions + 'static,
|
||||||
{
|
{
|
||||||
let (client, allow_host) = if let Some(rid) = client_rid {
|
let (client, allow_host) = if let Some(rid) = client_rid {
|
||||||
let r = state.resource_table.get::<HttpClientResource>(rid)?;
|
let r = state
|
||||||
|
.resource_table
|
||||||
|
.get::<HttpClientResource>(rid)
|
||||||
|
.map_err(FetchError::Resource)?;
|
||||||
(r.client.clone(), r.allow_host)
|
(r.client.clone(), r.allow_host)
|
||||||
} else {
|
} else {
|
||||||
(get_or_create_client_from_state(state)?, false)
|
(get_or_create_client_from_state(state)?, false)
|
||||||
|
@ -364,20 +412,18 @@ where
|
||||||
let scheme = url.scheme();
|
let scheme = url.scheme();
|
||||||
let (request_rid, cancel_handle_rid) = match scheme {
|
let (request_rid, cancel_handle_rid) = match scheme {
|
||||||
"file" => {
|
"file" => {
|
||||||
let path = url.to_file_path().map_err(|_| {
|
let path = url.to_file_path().map_err(|_| FetchError::NetworkError)?;
|
||||||
type_error("NetworkError when attempting to fetch resource")
|
|
||||||
})?;
|
|
||||||
let permissions = state.borrow_mut::<FP>();
|
let permissions = state.borrow_mut::<FP>();
|
||||||
let path = permissions.check_read(&path, "fetch()")?;
|
let path = permissions
|
||||||
|
.check_read(&path, "fetch()")
|
||||||
|
.map_err(FetchError::Permission)?;
|
||||||
let url = match path {
|
let url = match path {
|
||||||
Cow::Owned(path) => Url::from_file_path(path).unwrap(),
|
Cow::Owned(path) => Url::from_file_path(path).unwrap(),
|
||||||
Cow::Borrowed(_) => url,
|
Cow::Borrowed(_) => url,
|
||||||
};
|
};
|
||||||
|
|
||||||
if method != Method::GET {
|
if method != Method::GET {
|
||||||
return Err(type_error(format!(
|
return Err(FetchError::FsNotGet(method));
|
||||||
"Fetching files only supports the GET method: received {method}"
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let Options {
|
let Options {
|
||||||
|
@ -396,13 +442,15 @@ where
|
||||||
}
|
}
|
||||||
"http" | "https" => {
|
"http" | "https" => {
|
||||||
let permissions = state.borrow_mut::<FP>();
|
let permissions = state.borrow_mut::<FP>();
|
||||||
permissions.check_net_url(&url, "fetch()")?;
|
permissions
|
||||||
|
.check_net_url(&url, "fetch()")
|
||||||
|
.map_err(FetchError::Resource)?;
|
||||||
|
|
||||||
let maybe_authority = extract_authority(&mut url);
|
let maybe_authority = extract_authority(&mut url);
|
||||||
let uri = url
|
let uri = url
|
||||||
.as_str()
|
.as_str()
|
||||||
.parse::<Uri>()
|
.parse::<Uri>()
|
||||||
.map_err(|_| type_error(format!("Invalid URL {url}")))?;
|
.map_err(|_| FetchError::InvalidUrl(url.clone()))?;
|
||||||
|
|
||||||
let mut con_len = None;
|
let mut con_len = None;
|
||||||
let body = if has_body {
|
let body = if has_body {
|
||||||
|
@ -416,7 +464,10 @@ where
|
||||||
.boxed()
|
.boxed()
|
||||||
}
|
}
|
||||||
(_, Some(resource)) => {
|
(_, Some(resource)) => {
|
||||||
let resource = state.resource_table.take_any(resource)?;
|
let resource = state
|
||||||
|
.resource_table
|
||||||
|
.take_any(resource)
|
||||||
|
.map_err(FetchError::Resource)?;
|
||||||
match resource.size_hint() {
|
match resource.size_hint() {
|
||||||
(body_size, Some(n)) if body_size == n && body_size > 0 => {
|
(body_size, Some(n)) if body_size == n && body_size > 0 => {
|
||||||
con_len = Some(body_size);
|
con_len = Some(body_size);
|
||||||
|
@ -453,10 +504,8 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
for (key, value) in headers {
|
for (key, value) in headers {
|
||||||
let name = HeaderName::from_bytes(&key)
|
let name = HeaderName::from_bytes(&key)?;
|
||||||
.map_err(|err| type_error(err.to_string()))?;
|
let v = HeaderValue::from_bytes(&value)?;
|
||||||
let v = HeaderValue::from_bytes(&value)
|
|
||||||
.map_err(|err| type_error(err.to_string()))?;
|
|
||||||
|
|
||||||
if (name != HOST || allow_host) && name != CONTENT_LENGTH {
|
if (name != HOST || allow_host) && name != CONTENT_LENGTH {
|
||||||
request.headers_mut().append(name, v);
|
request.headers_mut().append(name, v);
|
||||||
|
@ -474,20 +523,18 @@ where
|
||||||
let options = state.borrow::<Options>();
|
let options = state.borrow::<Options>();
|
||||||
if let Some(request_builder_hook) = options.request_builder_hook {
|
if let Some(request_builder_hook) = options.request_builder_hook {
|
||||||
request_builder_hook(&mut request)
|
request_builder_hook(&mut request)
|
||||||
.map_err(|err| type_error(err.to_string()))?;
|
.map_err(FetchError::RequestBuilderHook)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let cancel_handle = CancelHandle::new_rc();
|
let cancel_handle = CancelHandle::new_rc();
|
||||||
let cancel_handle_ = cancel_handle.clone();
|
let cancel_handle_ = cancel_handle.clone();
|
||||||
|
|
||||||
let fut = {
|
let fut = async move {
|
||||||
async move {
|
client
|
||||||
client
|
.send(request)
|
||||||
.send(request)
|
.map_err(Into::into)
|
||||||
.map_err(Into::into)
|
.or_cancel(cancel_handle_)
|
||||||
.or_cancel(cancel_handle_)
|
.await
|
||||||
.await
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let request_rid = state.resource_table.add(FetchRequestResource {
|
let request_rid = state.resource_table.add(FetchRequestResource {
|
||||||
|
@ -501,12 +548,10 @@ where
|
||||||
(request_rid, Some(cancel_handle_rid))
|
(request_rid, Some(cancel_handle_rid))
|
||||||
}
|
}
|
||||||
"data" => {
|
"data" => {
|
||||||
let data_url = DataUrl::process(url.as_str())
|
let data_url =
|
||||||
.map_err(|e| type_error(format!("{e:?}")))?;
|
DataUrl::process(url.as_str()).map_err(FetchError::DataUrl)?;
|
||||||
|
|
||||||
let (body, _) = data_url
|
let (body, _) = data_url.decode_to_vec().map_err(FetchError::Base64)?;
|
||||||
.decode_to_vec()
|
|
||||||
.map_err(|e| type_error(format!("{e:?}")))?;
|
|
||||||
let body = http_body_util::Full::new(body.into())
|
let body = http_body_util::Full::new(body.into())
|
||||||
.map_err(|never| match never {})
|
.map_err(|never| match never {})
|
||||||
.boxed();
|
.boxed();
|
||||||
|
@ -528,11 +573,9 @@ where
|
||||||
"blob" => {
|
"blob" => {
|
||||||
// Blob URL resolution happens in the JS side of fetch. If we got here is
|
// Blob URL resolution happens in the JS side of fetch. If we got here is
|
||||||
// because the URL isn't an object URL.
|
// because the URL isn't an object URL.
|
||||||
return Err(type_error("Blob for the given URL not found."));
|
return Err(FetchError::BlobNotFound);
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(type_error(format!("Url scheme '{scheme}' not supported")))
|
|
||||||
}
|
}
|
||||||
|
_ => return Err(FetchError::SchemeNotSupported(scheme.to_string())),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(FetchReturn {
|
Ok(FetchReturn {
|
||||||
|
@ -564,11 +607,12 @@ pub struct FetchResponse {
|
||||||
pub async fn op_fetch_send(
|
pub async fn op_fetch_send(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
#[smi] rid: ResourceId,
|
#[smi] rid: ResourceId,
|
||||||
) -> Result<FetchResponse, AnyError> {
|
) -> Result<FetchResponse, FetchError> {
|
||||||
let request = state
|
let request = state
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.resource_table
|
.resource_table
|
||||||
.take::<FetchRequestResource>(rid)?;
|
.take::<FetchRequestResource>(rid)
|
||||||
|
.map_err(FetchError::Resource)?;
|
||||||
|
|
||||||
let request = Rc::try_unwrap(request)
|
let request = Rc::try_unwrap(request)
|
||||||
.ok()
|
.ok()
|
||||||
|
@ -581,22 +625,23 @@ pub async fn op_fetch_send(
|
||||||
// If any error in the chain is a hyper body error, return that as a special result we can use to
|
// If any error in the chain is a hyper body error, return that as a special result we can use to
|
||||||
// reconstruct an error chain (eg: `new TypeError(..., { cause: new Error(...) })`).
|
// reconstruct an error chain (eg: `new TypeError(..., { cause: new Error(...) })`).
|
||||||
// TODO(mmastrac): it would be a lot easier if we just passed a v8::Global through here instead
|
// TODO(mmastrac): it would be a lot easier if we just passed a v8::Global through here instead
|
||||||
let mut err_ref: &dyn std::error::Error = err.as_ref();
|
|
||||||
while let Some(err_src) = std::error::Error::source(err_ref) {
|
if let FetchError::ClientSend(err_src) = &err {
|
||||||
if let Some(err_src) = err_src.downcast_ref::<hyper::Error>() {
|
if let Some(client_err) = std::error::Error::source(&err_src.source) {
|
||||||
if let Some(err_src) = std::error::Error::source(err_src) {
|
if let Some(err_src) = client_err.downcast_ref::<hyper::Error>() {
|
||||||
return Ok(FetchResponse {
|
if let Some(err_src) = std::error::Error::source(err_src) {
|
||||||
error: Some((err.to_string(), err_src.to_string())),
|
return Ok(FetchResponse {
|
||||||
..Default::default()
|
error: Some((err.to_string(), err_src.to_string())),
|
||||||
});
|
..Default::default()
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err_ref = err_src;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Err(type_error(err.to_string()));
|
return Err(err);
|
||||||
}
|
}
|
||||||
Err(_) => return Err(type_error("Request was cancelled")),
|
Err(_) => return Err(FetchError::RequestCanceled),
|
||||||
};
|
};
|
||||||
|
|
||||||
let status = res.status();
|
let status = res.status();
|
||||||
|
@ -636,7 +681,7 @@ pub async fn op_fetch_send(
|
||||||
}
|
}
|
||||||
|
|
||||||
type CancelableResponseResult =
|
type CancelableResponseResult =
|
||||||
Result<Result<http::Response<ResBody>, AnyError>, Canceled>;
|
Result<Result<http::Response<ResBody>, FetchError>, Canceled>;
|
||||||
|
|
||||||
pub struct FetchRequestResource {
|
pub struct FetchRequestResource {
|
||||||
pub future: Pin<Box<dyn Future<Output = CancelableResponseResult>>>,
|
pub future: Pin<Box<dyn Future<Output = CancelableResponseResult>>>,
|
||||||
|
@ -691,7 +736,7 @@ impl FetchResponseResource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn upgrade(self) -> Result<hyper::upgrade::Upgraded, AnyError> {
|
pub async fn upgrade(self) -> Result<hyper::upgrade::Upgraded, hyper::Error> {
|
||||||
let reader = self.response_reader.into_inner();
|
let reader = self.response_reader.into_inner();
|
||||||
match reader {
|
match reader {
|
||||||
FetchResponseReader::Start(resp) => Ok(hyper::upgrade::on(resp).await?),
|
FetchResponseReader::Start(resp) => Ok(hyper::upgrade::on(resp).await?),
|
||||||
|
@ -746,7 +791,9 @@ impl Resource for FetchResponseResource {
|
||||||
// safely call `await` on it without creating a race condition.
|
// safely call `await` on it without creating a race condition.
|
||||||
Some(_) => match reader.as_mut().next().await.unwrap() {
|
Some(_) => match reader.as_mut().next().await.unwrap() {
|
||||||
Ok(chunk) => assert!(chunk.is_empty()),
|
Ok(chunk) => assert!(chunk.is_empty()),
|
||||||
Err(err) => break Err(type_error(err.to_string())),
|
Err(err) => {
|
||||||
|
break Err(deno_core::error::type_error(err.to_string()))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
None => break Ok(BufView::empty()),
|
None => break Ok(BufView::empty()),
|
||||||
}
|
}
|
||||||
|
@ -809,14 +856,16 @@ pub fn op_fetch_custom_client<FP>(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[serde] args: CreateHttpClientArgs,
|
#[serde] args: CreateHttpClientArgs,
|
||||||
#[cppgc] tls_keys: &TlsKeysHolder,
|
#[cppgc] tls_keys: &TlsKeysHolder,
|
||||||
) -> Result<ResourceId, AnyError>
|
) -> Result<ResourceId, FetchError>
|
||||||
where
|
where
|
||||||
FP: FetchPermissions + 'static,
|
FP: FetchPermissions + 'static,
|
||||||
{
|
{
|
||||||
if let Some(proxy) = args.proxy.clone() {
|
if let Some(proxy) = args.proxy.clone() {
|
||||||
let permissions = state.borrow_mut::<FP>();
|
let permissions = state.borrow_mut::<FP>();
|
||||||
let url = Url::parse(&proxy.url)?;
|
let url = Url::parse(&proxy.url)?;
|
||||||
permissions.check_net_url(&url, "Deno.createHttpClient()")?;
|
permissions
|
||||||
|
.check_net_url(&url, "Deno.createHttpClient()")
|
||||||
|
.map_err(FetchError::Permission)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let options = state.borrow::<Options>();
|
let options = state.borrow::<Options>();
|
||||||
|
@ -829,7 +878,9 @@ where
|
||||||
let client = create_http_client(
|
let client = create_http_client(
|
||||||
&options.user_agent,
|
&options.user_agent,
|
||||||
CreateHttpClientOptions {
|
CreateHttpClientOptions {
|
||||||
root_cert_store: options.root_cert_store()?,
|
root_cert_store: options
|
||||||
|
.root_cert_store()
|
||||||
|
.map_err(HttpClientCreateError::RootCertStore)?,
|
||||||
ca_certs,
|
ca_certs,
|
||||||
proxy: args.proxy,
|
proxy: args.proxy,
|
||||||
unsafely_ignore_certificate_errors: options
|
unsafely_ignore_certificate_errors: options
|
||||||
|
@ -887,19 +938,34 @@ impl Default for CreateHttpClientOptions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum HttpClientCreateError {
|
||||||
|
#[error(transparent)]
|
||||||
|
Tls(deno_tls::TlsError),
|
||||||
|
#[error("Illegal characters in User-Agent: received {0}")]
|
||||||
|
InvalidUserAgent(String),
|
||||||
|
#[error("invalid proxy url")]
|
||||||
|
InvalidProxyUrl,
|
||||||
|
#[error("Cannot create Http Client: either `http1` or `http2` needs to be set to true")]
|
||||||
|
HttpVersionSelectionInvalid,
|
||||||
|
#[error(transparent)]
|
||||||
|
RootCertStore(deno_core::error::AnyError),
|
||||||
|
}
|
||||||
|
|
||||||
/// Create new instance of async Client. This client supports
|
/// Create new instance of async Client. This client supports
|
||||||
/// proxies and doesn't follow redirects.
|
/// proxies and doesn't follow redirects.
|
||||||
pub fn create_http_client(
|
pub fn create_http_client(
|
||||||
user_agent: &str,
|
user_agent: &str,
|
||||||
options: CreateHttpClientOptions,
|
options: CreateHttpClientOptions,
|
||||||
) -> Result<Client, AnyError> {
|
) -> Result<Client, HttpClientCreateError> {
|
||||||
let mut tls_config = deno_tls::create_client_config(
|
let mut tls_config = deno_tls::create_client_config(
|
||||||
options.root_cert_store,
|
options.root_cert_store,
|
||||||
options.ca_certs,
|
options.ca_certs,
|
||||||
options.unsafely_ignore_certificate_errors,
|
options.unsafely_ignore_certificate_errors,
|
||||||
options.client_cert_chain_and_key.into(),
|
options.client_cert_chain_and_key.into(),
|
||||||
deno_tls::SocketUse::Http,
|
deno_tls::SocketUse::Http,
|
||||||
)?;
|
)
|
||||||
|
.map_err(HttpClientCreateError::Tls)?;
|
||||||
|
|
||||||
// Proxy TLS should not send ALPN
|
// Proxy TLS should not send ALPN
|
||||||
tls_config.alpn_protocols.clear();
|
tls_config.alpn_protocols.clear();
|
||||||
|
@ -919,9 +985,7 @@ pub fn create_http_client(
|
||||||
http_connector.enforce_http(false);
|
http_connector.enforce_http(false);
|
||||||
|
|
||||||
let user_agent = user_agent.parse::<HeaderValue>().map_err(|_| {
|
let user_agent = user_agent.parse::<HeaderValue>().map_err(|_| {
|
||||||
type_error(format!(
|
HttpClientCreateError::InvalidUserAgent(user_agent.to_string())
|
||||||
"Illegal characters in User-Agent: received {user_agent}"
|
|
||||||
))
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let mut builder =
|
let mut builder =
|
||||||
|
@ -932,7 +996,7 @@ pub fn create_http_client(
|
||||||
let mut proxies = proxy::from_env();
|
let mut proxies = proxy::from_env();
|
||||||
if let Some(proxy) = options.proxy {
|
if let Some(proxy) = options.proxy {
|
||||||
let mut intercept = proxy::Intercept::all(&proxy.url)
|
let mut intercept = proxy::Intercept::all(&proxy.url)
|
||||||
.ok_or_else(|| type_error("invalid proxy url"))?;
|
.ok_or_else(|| HttpClientCreateError::InvalidProxyUrl)?;
|
||||||
if let Some(basic_auth) = &proxy.basic_auth {
|
if let Some(basic_auth) = &proxy.basic_auth {
|
||||||
intercept.set_auth(&basic_auth.username, &basic_auth.password);
|
intercept.set_auth(&basic_auth.username, &basic_auth.password);
|
||||||
}
|
}
|
||||||
|
@ -964,7 +1028,7 @@ pub fn create_http_client(
|
||||||
}
|
}
|
||||||
(true, true) => {}
|
(true, true) => {}
|
||||||
(false, false) => {
|
(false, false) => {
|
||||||
return Err(type_error("Cannot create Http Client: either `http1` or `http2` needs to be set to true"))
|
return Err(HttpClientCreateError::HttpVersionSelectionInvalid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -980,10 +1044,8 @@ pub fn create_http_client(
|
||||||
|
|
||||||
#[op2]
|
#[op2]
|
||||||
#[serde]
|
#[serde]
|
||||||
pub fn op_utf8_to_byte_string(
|
pub fn op_utf8_to_byte_string(#[string] input: String) -> ByteString {
|
||||||
#[string] input: String,
|
input.into()
|
||||||
) -> Result<ByteString, AnyError> {
|
|
||||||
Ok(input.into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -1003,7 +1065,7 @@ const STAR_STAR: HeaderValue = HeaderValue::from_static("*/*");
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ClientSendError {
|
pub struct ClientSendError {
|
||||||
uri: Uri,
|
uri: Uri,
|
||||||
source: hyper_util::client::legacy::Error,
|
pub source: hyper_util::client::legacy::Error,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClientSendError {
|
impl ClientSendError {
|
||||||
|
@ -1075,12 +1137,14 @@ impl Client {
|
||||||
.oneshot(req)
|
.oneshot(req)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| ClientSendError { uri, source: e })?;
|
.map_err(|e| ClientSendError { uri, source: e })?;
|
||||||
Ok(resp.map(|b| b.map_err(|e| anyhow!(e)).boxed()))
|
Ok(resp.map(|b| b.map_err(|e| deno_core::anyhow::anyhow!(e)).boxed()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ReqBody = http_body_util::combinators::BoxBody<Bytes, Error>;
|
pub type ReqBody =
|
||||||
pub type ResBody = http_body_util::combinators::BoxBody<Bytes, Error>;
|
http_body_util::combinators::BoxBody<Bytes, deno_core::error::AnyError>;
|
||||||
|
pub type ResBody =
|
||||||
|
http_body_util::combinators::BoxBody<Bytes, deno_core::error::AnyError>;
|
||||||
|
|
||||||
/// Copied from https://github.com/seanmonstar/reqwest/blob/b9d62a0323d96f11672a61a17bf8849baec00275/src/async_impl/request.rs#L572
|
/// Copied from https://github.com/seanmonstar/reqwest/blob/b9d62a0323d96f11672a61a17bf8849baec00275/src/async_impl/request.rs#L572
|
||||||
/// Check the request URL for a "username:password" type authority, and if
|
/// Check the request URL for a "username:password" type authority, and if
|
||||||
|
|
|
@ -28,9 +28,10 @@ libc.workspace = true
|
||||||
rand.workspace = true
|
rand.workspace = true
|
||||||
rayon = "1.8.0"
|
rayon = "1.8.0"
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
|
thiserror.workspace = true
|
||||||
|
|
||||||
[target.'cfg(unix)'.dependencies]
|
[target.'cfg(unix)'.dependencies]
|
||||||
nix.workspace = true
|
nix = { workspace = true, features = ["user"] }
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
winapi = { workspace = true, features = ["winbase"] }
|
winapi = { workspace = true, features = ["winbase"] }
|
||||||
|
|
|
@ -14,6 +14,8 @@ pub use crate::interface::FileSystemRc;
|
||||||
pub use crate::interface::FsDirEntry;
|
pub use crate::interface::FsDirEntry;
|
||||||
pub use crate::interface::FsFileType;
|
pub use crate::interface::FsFileType;
|
||||||
pub use crate::interface::OpenOptions;
|
pub use crate::interface::OpenOptions;
|
||||||
|
pub use crate::ops::FsOpsError;
|
||||||
|
pub use crate::ops::OperationError;
|
||||||
pub use crate::std_fs::RealFs;
|
pub use crate::std_fs::RealFs;
|
||||||
pub use crate::sync::MaybeSend;
|
pub use crate::sync::MaybeSend;
|
||||||
pub use crate::sync::MaybeSync;
|
pub use crate::sync::MaybeSync;
|
||||||
|
|
575
ext/fs/ops.rs
575
ext/fs/ops.rs
File diff suppressed because it is too large
Load diff
|
@ -19,7 +19,6 @@ use crate::service::SignallingRc;
|
||||||
use crate::websocket_upgrade::WebSocketUpgrade;
|
use crate::websocket_upgrade::WebSocketUpgrade;
|
||||||
use crate::LocalExecutor;
|
use crate::LocalExecutor;
|
||||||
use cache_control::CacheControl;
|
use cache_control::CacheControl;
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::external;
|
use deno_core::external;
|
||||||
use deno_core::futures::future::poll_fn;
|
use deno_core::futures::future::poll_fn;
|
||||||
use deno_core::futures::TryFutureExt;
|
use deno_core::futures::TryFutureExt;
|
||||||
|
@ -146,12 +145,32 @@ macro_rules! clone_external {
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum HttpNextError {
|
||||||
|
#[error(transparent)]
|
||||||
|
Resource(deno_core::error::AnyError),
|
||||||
|
#[error("{0}")]
|
||||||
|
Io(#[from] io::Error),
|
||||||
|
#[error(transparent)]
|
||||||
|
WebSocketUpgrade(crate::websocket_upgrade::WebSocketUpgradeError),
|
||||||
|
#[error("{0}")]
|
||||||
|
Hyper(#[from] hyper::Error),
|
||||||
|
#[error(transparent)]
|
||||||
|
JoinError(#[from] tokio::task::JoinError),
|
||||||
|
#[error(transparent)]
|
||||||
|
Canceled(#[from] deno_core::Canceled),
|
||||||
|
#[error(transparent)]
|
||||||
|
HttpPropertyExtractor(deno_core::error::AnyError),
|
||||||
|
#[error(transparent)]
|
||||||
|
UpgradeUnavailable(#[from] crate::service::UpgradeUnavailableError),
|
||||||
|
}
|
||||||
|
|
||||||
#[op2(fast)]
|
#[op2(fast)]
|
||||||
#[smi]
|
#[smi]
|
||||||
pub fn op_http_upgrade_raw(
|
pub fn op_http_upgrade_raw(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
external: *const c_void,
|
external: *const c_void,
|
||||||
) -> Result<ResourceId, AnyError> {
|
) -> Result<ResourceId, HttpNextError> {
|
||||||
// SAFETY: external is deleted before calling this op.
|
// SAFETY: external is deleted before calling this op.
|
||||||
let http = unsafe { take_external!(external, "op_http_upgrade_raw") };
|
let http = unsafe { take_external!(external, "op_http_upgrade_raw") };
|
||||||
|
|
||||||
|
@ -177,7 +196,7 @@ pub fn op_http_upgrade_raw(
|
||||||
upgraded.write_all(&bytes).await?;
|
upgraded.write_all(&bytes).await?;
|
||||||
break upgraded;
|
break upgraded;
|
||||||
}
|
}
|
||||||
Err(err) => return Err(err),
|
Err(err) => return Err(HttpNextError::WebSocketUpgrade(err)),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -193,7 +212,7 @@ pub fn op_http_upgrade_raw(
|
||||||
}
|
}
|
||||||
read_tx.write_all(&buf[..read]).await?;
|
read_tx.write_all(&buf[..read]).await?;
|
||||||
}
|
}
|
||||||
Ok::<_, AnyError>(())
|
Ok::<_, HttpNextError>(())
|
||||||
});
|
});
|
||||||
spawn(async move {
|
spawn(async move {
|
||||||
let mut buf = [0; 1024];
|
let mut buf = [0; 1024];
|
||||||
|
@ -204,7 +223,7 @@ pub fn op_http_upgrade_raw(
|
||||||
}
|
}
|
||||||
upgraded_tx.write_all(&buf[..read]).await?;
|
upgraded_tx.write_all(&buf[..read]).await?;
|
||||||
}
|
}
|
||||||
Ok::<_, AnyError>(())
|
Ok::<_, HttpNextError>(())
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -223,7 +242,7 @@ pub async fn op_http_upgrade_websocket_next(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
external: *const c_void,
|
external: *const c_void,
|
||||||
#[serde] headers: Vec<(ByteString, ByteString)>,
|
#[serde] headers: Vec<(ByteString, ByteString)>,
|
||||||
) -> Result<ResourceId, AnyError> {
|
) -> Result<ResourceId, HttpNextError> {
|
||||||
let http =
|
let http =
|
||||||
// SAFETY: external is deleted before calling this op.
|
// SAFETY: external is deleted before calling this op.
|
||||||
unsafe { take_external!(external, "op_http_upgrade_websocket_next") };
|
unsafe { take_external!(external, "op_http_upgrade_websocket_next") };
|
||||||
|
@ -246,7 +265,11 @@ pub async fn op_http_upgrade_websocket_next(
|
||||||
|
|
||||||
// Stage 3: take the extracted raw network stream and upgrade it to a websocket, then return it
|
// Stage 3: take the extracted raw network stream and upgrade it to a websocket, then return it
|
||||||
let (stream, bytes) = extract_network_stream(upgraded);
|
let (stream, bytes) = extract_network_stream(upgraded);
|
||||||
ws_create_server_stream(&mut state.borrow_mut(), stream, bytes)
|
Ok(ws_create_server_stream(
|
||||||
|
&mut state.borrow_mut(),
|
||||||
|
stream,
|
||||||
|
bytes,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[op2(fast)]
|
#[op2(fast)]
|
||||||
|
@ -686,7 +709,7 @@ pub async fn op_http_set_response_body_resource(
|
||||||
#[smi] stream_rid: ResourceId,
|
#[smi] stream_rid: ResourceId,
|
||||||
auto_close: bool,
|
auto_close: bool,
|
||||||
status: u16,
|
status: u16,
|
||||||
) -> Result<bool, AnyError> {
|
) -> Result<bool, HttpNextError> {
|
||||||
let http =
|
let http =
|
||||||
// SAFETY: op is called with external.
|
// SAFETY: op is called with external.
|
||||||
unsafe { clone_external!(external, "op_http_set_response_body_resource") };
|
unsafe { clone_external!(external, "op_http_set_response_body_resource") };
|
||||||
|
@ -701,9 +724,15 @@ pub async fn op_http_set_response_body_resource(
|
||||||
let resource = {
|
let resource = {
|
||||||
let mut state = state.borrow_mut();
|
let mut state = state.borrow_mut();
|
||||||
if auto_close {
|
if auto_close {
|
||||||
state.resource_table.take_any(stream_rid)?
|
state
|
||||||
|
.resource_table
|
||||||
|
.take_any(stream_rid)
|
||||||
|
.map_err(HttpNextError::Resource)?
|
||||||
} else {
|
} else {
|
||||||
state.resource_table.get_any(stream_rid)?
|
state
|
||||||
|
.resource_table
|
||||||
|
.get_any(stream_rid)
|
||||||
|
.map_err(HttpNextError::Resource)?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -810,17 +839,17 @@ async fn serve_http2_autodetect(
|
||||||
io: impl HttpServeStream,
|
io: impl HttpServeStream,
|
||||||
svc: impl HttpService<Incoming, ResBody = HttpRecordResponse> + 'static,
|
svc: impl HttpService<Incoming, ResBody = HttpRecordResponse> + 'static,
|
||||||
cancel: Rc<CancelHandle>,
|
cancel: Rc<CancelHandle>,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), HttpNextError> {
|
||||||
let prefix = NetworkStreamPrefixCheck::new(io, HTTP2_PREFIX);
|
let prefix = NetworkStreamPrefixCheck::new(io, HTTP2_PREFIX);
|
||||||
let (matches, io) = prefix.match_prefix().await?;
|
let (matches, io) = prefix.match_prefix().await?;
|
||||||
if matches {
|
if matches {
|
||||||
serve_http2_unconditional(io, svc, cancel)
|
serve_http2_unconditional(io, svc, cancel)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| e.into())
|
.map_err(HttpNextError::Hyper)
|
||||||
} else {
|
} else {
|
||||||
serve_http11_unconditional(io, svc, cancel)
|
serve_http11_unconditional(io, svc, cancel)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| e.into())
|
.map_err(HttpNextError::Hyper)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -829,7 +858,7 @@ fn serve_https(
|
||||||
request_info: HttpConnectionProperties,
|
request_info: HttpConnectionProperties,
|
||||||
lifetime: HttpLifetime,
|
lifetime: HttpLifetime,
|
||||||
tx: tokio::sync::mpsc::Sender<Rc<HttpRecord>>,
|
tx: tokio::sync::mpsc::Sender<Rc<HttpRecord>>,
|
||||||
) -> JoinHandle<Result<(), AnyError>> {
|
) -> JoinHandle<Result<(), HttpNextError>> {
|
||||||
let HttpLifetime {
|
let HttpLifetime {
|
||||||
server_state,
|
server_state,
|
||||||
connection_cancel_handle,
|
connection_cancel_handle,
|
||||||
|
@ -848,11 +877,11 @@ fn serve_https(
|
||||||
if Some(TLS_ALPN_HTTP_2) == handshake.as_deref() {
|
if Some(TLS_ALPN_HTTP_2) == handshake.as_deref() {
|
||||||
serve_http2_unconditional(io, svc, listen_cancel_handle)
|
serve_http2_unconditional(io, svc, listen_cancel_handle)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| e.into())
|
.map_err(HttpNextError::Hyper)
|
||||||
} else if Some(TLS_ALPN_HTTP_11) == handshake.as_deref() {
|
} else if Some(TLS_ALPN_HTTP_11) == handshake.as_deref() {
|
||||||
serve_http11_unconditional(io, svc, listen_cancel_handle)
|
serve_http11_unconditional(io, svc, listen_cancel_handle)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| e.into())
|
.map_err(HttpNextError::Hyper)
|
||||||
} else {
|
} else {
|
||||||
serve_http2_autodetect(io, svc, listen_cancel_handle).await
|
serve_http2_autodetect(io, svc, listen_cancel_handle).await
|
||||||
}
|
}
|
||||||
|
@ -866,7 +895,7 @@ fn serve_http(
|
||||||
request_info: HttpConnectionProperties,
|
request_info: HttpConnectionProperties,
|
||||||
lifetime: HttpLifetime,
|
lifetime: HttpLifetime,
|
||||||
tx: tokio::sync::mpsc::Sender<Rc<HttpRecord>>,
|
tx: tokio::sync::mpsc::Sender<Rc<HttpRecord>>,
|
||||||
) -> JoinHandle<Result<(), AnyError>> {
|
) -> JoinHandle<Result<(), HttpNextError>> {
|
||||||
let HttpLifetime {
|
let HttpLifetime {
|
||||||
server_state,
|
server_state,
|
||||||
connection_cancel_handle,
|
connection_cancel_handle,
|
||||||
|
@ -887,7 +916,7 @@ fn serve_http_on<HTTP>(
|
||||||
listen_properties: &HttpListenProperties,
|
listen_properties: &HttpListenProperties,
|
||||||
lifetime: HttpLifetime,
|
lifetime: HttpLifetime,
|
||||||
tx: tokio::sync::mpsc::Sender<Rc<HttpRecord>>,
|
tx: tokio::sync::mpsc::Sender<Rc<HttpRecord>>,
|
||||||
) -> JoinHandle<Result<(), AnyError>>
|
) -> JoinHandle<Result<(), HttpNextError>>
|
||||||
where
|
where
|
||||||
HTTP: HttpPropertyExtractor,
|
HTTP: HttpPropertyExtractor,
|
||||||
{
|
{
|
||||||
|
@ -918,7 +947,7 @@ struct HttpLifetime {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct HttpJoinHandle {
|
struct HttpJoinHandle {
|
||||||
join_handle: AsyncRefCell<Option<JoinHandle<Result<(), AnyError>>>>,
|
join_handle: AsyncRefCell<Option<JoinHandle<Result<(), HttpNextError>>>>,
|
||||||
connection_cancel_handle: Rc<CancelHandle>,
|
connection_cancel_handle: Rc<CancelHandle>,
|
||||||
listen_cancel_handle: Rc<CancelHandle>,
|
listen_cancel_handle: Rc<CancelHandle>,
|
||||||
rx: AsyncRefCell<tokio::sync::mpsc::Receiver<Rc<HttpRecord>>>,
|
rx: AsyncRefCell<tokio::sync::mpsc::Receiver<Rc<HttpRecord>>>,
|
||||||
|
@ -978,12 +1007,13 @@ impl Drop for HttpJoinHandle {
|
||||||
pub fn op_http_serve<HTTP>(
|
pub fn op_http_serve<HTTP>(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
#[smi] listener_rid: ResourceId,
|
#[smi] listener_rid: ResourceId,
|
||||||
) -> Result<(ResourceId, &'static str, String), AnyError>
|
) -> Result<(ResourceId, &'static str, String), HttpNextError>
|
||||||
where
|
where
|
||||||
HTTP: HttpPropertyExtractor,
|
HTTP: HttpPropertyExtractor,
|
||||||
{
|
{
|
||||||
let listener =
|
let listener =
|
||||||
HTTP::get_listener_for_rid(&mut state.borrow_mut(), listener_rid)?;
|
HTTP::get_listener_for_rid(&mut state.borrow_mut(), listener_rid)
|
||||||
|
.map_err(HttpNextError::Resource)?;
|
||||||
|
|
||||||
let listen_properties = HTTP::listen_properties_from_listener(&listener)?;
|
let listen_properties = HTTP::listen_properties_from_listener(&listener)?;
|
||||||
|
|
||||||
|
@ -998,7 +1028,8 @@ where
|
||||||
loop {
|
loop {
|
||||||
let conn = HTTP::accept_connection_from_listener(&listener)
|
let conn = HTTP::accept_connection_from_listener(&listener)
|
||||||
.try_or_cancel(listen_cancel_clone.clone())
|
.try_or_cancel(listen_cancel_clone.clone())
|
||||||
.await?;
|
.await
|
||||||
|
.map_err(HttpNextError::HttpPropertyExtractor)?;
|
||||||
serve_http_on::<HTTP>(
|
serve_http_on::<HTTP>(
|
||||||
conn,
|
conn,
|
||||||
&listen_properties_clone,
|
&listen_properties_clone,
|
||||||
|
@ -1007,7 +1038,7 @@ where
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
#[allow(unreachable_code)]
|
#[allow(unreachable_code)]
|
||||||
Ok::<_, AnyError>(())
|
Ok::<_, HttpNextError>(())
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set the handle after we start the future
|
// Set the handle after we start the future
|
||||||
|
@ -1027,25 +1058,25 @@ where
|
||||||
pub fn op_http_serve_on<HTTP>(
|
pub fn op_http_serve_on<HTTP>(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
#[smi] connection_rid: ResourceId,
|
#[smi] connection_rid: ResourceId,
|
||||||
) -> Result<(ResourceId, &'static str, String), AnyError>
|
) -> Result<(ResourceId, &'static str, String), HttpNextError>
|
||||||
where
|
where
|
||||||
HTTP: HttpPropertyExtractor,
|
HTTP: HttpPropertyExtractor,
|
||||||
{
|
{
|
||||||
let connection =
|
let connection =
|
||||||
HTTP::get_connection_for_rid(&mut state.borrow_mut(), connection_rid)?;
|
HTTP::get_connection_for_rid(&mut state.borrow_mut(), connection_rid)
|
||||||
|
.map_err(HttpNextError::Resource)?;
|
||||||
|
|
||||||
let listen_properties = HTTP::listen_properties_from_connection(&connection)?;
|
let listen_properties = HTTP::listen_properties_from_connection(&connection)?;
|
||||||
|
|
||||||
let (tx, rx) = tokio::sync::mpsc::channel(10);
|
let (tx, rx) = tokio::sync::mpsc::channel(10);
|
||||||
let resource: Rc<HttpJoinHandle> = Rc::new(HttpJoinHandle::new(rx));
|
let resource: Rc<HttpJoinHandle> = Rc::new(HttpJoinHandle::new(rx));
|
||||||
|
|
||||||
let handle: JoinHandle<Result<(), deno_core::anyhow::Error>> =
|
let handle = serve_http_on::<HTTP>(
|
||||||
serve_http_on::<HTTP>(
|
connection,
|
||||||
connection,
|
&listen_properties,
|
||||||
&listen_properties,
|
resource.lifetime(),
|
||||||
resource.lifetime(),
|
tx,
|
||||||
tx,
|
);
|
||||||
);
|
|
||||||
|
|
||||||
// Set the handle after we start the future
|
// Set the handle after we start the future
|
||||||
*RcRef::map(&resource, |this| &this.join_handle)
|
*RcRef::map(&resource, |this| &this.join_handle)
|
||||||
|
@ -1091,12 +1122,13 @@ pub fn op_http_try_wait(
|
||||||
pub async fn op_http_wait(
|
pub async fn op_http_wait(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
#[smi] rid: ResourceId,
|
#[smi] rid: ResourceId,
|
||||||
) -> Result<*const c_void, AnyError> {
|
) -> Result<*const c_void, HttpNextError> {
|
||||||
// We will get the join handle initially, as we might be consuming requests still
|
// We will get the join handle initially, as we might be consuming requests still
|
||||||
let join_handle = state
|
let join_handle = state
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<HttpJoinHandle>(rid)?;
|
.get::<HttpJoinHandle>(rid)
|
||||||
|
.map_err(HttpNextError::Resource)?;
|
||||||
|
|
||||||
let cancel = join_handle.listen_cancel_handle();
|
let cancel = join_handle.listen_cancel_handle();
|
||||||
let next = async {
|
let next = async {
|
||||||
|
@ -1123,13 +1155,12 @@ pub async fn op_http_wait(
|
||||||
|
|
||||||
// Filter out shutdown (ENOTCONN) errors
|
// Filter out shutdown (ENOTCONN) errors
|
||||||
if let Err(err) = res {
|
if let Err(err) = res {
|
||||||
if let Some(err) = err.source() {
|
if let HttpNextError::Io(err) = &err {
|
||||||
if let Some(err) = err.downcast_ref::<io::Error>() {
|
if err.kind() == io::ErrorKind::NotConnected {
|
||||||
if err.kind() == io::ErrorKind::NotConnected {
|
return Ok(null());
|
||||||
return Ok(null());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1142,7 +1173,7 @@ pub fn op_http_cancel(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[smi] rid: ResourceId,
|
#[smi] rid: ResourceId,
|
||||||
graceful: bool,
|
graceful: bool,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), deno_core::error::AnyError> {
|
||||||
let join_handle = state.resource_table.get::<HttpJoinHandle>(rid)?;
|
let join_handle = state.resource_table.get::<HttpJoinHandle>(rid)?;
|
||||||
|
|
||||||
if graceful {
|
if graceful {
|
||||||
|
@ -1162,11 +1193,12 @@ pub async fn op_http_close(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
#[smi] rid: ResourceId,
|
#[smi] rid: ResourceId,
|
||||||
graceful: bool,
|
graceful: bool,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), HttpNextError> {
|
||||||
let join_handle = state
|
let join_handle = state
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.resource_table
|
.resource_table
|
||||||
.take::<HttpJoinHandle>(rid)?;
|
.take::<HttpJoinHandle>(rid)
|
||||||
|
.map_err(HttpNextError::Resource)?;
|
||||||
|
|
||||||
if graceful {
|
if graceful {
|
||||||
http_general_trace!("graceful shutdown");
|
http_general_trace!("graceful shutdown");
|
||||||
|
@ -1212,23 +1244,26 @@ impl UpgradeStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read(self: Rc<Self>, buf: &mut [u8]) -> Result<usize, AnyError> {
|
async fn read(
|
||||||
|
self: Rc<Self>,
|
||||||
|
buf: &mut [u8],
|
||||||
|
) -> Result<usize, std::io::Error> {
|
||||||
let cancel_handle = RcRef::map(self.clone(), |this| &this.cancel_handle);
|
let cancel_handle = RcRef::map(self.clone(), |this| &this.cancel_handle);
|
||||||
async {
|
async {
|
||||||
let read = RcRef::map(self, |this| &this.read);
|
let read = RcRef::map(self, |this| &this.read);
|
||||||
let mut read = read.borrow_mut().await;
|
let mut read = read.borrow_mut().await;
|
||||||
Ok(Pin::new(&mut *read).read(buf).await?)
|
Pin::new(&mut *read).read(buf).await
|
||||||
}
|
}
|
||||||
.try_or_cancel(cancel_handle)
|
.try_or_cancel(cancel_handle)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn write(self: Rc<Self>, buf: &[u8]) -> Result<usize, AnyError> {
|
async fn write(self: Rc<Self>, buf: &[u8]) -> Result<usize, std::io::Error> {
|
||||||
let cancel_handle = RcRef::map(self.clone(), |this| &this.cancel_handle);
|
let cancel_handle = RcRef::map(self.clone(), |this| &this.cancel_handle);
|
||||||
async {
|
async {
|
||||||
let write = RcRef::map(self, |this| &this.write);
|
let write = RcRef::map(self, |this| &this.write);
|
||||||
let mut write = write.borrow_mut().await;
|
let mut write = write.borrow_mut().await;
|
||||||
Ok(Pin::new(&mut *write).write(buf).await?)
|
Pin::new(&mut *write).write(buf).await
|
||||||
}
|
}
|
||||||
.try_or_cancel(cancel_handle)
|
.try_or_cancel(cancel_handle)
|
||||||
.await
|
.await
|
||||||
|
@ -1238,7 +1273,7 @@ impl UpgradeStream {
|
||||||
self: Rc<Self>,
|
self: Rc<Self>,
|
||||||
buf1: &[u8],
|
buf1: &[u8],
|
||||||
buf2: &[u8],
|
buf2: &[u8],
|
||||||
) -> Result<usize, AnyError> {
|
) -> Result<usize, std::io::Error> {
|
||||||
let mut wr = RcRef::map(self, |r| &r.write).borrow_mut().await;
|
let mut wr = RcRef::map(self, |r| &r.write).borrow_mut().await;
|
||||||
|
|
||||||
let total = buf1.len() + buf2.len();
|
let total = buf1.len() + buf2.len();
|
||||||
|
@ -1291,9 +1326,12 @@ pub async fn op_raw_write_vectored(
|
||||||
#[smi] rid: ResourceId,
|
#[smi] rid: ResourceId,
|
||||||
#[buffer] buf1: JsBuffer,
|
#[buffer] buf1: JsBuffer,
|
||||||
#[buffer] buf2: JsBuffer,
|
#[buffer] buf2: JsBuffer,
|
||||||
) -> Result<usize, AnyError> {
|
) -> Result<usize, HttpNextError> {
|
||||||
let resource: Rc<UpgradeStream> =
|
let resource: Rc<UpgradeStream> = state
|
||||||
state.borrow().resource_table.get::<UpgradeStream>(rid)?;
|
.borrow()
|
||||||
|
.resource_table
|
||||||
|
.get::<UpgradeStream>(rid)
|
||||||
|
.map_err(HttpNextError::Resource)?;
|
||||||
let nwritten = resource.write_vectored(&buf1, &buf2).await?;
|
let nwritten = resource.write_vectored(&buf1, &buf2).await?;
|
||||||
Ok(nwritten)
|
Ok(nwritten)
|
||||||
}
|
}
|
||||||
|
|
153
ext/http/lib.rs
153
ext/http/lib.rs
|
@ -6,8 +6,6 @@ use async_compression::Level;
|
||||||
use base64::prelude::BASE64_STANDARD;
|
use base64::prelude::BASE64_STANDARD;
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
use cache_control::CacheControl;
|
use cache_control::CacheControl;
|
||||||
use deno_core::error::custom_error;
|
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::futures::channel::mpsc;
|
use deno_core::futures::channel::mpsc;
|
||||||
use deno_core::futures::channel::oneshot;
|
use deno_core::futures::channel::oneshot;
|
||||||
use deno_core::futures::future::pending;
|
use deno_core::futures::future::pending;
|
||||||
|
@ -89,11 +87,14 @@ mod service;
|
||||||
mod websocket_upgrade;
|
mod websocket_upgrade;
|
||||||
|
|
||||||
use fly_accept_encoding::Encoding;
|
use fly_accept_encoding::Encoding;
|
||||||
|
pub use http_next::HttpNextError;
|
||||||
pub use request_properties::DefaultHttpPropertyExtractor;
|
pub use request_properties::DefaultHttpPropertyExtractor;
|
||||||
pub use request_properties::HttpConnectionProperties;
|
pub use request_properties::HttpConnectionProperties;
|
||||||
pub use request_properties::HttpListenProperties;
|
pub use request_properties::HttpListenProperties;
|
||||||
pub use request_properties::HttpPropertyExtractor;
|
pub use request_properties::HttpPropertyExtractor;
|
||||||
pub use request_properties::HttpRequestProperties;
|
pub use request_properties::HttpRequestProperties;
|
||||||
|
pub use service::UpgradeUnavailableError;
|
||||||
|
pub use websocket_upgrade::WebSocketUpgradeError;
|
||||||
|
|
||||||
deno_core::extension!(
|
deno_core::extension!(
|
||||||
deno_http,
|
deno_http,
|
||||||
|
@ -134,6 +135,38 @@ deno_core::extension!(
|
||||||
esm = ["00_serve.ts", "01_http.js", "02_websocket.ts"],
|
esm = ["00_serve.ts", "01_http.js", "02_websocket.ts"],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum HttpError {
|
||||||
|
#[error(transparent)]
|
||||||
|
Resource(deno_core::error::AnyError),
|
||||||
|
#[error(transparent)]
|
||||||
|
Canceled(#[from] deno_core::Canceled),
|
||||||
|
#[error("{0}")]
|
||||||
|
HyperV014(#[source] Arc<hyper_v014::Error>),
|
||||||
|
#[error("{0}")]
|
||||||
|
InvalidHeaderName(#[from] hyper_v014::header::InvalidHeaderName),
|
||||||
|
#[error("{0}")]
|
||||||
|
InvalidHeaderValue(#[from] hyper_v014::header::InvalidHeaderValue),
|
||||||
|
#[error("{0}")]
|
||||||
|
Http(#[from] hyper_v014::http::Error),
|
||||||
|
#[error("response headers already sent")]
|
||||||
|
ResponseHeadersAlreadySent,
|
||||||
|
#[error("connection closed while sending response")]
|
||||||
|
ConnectionClosedWhileSendingResponse,
|
||||||
|
#[error("already in use")]
|
||||||
|
AlreadyInUse,
|
||||||
|
#[error("{0}")]
|
||||||
|
Io(#[from] std::io::Error),
|
||||||
|
#[error("no response headers")]
|
||||||
|
NoResponseHeaders,
|
||||||
|
#[error("response already completed")]
|
||||||
|
ResponseAlreadyCompleted,
|
||||||
|
#[error("cannot upgrade because request body was used")]
|
||||||
|
UpgradeBodyUsed,
|
||||||
|
#[error(transparent)]
|
||||||
|
Other(deno_core::error::AnyError),
|
||||||
|
}
|
||||||
|
|
||||||
pub enum HttpSocketAddr {
|
pub enum HttpSocketAddr {
|
||||||
IpSocket(std::net::SocketAddr),
|
IpSocket(std::net::SocketAddr),
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
|
@ -216,7 +249,7 @@ impl HttpConnResource {
|
||||||
String,
|
String,
|
||||||
String,
|
String,
|
||||||
)>,
|
)>,
|
||||||
AnyError,
|
HttpError,
|
||||||
> {
|
> {
|
||||||
let fut = async {
|
let fut = async {
|
||||||
let (request_tx, request_rx) = oneshot::channel();
|
let (request_tx, request_rx) = oneshot::channel();
|
||||||
|
@ -259,8 +292,8 @@ impl HttpConnResource {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A future that completes when this HTTP connection is closed or errors.
|
/// A future that completes when this HTTP connection is closed or errors.
|
||||||
async fn closed(&self) -> Result<(), AnyError> {
|
async fn closed(&self) -> Result<(), HttpError> {
|
||||||
self.closed_fut.clone().map_err(AnyError::from).await
|
self.closed_fut.clone().map_err(HttpError::HyperV014).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,14 +313,13 @@ pub fn http_create_conn_resource<S, A>(
|
||||||
io: S,
|
io: S,
|
||||||
addr: A,
|
addr: A,
|
||||||
scheme: &'static str,
|
scheme: &'static str,
|
||||||
) -> Result<ResourceId, AnyError>
|
) -> ResourceId
|
||||||
where
|
where
|
||||||
S: AsyncRead + AsyncWrite + Unpin + Send + 'static,
|
S: AsyncRead + AsyncWrite + Unpin + Send + 'static,
|
||||||
A: Into<HttpSocketAddr>,
|
A: Into<HttpSocketAddr>,
|
||||||
{
|
{
|
||||||
let conn = HttpConnResource::new(io, scheme, addr.into());
|
let conn = HttpConnResource::new(io, scheme, addr.into());
|
||||||
let rid = state.resource_table.add(conn);
|
state.resource_table.add(conn)
|
||||||
Ok(rid)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An object that implements the `hyper::Service` trait, through which Hyper
|
/// An object that implements the `hyper::Service` trait, through which Hyper
|
||||||
|
@ -423,7 +455,9 @@ impl Resource for HttpStreamReadResource {
|
||||||
// safely call `await` on it without creating a race condition.
|
// safely call `await` on it without creating a race condition.
|
||||||
Some(_) => match body.as_mut().next().await.unwrap() {
|
Some(_) => match body.as_mut().next().await.unwrap() {
|
||||||
Ok(chunk) => assert!(chunk.is_empty()),
|
Ok(chunk) => assert!(chunk.is_empty()),
|
||||||
Err(err) => break Err(AnyError::from(err)),
|
Err(err) => {
|
||||||
|
break Err(HttpError::HyperV014(Arc::new(err)).into())
|
||||||
|
}
|
||||||
},
|
},
|
||||||
None => break Ok(BufView::empty()),
|
None => break Ok(BufView::empty()),
|
||||||
}
|
}
|
||||||
|
@ -545,8 +579,12 @@ struct NextRequestResponse(
|
||||||
async fn op_http_accept(
|
async fn op_http_accept(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
#[smi] rid: ResourceId,
|
#[smi] rid: ResourceId,
|
||||||
) -> Result<Option<NextRequestResponse>, AnyError> {
|
) -> Result<Option<NextRequestResponse>, HttpError> {
|
||||||
let conn = state.borrow().resource_table.get::<HttpConnResource>(rid)?;
|
let conn = state
|
||||||
|
.borrow()
|
||||||
|
.resource_table
|
||||||
|
.get::<HttpConnResource>(rid)
|
||||||
|
.map_err(HttpError::Resource)?;
|
||||||
|
|
||||||
match conn.accept().await {
|
match conn.accept().await {
|
||||||
Ok(Some((read_stream, write_stream, method, url))) => {
|
Ok(Some((read_stream, write_stream, method, url))) => {
|
||||||
|
@ -657,11 +695,12 @@ async fn op_http_write_headers(
|
||||||
#[smi] status: u16,
|
#[smi] status: u16,
|
||||||
#[serde] headers: Vec<(ByteString, ByteString)>,
|
#[serde] headers: Vec<(ByteString, ByteString)>,
|
||||||
#[serde] data: Option<StringOrBuffer>,
|
#[serde] data: Option<StringOrBuffer>,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), HttpError> {
|
||||||
let stream = state
|
let stream = state
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<HttpStreamWriteResource>(rid)?;
|
.get::<HttpStreamWriteResource>(rid)
|
||||||
|
.map_err(HttpError::Resource)?;
|
||||||
|
|
||||||
// Track supported encoding
|
// Track supported encoding
|
||||||
let encoding = stream.accept_encoding;
|
let encoding = stream.accept_encoding;
|
||||||
|
@ -708,14 +747,14 @@ async fn op_http_write_headers(
|
||||||
let mut old_wr = RcRef::map(&stream, |r| &r.wr).borrow_mut().await;
|
let mut old_wr = RcRef::map(&stream, |r| &r.wr).borrow_mut().await;
|
||||||
let response_tx = match replace(&mut *old_wr, new_wr) {
|
let response_tx = match replace(&mut *old_wr, new_wr) {
|
||||||
HttpResponseWriter::Headers(response_tx) => response_tx,
|
HttpResponseWriter::Headers(response_tx) => response_tx,
|
||||||
_ => return Err(http_error("response headers already sent")),
|
_ => return Err(HttpError::ResponseHeadersAlreadySent),
|
||||||
};
|
};
|
||||||
|
|
||||||
match response_tx.send(body) {
|
match response_tx.send(body) {
|
||||||
Ok(_) => Ok(()),
|
Ok(_) => Ok(()),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
stream.conn.closed().await?;
|
stream.conn.closed().await?;
|
||||||
Err(http_error("connection closed while sending response"))
|
Err(HttpError::ConnectionClosedWhileSendingResponse)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -725,11 +764,14 @@ async fn op_http_write_headers(
|
||||||
fn op_http_headers(
|
fn op_http_headers(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[smi] rid: u32,
|
#[smi] rid: u32,
|
||||||
) -> Result<Vec<(ByteString, ByteString)>, AnyError> {
|
) -> Result<Vec<(ByteString, ByteString)>, HttpError> {
|
||||||
let stream = state.resource_table.get::<HttpStreamReadResource>(rid)?;
|
let stream = state
|
||||||
|
.resource_table
|
||||||
|
.get::<HttpStreamReadResource>(rid)
|
||||||
|
.map_err(HttpError::Resource)?;
|
||||||
let rd = RcRef::map(&stream, |r| &r.rd)
|
let rd = RcRef::map(&stream, |r| &r.rd)
|
||||||
.try_borrow()
|
.try_borrow()
|
||||||
.ok_or_else(|| http_error("already in use"))?;
|
.ok_or(HttpError::AlreadyInUse)?;
|
||||||
match &*rd {
|
match &*rd {
|
||||||
HttpRequestReader::Headers(request) => Ok(req_headers(request.headers())),
|
HttpRequestReader::Headers(request) => Ok(req_headers(request.headers())),
|
||||||
HttpRequestReader::Body(headers, _) => Ok(req_headers(headers)),
|
HttpRequestReader::Body(headers, _) => Ok(req_headers(headers)),
|
||||||
|
@ -741,7 +783,7 @@ fn http_response(
|
||||||
data: Option<StringOrBuffer>,
|
data: Option<StringOrBuffer>,
|
||||||
compressing: bool,
|
compressing: bool,
|
||||||
encoding: Encoding,
|
encoding: Encoding,
|
||||||
) -> Result<(HttpResponseWriter, hyper_v014::Body), AnyError> {
|
) -> Result<(HttpResponseWriter, hyper_v014::Body), HttpError> {
|
||||||
// Gzip, after level 1, doesn't produce significant size difference.
|
// Gzip, after level 1, doesn't produce significant size difference.
|
||||||
// This default matches nginx default gzip compression level (1):
|
// This default matches nginx default gzip compression level (1):
|
||||||
// https://nginx.org/en/docs/http/ngx_http_gzip_module.html#gzip_comp_level
|
// https://nginx.org/en/docs/http/ngx_http_gzip_module.html#gzip_comp_level
|
||||||
|
@ -878,25 +920,34 @@ async fn op_http_write_resource(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
#[smi] rid: ResourceId,
|
#[smi] rid: ResourceId,
|
||||||
#[smi] stream: ResourceId,
|
#[smi] stream: ResourceId,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), HttpError> {
|
||||||
let http_stream = state
|
let http_stream = state
|
||||||
.borrow()
|
.borrow()
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<HttpStreamWriteResource>(rid)?;
|
.get::<HttpStreamWriteResource>(rid)
|
||||||
|
.map_err(HttpError::Resource)?;
|
||||||
let mut wr = RcRef::map(&http_stream, |r| &r.wr).borrow_mut().await;
|
let mut wr = RcRef::map(&http_stream, |r| &r.wr).borrow_mut().await;
|
||||||
let resource = state.borrow().resource_table.get_any(stream)?;
|
let resource = state
|
||||||
|
.borrow()
|
||||||
|
.resource_table
|
||||||
|
.get_any(stream)
|
||||||
|
.map_err(HttpError::Resource)?;
|
||||||
loop {
|
loop {
|
||||||
match *wr {
|
match *wr {
|
||||||
HttpResponseWriter::Headers(_) => {
|
HttpResponseWriter::Headers(_) => {
|
||||||
return Err(http_error("no response headers"))
|
return Err(HttpError::NoResponseHeaders)
|
||||||
}
|
}
|
||||||
HttpResponseWriter::Closed => {
|
HttpResponseWriter::Closed => {
|
||||||
return Err(http_error("response already completed"))
|
return Err(HttpError::ResponseAlreadyCompleted)
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
let view = resource.clone().read(64 * 1024).await?; // 64KB
|
let view = resource
|
||||||
|
.clone()
|
||||||
|
.read(64 * 1024)
|
||||||
|
.await
|
||||||
|
.map_err(HttpError::Other)?; // 64KB
|
||||||
if view.is_empty() {
|
if view.is_empty() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -937,16 +988,17 @@ async fn op_http_write(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
#[smi] rid: ResourceId,
|
#[smi] rid: ResourceId,
|
||||||
#[buffer] buf: JsBuffer,
|
#[buffer] buf: JsBuffer,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), HttpError> {
|
||||||
let stream = state
|
let stream = state
|
||||||
.borrow()
|
.borrow()
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<HttpStreamWriteResource>(rid)?;
|
.get::<HttpStreamWriteResource>(rid)
|
||||||
|
.map_err(HttpError::Resource)?;
|
||||||
let mut wr = RcRef::map(&stream, |r| &r.wr).borrow_mut().await;
|
let mut wr = RcRef::map(&stream, |r| &r.wr).borrow_mut().await;
|
||||||
|
|
||||||
match &mut *wr {
|
match &mut *wr {
|
||||||
HttpResponseWriter::Headers(_) => Err(http_error("no response headers")),
|
HttpResponseWriter::Headers(_) => Err(HttpError::NoResponseHeaders),
|
||||||
HttpResponseWriter::Closed => Err(http_error("response already completed")),
|
HttpResponseWriter::Closed => Err(HttpError::ResponseAlreadyCompleted),
|
||||||
HttpResponseWriter::Body { writer, .. } => {
|
HttpResponseWriter::Body { writer, .. } => {
|
||||||
let mut result = writer.write_all(&buf).await;
|
let mut result = writer.write_all(&buf).await;
|
||||||
if result.is_ok() {
|
if result.is_ok() {
|
||||||
|
@ -961,7 +1013,7 @@ async fn op_http_write(
|
||||||
stream.conn.closed().await?;
|
stream.conn.closed().await?;
|
||||||
// If there was no connection error, drop body_tx.
|
// If there was no connection error, drop body_tx.
|
||||||
*wr = HttpResponseWriter::Closed;
|
*wr = HttpResponseWriter::Closed;
|
||||||
Err(http_error("response already completed"))
|
Err(HttpError::ResponseAlreadyCompleted)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -975,7 +1027,7 @@ async fn op_http_write(
|
||||||
stream.conn.closed().await?;
|
stream.conn.closed().await?;
|
||||||
// If there was no connection error, drop body_tx.
|
// If there was no connection error, drop body_tx.
|
||||||
*wr = HttpResponseWriter::Closed;
|
*wr = HttpResponseWriter::Closed;
|
||||||
Err(http_error("response already completed"))
|
Err(HttpError::ResponseAlreadyCompleted)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -989,11 +1041,12 @@ async fn op_http_write(
|
||||||
async fn op_http_shutdown(
|
async fn op_http_shutdown(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
#[smi] rid: ResourceId,
|
#[smi] rid: ResourceId,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), HttpError> {
|
||||||
let stream = state
|
let stream = state
|
||||||
.borrow()
|
.borrow()
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<HttpStreamWriteResource>(rid)?;
|
.get::<HttpStreamWriteResource>(rid)
|
||||||
|
.map_err(HttpError::Resource)?;
|
||||||
let mut wr = RcRef::map(&stream, |r| &r.wr).borrow_mut().await;
|
let mut wr = RcRef::map(&stream, |r| &r.wr).borrow_mut().await;
|
||||||
let wr = take(&mut *wr);
|
let wr = take(&mut *wr);
|
||||||
match wr {
|
match wr {
|
||||||
|
@ -1022,14 +1075,12 @@ async fn op_http_shutdown(
|
||||||
|
|
||||||
#[op2]
|
#[op2]
|
||||||
#[string]
|
#[string]
|
||||||
fn op_http_websocket_accept_header(
|
fn op_http_websocket_accept_header(#[string] key: String) -> String {
|
||||||
#[string] key: String,
|
|
||||||
) -> Result<String, AnyError> {
|
|
||||||
let digest = ring::digest::digest(
|
let digest = ring::digest::digest(
|
||||||
&ring::digest::SHA1_FOR_LEGACY_USE_ONLY,
|
&ring::digest::SHA1_FOR_LEGACY_USE_ONLY,
|
||||||
format!("{key}258EAFA5-E914-47DA-95CA-C5AB0DC85B11").as_bytes(),
|
format!("{key}258EAFA5-E914-47DA-95CA-C5AB0DC85B11").as_bytes(),
|
||||||
);
|
);
|
||||||
Ok(BASE64_STANDARD.encode(digest))
|
BASE64_STANDARD.encode(digest)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[op2(async)]
|
#[op2(async)]
|
||||||
|
@ -1037,25 +1088,29 @@ fn op_http_websocket_accept_header(
|
||||||
async fn op_http_upgrade_websocket(
|
async fn op_http_upgrade_websocket(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
#[smi] rid: ResourceId,
|
#[smi] rid: ResourceId,
|
||||||
) -> Result<ResourceId, AnyError> {
|
) -> Result<ResourceId, HttpError> {
|
||||||
let stream = state
|
let stream = state
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<HttpStreamReadResource>(rid)?;
|
.get::<HttpStreamReadResource>(rid)
|
||||||
|
.map_err(HttpError::Resource)?;
|
||||||
let mut rd = RcRef::map(&stream, |r| &r.rd).borrow_mut().await;
|
let mut rd = RcRef::map(&stream, |r| &r.rd).borrow_mut().await;
|
||||||
|
|
||||||
let request = match &mut *rd {
|
let request = match &mut *rd {
|
||||||
HttpRequestReader::Headers(request) => request,
|
HttpRequestReader::Headers(request) => request,
|
||||||
_ => {
|
_ => return Err(HttpError::UpgradeBodyUsed),
|
||||||
return Err(http_error("cannot upgrade because request body was used"))
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let (transport, bytes) =
|
let (transport, bytes) = extract_network_stream(
|
||||||
extract_network_stream(hyper_v014::upgrade::on(request).await?);
|
hyper_v014::upgrade::on(request)
|
||||||
let ws_rid =
|
.await
|
||||||
ws_create_server_stream(&mut state.borrow_mut(), transport, bytes)?;
|
.map_err(|err| HttpError::HyperV014(Arc::new(err)))?,
|
||||||
Ok(ws_rid)
|
);
|
||||||
|
Ok(ws_create_server_stream(
|
||||||
|
&mut state.borrow_mut(),
|
||||||
|
transport,
|
||||||
|
bytes,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Needed so hyper can use non Send futures
|
// Needed so hyper can use non Send futures
|
||||||
|
@ -1082,10 +1137,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn http_error(message: &'static str) -> AnyError {
|
|
||||||
custom_error("Http", message)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Filters out the ever-surprising 'shutdown ENOTCONN' errors.
|
/// Filters out the ever-surprising 'shutdown ENOTCONN' errors.
|
||||||
fn filter_enotconn(
|
fn filter_enotconn(
|
||||||
result: Result<(), hyper_v014::Error>,
|
result: Result<(), hyper_v014::Error>,
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::futures::stream::Peekable;
|
use deno_core::futures::stream::Peekable;
|
||||||
use deno_core::futures::Stream;
|
use deno_core::futures::Stream;
|
||||||
use deno_core::futures::StreamExt;
|
use deno_core::futures::StreamExt;
|
||||||
|
use deno_core::futures::TryFutureExt;
|
||||||
use deno_core::AsyncRefCell;
|
use deno_core::AsyncRefCell;
|
||||||
use deno_core::AsyncResult;
|
use deno_core::AsyncResult;
|
||||||
use deno_core::BufView;
|
use deno_core::BufView;
|
||||||
|
@ -22,7 +22,7 @@ use std::task::Poll;
|
||||||
struct ReadFuture(Incoming);
|
struct ReadFuture(Incoming);
|
||||||
|
|
||||||
impl Stream for ReadFuture {
|
impl Stream for ReadFuture {
|
||||||
type Item = Result<Bytes, AnyError>;
|
type Item = Result<Bytes, hyper::Error>;
|
||||||
|
|
||||||
fn poll_next(
|
fn poll_next(
|
||||||
self: Pin<&mut Self>,
|
self: Pin<&mut Self>,
|
||||||
|
@ -37,13 +37,13 @@ impl Stream for ReadFuture {
|
||||||
if let Ok(data) = frame.into_data() {
|
if let Ok(data) = frame.into_data() {
|
||||||
// Ensure that we never yield an empty frame
|
// Ensure that we never yield an empty frame
|
||||||
if !data.is_empty() {
|
if !data.is_empty() {
|
||||||
break Poll::Ready(Some(Ok::<_, AnyError>(data)));
|
break Poll::Ready(Some(Ok(data)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Loop again so we don't lose the waker
|
// Loop again so we don't lose the waker
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Some(Err(e)) => Poll::Ready(Some(Err(e.into()))),
|
Some(Err(e)) => Poll::Ready(Some(Err(e))),
|
||||||
None => Poll::Ready(None),
|
None => Poll::Ready(None),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ impl HttpRequestBody {
|
||||||
Self(AsyncRefCell::new(ReadFuture(body).peekable()), size_hint)
|
Self(AsyncRefCell::new(ReadFuture(body).peekable()), size_hint)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read(self: Rc<Self>, limit: usize) -> Result<BufView, AnyError> {
|
async fn read(self: Rc<Self>, limit: usize) -> Result<BufView, hyper::Error> {
|
||||||
let peekable = RcRef::map(self, |this| &this.0);
|
let peekable = RcRef::map(self, |this| &this.0);
|
||||||
let mut peekable = peekable.borrow_mut().await;
|
let mut peekable = peekable.borrow_mut().await;
|
||||||
match Pin::new(&mut *peekable).peek_mut().await {
|
match Pin::new(&mut *peekable).peek_mut().await {
|
||||||
|
@ -82,7 +82,7 @@ impl Resource for HttpRequestBody {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read(self: Rc<Self>, limit: usize) -> AsyncResult<BufView> {
|
fn read(self: Rc<Self>, limit: usize) -> AsyncResult<BufView> {
|
||||||
Box::pin(HttpRequestBody::read(self, limit))
|
Box::pin(HttpRequestBody::read(self, limit).map_err(Into::into))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size_hint(&self) -> (u64, Option<u64>) {
|
fn size_hint(&self) -> (u64, Option<u64>) {
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
use crate::request_properties::HttpConnectionProperties;
|
use crate::request_properties::HttpConnectionProperties;
|
||||||
use crate::response_body::ResponseBytesInner;
|
use crate::response_body::ResponseBytesInner;
|
||||||
use crate::response_body::ResponseStreamResult;
|
use crate::response_body::ResponseStreamResult;
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::futures::ready;
|
use deno_core::futures::ready;
|
||||||
use deno_core::BufView;
|
use deno_core::BufView;
|
||||||
use deno_core::OpState;
|
use deno_core::OpState;
|
||||||
|
@ -206,6 +205,10 @@ pub(crate) async fn handle_request(
|
||||||
Ok(response)
|
Ok(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
#[error("upgrade unavailable")]
|
||||||
|
pub struct UpgradeUnavailableError;
|
||||||
|
|
||||||
struct HttpRecordInner {
|
struct HttpRecordInner {
|
||||||
server_state: SignallingRc<HttpServerState>,
|
server_state: SignallingRc<HttpServerState>,
|
||||||
request_info: HttpConnectionProperties,
|
request_info: HttpConnectionProperties,
|
||||||
|
@ -344,14 +347,14 @@ impl HttpRecord {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform the Hyper upgrade on this record.
|
/// Perform the Hyper upgrade on this record.
|
||||||
pub fn upgrade(&self) -> Result<OnUpgrade, AnyError> {
|
pub fn upgrade(&self) -> Result<OnUpgrade, UpgradeUnavailableError> {
|
||||||
// Manually perform the upgrade. We're peeking into hyper's underlying machinery here a bit
|
// Manually perform the upgrade. We're peeking into hyper's underlying machinery here a bit
|
||||||
self
|
self
|
||||||
.self_mut()
|
.self_mut()
|
||||||
.request_parts
|
.request_parts
|
||||||
.extensions
|
.extensions
|
||||||
.remove::<OnUpgrade>()
|
.remove::<OnUpgrade>()
|
||||||
.ok_or_else(|| AnyError::msg("upgrade unavailable"))
|
.ok_or(UpgradeUnavailableError)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Take the Hyper body from this record.
|
/// Take the Hyper body from this record.
|
||||||
|
@ -515,7 +518,7 @@ pub struct HttpRecordResponse(ManuallyDrop<Rc<HttpRecord>>);
|
||||||
|
|
||||||
impl Body for HttpRecordResponse {
|
impl Body for HttpRecordResponse {
|
||||||
type Data = BufView;
|
type Data = BufView;
|
||||||
type Error = AnyError;
|
type Error = deno_core::error::AnyError;
|
||||||
|
|
||||||
fn poll_frame(
|
fn poll_frame(
|
||||||
self: Pin<&mut Self>,
|
self: Pin<&mut Self>,
|
||||||
|
@ -640,7 +643,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_handle_request() -> Result<(), AnyError> {
|
async fn test_handle_request() -> Result<(), deno_core::error::AnyError> {
|
||||||
let (tx, mut rx) = tokio::sync::mpsc::channel(10);
|
let (tx, mut rx) = tokio::sync::mpsc::channel(10);
|
||||||
let server_state = HttpServerState::new();
|
let server_state = HttpServerState::new();
|
||||||
let server_state_check = server_state.clone();
|
let server_state_check = server_state.clone();
|
||||||
|
|
|
@ -4,7 +4,6 @@ use std::marker::PhantomData;
|
||||||
|
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use bytes::BytesMut;
|
use bytes::BytesMut;
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use httparse::Status;
|
use httparse::Status;
|
||||||
use hyper::header::HeaderName;
|
use hyper::header::HeaderName;
|
||||||
use hyper::header::HeaderValue;
|
use hyper::header::HeaderValue;
|
||||||
|
@ -13,12 +12,30 @@ use memmem::Searcher;
|
||||||
use memmem::TwoWaySearcher;
|
use memmem::TwoWaySearcher;
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
|
|
||||||
use crate::http_error;
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum WebSocketUpgradeError {
|
||||||
|
#[error("invalid headers")]
|
||||||
|
InvalidHeaders,
|
||||||
|
#[error("{0}")]
|
||||||
|
HttpParse(#[from] httparse::Error),
|
||||||
|
#[error("{0}")]
|
||||||
|
Http(#[from] http::Error),
|
||||||
|
#[error("{0}")]
|
||||||
|
Utf8(#[from] std::str::Utf8Error),
|
||||||
|
#[error("{0}")]
|
||||||
|
InvalidHeaderName(#[from] http::header::InvalidHeaderName),
|
||||||
|
#[error("{0}")]
|
||||||
|
InvalidHeaderValue(#[from] http::header::InvalidHeaderValue),
|
||||||
|
#[error("invalid HTTP status line")]
|
||||||
|
InvalidHttpStatusLine,
|
||||||
|
#[error("attempted to write to completed upgrade buffer")]
|
||||||
|
UpgradeBufferAlreadyCompleted,
|
||||||
|
}
|
||||||
|
|
||||||
/// Given a buffer that ends in `\n\n` or `\r\n\r\n`, returns a parsed [`Request<Body>`].
|
/// Given a buffer that ends in `\n\n` or `\r\n\r\n`, returns a parsed [`Request<Body>`].
|
||||||
fn parse_response<T: Default>(
|
fn parse_response<T: Default>(
|
||||||
header_bytes: &[u8],
|
header_bytes: &[u8],
|
||||||
) -> Result<(usize, Response<T>), AnyError> {
|
) -> Result<(usize, Response<T>), WebSocketUpgradeError> {
|
||||||
let mut headers = [httparse::EMPTY_HEADER; 16];
|
let mut headers = [httparse::EMPTY_HEADER; 16];
|
||||||
let status = httparse::parse_headers(header_bytes, &mut headers)?;
|
let status = httparse::parse_headers(header_bytes, &mut headers)?;
|
||||||
match status {
|
match status {
|
||||||
|
@ -32,7 +49,7 @@ fn parse_response<T: Default>(
|
||||||
}
|
}
|
||||||
Ok((index, resp))
|
Ok((index, resp))
|
||||||
}
|
}
|
||||||
_ => Err(http_error("invalid headers")),
|
_ => Err(WebSocketUpgradeError::InvalidHeaders),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,11 +86,14 @@ pub struct WebSocketUpgrade<T: Default> {
|
||||||
impl<T: Default> WebSocketUpgrade<T> {
|
impl<T: Default> WebSocketUpgrade<T> {
|
||||||
/// Ensures that the status line starts with "HTTP/1.1 101 " which matches all of the node.js
|
/// Ensures that the status line starts with "HTTP/1.1 101 " which matches all of the node.js
|
||||||
/// WebSocket libraries that are known. We don't care about the trailing status text.
|
/// WebSocket libraries that are known. We don't care about the trailing status text.
|
||||||
fn validate_status(&self, status: &[u8]) -> Result<(), AnyError> {
|
fn validate_status(
|
||||||
|
&self,
|
||||||
|
status: &[u8],
|
||||||
|
) -> Result<(), WebSocketUpgradeError> {
|
||||||
if status.starts_with(b"HTTP/1.1 101 ") {
|
if status.starts_with(b"HTTP/1.1 101 ") {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(http_error("invalid HTTP status line"))
|
Err(WebSocketUpgradeError::InvalidHttpStatusLine)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +102,7 @@ impl<T: Default> WebSocketUpgrade<T> {
|
||||||
pub fn write(
|
pub fn write(
|
||||||
&mut self,
|
&mut self,
|
||||||
bytes: &[u8],
|
bytes: &[u8],
|
||||||
) -> Result<Option<(Response<T>, Bytes)>, AnyError> {
|
) -> Result<Option<(Response<T>, Bytes)>, WebSocketUpgradeError> {
|
||||||
use WebSocketUpgradeState::*;
|
use WebSocketUpgradeState::*;
|
||||||
|
|
||||||
match self.state {
|
match self.state {
|
||||||
|
@ -142,9 +162,7 @@ impl<T: Default> WebSocketUpgrade<T> {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Complete => {
|
Complete => Err(WebSocketUpgradeError::UpgradeBufferAlreadyCompleted),
|
||||||
Err(http_error("attempted to write to completed upgrade buffer"))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,8 +175,8 @@ mod tests {
|
||||||
type ExpectedResponseAndHead = Option<(Response<Body>, &'static [u8])>;
|
type ExpectedResponseAndHead = Option<(Response<Body>, &'static [u8])>;
|
||||||
|
|
||||||
fn assert_response(
|
fn assert_response(
|
||||||
result: Result<Option<(Response<Body>, Bytes)>, AnyError>,
|
result: Result<Option<(Response<Body>, Bytes)>, WebSocketUpgradeError>,
|
||||||
expected: Result<ExpectedResponseAndHead, &'static str>,
|
expected: Result<ExpectedResponseAndHead, WebSocketUpgradeError>,
|
||||||
chunk_info: Option<(usize, usize)>,
|
chunk_info: Option<(usize, usize)>,
|
||||||
) {
|
) {
|
||||||
let formatted = format!("{result:?}");
|
let formatted = format!("{result:?}");
|
||||||
|
@ -189,8 +207,8 @@ mod tests {
|
||||||
"Expected Ok(None), was {formatted}",
|
"Expected Ok(None), was {formatted}",
|
||||||
),
|
),
|
||||||
Err(e) => assert_eq!(
|
Err(e) => assert_eq!(
|
||||||
e,
|
format!("{e:?}"),
|
||||||
result.err().map(|e| format!("{e:?}")).unwrap_or_default(),
|
format!("{:?}", result.unwrap_err()),
|
||||||
"Expected error, was {formatted}",
|
"Expected error, was {formatted}",
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
@ -198,7 +216,7 @@ mod tests {
|
||||||
|
|
||||||
fn validate_upgrade_all_at_once(
|
fn validate_upgrade_all_at_once(
|
||||||
s: &str,
|
s: &str,
|
||||||
expected: Result<ExpectedResponseAndHead, &'static str>,
|
expected: Result<ExpectedResponseAndHead, WebSocketUpgradeError>,
|
||||||
) {
|
) {
|
||||||
let mut upgrade = WebSocketUpgrade::default();
|
let mut upgrade = WebSocketUpgrade::default();
|
||||||
let res = upgrade.write(s.as_bytes());
|
let res = upgrade.write(s.as_bytes());
|
||||||
|
@ -209,7 +227,7 @@ mod tests {
|
||||||
fn validate_upgrade_chunks(
|
fn validate_upgrade_chunks(
|
||||||
s: &str,
|
s: &str,
|
||||||
size: usize,
|
size: usize,
|
||||||
expected: Result<ExpectedResponseAndHead, &'static str>,
|
expected: Result<ExpectedResponseAndHead, WebSocketUpgradeError>,
|
||||||
) {
|
) {
|
||||||
let chunk_info = Some((s.as_bytes().len(), size));
|
let chunk_info = Some((s.as_bytes().len(), size));
|
||||||
let mut upgrade = WebSocketUpgrade::default();
|
let mut upgrade = WebSocketUpgrade::default();
|
||||||
|
@ -226,7 +244,7 @@ mod tests {
|
||||||
|
|
||||||
fn validate_upgrade(
|
fn validate_upgrade(
|
||||||
s: &str,
|
s: &str,
|
||||||
expected: fn() -> Result<ExpectedResponseAndHead, &'static str>,
|
expected: fn() -> Result<ExpectedResponseAndHead, WebSocketUpgradeError>,
|
||||||
) {
|
) {
|
||||||
validate_upgrade_all_at_once(s, expected());
|
validate_upgrade_all_at_once(s, expected());
|
||||||
validate_upgrade_chunks(s, 1, expected());
|
validate_upgrade_chunks(s, 1, expected());
|
||||||
|
@ -315,7 +333,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn upgrade_invalid_status() {
|
fn upgrade_invalid_status() {
|
||||||
validate_upgrade("HTTP/1.1 200 OK\nConnection: Upgrade\n\n", || {
|
validate_upgrade("HTTP/1.1 200 OK\nConnection: Upgrade\n\n", || {
|
||||||
Err("invalid HTTP status line")
|
Err(WebSocketUpgradeError::InvalidHttpStatusLine)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,7 +345,11 @@ mod tests {
|
||||||
.join("\n");
|
.join("\n");
|
||||||
validate_upgrade(
|
validate_upgrade(
|
||||||
&format!("HTTP/1.1 101 Switching Protocols\n{headers}\n\n"),
|
&format!("HTTP/1.1 101 Switching Protocols\n{headers}\n\n"),
|
||||||
|| Err("too many headers"),
|
|| {
|
||||||
|
Err(WebSocketUpgradeError::HttpParse(
|
||||||
|
httparse::Error::TooManyHeaders,
|
||||||
|
))
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -469,6 +469,7 @@ deno_core::extension!(deno_node,
|
||||||
"internal_binding/constants.ts",
|
"internal_binding/constants.ts",
|
||||||
"internal_binding/crypto.ts",
|
"internal_binding/crypto.ts",
|
||||||
"internal_binding/handle_wrap.ts",
|
"internal_binding/handle_wrap.ts",
|
||||||
|
"internal_binding/http_parser.ts",
|
||||||
"internal_binding/mod.ts",
|
"internal_binding/mod.ts",
|
||||||
"internal_binding/node_file.ts",
|
"internal_binding/node_file.ts",
|
||||||
"internal_binding/node_options.ts",
|
"internal_binding/node_options.ts",
|
||||||
|
|
|
@ -66,6 +66,7 @@ pub fn op_node_sys_to_uv_error(err: i32) -> String {
|
||||||
ERROR_INVALID_PARAMETER => "EINVAL",
|
ERROR_INVALID_PARAMETER => "EINVAL",
|
||||||
WSAEINVAL => "EINVAL",
|
WSAEINVAL => "EINVAL",
|
||||||
WSAEPFNOSUPPORT => "EINVAL",
|
WSAEPFNOSUPPORT => "EINVAL",
|
||||||
|
ERROR_NOT_A_REPARSE_POINT => "EINVAL",
|
||||||
ERROR_BEGINNING_OF_MEDIA => "EIO",
|
ERROR_BEGINNING_OF_MEDIA => "EIO",
|
||||||
ERROR_BUS_RESET => "EIO",
|
ERROR_BUS_RESET => "EIO",
|
||||||
ERROR_CRC => "EIO",
|
ERROR_CRC => "EIO",
|
||||||
|
|
|
@ -4,13 +4,10 @@
|
||||||
// deno-lint-ignore-file prefer-primordials
|
// deno-lint-ignore-file prefer-primordials
|
||||||
|
|
||||||
import { TextEncoder } from "ext:deno_web/08_text_encoding.js";
|
import { TextEncoder } from "ext:deno_web/08_text_encoding.js";
|
||||||
import {
|
import { MaybeEmpty, notImplemented } from "ext:deno_node/_utils.ts";
|
||||||
intoCallbackAPIWithIntercept,
|
|
||||||
MaybeEmpty,
|
|
||||||
notImplemented,
|
|
||||||
} from "ext:deno_node/_utils.ts";
|
|
||||||
import { pathFromURL } from "ext:deno_web/00_infra.js";
|
import { pathFromURL } from "ext:deno_web/00_infra.js";
|
||||||
import { promisify } from "ext:deno_node/internal/util.mjs";
|
import { promisify } from "ext:deno_node/internal/util.mjs";
|
||||||
|
import { denoErrorToNodeError } from "ext:deno_node/internal/errors.ts";
|
||||||
|
|
||||||
type ReadlinkCallback = (
|
type ReadlinkCallback = (
|
||||||
err: MaybeEmpty<Error>,
|
err: MaybeEmpty<Error>,
|
||||||
|
@ -69,12 +66,17 @@ export function readlink(
|
||||||
|
|
||||||
const encoding = getEncoding(optOrCallback);
|
const encoding = getEncoding(optOrCallback);
|
||||||
|
|
||||||
intoCallbackAPIWithIntercept<string, Uint8Array | string>(
|
Deno.readLink(path).then((data: string) => {
|
||||||
Deno.readLink,
|
const res = maybeEncode(data, encoding);
|
||||||
(data: string): string | Uint8Array => maybeEncode(data, encoding),
|
if (cb) cb(null, res);
|
||||||
cb,
|
}, (err: Error) => {
|
||||||
path,
|
if (cb) {
|
||||||
);
|
(cb as (e: Error) => void)(denoErrorToNodeError(err, {
|
||||||
|
syscall: "readlink",
|
||||||
|
path,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export const readlinkPromise = promisify(readlink) as (
|
export const readlinkPromise = promisify(readlink) as (
|
||||||
|
@ -88,5 +90,12 @@ export function readlinkSync(
|
||||||
): string | Uint8Array {
|
): string | Uint8Array {
|
||||||
path = path instanceof URL ? pathFromURL(path) : path;
|
path = path instanceof URL ? pathFromURL(path) : path;
|
||||||
|
|
||||||
return maybeEncode(Deno.readLinkSync(path), getEncoding(opt));
|
try {
|
||||||
|
return maybeEncode(Deno.readLinkSync(path), getEncoding(opt));
|
||||||
|
} catch (error) {
|
||||||
|
throw denoErrorToNodeError(error, {
|
||||||
|
syscall: "readlink",
|
||||||
|
path,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,8 +87,7 @@ export function runNextTicks() {
|
||||||
// runMicrotasks();
|
// runMicrotasks();
|
||||||
// if (!hasTickScheduled() && !hasRejectionToWarn())
|
// if (!hasTickScheduled() && !hasRejectionToWarn())
|
||||||
// return;
|
// return;
|
||||||
if (!core.hasTickScheduled()) {
|
if (queue.isEmpty() || !core.hasTickScheduled()) {
|
||||||
core.runMicrotasks();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
159
ext/node/polyfills/internal_binding/http_parser.ts
Normal file
159
ext/node/polyfills/internal_binding/http_parser.ts
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
// Copyright Joyent, Inc. and other Node contributors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the
|
||||||
|
// "Software"), to deal in the Software without restriction, including
|
||||||
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||||
|
// persons to whom the Software is furnished to do so, subject to the
|
||||||
|
// following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included
|
||||||
|
// in all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||||
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||||
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||||
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
import { primordials } from "ext:core/mod.js";
|
||||||
|
import { AsyncWrap } from "ext:deno_node/internal_binding/async_wrap.ts";
|
||||||
|
|
||||||
|
const {
|
||||||
|
ObjectDefineProperty,
|
||||||
|
ObjectEntries,
|
||||||
|
ObjectSetPrototypeOf,
|
||||||
|
SafeArrayIterator,
|
||||||
|
} = primordials;
|
||||||
|
|
||||||
|
export const methods = [
|
||||||
|
"DELETE",
|
||||||
|
"GET",
|
||||||
|
"HEAD",
|
||||||
|
"POST",
|
||||||
|
"PUT",
|
||||||
|
"CONNECT",
|
||||||
|
"OPTIONS",
|
||||||
|
"TRACE",
|
||||||
|
"COPY",
|
||||||
|
"LOCK",
|
||||||
|
"MKCOL",
|
||||||
|
"MOVE",
|
||||||
|
"PROPFIND",
|
||||||
|
"PROPPATCH",
|
||||||
|
"SEARCH",
|
||||||
|
"UNLOCK",
|
||||||
|
"BIND",
|
||||||
|
"REBIND",
|
||||||
|
"UNBIND",
|
||||||
|
"ACL",
|
||||||
|
"REPORT",
|
||||||
|
"MKACTIVITY",
|
||||||
|
"CHECKOUT",
|
||||||
|
"MERGE",
|
||||||
|
"M-SEARCH",
|
||||||
|
"NOTIFY",
|
||||||
|
"SUBSCRIBE",
|
||||||
|
"UNSUBSCRIBE",
|
||||||
|
"PATCH",
|
||||||
|
"PURGE",
|
||||||
|
"MKCALENDAR",
|
||||||
|
"LINK",
|
||||||
|
"UNLINK",
|
||||||
|
"SOURCE",
|
||||||
|
"QUERY",
|
||||||
|
];
|
||||||
|
|
||||||
|
export const allMethods = [
|
||||||
|
"DELETE",
|
||||||
|
"GET",
|
||||||
|
"HEAD",
|
||||||
|
"POST",
|
||||||
|
"PUT",
|
||||||
|
"CONNECT",
|
||||||
|
"OPTIONS",
|
||||||
|
"TRACE",
|
||||||
|
"COPY",
|
||||||
|
"LOCK",
|
||||||
|
"MKCOL",
|
||||||
|
"MOVE",
|
||||||
|
"PROPFIND",
|
||||||
|
"PROPPATCH",
|
||||||
|
"SEARCH",
|
||||||
|
"UNLOCK",
|
||||||
|
"BIND",
|
||||||
|
"REBIND",
|
||||||
|
"UNBIND",
|
||||||
|
"ACL",
|
||||||
|
"REPORT",
|
||||||
|
"MKACTIVITY",
|
||||||
|
"CHECKOUT",
|
||||||
|
"MERGE",
|
||||||
|
"M-SEARCH",
|
||||||
|
"NOTIFY",
|
||||||
|
"SUBSCRIBE",
|
||||||
|
"UNSUBSCRIBE",
|
||||||
|
"PATCH",
|
||||||
|
"PURGE",
|
||||||
|
"MKCALENDAR",
|
||||||
|
"LINK",
|
||||||
|
"UNLINK",
|
||||||
|
"SOURCE",
|
||||||
|
"PRI",
|
||||||
|
"DESCRIBE",
|
||||||
|
"ANNOUNCE",
|
||||||
|
"SETUP",
|
||||||
|
"PLAY",
|
||||||
|
"PAUSE",
|
||||||
|
"TEARDOWN",
|
||||||
|
"GET_PARAMETER",
|
||||||
|
"SET_PARAMETER",
|
||||||
|
"REDIRECT",
|
||||||
|
"RECORD",
|
||||||
|
"FLUSH",
|
||||||
|
"QUERY",
|
||||||
|
];
|
||||||
|
|
||||||
|
export function HTTPParser() {
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectSetPrototypeOf(HTTPParser.prototype, AsyncWrap.prototype);
|
||||||
|
|
||||||
|
function defineProps(obj: object, props: Record<string, unknown>) {
|
||||||
|
for (const entry of new SafeArrayIterator(ObjectEntries(props))) {
|
||||||
|
ObjectDefineProperty(obj, entry[0], {
|
||||||
|
value: entry[1],
|
||||||
|
enumerable: true,
|
||||||
|
writable: true,
|
||||||
|
configurable: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defineProps(HTTPParser, {
|
||||||
|
REQUEST: 1,
|
||||||
|
RESPONSE: 2,
|
||||||
|
kOnMessageBegin: 0,
|
||||||
|
kOnHeaders: 1,
|
||||||
|
kOnHeadersComplete: 2,
|
||||||
|
kOnBody: 3,
|
||||||
|
kOnMessageComplete: 4,
|
||||||
|
kOnExecute: 5,
|
||||||
|
kOnTimeout: 6,
|
||||||
|
kLenientNone: 0,
|
||||||
|
kLenientHeaders: 1,
|
||||||
|
kLenientChunkedLength: 2,
|
||||||
|
kLenientKeepAlive: 4,
|
||||||
|
kLenientTransferEncoding: 8,
|
||||||
|
kLenientVersion: 16,
|
||||||
|
kLenientDataAfterClose: 32,
|
||||||
|
kLenientOptionalLFAfterCR: 64,
|
||||||
|
kLenientOptionalCRLFAfterChunk: 128,
|
||||||
|
kLenientOptionalCRBeforeLF: 256,
|
||||||
|
kLenientSpacesAfterChunkSize: 512,
|
||||||
|
kLenientAll: 1023,
|
||||||
|
});
|
|
@ -17,6 +17,7 @@ import * as types from "ext:deno_node/internal_binding/types.ts";
|
||||||
import * as udpWrap from "ext:deno_node/internal_binding/udp_wrap.ts";
|
import * as udpWrap from "ext:deno_node/internal_binding/udp_wrap.ts";
|
||||||
import * as util from "ext:deno_node/internal_binding/util.ts";
|
import * as util from "ext:deno_node/internal_binding/util.ts";
|
||||||
import * as uv from "ext:deno_node/internal_binding/uv.ts";
|
import * as uv from "ext:deno_node/internal_binding/uv.ts";
|
||||||
|
import * as httpParser from "ext:deno_node/internal_binding/http_parser.ts";
|
||||||
|
|
||||||
const modules = {
|
const modules = {
|
||||||
"async_wrap": asyncWrap,
|
"async_wrap": asyncWrap,
|
||||||
|
@ -32,7 +33,7 @@ const modules = {
|
||||||
"fs_dir": {},
|
"fs_dir": {},
|
||||||
"fs_event_wrap": {},
|
"fs_event_wrap": {},
|
||||||
"heap_utils": {},
|
"heap_utils": {},
|
||||||
"http_parser": {},
|
"http_parser": httpParser,
|
||||||
icu: {},
|
icu: {},
|
||||||
inspector: {},
|
inspector: {},
|
||||||
"js_stream": {},
|
"js_stream": {},
|
||||||
|
|
|
@ -25,6 +25,7 @@ serde = { workspace = true, features = ["derive"] }
|
||||||
tokio = { workspace = true, features = ["full"] }
|
tokio = { workspace = true, features = ["full"] }
|
||||||
wgpu-types = { workspace = true, features = ["serde"] }
|
wgpu-types = { workspace = true, features = ["serde"] }
|
||||||
raw-window-handle = { workspace = true }
|
raw-window-handle = { workspace = true }
|
||||||
|
thiserror.workspace = true
|
||||||
|
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies.wgpu-core]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies.wgpu-core]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use deno_core::error::type_error;
|
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::op2;
|
use deno_core::op2;
|
||||||
use deno_core::OpState;
|
use deno_core::OpState;
|
||||||
use deno_core::Resource;
|
use deno_core::Resource;
|
||||||
|
@ -13,9 +11,18 @@ use std::sync::Arc;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use super::error::DomExceptionOperationError;
|
|
||||||
use super::error::WebGpuResult;
|
use super::error::WebGpuResult;
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum BufferError {
|
||||||
|
#[error(transparent)]
|
||||||
|
Resource(deno_core::error::AnyError),
|
||||||
|
#[error("usage is not valid")]
|
||||||
|
InvalidUsage,
|
||||||
|
#[error(transparent)]
|
||||||
|
Access(wgpu_core::resource::BufferAccessError),
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) struct WebGpuBuffer(
|
pub(crate) struct WebGpuBuffer(
|
||||||
pub(crate) super::Instance,
|
pub(crate) super::Instance,
|
||||||
pub(crate) wgpu_core::id::BufferId,
|
pub(crate) wgpu_core::id::BufferId,
|
||||||
|
@ -46,18 +53,19 @@ pub fn op_webgpu_create_buffer(
|
||||||
#[number] size: u64,
|
#[number] size: u64,
|
||||||
usage: u32,
|
usage: u32,
|
||||||
mapped_at_creation: bool,
|
mapped_at_creation: bool,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, BufferError> {
|
||||||
let instance = state.borrow::<super::Instance>();
|
let instance = state.borrow::<super::Instance>();
|
||||||
let device_resource = state
|
let device_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<super::WebGpuDevice>(device_rid)?;
|
.get::<super::WebGpuDevice>(device_rid)
|
||||||
|
.map_err(BufferError::Resource)?;
|
||||||
let device = device_resource.1;
|
let device = device_resource.1;
|
||||||
|
|
||||||
let descriptor = wgpu_core::resource::BufferDescriptor {
|
let descriptor = wgpu_core::resource::BufferDescriptor {
|
||||||
label: Some(label),
|
label: Some(label),
|
||||||
size,
|
size,
|
||||||
usage: wgpu_types::BufferUsages::from_bits(usage)
|
usage: wgpu_types::BufferUsages::from_bits(usage)
|
||||||
.ok_or_else(|| type_error("usage is not valid"))?,
|
.ok_or(BufferError::InvalidUsage)?,
|
||||||
mapped_at_creation,
|
mapped_at_creation,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -77,18 +85,21 @@ pub async fn op_webgpu_buffer_get_map_async(
|
||||||
mode: u32,
|
mode: u32,
|
||||||
#[number] offset: u64,
|
#[number] offset: u64,
|
||||||
#[number] size: u64,
|
#[number] size: u64,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, BufferError> {
|
||||||
let device;
|
let device;
|
||||||
let done = Arc::new(Mutex::new(None));
|
let done = Arc::new(Mutex::new(None));
|
||||||
{
|
{
|
||||||
let state_ = state.borrow();
|
let state_ = state.borrow();
|
||||||
let instance = state_.borrow::<super::Instance>();
|
let instance = state_.borrow::<super::Instance>();
|
||||||
let buffer_resource =
|
let buffer_resource = state_
|
||||||
state_.resource_table.get::<WebGpuBuffer>(buffer_rid)?;
|
.resource_table
|
||||||
|
.get::<WebGpuBuffer>(buffer_rid)
|
||||||
|
.map_err(BufferError::Resource)?;
|
||||||
let buffer = buffer_resource.1;
|
let buffer = buffer_resource.1;
|
||||||
let device_resource = state_
|
let device_resource = state_
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<super::WebGpuDevice>(device_rid)?;
|
.get::<super::WebGpuDevice>(device_rid)
|
||||||
|
.map_err(BufferError::Resource)?;
|
||||||
device = device_resource.1;
|
device = device_resource.1;
|
||||||
|
|
||||||
let done_ = done.clone();
|
let done_ = done.clone();
|
||||||
|
@ -120,9 +131,7 @@ pub async fn op_webgpu_buffer_get_map_async(
|
||||||
let result = done.lock().unwrap().take();
|
let result = done.lock().unwrap().take();
|
||||||
match result {
|
match result {
|
||||||
Some(Ok(())) => return Ok(WebGpuResult::empty()),
|
Some(Ok(())) => return Ok(WebGpuResult::empty()),
|
||||||
Some(Err(e)) => {
|
Some(Err(e)) => return Err(BufferError::Access(e)),
|
||||||
return Err(DomExceptionOperationError::new(&e.to_string()).into())
|
|
||||||
}
|
|
||||||
None => {
|
None => {
|
||||||
{
|
{
|
||||||
let state = state.borrow();
|
let state = state.borrow();
|
||||||
|
@ -143,9 +152,12 @@ pub fn op_webgpu_buffer_get_mapped_range(
|
||||||
#[number] offset: u64,
|
#[number] offset: u64,
|
||||||
#[number] size: Option<u64>,
|
#[number] size: Option<u64>,
|
||||||
#[buffer] buf: &mut [u8],
|
#[buffer] buf: &mut [u8],
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, BufferError> {
|
||||||
let instance = state.borrow::<super::Instance>();
|
let instance = state.borrow::<super::Instance>();
|
||||||
let buffer_resource = state.resource_table.get::<WebGpuBuffer>(buffer_rid)?;
|
let buffer_resource = state
|
||||||
|
.resource_table
|
||||||
|
.get::<WebGpuBuffer>(buffer_rid)
|
||||||
|
.map_err(BufferError::Resource)?;
|
||||||
let buffer = buffer_resource.1;
|
let buffer = buffer_resource.1;
|
||||||
|
|
||||||
let (slice_pointer, range_size) =
|
let (slice_pointer, range_size) =
|
||||||
|
@ -154,7 +166,7 @@ pub fn op_webgpu_buffer_get_mapped_range(
|
||||||
offset,
|
offset,
|
||||||
size
|
size
|
||||||
))
|
))
|
||||||
.map_err(|e| DomExceptionOperationError::new(&e.to_string()))?;
|
.map_err(BufferError::Access)?;
|
||||||
|
|
||||||
// SAFETY: guarantee to be safe from wgpu
|
// SAFETY: guarantee to be safe from wgpu
|
||||||
let slice = unsafe {
|
let slice = unsafe {
|
||||||
|
@ -176,12 +188,16 @@ pub fn op_webgpu_buffer_unmap(
|
||||||
#[smi] buffer_rid: ResourceId,
|
#[smi] buffer_rid: ResourceId,
|
||||||
#[smi] mapped_rid: ResourceId,
|
#[smi] mapped_rid: ResourceId,
|
||||||
#[buffer] buf: Option<&[u8]>,
|
#[buffer] buf: Option<&[u8]>,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, BufferError> {
|
||||||
let mapped_resource = state
|
let mapped_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
.take::<WebGpuBufferMapped>(mapped_rid)?;
|
.take::<WebGpuBufferMapped>(mapped_rid)
|
||||||
|
.map_err(BufferError::Resource)?;
|
||||||
let instance = state.borrow::<super::Instance>();
|
let instance = state.borrow::<super::Instance>();
|
||||||
let buffer_resource = state.resource_table.get::<WebGpuBuffer>(buffer_rid)?;
|
let buffer_resource = state
|
||||||
|
.resource_table
|
||||||
|
.get::<WebGpuBuffer>(buffer_rid)
|
||||||
|
.map_err(BufferError::Resource)?;
|
||||||
let buffer = buffer_resource.1;
|
let buffer = buffer_resource.1;
|
||||||
|
|
||||||
if let Some(buf) = buf {
|
if let Some(buf) = buf {
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use deno_core::error::type_error;
|
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::op2;
|
use deno_core::op2;
|
||||||
use deno_core::OpState;
|
use deno_core::OpState;
|
||||||
use deno_core::Resource;
|
use deno_core::Resource;
|
||||||
|
@ -13,6 +11,14 @@ use std::rc::Rc;
|
||||||
|
|
||||||
use super::error::WebGpuResult;
|
use super::error::WebGpuResult;
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum BundleError {
|
||||||
|
#[error(transparent)]
|
||||||
|
Resource(deno_core::error::AnyError),
|
||||||
|
#[error("size must be larger than 0")]
|
||||||
|
InvalidSize,
|
||||||
|
}
|
||||||
|
|
||||||
struct WebGpuRenderBundleEncoder(
|
struct WebGpuRenderBundleEncoder(
|
||||||
RefCell<wgpu_core::command::RenderBundleEncoder>,
|
RefCell<wgpu_core::command::RenderBundleEncoder>,
|
||||||
);
|
);
|
||||||
|
@ -53,7 +59,7 @@ pub struct CreateRenderBundleEncoderArgs {
|
||||||
pub fn op_webgpu_create_render_bundle_encoder(
|
pub fn op_webgpu_create_render_bundle_encoder(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[serde] args: CreateRenderBundleEncoderArgs,
|
#[serde] args: CreateRenderBundleEncoderArgs,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let device_resource = state
|
let device_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<super::WebGpuDevice>(args.device_rid)?;
|
.get::<super::WebGpuDevice>(args.device_rid)?;
|
||||||
|
@ -100,7 +106,7 @@ pub fn op_webgpu_render_bundle_encoder_finish(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[smi] render_bundle_encoder_rid: ResourceId,
|
#[smi] render_bundle_encoder_rid: ResourceId,
|
||||||
#[string] label: Cow<str>,
|
#[string] label: Cow<str>,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let render_bundle_encoder_resource =
|
let render_bundle_encoder_resource =
|
||||||
state
|
state
|
||||||
.resource_table
|
.resource_table
|
||||||
|
@ -131,7 +137,7 @@ pub fn op_webgpu_render_bundle_encoder_set_bind_group(
|
||||||
#[buffer] dynamic_offsets_data: &[u32],
|
#[buffer] dynamic_offsets_data: &[u32],
|
||||||
#[number] dynamic_offsets_data_start: usize,
|
#[number] dynamic_offsets_data_start: usize,
|
||||||
#[number] dynamic_offsets_data_length: usize,
|
#[number] dynamic_offsets_data_length: usize,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let bind_group_resource =
|
let bind_group_resource =
|
||||||
state
|
state
|
||||||
.resource_table
|
.resource_table
|
||||||
|
@ -171,7 +177,7 @@ pub fn op_webgpu_render_bundle_encoder_push_debug_group(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[smi] render_bundle_encoder_rid: ResourceId,
|
#[smi] render_bundle_encoder_rid: ResourceId,
|
||||||
#[string] group_label: &str,
|
#[string] group_label: &str,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let render_bundle_encoder_resource =
|
let render_bundle_encoder_resource =
|
||||||
state
|
state
|
||||||
.resource_table
|
.resource_table
|
||||||
|
@ -195,7 +201,7 @@ pub fn op_webgpu_render_bundle_encoder_push_debug_group(
|
||||||
pub fn op_webgpu_render_bundle_encoder_pop_debug_group(
|
pub fn op_webgpu_render_bundle_encoder_pop_debug_group(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[smi] render_bundle_encoder_rid: ResourceId,
|
#[smi] render_bundle_encoder_rid: ResourceId,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let render_bundle_encoder_resource =
|
let render_bundle_encoder_resource =
|
||||||
state
|
state
|
||||||
.resource_table
|
.resource_table
|
||||||
|
@ -214,7 +220,7 @@ pub fn op_webgpu_render_bundle_encoder_insert_debug_marker(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[smi] render_bundle_encoder_rid: ResourceId,
|
#[smi] render_bundle_encoder_rid: ResourceId,
|
||||||
#[string] marker_label: &str,
|
#[string] marker_label: &str,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let render_bundle_encoder_resource =
|
let render_bundle_encoder_resource =
|
||||||
state
|
state
|
||||||
.resource_table
|
.resource_table
|
||||||
|
@ -239,7 +245,7 @@ pub fn op_webgpu_render_bundle_encoder_set_pipeline(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[smi] render_bundle_encoder_rid: ResourceId,
|
#[smi] render_bundle_encoder_rid: ResourceId,
|
||||||
#[smi] pipeline: ResourceId,
|
#[smi] pipeline: ResourceId,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let render_pipeline_resource =
|
let render_pipeline_resource =
|
||||||
state
|
state
|
||||||
.resource_table
|
.resource_table
|
||||||
|
@ -266,18 +272,17 @@ pub fn op_webgpu_render_bundle_encoder_set_index_buffer(
|
||||||
#[serde] index_format: wgpu_types::IndexFormat,
|
#[serde] index_format: wgpu_types::IndexFormat,
|
||||||
#[number] offset: u64,
|
#[number] offset: u64,
|
||||||
#[number] size: u64,
|
#[number] size: u64,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, BundleError> {
|
||||||
let buffer_resource = state
|
let buffer_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<super::buffer::WebGpuBuffer>(buffer)?;
|
.get::<super::buffer::WebGpuBuffer>(buffer)
|
||||||
let render_bundle_encoder_resource =
|
.map_err(BundleError::Resource)?;
|
||||||
state
|
let render_bundle_encoder_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<WebGpuRenderBundleEncoder>(render_bundle_encoder_rid)?;
|
.get::<WebGpuRenderBundleEncoder>(render_bundle_encoder_rid)
|
||||||
let size = Some(
|
.map_err(BundleError::Resource)?;
|
||||||
std::num::NonZeroU64::new(size)
|
let size =
|
||||||
.ok_or_else(|| type_error("size must be larger than 0"))?,
|
Some(std::num::NonZeroU64::new(size).ok_or(BundleError::InvalidSize)?);
|
||||||
);
|
|
||||||
|
|
||||||
render_bundle_encoder_resource
|
render_bundle_encoder_resource
|
||||||
.0
|
.0
|
||||||
|
@ -296,19 +301,17 @@ pub fn op_webgpu_render_bundle_encoder_set_vertex_buffer(
|
||||||
#[smi] buffer: ResourceId,
|
#[smi] buffer: ResourceId,
|
||||||
#[number] offset: u64,
|
#[number] offset: u64,
|
||||||
#[number] size: Option<u64>,
|
#[number] size: Option<u64>,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, BundleError> {
|
||||||
let buffer_resource = state
|
let buffer_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<super::buffer::WebGpuBuffer>(buffer)?;
|
.get::<super::buffer::WebGpuBuffer>(buffer)
|
||||||
let render_bundle_encoder_resource =
|
.map_err(BundleError::Resource)?;
|
||||||
state
|
let render_bundle_encoder_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<WebGpuRenderBundleEncoder>(render_bundle_encoder_rid)?;
|
.get::<WebGpuRenderBundleEncoder>(render_bundle_encoder_rid)
|
||||||
|
.map_err(BundleError::Resource)?;
|
||||||
let size = if let Some(size) = size {
|
let size = if let Some(size) = size {
|
||||||
Some(
|
Some(std::num::NonZeroU64::new(size).ok_or(BundleError::InvalidSize)?)
|
||||||
std::num::NonZeroU64::new(size)
|
|
||||||
.ok_or_else(|| type_error("size must be larger than 0"))?,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -333,7 +336,7 @@ pub fn op_webgpu_render_bundle_encoder_draw(
|
||||||
instance_count: u32,
|
instance_count: u32,
|
||||||
first_vertex: u32,
|
first_vertex: u32,
|
||||||
first_instance: u32,
|
first_instance: u32,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let render_bundle_encoder_resource =
|
let render_bundle_encoder_resource =
|
||||||
state
|
state
|
||||||
.resource_table
|
.resource_table
|
||||||
|
@ -360,7 +363,7 @@ pub fn op_webgpu_render_bundle_encoder_draw_indexed(
|
||||||
first_index: u32,
|
first_index: u32,
|
||||||
base_vertex: i32,
|
base_vertex: i32,
|
||||||
first_instance: u32,
|
first_instance: u32,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let render_bundle_encoder_resource =
|
let render_bundle_encoder_resource =
|
||||||
state
|
state
|
||||||
.resource_table
|
.resource_table
|
||||||
|
@ -385,7 +388,7 @@ pub fn op_webgpu_render_bundle_encoder_draw_indirect(
|
||||||
#[smi] render_bundle_encoder_rid: ResourceId,
|
#[smi] render_bundle_encoder_rid: ResourceId,
|
||||||
#[smi] indirect_buffer: ResourceId,
|
#[smi] indirect_buffer: ResourceId,
|
||||||
#[number] indirect_offset: u64,
|
#[number] indirect_offset: u64,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let buffer_resource = state
|
let buffer_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<super::buffer::WebGpuBuffer>(indirect_buffer)?;
|
.get::<super::buffer::WebGpuBuffer>(indirect_buffer)?;
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use deno_core::error::type_error;
|
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::op2;
|
use deno_core::op2;
|
||||||
use deno_core::OpState;
|
use deno_core::OpState;
|
||||||
use deno_core::ResourceId;
|
use deno_core::ResourceId;
|
||||||
|
@ -16,6 +14,47 @@ use std::ptr::NonNull;
|
||||||
|
|
||||||
use crate::surface::WebGpuSurface;
|
use crate::surface::WebGpuSurface;
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum ByowError {
|
||||||
|
#[error("Cannot create surface outside of WebGPU context. Did you forget to call `navigator.gpu.requestAdapter()`?")]
|
||||||
|
WebGPUNotInitiated,
|
||||||
|
#[error("Invalid parameters")]
|
||||||
|
InvalidParameters,
|
||||||
|
#[error(transparent)]
|
||||||
|
CreateSurface(wgpu_core::instance::CreateSurfaceError),
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
#[error("Invalid system on Windows")]
|
||||||
|
InvalidSystem,
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
#[error("Invalid system on macOS")]
|
||||||
|
InvalidSystem,
|
||||||
|
#[cfg(any(
|
||||||
|
target_os = "linux",
|
||||||
|
target_os = "freebsd",
|
||||||
|
target_os = "openbsd"
|
||||||
|
))]
|
||||||
|
#[error("Invalid system on Linux/BSD")]
|
||||||
|
InvalidSystem,
|
||||||
|
#[cfg(any(
|
||||||
|
target_os = "windows",
|
||||||
|
target_os = "linux",
|
||||||
|
target_os = "freebsd",
|
||||||
|
target_os = "openbsd"
|
||||||
|
))]
|
||||||
|
#[error("window is null")]
|
||||||
|
NullWindow,
|
||||||
|
#[cfg(any(
|
||||||
|
target_os = "linux",
|
||||||
|
target_os = "freebsd",
|
||||||
|
target_os = "openbsd"
|
||||||
|
))]
|
||||||
|
#[error("display is null")]
|
||||||
|
NullDisplay,
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
#[error("ns_view is null")]
|
||||||
|
NSViewDisplay,
|
||||||
|
}
|
||||||
|
|
||||||
#[op2(fast)]
|
#[op2(fast)]
|
||||||
#[smi]
|
#[smi]
|
||||||
pub fn op_webgpu_surface_create(
|
pub fn op_webgpu_surface_create(
|
||||||
|
@ -23,10 +62,10 @@ pub fn op_webgpu_surface_create(
|
||||||
#[string] system: &str,
|
#[string] system: &str,
|
||||||
p1: *const c_void,
|
p1: *const c_void,
|
||||||
p2: *const c_void,
|
p2: *const c_void,
|
||||||
) -> Result<ResourceId, AnyError> {
|
) -> Result<ResourceId, ByowError> {
|
||||||
let instance = state.try_borrow::<super::Instance>().ok_or_else(|| {
|
let instance = state
|
||||||
type_error("Cannot create surface outside of WebGPU context. Did you forget to call `navigator.gpu.requestAdapter()`?")
|
.try_borrow::<super::Instance>()
|
||||||
})?;
|
.ok_or(ByowError::WebGPUNotInitiated)?;
|
||||||
// Security note:
|
// Security note:
|
||||||
//
|
//
|
||||||
// The `p1` and `p2` parameters are pointers to platform-specific window
|
// The `p1` and `p2` parameters are pointers to platform-specific window
|
||||||
|
@ -41,13 +80,15 @@ pub fn op_webgpu_surface_create(
|
||||||
//
|
//
|
||||||
// - Only FFI can export v8::External to user code.
|
// - Only FFI can export v8::External to user code.
|
||||||
if p1.is_null() {
|
if p1.is_null() {
|
||||||
return Err(type_error("Invalid parameters"));
|
return Err(ByowError::InvalidParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (win_handle, display_handle) = raw_window(system, p1, p2)?;
|
let (win_handle, display_handle) = raw_window(system, p1, p2)?;
|
||||||
// SAFETY: see above comment
|
// SAFETY: see above comment
|
||||||
let surface = unsafe {
|
let surface = unsafe {
|
||||||
instance.instance_create_surface(display_handle, win_handle, None)?
|
instance
|
||||||
|
.instance_create_surface(display_handle, win_handle, None)
|
||||||
|
.map_err(ByowError::CreateSurface)?
|
||||||
};
|
};
|
||||||
|
|
||||||
let rid = state
|
let rid = state
|
||||||
|
@ -66,15 +107,14 @@ fn raw_window(
|
||||||
system: &str,
|
system: &str,
|
||||||
_ns_window: *const c_void,
|
_ns_window: *const c_void,
|
||||||
ns_view: *const c_void,
|
ns_view: *const c_void,
|
||||||
) -> Result<RawHandles, AnyError> {
|
) -> Result<RawHandles, ByowError> {
|
||||||
if system != "cocoa" {
|
if system != "cocoa" {
|
||||||
return Err(type_error("Invalid system on macOS"));
|
return Err(ByowError::InvalidSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
let win_handle = raw_window_handle::RawWindowHandle::AppKit(
|
let win_handle = raw_window_handle::RawWindowHandle::AppKit(
|
||||||
raw_window_handle::AppKitWindowHandle::new(
|
raw_window_handle::AppKitWindowHandle::new(
|
||||||
NonNull::new(ns_view as *mut c_void)
|
NonNull::new(ns_view as *mut c_void).ok_or(ByowError::NSViewDisplay)?,
|
||||||
.ok_or(type_error("ns_view is null"))?,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -89,16 +129,16 @@ fn raw_window(
|
||||||
system: &str,
|
system: &str,
|
||||||
window: *const c_void,
|
window: *const c_void,
|
||||||
hinstance: *const c_void,
|
hinstance: *const c_void,
|
||||||
) -> Result<RawHandles, AnyError> {
|
) -> Result<RawHandles, ByowError> {
|
||||||
use raw_window_handle::WindowsDisplayHandle;
|
use raw_window_handle::WindowsDisplayHandle;
|
||||||
if system != "win32" {
|
if system != "win32" {
|
||||||
return Err(type_error("Invalid system on Windows"));
|
return Err(ByowError::InvalidSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
let win_handle = {
|
let win_handle = {
|
||||||
let mut handle = raw_window_handle::Win32WindowHandle::new(
|
let mut handle = raw_window_handle::Win32WindowHandle::new(
|
||||||
std::num::NonZeroIsize::new(window as isize)
|
std::num::NonZeroIsize::new(window as isize)
|
||||||
.ok_or(type_error("window is null"))?,
|
.ok_or(ByowError::NullWindow)?,
|
||||||
);
|
);
|
||||||
handle.hinstance = std::num::NonZeroIsize::new(hinstance as isize);
|
handle.hinstance = std::num::NonZeroIsize::new(hinstance as isize);
|
||||||
|
|
||||||
|
@ -115,7 +155,7 @@ fn raw_window(
|
||||||
system: &str,
|
system: &str,
|
||||||
window: *const c_void,
|
window: *const c_void,
|
||||||
display: *const c_void,
|
display: *const c_void,
|
||||||
) -> Result<RawHandles, AnyError> {
|
) -> Result<RawHandles, ByowError> {
|
||||||
let (win_handle, display_handle);
|
let (win_handle, display_handle);
|
||||||
if system == "x11" {
|
if system == "x11" {
|
||||||
win_handle = raw_window_handle::RawWindowHandle::Xlib(
|
win_handle = raw_window_handle::RawWindowHandle::Xlib(
|
||||||
|
@ -131,19 +171,17 @@ fn raw_window(
|
||||||
} else if system == "wayland" {
|
} else if system == "wayland" {
|
||||||
win_handle = raw_window_handle::RawWindowHandle::Wayland(
|
win_handle = raw_window_handle::RawWindowHandle::Wayland(
|
||||||
raw_window_handle::WaylandWindowHandle::new(
|
raw_window_handle::WaylandWindowHandle::new(
|
||||||
NonNull::new(window as *mut c_void)
|
NonNull::new(window as *mut c_void).ok_or(ByowError::NullWindow)?,
|
||||||
.ok_or(type_error("window is null"))?,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
display_handle = raw_window_handle::RawDisplayHandle::Wayland(
|
display_handle = raw_window_handle::RawDisplayHandle::Wayland(
|
||||||
raw_window_handle::WaylandDisplayHandle::new(
|
raw_window_handle::WaylandDisplayHandle::new(
|
||||||
NonNull::new(display as *mut c_void)
|
NonNull::new(display as *mut c_void).ok_or(ByowError::NullDisplay)?,
|
||||||
.ok_or(type_error("display is null"))?,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return Err(type_error("Invalid system on Linux/BSD"));
|
return Err(ByowError::InvalidSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((win_handle, display_handle))
|
Ok((win_handle, display_handle))
|
||||||
|
@ -160,6 +198,6 @@ fn raw_window(
|
||||||
_system: &str,
|
_system: &str,
|
||||||
_window: *const c_void,
|
_window: *const c_void,
|
||||||
_display: *const c_void,
|
_display: *const c_void,
|
||||||
) -> Result<RawHandles, AnyError> {
|
) -> Result<RawHandles, deno_core::error::AnyError> {
|
||||||
Err(type_error("Unsupported platform"))
|
Err(deno_core::error::type_error("Unsupported platform"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::ResourceId;
|
use deno_core::ResourceId;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::convert::From;
|
use std::convert::From;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt;
|
|
||||||
use wgpu_core::binding_model::CreateBindGroupError;
|
use wgpu_core::binding_model::CreateBindGroupError;
|
||||||
use wgpu_core::binding_model::CreateBindGroupLayoutError;
|
use wgpu_core::binding_model::CreateBindGroupLayoutError;
|
||||||
use wgpu_core::binding_model::CreatePipelineLayoutError;
|
use wgpu_core::binding_model::CreatePipelineLayoutError;
|
||||||
|
@ -286,29 +284,3 @@ impl From<ConfigureSurfaceError> for WebGpuError {
|
||||||
WebGpuError::Validation(fmt_err(&err))
|
WebGpuError::Validation(fmt_err(&err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct DomExceptionOperationError {
|
|
||||||
pub msg: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DomExceptionOperationError {
|
|
||||||
pub fn new(msg: &str) -> Self {
|
|
||||||
DomExceptionOperationError {
|
|
||||||
msg: msg.to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for DomExceptionOperationError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
f.pad(&self.msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::error::Error for DomExceptionOperationError {}
|
|
||||||
|
|
||||||
pub fn get_error_class_name(e: &AnyError) -> Option<&'static str> {
|
|
||||||
e.downcast_ref::<DomExceptionOperationError>()
|
|
||||||
.map(|_| "DOMExceptionOperationError")
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
#![cfg(not(target_arch = "wasm32"))]
|
#![cfg(not(target_arch = "wasm32"))]
|
||||||
#![warn(unsafe_op_in_unsafe_fn)]
|
#![warn(unsafe_op_in_unsafe_fn)]
|
||||||
|
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::op2;
|
use deno_core::op2;
|
||||||
use deno_core::OpState;
|
use deno_core::OpState;
|
||||||
use deno_core::Resource;
|
use deno_core::Resource;
|
||||||
|
@ -16,7 +15,6 @@ use std::rc::Rc;
|
||||||
pub use wgpu_core;
|
pub use wgpu_core;
|
||||||
pub use wgpu_types;
|
pub use wgpu_types;
|
||||||
|
|
||||||
use error::DomExceptionOperationError;
|
|
||||||
use error::WebGpuResult;
|
use error::WebGpuResult;
|
||||||
|
|
||||||
pub const UNSTABLE_FEATURE_NAME: &str = "webgpu";
|
pub const UNSTABLE_FEATURE_NAME: &str = "webgpu";
|
||||||
|
@ -85,6 +83,18 @@ pub mod shader;
|
||||||
pub mod surface;
|
pub mod surface;
|
||||||
pub mod texture;
|
pub mod texture;
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum InitError {
|
||||||
|
#[error(transparent)]
|
||||||
|
Resource(deno_core::error::AnyError),
|
||||||
|
#[error(transparent)]
|
||||||
|
InvalidAdapter(wgpu_core::instance::InvalidAdapter),
|
||||||
|
#[error(transparent)]
|
||||||
|
RequestDevice(wgpu_core::instance::RequestDeviceError),
|
||||||
|
#[error(transparent)]
|
||||||
|
InvalidDevice(wgpu_core::device::InvalidDevice),
|
||||||
|
}
|
||||||
|
|
||||||
pub type Instance = std::sync::Arc<wgpu_core::global::Global>;
|
pub type Instance = std::sync::Arc<wgpu_core::global::Global>;
|
||||||
|
|
||||||
struct WebGpuAdapter(Instance, wgpu_core::id::AdapterId);
|
struct WebGpuAdapter(Instance, wgpu_core::id::AdapterId);
|
||||||
|
@ -400,7 +410,7 @@ pub fn op_webgpu_request_adapter(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
#[serde] power_preference: Option<wgpu_types::PowerPreference>,
|
#[serde] power_preference: Option<wgpu_types::PowerPreference>,
|
||||||
force_fallback_adapter: bool,
|
force_fallback_adapter: bool,
|
||||||
) -> Result<GpuAdapterResOrErr, AnyError> {
|
) -> Result<GpuAdapterResOrErr, InitError> {
|
||||||
let mut state = state.borrow_mut();
|
let mut state = state.borrow_mut();
|
||||||
|
|
||||||
let backends = std::env::var("DENO_WEBGPU_BACKEND").map_or_else(
|
let backends = std::env::var("DENO_WEBGPU_BACKEND").map_or_else(
|
||||||
|
@ -441,10 +451,11 @@ pub fn op_webgpu_request_adapter(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let adapter_features =
|
let adapter_features =
|
||||||
gfx_select!(adapter => instance.adapter_features(adapter))?;
|
gfx_select!(adapter => instance.adapter_features(adapter))
|
||||||
|
.map_err(InitError::InvalidAdapter)?;
|
||||||
let features = deserialize_features(&adapter_features);
|
let features = deserialize_features(&adapter_features);
|
||||||
let adapter_limits =
|
let adapter_limits = gfx_select!(adapter => instance.adapter_limits(adapter))
|
||||||
gfx_select!(adapter => instance.adapter_limits(adapter))?;
|
.map_err(InitError::InvalidAdapter)?;
|
||||||
|
|
||||||
let instance = instance.clone();
|
let instance = instance.clone();
|
||||||
|
|
||||||
|
@ -663,10 +674,12 @@ pub fn op_webgpu_request_device(
|
||||||
#[string] label: String,
|
#[string] label: String,
|
||||||
#[serde] required_features: GpuRequiredFeatures,
|
#[serde] required_features: GpuRequiredFeatures,
|
||||||
#[serde] required_limits: Option<wgpu_types::Limits>,
|
#[serde] required_limits: Option<wgpu_types::Limits>,
|
||||||
) -> Result<GpuDeviceRes, AnyError> {
|
) -> Result<GpuDeviceRes, InitError> {
|
||||||
let mut state = state.borrow_mut();
|
let mut state = state.borrow_mut();
|
||||||
let adapter_resource =
|
let adapter_resource = state
|
||||||
state.resource_table.take::<WebGpuAdapter>(adapter_rid)?;
|
.resource_table
|
||||||
|
.take::<WebGpuAdapter>(adapter_rid)
|
||||||
|
.map_err(InitError::Resource)?;
|
||||||
let adapter = adapter_resource.1;
|
let adapter = adapter_resource.1;
|
||||||
let instance = state.borrow::<Instance>();
|
let instance = state.borrow::<Instance>();
|
||||||
|
|
||||||
|
@ -685,13 +698,14 @@ pub fn op_webgpu_request_device(
|
||||||
));
|
));
|
||||||
adapter_resource.close();
|
adapter_resource.close();
|
||||||
if let Some(err) = maybe_err {
|
if let Some(err) = maybe_err {
|
||||||
return Err(DomExceptionOperationError::new(&err.to_string()).into());
|
return Err(InitError::RequestDevice(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
let device_features =
|
let device_features = gfx_select!(device => instance.device_features(device))
|
||||||
gfx_select!(device => instance.device_features(device))?;
|
.map_err(InitError::InvalidDevice)?;
|
||||||
let features = deserialize_features(&device_features);
|
let features = deserialize_features(&device_features);
|
||||||
let limits = gfx_select!(device => instance.device_limits(device))?;
|
let limits = gfx_select!(device => instance.device_limits(device))
|
||||||
|
.map_err(InitError::InvalidDevice)?;
|
||||||
|
|
||||||
let instance = instance.clone();
|
let instance = instance.clone();
|
||||||
let instance2 = instance.clone();
|
let instance2 = instance.clone();
|
||||||
|
@ -722,14 +736,17 @@ pub struct GPUAdapterInfo {
|
||||||
pub fn op_webgpu_request_adapter_info(
|
pub fn op_webgpu_request_adapter_info(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
#[smi] adapter_rid: ResourceId,
|
#[smi] adapter_rid: ResourceId,
|
||||||
) -> Result<GPUAdapterInfo, AnyError> {
|
) -> Result<GPUAdapterInfo, InitError> {
|
||||||
let state = state.borrow_mut();
|
let state = state.borrow_mut();
|
||||||
let adapter_resource =
|
let adapter_resource = state
|
||||||
state.resource_table.get::<WebGpuAdapter>(adapter_rid)?;
|
.resource_table
|
||||||
|
.get::<WebGpuAdapter>(adapter_rid)
|
||||||
|
.map_err(InitError::Resource)?;
|
||||||
let adapter = adapter_resource.1;
|
let adapter = adapter_resource.1;
|
||||||
let instance = state.borrow::<Instance>();
|
let instance = state.borrow::<Instance>();
|
||||||
|
|
||||||
let info = gfx_select!(adapter => instance.adapter_get_info(adapter))?;
|
let info = gfx_select!(adapter => instance.adapter_get_info(adapter))
|
||||||
|
.map_err(InitError::InvalidAdapter)?;
|
||||||
|
|
||||||
Ok(GPUAdapterInfo {
|
Ok(GPUAdapterInfo {
|
||||||
vendor: info.vendor.to_string(),
|
vendor: info.vendor.to_string(),
|
||||||
|
@ -770,9 +787,11 @@ impl From<GpuQueryType> for wgpu_types::QueryType {
|
||||||
pub fn op_webgpu_create_query_set(
|
pub fn op_webgpu_create_query_set(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[serde] args: CreateQuerySetArgs,
|
#[serde] args: CreateQuerySetArgs,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, InitError> {
|
||||||
let device_resource =
|
let device_resource = state
|
||||||
state.resource_table.get::<WebGpuDevice>(args.device_rid)?;
|
.resource_table
|
||||||
|
.get::<WebGpuDevice>(args.device_rid)
|
||||||
|
.map_err(InitError::Resource)?;
|
||||||
let device = device_resource.1;
|
let device = device_resource.1;
|
||||||
let instance = state.borrow::<Instance>();
|
let instance = state.borrow::<Instance>();
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use deno_core::error::type_error;
|
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::op2;
|
use deno_core::op2;
|
||||||
use deno_core::OpState;
|
use deno_core::OpState;
|
||||||
use deno_core::Resource;
|
use deno_core::Resource;
|
||||||
|
@ -12,6 +10,14 @@ use std::cell::RefCell;
|
||||||
|
|
||||||
use super::error::WebGpuResult;
|
use super::error::WebGpuResult;
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum RenderPassError {
|
||||||
|
#[error(transparent)]
|
||||||
|
Resource(deno_core::error::AnyError),
|
||||||
|
#[error("size must be larger than 0")]
|
||||||
|
InvalidSize,
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) struct WebGpuRenderPass(
|
pub(crate) struct WebGpuRenderPass(
|
||||||
pub(crate) RefCell<wgpu_core::command::RenderPass>,
|
pub(crate) RefCell<wgpu_core::command::RenderPass>,
|
||||||
);
|
);
|
||||||
|
@ -38,7 +44,7 @@ pub struct RenderPassSetViewportArgs {
|
||||||
pub fn op_webgpu_render_pass_set_viewport(
|
pub fn op_webgpu_render_pass_set_viewport(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[serde] args: RenderPassSetViewportArgs,
|
#[serde] args: RenderPassSetViewportArgs,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let render_pass_resource = state
|
let render_pass_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<WebGpuRenderPass>(args.render_pass_rid)?;
|
.get::<WebGpuRenderPass>(args.render_pass_rid)?;
|
||||||
|
@ -65,7 +71,7 @@ pub fn op_webgpu_render_pass_set_scissor_rect(
|
||||||
y: u32,
|
y: u32,
|
||||||
width: u32,
|
width: u32,
|
||||||
height: u32,
|
height: u32,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let render_pass_resource = state
|
let render_pass_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<WebGpuRenderPass>(render_pass_rid)?;
|
.get::<WebGpuRenderPass>(render_pass_rid)?;
|
||||||
|
@ -87,7 +93,7 @@ pub fn op_webgpu_render_pass_set_blend_constant(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[smi] render_pass_rid: ResourceId,
|
#[smi] render_pass_rid: ResourceId,
|
||||||
#[serde] color: wgpu_types::Color,
|
#[serde] color: wgpu_types::Color,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let render_pass_resource = state
|
let render_pass_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<WebGpuRenderPass>(render_pass_rid)?;
|
.get::<WebGpuRenderPass>(render_pass_rid)?;
|
||||||
|
@ -106,7 +112,7 @@ pub fn op_webgpu_render_pass_set_stencil_reference(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[smi] render_pass_rid: ResourceId,
|
#[smi] render_pass_rid: ResourceId,
|
||||||
reference: u32,
|
reference: u32,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let render_pass_resource = state
|
let render_pass_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<WebGpuRenderPass>(render_pass_rid)?;
|
.get::<WebGpuRenderPass>(render_pass_rid)?;
|
||||||
|
@ -125,7 +131,7 @@ pub fn op_webgpu_render_pass_begin_occlusion_query(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[smi] render_pass_rid: ResourceId,
|
#[smi] render_pass_rid: ResourceId,
|
||||||
query_index: u32,
|
query_index: u32,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let render_pass_resource = state
|
let render_pass_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<WebGpuRenderPass>(render_pass_rid)?;
|
.get::<WebGpuRenderPass>(render_pass_rid)?;
|
||||||
|
@ -143,7 +149,7 @@ pub fn op_webgpu_render_pass_begin_occlusion_query(
|
||||||
pub fn op_webgpu_render_pass_end_occlusion_query(
|
pub fn op_webgpu_render_pass_end_occlusion_query(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[smi] render_pass_rid: ResourceId,
|
#[smi] render_pass_rid: ResourceId,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let render_pass_resource = state
|
let render_pass_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<WebGpuRenderPass>(render_pass_rid)?;
|
.get::<WebGpuRenderPass>(render_pass_rid)?;
|
||||||
|
@ -161,7 +167,7 @@ pub fn op_webgpu_render_pass_execute_bundles(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[smi] render_pass_rid: ResourceId,
|
#[smi] render_pass_rid: ResourceId,
|
||||||
#[serde] bundles: Vec<u32>,
|
#[serde] bundles: Vec<u32>,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let bundles = bundles
|
let bundles = bundles
|
||||||
.iter()
|
.iter()
|
||||||
.map(|rid| {
|
.map(|rid| {
|
||||||
|
@ -171,7 +177,7 @@ pub fn op_webgpu_render_pass_execute_bundles(
|
||||||
.get::<super::bundle::WebGpuRenderBundle>(*rid)?;
|
.get::<super::bundle::WebGpuRenderBundle>(*rid)?;
|
||||||
Ok(render_bundle_resource.1)
|
Ok(render_bundle_resource.1)
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, AnyError>>()?;
|
.collect::<Result<Vec<_>, deno_core::error::AnyError>>()?;
|
||||||
|
|
||||||
let render_pass_resource = state
|
let render_pass_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
|
@ -191,7 +197,7 @@ pub fn op_webgpu_render_pass_end(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[smi] command_encoder_rid: ResourceId,
|
#[smi] command_encoder_rid: ResourceId,
|
||||||
#[smi] render_pass_rid: ResourceId,
|
#[smi] render_pass_rid: ResourceId,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let command_encoder_resource = state
|
let command_encoder_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<super::command_encoder::WebGpuCommandEncoder>(
|
.get::<super::command_encoder::WebGpuCommandEncoder>(
|
||||||
|
@ -217,7 +223,7 @@ pub fn op_webgpu_render_pass_set_bind_group(
|
||||||
#[buffer] dynamic_offsets_data: &[u32],
|
#[buffer] dynamic_offsets_data: &[u32],
|
||||||
#[number] dynamic_offsets_data_start: usize,
|
#[number] dynamic_offsets_data_start: usize,
|
||||||
#[number] dynamic_offsets_data_length: usize,
|
#[number] dynamic_offsets_data_length: usize,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let bind_group_resource =
|
let bind_group_resource =
|
||||||
state
|
state
|
||||||
.resource_table
|
.resource_table
|
||||||
|
@ -251,7 +257,7 @@ pub fn op_webgpu_render_pass_push_debug_group(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[smi] render_pass_rid: ResourceId,
|
#[smi] render_pass_rid: ResourceId,
|
||||||
#[string] group_label: &str,
|
#[string] group_label: &str,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let render_pass_resource = state
|
let render_pass_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<WebGpuRenderPass>(render_pass_rid)?;
|
.get::<WebGpuRenderPass>(render_pass_rid)?;
|
||||||
|
@ -270,7 +276,7 @@ pub fn op_webgpu_render_pass_push_debug_group(
|
||||||
pub fn op_webgpu_render_pass_pop_debug_group(
|
pub fn op_webgpu_render_pass_pop_debug_group(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[smi] render_pass_rid: ResourceId,
|
#[smi] render_pass_rid: ResourceId,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let render_pass_resource = state
|
let render_pass_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<WebGpuRenderPass>(render_pass_rid)?;
|
.get::<WebGpuRenderPass>(render_pass_rid)?;
|
||||||
|
@ -288,7 +294,7 @@ pub fn op_webgpu_render_pass_insert_debug_marker(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[smi] render_pass_rid: ResourceId,
|
#[smi] render_pass_rid: ResourceId,
|
||||||
#[string] marker_label: &str,
|
#[string] marker_label: &str,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let render_pass_resource = state
|
let render_pass_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<WebGpuRenderPass>(render_pass_rid)?;
|
.get::<WebGpuRenderPass>(render_pass_rid)?;
|
||||||
|
@ -308,7 +314,7 @@ pub fn op_webgpu_render_pass_set_pipeline(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[smi] render_pass_rid: ResourceId,
|
#[smi] render_pass_rid: ResourceId,
|
||||||
pipeline: u32,
|
pipeline: u32,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let render_pipeline_resource =
|
let render_pipeline_resource =
|
||||||
state
|
state
|
||||||
.resource_table
|
.resource_table
|
||||||
|
@ -334,19 +340,18 @@ pub fn op_webgpu_render_pass_set_index_buffer(
|
||||||
#[serde] index_format: wgpu_types::IndexFormat,
|
#[serde] index_format: wgpu_types::IndexFormat,
|
||||||
#[number] offset: u64,
|
#[number] offset: u64,
|
||||||
#[number] size: Option<u64>,
|
#[number] size: Option<u64>,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, RenderPassError> {
|
||||||
let buffer_resource = state
|
let buffer_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<super::buffer::WebGpuBuffer>(buffer)?;
|
.get::<super::buffer::WebGpuBuffer>(buffer)
|
||||||
|
.map_err(RenderPassError::Resource)?;
|
||||||
let render_pass_resource = state
|
let render_pass_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<WebGpuRenderPass>(render_pass_rid)?;
|
.get::<WebGpuRenderPass>(render_pass_rid)
|
||||||
|
.map_err(RenderPassError::Resource)?;
|
||||||
|
|
||||||
let size = if let Some(size) = size {
|
let size = if let Some(size) = size {
|
||||||
Some(
|
Some(std::num::NonZeroU64::new(size).ok_or(RenderPassError::InvalidSize)?)
|
||||||
std::num::NonZeroU64::new(size)
|
|
||||||
.ok_or_else(|| type_error("size must be larger than 0"))?,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -370,19 +375,18 @@ pub fn op_webgpu_render_pass_set_vertex_buffer(
|
||||||
buffer: u32,
|
buffer: u32,
|
||||||
#[number] offset: u64,
|
#[number] offset: u64,
|
||||||
#[number] size: Option<u64>,
|
#[number] size: Option<u64>,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, RenderPassError> {
|
||||||
let buffer_resource = state
|
let buffer_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<super::buffer::WebGpuBuffer>(buffer)?;
|
.get::<super::buffer::WebGpuBuffer>(buffer)
|
||||||
|
.map_err(RenderPassError::Resource)?;
|
||||||
let render_pass_resource = state
|
let render_pass_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<WebGpuRenderPass>(render_pass_rid)?;
|
.get::<WebGpuRenderPass>(render_pass_rid)
|
||||||
|
.map_err(RenderPassError::Resource)?;
|
||||||
|
|
||||||
let size = if let Some(size) = size {
|
let size = if let Some(size) = size {
|
||||||
Some(
|
Some(std::num::NonZeroU64::new(size).ok_or(RenderPassError::InvalidSize)?)
|
||||||
std::num::NonZeroU64::new(size)
|
|
||||||
.ok_or_else(|| type_error("size must be larger than 0"))?,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -407,7 +411,7 @@ pub fn op_webgpu_render_pass_draw(
|
||||||
instance_count: u32,
|
instance_count: u32,
|
||||||
first_vertex: u32,
|
first_vertex: u32,
|
||||||
first_instance: u32,
|
first_instance: u32,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let render_pass_resource = state
|
let render_pass_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<WebGpuRenderPass>(render_pass_rid)?;
|
.get::<WebGpuRenderPass>(render_pass_rid)?;
|
||||||
|
@ -433,7 +437,7 @@ pub fn op_webgpu_render_pass_draw_indexed(
|
||||||
first_index: u32,
|
first_index: u32,
|
||||||
base_vertex: i32,
|
base_vertex: i32,
|
||||||
first_instance: u32,
|
first_instance: u32,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let render_pass_resource = state
|
let render_pass_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<WebGpuRenderPass>(render_pass_rid)?;
|
.get::<WebGpuRenderPass>(render_pass_rid)?;
|
||||||
|
@ -457,7 +461,7 @@ pub fn op_webgpu_render_pass_draw_indirect(
|
||||||
#[smi] render_pass_rid: ResourceId,
|
#[smi] render_pass_rid: ResourceId,
|
||||||
indirect_buffer: u32,
|
indirect_buffer: u32,
|
||||||
#[number] indirect_offset: u64,
|
#[number] indirect_offset: u64,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let buffer_resource = state
|
let buffer_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<super::buffer::WebGpuBuffer>(indirect_buffer)?;
|
.get::<super::buffer::WebGpuBuffer>(indirect_buffer)?;
|
||||||
|
@ -481,7 +485,7 @@ pub fn op_webgpu_render_pass_draw_indexed_indirect(
|
||||||
#[smi] render_pass_rid: ResourceId,
|
#[smi] render_pass_rid: ResourceId,
|
||||||
indirect_buffer: u32,
|
indirect_buffer: u32,
|
||||||
#[number] indirect_offset: u64,
|
#[number] indirect_offset: u64,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let buffer_resource = state
|
let buffer_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<super::buffer::WebGpuBuffer>(indirect_buffer)?;
|
.get::<super::buffer::WebGpuBuffer>(indirect_buffer)?;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::op2;
|
use deno_core::op2;
|
||||||
use deno_core::OpState;
|
use deno_core::OpState;
|
||||||
use deno_core::Resource;
|
use deno_core::Resource;
|
||||||
|
@ -47,7 +46,7 @@ pub struct CreateSamplerArgs {
|
||||||
pub fn op_webgpu_create_sampler(
|
pub fn op_webgpu_create_sampler(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[serde] args: CreateSamplerArgs,
|
#[serde] args: CreateSamplerArgs,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let instance = state.borrow::<super::Instance>();
|
let instance = state.borrow::<super::Instance>();
|
||||||
let device_resource = state
|
let device_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::op2;
|
use deno_core::op2;
|
||||||
use deno_core::OpState;
|
use deno_core::OpState;
|
||||||
use deno_core::Resource;
|
use deno_core::Resource;
|
||||||
|
@ -31,7 +30,7 @@ pub fn op_webgpu_create_shader_module(
|
||||||
#[smi] device_rid: ResourceId,
|
#[smi] device_rid: ResourceId,
|
||||||
#[string] label: Cow<str>,
|
#[string] label: Cow<str>,
|
||||||
#[string] code: Cow<str>,
|
#[string] code: Cow<str>,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let instance = state.borrow::<super::Instance>();
|
let instance = state.borrow::<super::Instance>();
|
||||||
let device_resource = state
|
let device_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use super::WebGpuResult;
|
use super::WebGpuResult;
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::op2;
|
use deno_core::op2;
|
||||||
use deno_core::OpState;
|
use deno_core::OpState;
|
||||||
use deno_core::Resource;
|
use deno_core::Resource;
|
||||||
|
@ -11,6 +10,16 @@ use std::borrow::Cow;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use wgpu_types::SurfaceStatus;
|
use wgpu_types::SurfaceStatus;
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum SurfaceError {
|
||||||
|
#[error(transparent)]
|
||||||
|
Resource(deno_core::error::AnyError),
|
||||||
|
#[error("Invalid Surface Status")]
|
||||||
|
InvalidStatus,
|
||||||
|
#[error(transparent)]
|
||||||
|
Surface(wgpu_core::present::SurfaceError),
|
||||||
|
}
|
||||||
|
|
||||||
pub struct WebGpuSurface(pub crate::Instance, pub wgpu_core::id::SurfaceId);
|
pub struct WebGpuSurface(pub crate::Instance, pub wgpu_core::id::SurfaceId);
|
||||||
impl Resource for WebGpuSurface {
|
impl Resource for WebGpuSurface {
|
||||||
fn name(&self) -> Cow<str> {
|
fn name(&self) -> Cow<str> {
|
||||||
|
@ -41,7 +50,7 @@ pub struct SurfaceConfigureArgs {
|
||||||
pub fn op_webgpu_surface_configure(
|
pub fn op_webgpu_surface_configure(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[serde] args: SurfaceConfigureArgs,
|
#[serde] args: SurfaceConfigureArgs,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let instance = state.borrow::<super::Instance>();
|
let instance = state.borrow::<super::Instance>();
|
||||||
let device_resource = state
|
let device_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
|
@ -75,18 +84,22 @@ pub fn op_webgpu_surface_get_current_texture(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[smi] device_rid: ResourceId,
|
#[smi] device_rid: ResourceId,
|
||||||
#[smi] surface_rid: ResourceId,
|
#[smi] surface_rid: ResourceId,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, SurfaceError> {
|
||||||
let instance = state.borrow::<super::Instance>();
|
let instance = state.borrow::<super::Instance>();
|
||||||
let device_resource = state
|
let device_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<super::WebGpuDevice>(device_rid)?;
|
.get::<super::WebGpuDevice>(device_rid)
|
||||||
|
.map_err(SurfaceError::Resource)?;
|
||||||
let device = device_resource.1;
|
let device = device_resource.1;
|
||||||
let surface_resource =
|
let surface_resource = state
|
||||||
state.resource_table.get::<WebGpuSurface>(surface_rid)?;
|
.resource_table
|
||||||
|
.get::<WebGpuSurface>(surface_rid)
|
||||||
|
.map_err(SurfaceError::Resource)?;
|
||||||
let surface = surface_resource.1;
|
let surface = surface_resource.1;
|
||||||
|
|
||||||
let output =
|
let output =
|
||||||
gfx_select!(device => instance.surface_get_current_texture(surface, None))?;
|
gfx_select!(device => instance.surface_get_current_texture(surface, None))
|
||||||
|
.map_err(SurfaceError::Surface)?;
|
||||||
|
|
||||||
match output.status {
|
match output.status {
|
||||||
SurfaceStatus::Good | SurfaceStatus::Suboptimal => {
|
SurfaceStatus::Good | SurfaceStatus::Suboptimal => {
|
||||||
|
@ -98,7 +111,7 @@ pub fn op_webgpu_surface_get_current_texture(
|
||||||
});
|
});
|
||||||
Ok(WebGpuResult::rid(rid))
|
Ok(WebGpuResult::rid(rid))
|
||||||
}
|
}
|
||||||
_ => Err(AnyError::msg("Invalid Surface Status")),
|
_ => Err(SurfaceError::InvalidStatus),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,17 +120,21 @@ pub fn op_webgpu_surface_present(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[smi] device_rid: ResourceId,
|
#[smi] device_rid: ResourceId,
|
||||||
#[smi] surface_rid: ResourceId,
|
#[smi] surface_rid: ResourceId,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), SurfaceError> {
|
||||||
let instance = state.borrow::<super::Instance>();
|
let instance = state.borrow::<super::Instance>();
|
||||||
let device_resource = state
|
let device_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<super::WebGpuDevice>(device_rid)?;
|
.get::<super::WebGpuDevice>(device_rid)
|
||||||
|
.map_err(SurfaceError::Resource)?;
|
||||||
let device = device_resource.1;
|
let device = device_resource.1;
|
||||||
let surface_resource =
|
let surface_resource = state
|
||||||
state.resource_table.get::<WebGpuSurface>(surface_rid)?;
|
.resource_table
|
||||||
|
.get::<WebGpuSurface>(surface_rid)
|
||||||
|
.map_err(SurfaceError::Resource)?;
|
||||||
let surface = surface_resource.1;
|
let surface = surface_resource.1;
|
||||||
|
|
||||||
let _ = gfx_select!(device => instance.surface_present(surface))?;
|
let _ = gfx_select!(device => instance.surface_present(surface))
|
||||||
|
.map_err(SurfaceError::Surface)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::op2;
|
use deno_core::op2;
|
||||||
use deno_core::OpState;
|
use deno_core::OpState;
|
||||||
use deno_core::Resource;
|
use deno_core::Resource;
|
||||||
|
@ -62,7 +61,7 @@ pub struct CreateTextureArgs {
|
||||||
pub fn op_webgpu_create_texture(
|
pub fn op_webgpu_create_texture(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[serde] args: CreateTextureArgs,
|
#[serde] args: CreateTextureArgs,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let instance = state.borrow::<super::Instance>();
|
let instance = state.borrow::<super::Instance>();
|
||||||
let device_resource = state
|
let device_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
|
@ -111,7 +110,7 @@ pub struct CreateTextureViewArgs {
|
||||||
pub fn op_webgpu_create_texture_view(
|
pub fn op_webgpu_create_texture_view(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[serde] args: CreateTextureViewArgs,
|
#[serde] args: CreateTextureViewArgs,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, deno_core::error::AnyError> {
|
||||||
let instance = state.borrow::<super::Instance>();
|
let instance = state.borrow::<super::Instance>();
|
||||||
let texture_resource = state
|
let texture_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
|
|
|
@ -28,4 +28,5 @@ hyper-util.workspace = true
|
||||||
once_cell.workspace = true
|
once_cell.workspace = true
|
||||||
rustls-tokio-stream.workspace = true
|
rustls-tokio-stream.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
|
thiserror.workspace = true
|
||||||
tokio.workspace = true
|
tokio.workspace = true
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
use crate::stream::WebSocketStream;
|
use crate::stream::WebSocketStream;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use deno_core::anyhow::bail;
|
|
||||||
use deno_core::error::invalid_hostname;
|
|
||||||
use deno_core::error::type_error;
|
|
||||||
use deno_core::error::AnyError;
|
|
||||||
use deno_core::futures::TryFutureExt;
|
use deno_core::futures::TryFutureExt;
|
||||||
use deno_core::op2;
|
use deno_core::op2;
|
||||||
use deno_core::unsync::spawn;
|
use deno_core::unsync::spawn;
|
||||||
|
@ -43,7 +39,6 @@ use serde::Serialize;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::fmt;
|
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
@ -75,11 +70,33 @@ static USE_WRITEV: Lazy<bool> = Lazy::new(|| {
|
||||||
false
|
false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum WebsocketError {
|
||||||
|
#[error(transparent)]
|
||||||
|
Url(url::ParseError),
|
||||||
|
#[error(transparent)]
|
||||||
|
Permission(deno_core::error::AnyError),
|
||||||
|
#[error(transparent)]
|
||||||
|
Resource(deno_core::error::AnyError),
|
||||||
|
#[error(transparent)]
|
||||||
|
Uri(#[from] http::uri::InvalidUri),
|
||||||
|
#[error("{0}")]
|
||||||
|
Io(#[from] std::io::Error),
|
||||||
|
#[error(transparent)]
|
||||||
|
WebSocket(#[from] fastwebsockets::WebSocketError),
|
||||||
|
#[error("failed to connect to WebSocket: {0}")]
|
||||||
|
ConnectionFailed(#[from] HandshakeError),
|
||||||
|
#[error(transparent)]
|
||||||
|
Canceled(#[from] deno_core::Canceled),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct WsRootStoreProvider(Option<Arc<dyn RootCertStoreProvider>>);
|
pub struct WsRootStoreProvider(Option<Arc<dyn RootCertStoreProvider>>);
|
||||||
|
|
||||||
impl WsRootStoreProvider {
|
impl WsRootStoreProvider {
|
||||||
pub fn get_or_try_init(&self) -> Result<Option<RootCertStore>, AnyError> {
|
pub fn get_or_try_init(
|
||||||
|
&self,
|
||||||
|
) -> Result<Option<RootCertStore>, deno_core::error::AnyError> {
|
||||||
Ok(match &self.0 {
|
Ok(match &self.0 {
|
||||||
Some(provider) => Some(provider.get_or_try_init()?.clone()),
|
Some(provider) => Some(provider.get_or_try_init()?.clone()),
|
||||||
None => None,
|
None => None,
|
||||||
|
@ -95,7 +112,7 @@ pub trait WebSocketPermissions {
|
||||||
&mut self,
|
&mut self,
|
||||||
_url: &url::Url,
|
_url: &url::Url,
|
||||||
_api_name: &str,
|
_api_name: &str,
|
||||||
) -> Result<(), AnyError>;
|
) -> Result<(), deno_core::error::AnyError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WebSocketPermissions for deno_permissions::PermissionsContainer {
|
impl WebSocketPermissions for deno_permissions::PermissionsContainer {
|
||||||
|
@ -104,7 +121,7 @@ impl WebSocketPermissions for deno_permissions::PermissionsContainer {
|
||||||
&mut self,
|
&mut self,
|
||||||
url: &url::Url,
|
url: &url::Url,
|
||||||
api_name: &str,
|
api_name: &str,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), deno_core::error::AnyError> {
|
||||||
deno_permissions::PermissionsContainer::check_net_url(self, url, api_name)
|
deno_permissions::PermissionsContainer::check_net_url(self, url, api_name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,13 +154,17 @@ pub fn op_ws_check_permission_and_cancel_handle<WP>(
|
||||||
#[string] api_name: String,
|
#[string] api_name: String,
|
||||||
#[string] url: String,
|
#[string] url: String,
|
||||||
cancel_handle: bool,
|
cancel_handle: bool,
|
||||||
) -> Result<Option<ResourceId>, AnyError>
|
) -> Result<Option<ResourceId>, WebsocketError>
|
||||||
where
|
where
|
||||||
WP: WebSocketPermissions + 'static,
|
WP: WebSocketPermissions + 'static,
|
||||||
{
|
{
|
||||||
state
|
state
|
||||||
.borrow_mut::<WP>()
|
.borrow_mut::<WP>()
|
||||||
.check_net_url(&url::Url::parse(&url)?, &api_name)?;
|
.check_net_url(
|
||||||
|
&url::Url::parse(&url).map_err(WebsocketError::Url)?,
|
||||||
|
&api_name,
|
||||||
|
)
|
||||||
|
.map_err(WebsocketError::Permission)?;
|
||||||
|
|
||||||
if cancel_handle {
|
if cancel_handle {
|
||||||
let rid = state
|
let rid = state
|
||||||
|
@ -163,16 +184,46 @@ pub struct CreateResponse {
|
||||||
extensions: String,
|
extensions: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum HandshakeError {
|
||||||
|
#[error("Missing path in url")]
|
||||||
|
MissingPath,
|
||||||
|
#[error("Invalid status code {0}")]
|
||||||
|
InvalidStatusCode(StatusCode),
|
||||||
|
#[error(transparent)]
|
||||||
|
Http(#[from] http::Error),
|
||||||
|
#[error(transparent)]
|
||||||
|
WebSocket(#[from] fastwebsockets::WebSocketError),
|
||||||
|
#[error("Didn't receive h2 alpn, aborting connection")]
|
||||||
|
NoH2Alpn,
|
||||||
|
#[error(transparent)]
|
||||||
|
Rustls(#[from] deno_tls::rustls::Error),
|
||||||
|
#[error(transparent)]
|
||||||
|
Io(#[from] std::io::Error),
|
||||||
|
#[error(transparent)]
|
||||||
|
H2(#[from] h2::Error),
|
||||||
|
#[error("Invalid hostname: '{0}'")]
|
||||||
|
InvalidHostname(String),
|
||||||
|
#[error(transparent)]
|
||||||
|
RootStoreError(deno_core::error::AnyError),
|
||||||
|
#[error(transparent)]
|
||||||
|
Tls(deno_tls::TlsError),
|
||||||
|
#[error(transparent)]
|
||||||
|
HeaderName(#[from] http::header::InvalidHeaderName),
|
||||||
|
#[error(transparent)]
|
||||||
|
HeaderValue(#[from] http::header::InvalidHeaderValue),
|
||||||
|
}
|
||||||
|
|
||||||
async fn handshake_websocket(
|
async fn handshake_websocket(
|
||||||
state: &Rc<RefCell<OpState>>,
|
state: &Rc<RefCell<OpState>>,
|
||||||
uri: &Uri,
|
uri: &Uri,
|
||||||
protocols: &str,
|
protocols: &str,
|
||||||
headers: Option<Vec<(ByteString, ByteString)>>,
|
headers: Option<Vec<(ByteString, ByteString)>>,
|
||||||
) -> Result<(WebSocket<WebSocketStream>, http::HeaderMap), AnyError> {
|
) -> Result<(WebSocket<WebSocketStream>, http::HeaderMap), HandshakeError> {
|
||||||
let mut request = Request::builder().method(Method::GET).uri(
|
let mut request = Request::builder().method(Method::GET).uri(
|
||||||
uri
|
uri
|
||||||
.path_and_query()
|
.path_and_query()
|
||||||
.ok_or(type_error("Missing path in url".to_string()))?
|
.ok_or(HandshakeError::MissingPath)?
|
||||||
.as_str(),
|
.as_str(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -194,7 +245,9 @@ async fn handshake_websocket(
|
||||||
request =
|
request =
|
||||||
populate_common_request_headers(request, &user_agent, protocols, &headers)?;
|
populate_common_request_headers(request, &user_agent, protocols, &headers)?;
|
||||||
|
|
||||||
let request = request.body(http_body_util::Empty::new())?;
|
let request = request
|
||||||
|
.body(http_body_util::Empty::new())
|
||||||
|
.map_err(HandshakeError::Http)?;
|
||||||
let domain = &uri.host().unwrap().to_string();
|
let domain = &uri.host().unwrap().to_string();
|
||||||
let port = &uri.port_u16().unwrap_or(match uri.scheme_str() {
|
let port = &uri.port_u16().unwrap_or(match uri.scheme_str() {
|
||||||
Some("wss") => 443,
|
Some("wss") => 443,
|
||||||
|
@ -231,7 +284,7 @@ async fn handshake_websocket(
|
||||||
async fn handshake_http1_ws(
|
async fn handshake_http1_ws(
|
||||||
request: Request<http_body_util::Empty<Bytes>>,
|
request: Request<http_body_util::Empty<Bytes>>,
|
||||||
addr: &String,
|
addr: &String,
|
||||||
) -> Result<(WebSocket<WebSocketStream>, http::HeaderMap), AnyError> {
|
) -> Result<(WebSocket<WebSocketStream>, http::HeaderMap), HandshakeError> {
|
||||||
let tcp_socket = TcpStream::connect(addr).await?;
|
let tcp_socket = TcpStream::connect(addr).await?;
|
||||||
handshake_connection(request, tcp_socket).await
|
handshake_connection(request, tcp_socket).await
|
||||||
}
|
}
|
||||||
|
@ -241,11 +294,11 @@ async fn handshake_http1_wss(
|
||||||
request: Request<http_body_util::Empty<Bytes>>,
|
request: Request<http_body_util::Empty<Bytes>>,
|
||||||
domain: &str,
|
domain: &str,
|
||||||
addr: &str,
|
addr: &str,
|
||||||
) -> Result<(WebSocket<WebSocketStream>, http::HeaderMap), AnyError> {
|
) -> Result<(WebSocket<WebSocketStream>, http::HeaderMap), HandshakeError> {
|
||||||
let tcp_socket = TcpStream::connect(addr).await?;
|
let tcp_socket = TcpStream::connect(addr).await?;
|
||||||
let tls_config = create_ws_client_config(state, SocketUse::Http1Only)?;
|
let tls_config = create_ws_client_config(state, SocketUse::Http1Only)?;
|
||||||
let dnsname = ServerName::try_from(domain.to_string())
|
let dnsname = ServerName::try_from(domain.to_string())
|
||||||
.map_err(|_| invalid_hostname(domain))?;
|
.map_err(|_| HandshakeError::InvalidHostname(domain.to_string()))?;
|
||||||
let mut tls_connector = TlsStream::new_client_side(
|
let mut tls_connector = TlsStream::new_client_side(
|
||||||
tcp_socket,
|
tcp_socket,
|
||||||
ClientConnection::new(tls_config.into(), dnsname)?,
|
ClientConnection::new(tls_config.into(), dnsname)?,
|
||||||
|
@ -266,11 +319,11 @@ async fn handshake_http2_wss(
|
||||||
domain: &str,
|
domain: &str,
|
||||||
headers: &Option<Vec<(ByteString, ByteString)>>,
|
headers: &Option<Vec<(ByteString, ByteString)>>,
|
||||||
addr: &str,
|
addr: &str,
|
||||||
) -> Result<(WebSocket<WebSocketStream>, http::HeaderMap), AnyError> {
|
) -> Result<(WebSocket<WebSocketStream>, http::HeaderMap), HandshakeError> {
|
||||||
let tcp_socket = TcpStream::connect(addr).await?;
|
let tcp_socket = TcpStream::connect(addr).await?;
|
||||||
let tls_config = create_ws_client_config(state, SocketUse::Http2Only)?;
|
let tls_config = create_ws_client_config(state, SocketUse::Http2Only)?;
|
||||||
let dnsname = ServerName::try_from(domain.to_string())
|
let dnsname = ServerName::try_from(domain.to_string())
|
||||||
.map_err(|_| invalid_hostname(domain))?;
|
.map_err(|_| HandshakeError::InvalidHostname(domain.to_string()))?;
|
||||||
// We need to better expose the underlying errors here
|
// We need to better expose the underlying errors here
|
||||||
let mut tls_connector = TlsStream::new_client_side(
|
let mut tls_connector = TlsStream::new_client_side(
|
||||||
tcp_socket,
|
tcp_socket,
|
||||||
|
@ -279,7 +332,7 @@ async fn handshake_http2_wss(
|
||||||
);
|
);
|
||||||
let handshake = tls_connector.handshake().await?;
|
let handshake = tls_connector.handshake().await?;
|
||||||
if handshake.alpn.is_none() {
|
if handshake.alpn.is_none() {
|
||||||
bail!("Didn't receive h2 alpn, aborting connection");
|
return Err(HandshakeError::NoH2Alpn);
|
||||||
}
|
}
|
||||||
let h2 = h2::client::Builder::new();
|
let h2 = h2::client::Builder::new();
|
||||||
let (mut send, conn) = h2.handshake::<_, Bytes>(tls_connector).await?;
|
let (mut send, conn) = h2.handshake::<_, Bytes>(tls_connector).await?;
|
||||||
|
@ -298,7 +351,7 @@ async fn handshake_http2_wss(
|
||||||
let (resp, send) = send.send_request(request.body(())?, false)?;
|
let (resp, send) = send.send_request(request.body(())?, false)?;
|
||||||
let resp = resp.await?;
|
let resp = resp.await?;
|
||||||
if resp.status() != StatusCode::OK {
|
if resp.status() != StatusCode::OK {
|
||||||
bail!("Invalid status code: {}", resp.status());
|
return Err(HandshakeError::InvalidStatusCode(resp.status()));
|
||||||
}
|
}
|
||||||
let (http::response::Parts { headers, .. }, recv) = resp.into_parts();
|
let (http::response::Parts { headers, .. }, recv) = resp.into_parts();
|
||||||
let mut stream = WebSocket::after_handshake(
|
let mut stream = WebSocket::after_handshake(
|
||||||
|
@ -317,7 +370,7 @@ async fn handshake_connection<
|
||||||
>(
|
>(
|
||||||
request: Request<http_body_util::Empty<Bytes>>,
|
request: Request<http_body_util::Empty<Bytes>>,
|
||||||
socket: S,
|
socket: S,
|
||||||
) -> Result<(WebSocket<WebSocketStream>, http::HeaderMap), AnyError> {
|
) -> Result<(WebSocket<WebSocketStream>, http::HeaderMap), HandshakeError> {
|
||||||
let (upgraded, response) =
|
let (upgraded, response) =
|
||||||
fastwebsockets::handshake::client(&LocalExecutor, request, socket).await?;
|
fastwebsockets::handshake::client(&LocalExecutor, request, socket).await?;
|
||||||
|
|
||||||
|
@ -332,7 +385,7 @@ async fn handshake_connection<
|
||||||
pub fn create_ws_client_config(
|
pub fn create_ws_client_config(
|
||||||
state: &Rc<RefCell<OpState>>,
|
state: &Rc<RefCell<OpState>>,
|
||||||
socket_use: SocketUse,
|
socket_use: SocketUse,
|
||||||
) -> Result<ClientConfig, AnyError> {
|
) -> Result<ClientConfig, HandshakeError> {
|
||||||
let unsafely_ignore_certificate_errors: Option<Vec<String>> = state
|
let unsafely_ignore_certificate_errors: Option<Vec<String>> = state
|
||||||
.borrow()
|
.borrow()
|
||||||
.try_borrow::<UnsafelyIgnoreCertificateErrors>()
|
.try_borrow::<UnsafelyIgnoreCertificateErrors>()
|
||||||
|
@ -340,7 +393,8 @@ pub fn create_ws_client_config(
|
||||||
let root_cert_store = state
|
let root_cert_store = state
|
||||||
.borrow()
|
.borrow()
|
||||||
.borrow::<WsRootStoreProvider>()
|
.borrow::<WsRootStoreProvider>()
|
||||||
.get_or_try_init()?;
|
.get_or_try_init()
|
||||||
|
.map_err(HandshakeError::RootStoreError)?;
|
||||||
|
|
||||||
create_client_config(
|
create_client_config(
|
||||||
root_cert_store,
|
root_cert_store,
|
||||||
|
@ -349,7 +403,7 @@ pub fn create_ws_client_config(
|
||||||
TlsKeys::Null,
|
TlsKeys::Null,
|
||||||
socket_use,
|
socket_use,
|
||||||
)
|
)
|
||||||
.map_err(|e| e.into())
|
.map_err(HandshakeError::Tls)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Headers common to both http/1.1 and h2 requests.
|
/// Headers common to both http/1.1 and h2 requests.
|
||||||
|
@ -358,7 +412,7 @@ fn populate_common_request_headers(
|
||||||
user_agent: &str,
|
user_agent: &str,
|
||||||
protocols: &str,
|
protocols: &str,
|
||||||
headers: &Option<Vec<(ByteString, ByteString)>>,
|
headers: &Option<Vec<(ByteString, ByteString)>>,
|
||||||
) -> Result<http::request::Builder, AnyError> {
|
) -> Result<http::request::Builder, HandshakeError> {
|
||||||
request = request
|
request = request
|
||||||
.header("User-Agent", user_agent)
|
.header("User-Agent", user_agent)
|
||||||
.header("Sec-WebSocket-Version", "13");
|
.header("Sec-WebSocket-Version", "13");
|
||||||
|
@ -369,10 +423,8 @@ fn populate_common_request_headers(
|
||||||
|
|
||||||
if let Some(headers) = headers {
|
if let Some(headers) = headers {
|
||||||
for (key, value) in headers {
|
for (key, value) in headers {
|
||||||
let name = HeaderName::from_bytes(key)
|
let name = HeaderName::from_bytes(key)?;
|
||||||
.map_err(|err| type_error(err.to_string()))?;
|
let v = HeaderValue::from_bytes(value)?;
|
||||||
let v = HeaderValue::from_bytes(value)
|
|
||||||
.map_err(|err| type_error(err.to_string()))?;
|
|
||||||
|
|
||||||
let is_disallowed_header = matches!(
|
let is_disallowed_header = matches!(
|
||||||
name,
|
name,
|
||||||
|
@ -402,14 +454,17 @@ pub async fn op_ws_create<WP>(
|
||||||
#[string] protocols: String,
|
#[string] protocols: String,
|
||||||
#[smi] cancel_handle: Option<ResourceId>,
|
#[smi] cancel_handle: Option<ResourceId>,
|
||||||
#[serde] headers: Option<Vec<(ByteString, ByteString)>>,
|
#[serde] headers: Option<Vec<(ByteString, ByteString)>>,
|
||||||
) -> Result<CreateResponse, AnyError>
|
) -> Result<CreateResponse, WebsocketError>
|
||||||
where
|
where
|
||||||
WP: WebSocketPermissions + 'static,
|
WP: WebSocketPermissions + 'static,
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
let mut s = state.borrow_mut();
|
let mut s = state.borrow_mut();
|
||||||
s.borrow_mut::<WP>()
|
s.borrow_mut::<WP>()
|
||||||
.check_net_url(&url::Url::parse(&url)?, &api_name)
|
.check_net_url(
|
||||||
|
&url::Url::parse(&url).map_err(WebsocketError::Url)?,
|
||||||
|
&api_name,
|
||||||
|
)
|
||||||
.expect(
|
.expect(
|
||||||
"Permission check should have been done in op_ws_check_permission",
|
"Permission check should have been done in op_ws_check_permission",
|
||||||
);
|
);
|
||||||
|
@ -419,7 +474,8 @@ where
|
||||||
let r = state
|
let r = state
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<WsCancelResource>(cancel_rid)?;
|
.get::<WsCancelResource>(cancel_rid)
|
||||||
|
.map_err(WebsocketError::Resource)?;
|
||||||
Some(r.0.clone())
|
Some(r.0.clone())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -428,15 +484,11 @@ where
|
||||||
let uri: Uri = url.parse()?;
|
let uri: Uri = url.parse()?;
|
||||||
|
|
||||||
let handshake = handshake_websocket(&state, &uri, &protocols, headers)
|
let handshake = handshake_websocket(&state, &uri, &protocols, headers)
|
||||||
.map_err(|err| {
|
.map_err(WebsocketError::ConnectionFailed);
|
||||||
AnyError::from(DomExceptionNetworkError::new(&format!(
|
|
||||||
"failed to connect to WebSocket: {err}"
|
|
||||||
)))
|
|
||||||
});
|
|
||||||
let (stream, response) = match cancel_resource {
|
let (stream, response) = match cancel_resource {
|
||||||
Some(rc) => handshake.try_or_cancel(rc).await,
|
Some(rc) => handshake.try_or_cancel(rc).await?,
|
||||||
None => handshake.await,
|
None => handshake.await?,
|
||||||
}?;
|
};
|
||||||
|
|
||||||
if let Some(cancel_rid) = cancel_handle {
|
if let Some(cancel_rid) = cancel_handle {
|
||||||
if let Ok(res) = state.borrow_mut().resource_table.take_any(cancel_rid) {
|
if let Ok(res) = state.borrow_mut().resource_table.take_any(cancel_rid) {
|
||||||
|
@ -521,14 +573,12 @@ impl ServerWebSocket {
|
||||||
self: &Rc<Self>,
|
self: &Rc<Self>,
|
||||||
lock: AsyncMutFuture<WebSocketWrite<WriteHalf<WebSocketStream>>>,
|
lock: AsyncMutFuture<WebSocketWrite<WriteHalf<WebSocketStream>>>,
|
||||||
frame: Frame<'_>,
|
frame: Frame<'_>,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), WebsocketError> {
|
||||||
let mut ws = lock.await;
|
let mut ws = lock.await;
|
||||||
if ws.is_closed() {
|
if ws.is_closed() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
ws.write_frame(frame)
|
ws.write_frame(frame).await?;
|
||||||
.await
|
|
||||||
.map_err(|err| type_error(err.to_string()))?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -543,7 +593,7 @@ pub fn ws_create_server_stream(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
transport: NetworkStream,
|
transport: NetworkStream,
|
||||||
read_buf: Bytes,
|
read_buf: Bytes,
|
||||||
) -> Result<ResourceId, AnyError> {
|
) -> ResourceId {
|
||||||
let mut ws = WebSocket::after_handshake(
|
let mut ws = WebSocket::after_handshake(
|
||||||
WebSocketStream::new(
|
WebSocketStream::new(
|
||||||
stream::WsStreamKind::Network(transport),
|
stream::WsStreamKind::Network(transport),
|
||||||
|
@ -555,8 +605,7 @@ pub fn ws_create_server_stream(
|
||||||
ws.set_auto_close(true);
|
ws.set_auto_close(true);
|
||||||
ws.set_auto_pong(true);
|
ws.set_auto_pong(true);
|
||||||
|
|
||||||
let rid = state.resource_table.add(ServerWebSocket::new(ws));
|
state.resource_table.add(ServerWebSocket::new(ws))
|
||||||
Ok(rid)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_binary(state: &mut OpState, rid: ResourceId, data: &[u8]) {
|
fn send_binary(state: &mut OpState, rid: ResourceId, data: &[u8]) {
|
||||||
|
@ -626,11 +675,12 @@ pub async fn op_ws_send_binary_async(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
#[smi] rid: ResourceId,
|
#[smi] rid: ResourceId,
|
||||||
#[buffer] data: JsBuffer,
|
#[buffer] data: JsBuffer,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), WebsocketError> {
|
||||||
let resource = state
|
let resource = state
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<ServerWebSocket>(rid)?;
|
.get::<ServerWebSocket>(rid)
|
||||||
|
.map_err(WebsocketError::Resource)?;
|
||||||
let data = data.to_vec();
|
let data = data.to_vec();
|
||||||
let lock = resource.reserve_lock();
|
let lock = resource.reserve_lock();
|
||||||
resource
|
resource
|
||||||
|
@ -644,11 +694,12 @@ pub async fn op_ws_send_text_async(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
#[smi] rid: ResourceId,
|
#[smi] rid: ResourceId,
|
||||||
#[string] data: String,
|
#[string] data: String,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), WebsocketError> {
|
||||||
let resource = state
|
let resource = state
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<ServerWebSocket>(rid)?;
|
.get::<ServerWebSocket>(rid)
|
||||||
|
.map_err(WebsocketError::Resource)?;
|
||||||
let lock = resource.reserve_lock();
|
let lock = resource.reserve_lock();
|
||||||
resource
|
resource
|
||||||
.write_frame(
|
.write_frame(
|
||||||
|
@ -678,11 +729,12 @@ pub fn op_ws_get_buffered_amount(
|
||||||
pub async fn op_ws_send_ping(
|
pub async fn op_ws_send_ping(
|
||||||
state: Rc<RefCell<OpState>>,
|
state: Rc<RefCell<OpState>>,
|
||||||
#[smi] rid: ResourceId,
|
#[smi] rid: ResourceId,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), WebsocketError> {
|
||||||
let resource = state
|
let resource = state
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.resource_table
|
.resource_table
|
||||||
.get::<ServerWebSocket>(rid)?;
|
.get::<ServerWebSocket>(rid)
|
||||||
|
.map_err(WebsocketError::Resource)?;
|
||||||
let lock = resource.reserve_lock();
|
let lock = resource.reserve_lock();
|
||||||
resource
|
resource
|
||||||
.write_frame(
|
.write_frame(
|
||||||
|
@ -698,7 +750,7 @@ pub async fn op_ws_close(
|
||||||
#[smi] rid: ResourceId,
|
#[smi] rid: ResourceId,
|
||||||
#[smi] code: Option<u16>,
|
#[smi] code: Option<u16>,
|
||||||
#[string] reason: Option<String>,
|
#[string] reason: Option<String>,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), WebsocketError> {
|
||||||
let Ok(resource) = state
|
let Ok(resource) = state
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.resource_table
|
.resource_table
|
||||||
|
@ -713,8 +765,7 @@ pub async fn op_ws_close(
|
||||||
|
|
||||||
resource.closed.set(true);
|
resource.closed.set(true);
|
||||||
let lock = resource.reserve_lock();
|
let lock = resource.reserve_lock();
|
||||||
resource.write_frame(lock, frame).await?;
|
resource.write_frame(lock, frame).await
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[op2]
|
#[op2]
|
||||||
|
@ -868,32 +919,6 @@ pub fn get_declaration() -> PathBuf {
|
||||||
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("lib.deno_websocket.d.ts")
|
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("lib.deno_websocket.d.ts")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct DomExceptionNetworkError {
|
|
||||||
pub msg: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DomExceptionNetworkError {
|
|
||||||
pub fn new(msg: &str) -> Self {
|
|
||||||
DomExceptionNetworkError {
|
|
||||||
msg: msg.to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for DomExceptionNetworkError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
f.pad(&self.msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::error::Error for DomExceptionNetworkError {}
|
|
||||||
|
|
||||||
pub fn get_network_error_class_name(e: &AnyError) -> Option<&'static str> {
|
|
||||||
e.downcast_ref::<DomExceptionNetworkError>()
|
|
||||||
.map(|_| "DOMExceptionNetworkError")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Needed so hyper can use non Send futures
|
// Needed so hyper can use non Send futures
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct LocalExecutor;
|
struct LocalExecutor;
|
||||||
|
|
|
@ -17,12 +17,24 @@ use deno_core::serde_json;
|
||||||
use deno_core::url;
|
use deno_core::url;
|
||||||
use deno_core::ModuleResolutionError;
|
use deno_core::ModuleResolutionError;
|
||||||
use deno_cron::CronError;
|
use deno_cron::CronError;
|
||||||
|
use deno_crypto::DecryptError;
|
||||||
|
use deno_crypto::EncryptError;
|
||||||
|
use deno_crypto::ExportKeyError;
|
||||||
|
use deno_crypto::GenerateKeyError;
|
||||||
|
use deno_crypto::ImportKeyError;
|
||||||
|
use deno_fetch::FetchError;
|
||||||
|
use deno_fetch::HttpClientCreateError;
|
||||||
use deno_ffi::CallError;
|
use deno_ffi::CallError;
|
||||||
use deno_ffi::CallbackError;
|
use deno_ffi::CallbackError;
|
||||||
use deno_ffi::DlfcnError;
|
use deno_ffi::DlfcnError;
|
||||||
use deno_ffi::IRError;
|
use deno_ffi::IRError;
|
||||||
use deno_ffi::ReprError;
|
use deno_ffi::ReprError;
|
||||||
use deno_ffi::StaticError;
|
use deno_ffi::StaticError;
|
||||||
|
use deno_fs::FsOpsError;
|
||||||
|
use deno_http::HttpError;
|
||||||
|
use deno_http::HttpNextError;
|
||||||
|
use deno_http::WebSocketUpgradeError;
|
||||||
|
use deno_io::fs::FsError;
|
||||||
use deno_kv::KvCheckError;
|
use deno_kv::KvCheckError;
|
||||||
use deno_kv::KvError;
|
use deno_kv::KvError;
|
||||||
use deno_kv::KvMutationError;
|
use deno_kv::KvMutationError;
|
||||||
|
@ -34,6 +46,8 @@ use deno_web::CompressionError;
|
||||||
use deno_web::MessagePortError;
|
use deno_web::MessagePortError;
|
||||||
use deno_web::StreamResourceError;
|
use deno_web::StreamResourceError;
|
||||||
use deno_web::WebError;
|
use deno_web::WebError;
|
||||||
|
use deno_websocket::HandshakeError;
|
||||||
|
use deno_websocket::WebsocketError;
|
||||||
use deno_webstorage::WebStorageError;
|
use deno_webstorage::WebStorageError;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
@ -175,6 +189,248 @@ pub fn get_nix_error_class(error: &nix::Error) -> &'static str {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_webgpu_error_class(e: &deno_webgpu::InitError) -> &'static str {
|
||||||
|
match e {
|
||||||
|
deno_webgpu::InitError::Resource(e) => {
|
||||||
|
get_error_class_name(e).unwrap_or("Error")
|
||||||
|
}
|
||||||
|
deno_webgpu::InitError::InvalidAdapter(_) => "Error",
|
||||||
|
deno_webgpu::InitError::RequestDevice(_) => "DOMExceptionOperationError",
|
||||||
|
deno_webgpu::InitError::InvalidDevice(_) => "Error",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_webgpu_buffer_error_class(
|
||||||
|
e: &deno_webgpu::buffer::BufferError,
|
||||||
|
) -> &'static str {
|
||||||
|
match e {
|
||||||
|
deno_webgpu::buffer::BufferError::Resource(e) => {
|
||||||
|
get_error_class_name(e).unwrap_or("Error")
|
||||||
|
}
|
||||||
|
deno_webgpu::buffer::BufferError::InvalidUsage => "TypeError",
|
||||||
|
deno_webgpu::buffer::BufferError::Access(_) => "DOMExceptionOperationError",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_webgpu_bundle_error_class(
|
||||||
|
e: &deno_webgpu::bundle::BundleError,
|
||||||
|
) -> &'static str {
|
||||||
|
match e {
|
||||||
|
deno_webgpu::bundle::BundleError::Resource(e) => {
|
||||||
|
get_error_class_name(e).unwrap_or("Error")
|
||||||
|
}
|
||||||
|
deno_webgpu::bundle::BundleError::InvalidSize => "TypeError",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_webgpu_byow_error_class(
|
||||||
|
e: &deno_webgpu::byow::ByowError,
|
||||||
|
) -> &'static str {
|
||||||
|
match e {
|
||||||
|
deno_webgpu::byow::ByowError::WebGPUNotInitiated => "TypeError",
|
||||||
|
deno_webgpu::byow::ByowError::InvalidParameters => "TypeError",
|
||||||
|
deno_webgpu::byow::ByowError::CreateSurface(_) => "Error",
|
||||||
|
deno_webgpu::byow::ByowError::InvalidSystem => "TypeError",
|
||||||
|
#[cfg(any(
|
||||||
|
target_os = "windows",
|
||||||
|
target_os = "linux",
|
||||||
|
target_os = "freebsd",
|
||||||
|
target_os = "openbsd"
|
||||||
|
))]
|
||||||
|
deno_webgpu::byow::ByowError::NullWindow => "TypeError",
|
||||||
|
#[cfg(any(
|
||||||
|
target_os = "linux",
|
||||||
|
target_os = "freebsd",
|
||||||
|
target_os = "openbsd"
|
||||||
|
))]
|
||||||
|
deno_webgpu::byow::ByowError::NullDisplay => "TypeError",
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
deno_webgpu::byow::ByowError::NSViewDisplay => "TypeError",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_webgpu_render_pass_error_class(
|
||||||
|
e: &deno_webgpu::render_pass::RenderPassError,
|
||||||
|
) -> &'static str {
|
||||||
|
match e {
|
||||||
|
deno_webgpu::render_pass::RenderPassError::Resource(e) => {
|
||||||
|
get_error_class_name(e).unwrap_or("Error")
|
||||||
|
}
|
||||||
|
deno_webgpu::render_pass::RenderPassError::InvalidSize => "TypeError",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_webgpu_surface_error_class(
|
||||||
|
e: &deno_webgpu::surface::SurfaceError,
|
||||||
|
) -> &'static str {
|
||||||
|
match e {
|
||||||
|
deno_webgpu::surface::SurfaceError::Resource(e) => {
|
||||||
|
get_error_class_name(e).unwrap_or("Error")
|
||||||
|
}
|
||||||
|
deno_webgpu::surface::SurfaceError::Surface(_) => "Error",
|
||||||
|
deno_webgpu::surface::SurfaceError::InvalidStatus => "Error",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_crypto_decrypt_error_class(e: &DecryptError) -> &'static str {
|
||||||
|
match e {
|
||||||
|
DecryptError::General(e) => get_crypto_shared_error_class(e),
|
||||||
|
DecryptError::Pkcs1(_) => "Error",
|
||||||
|
DecryptError::Failed => "DOMExceptionOperationError",
|
||||||
|
DecryptError::InvalidLength => "TypeError",
|
||||||
|
DecryptError::InvalidCounterLength => "TypeError",
|
||||||
|
DecryptError::InvalidTagLength => "TypeError",
|
||||||
|
DecryptError::InvalidKeyOrIv => "DOMExceptionOperationError",
|
||||||
|
DecryptError::TooMuchData => "DOMExceptionOperationError",
|
||||||
|
DecryptError::InvalidIvLength => "TypeError",
|
||||||
|
DecryptError::Rsa(_) => "DOMExceptionOperationError",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_crypto_encrypt_error_class(e: &EncryptError) -> &'static str {
|
||||||
|
match e {
|
||||||
|
EncryptError::General(e) => get_crypto_shared_error_class(e),
|
||||||
|
EncryptError::InvalidKeyOrIv => "DOMExceptionOperationError",
|
||||||
|
EncryptError::Failed => "DOMExceptionOperationError",
|
||||||
|
EncryptError::InvalidLength => "TypeError",
|
||||||
|
EncryptError::InvalidIvLength => "TypeError",
|
||||||
|
EncryptError::InvalidCounterLength => "TypeError",
|
||||||
|
EncryptError::TooMuchData => "DOMExceptionOperationError",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_crypto_shared_error_class(e: &deno_crypto::SharedError) -> &'static str {
|
||||||
|
match e {
|
||||||
|
deno_crypto::SharedError::ExpectedValidPrivateKey => "TypeError",
|
||||||
|
deno_crypto::SharedError::ExpectedValidPublicKey => "TypeError",
|
||||||
|
deno_crypto::SharedError::ExpectedValidPrivateECKey => "TypeError",
|
||||||
|
deno_crypto::SharedError::ExpectedValidPublicECKey => "TypeError",
|
||||||
|
deno_crypto::SharedError::ExpectedPrivateKey => "TypeError",
|
||||||
|
deno_crypto::SharedError::ExpectedPublicKey => "TypeError",
|
||||||
|
deno_crypto::SharedError::ExpectedSecretKey => "TypeError",
|
||||||
|
deno_crypto::SharedError::FailedDecodePrivateKey => {
|
||||||
|
"DOMExceptionOperationError"
|
||||||
|
}
|
||||||
|
deno_crypto::SharedError::FailedDecodePublicKey => {
|
||||||
|
"DOMExceptionOperationError"
|
||||||
|
}
|
||||||
|
deno_crypto::SharedError::UnsupportedFormat => {
|
||||||
|
"DOMExceptionNotSupportedError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_crypto_ed25519_error_class(
|
||||||
|
e: &deno_crypto::Ed25519Error,
|
||||||
|
) -> &'static str {
|
||||||
|
match e {
|
||||||
|
deno_crypto::Ed25519Error::FailedExport => "DOMExceptionOperationError",
|
||||||
|
deno_crypto::Ed25519Error::Der(_) => "Error",
|
||||||
|
deno_crypto::Ed25519Error::KeyRejected(_) => "Error",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_crypto_export_key_error_class(e: &ExportKeyError) -> &'static str {
|
||||||
|
match e {
|
||||||
|
ExportKeyError::General(e) => get_crypto_shared_error_class(e),
|
||||||
|
ExportKeyError::Der(_) => "Error",
|
||||||
|
ExportKeyError::UnsupportedNamedCurve => "DOMExceptionNotSupportedError",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_crypto_generate_key_error_class(e: &GenerateKeyError) -> &'static str {
|
||||||
|
match e {
|
||||||
|
GenerateKeyError::General(e) => get_crypto_shared_error_class(e),
|
||||||
|
GenerateKeyError::BadPublicExponent => "DOMExceptionOperationError",
|
||||||
|
GenerateKeyError::InvalidHMACKeyLength => "DOMExceptionOperationError",
|
||||||
|
GenerateKeyError::FailedRSAKeySerialization => "DOMExceptionOperationError",
|
||||||
|
GenerateKeyError::InvalidAESKeyLength => "DOMExceptionOperationError",
|
||||||
|
GenerateKeyError::FailedRSAKeyGeneration => "DOMExceptionOperationError",
|
||||||
|
GenerateKeyError::FailedECKeyGeneration => "DOMExceptionOperationError",
|
||||||
|
GenerateKeyError::FailedKeyGeneration => "DOMExceptionOperationError",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_crypto_import_key_error_class(e: &ImportKeyError) -> &'static str {
|
||||||
|
match e {
|
||||||
|
ImportKeyError::General(e) => get_crypto_shared_error_class(e),
|
||||||
|
ImportKeyError::InvalidModulus => "DOMExceptionDataError",
|
||||||
|
ImportKeyError::InvalidPublicExponent => "DOMExceptionDataError",
|
||||||
|
ImportKeyError::InvalidPrivateExponent => "DOMExceptionDataError",
|
||||||
|
ImportKeyError::InvalidFirstPrimeFactor => "DOMExceptionDataError",
|
||||||
|
ImportKeyError::InvalidSecondPrimeFactor => "DOMExceptionDataError",
|
||||||
|
ImportKeyError::InvalidFirstCRTExponent => "DOMExceptionDataError",
|
||||||
|
ImportKeyError::InvalidSecondCRTExponent => "DOMExceptionDataError",
|
||||||
|
ImportKeyError::InvalidCRTCoefficient => "DOMExceptionDataError",
|
||||||
|
ImportKeyError::InvalidB64Coordinate => "DOMExceptionDataError",
|
||||||
|
ImportKeyError::InvalidRSAPublicKey => "DOMExceptionDataError",
|
||||||
|
ImportKeyError::InvalidRSAPrivateKey => "DOMExceptionDataError",
|
||||||
|
ImportKeyError::UnsupportedAlgorithm => "DOMExceptionDataError",
|
||||||
|
ImportKeyError::PublicKeyTooLong => "DOMExceptionDataError",
|
||||||
|
ImportKeyError::PrivateKeyTooLong => "DOMExceptionDataError",
|
||||||
|
ImportKeyError::InvalidP256ECPoint => "DOMExceptionDataError",
|
||||||
|
ImportKeyError::InvalidP384ECPoint => "DOMExceptionDataError",
|
||||||
|
ImportKeyError::InvalidP521ECPoint => "DOMExceptionDataError",
|
||||||
|
ImportKeyError::UnsupportedNamedCurve => "DOMExceptionDataError",
|
||||||
|
ImportKeyError::CurveMismatch => "DOMExceptionDataError",
|
||||||
|
ImportKeyError::InvalidKeyData => "DOMExceptionDataError",
|
||||||
|
ImportKeyError::InvalidJWKPrivateKey => "DOMExceptionDataError",
|
||||||
|
ImportKeyError::EllipticCurve(_) => "DOMExceptionDataError",
|
||||||
|
ImportKeyError::ExpectedValidPkcs8Data => "DOMExceptionDataError",
|
||||||
|
ImportKeyError::MalformedParameters => "DOMExceptionDataError",
|
||||||
|
ImportKeyError::Spki(_) => "DOMExceptionDataError",
|
||||||
|
ImportKeyError::InvalidP256ECSPKIData => "DOMExceptionDataError",
|
||||||
|
ImportKeyError::InvalidP384ECSPKIData => "DOMExceptionDataError",
|
||||||
|
ImportKeyError::InvalidP521ECSPKIData => "DOMExceptionDataError",
|
||||||
|
ImportKeyError::Der(_) => "DOMExceptionDataError",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_crypto_x448_error_class(e: &deno_crypto::X448Error) -> &'static str {
|
||||||
|
match e {
|
||||||
|
deno_crypto::X448Error::FailedExport => "DOMExceptionOperationError",
|
||||||
|
deno_crypto::X448Error::Der(_) => "Error",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_crypto_x25519_error_class(e: &deno_crypto::X25519Error) -> &'static str {
|
||||||
|
match e {
|
||||||
|
deno_crypto::X25519Error::FailedExport => "DOMExceptionOperationError",
|
||||||
|
deno_crypto::X25519Error::Der(_) => "Error",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_crypto_error_class(e: &deno_crypto::Error) -> &'static str {
|
||||||
|
match e {
|
||||||
|
deno_crypto::Error::Der(_) => "Error",
|
||||||
|
deno_crypto::Error::JoinError(_) => "Error",
|
||||||
|
deno_crypto::Error::MissingArgumentHash => "TypeError",
|
||||||
|
deno_crypto::Error::MissingArgumentSaltLength => "TypeError",
|
||||||
|
deno_crypto::Error::Other(e) => get_error_class_name(e).unwrap_or("Error"),
|
||||||
|
deno_crypto::Error::UnsupportedAlgorithm => "TypeError",
|
||||||
|
deno_crypto::Error::KeyRejected(_) => "Error",
|
||||||
|
deno_crypto::Error::RSA(_) => "Error",
|
||||||
|
deno_crypto::Error::Pkcs1(_) => "Error",
|
||||||
|
deno_crypto::Error::Unspecified(_) => "Error",
|
||||||
|
deno_crypto::Error::InvalidKeyFormat => "TypeError",
|
||||||
|
deno_crypto::Error::MissingArgumentPublicKey => "TypeError",
|
||||||
|
deno_crypto::Error::P256Ecdsa(_) => "Error",
|
||||||
|
deno_crypto::Error::DecodePrivateKey => "TypeError",
|
||||||
|
deno_crypto::Error::MissingArgumentNamedCurve => "TypeError",
|
||||||
|
deno_crypto::Error::MissingArgumentInfo => "TypeError",
|
||||||
|
deno_crypto::Error::HKDFLengthTooLarge => "DOMExceptionOperationError",
|
||||||
|
deno_crypto::Error::General(e) => get_crypto_shared_error_class(e),
|
||||||
|
deno_crypto::Error::Base64Decode(_) => "Error",
|
||||||
|
deno_crypto::Error::DataInvalidSize => "TypeError",
|
||||||
|
deno_crypto::Error::InvalidKeyLength => "TypeError",
|
||||||
|
deno_crypto::Error::EncryptionError => "DOMExceptionOperationError",
|
||||||
|
deno_crypto::Error::DecryptionError => "DOMExceptionOperationError",
|
||||||
|
deno_crypto::Error::ArrayBufferViewLengthExceeded(_) => {
|
||||||
|
"DOMExceptionQuotaExceededError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_napi_error_class(e: &NApiError) -> &'static str {
|
fn get_napi_error_class(e: &NApiError) -> &'static str {
|
||||||
match e {
|
match e {
|
||||||
NApiError::InvalidPath
|
NApiError::InvalidPath
|
||||||
|
@ -366,6 +622,107 @@ fn get_broadcast_channel_error(error: &BroadcastChannelError) -> &'static str {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_fetch_error(error: &FetchError) -> &'static str {
|
||||||
|
match error {
|
||||||
|
FetchError::Resource(e) | FetchError::Permission(e) => {
|
||||||
|
get_error_class_name(e).unwrap_or("Error")
|
||||||
|
}
|
||||||
|
FetchError::NetworkError => "TypeError",
|
||||||
|
FetchError::FsNotGet(_) => "TypeError",
|
||||||
|
FetchError::InvalidUrl(_) => "TypeError",
|
||||||
|
FetchError::InvalidHeaderName(_) => "TypeError",
|
||||||
|
FetchError::InvalidHeaderValue(_) => "TypeError",
|
||||||
|
FetchError::DataUrl(_) => "TypeError",
|
||||||
|
FetchError::Base64(_) => "TypeError",
|
||||||
|
FetchError::BlobNotFound => "TypeError",
|
||||||
|
FetchError::SchemeNotSupported(_) => "TypeError",
|
||||||
|
FetchError::RequestCanceled => "TypeError",
|
||||||
|
FetchError::Http(_) => "Error",
|
||||||
|
FetchError::ClientCreate(e) => get_http_client_create_error(e),
|
||||||
|
FetchError::Url(e) => get_url_parse_error_class(e),
|
||||||
|
FetchError::Method(_) => "TypeError",
|
||||||
|
FetchError::ClientSend(_) => "TypeError",
|
||||||
|
FetchError::RequestBuilderHook(_) => "TypeError",
|
||||||
|
FetchError::Io(e) => get_io_error_class(e),
|
||||||
|
FetchError::Hyper(e) => get_hyper_error_class(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_http_client_create_error(error: &HttpClientCreateError) -> &'static str {
|
||||||
|
match error {
|
||||||
|
HttpClientCreateError::Tls(_) => "TypeError",
|
||||||
|
HttpClientCreateError::InvalidUserAgent(_) => "TypeError",
|
||||||
|
HttpClientCreateError::InvalidProxyUrl => "TypeError",
|
||||||
|
HttpClientCreateError::HttpVersionSelectionInvalid => "TypeError",
|
||||||
|
HttpClientCreateError::RootCertStore(_) => "TypeError",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_websocket_error(error: &WebsocketError) -> &'static str {
|
||||||
|
match error {
|
||||||
|
WebsocketError::Permission(e) | WebsocketError::Resource(e) => {
|
||||||
|
get_error_class_name(e).unwrap_or("Error")
|
||||||
|
}
|
||||||
|
WebsocketError::Url(e) => get_url_parse_error_class(e),
|
||||||
|
WebsocketError::Io(e) => get_io_error_class(e),
|
||||||
|
WebsocketError::WebSocket(_) => "TypeError",
|
||||||
|
WebsocketError::ConnectionFailed(_) => "DOMExceptionNetworkError",
|
||||||
|
WebsocketError::Uri(_) => "Error",
|
||||||
|
WebsocketError::Canceled(e) => {
|
||||||
|
let io_err: io::Error = e.to_owned().into();
|
||||||
|
get_io_error_class(&io_err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_websocket_handshake_error(error: &HandshakeError) -> &'static str {
|
||||||
|
match error {
|
||||||
|
HandshakeError::RootStoreError(e) => {
|
||||||
|
get_error_class_name(e).unwrap_or("Error")
|
||||||
|
}
|
||||||
|
HandshakeError::Tls(e) => get_tls_error_class(e),
|
||||||
|
HandshakeError::MissingPath => "TypeError",
|
||||||
|
HandshakeError::Http(_) => "Error",
|
||||||
|
HandshakeError::InvalidHostname(_) => "TypeError",
|
||||||
|
HandshakeError::Io(e) => get_io_error_class(e),
|
||||||
|
HandshakeError::Rustls(_) => "Error",
|
||||||
|
HandshakeError::H2(_) => "Error",
|
||||||
|
HandshakeError::NoH2Alpn => "Error",
|
||||||
|
HandshakeError::InvalidStatusCode(_) => "Error",
|
||||||
|
HandshakeError::WebSocket(_) => "TypeError",
|
||||||
|
HandshakeError::HeaderName(_) => "TypeError",
|
||||||
|
HandshakeError::HeaderValue(_) => "TypeError",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_fs_error(error: &FsOpsError) -> &'static str {
|
||||||
|
match error {
|
||||||
|
FsOpsError::Io(e) => get_io_error_class(e),
|
||||||
|
FsOpsError::OperationError(e) => match &e.err {
|
||||||
|
FsError::Io(e) => get_io_error_class(e),
|
||||||
|
FsError::FileBusy => "Busy",
|
||||||
|
FsError::NotSupported => "NotSupported",
|
||||||
|
FsError::NotCapable(_) => "NotCapable",
|
||||||
|
},
|
||||||
|
FsOpsError::Permission(e)
|
||||||
|
| FsOpsError::Resource(e)
|
||||||
|
| FsOpsError::Other(e) => get_error_class_name(e).unwrap_or("Error"),
|
||||||
|
FsOpsError::InvalidUtf8(_) => "InvalidData",
|
||||||
|
FsOpsError::StripPrefix(_) => "Error",
|
||||||
|
FsOpsError::Canceled(e) => {
|
||||||
|
let io_err: io::Error = e.to_owned().into();
|
||||||
|
get_io_error_class(&io_err)
|
||||||
|
}
|
||||||
|
FsOpsError::InvalidSeekMode(_) => "TypeError",
|
||||||
|
FsOpsError::InvalidControlCharacter(_) => "Error",
|
||||||
|
FsOpsError::InvalidCharacter(_) => "Error",
|
||||||
|
#[cfg(windows)]
|
||||||
|
FsOpsError::InvalidTrailingCharacter => "Error",
|
||||||
|
FsOpsError::NotCapableAccess { .. } => "NotCapable",
|
||||||
|
FsOpsError::NotCapable(_) => "NotCapable",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_kv_error(error: &KvError) -> &'static str {
|
fn get_kv_error(error: &KvError) -> &'static str {
|
||||||
match error {
|
match error {
|
||||||
KvError::DatabaseHandler(e) | KvError::Resource(e) | KvError::Kv(e) => {
|
KvError::DatabaseHandler(e) | KvError::Resource(e) | KvError::Kv(e) => {
|
||||||
|
@ -449,10 +806,61 @@ fn get_net_map_error(error: &deno_net::io::MapError) -> &'static str {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_http_error(error: &HttpError) -> &'static str {
|
||||||
|
match error {
|
||||||
|
HttpError::Canceled(e) => {
|
||||||
|
let io_err: io::Error = e.to_owned().into();
|
||||||
|
get_io_error_class(&io_err)
|
||||||
|
}
|
||||||
|
HttpError::HyperV014(e) => get_hyper_v014_error_class(e),
|
||||||
|
HttpError::InvalidHeaderName(_) => "Error",
|
||||||
|
HttpError::InvalidHeaderValue(_) => "Error",
|
||||||
|
HttpError::Http(_) => "Error",
|
||||||
|
HttpError::ResponseHeadersAlreadySent => "Http",
|
||||||
|
HttpError::ConnectionClosedWhileSendingResponse => "Http",
|
||||||
|
HttpError::AlreadyInUse => "Http",
|
||||||
|
HttpError::Io(e) => get_io_error_class(e),
|
||||||
|
HttpError::NoResponseHeaders => "Http",
|
||||||
|
HttpError::ResponseAlreadyCompleted => "Http",
|
||||||
|
HttpError::UpgradeBodyUsed => "Http",
|
||||||
|
HttpError::Resource(e) | HttpError::Other(e) => {
|
||||||
|
get_error_class_name(e).unwrap_or("Error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_http_next_error(error: &HttpNextError) -> &'static str {
|
||||||
|
match error {
|
||||||
|
HttpNextError::Io(e) => get_io_error_class(e),
|
||||||
|
HttpNextError::WebSocketUpgrade(e) => get_websocket_upgrade_error(e),
|
||||||
|
HttpNextError::Hyper(e) => get_hyper_error_class(e),
|
||||||
|
HttpNextError::JoinError(_) => "Error",
|
||||||
|
HttpNextError::Canceled(e) => {
|
||||||
|
let io_err: io::Error = e.to_owned().into();
|
||||||
|
get_io_error_class(&io_err)
|
||||||
|
}
|
||||||
|
HttpNextError::UpgradeUnavailable(_) => "Error",
|
||||||
|
HttpNextError::HttpPropertyExtractor(e) | HttpNextError::Resource(e) => {
|
||||||
|
get_error_class_name(e).unwrap_or("Error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_websocket_upgrade_error(error: &WebSocketUpgradeError) -> &'static str {
|
||||||
|
match error {
|
||||||
|
WebSocketUpgradeError::InvalidHeaders => "Http",
|
||||||
|
WebSocketUpgradeError::HttpParse(_) => "Error",
|
||||||
|
WebSocketUpgradeError::Http(_) => "Error",
|
||||||
|
WebSocketUpgradeError::Utf8(_) => "Error",
|
||||||
|
WebSocketUpgradeError::InvalidHeaderName(_) => "Error",
|
||||||
|
WebSocketUpgradeError::InvalidHeaderValue(_) => "Error",
|
||||||
|
WebSocketUpgradeError::InvalidHttpStatusLine => "Http",
|
||||||
|
WebSocketUpgradeError::UpgradeBufferAlreadyCompleted => "Http",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_error_class_name(e: &AnyError) -> Option<&'static str> {
|
pub fn get_error_class_name(e: &AnyError) -> Option<&'static str> {
|
||||||
deno_core::error::get_custom_error_class(e)
|
deno_core::error::get_custom_error_class(e)
|
||||||
.or_else(|| deno_webgpu::error::get_error_class_name(e))
|
|
||||||
.or_else(|| deno_websocket::get_network_error_class_name(e))
|
|
||||||
.or_else(|| e.downcast_ref::<NApiError>().map(get_napi_error_class))
|
.or_else(|| e.downcast_ref::<NApiError>().map(get_napi_error_class))
|
||||||
.or_else(|| e.downcast_ref::<WebError>().map(get_web_error_class))
|
.or_else(|| e.downcast_ref::<WebError>().map(get_web_error_class))
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
|
@ -470,6 +878,13 @@ pub fn get_error_class_name(e: &AnyError) -> Option<&'static str> {
|
||||||
.or_else(|| e.downcast_ref::<BlobError>().map(get_web_blob_error_class))
|
.or_else(|| e.downcast_ref::<BlobError>().map(get_web_blob_error_class))
|
||||||
.or_else(|| e.downcast_ref::<IRError>().map(|_| "TypeError"))
|
.or_else(|| e.downcast_ref::<IRError>().map(|_| "TypeError"))
|
||||||
.or_else(|| e.downcast_ref::<ReprError>().map(get_ffi_repr_error_class))
|
.or_else(|| e.downcast_ref::<ReprError>().map(get_ffi_repr_error_class))
|
||||||
|
.or_else(|| e.downcast_ref::<HttpError>().map(get_http_error))
|
||||||
|
.or_else(|| e.downcast_ref::<HttpNextError>().map(get_http_next_error))
|
||||||
|
.or_else(|| {
|
||||||
|
e.downcast_ref::<WebSocketUpgradeError>()
|
||||||
|
.map(get_websocket_upgrade_error)
|
||||||
|
})
|
||||||
|
.or_else(|| e.downcast_ref::<FsOpsError>().map(get_fs_error))
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
e.downcast_ref::<DlfcnError>()
|
e.downcast_ref::<DlfcnError>()
|
||||||
.map(get_ffi_dlfcn_error_class)
|
.map(get_ffi_dlfcn_error_class)
|
||||||
|
@ -487,7 +902,17 @@ pub fn get_error_class_name(e: &AnyError) -> Option<&'static str> {
|
||||||
.or_else(|| e.downcast_ref::<CronError>().map(get_cron_error_class))
|
.or_else(|| e.downcast_ref::<CronError>().map(get_cron_error_class))
|
||||||
.or_else(|| e.downcast_ref::<CanvasError>().map(get_canvas_error))
|
.or_else(|| e.downcast_ref::<CanvasError>().map(get_canvas_error))
|
||||||
.or_else(|| e.downcast_ref::<CacheError>().map(get_cache_error))
|
.or_else(|| e.downcast_ref::<CacheError>().map(get_cache_error))
|
||||||
|
.or_else(|| e.downcast_ref::<WebsocketError>().map(get_websocket_error))
|
||||||
|
.or_else(|| {
|
||||||
|
e.downcast_ref::<HandshakeError>()
|
||||||
|
.map(get_websocket_handshake_error)
|
||||||
|
})
|
||||||
.or_else(|| e.downcast_ref::<KvError>().map(get_kv_error))
|
.or_else(|| e.downcast_ref::<KvError>().map(get_kv_error))
|
||||||
|
.or_else(|| e.downcast_ref::<FetchError>().map(get_fetch_error))
|
||||||
|
.or_else(|| {
|
||||||
|
e.downcast_ref::<HttpClientCreateError>()
|
||||||
|
.map(get_http_client_create_error)
|
||||||
|
})
|
||||||
.or_else(|| e.downcast_ref::<NetError>().map(get_net_error))
|
.or_else(|| e.downcast_ref::<NetError>().map(get_net_error))
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
e.downcast_ref::<deno_net::io::MapError>()
|
e.downcast_ref::<deno_net::io::MapError>()
|
||||||
|
@ -497,6 +922,70 @@ pub fn get_error_class_name(e: &AnyError) -> Option<&'static str> {
|
||||||
e.downcast_ref::<BroadcastChannelError>()
|
e.downcast_ref::<BroadcastChannelError>()
|
||||||
.map(get_broadcast_channel_error)
|
.map(get_broadcast_channel_error)
|
||||||
})
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
e.downcast_ref::<deno_webgpu::InitError>()
|
||||||
|
.map(get_webgpu_error_class)
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
e.downcast_ref::<deno_webgpu::buffer::BufferError>()
|
||||||
|
.map(get_webgpu_buffer_error_class)
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
e.downcast_ref::<deno_webgpu::bundle::BundleError>()
|
||||||
|
.map(get_webgpu_bundle_error_class)
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
e.downcast_ref::<deno_webgpu::byow::ByowError>()
|
||||||
|
.map(get_webgpu_byow_error_class)
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
e.downcast_ref::<deno_webgpu::render_pass::RenderPassError>()
|
||||||
|
.map(get_webgpu_render_pass_error_class)
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
e.downcast_ref::<deno_webgpu::surface::SurfaceError>()
|
||||||
|
.map(get_webgpu_surface_error_class)
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
e.downcast_ref::<DecryptError>()
|
||||||
|
.map(get_crypto_decrypt_error_class)
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
e.downcast_ref::<EncryptError>()
|
||||||
|
.map(get_crypto_encrypt_error_class)
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
e.downcast_ref::<deno_crypto::SharedError>()
|
||||||
|
.map(get_crypto_shared_error_class)
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
e.downcast_ref::<deno_crypto::Ed25519Error>()
|
||||||
|
.map(get_crypto_ed25519_error_class)
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
e.downcast_ref::<ExportKeyError>()
|
||||||
|
.map(get_crypto_export_key_error_class)
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
e.downcast_ref::<GenerateKeyError>()
|
||||||
|
.map(get_crypto_generate_key_error_class)
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
e.downcast_ref::<ImportKeyError>()
|
||||||
|
.map(get_crypto_import_key_error_class)
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
e.downcast_ref::<deno_crypto::X448Error>()
|
||||||
|
.map(get_crypto_x448_error_class)
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
e.downcast_ref::<deno_crypto::X25519Error>()
|
||||||
|
.map(get_crypto_x25519_error_class)
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
e.downcast_ref::<deno_crypto::Error>()
|
||||||
|
.map(get_crypto_error_class)
|
||||||
|
})
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
e.downcast_ref::<WebStorageError>()
|
e.downcast_ref::<WebStorageError>()
|
||||||
.map(get_webstorage_class_name)
|
.map(get_webstorage_class_name)
|
||||||
|
|
|
@ -34,7 +34,7 @@ fn op_http_start(
|
||||||
let (read_half, write_half) = resource.into_inner();
|
let (read_half, write_half) = resource.into_inner();
|
||||||
let tcp_stream = read_half.reunite(write_half)?;
|
let tcp_stream = read_half.reunite(write_half)?;
|
||||||
let addr = tcp_stream.local_addr()?;
|
let addr = tcp_stream.local_addr()?;
|
||||||
return http_create_conn_resource(state, tcp_stream, addr, "http");
|
return Ok(http_create_conn_resource(state, tcp_stream, addr, "http"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(resource_rc) = state
|
if let Ok(resource_rc) = state
|
||||||
|
@ -49,7 +49,7 @@ fn op_http_start(
|
||||||
let (read_half, write_half) = resource.into_inner();
|
let (read_half, write_half) = resource.into_inner();
|
||||||
let tls_stream = read_half.unsplit(write_half);
|
let tls_stream = read_half.unsplit(write_half);
|
||||||
let addr = tls_stream.local_addr()?;
|
let addr = tls_stream.local_addr()?;
|
||||||
return http_create_conn_resource(state, tls_stream, addr, "https");
|
return Ok(http_create_conn_resource(state, tls_stream, addr, "https"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
|
@ -65,7 +65,12 @@ fn op_http_start(
|
||||||
let (read_half, write_half) = resource.into_inner();
|
let (read_half, write_half) = resource.into_inner();
|
||||||
let unix_stream = read_half.reunite(write_half)?;
|
let unix_stream = read_half.reunite(write_half)?;
|
||||||
let addr = unix_stream.local_addr()?;
|
let addr = unix_stream.local_addr()?;
|
||||||
return http_create_conn_resource(state, unix_stream, addr, "http+unix");
|
return Ok(http_create_conn_resource(
|
||||||
|
state,
|
||||||
|
unix_stream,
|
||||||
|
addr,
|
||||||
|
"http+unix",
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(bad_resource_id())
|
Err(bad_resource_id())
|
||||||
|
|
|
@ -244,7 +244,8 @@ fn op_set_raw(
|
||||||
let tty_mode_store = state.borrow::<TtyModeStore>().clone();
|
let tty_mode_store = state.borrow::<TtyModeStore>().clone();
|
||||||
let previous_mode = tty_mode_store.get(rid);
|
let previous_mode = tty_mode_store.get(rid);
|
||||||
|
|
||||||
let raw_fd = handle_or_fd;
|
// SAFETY: Nix crate requires value to implement the AsFd trait
|
||||||
|
let raw_fd = unsafe { std::os::fd::BorrowedFd::borrow_raw(handle_or_fd) };
|
||||||
|
|
||||||
if is_raw {
|
if is_raw {
|
||||||
let mut raw = match previous_mode {
|
let mut raw = match previous_mode {
|
||||||
|
|
|
@ -4,6 +4,7 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use crate::web_worker::WebWorkerInternalHandle;
|
use crate::web_worker::WebWorkerInternalHandle;
|
||||||
use crate::web_worker::WebWorkerType;
|
use crate::web_worker::WebWorkerType;
|
||||||
|
use deno_core::error::custom_error;
|
||||||
use deno_core::error::type_error;
|
use deno_core::error::type_error;
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_core::futures::StreamExt;
|
use deno_core::futures::StreamExt;
|
||||||
|
@ -12,7 +13,6 @@ use deno_core::url::Url;
|
||||||
use deno_core::OpState;
|
use deno_core::OpState;
|
||||||
use deno_fetch::data_url::DataUrl;
|
use deno_fetch::data_url::DataUrl;
|
||||||
use deno_web::BlobStore;
|
use deno_web::BlobStore;
|
||||||
use deno_websocket::DomExceptionNetworkError;
|
|
||||||
use http_body_util::BodyExt;
|
use http_body_util::BodyExt;
|
||||||
use hyper::body::Bytes;
|
use hyper::body::Bytes;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
@ -151,17 +151,16 @@ pub fn op_worker_sync_fetch(
|
||||||
match mime_type.as_deref() {
|
match mime_type.as_deref() {
|
||||||
Some("application/javascript" | "text/javascript") => {}
|
Some("application/javascript" | "text/javascript") => {}
|
||||||
Some(mime_type) => {
|
Some(mime_type) => {
|
||||||
return Err(
|
return Err(custom_error(
|
||||||
DomExceptionNetworkError {
|
"DOMExceptionNetworkError",
|
||||||
msg: format!("Invalid MIME type {mime_type:?}."),
|
format!("Invalid MIME type {mime_type:?}."),
|
||||||
}
|
))
|
||||||
.into(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
return Err(
|
return Err(custom_error(
|
||||||
DomExceptionNetworkError::new("Missing MIME type.").into(),
|
"DOMExceptionNetworkError",
|
||||||
)
|
"Missing MIME type.",
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1111,7 +1111,7 @@ console.log(getValue());"#,
|
||||||
.run();
|
.run();
|
||||||
output.assert_exit_code(0);
|
output.assert_exit_code(0);
|
||||||
output.assert_matches_text(
|
output.assert_matches_text(
|
||||||
r#"Download http://localhost:4260/@denotest/esm-basic
|
r#"Download http://localhost:4260/@denotest%2fesm-basic
|
||||||
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
||||||
Initialize @denotest/esm-basic@1.0.0
|
Initialize @denotest/esm-basic@1.0.0
|
||||||
Check file:///[WILDCARD]/main.ts
|
Check file:///[WILDCARD]/main.ts
|
||||||
|
|
|
@ -876,7 +876,7 @@ fn auto_discover_lock_file() {
|
||||||
.run();
|
.run();
|
||||||
output
|
output
|
||||||
.assert_matches_text(
|
.assert_matches_text(
|
||||||
r#"Download http://localhost:4260/@denotest/bin
|
r#"Download http://localhost:4260/@denotest%2fbin
|
||||||
error: Integrity check failed for package: "npm:@denotest/bin@1.0.0". Unable to verify that the package
|
error: Integrity check failed for package: "npm:@denotest/bin@1.0.0". Unable to verify that the package
|
||||||
is the same as when the lockfile was generated.
|
is the same as when the lockfile was generated.
|
||||||
|
|
||||||
|
@ -1058,10 +1058,10 @@ fn reload_info_not_found_cache_but_exists_remote() {
|
||||||
.run();
|
.run();
|
||||||
output.assert_matches_text(concat!(
|
output.assert_matches_text(concat!(
|
||||||
"[UNORDERED_START]\n",
|
"[UNORDERED_START]\n",
|
||||||
"Download http://localhost:4260/@denotest/esm-basic\n",
|
"Download http://localhost:4260/@denotest%2fesm-basic\n",
|
||||||
"Download http://localhost:4260/@denotest/esm-import-cjs-default\n",
|
"Download http://localhost:4260/@denotest%2fesm-import-cjs-default\n",
|
||||||
"Download http://localhost:4260/@denotest/cjs-default-export\n",
|
"Download http://localhost:4260/@denotest%2fcjs-default-export\n",
|
||||||
"Download http://localhost:4260/@denotest/cjs-default-export/1.0.0.tgz\n",
|
"Download http://localhost:4260/@denotestcjs-default-export/1.0.0.tgz\n",
|
||||||
"Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz\n",
|
"Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz\n",
|
||||||
"Download http://localhost:4260/@denotest/esm-import-cjs-default/1.0.0.tgz\n",
|
"Download http://localhost:4260/@denotest/esm-import-cjs-default/1.0.0.tgz\n",
|
||||||
"[UNORDERED_END]\n",
|
"[UNORDERED_END]\n",
|
||||||
|
@ -1088,8 +1088,8 @@ fn reload_info_not_found_cache_but_exists_remote() {
|
||||||
let output = test_context.new_command().args("run main.ts").run();
|
let output = test_context.new_command().args("run main.ts").run();
|
||||||
output.assert_matches_text(concat!(
|
output.assert_matches_text(concat!(
|
||||||
"[UNORDERED_START]\n",
|
"[UNORDERED_START]\n",
|
||||||
"Download http://localhost:4260/@denotest/esm-import-cjs-default\n",
|
"Download http://localhost:4260/@denotest%2fesm-import-cjs-default\n",
|
||||||
"Download http://localhost:4260/@denotest/cjs-default-export\n",
|
"Download http://localhost:4260/@denotest%2fcjs-default-export\n",
|
||||||
"[UNORDERED_END]\n",
|
"[UNORDERED_END]\n",
|
||||||
"Node esm importing node cjs\n[WILDCARD]",
|
"Node esm importing node cjs\n[WILDCARD]",
|
||||||
));
|
));
|
||||||
|
@ -1120,8 +1120,8 @@ fn reload_info_not_found_cache_but_exists_remote() {
|
||||||
let output = test_context.new_command().args("run main.ts").run();
|
let output = test_context.new_command().args("run main.ts").run();
|
||||||
output.assert_matches_text(concat!(
|
output.assert_matches_text(concat!(
|
||||||
"[UNORDERED_START]\n",
|
"[UNORDERED_START]\n",
|
||||||
"Download http://localhost:4260/@denotest/esm-import-cjs-default\n",
|
"Download http://localhost:4260/@denotest%2fesm-import-cjs-default\n",
|
||||||
"Download http://localhost:4260/@denotest/cjs-default-export\n",
|
"Download http://localhost:4260/@denotest%2fcjs-default-export\n",
|
||||||
"[UNORDERED_END]\n",
|
"[UNORDERED_END]\n",
|
||||||
"Node esm importing node cjs\n[WILDCARD]",
|
"Node esm importing node cjs\n[WILDCARD]",
|
||||||
));
|
));
|
||||||
|
@ -1159,8 +1159,8 @@ fn reload_info_not_found_cache_but_exists_remote() {
|
||||||
let output = test_context.new_command().args("run main.ts").run();
|
let output = test_context.new_command().args("run main.ts").run();
|
||||||
output.assert_matches_text(concat!(
|
output.assert_matches_text(concat!(
|
||||||
"[UNORDERED_START]\n",
|
"[UNORDERED_START]\n",
|
||||||
"Download http://localhost:4260/@denotest/esm-import-cjs-default\n",
|
"Download http://localhost:4260/@denotest%2fesm-import-cjs-default\n",
|
||||||
"Download http://localhost:4260/@denotest/cjs-default-export\n",
|
"Download http://localhost:4260/@denotest%2fcjs-default-export\n",
|
||||||
"[UNORDERED_END]\n",
|
"[UNORDERED_END]\n",
|
||||||
"[UNORDERED_START]\n",
|
"[UNORDERED_START]\n",
|
||||||
"Initialize @denotest/cjs-default-export@1.0.0\n",
|
"Initialize @denotest/cjs-default-export@1.0.0\n",
|
||||||
|
@ -1196,9 +1196,9 @@ fn reload_info_not_found_cache_but_exists_remote() {
|
||||||
let output = test_context.new_command().args("run main.ts").run();
|
let output = test_context.new_command().args("run main.ts").run();
|
||||||
output.assert_matches_text(concat!(
|
output.assert_matches_text(concat!(
|
||||||
"[UNORDERED_START]\n",
|
"[UNORDERED_START]\n",
|
||||||
"Download http://localhost:4260/@denotest/esm-basic\n",
|
"Download http://localhost:4260/@denotest%2fesm-basic\n",
|
||||||
"Download http://localhost:4260/@denotest/esm-import-cjs-default\n",
|
"Download http://localhost:4260/@denotest%2fesm-import-cjs-default\n",
|
||||||
"Download http://localhost:4260/@denotest/cjs-default-export\n",
|
"Download http://localhost:4260/@denotest%2fcjs-default-export\n",
|
||||||
"[UNORDERED_END]\n",
|
"[UNORDERED_END]\n",
|
||||||
"Initialize @denotest/esm-basic@1.0.0\n",
|
"Initialize @denotest/esm-basic@1.0.0\n",
|
||||||
"Node esm importing node cjs\n[WILDCARD]",
|
"Node esm importing node cjs\n[WILDCARD]",
|
||||||
|
@ -1237,9 +1237,9 @@ fn reload_info_not_found_cache_but_exists_remote() {
|
||||||
let output = test_context.new_command().args("run main.ts").run();
|
let output = test_context.new_command().args("run main.ts").run();
|
||||||
output.assert_matches_text(concat!(
|
output.assert_matches_text(concat!(
|
||||||
"[UNORDERED_START]\n",
|
"[UNORDERED_START]\n",
|
||||||
"Download http://localhost:4260/@denotest/cjs-default-export\n",
|
"Download http://localhost:4260/@denotest%2fcjs-default-export\n",
|
||||||
"Download http://localhost:4260/@denotest/esm-basic\n",
|
"Download http://localhost:4260/@denotest%2fesm-basic\n",
|
||||||
"Download http://localhost:4260/@denotest/esm-import-cjs-default\n",
|
"Download http://localhost:4260/@denotest%2fesm-import-cjs-default\n",
|
||||||
"[UNORDERED_END]\n",
|
"[UNORDERED_END]\n",
|
||||||
"Node esm importing node cjs\n[WILDCARD]",
|
"Node esm importing node cjs\n[WILDCARD]",
|
||||||
));
|
));
|
||||||
|
@ -1419,7 +1419,7 @@ fn top_level_install_package_json_explicit_opt_in() {
|
||||||
temp_dir.write("main.ts", "console.log(5);");
|
temp_dir.write("main.ts", "console.log(5);");
|
||||||
let output = test_context.new_command().args("cache main.ts").run();
|
let output = test_context.new_command().args("cache main.ts").run();
|
||||||
output.assert_matches_text(concat!(
|
output.assert_matches_text(concat!(
|
||||||
"Download http://localhost:4260/@denotest/esm-basic\n",
|
"Download http://localhost:4260/@denotest%2fesm-basic\n",
|
||||||
"Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz\n",
|
"Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz\n",
|
||||||
"Initialize @denotest/esm-basic@1.0.0\n",
|
"Initialize @denotest/esm-basic@1.0.0\n",
|
||||||
));
|
));
|
||||||
|
|
|
@ -898,7 +898,7 @@ fn lock_redirects() {
|
||||||
.run()
|
.run()
|
||||||
.assert_matches_text(concat!(
|
.assert_matches_text(concat!(
|
||||||
"Download http://localhost:4545/echo.ts\n",
|
"Download http://localhost:4545/echo.ts\n",
|
||||||
"Download http://localhost:4260/@denotest/esm-basic\n",
|
"Download http://localhost:4260/@denotest%2fesm-basic\n",
|
||||||
"Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz\n",
|
"Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz\n",
|
||||||
"Hi, there",
|
"Hi, there",
|
||||||
));
|
));
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Add npm:@denotest/esm-basic@1.0.0
|
Add npm:@denotest/esm-basic@1.0.0
|
||||||
Download http://localhost:4260/@denotest/esm-basic
|
Download http://localhost:4260/@denotest%2fesm-basic
|
||||||
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
||||||
Initialize @denotest/esm-basic@1.0.0
|
Initialize @denotest/esm-basic@1.0.0
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
Add npm:@denotest/esm-basic@1.0.0
|
Add npm:@denotest/esm-basic@1.0.0
|
||||||
Download http://localhost:4260/@denotest/esm-basic
|
Download http://localhost:4260/@denotest%2fesm-basic
|
||||||
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
Add npm:@denotest/unstable@1.0.0-beta.1
|
Add npm:@denotest/unstable@1.0.0-beta.1
|
||||||
Download http://localhost:4260/@denotest/unstable
|
Download http://localhost:4260/@denotest%2funstable
|
||||||
Download http://localhost:4260/@denotest/unstable/1.0.0-beta.1.tgz
|
Download http://localhost:4260/@denotest/unstable/1.0.0-beta.1.tgz
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
Add npm:@denotest/esm-basic@1.0.0
|
Add npm:@denotest/esm-basic@1.0.0
|
||||||
Add jsr:@denotest/add@1.0.0
|
Add jsr:@denotest/add@1.0.0
|
||||||
Add npm:@denotest/say-hello@1.0.0
|
Add npm:@denotest/say-hello@1.0.0
|
||||||
Download http://localhost:4260/@denotest/esm-basic
|
Download http://localhost:4260/@denotest%2fesm-basic
|
||||||
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
||||||
Download http://localhost:4260/@denotest/say-hello
|
Download http://localhost:4260/@denotest%2fsay-hello
|
||||||
Download http://localhost:4260/@denotest/say-hello/1.0.0.tgz
|
Download http://localhost:4260/@denotest/say-hello/1.0.0.tgz
|
||||||
Initialize @denotest/esm-basic@1.0.0
|
Initialize @denotest/esm-basic@1.0.0
|
||||||
Initialize @denotest/say-hello@1.0.0
|
Initialize @denotest/say-hello@1.0.0
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Add npm:@denotest/esm-basic@1.0.0
|
Add npm:@denotest/esm-basic@1.0.0
|
||||||
Download http://localhost:4260/@denotest/esm-basic
|
Download http://localhost:4260/@denotest%2fesm-basic
|
||||||
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
||||||
Initialize @denotest/esm-basic@1.0.0
|
Initialize @denotest/esm-basic@1.0.0
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
Download http://localhost:4260/@denotest/esm-basic
|
Download http://localhost:4260/@denotest%2fesm-basic
|
||||||
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
||||||
Initialize @denotest/esm-basic@1.0.0
|
Initialize @denotest/esm-basic@1.0.0
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
Download http://localhost:4260/@denotest/esm-basic
|
Download http://localhost:4260/@denotest%2fesm-basic
|
||||||
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Download http://localhost:4260/@denotest/cjs-default-export
|
Download http://localhost:4260/@denotest%2fcjs-default-export
|
||||||
Download http://localhost:4260/@denotest/cjs-default-export/1.0.0.tgz
|
Download http://localhost:4260/@denotest/cjs-default-export/1.0.0.tgz
|
||||||
Check file:///[WILDCARD]/main.ts
|
Check file:///[WILDCARD]/main.ts
|
||||||
error: TS2322 [ERROR]: Type 'number' is not assignable to type 'string'.
|
error: TS2322 [ERROR]: Type 'number' is not assignable to type 'string'.
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
Download http://localhost:4260/@denotest/esm-basic
|
Download http://localhost:4260/@denotest%2fesm-basic
|
||||||
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
||||||
Initialize @denotest/esm-basic@1.0.0
|
Initialize @denotest/esm-basic@1.0.0
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Download http://localhost:4260/@denotest/esm-basic
|
Download http://localhost:4260/@denotest%2fesm-basic
|
||||||
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
||||||
Initialize @denotest/esm-basic@1.0.0
|
Initialize @denotest/esm-basic@1.0.0
|
||||||
Check file://[WILDCARD]/main.ts
|
Check file://[WILDCARD]/main.ts
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
Download http://localhost:4260/@denotest/esm-basic
|
Download http://localhost:4260/@denotest%2fesm-basic
|
||||||
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
||||||
Initialize @denotest/esm-basic@1.0.0
|
Initialize @denotest/esm-basic@1.0.0
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
Download http://localhost:4260/@denotest/esm-basic
|
Download http://localhost:4260/@denotest%2fesm-basic
|
||||||
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
||||||
Initialize @denotest/esm-basic@1.0.0
|
Initialize @denotest/esm-basic@1.0.0
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[UNORDERED_START]
|
[UNORDERED_START]
|
||||||
Download http://localhost:4261/@denotest/basic
|
Download http://localhost:4261/@denotest%2fbasic
|
||||||
Download http://localhost:4262/@denotest2/basic
|
Download http://localhost:4262/@denotest2%2fbasic
|
||||||
Download http://localhost:4261/@denotest/basic/1.0.0.tgz
|
Download http://localhost:4261/@denotest/basic/1.0.0.tgz
|
||||||
Download http://localhost:4262/@denotest2/basic/1.0.0.tgz
|
Download http://localhost:4262/@denotest2/basic/1.0.0.tgz
|
||||||
Initialize @denotest2/basic@1.0.0
|
Initialize @denotest2/basic@1.0.0
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
{
|
{
|
||||||
"args": "info preact/debug",
|
"steps": [
|
||||||
"output": "with_import_map.out",
|
{
|
||||||
"exitCode": 0
|
"args": "info preact/debug",
|
||||||
|
"output": "with_import_map.out",
|
||||||
|
"exitCode": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
Download http://localhost:4260/@denotest/esm-basic
|
Download http://localhost:4260/@denotest%2fesm-basic
|
||||||
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
||||||
Initialize @denotest/esm-basic@1.0.0
|
Initialize @denotest/esm-basic@1.0.0
|
||||||
|
|
16
tests/specs/info/workspace_member/__test__.jsonc
Normal file
16
tests/specs/info/workspace_member/__test__.jsonc
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"tests": {
|
||||||
|
"member_folder": {
|
||||||
|
"args": "info --quiet foo",
|
||||||
|
"cwd": "member",
|
||||||
|
"output": "info_workspace_member.out",
|
||||||
|
"exitCode": 0
|
||||||
|
},
|
||||||
|
"member_folder_sub": {
|
||||||
|
"args": "info --quiet foo",
|
||||||
|
"cwd": "member/sub",
|
||||||
|
"output": "info_workspace_member_sub.out",
|
||||||
|
"exitCode": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
tests/specs/info/workspace_member/deno.json
Normal file
3
tests/specs/info/workspace_member/deno.json
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"workspace": ["./member"]
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
local: [WILDCARD]file.ts
|
||||||
|
type: TypeScript
|
||||||
|
dependencies: 0 unique
|
||||||
|
size: [WILDCARD]
|
||||||
|
|
||||||
|
file://[WILDCARD]/member/sub/file.ts ([WILDCARD])
|
|
@ -0,0 +1,6 @@
|
||||||
|
local: [WILDCARD]file.ts
|
||||||
|
type: TypeScript
|
||||||
|
dependencies: 0 unique
|
||||||
|
size: [WILDCARD]
|
||||||
|
|
||||||
|
file://[WILDCARD]/member/sub/file.ts ([WILDCARD])
|
5
tests/specs/info/workspace_member/member/deno.json
Normal file
5
tests/specs/info/workspace_member/member/deno.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"imports": {
|
||||||
|
"foo": "./sub/file.ts"
|
||||||
|
}
|
||||||
|
}
|
1
tests/specs/info/workspace_member/member/sub/file.ts
Normal file
1
tests/specs/info/workspace_member/member/sub/file.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export {};
|
|
@ -1,4 +1,4 @@
|
||||||
Download http://localhost:4260/@denotest/esm-basic
|
Download http://localhost:4260/@denotest%2fesm-basic
|
||||||
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
||||||
✅ Successfully installed deno-test-bin[WILDCARD]
|
✅ Successfully installed deno-test-bin[WILDCARD]
|
||||||
[WILDCARD]
|
[WILDCARD]
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
Add npm:@denotest/esm-basic@1.0.0
|
Add npm:@denotest/esm-basic@1.0.0
|
||||||
Download http://localhost:4260/@denotest/esm-basic
|
Download http://localhost:4260/@denotest%2fesm-basic
|
||||||
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Add npm:@denotest/esm-basic@1.0.0
|
Add npm:@denotest/esm-basic@1.0.0
|
||||||
Download http://localhost:4260/@denotest/esm-basic
|
Download http://localhost:4260/@denotest%2fesm-basic
|
||||||
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
||||||
Initialize @denotest/esm-basic@1.0.0
|
Initialize @denotest/esm-basic@1.0.0
|
||||||
|
|
|
@ -8,7 +8,7 @@ Download http://localhost:4545/subdir/print_hello.ts
|
||||||
Download http://127.0.0.1:4250/@denotest/add/meta.json
|
Download http://127.0.0.1:4250/@denotest/add/meta.json
|
||||||
Download http://127.0.0.1:4250/@denotest/add/1.0.0_meta.json
|
Download http://127.0.0.1:4250/@denotest/add/1.0.0_meta.json
|
||||||
Download http://127.0.0.1:4250/@denotest/add/1.0.0/mod.ts
|
Download http://127.0.0.1:4250/@denotest/add/1.0.0/mod.ts
|
||||||
Download http://localhost:4260/@denotest/esm-basic
|
Download http://localhost:4260/@denotest%2fesm-basic
|
||||||
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
||||||
Download http://127.0.0.1:4250/@std/testing/1.0.0/bdd.ts
|
Download http://127.0.0.1:4250/@std/testing/1.0.0/bdd.ts
|
||||||
Download http://127.0.0.1:4250/@std/testing/1.0.0/types.ts
|
Download http://127.0.0.1:4250/@std/testing/1.0.0/types.ts
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
Download http://localhost:4260/@denotest/esm-basic
|
Download http://localhost:4260/@denotest%2fesm-basic
|
||||||
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
||||||
Initialize @denotest/esm-basic@1.0.0
|
Initialize @denotest/esm-basic@1.0.0
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Add npm:@denotest/esm-basic@1.0.0
|
Add npm:@denotest/esm-basic@1.0.0
|
||||||
Download http://localhost:4260/@denotest/esm-basic
|
Download http://localhost:4260/@denotest%2fesm-basic
|
||||||
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
||||||
Initialize @denotest/esm-basic@1.0.0
|
Initialize @denotest/esm-basic@1.0.0
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Add npm:@denotest/esm-basic@1.0.0
|
Add npm:@denotest/esm-basic@1.0.0
|
||||||
Download http://localhost:4260/@denotest/esm-basic
|
Download http://localhost:4260/@denotest%2fesm-basic
|
||||||
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
||||||
Initialize @denotest/esm-basic@1.0.0
|
Initialize @denotest/esm-basic@1.0.0
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Add npm:@denotest/esm-basic@1.0.0
|
Add npm:@denotest/esm-basic@1.0.0
|
||||||
Download http://localhost:4260/@denotest/esm-basic
|
Download http://localhost:4260/@denotest%2fesm-basic
|
||||||
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
||||||
Initialize @denotest/esm-basic@1.0.0
|
Initialize @denotest/esm-basic@1.0.0
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
Add npm:@denotest/deprecated-package@1.0.0
|
Add npm:@denotest/deprecated-package@1.0.0
|
||||||
Download http://localhost:4260/@denotest/deprecated-package
|
Download http://localhost:4260/@denotest%2fdeprecated-package
|
||||||
Download http://localhost:4260/@denotest/deprecated-package/1.0.0.tgz
|
Download http://localhost:4260/@denotest/deprecated-package/1.0.0.tgz
|
||||||
Initialize @denotest/deprecated-package@1.0.0
|
Initialize @denotest/deprecated-package@1.0.0
|
||||||
Warning The following packages are deprecated:
|
Warning The following packages are deprecated:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[UNORDERED_START]
|
[UNORDERED_START]
|
||||||
Download http://127.0.0.1:4250/@denotest/add/meta.json
|
Download http://127.0.0.1:4250/@denotest/add/meta.json
|
||||||
Download http://localhost:4260/@denotest/esm-basic
|
Download http://localhost:4260/@denotest%2fesm-basic
|
||||||
Download http://127.0.0.1:4250/@denotest/add/1.0.0_meta.json
|
Download http://127.0.0.1:4250/@denotest/add/1.0.0_meta.json
|
||||||
Download http://127.0.0.1:4250/@denotest/add/1.0.0/mod.ts
|
Download http://127.0.0.1:4250/@denotest/add/1.0.0/mod.ts
|
||||||
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[UNORDERED_START]
|
[UNORDERED_START]
|
||||||
Download http://localhost:4260/@denotest/node-lifecycle-scripts
|
Download http://localhost:4260/@denotest%2fnode-lifecycle-scripts
|
||||||
Download http://localhost:4260/@denotest/bin
|
Download http://localhost:4260/@denotest%2fbin
|
||||||
Download http://localhost:4260/@denotest/node-lifecycle-scripts/1.0.0.tgz
|
Download http://localhost:4260/@denotest/node-lifecycle-scripts/1.0.0.tgz
|
||||||
Download http://localhost:4260/@denotest/bin/1.0.0.tgz
|
Download http://localhost:4260/@denotest/bin/1.0.0.tgz
|
||||||
Initialize @denotest/node-lifecycle-scripts@1.0.0
|
Initialize @denotest/node-lifecycle-scripts@1.0.0
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[UNORDERED_START]
|
[UNORDERED_START]
|
||||||
Download http://localhost:4260/@denotest/non-existent-optional-peer
|
Download http://localhost:4260/@denotest%2fnon-existent-optional-peer
|
||||||
Download http://localhost:4260/uWebSockets.js
|
Download http://localhost:4260/uWebSockets.js
|
||||||
Download http://localhost:4260/@denotest/non-existent-optional-peer/1.0.0.tgz
|
Download http://localhost:4260/@denotest/non-existent-optional-peer/1.0.0.tgz
|
||||||
[UNORDERED_END]
|
[UNORDERED_END]
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
Download http://localhost:4260/@denotest/esm-basic
|
Download http://localhost:4260/@denotest%2fesm-basic
|
||||||
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
||||||
Initialize @denotest/esm-basic@1.0.0
|
Initialize @denotest/esm-basic@1.0.0
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Download http://localhost:4260/@denotest/subtract
|
Download http://localhost:4260/@denotest%2fsubtract
|
||||||
error: Uncaught (in promise) TypeError: The lockfile is out of date. Run `deno install --frozen=false`, or rerun with `--frozen=false` to update it.
|
error: Uncaught (in promise) TypeError: The lockfile is out of date. Run `deno install --frozen=false`, or rerun with `--frozen=false` to update it.
|
||||||
changes:
|
changes:
|
||||||
4 | - "npm:@denotest/add@1": "1.0.0"
|
4 | - "npm:@denotest/add@1": "1.0.0"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Download http://localhost:4260/@denotest/subtract
|
Download http://localhost:4260/@denotest%2fsubtract
|
||||||
error: The lockfile is out of date. Run `deno install --frozen=false`, or rerun with `--frozen=false` to update it.
|
error: The lockfile is out of date. Run `deno install --frozen=false`, or rerun with `--frozen=false` to update it.
|
||||||
changes:
|
changes:
|
||||||
4 | - "npm:@denotest/add@1": "1.0.0"
|
4 | - "npm:@denotest/add@1": "1.0.0"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Download http://localhost:4260/@denotest/bin
|
Download http://localhost:4260/@denotest%2fbin
|
||||||
error: The lockfile is out of date. Run `deno install --frozen=false`, or rerun with `--frozen=false` to update it.
|
error: The lockfile is out of date. Run `deno install --frozen=false`, or rerun with `--frozen=false` to update it.
|
||||||
changes:
|
changes:
|
||||||
4 | - "npm:@denotest/add@1": "1.0.0"
|
4 | - "npm:@denotest/add@1": "1.0.0"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Download http://localhost:4260/@denotest/add
|
Download http://localhost:4260/@denotest%2fadd
|
||||||
error: The lockfile is out of date. Run `deno install --frozen=false`, or rerun with `--frozen=false` to update it.
|
error: The lockfile is out of date. Run `deno install --frozen=false`, or rerun with `--frozen=false` to update it.
|
||||||
changes:
|
changes:
|
||||||
1 | -
|
1 | -
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
Download http://localhost:4260/@denotest/esm-basic
|
Download http://localhost:4260/@denotest%2fesm-basic
|
||||||
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz
|
||||||
Initialize @denotest/esm-basic@1.0.0
|
Initialize @denotest/esm-basic@1.0.0
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Download http://localhost:4260/@denotest/cjs-reexport-same-specifier-in-sub-folder
|
Download http://localhost:4260/@denotest%2fcjs-reexport-same-specifier-in-sub-folder
|
||||||
Download http://localhost:4260/@denotest/cjs-reexport-same-specifier-in-sub-folder/1.0.0.tgz
|
Download http://localhost:4260/@denotest/cjs-reexport-same-specifier-in-sub-folder/1.0.0.tgz
|
||||||
[Module: null prototype] {
|
[Module: null prototype] {
|
||||||
default: { main: [Getter], sub: [Getter] },
|
default: { main: [Getter], sub: [Getter] },
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
Download http://localhost:4260/@denotest/add
|
Download http://localhost:4260/@denotest%2fadd
|
||||||
Download http://localhost:4260/@denotest/add/1.0.0.tgz
|
Download http://localhost:4260/@denotest/add/1.0.0.tgz
|
||||||
Initialize @denotest/add@1.0.0
|
Initialize @denotest/add@1.0.0
|
||||||
3
|
3
|
||||||
Download http://localhost:4260/@denotest/subtract
|
Download http://localhost:4260/@denotest%2fsubtract
|
||||||
Download http://localhost:4260/@denotest/subtract/1.0.0.tgz
|
Download http://localhost:4260/@denotest/subtract/1.0.0.tgz
|
||||||
Initialize @denotest/subtract@1.0.0
|
Initialize @denotest/subtract@1.0.0
|
||||||
1
|
1
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[UNORDERED_START]
|
[UNORDERED_START]
|
||||||
Download http://localhost:4260/@denotest/transitive-bin
|
Download http://localhost:4260/@denotest%2ftransitive-bin
|
||||||
Download http://localhost:4260/@denotest/bin
|
Download http://localhost:4260/@denotest%2fbin
|
||||||
Download http://localhost:4260/@denotest/bin/1.0.0.tgz
|
Download http://localhost:4260/@denotest/bin/1.0.0.tgz
|
||||||
Download http://localhost:4260/@denotest/transitive-bin/1.0.0.tgz
|
Download http://localhost:4260/@denotest/transitive-bin/1.0.0.tgz
|
||||||
Download http://localhost:4260/@denotest/bin/0.7.0.tgz
|
Download http://localhost:4260/@denotest/bin/0.7.0.tgz
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Download http://localhost:4260/@denotest/check-error
|
Download http://localhost:4260/@denotest%2fcheck-error
|
||||||
Download http://localhost:4260/@denotest/check-error/1.0.0.tgz
|
Download http://localhost:4260/@denotest/check-error/1.0.0.tgz
|
||||||
Check file:///[WILDCARD]/check_errors/main.ts
|
Check file:///[WILDCARD]/check_errors/main.ts
|
||||||
error: TS2506 [ERROR]: 'Class1' is referenced directly or indirectly in its own base expression.
|
error: TS2506 [ERROR]: 'Class1' is referenced directly or indirectly in its own base expression.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Download http://localhost:4260/@denotest/check-error
|
Download http://localhost:4260/@denotest%2fcheck-error
|
||||||
Download http://localhost:4260/@denotest/check-error/1.0.0.tgz
|
Download http://localhost:4260/@denotest/check-error/1.0.0.tgz
|
||||||
Check file:///[WILDCARD]/check_errors/main.ts
|
Check file:///[WILDCARD]/check_errors/main.ts
|
||||||
error: TS2339 [ERROR]: Property 'Asdf' does not exist on type 'typeof import("file:///[WILDCARD]/@denotest/check-error/1.0.0/index.d.ts")'.
|
error: TS2339 [ERROR]: Property 'Asdf' does not exist on type 'typeof import("file:///[WILDCARD]/@denotest/check-error/1.0.0/index.d.ts")'.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Download http://localhost:4260/@denotest/check-error
|
Download http://localhost:4260/@denotest%2fcheck-error
|
||||||
Download http://localhost:4260/@denotest/check-error/1.0.0.tgz
|
Download http://localhost:4260/@denotest/check-error/1.0.0.tgz
|
||||||
Check file:///[WILDCARD]/check_errors/main.ts
|
Check file:///[WILDCARD]/check_errors/main.ts
|
||||||
error: TS2506 [ERROR]: 'Class1' is referenced directly or indirectly in its own base expression.
|
error: TS2506 [ERROR]: 'Class1' is referenced directly or indirectly in its own base expression.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Download http://localhost:4260/@denotest/check-error
|
Download http://localhost:4260/@denotest%2fcheck-error
|
||||||
Download http://localhost:4260/@denotest/check-error/1.0.0.tgz
|
Download http://localhost:4260/@denotest/check-error/1.0.0.tgz
|
||||||
Check file:///[WILDCARD]/check_errors/main.ts
|
Check file:///[WILDCARD]/check_errors/main.ts
|
||||||
error: TS2339 [ERROR]: Property 'Asdf' does not exist on type 'typeof import("file:///[WILDCARD]/@denotest/check-error/1.0.0/index.d.ts")'.
|
error: TS2339 [ERROR]: Property 'Asdf' does not exist on type 'typeof import("file:///[WILDCARD]/@denotest/check-error/1.0.0/index.d.ts")'.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Download http://localhost:4260/@denotest/file-dts-dmts-dcts
|
Download http://localhost:4260/@denotest%2ffile-dts-dmts-dcts
|
||||||
Download http://localhost:4260/@denotest/file-dts-dmts-dcts/1.0.0.tgz
|
Download http://localhost:4260/@denotest/file-dts-dmts-dcts/1.0.0.tgz
|
||||||
Check file:///[WILDCARD]/main.ts
|
Check file:///[WILDCARD]/main.ts
|
||||||
error: TS2322 [ERROR]: Type '5' is not assignable to type '"dts"'.
|
error: TS2322 [ERROR]: Type '5' is not assignable to type '"dts"'.
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue