summaryrefslogtreecommitdiff
path: root/decrypt_bookmarks.js
diff options
context:
space:
mode:
Diffstat (limited to 'decrypt_bookmarks.js')
-rw-r--r--decrypt_bookmarks.js34
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);
+}