Skip to content

Commit

Permalink
Introduce WebCrypto API
Browse files Browse the repository at this point in the history
  • Loading branch information
yacinehmito committed Feb 20, 2021
1 parent 4f80587 commit 9bbde5a
Show file tree
Hide file tree
Showing 11 changed files with 735 additions and 24 deletions.
5 changes: 5 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ deno_core = { path = "../core", version = "0.79.0" }
deno_fetch = { path = "../op_crates/fetch", version = "0.22.0" }
deno_web = { path = "../op_crates/web", version = "0.30.0" }
deno_websocket = { path = "../op_crates/websocket", version = "0.5.0" }
deno_crypto = { path = "../op_crates/crypto", version = "0.13.0" }
regex = "1.4.3"
serde = { version = "1.0.123", features = ["derive"] }

Expand Down
5 changes: 5 additions & 0 deletions cli/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ fn create_compiler_snapshot(
op_crate_libs.insert("deno.web", deno_web::get_declaration());
op_crate_libs.insert("deno.fetch", deno_fetch::get_declaration());
op_crate_libs.insert("deno.websocket", deno_websocket::get_declaration());
op_crate_libs.insert("deno.crypto", deno_crypto::get_declaration());

// ensure we invalidate the build properly.
for (_, path) in op_crate_libs.iter() {
Expand Down Expand Up @@ -259,6 +260,10 @@ fn main() {
"cargo:rustc-env=DENO_WEBSOCKET_LIB_PATH={}",
deno_websocket::get_declaration().display()
);
println!(
"cargo:rustc-env=DENO_CRYPTO_LIB_PATH={}",
deno_crypto::get_declaration().display()
);

println!("cargo:rustc-env=TARGET={}", env::var("TARGET").unwrap());
println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap());
Expand Down
21 changes: 1 addition & 20 deletions cli/dts/lib.deno.shared_globals.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
/// <reference lib="deno.web" />
/// <reference lib="deno.fetch" />
/// <reference lib="deno.websocket" />
/// <reference lib="deno.crypto" />

declare namespace WebAssembly {
/**
Expand Down Expand Up @@ -416,26 +417,6 @@ declare interface Console {

declare var console: Console;

declare interface Crypto {
readonly subtle: null;
getRandomValues<
T extends
| Int8Array
| Int16Array
| Int32Array
| Uint8Array
| Uint16Array
| Uint32Array
| Uint8ClampedArray
| Float32Array
| Float64Array
| DataView
| null,
>(
array: T,
): T;
}

interface MessageEventInit<T = any> extends EventInit {
data?: T;
origin?: string;
Expand Down
3 changes: 2 additions & 1 deletion cli/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,11 +280,12 @@ fn print_cache_info(

fn get_types(unstable: bool) -> String {
let mut types = format!(
"{}\n{}\n{}\n{}\n{}\n{}",
"{}\n{}\n{}\n{}\n{}\n{}\n{}",
crate::tsc::DENO_NS_LIB,
crate::tsc::DENO_WEB_LIB,
crate::tsc::DENO_FETCH_LIB,
crate::tsc::DENO_WEBSOCKET_LIB,
crate::tsc::DENO_CRYPTO_LIB,
crate::tsc::SHARED_GLOBALS_LIB,
crate::tsc::WINDOW_LIB,
);
Expand Down
1 change: 1 addition & 0 deletions cli/tsc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub static DENO_WEB_LIB: &str = include_str!(env!("DENO_WEB_LIB_PATH"));
pub static DENO_FETCH_LIB: &str = include_str!(env!("DENO_FETCH_LIB_PATH"));
pub static DENO_WEBSOCKET_LIB: &str =
include_str!(env!("DENO_WEBSOCKET_LIB_PATH"));
pub static DENO_CRYPTO_LIB: &str = include_str!(env!("DENO_CRYPTO_LIB_PATH"));
pub static SHARED_GLOBALS_LIB: &str =
include_str!("dts/lib.deno.shared_globals.d.ts");
pub static WINDOW_LIB: &str = include_str!("dts/lib.deno.window.d.ts");
Expand Down
136 changes: 136 additions & 0 deletions op_crates/crypto/01_crypto.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
"use strict";

// Implements https://www.w3.org/TR/WebCryptoAPI

((window) => {
const core = window.Deno.core;

Expand Down Expand Up @@ -41,11 +43,145 @@
return arrayBufferView;
}

// Algorithm normalization, which involves storing the expected data for
// each pair of algorithm and crypto operation, is done on the JS side because
// it is convenient.
// Shall it stay that way, or are we better to move it on the Rust side?

// We need this method after initialization, anytime we need to normalize
// a provided algorithm. We store it here to prevent prototype pollution.
const toUpperCase = String.prototype.toUpperCase;

class RegisteredAlgorithmsContainer {
#nameIndex;
#definitions;

constructor(definitions) {
this.#nameIndex = Object.create(null);
this.#definitions = Object.create(null);
for (const [name, definition] of Object.entries(definitions)) {
this.#nameIndex[name.toUpperCase()] = name;
this.#definitions[name] = definition;
}
}

/**
* A definition is an object whose keys are the keys that the input must
* have and whose values are validation functions for the associate value.
* The validation function will either return the value if it valid, or
* throw an error that must be forwarded.
*/
getDefinition(name) {
return this.#definitions[name];
}

normalizeName(providedName) {
const upperCaseName = toUpperCase.call(providedName);
return this.#nameIndex[upperCaseName];
}
}

const supportedAlgorithms = {};

function normalizeAlgorithm(algorithm, registeredAlgorithms) {
let alg;
if (typeof algorithm === "string") {
alg = { name: algorithm };
} else if (typeof algorithm === "object" && algorithm !== null) {
if (typeof algorithm.name !== "string") {
throw new TypeError("Algorithm name is missing or not a string");
}
alg = { ...algorithm };
} else {
throw new TypeError("Argument 1 must be an object or a string");
}
const algorithmName = registeredAlgorithms.normalizeName(alg.name);
if (algorithmName === undefined) {
throw new DOMException(
"Unrecognized algorithm name",
"NotSupportedError",
);
}
const definition = registeredAlgorithms.getDefinition(algorithmName);
for (const [propertyName, validate] of Object.entries(definition)) {
alg[propertyName] = validate(algorithm[propertyName]);
}
alg.name = algorithmName;
return alg;
}

const subtle = {
async decrypt(algorithm, key, data) {
await Promise.resolve();
throw new Error("Not implemented");
},
async deriveBits(algorithm, baseKey, length) {
await Promise.resolve();
throw new Error("Not implemented");
},
async deriveKey(
algorithm,
baseKey,
derivedKeyType,
extractable,
keyUsages,
) {
await Promise.resolve();
throw new Error("Not implemented");
},
async digest(algorithm, data) {
await Promise.resolve();
throw new Error("Not implemented");
},
async encrypt(algorithm, key, data) {
await Promise.resolve();
throw new Error("Not implemented");
},
async exportKey(format, key) {
await Promise.resolve();
throw new Error("Not implemented");
},
async generateKey(algorithm, extractable, keyUsages) {
await Promise.resolve();
throw new Error("Not implemented");
},
async importKey(format, keyData, algorithm, extractable, keyUsages) {
await Promise.resolve();
throw new Error("Not implemented");
},
async sign(algorithm, key, data) {
await Promise.resolve();
throw new Error("Not implemented");
},
async unwrapKey(
format,
wrappedKey,
unwrappingKey,
unwrapAlgorithm,
unwrappedKeyAlgorithm,
extractable,
keyUsages,
) {
await Promise.resolve();
throw new Error("Not implemented");
},
async verify(algorithm, key, signature, data) {
await Promise.resolve();
throw new Error("Not implemented");
},
async wrapKey(format, key, wrappingKey, wrapAlgorithm) {
await Promise.resolve();
throw new Error("Not implemented");
},
};

window.crypto = {
getRandomValues,
subtle,
};
window.__bootstrap = window.__bootstrap || {};
window.__bootstrap.crypto = {
getRandomValues,
subtle,
};
})(this);
5 changes: 4 additions & 1 deletion op_crates/crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,7 @@ path = "lib.rs"
[dependencies]
deno_core = { version = "0.79.0", path = "../../core" }
rand = "0.8.3"

ring = "0.16.19"
tokio = { version = "1.1.1", features = ["full"] }
serde_json = { version = "1.0.62", features = ["preserve_order"] }
serde = { version = "1.0.123", features = ["derive"] }
Loading

0 comments on commit 9bbde5a

Please sign in to comment.