summaryrefslogtreecommitdiff
path: root/decrypt_bookmarks.js
blob: e73c4e4c8325a9fe4cc2fd51c0dc170d887d8a23 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#!/usr/bin/env node
// Decrypt Floccus bookmarks
// Usage: node decrypt_bookmarks.js [password]

const crypto = require('crypto');
const fs = require('fs');

const BOOKMARKS_PATH = '/var/www/webdav/bookmarks.xbel';
const password = process.argv[2] || process.env.BOOKMARKS_PASSWORD || JSON.parse(require('fs').readFileSync('/etc/automation/bookmarks.json', 'utf8')).password;

const data = JSON.parse(fs.readFileSync(BOOKMARKS_PATH, 'utf8'));
const ciphertext = Buffer.from(data.ciphertext, 'base64');
const salt = data.salt;  // Floccus uses salt as UTF-8 string, not hex-decoded

// Floccus encryption: PBKDF2-SHA256, 250000 iterations
const key = crypto.pbkdf2Sync(password, salt, 250000, 32, 'sha256');

// 16-byte IV at start, then ciphertext, then 16-byte GCM tag at end
const iv = ciphertext.slice(0, 16);
const encrypted = ciphertext.slice(16, -16);
const tag = ciphertext.slice(-16);

try {
  const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
  decipher.setAuthTag(tag);
  
  let decrypted = decipher.update(encrypted);
  decrypted = Buffer.concat([decrypted, decipher.final()]);
  
  console.log(decrypted.toString('utf8'));
} catch (e) {
  console.error('Decryption failed:', e.message);
  process.exit(1);
}