Skip to content

Commit

Permalink
feat: Add JSR support (#409)
Browse files Browse the repository at this point in the history
* handle import changes

Signed-off-by: Jersey <wgyt735yt@gmail.com>

* fix most errors

Signed-off-by: Jersey <wgyt735yt@gmail.com>

* web_bson is on jsr now!

Signed-off-by: Jersey <wgyt735yt@gmail.com>

* make the document type the right one so that things dont combust

Signed-off-by: Jersey <wgyt735yt@gmail.com>

* turns out the scope is DB

Signed-off-by: Jersey <wgyt735yt@gmail.com>

* include our own document type and re-export less

Signed-off-by: Jersey <wgyt735yt@gmail.com>

* fix lint

Signed-off-by: Jersey <wgyt735yt@gmail.com>

* d o c s

Signed-off-by: Jersey <wgyt735yt@gmail.com>

* whoops

Signed-off-by: Jersey <wgyt735yt@gmail.com>

* turns out i forgot to update the test

Signed-off-by: Jersey <wgyt735yt@gmail.com>

* make readme show on jsr side

* alphabetically sort stuff

Signed-off-by: Jersey <wgyt735yt@gmail.com>

* fix mentioned issues

Signed-off-by: Jersey <wgyt735yt@gmail.com>

* empty commit to run tests again, they're flaky

Signed-off-by: Jersey <wgyt735yt@gmail.com>

* turns out i forgot to add a few things back

Signed-off-by: Jersey <wgyt735yt@gmail.com>

* whoops i forgot to remove an unused dep

---------

Signed-off-by: Jersey <wgyt735yt@gmail.com>
  • Loading branch information
williamhorning committed Mar 23, 2024
1 parent 5356b71 commit 749d804
Show file tree
Hide file tree
Showing 42 changed files with 418 additions and 178 deletions.
20 changes: 20 additions & 0 deletions deno.json
@@ -0,0 +1,20 @@
{
"name": "@db/mongo",
"version": "0.33.0",
"exports": {
".": "./mod.ts",
"./client": "./src/client.ts",
"./collection": "./src/collection/collection.ts",
"./gridfs": "./src/gridfs/bucket.ts",
"./types": "./src/types.ts"
},
"publish": {
"exclude": [".github", "tests", ".gitattributes", ".gitignore", "deno.lock"]
},
"test": {
"include": [
"tests/cases/*.ts"
]
},
"lock": false
}
28 changes: 22 additions & 6 deletions deps.ts
@@ -1,6 +1,22 @@
export * from "https://deno.land/x/web_bson@v0.3.0/mod.js";
export { writeAll } from "https://deno.land/std@0.209.0/streams/write_all.ts";
export { crypto } from "https://deno.land/std@0.209.0/crypto/mod.ts";
export { BufReader } from "https://deno.land/std@0.209.0/io/mod.ts";
export * as b64 from "https://deno.land/std@0.209.0/encoding/base64.ts";
export * as hex from "https://deno.land/std@0.209.0/encoding/hex.ts";
export {
Binary,
BSONRegExp,
BSONSymbol,
Code,
DBRef,
Decimal128,
deserialize,
Double,
Int32,
Long,
MaxKey,
MinKey,
ObjectId,
serialize,
Timestamp,
UUID,
} from "jsr:@lucsoft/web-bson@^0.3.1";
export { crypto as stdCrypto } from "jsr:@std/crypto@^0.220.1/crypto";
export { decodeBase64, encodeBase64 } from "jsr:@std/encoding@^0.220.1/base64";
export { encodeHex } from "jsr:@std/encoding@^0.220.1/hex";
export { BufReader, writeAll } from "jsr:@std/io@^0.220.1";
10 changes: 4 additions & 6 deletions mod.ts
@@ -1,8 +1,3 @@
export { MongoClient } from "./src/client.ts";
export { Database } from "./src/database.ts";
export { Collection } from "./src/collection/mod.ts";
export * from "./src/types.ts";
export * as Bson from "./deps.ts";
export {
Binary,
BSONRegExp,
Expand All @@ -19,5 +14,8 @@ export {
Timestamp,
UUID,
} from "./deps.ts";
export type { Document } from "./deps.ts";
export { MongoClient } from "./src/client.ts";
export { Collection } from "./src/collection/mod.ts";
export { Database } from "./src/database.ts";
export { GridFSBucket } from "./src/gridfs/bucket.ts";
export * from "./src/types.ts";
12 changes: 4 additions & 8 deletions src/auth/base.ts
@@ -1,15 +1,11 @@
import { ConnectOptions, Credential } from "../types.ts";
import { WireProtocol } from "../protocol/mod.ts";
import { Document } from "../../deps.ts";
import { ConnectOptions, Credential, Document } from "../types.ts";

export abstract class AuthPlugin {
abstract prepare(
authContext: AuthContext,
): Document;
abstract auth(
authContext: AuthContext,
): Document;
abstract auth(authContext: AuthContext): Document;
abstract prepare(authContext: AuthContext): Document;
}

/** Context used during authentication */
export class AuthContext {
/** The connection to authenticate */
Expand Down
28 changes: 17 additions & 11 deletions src/auth/scram.ts
@@ -1,10 +1,16 @@
import { Credential } from "../types.ts";
import { saslprep } from "../utils/saslprep/mod.ts";
import { AuthContext, AuthPlugin } from "./base.ts";
import { HandshakeDocument } from "../protocol/handshake.ts";
import {
Binary,
decodeBase64,
encodeBase64,
encodeHex,
stdCrypto,
} from "../../deps.ts";
import { MongoDriverError } from "../error.ts";
import { b64, Binary, crypto as stdCrypto, Document, hex } from "../../deps.ts";
import { HandshakeDocument } from "../protocol/handshake.ts";
import { driverMetadata } from "../protocol/mod.ts";
import { Credential, Document } from "../types.ts";
import { saslprep } from "../utils/saslprep/mod.ts";
import { AuthContext, AuthPlugin } from "./base.ts";
import { pbkdf2 } from "./pbkdf2.ts";

type CryptoMethod = "sha1" | "sha256";
Expand Down Expand Up @@ -65,7 +71,7 @@ export function clientFirstMessageBare(username: string, nonce: Uint8Array) {
...enc.encode("n="),
...enc.encode(username),
...enc.encode(",r="),
...enc.encode(b64.encodeBase64(nonce)),
...enc.encode(encodeBase64(nonce)),
],
);
}
Expand Down Expand Up @@ -160,7 +166,7 @@ export async function continueScramConversation(
const withoutProof = `c=biws,r=${rnonce}`;
const saltedPassword = await HI(
processedPassword,
b64.decodeBase64(salt),
decodeBase64(salt),
iterations,
cryptoMethod,
);
Expand Down Expand Up @@ -193,7 +199,7 @@ export async function continueScramConversation(
);
if (
!compareDigest(
b64.decodeBase64(parsedResponse.v),
decodeBase64(parsedResponse.v),
new Uint8Array(serverSignature),
)
) {
Expand Down Expand Up @@ -260,7 +266,7 @@ export async function passwordDigest(
"MD5",
enc.encode(`${username}:mongo:${password}`),
);
return hex.encodeHex(new Uint8Array(result));
return encodeHex(new Uint8Array(result));
}

// XOR two buffers
Expand All @@ -275,7 +281,7 @@ export function xor(_a: ArrayBuffer, _b: ArrayBuffer) {
res[i] = a[i] ^ b[i];
}

return b64.encodeBase64(res);
return encodeBase64(res);
}

export function H(method: CryptoMethod, text: BufferSource) {
Expand Down Expand Up @@ -333,7 +339,7 @@ export async function HI(
cryptoMethod: CryptoMethod,
): Promise<ArrayBuffer> {
// omit the work if already generated
const key = [data, b64.encodeBase64(salt), iterations].join(
const key = [data, encodeBase64(salt), iterations].join(
"_",
);
if (_hiCache[key] !== undefined) {
Expand Down
5 changes: 2 additions & 3 deletions src/auth/x509.ts
@@ -1,8 +1,7 @@
import { Credential } from "../types.ts";
import { AuthContext, AuthPlugin } from "./base.ts";
import { HandshakeDocument } from "../protocol/handshake.ts";
import { driverMetadata } from "../protocol/mod.ts";
import { Document } from "../../deps.ts";
import { Credential, Document } from "../types.ts";
import { AuthContext, AuthPlugin } from "./base.ts";

export interface X509Command extends Document {
authenticate: number;
Expand Down
40 changes: 33 additions & 7 deletions src/client.ts
@@ -1,20 +1,32 @@
import { Cluster } from "./cluster.ts";
import { Database } from "./database.ts";
import { BuildInfo, ConnectOptions, ListDatabaseInfo } from "./types.ts";
import { parse } from "./utils/uri.ts";
import { MongoDriverError } from "./error.ts";
import { Cluster } from "./cluster.ts";
import { Document } from "../deps.ts";
import {
BuildInfo,
ConnectOptions,
Document,
ListDatabaseInfo,
} from "./types.ts";
import { parse } from "./utils/uri.ts";

/**
* A client that allows you to interact with a MongoDB Server
* @module
*/

/** A client that allows you to interact with a MongoDB Server */
export class MongoClient {
#cluster?: Cluster;
#defaultDbName = "admin";
#buildInfo?: BuildInfo;

get buildInfo() {
/** Get information about your server's build */
get buildInfo(): BuildInfo | undefined {
return this.#buildInfo;
}

getCluster() {
/** Get the cluster associated with the client */
getCluster(): Cluster {
if (!this.#cluster) {
throw new MongoDriverError(
"MongoClient is not connected to the Database",
Expand All @@ -24,6 +36,11 @@ export class MongoClient {
return this.#cluster;
}

/**
* Connect to the given MongoDB server
*
* @param options Connection options or a MongoDB URI
*/
async connect(
options: ConnectOptions | string,
): Promise<Database> {
Expand All @@ -48,6 +65,12 @@ export class MongoClient {
return this.database((options as ConnectOptions).db);
}

/**
* List all databases on the connected server
*
* @param options Options to pass to the `listDatabases` command
* @returns A list of databases including their name, size on disk, and whether they are empty
*/
async listDatabases(options: {
filter?: Document;
nameOnly?: boolean;
Expand All @@ -64,15 +87,18 @@ export class MongoClient {
return databases;
}

/** Run a command on the connected server */
// deno-lint-ignore no-explicit-any
runCommand<T = any>(db: string, body: Document): Promise<T> {
return this.getCluster().protocol.commandSingle(db, body);
}

database(name = this.#defaultDbName): Database {
/** Get a database instance on the connected server */
database(name: string = this.#defaultDbName): Database {
return new Database(this.getCluster(), name);
}

/** Close the connection to the server */
close() {
if (this.#cluster) this.#cluster.close();
}
Expand Down
21 changes: 13 additions & 8 deletions src/cluster.ts
@@ -1,8 +1,7 @@
import { WireProtocol } from "./protocol/mod.ts";
import { ConnectOptions } from "./types.ts";
import { AuthContext, ScramAuthPlugin, X509AuthPlugin } from "./auth/mod.ts";
import { MongoDriverError } from "./error.ts";
import { Server } from "./types.ts";
import { WireProtocol } from "./protocol/mod.ts";
import { ConnectOptions, Server } from "./types.ts";

export class Cluster {
#options: ConnectOptions;
Expand All @@ -24,7 +23,10 @@ export class Cluster {
);
}

connectToServer(server: Server, options: ConnectOptions) {
connectToServer(
server: Server,
options: ConnectOptions,
): Promise<Deno.TlsConn | Deno.TcpConn> {
const denoConnectOps: Deno.ConnectTlsOptions = {
hostname: server.host,
port: server.port,
Expand Down Expand Up @@ -57,7 +59,10 @@ export class Cluster {
);
}

async authenticateToServer(conn: Deno.Conn, options: ConnectOptions) {
async authenticateToServer(
conn: Deno.Conn,
options: ConnectOptions,
): Promise<WireProtocol> {
const protocol = new WireProtocol(conn);
if (options.credential) {
const authContext = new AuthContext(
Expand Down Expand Up @@ -111,16 +116,16 @@ export class Cluster {
};
}

get protocol() {
get protocol(): WireProtocol {
return this.getMaster().protocol;
}

close() {
for (const conn of this.#connections) {
try {
conn.close();
} catch (error) {
console.error(`Error closing connection: ${error}`);
} catch {
// this is safe to ignore
}
}
}
Expand Down

0 comments on commit 749d804

Please sign in to comment.