#!/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); }