#!/usr/bin/env node // Add a bookmark to Floccus encrypted bookmarks // Usage: node add_bookmark.js const crypto = require('crypto'); const fs = require('fs'); const BOOKMARKS_PATH = '/var/www/webdav/bookmarks.xbel'; const PASSWORD = process.env.BOOKMARKS_PASSWORD || JSON.parse(require('fs').readFileSync('/etc/automation/bookmarks.json', 'utf8')).password; const url = process.argv[2]; const title = process.argv[3]; if (!url || !title) { console.log('Usage: node add_bookmark.js <url> <title>'); process.exit(1); } function decrypt(data, password) { const ciphertext = Buffer.from(data.ciphertext, 'base64'); const salt = data.salt; const key = crypto.pbkdf2Sync(password, salt, 250000, 32, 'sha256'); const iv = ciphertext.slice(0, 16); const encrypted = ciphertext.slice(16, -16); const tag = ciphertext.slice(-16); const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv); decipher.setAuthTag(tag); return Buffer.concat([decipher.update(encrypted), decipher.final()]).toString('utf8'); } function encrypt(plaintext, password, salt) { const key = crypto.pbkdf2Sync(password, salt, 250000, 32, 'sha256'); const iv = crypto.randomBytes(16); const cipher = crypto.createCipheriv('aes-256-gcm', key, iv); const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]); const tag = cipher.getAuthTag(); const combined = Buffer.concat([iv, encrypted, tag]); return combined.toString('base64'); } // Read and decrypt const data = JSON.parse(fs.readFileSync(BOOKMARKS_PATH, 'utf8')); let xml = decrypt(data, PASSWORD); // Find highest ID const idMatch = xml.match(/highestId :(\d+):/); let highestId = idMatch ? parseInt(idMatch[1]) : 100; const newId = highestId + 1; // Escape XML entities const escapeXml = (str) => str .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') .replace(/'/g, '''); // Add bookmark const newBookmark = `<bookmark href="${escapeXml(url)}" id="${newId}"> <title>${escapeXml(title)} `; xml = xml.replace(/highestId :(\d+):/, `highestId :${newId}:`); xml = xml.replace('', newBookmark); // Encrypt and save const newCiphertext = encrypt(xml, PASSWORD, data.salt); fs.writeFileSync(BOOKMARKS_PATH, JSON.stringify({ ciphertext: newCiphertext, salt: data.salt })); console.log(`Added bookmark: ${title}`); console.log(`URL: ${url}`); console.log(`ID: ${newId}`);