chadtmiller.com/pds.js
An atproto PDS in JavaScript, for Cloudflare Workers and Node
0
0
/**
* Bridge to `git credential` so app passwords can live in the user's
* configured credential store under protocol=atproto.
*/
import { spawnSync } from 'node:child_process';
/**
* @typedef {Object} Credential
* @property {string} [username]
* @property {string} [password]
*/
/**
* @param {'fill'|'approve'|'reject'} action
* @param {Record<string, string>} fields
* @returns {Credential}
*/
function credential(action, fields) {
const input = `${Object.entries(fields)
.map(([k, v]) => `${k}=${v}`)
.join('\n')}\n\n`;
const result = spawnSync('git', ['credential', action], {
input,
encoding: 'utf8',
stdio: ['pipe', 'pipe', 'pipe'],
});
if (result.status !== 0) return {};
/** @type {Credential} */
const parsed = {};
for (const line of (result.stdout ?? '').split('\n')) {
const eq = line.indexOf('=');
if (eq === -1) continue;
const key = line.slice(0, eq);
if (key === 'username') parsed.username = line.slice(eq + 1);
if (key === 'password') parsed.password = line.slice(eq + 1);
}
return parsed;
}
/**
* @param {string} host
* @returns {Credential}
*/
export function credentialFill(host) {
return credential('fill', { protocol: 'atproto', host });
}
/**
* @param {string} host
* @param {Credential} cred
*/
export function credentialApprove(host, cred) {
if (!cred.password) return;
credential('approve', {
protocol: 'atproto',
host,
username: cred.username ?? '',
password: cred.password,
});
}
/**
* @param {string} host
* @param {Credential} cred
*/
export function credentialReject(host, cred) {
if (!cred.password) return;
credential('reject', {
protocol: 'atproto',
host,
username: cred.username ?? '',
password: cred.password,
});
}