Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: use custom base64 decoder to workaround deno bug #406

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

markwylde
Copy link

@markwylde markwylde commented Dec 4, 2023

This PR works around issue #381, a bug that appears to be in Deno:
denoland/deno#19546

It uses a custom base64 function, but maybe we could find another library out there that doesn't use the built in atob.

@lucsoft
Copy link
Collaborator

lucsoft commented Dec 4, 2023

Wait does the std base64 encoder also has this issue or just atob?

@erfanium erfanium requested a review from lucsoft December 4, 2023 18:19
@markwylde
Copy link
Author

Yeah the std base64 encoder uses atob [1], which it looks like is broken unless I've misunderstood.

  1. https://github.com/denoland/deno_std/blob/main/encoding/base64.ts#L151

@@ -114,6 +114,17 @@ export async function executeScram(
return continueScramConversation(cryptoMethod, result, authContext);
}

function decodeBase64(b64: string): Uint8Array {
const b64Web = b64.replace(/-/g, "+").replace(/_/g, "/");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you are converting a URL Safe base64 to an actual base64?

so you issue is that you don't actually use a base64 string, but you use a url safe base64 adoptation.

base64 uses / and + by default. so the current impl is not wrong. we just expect actual base64 strings

do you require a url safe base64? / is this per mongodb driver spec?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a really good question lucsoft, but I don't have the answers unfortunately.

I have managed to create a small script to recreate the problem:

import { MongoClient } from '../mod.ts';

for (let x = 0; x < 100000; x++) {
  const client = new MongoClient();

  const url = `mongodb://testadmin1:testpass1@localhost:27017?directConnection=true`
  console.log('url:', url);
  await client.connect(url);

  await client.close()
  console.log('');
}

Run that, and within a few seconds it will throw:

deno-mongo % deno run --allow-net demo/main.ts
url: mongodb://testadmin1:testpass1@localhost:27017?directConnection=true

url: mongodb://testadmin1:testpass1@localhost:27017?directConnection=true

url: mongodb://testadmin1:testpass1@localhost:27017?directConnection=true



url: mongodb://testadmin1:testpass1@localhost:27017?directConnection=true
error: Uncaught (in promise) Error: MongoError: "Connection failed: Failed to decode base64"
      throw new MongoDriverError(`Connection failed: ${e.message || e}`);
            ^
    at MongoClient.connect (file:///deno-mongo/src/client.ts:46:13)
    at eventLoopTick (ext:core/01_core.js:178:11)
    at async file:///deno-mongo/demo/main.ts:8:3

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still not sure what's going on, but if I edit the scram.ts file

Screenshot 2023-12-04 at 20 47 35

Then run my script above, I get:

url: mongodb://testadmin1:testpass1@localhost:27017?directConnection=true
parsedResponse= { v: "" }
decodeBase64 Uint8Array(0) []

url: mongodb://testadmin1:testpass1@localhost:27017?directConnection=true
parsedResponse= { v: "" }
decodeBase64 Uint8Array(0) []

url: mongodb://testadmin1:testpass1@localhost:27017?directConnection=true
parsedResponse= { v: "XwftqO5acqzP3qfL6HMwI" }
error: Uncaught (in promise) InvalidCharacterError: Failed to decode base64
  const binString = atob(b64);
                    ^
    at atob (ext:deno_web/05_base64.js:28:16)
    at Module.decode (https://deno.land/std@0.202.0/encoding/base64.ts:138:21)
    at continueScramConversation (file://deno-mongo/src/auth/scram.ts:206:35)
    at eventLoopTick (ext:core/01_core.js:178:11)
    at async Cluster.authenticateToServer (file://deno-mongo/src/cluster.ts:86:7)
    at async Promise.all (index 0)
    at async Cluster.authenticate (file://deno-mongo/src/cluster.ts:55:23)
    at async MongoClient.connect (file://deno-mongo/src/client.ts:37:7)
    at async file://deno-mongo/demo/main.ts:8:3

It's strange, the ones before have a blank parsedResponse, seem to work. But when data get's returned it fails. What is that data?

Copy link
Collaborator

@lucsoft lucsoft left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not a fix this is a feature request. is this per spec? 😄 Hope we can resolve this together :)

if you have any questions feel free to ask

@markwylde
Copy link
Author

this is not a fix this is a feature request. is this per spec? 😄 Hope we can resolve this together :)

if you have any questions feel free to ask

Sorry, I'm happy to rebase to any commit message appropriate for this.

@opimand
Copy link

opimand commented May 2, 2024

Some fix? Can't use Mongo with Deno by default

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants