Files
quak/test/crypto/encoding.test.ts
sneak d8a4b0291e Rename quack to quak
German for 'quack', matching the Ente (German for 'duck') naming. All
references updated: package name, CLI binary, X-Client-Package header,
test descriptions, temp dir prefixes, README, Makefile docker tag.
2026-05-13 18:02:55 -07:00

90 lines
3.5 KiB
TypeScript

/**
* Tests for `crypto.fromBase64`, `crypto.toBase64`, and
* `crypto.toBase64URL`.
*
* Ente delivers most binary fields as standard base64 strings (with `+`,
* `/`, and `=` padding). A few fields, notably the auth token returned by
* the login flow, are URL-safe base64 (with `-` and `_` instead of `+` and
* `/`, and stripped padding). quak must accept both forms on input and
* produce the right form on output.
*
* These tests pin the contract:
* - `toBase64(b)` produces standard base64 with padding.
* - `toBase64URL(b)` produces URL-safe base64 without padding.
* - `fromBase64(s)` accepts both forms transparently and round-trips.
*/
import { beforeAll, describe, expect, it } from "vitest";
import {
fromBase64,
init,
toBase64,
toBase64URL,
} from "../../src/crypto/index.js";
describe("crypto encoding helpers", () => {
beforeAll(async () => {
await init();
});
/**
* The test input contains bytes that produce `+`, `/`, and `=` in
* standard base64. Specifically the bytes `0xFB 0xFF 0xBF` encode to
* `+/+/` in standard base64 and `-_-_` in URL-safe base64. This makes
* the alphabet difference observable.
*/
const BYTES_WITH_AMBIGUOUS_CHARS = new Uint8Array([0xfb, 0xff, 0xbf]);
it("round-trips arbitrary bytes through standard base64", () => {
const original = new Uint8Array([0, 1, 2, 127, 128, 250, 255]);
const encoded = toBase64(original);
expect(typeof encoded).toBe("string");
expect(fromBase64(encoded)).toEqual(original);
});
it("toBase64 produces a standard-alphabet string", () => {
// Standard base64 may contain `+`, `/`, and trailing `=`. URL-safe
// base64 is forbidden from containing those characters. We test
// that toBase64 chose the standard alphabet.
const encoded = toBase64(BYTES_WITH_AMBIGUOUS_CHARS);
// For these specific bytes the encoding contains both `+` and `/`,
// proving the alphabet is the standard one.
expect(encoded).toMatch(/[+/]/);
});
it("toBase64URL produces a URL-safe string with no padding", () => {
const encoded = toBase64URL(BYTES_WITH_AMBIGUOUS_CHARS);
// URL-safe alphabet: no `+`, `/`, or `=`.
expect(encoded).not.toMatch(/[+/=]/);
// The substitutions `-` and `_` should appear.
expect(encoded).toMatch(/[-_]/);
});
it("fromBase64 accepts standard input", () => {
const standard = toBase64(BYTES_WITH_AMBIGUOUS_CHARS);
expect(fromBase64(standard)).toEqual(BYTES_WITH_AMBIGUOUS_CHARS);
});
it("fromBase64 accepts URL-safe input", () => {
const urlSafe = toBase64URL(BYTES_WITH_AMBIGUOUS_CHARS);
expect(fromBase64(urlSafe)).toEqual(BYTES_WITH_AMBIGUOUS_CHARS);
});
it("fromBase64 accepts URL-safe input even without padding", () => {
// Construct a URL-safe form with the padding stripped, as Ente
// delivers it. `fromBase64` must still decode it correctly.
const stripped = toBase64URL(BYTES_WITH_AMBIGUOUS_CHARS).replace(
/=+$/,
"",
);
expect(fromBase64(stripped)).toEqual(BYTES_WITH_AMBIGUOUS_CHARS);
});
it("fromBase64 rejects garbage", () => {
// Non-base64 characters should not silently decode to something. We
// do not commit to the exact error type but we do commit that the
// call cannot return data successfully.
expect(() => fromBase64("!!! not base64 !!!")).toThrow();
});
});