ssb: base de multicuenta, igual que en la version de movil

Se traen los mismos cambios: la cuenta sale de OASIS_ACCOUNT con el nombre validado,
statePath se separa por cuenta, y los doce sitios que construian la ruta como
os.homedir() + '/.ssb' pasan a usar la de la cuenta activa.

El mas importante sigue siendo panicmode_model: con varias identidades habria borrado
la que no era.

Tambien entra el gate que faltaba en renderMobileTopbar, sin el cual la cabecera de
movil se dibujaba encima de la de upstream en escritorio.

La configuracion de escritorio no se toca: sigue con tema Dark-SNH y todos los
modulos.

Verificado arrancando sin OASIS_MOBILE: ocho rutas OK, incluidas /peers y /stats que
son las que leen gossip.json, y cero rastro de la interfaz movil.
This commit is contained in:
SITO 2026-08-19 00:45:40 +02:00
parent ddd2787b73
commit f79573b317
7 changed files with 39 additions and 21 deletions

View file

@ -3507,7 +3507,7 @@ router
}); });
}; };
try { try {
const gossipPathLocal = path.join(os.homedir(), '.ssb', 'gossip.json'); const gossipPathLocal = path.join(require('../server/ssb_config').path, 'gossip.json');
let gossip = []; let gossip = [];
try { gossip = JSON.parse(await promisesFs.readFile(gossipPathLocal, 'utf8')); } catch (_) {} try { gossip = JSON.parse(await promisesFs.readFile(gossipPathLocal, 'utf8')); } catch (_) {}
if (Array.isArray(gossip)) { if (Array.isArray(gossip)) {
@ -8770,9 +8770,9 @@ router
if (pubKey) { if (pubKey) {
try { try {
const os = require('os'), fsx = require('fs'), px = require('path'); 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 = []; 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); 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; } if (activePub) { ctx.redirect('/invites?flash=alreadyFederated'); return; }
} catch (_) {} } catch (_) {}

View file

@ -6,8 +6,8 @@ const archiver = require('../server/node_modules/archiver');
module.exports = { module.exports = {
exportSSB: async (outputPath) => { exportSSB: async (outputPath) => {
try { try {
const homeDir = os.homedir(); // se exporta la cuenta activa, no siempre la de por defecto
const ssbPath = path.join(homeDir, '.ssb'); const ssbPath = require('../server/ssb_config').path;
const output = fs.createWriteStream(outputPath); const output = fs.createWriteStream(outputPath);
const archive = archiver('zip', { const archive = archiver('zip', {
zlib: { level: 9 } zlib: { level: 9 }

View file

@ -49,8 +49,8 @@ module.exports = {
exportData: async (password) => { exportData: async (password) => {
try { try {
const pw = normalizePassword(password); const pw = normalizePassword(password);
const homeDir = os.homedir(); // identidad de la cuenta activa
const secretFilePath = path.join(homeDir, '.ssb', 'secret'); const secretFilePath = path.join(require('../server/ssb_config').path, 'secret');
if (!fs.existsSync(secretFilePath)) { if (!fs.existsSync(secretFilePath)) {
throw new Error(".ssb/secret file doesn't exist"); throw new Error(".ssb/secret file doesn't exist");
} }
@ -78,8 +78,8 @@ module.exports = {
} catch (_) { } catch (_) {
throw new Error('Wrong password or corrupt backup file.'); throw new Error('Wrong password or corrupt backup file.');
} }
const homeDir = os.homedir(); // identidad de la cuenta activa
const ssbDir = path.join(homeDir, '.ssb'); const ssbDir = require('../server/ssb_config').path;
fs.mkdirSync(ssbDir, { recursive: true }); fs.mkdirSync(ssbDir, { recursive: true });
const secretPath = path.join(ssbDir, 'secret'); const secretPath = path.join(ssbDir, 'secret');
if (fs.existsSync(secretPath)) { if (fs.existsSync(secretPath)) {

View file

@ -66,8 +66,8 @@ const configure = (...customOptions) =>
Object.assign({}, defaultOptions, ...customOptions); Object.assign({}, defaultOptions, ...customOptions);
// PEERS // PEERS
const ebtDir = path.join(os.homedir(), '.ssb', 'ebt'); const ebtDir = path.join(require('../server/ssb_config').path, 'ebt');
const unfollowedPath = path.join(os.homedir(), '.ssb', 'gossip_unfollowed.json'); const unfollowedPath = path.join(require('../server/ssb_config').path, 'gossip_unfollowed.json');
async function loadPeersFromEbt() { async function loadPeersFromEbt() {
let result = []; let result = [];
@ -789,7 +789,7 @@ models.meta = {
discovered: async () => { discovered: async () => {
const ssb = await cooler.open(); const ssb = await cooler.open();
const snapshot = await ssb.conn.dbPeers(); 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(); let gossipMap = new Map();
try { try {
const gossipData = JSON.parse(await fs.readFile(gossipPath, 'utf8')); const gossipData = JSON.parse(await fs.readFile(gossipPath, 'utf8'));

View file

@ -5,8 +5,8 @@ const path = require('path');
module.exports = { module.exports = {
removeSSB: async () => { removeSSB: async () => {
try { try {
const homeDir = os.homedir(); // ruta de la cuenta activa: con varias identidades, ~/.ssb fijo borraria otra
const ssbPath = path.join(homeDir, '.ssb'); const ssbPath = require('../server/ssb_config').path;
await fs.promises.rm(ssbPath, { recursive: true, force: true }); await fs.promises.rm(ssbPath, { recursive: true, force: true });
} catch (error) { } catch (error) {
throw new Error("Error deleting data: " + error.message); throw new Error("Error deleting data: " + error.message);

View file

@ -22,7 +22,7 @@ function readAddrMap() {
const listPubsFromEbt = () => { const listPubsFromEbt = () => {
try { try {
const ebtDir = path.join(os.homedir(), '.ssb', 'ebt'); const ebtDir = path.join(require('../server/ssb_config').path, 'ebt');
const files = fs.readdirSync(ebtDir); const files = fs.readdirSync(ebtDir);
return files.filter(f => f.endsWith('.ed25519')); return files.filter(f => f.endsWith('.ed25519'));
} catch { } catch {
@ -428,12 +428,12 @@ module.exports = ({ cooler, tribeCrypto, tribesModel }) => {
const inhabitants = new Set(allMsgs.map(m => m.value.author)).size; 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 createdAt = secretStat.birthtime.toLocaleString();
const folderSize = getFolderSize(`${os.homedir()}/.ssb`); const folderSize = getFolderSize((require('../server/ssb_config').path + ''));
const flumeSize = getFolderSize(`${os.homedir()}/.ssb/flume`); const flumeSize = getFolderSize((require('../server/ssb_config').path + '/flume'));
const blobsSize = getFolderSize(`${os.homedir()}/.ssb/blobs`); const blobsSize = getFolderSize((require('../server/ssb_config').path + '/blobs'));
const allTs = scopedMsgs.map(m => m.value.timestamp || 0).filter(Boolean); const allTs = scopedMsgs.map(m => m.value.timestamp || 0).filter(Boolean);
const lastTs = allTs.length ? Math.max(...allTs) : 0; const lastTs = allTs.length ? Math.max(...allTs) : 0;

View file

@ -11,7 +11,21 @@ const i = argv.indexOf('--');
const conf = argv.slice(i + 1); const conf = argv.slice(i + 1);
const cliArgs = ~i ? argv.slice(0, i) : argv; const cliArgs = ~i ? argv.slice(0, i) : argv;
let config = Config('ssb', minimist(conf)); // Nombre de la cuenta: define donde vive todo (~/.<cuenta>) 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 }; config = { ...config, ...configData };
const debug = process.argv.includes('--debug') || process.env.OASIS_DEBUG === '1' || process.env.OASIS_DEBUG === 'true'; 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 = config.blobs || {};
config.blobs.max = 50 * megabyte; config.blobs.max = 50 * megabyte;
config.account = account;
config.statePath = (name) => { 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; return config.path ? path.join(config.path, name) : null;
}; };