openvibers/openvibe.network Commits

Legacy secret cleanup: configuration rows only (the VAPID public key is public) (#561)

OP OpenVibers committed 8 days ago · 2438670278 · 3 files, +8 −2

The VAPID pair is not configuration (NOT_CONFIG): the journal never holds it, so the cleanup could never prove a
sealed copy and logged the public key as one kept secret on every boot. New public keys are stored as a string.

Changes

ddiff --git a/server/admin/site-config.js b/server/admin/site-config.js
iindex f5b1f80b..ceaa253e 100644
---- a/server/admin/site-config.js
++++ b/server/admin/site-config.js
@@@ -136,7 +136,9 @@ function readSecret(db, key) {
*/
async function migrateLegacySecrets(db, out) {
const rows = await db.prepare('SELECT key, value, type FROM site_settings').all();
-- const candidates = rows.filter((r) => r.value != null && String(r.value) !== ''
++ // Only configuration rows: keys the journal never holds (NOT_CONFIG: the VAPID pair, migration markers) have no
++ // sealed copy to prove against, and are not counted.
++ const candidates = rows.filter((r) => r.value != null && String(r.value) !== '' && isConfigKey(r.key)
&& (r.type === 'secret' || SECRET.test(r.key)) && !secrets.isSecret(r.key));
if (!candidates.length) return { checked: 0, blanked: 0, differs: 0, kept: 0, sealed: !!out.store.sealed };
if (!out.store.sealed) {
ddiff --git a/server/push/push-service.js b/server/push/push-service.js
iindex 4b9b819d..ce4e6779 100644
---- a/server/push/push-service.js
++++ b/server/push/push-service.js
@@@ -64,7 +64,7 @@ async function initVapid(db) {
const keys = webpush.generateVAPIDKeys();
publicKey = keys.publicKey;
privateKey = keys.privateKey;
-- await upsert.run('vapid_public_key', publicKey, 'secret');
++ await upsert.run('vapid_public_key', publicKey, 'string'); // public: served to every browser
await upsert.run('vapid_private_key', privateKey, 'secret');
_publicKey = publicKey;
console.log('[push] Generated new VAPID keypair');
ddiff --git a/test/legacy-secrets-kek.test.js b/test/legacy-secrets-kek.test.js
iindex 40f56cd3..c4a17d6a 100644
---- a/test/legacy-secrets-kek.test.js
++++ b/test/legacy-secrets-kek.test.js
@@@ -26,6 +26,8 @@ console.error = (...a) => logs.push(a.map(String).join(' '));
await set.run('net.ipinfo_token', SECRET, 'secret');
await set.run('discord_bot_token', PROVIDER, 'secret');
await set.run('platform_name', 'OpenVibe', 'string');
++ // The VAPID public key (served to browsers) has an old 'secret' row type: it is not configuration, not counted.
++ await set.run('vapid_public_key', 'sentinel-vapid-public', 'secret');
const siteConfig = require('../server/admin/site-config');
const report = await siteConfig.init(db);
@@@ -33,12 +35,14 @@ console.error = (...a) => logs.push(a.map(String).join(' '));
assert.strictEqual(journal.store.sealed, true);
assert.strictEqual(report.blanked, 1, 'the non-provider secret row was blanked');
assert.strictEqual(report.differs, 0, 'an equal value is not counted as differing');
++ assert.strictEqual(report.checked, 1, 'a non-configuration row (vapid_public_key) is not a candidate');
const raw = async (k) => (await db.prepare('SELECT value, type FROM site_settings WHERE key = ?').get(k));
assert.strictEqual((await raw('net.ipinfo_token')).value, '', 'no secret-class value remains in site_settings');
assert.strictEqual((await raw('net.ipinfo_token')).type, 'secret', 'the typed slot stays for the settings page');
assert.strictEqual((await raw('discord_bot_token')).value, PROVIDER, 'a provider secret is never moved or blanked');
assert.strictEqual((await raw('platform_name')).value, 'OpenVibe', 'a non-secret row is untouched');
++ assert.strictEqual((await raw('vapid_public_key')).value, 'sentinel-vapid-public', 'the VAPID public key is untouched');
assert.strictEqual(await db.getSetting('net.ipinfo_token'), SECRET, 'the reader gets the journal value');
assert.strictEqual(await db.getSetting('discord_bot_token'), null, 'a provider secret is still environment-only');