chadtmiller.com/pds.js
An atproto PDS in JavaScript, for Cloudflare Workers and Node
0
0
#!/usr/bin/env node
// A throwaway OAuth client for driving the authorize flow by hand, so the
// consent screen can be seen and verified. Runs a loopback client through PAR,
// then fetches (and saves) the consent page and prints the authorize URL to
// open in a browser.
//
// node scripts/oauth-probe.mjs [--scope "..."] [--login-hint <handle|did>]
//
// Env: BASE (default http://localhost:2471).
import { writeFileSync } from 'node:fs';
import { DpopClient, seedDpopNonce } from '../test/helpers/dpop.js';
const BASE = process.env.BASE || 'http://localhost:2471';
const args = process.argv.slice(2);
const arg = (name, fallback) => {
const i = args.indexOf(name);
return i >= 0 ? args[i + 1] : fallback;
};
const clientId = 'http://localhost:3000';
const redirectUri = 'http://localhost:3000/callback';
const scope = arg('--scope', 'atproto transition:generic');
const loginHint = arg('--login-hint', 'test.host.docker.internal');
const dpop = await DpopClient.create();
await seedDpopNonce(BASE);
const parProof = await dpop.createProof('POST', `${BASE}/oauth/par`);
const parRes = await fetch(`${BASE}/oauth/par`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
DPoP: parProof,
},
body: new URLSearchParams({
client_id: clientId,
redirect_uri: redirectUri,
response_type: 'code',
scope,
code_challenge: 'E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM',
code_challenge_method: 'S256',
login_hint: loginHint,
}).toString(),
});
if (!parRes.ok) {
console.error(`PAR failed: ${parRes.status} ${await parRes.text()}`);
process.exit(1);
}
const { request_uri } = await parRes.json();
const authorizeUrl = `${BASE}/oauth/authorize?client_id=${encodeURIComponent(clientId)}&request_uri=${encodeURIComponent(request_uri)}`;
const consent = await fetch(authorizeUrl, { headers: { Accept: 'text/html' } });
const html = await consent.text();
writeFileSync('/tmp/consent.html', html);
console.log(`scope: ${scope}`);
console.log(
`consent GET: ${consent.status} (${html.length} bytes -> /tmp/consent.html)`,
);
console.log(
`react mode: ${/window\.__PDS__=JSON\.parse/.test(html) ? 'yes (SPA consent)' : 'no (server-rendered)'}`,
);
console.log(`\nOpen in a browser to click through:\n${authorizeUrl}`);