chadtmiller.com/pds.js
An atproto PDS in JavaScript, for Cloudflare Workers and Node
0
0
import { describe, expect, it } from 'vitest';
import { decodeJwt, expiryOf } from '#/lib/jwt.js';
/**
* @param {object} header @param {object} payload
* @returns {string}
*/
function jwt(header, payload) {
const part = (value) =>
btoa(JSON.stringify(value))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '');
return `${part(header)}.${part(payload)}.c2ln`;
}
describe('decodeJwt', () => {
it('reads both segments of a space credential', () => {
const token = jwt(
{ alg: 'ES256', typ: 'atproto-space-credential+jwt', kid: '#atproto' },
{
iss: 'did:plc:authority',
sub: 'at://did:plc:authority/space/com.example.forum/general',
cnf: { jkt: 'a-thumbprint' },
exp: 1_800_000_000,
},
);
const decoded = decodeJwt(token);
expect(decoded?.header.typ).toBe('atproto-space-credential+jwt');
expect(decoded?.payload.cnf.jkt).toBe('a-thumbprint');
});
// A segment whose length is not a multiple of four is the normal case: these
// tokens are base64url with the padding stripped.
it('decodes a segment whose padding was stripped', () => {
const token = jwt({ alg: 'ES256' }, { iss: 'did:plc:a' });
expect(token.split('.')[1].length % 4).not.toBe(0);
expect(decodeJwt(token)?.payload.iss).toBe('did:plc:a');
});
it('answers null for anything that is not a JWT', () => {
expect(decodeJwt('not-a-token')).toBeNull();
expect(decodeJwt('')).toBeNull();
expect(decodeJwt('a.b.c')).toBeNull();
});
});
describe('expiryOf', () => {
it('reads exp as milliseconds', () => {
expect(expiryOf(jwt({}, { exp: 1_800_000_000 }))).toBe(1_800_000_000_000);
});
// A token stating no expiry gets a held-for-ten-minutes fallback at the call
// site, which only fires because this answers zero rather than NaN.
it('answers zero for a token that states none', () => {
expect(expiryOf(jwt({}, { iss: 'did:plc:a' }))).toBe(0);
expect(expiryOf('rubbish')).toBe(0);
});
});