porsager / postgres

Postgres.js - The Fastest full featured PostgreSQL client for Node.js, Deno, Bun and CloudFlare
The Unlicense
7.5k stars 275 forks source link

URIError: URI malformed | special characters aren't accepted #735

Open draylegend opened 11 months ago

draylegend commented 11 months ago

can't connect to supabase using env var DATABASE_URL="postgresql://postgres:[PASSWORD]@db.[REFERENCE-ID].supabase.co:5432/postgres". It fails if the password contains %, # and other special characters. Therefore the range of passwords is reduced to a-zA-Z0-9. What do you think about expanding to more characters in order to make the password more secure?

!@#$%^&*, ()-_+=[]{}:;'".<>/\|~?`

Error

$ bun admin/src/be.ts 
543 |   const urlObj = new URL(url.replace(host, host.split(',')[0]))
544 | 
545 |   return {
546 |     url: {
547 |       username: decodeURIComponent(urlObj.username),
548 |       password: decodeURIComponent(urlObj.password),
                    ^
URIError: URI error
      at parseUrl (/home/dl/virtum.club/node_modules/postgres/src/index.js:548:16)
      at parseOptions (/home/dl/virtum.club/node_modules/postgres/src/index.js:435:29)
      at Postgres (/home/dl/virtum.club/node_modules/postgres/src/index.js:50:18)
      at /home/dl/virtum.club/admin/src/be.ts:11:15

Usage

// admin/src/be.ts
import { pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core';
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';

export const notes = pgTable('note', {
  id: serial('id').primaryKey(),
  note: text('note').notNull(),
  createdAt: timestamp('created_at').defaultNow().notNull(),
});

const client = postgres(process.env['DATABASE_URL']!);
const db = drizzle(client);

(async () => {
  console.log(await db.select().from(notes));
})();
porsager commented 11 months ago

you've got the clue in your here:

548 |       password: decodeURIComponent(urlObj.password),
                    ^
URIError: URI error

ensure you encode the properties right.

draylegend commented 11 months ago

I get the connection string from the process.env['DATABASE_URL']. Sounds like I need to split up the string and encode the username and password, right @porsager?

porsager commented 11 months ago

Oh I see.. I think that ought to already have the necessary characters URI encoded if it's set by supabase.. Can you show a sample of the string you get with the same characters, but moved around as to not reveal the password?

draylegend commented 11 months ago
DATABASE_URL="postgresql://postgres:abc%def#ghklMN@db.[SUPABASE-REFERENCE-ID].supabase.co:5432/postgres"

It'd be awesome to just pass the env variable to postgres function without splitting up/encoding/decoding a connection string

binury commented 8 months ago
DATABASE_URL="postgresql://postgres:abc%def#ghklMN@db.[SUPABASE-REFERENCE-ID].supabase.co:5432/postgres"

It'd be awesome to just pass the env variable to postgres function without splitting up/encoding/decoding a connection string

FWIW, anywhere that you can pass that URI -e.g. to psql- you can also pass the credential-encoded counterpart.

andlipro commented 2 months ago

usage with encoding const sql = postgres(encodeURI(process.env.DATABASE_URL || "")); helped me