Files
publisher-dashboard/packages/utils/src/generate-base58-token.test.ts
RevIQ ddd7c0c03b Add generateSecureBase58Token to shared utils with login_ prefix
- Create packages/utils/src/generate-base58-token.ts with typed prefix support
- Function returns `${TPrefix}${string}` for type-safe prefixed tokens
- Add isBase58() validator and parseBase58Token() helper
- Add comprehensive tests (13 test cases)

- Update login request tokens to use "login_" prefix
- Fix login-password.ts to not replace token (cookie/DB mismatch bug)
- Migrate all token generation from generateSecureToken (hex) to
  generateSecureBase58Token (base58)
- Remove duplicate token generation from api-server/utils/crypto.ts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 19:31:30 +08:00

106 lines
3.3 KiB
TypeScript

import { describe, expect, it } from "bun:test";
import {
generateSecureBase58Token,
isBase58,
parseBase58Token,
} from "./generate-base58-token.js";
const BASE58_ALPHABET =
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
describe("isBase58", () => {
it("should return true for valid base58 strings", () => {
expect(isBase58("123456789")).toBe(true);
expect(isBase58("ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")).toBe(
true,
);
expect(isBase58("9JKmn")).toBe(true);
});
it("should return false for strings with invalid characters", () => {
// 0, O, I, l are not in base58 alphabet
expect(isBase58("0")).toBe(false);
expect(isBase58("O")).toBe(false);
expect(isBase58("I")).toBe(false);
expect(isBase58("l")).toBe(false);
expect(isBase58("abc0def")).toBe(false);
});
it("should return false for empty strings", () => {
expect(isBase58("")).toBe(false);
});
it("should return false for strings with special characters", () => {
expect(isBase58("abc+def")).toBe(false);
expect(isBase58("abc/def")).toBe(false);
expect(isBase58("abc=def")).toBe(false);
});
});
describe("generateSecureBase58Token", () => {
it("should generate a valid base58 token", () => {
const token = generateSecureBase58Token();
expect(isBase58(token)).toBe(true);
});
it("should generate tokens of expected length (~33 chars for 24 bytes)", () => {
const token = generateSecureBase58Token();
// 24 bytes = 192 bits, base58 encoding gives roughly 33 chars
expect(token.length).toBeGreaterThanOrEqual(30);
expect(token.length).toBeLessThanOrEqual(35);
});
it("should generate unique tokens", () => {
const tokens = new Set<string>();
for (let i = 0; i < 100; i++) {
tokens.add(generateSecureBase58Token());
}
expect(tokens.size).toBe(100);
});
it("should only use base58 alphabet characters", () => {
for (let i = 0; i < 50; i++) {
const token = generateSecureBase58Token();
for (const char of token) {
expect(BASE58_ALPHABET.includes(char)).toBe(true);
}
}
});
it("should prepend prefix when provided", () => {
const token = generateSecureBase58Token("lrt_");
expect(token.startsWith("lrt_")).toBe(true);
// The part after prefix should be valid base58
expect(isBase58(token.slice(4))).toBe(true);
});
});
describe("parseBase58Token", () => {
it("should parse token with correct prefix", () => {
const token = generateSecureBase58Token("lrt_");
const parsed = parseBase58Token(token, "lrt_");
expect(parsed).not.toBeNull();
if (parsed !== null) {
expect(isBase58(parsed)).toBe(true);
}
});
it("should return null for wrong prefix", () => {
const token = generateSecureBase58Token("lrt_");
const parsed = parseBase58Token(token, "wrong_");
expect(parsed).toBeNull();
});
it("should return null for missing prefix", () => {
const token = generateSecureBase58Token();
const parsed = parseBase58Token(token, "lrt_");
expect(parsed).toBeNull();
});
it("should return null for invalid base58 after prefix", () => {
const invalidToken = "lrt_abc0def"; // 0 is not valid base58
const parsed = parseBase58Token(invalidToken, "lrt_");
expect(parsed).toBeNull();
});
});