()
| 56 | } |
| 57 | |
| 58 | function encrypt() { |
| 59 | if (!existsSync(PLAINTEXT_PATH)) { |
| 60 | console.error( |
| 61 | `Missing ${PLAINTEXT_PATH}. Create it with the multi-provider schema (e.g. { "twitter": { "accounts": [...] } }).` |
| 62 | ); |
| 63 | process.exit(1); |
| 64 | } |
| 65 | |
| 66 | const plaintext = readFileSync(PLAINTEXT_PATH, 'utf-8'); |
| 67 | const parsed = JSON.parse(plaintext); |
| 68 | const hasTwitter = Array.isArray(parsed?.twitter?.accounts) && parsed.twitter.accounts.length > 0; |
| 69 | const hasBluesky = Array.isArray(parsed?.bluesky?.accounts) && parsed.bluesky.accounts.length > 0; |
| 70 | if (!hasTwitter && !hasBluesky) { |
| 71 | console.error( |
| 72 | 'credentials.json must include a non-empty twitter.accounts and/or bluesky.accounts array (see credentials.example.json).' |
| 73 | ); |
| 74 | process.exit(1); |
| 75 | } |
| 76 | if (hasBluesky) { |
| 77 | const bskyFields = ['identifier', 'appPassword', 'service']; |
| 78 | for (let i = 0; i < parsed.bluesky.accounts.length; i++) { |
| 79 | const cred = parsed.bluesky.accounts[i]; |
| 80 | const id = `bluesky.accounts[${i}]`; |
| 81 | if (cred === null || typeof cred !== 'object' || Array.isArray(cred)) { |
| 82 | console.error(`${id}: each account must be a plain object`); |
| 83 | process.exit(1); |
| 84 | } |
| 85 | for (const field of bskyFields) { |
| 86 | const v = cred[field]; |
| 87 | if (typeof v !== 'string' || v.length === 0) { |
| 88 | console.error(`${id}: "${field}" must be a non-empty string`); |
| 89 | process.exit(1); |
| 90 | } |
| 91 | } |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | let keyB64url; |
| 96 | if (existsSync(KEY_PATH)) { |
| 97 | keyB64url = readFileSync(KEY_PATH, 'utf-8').trim(); |
| 98 | } else { |
| 99 | const rawKey = randomBytes(32); |
| 100 | keyB64url = rawKey.toString('base64url'); |
| 101 | writeFileSync(KEY_PATH, keyB64url + '\n', 'utf-8'); |
| 102 | console.log('\nNew encryption key written to .credential-key'); |
| 103 | console.log('Set Worker secret: wrangler secret put CREDENTIAL_KEY'); |
| 104 | console.log('Paste this value (base64url, one line):\n'); |
| 105 | console.log(keyB64url); |
| 106 | console.log(''); |
| 107 | } |
| 108 | |
| 109 | const key = base64UrlToBuffer(keyB64url); |
| 110 | if (key.length !== 32) { |
| 111 | console.error('.credential-key must decode to 32 bytes (AES-256). Use base64url.'); |
| 112 | process.exit(1); |
| 113 | } |
| 114 | |
| 115 | const iv = randomBytes(12); |
no test coverage detected