256 lines
7.3 KiB
JavaScript
256 lines
7.3 KiB
JavaScript
/** 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
|
|
}
|
|
}
|