/** Libera defaults + ~/.irc config/secrets. */ function bareIrcRandomSuffix(n) { var alphabet = 'abcdefghijkmnpqrstuvwxyz23456789' var out = '' var i var len = n > 0 ? n : 4 for (i = 0; i < len; i++) { out += alphabet.charAt(Math.floor(Math.random() * alphabet.length)) } return out } function bareIrcRandomNick() { return ('os' + bareIrcRandomSuffix(5)).slice(0, 16) } function bareIrcNickLooksMachine(nick) { var s = String(nick || '') if (!s) return true if (/^[0-9a-f]{8,16}$/i.test(s)) return true if (/^[0-9a-f]{12}$/i.test(s)) return true if (/^[a-z0-9]{10,}-[a-z0-9]{4,}$/i.test(s)) return true return false } function bareIrcHostLooksLibera(host) { var h = String(host || '') .trim() .toLowerCase() return h === 'libera.chat' || h.endsWith('.libera.chat') } var BARE_IRC_LIBERA = { name: 'libera', host: 'irc.libera.chat', port: 6697, tls: true, regional: { eu: 'irc.eu.libera.chat', us: 'irc.us.libera.chat', au: 'irc.au.libera.chat', ea: 'irc.ea.libera.chat', ipv4: 'irc.ipv4.libera.chat', ipv6: 'irc.ipv6.libera.chat' } } function bareIrcHome(ctx) { var env = ctx && ctx.env && typeof ctx.env === 'object' ? ctx.env : {} if (env.HOME) return String(env.HOME) if (typeof ctx.bareOsResolveHome === 'function') { try { return String(ctx.bareOsResolveHome() || '') } catch (e) { /* ignore */ } } return '/home/guest' } function bareIrcConfigPaths(ctx) { var home = bareIrcHome(ctx).replace(/\/+$/, '') return { dir: home + '/.irc', config: home + '/.irc/config.json', secrets: home + '/.irc/secrets.json', bindings: home + '/.irc/bindings.json' } } function bareIrcReadJsonFile(ctx, path) { if (!ctx || !ctx.vfs || typeof ctx.vfs.readFile !== 'function') return null try { var buf = ctx.vfs.readFile(path) if (buf && typeof buf.then === 'function') return buf if (!buf) return null var t = ctx.b4a && typeof ctx.b4a.toString === 'function' ? ctx.b4a.toString(buf) : String(buf) t = String(t || '').trim() if (!t) return null return JSON.parse(t) } catch (e) { return null } } async function bareIrcLoadConfig(ctx) { var paths = bareIrcConfigPaths(ctx) var raw = bareIrcReadJsonFile(ctx, paths.config) if (raw && typeof raw.then === 'function') { try { var buf = await raw if (!buf) raw = null else { var t = ctx.b4a && typeof ctx.b4a.toString === 'function' ? ctx.b4a.toString(buf) : String(buf) raw = t && String(t).trim() ? JSON.parse(String(t).trim()) : null } } catch (e) { raw = null } } var sec = bareIrcReadJsonFile(ctx, paths.secrets) if (sec && typeof sec.then === 'function') { try { var sb = await sec if (!sb) sec = null else { var st = ctx.b4a && typeof ctx.b4a.toString === 'function' ? ctx.b4a.toString(sb) : String(sb) sec = st && String(st).trim() ? JSON.parse(String(st).trim()) : null } } catch (e2) { sec = null } } return { paths: paths, config: raw && typeof raw === 'object' ? raw : {}, secrets: sec && typeof sec === 'object' ? sec : {} } } function bareIrcResolveConnect(ctx, flags, loaded) { var env = ctx && ctx.env && typeof ctx.env === 'object' ? ctx.env : {} var cfg = (loaded && loaded.config) || {} var sec = (loaded && loaded.secrets) || {} var servers = Array.isArray(cfg.servers) ? cfg.servers : [] var named = flags.network || flags.host || '' var srv = servers[0] || {} if (named) { for (var i = 0; i < servers.length; i++) { if (servers[i] && servers[i].name === named) srv = servers[i] } if (named === 'libera' || named === 'irc.libera.chat') { srv = Object.assign({}, BARE_IRC_LIBERA, srv) } else if (BARE_IRC_LIBERA.regional[named]) { srv = Object.assign({}, BARE_IRC_LIBERA, srv, { host: BARE_IRC_LIBERA.regional[named] }) } } var host = flags.host || srv.host || BARE_IRC_LIBERA.host if (host === 'libera') host = BARE_IRC_LIBERA.host var port = flags.port != null ? flags.port : srv.port || BARE_IRC_LIBERA.port var tls = flags.tls != null ? flags.tls : srv.tls !== false var nick = flags.nick || cfg.nick || env.BARE_IRC_NICK || '' var generatedNick = false if (!nick) { var candidate = env.USER || env.LOGNAME || '' if (candidate && !bareIrcNickLooksMachine(candidate)) nick = candidate } if (!nick) { nick = bareIrcRandomNick() generatedNick = true } var saslUser = flags.saslUser || cfg.saslUser || sec.saslUser || '' var saslPass = flags.saslPass != null ? flags.saslPass : sec.saslPass || '' var autojoin = Array.isArray(flags.autojoin) ? flags.autojoin : Array.isArray(cfg.autojoin) ? cfg.autojoin : [] return { host: host, port: port, tls: tls, insecurePlain: !!flags.insecurePlain, nick: String(nick).slice(0, 16), generatedNick: generatedNick, username: flags.username || cfg.username || 'bareos', realname: flags.realname || cfg.realname || 'Bare OS irc', pass: flags.pass || sec.serverPass || '', saslUser: saslUser, saslPass: saslPass, autojoin: autojoin, shareChannels: cfg.shareChannels === true, network: srv.name || (bareIrcHostLooksLibera(host) ? 'libera' : host) } } function bareIrcParseFlags(argv) { var args = argv.slice(1) var flags = { help: false, json: false, tls: null, insecurePlain: false, host: '', port: null, nick: '', saslUser: '', network: '', rest: [] } for (var i = 0; i < args.length; i++) { var a = args[i] if (a === '-h' || a === '--help') flags.help = true else if (a === '--json') flags.json = true else if (a === '--tls') flags.tls = true else if (a === '--plain') flags.tls = false else if (a === '--insecure-plain') flags.insecurePlain = true else if (a === '--host' && args[i + 1]) flags.host = args[++i] else if (a === '--port' && args[i + 1]) flags.port = parseInt(args[++i], 10) else if (a === '--nick' && args[i + 1]) flags.nick = args[++i] else if (a === '--sasl-user' && args[i + 1]) flags.saslUser = args[++i] else if (a === '--network' && args[i + 1]) flags.network = args[++i] else if (a && a.charAt(0) !== '-') flags.rest.push(a) } if (flags.rest[0] && !flags.host && !flags.network) { var r0 = flags.rest[0] if ( r0 === 'libera' || r0 === 'eu' || r0 === 'us' || r0 === 'au' || r0 === 'ea' || r0.indexOf('.') >= 0 ) { flags.network = r0 flags.rest = flags.rest.slice(1) } } return flags } async function bareIrcRememberNick(ctx, nick) { var n = String(nick || '').trim() if (!n) return false if (!ctx || !ctx.vfs || typeof ctx.vfs.writeFile !== 'function') return false var paths = bareIrcConfigPaths(ctx) var loaded = await bareIrcLoadConfig(ctx) var cfg = loaded.config || {} if (cfg.nick) return false cfg.nick = n try { if (typeof ctx.vfs.mkdir === 'function') { var mk = ctx.vfs.mkdir(paths.dir, { recursive: true }) if (mk && typeof mk.then === 'function') await mk } var body = JSON.stringify(cfg, null, 2) var w = ctx.vfs.writeFile(paths.config, body) if (w && typeof w.then === 'function') await w return true } catch (e) { return false } }