Skip to content

Commit

Permalink
Remove require('crypto') imports in browser client (#721)
Browse files Browse the repository at this point in the history
  • Loading branch information
jaclarke authored Aug 23, 2023
1 parent 4b01e37 commit 1db40b8
Show file tree
Hide file tree
Showing 14 changed files with 444 additions and 384 deletions.
18 changes: 7 additions & 11 deletions compileForDeno.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,17 +135,13 @@ export async function run({

let resolvedImportPath = resolveImportPath(importPath, sourcePath);

if (resolvedImportPath.endsWith("/adapter.node.ts")) {
resolvedImportPath = resolvedImportPath.replace(
"/adapter.node.ts",
"/adapter.deno.ts"
);
}
if (resolvedImportPath.endsWith("/adapter.shared.node.ts")) {
resolvedImportPath = resolvedImportPath.replace(
"/adapter.shared.node.ts",
"/adapter.shared.deno.ts"
);
for (const name of ["adapter", "adapter.shared", "adapter.crypto"]) {
if (resolvedImportPath.endsWith(`/${name}.node.ts`)) {
resolvedImportPath = resolvedImportPath.replace(
`/${name}.node.ts`,
`/${name}.deno.ts`
);
}
}

rewrittenFile.push(resolvedImportPath);
Expand Down
35 changes: 35 additions & 0 deletions packages/driver/src/adapter.crypto.deno.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { crypto } from "https://deno.land/[email protected]/crypto/mod.ts";

import type { CryptoUtils } from "./utils.ts";

const cryptoUtils: CryptoUtils = {
async randomBytes(size: number): Promise<Uint8Array> {
const buf = new Uint8Array(size);
return crypto.getRandomValues(buf);
},

async H(msg: Uint8Array): Promise<Uint8Array> {
return new Uint8Array(await crypto.subtle.digest("SHA-256", msg));
},

async HMAC(key: Uint8Array, msg: Uint8Array): Promise<Uint8Array> {
return new Uint8Array(
await crypto.subtle.sign(
"HMAC",
await crypto.subtle.importKey(
"raw",
key,
{
name: "HMAC",
hash: { name: "SHA-256" },
},
false,
["sign"]
),
msg
)
);
},
};

export default cryptoUtils;
39 changes: 39 additions & 0 deletions packages/driver/src/adapter.crypto.node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import type { CryptoUtils } from "./utils";

let cryptoUtils: CryptoUtils;

if (typeof crypto === "undefined") {
// tslint:disable-next-line:no-var-requires
const nodeCrypto = require("crypto");

cryptoUtils = {
randomBytes(size: number): Promise<Uint8Array> {
return new Promise((resolve, reject) => {
nodeCrypto.randomBytes(size, (err: Error | null, buf: Buffer) => {
if (err) {
reject(err);
} else {
resolve(buf);
}
});
});
},

async H(msg: Uint8Array): Promise<Uint8Array> {
const sign = nodeCrypto.createHash("sha256");
sign.update(msg);
return sign.digest();
},

async HMAC(key: Uint8Array, msg: Uint8Array): Promise<Uint8Array> {
const hm = nodeCrypto.createHmac("sha256", key);
hm.update(msg);
return hm.digest();
},
};
} else {
// tslint:disable-next-line:no-var-requires
cryptoUtils = require("./browserCrypto").default;
}

export default cryptoUtils;
33 changes: 0 additions & 33 deletions packages/driver/src/adapter.shared.deno.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,3 @@
import { crypto } from "https://deno.land/[email protected]/crypto/mod.ts";

export async function randomBytes(size: number): Promise<Uint8Array> {
const buf = new Uint8Array(size);
return crypto.getRandomValues(buf);
}

export async function H(msg: Uint8Array): Promise<Uint8Array> {
return new Uint8Array(await crypto.subtle.digest("SHA-256", msg));
}

export async function HMAC(
key: Uint8Array,
msg: Uint8Array
): Promise<Uint8Array> {
return new Uint8Array(
await crypto.subtle.sign(
"HMAC",
await crypto.subtle.importKey(
"raw",
key,
{
name: "HMAC",
hash: { name: "SHA-256" },
},
false,
["sign"]
),
msg
)
);
}

export function getEnv(envName: string, required = false): string | undefined {
if (!required) {
const state = Deno.permissions.querySync({
Expand Down
62 changes: 0 additions & 62 deletions packages/driver/src/adapter.shared.node.ts
Original file line number Diff line number Diff line change
@@ -1,65 +1,3 @@
let randomBytes: (size: number) => Promise<Uint8Array>;
let H: (msg: Uint8Array) => Promise<Uint8Array>;
let HMAC: (key: Uint8Array, msg: Uint8Array) => Promise<Uint8Array>;

if (typeof crypto === "undefined") {
// tslint:disable-next-line:no-var-requires
const nodeCrypto = require("crypto");

randomBytes = (size: number): Promise<Uint8Array> => {
return new Promise((resolve, reject) => {
nodeCrypto.randomBytes(size, (err: Error | null, buf: Buffer) => {
if (err) {
reject(err);
} else {
resolve(buf);
}
});
});
};

H = async (msg: Uint8Array): Promise<Uint8Array> => {
const sign = nodeCrypto.createHash("sha256");
sign.update(msg);
return sign.digest();
};

HMAC = async (key: Uint8Array, msg: Uint8Array): Promise<Uint8Array> => {
const hm = nodeCrypto.createHmac("sha256", key);
hm.update(msg);
return hm.digest();
};
} else {
randomBytes = async (size: number): Promise<Uint8Array> => {
return crypto.getRandomValues(new Uint8Array(size));
};

H = async (msg: Uint8Array): Promise<Uint8Array> => {
return new Uint8Array(await crypto.subtle.digest("SHA-256", msg));
};

HMAC = async (key: Uint8Array, msg: Uint8Array): Promise<Uint8Array> => {
return new Uint8Array(
await crypto.subtle.sign(
"HMAC",
await crypto.subtle.importKey(
"raw",
key,
{
name: "HMAC",
hash: { name: "SHA-256" },
},
false,
["sign"]
),
msg
)
);
};
}

export { randomBytes, H, HMAC };

export function getEnv(
envName: string,
required: boolean = false
Expand Down
7 changes: 5 additions & 2 deletions packages/driver/src/browserClient.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { BaseClientPool, Client, ConnectOptions } from "./baseClient";
import { getConnectArgumentsParser } from "./conUtils";
import cryptoUtils from "./browserCrypto";
import { EdgeDBError } from "./errors";
import { FetchConnection } from "./fetchConn";
import { getHTTPSCRAMAuth } from "./httpScram";
import { Options } from "./options";

const parseConnectArguments = getConnectArgumentsParser(null);
const httpSCRAMAuth = getHTTPSCRAMAuth(cryptoUtils);

export class FetchClientPool extends BaseClientPool {
class FetchClientPool extends BaseClientPool {
isStateless = true;
_connectWithTimeout = FetchConnection.connectWithTimeout;
_connectWithTimeout = FetchConnection.createConnectWithTimeout(httpSCRAMAuth);
}

export function createClient(): Client {
Expand Down
32 changes: 32 additions & 0 deletions packages/driver/src/browserCrypto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import type { CryptoUtils } from "./utils";

const cryptoUtils: CryptoUtils = {
async randomBytes(size: number): Promise<Uint8Array> {
return crypto.getRandomValues(new Uint8Array(size));
},

async H(msg: Uint8Array): Promise<Uint8Array> {
return new Uint8Array(await crypto.subtle.digest("SHA-256", msg));
},

async HMAC(key: Uint8Array, msg: Uint8Array): Promise<Uint8Array> {
return new Uint8Array(
await crypto.subtle.sign(
"HMAC",
await crypto.subtle.importKey(
"raw",
key,
{
name: "HMAC",
hash: { name: "SHA-256" },
},
false,
["sign"]
),
msg
)
);
},
};

export default cryptoUtils;
64 changes: 33 additions & 31 deletions packages/driver/src/fetchConn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { PROTO_VER, BaseRawConnection } from "./baseConn";
import Event from "./primitives/event";
import * as chars from "./primitives/chars";
import { InternalClientError, ProtocolError } from "./errors";
import { HTTPSCRAMAuth } from "./httpScram";
import type { HttpSCRAMAuth } from "./httpScram";

interface FetchConfig {
address: Address | string;
Expand Down Expand Up @@ -177,38 +177,40 @@ export class FetchConnection extends BaseFetchConnection {
return `${baseUrl}/db/${database}`;
}

static async connectWithTimeout(
addr: Address,
config: NormalizedConnectConfig,
registry: CodecsRegistry
): Promise<FetchConnection> {
const {
connectionParams: { tlsSecurity, user, password = "", secretKey },
} = config;

let token = secretKey ?? _tokens.get(config);

if (!token) {
const protocol = tlsSecurity === "insecure" ? "http" : "https";
const baseUrl = `${protocol}://${addr[0]}:${addr[1]}`;
token = await HTTPSCRAMAuth(baseUrl, user, password);
_tokens.set(config, token);
}
static createConnectWithTimeout(httpSCRAMAuth: HttpSCRAMAuth) {
return async function connectWithTimeout(
addr: Address,
config: NormalizedConnectConfig,
registry: CodecsRegistry
) {
const {
connectionParams: { tlsSecurity, user, password = "", secretKey },
} = config;

let token = secretKey ?? _tokens.get(config);

if (!token) {
const protocol = tlsSecurity === "insecure" ? "http" : "https";
const baseUrl = `${protocol}://${addr[0]}:${addr[1]}`;
token = await httpSCRAMAuth(baseUrl, user, password);
_tokens.set(config, token);
}

const conn = new FetchConnection(
{
address: addr,
tlsSecurity,
database: config.connectionParams.database,
user: config.connectionParams.user,
token,
},
registry
);
const conn = new FetchConnection(
{
address: addr,
tlsSecurity,
database: config.connectionParams.database,
user: config.connectionParams.user,
token,
},
registry
);

conn.connected = true;
conn.connWaiter.set();
conn.connected = true;
conn.connWaiter.set();

return conn;
return conn;
};
}
}
Loading

0 comments on commit 1db40b8

Please sign in to comment.