|
| 1 | +// CLI entry point. Run with one of: |
| 2 | +// npm run send # encrypts and asks Cryptify to mail recipients |
| 3 | +// npm run upload # encrypts and uploads silently |
| 4 | +// npm start # same as `npm run send` |
| 5 | +// |
| 6 | +// Configuration via .env or environment variables — see .env.example. |
| 7 | + |
| 8 | +import { readFile } from 'node:fs/promises'; |
| 9 | +import { basename } from 'node:path'; |
| 10 | +import { |
| 11 | + API_KEY, |
| 12 | + CITIZEN_EMAIL, |
| 13 | + ORGANISATION_EMAIL, |
| 14 | + MESSAGE, |
| 15 | + INPUT_FILES, |
| 16 | + DOWNLOAD_URL, |
| 17 | + IS_CRYPTIFY_STAGING, |
| 18 | + CRYPTIFY_URL, |
| 19 | + PKG_URL, |
| 20 | +} from './src/config.mjs'; |
| 21 | +import { encryptAndSend, encryptAndUpload } from './src/encryption.mjs'; |
| 22 | + |
| 23 | +if (!API_KEY) { |
| 24 | + console.error('Missing PG_API_KEY. Copy .env.example to .env and set it.'); |
| 25 | + process.exit(2); |
| 26 | +} |
| 27 | + |
| 28 | +const mode = process.argv.includes('--upload-only') ? 'upload-only' : 'send-email'; |
| 29 | + |
| 30 | +console.log(`pg-node example — mode: ${mode}`); |
| 31 | +console.log(` PKG: ${PKG_URL}`); |
| 32 | +console.log(` Cryptify: ${CRYPTIFY_URL}${IS_CRYPTIFY_STAGING ? ' (staging — no mails actually sent)' : ''}`); |
| 33 | +console.log(` Citizen: ${CITIZEN_EMAIL}`); |
| 34 | +console.log(` Organisation: ${ORGANISATION_EMAIL}`); |
| 35 | +console.log(''); |
| 36 | + |
| 37 | +const files = await loadFiles(); |
| 38 | +console.log(`Encrypting ${files.length} file(s):`); |
| 39 | +for (const f of files) console.log(` ${f.name} (${f.size} bytes)`); |
| 40 | +console.log(''); |
| 41 | + |
| 42 | +const abortController = new AbortController(); |
| 43 | +process.on('SIGINT', () => { |
| 44 | + console.log('\nCancelling…'); |
| 45 | + abortController.abort(); |
| 46 | +}); |
| 47 | + |
| 48 | +const onProgress = (pct) => { |
| 49 | + process.stdout.write(`\r upload progress: ${pct}% `); |
| 50 | +}; |
| 51 | + |
| 52 | +const t0 = performance.now(); |
| 53 | +const uuid = |
| 54 | + mode === 'send-email' |
| 55 | + ? await encryptAndSend({ |
| 56 | + files, |
| 57 | + citizen: { email: CITIZEN_EMAIL }, |
| 58 | + organisation: { email: ORGANISATION_EMAIL }, |
| 59 | + apiKey: API_KEY, |
| 60 | + message: MESSAGE, |
| 61 | + onProgress, |
| 62 | + signal: abortController.signal, |
| 63 | + }) |
| 64 | + : await encryptAndUpload({ |
| 65 | + files, |
| 66 | + citizen: { email: CITIZEN_EMAIL }, |
| 67 | + organisation: { email: ORGANISATION_EMAIL }, |
| 68 | + apiKey: API_KEY, |
| 69 | + onProgress, |
| 70 | + signal: abortController.signal, |
| 71 | + }); |
| 72 | +const t1 = performance.now(); |
| 73 | + |
| 74 | +process.stdout.write('\n'); |
| 75 | +console.log(''); |
| 76 | +console.log(`Done in ${(t1 - t0).toFixed(0)}ms`); |
| 77 | +console.log(`UUID: ${uuid}`); |
| 78 | +console.log(`Download: ${DOWNLOAD_URL}/download?uuid=${uuid}`); |
| 79 | + |
| 80 | +if (mode === 'send-email' && IS_CRYPTIFY_STAGING) { |
| 81 | + console.log(''); |
| 82 | + console.log('Note: staging Cryptify does not actually deliver mails. Open the URL above to test decrypt.'); |
| 83 | +} |
| 84 | + |
| 85 | +/** Read each path in PG_INPUT_FILES as a File. If empty, return two demo files. */ |
| 86 | +async function loadFiles() { |
| 87 | + if (INPUT_FILES.length === 0) { |
| 88 | + return [ |
| 89 | + new File( |
| 90 | + [new TextEncoder().encode('This is a sample report for PostGuard encryption testing.\n')], |
| 91 | + 'report.txt', |
| 92 | + { type: 'text/plain' } |
| 93 | + ), |
| 94 | + new File( |
| 95 | + [new TextEncoder().encode('Confidential notes — only the intended recipient can read this.\n')], |
| 96 | + 'notes.txt', |
| 97 | + { type: 'text/plain' } |
| 98 | + ), |
| 99 | + ]; |
| 100 | + } |
| 101 | + return Promise.all( |
| 102 | + INPUT_FILES.map(async (path) => { |
| 103 | + const bytes = await readFile(path); |
| 104 | + return new File([bytes], basename(path)); |
| 105 | + }) |
| 106 | + ); |
| 107 | +} |
0 commit comments