UNPKG

dedpaste

Version:

CLI pastebin application using Cloudflare Workers and R2

157 lines (128 loc) 4.71 kB
// Keybase integration utilities import fetch from 'node-fetch'; import { promises as fsPromises } from 'fs'; import path from 'path'; import { addFriendKey } from './keyManager.js'; import { importPgpKey } from './pgpUtils.js'; // Keybase API URL const KEYBASE_API_URL = 'https://keybase.io/_/api/1.0'; /** * Fetch user information from Keybase * @param {string} username - Keybase username * @returns {Promise<Object>} - User information */ async function fetchKeybaseUser(username) { try { const url = `${KEYBASE_API_URL}/user/lookup.json?username=${encodeURIComponent(username)}`; const response = await fetch(url); if (!response.ok) { throw new Error(`Keybase API error: ${response.status} ${response.statusText}`); } const data = await response.json(); if (!data.status || data.status.code !== 0) { throw new Error(`Keybase API error: ${data.status?.desc || 'Unknown error'}`); } if (!data.them) { throw new Error(`User '${username}' not found on Keybase`); } return data.them; } catch (error) { throw new Error(`Failed to fetch Keybase user: ${error.message}`); } } /** * Fetch public key for a Keybase user * @param {string} username - Keybase username * @returns {Promise<string>} - PGP public key text */ async function fetchKeybasePgpKey(username) { try { const url = `${KEYBASE_API_URL}/user/lookup.json?username=${encodeURIComponent(username)}&fields=public_keys`; const response = await fetch(url); if (!response.ok) { throw new Error(`Keybase API error: ${response.status} ${response.statusText}`); } const data = await response.json(); if (!data.status || data.status.code !== 0) { throw new Error(`Keybase API error: ${data.status?.desc || 'Unknown error'}`); } if (!data.them) { throw new Error(`User '${username}' not found on Keybase`); } const publicKeys = data.them.public_keys; // Check for PGP key if (!publicKeys || !publicKeys.primary || !publicKeys.primary.bundle) { throw new Error(`No PGP key found for user '${username}'`); } return publicKeys.primary.bundle; } catch (error) { throw new Error(`Failed to fetch Keybase PGP key: ${error.message}`); } } /** * Verify a Keybase user's proofs * @param {string} username - Keybase username * @returns {Promise<Object>} - Verification results */ async function verifyKeybaseProofs(username) { try { const url = `${KEYBASE_API_URL}/user/lookup.json?username=${encodeURIComponent(username)}&fields=proofs_summary`; const response = await fetch(url); if (!response.ok) { throw new Error(`Keybase API error: ${response.status} ${response.statusText}`); } const data = await response.json(); if (!data.them || !data.them.proofs_summary) { throw new Error(`No proofs found for user '${username}'`); } // Return the proof summary return data.them.proofs_summary; } catch (error) { throw new Error(`Failed to verify Keybase proofs: ${error.message}`); } } /** * Add a Keybase user's PGP key to friend list * @param {string} username - Keybase username * @param {string} [friendName] - Optional custom name for the friend * @param {boolean} [verify=true] - Whether to verify proofs * @returns {Promise<Object>} - Result with key details */ async function addKeybaseKey(username, friendName = null, verify = true) { try { // Verify the user's proofs if requested if (verify) { const proofs = await verifyKeybaseProofs(username); // Check if user has at least one verified proof const hasVerifiedProofs = Object.values(proofs.all || []).some(proof => proof.state === 1); if (!hasVerifiedProofs) { throw new Error(`User '${username}' has no verified proofs on Keybase. Use verify=false to bypass this check.`); } } // Fetch the user's PGP key const pgpKey = await fetchKeybasePgpKey(username); // Import and parse the key const keyInfo = await importPgpKey(pgpKey); // Use provided name or derive from key const name = friendName || `keybase:${username}`; // Store the key in friends directory const result = await addFriendKey(name, pgpKey); return { name, username, keybaseUser: username, email: keyInfo.email, keyId: keyInfo.keyId, path: result }; } catch (error) { throw new Error(`Failed to add Keybase key: ${error.message}`); } } // Export functions export { fetchKeybaseUser, fetchKeybasePgpKey, verifyKeybaseProofs, addKeybaseKey };