diff options
Diffstat (limited to 'decrypt_bookmarks.js')
| -rw-r--r-- | decrypt_bookmarks.js | 34 |
1 files changed, 34 insertions, 0 deletions
diff --git a/decrypt_bookmarks.js b/decrypt_bookmarks.js new file mode 100644 index 0000000..e73c4e4 --- /dev/null +++ b/decrypt_bookmarks.js @@ -0,0 +1,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); +} |
