diff --git a/apps/relay/src/channels.test.ts b/apps/relay/src/channels.test.ts index fcbc3eb..a5f87a8 100644 --- a/apps/relay/src/channels.test.ts +++ b/apps/relay/src/channels.test.ts @@ -27,7 +27,7 @@ describe("channel store", () => { describe("open", () => { test("opens a channel and returns the token", async () => { const channel = await channels.open(); - expect(channel._unsafeUnwrap()).toMatch(/[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}/); + expect(channel._unsafeUnwrap()).toMatch(/[2-9A-HJ-NP-Z]{8}/); }); }); diff --git a/apps/relay/src/channels.ts b/apps/relay/src/channels.ts index 708543b..7d11f22 100644 --- a/apps/relay/src/channels.ts +++ b/apps/relay/src/channels.ts @@ -1,7 +1,7 @@ import { Redis } from "ioredis"; import { ResultAsync, err, ok } from "neverthrow"; -import { randomUUID } from "crypto"; import { RelayAsyncResult, RelayError } from "./errors"; +import { generateChannelToken } from "./tokens"; interface ChannelStoreOpts { redisUrl: string; @@ -18,7 +18,7 @@ export class ChannelStore { } async open(state?: T): RelayAsyncResult { - const channelToken = randomUUID(); + const channelToken = generateChannelToken(); return ResultAsync.fromPromise( this.redis.set(channelToken, JSON.stringify(state ?? {}), "EX", this.ttl), (err) => new RelayError("unavailable", err as Error), diff --git a/apps/relay/src/server.test.ts b/apps/relay/src/server.test.ts index 1b58e04..220910e 100644 --- a/apps/relay/src/server.test.ts +++ b/apps/relay/src/server.test.ts @@ -74,7 +74,7 @@ describe("relay server", () => { expect(response.status).toBe(201); const { channelToken, url, connectUri, nonce, ...rest } = response.data; - expect(channelToken).toMatch(/[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}/); + expect(channelToken).toMatch(/[2-9A-HJ-NP-Z]{8}/); expect(url).toMatch("https://warpcast.com/~/sign-in-with-farcaster"); expect(url).toBe(connectUri); expect(rest).toStrictEqual({}); @@ -106,7 +106,7 @@ describe("relay server", () => { expect(params.get("expirationTime")).toBe(expirationTime); expect(params.get("requestId")).toBe(requestId); expect(params.get("redirectUrl")).toBe(redirectUrl); - expect(channelToken).toMatch(/[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}/); + expect(channelToken).toMatch(/[2-9A-HJ-NP-Z]{8}/); expect(nonce).toBe(customNonce); expect(url).toBe(connectUri); expect(rest).toStrictEqual({}); diff --git a/apps/relay/src/tokens.ts b/apps/relay/src/tokens.ts new file mode 100644 index 0000000..d0ed0c9 --- /dev/null +++ b/apps/relay/src/tokens.ts @@ -0,0 +1,16 @@ +import crypto from "crypto"; + +const ALPHABET = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ"; + +export function generateChannelToken(length = 8): string { + const bytes = crypto.randomBytes(length); + let id = ""; + for (let i = 0; i < length; i++) { + const byte = bytes[i]; + if (byte === undefined) { + throw new Error("Error generating channel token"); + } + id += ALPHABET[byte % ALPHABET.length]; + } + return id; +}