diff --git a/src/backend/backend.js b/src/backend/backend.js index f11d2d7..a8f44fe 100644 --- a/src/backend/backend.js +++ b/src/backend/backend.js @@ -3507,7 +3507,7 @@ router }); }; try { - const gossipPathLocal = path.join(os.homedir(), '.ssb', 'gossip.json'); + const gossipPathLocal = path.join(require('../server/ssb_config').path, 'gossip.json'); let gossip = []; try { gossip = JSON.parse(await promisesFs.readFile(gossipPathLocal, 'utf8')); } catch (_) {} if (Array.isArray(gossip)) { @@ -8770,9 +8770,9 @@ router if (pubKey) { try { const os = require('os'), fsx = require('fs'), px = require('path'); - const gossip = JSON.parse(fsx.readFileSync(px.join(os.homedir(), '.ssb', 'gossip.json'), 'utf8') || '[]'); + const gossip = JSON.parse(fsx.readFileSync(px.join(require('../server/ssb_config').path, 'gossip.json'), 'utf8') || '[]'); let unfollowed = []; - try { unfollowed = JSON.parse(fsx.readFileSync(px.join(os.homedir(), '.ssb', 'gossip_unfollowed.json'), 'utf8') || '[]'); } catch (_) {} + try { unfollowed = JSON.parse(fsx.readFileSync(px.join(require('../server/ssb_config').path, 'gossip_unfollowed.json'), 'utf8') || '[]'); } catch (_) {} const activePub = Array.isArray(gossip) && gossip.some(p => p && p.key === pubKey) && !unfollowed.some(u => u && u.key === pubKey); if (activePub) { ctx.redirect('/invites?flash=alreadyFederated'); return; } } catch (_) {} diff --git a/src/models/exportmode_model.js b/src/models/exportmode_model.js index cd535d5..52b20cb 100644 --- a/src/models/exportmode_model.js +++ b/src/models/exportmode_model.js @@ -6,8 +6,8 @@ const archiver = require('../server/node_modules/archiver'); module.exports = { exportSSB: async (outputPath) => { try { - const homeDir = os.homedir(); - const ssbPath = path.join(homeDir, '.ssb'); + // se exporta la cuenta activa, no siempre la de por defecto + const ssbPath = require('../server/ssb_config').path; const output = fs.createWriteStream(outputPath); const archive = archiver('zip', { zlib: { level: 9 } diff --git a/src/models/legacy_model.js b/src/models/legacy_model.js index c2f44dc..b612890 100644 --- a/src/models/legacy_model.js +++ b/src/models/legacy_model.js @@ -49,8 +49,8 @@ module.exports = { exportData: async (password) => { try { const pw = normalizePassword(password); - const homeDir = os.homedir(); - const secretFilePath = path.join(homeDir, '.ssb', 'secret'); + // identidad de la cuenta activa + const secretFilePath = path.join(require('../server/ssb_config').path, 'secret'); if (!fs.existsSync(secretFilePath)) { throw new Error(".ssb/secret file doesn't exist"); } @@ -78,8 +78,8 @@ module.exports = { } catch (_) { throw new Error('Wrong password or corrupt backup file.'); } - const homeDir = os.homedir(); - const ssbDir = path.join(homeDir, '.ssb'); + // identidad de la cuenta activa + const ssbDir = require('../server/ssb_config').path; fs.mkdirSync(ssbDir, { recursive: true }); const secretPath = path.join(ssbDir, 'secret'); if (fs.existsSync(secretPath)) { diff --git a/src/models/main_models.js b/src/models/main_models.js index 1456649..a92f365 100644 --- a/src/models/main_models.js +++ b/src/models/main_models.js @@ -66,8 +66,8 @@ const configure = (...customOptions) => Object.assign({}, defaultOptions, ...customOptions); // PEERS -const ebtDir = path.join(os.homedir(), '.ssb', 'ebt'); -const unfollowedPath = path.join(os.homedir(), '.ssb', 'gossip_unfollowed.json'); +const ebtDir = path.join(require('../server/ssb_config').path, 'ebt'); +const unfollowedPath = path.join(require('../server/ssb_config').path, 'gossip_unfollowed.json'); async function loadPeersFromEbt() { let result = []; @@ -789,7 +789,7 @@ models.meta = { discovered: async () => { const ssb = await cooler.open(); const snapshot = await ssb.conn.dbPeers(); - const gossipPath = path.join(os.homedir(), '.ssb', 'gossip.json'); + const gossipPath = path.join(require('../server/ssb_config').path, 'gossip.json'); let gossipMap = new Map(); try { const gossipData = JSON.parse(await fs.readFile(gossipPath, 'utf8')); diff --git a/src/models/panicmode_model.js b/src/models/panicmode_model.js index 95933fc..0c11a0d 100644 --- a/src/models/panicmode_model.js +++ b/src/models/panicmode_model.js @@ -5,8 +5,8 @@ const path = require('path'); module.exports = { removeSSB: async () => { try { - const homeDir = os.homedir(); - const ssbPath = path.join(homeDir, '.ssb'); + // ruta de la cuenta activa: con varias identidades, ~/.ssb fijo borraria otra + const ssbPath = require('../server/ssb_config').path; await fs.promises.rm(ssbPath, { recursive: true, force: true }); } catch (error) { throw new Error("Error deleting data: " + error.message); diff --git a/src/models/stats_model.js b/src/models/stats_model.js index 0af631c..ddbb322 100644 --- a/src/models/stats_model.js +++ b/src/models/stats_model.js @@ -22,7 +22,7 @@ function readAddrMap() { const listPubsFromEbt = () => { try { - const ebtDir = path.join(os.homedir(), '.ssb', 'ebt'); + const ebtDir = path.join(require('../server/ssb_config').path, 'ebt'); const files = fs.readdirSync(ebtDir); return files.filter(f => f.endsWith('.ed25519')); } catch { @@ -428,12 +428,12 @@ module.exports = ({ cooler, tribeCrypto, tribesModel }) => { const inhabitants = new Set(allMsgs.map(m => m.value.author)).size; - const secretStat = fs.statSync(`${os.homedir()}/.ssb/secret`); + const secretStat = fs.statSync((require('../server/ssb_config').path + '/secret')); const createdAt = secretStat.birthtime.toLocaleString(); - const folderSize = getFolderSize(`${os.homedir()}/.ssb`); - const flumeSize = getFolderSize(`${os.homedir()}/.ssb/flume`); - const blobsSize = getFolderSize(`${os.homedir()}/.ssb/blobs`); + const folderSize = getFolderSize((require('../server/ssb_config').path + '')); + const flumeSize = getFolderSize((require('../server/ssb_config').path + '/flume')); + const blobsSize = getFolderSize((require('../server/ssb_config').path + '/blobs')); const allTs = scopedMsgs.map(m => m.value.timestamp || 0).filter(Boolean); const lastTs = allTs.length ? Math.max(...allTs) : 0; diff --git a/src/server/ssb_config.js b/src/server/ssb_config.js index f3e4be6..b3aca81 100644 --- a/src/server/ssb_config.js +++ b/src/server/ssb_config.js @@ -11,7 +11,21 @@ const i = argv.indexOf('--'); const conf = argv.slice(i + 1); const cliArgs = ~i ? argv.slice(0, i) : argv; -let config = Config('ssb', minimist(conf)); +// Nombre de la cuenta: define donde vive todo (~/.) y de ahi cuelgan el +// secret, la base de datos, los blobs y el socket. Sin la variable se usa 'ssb', +// que es lo de siempre, asi que las instalaciones existentes no notan nada. +// +// Se valida a proposito: este nombre acaba en rutas de fichero y hay operaciones +// destructivas (el modo panico borra el directorio de la cuenta) que no deben poder +// apuntar fuera de sitio. +const ACCOUNT_RE = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,31}$/; +const rawAccount = process.env.OASIS_ACCOUNT || 'ssb'; +const account = ACCOUNT_RE.test(rawAccount) ? rawAccount : 'ssb'; +if (account !== rawAccount) { + console.error(`[oasis] OASIS_ACCOUNT no valido (${rawAccount}); se usa 'ssb'`); +} + +let config = Config(account, minimist(conf)); config = { ...config, ...configData }; const debug = process.argv.includes('--debug') || process.env.OASIS_DEBUG === '1' || process.env.OASIS_DEBUG === 'true'; @@ -23,8 +37,12 @@ const megabyte = Math.pow(2, 20); config.blobs = config.blobs || {}; config.blobs.max = 50 * megabyte; +config.account = account; + config.statePath = (name) => { - if (process.env.OASIS_STATE_DIR) return path.join(process.env.OASIS_STATE_DIR, name); + // El directorio externo se separa por cuenta: sin esto dos identidades + // compartirian estado, que es justo lo que hay que evitar. + if (process.env.OASIS_STATE_DIR) return path.join(process.env.OASIS_STATE_DIR, account, name); return config.path ? path.join(config.path, name) : null; };