hid: add WebIRC support

Such clients can only be identified through STATS L.

It's a bit weird to abuse the "port" field this way,
but right now, it serves its purpose.
This commit is contained in:
Přemysl Eric Janouch 2022-03-15 18:58:27 +01:00
parent b832a38ca6
commit 9603456cd6
Signed by: p
GPG Key ID: A0420B94F92B9493

View File

@ -1,5 +1,5 @@
// //
// Copyright (c) 2014 - 2018, Přemysl Eric Janouch <p@janouch.name> // Copyright (c) 2014 - 2022, Přemysl Eric Janouch <p@janouch.name>
// //
// Permission to use, copy, modify, and/or distribute this software for any // Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted. // purpose with or without fee is hereby granted.
@ -414,6 +414,7 @@ var configTable = []simpleConfigItem{
{"bind", ":6667", "Bind addresses of the IRC server"}, {"bind", ":6667", "Bind addresses of the IRC server"},
{"tls_cert", "", "Server TLS certificate (PEM)"}, {"tls_cert", "", "Server TLS certificate (PEM)"},
{"tls_key", "", "Server TLS private key (PEM)"}, {"tls_key", "", "Server TLS private key (PEM)"},
{"webirc_password", "", "Password for WebIRC"},
{"operators", "", "IRCop TLS certificate SHA-256 fingerprints"}, {"operators", "", "IRCop TLS certificate SHA-256 fingerprints"},
@ -1437,6 +1438,44 @@ var ircCapHandlers = map[string]func(*client, *ircCapArgs){
// XXX: Maybe these also deserve to be methods for client? They operate on // XXX: Maybe these also deserve to be methods for client? They operate on
// global state, though. // global state, though.
func ircParseWEBIRCOptions(options string, out map[string]string) {
for _, option := range strings.Split(options, " ") {
if equal := strings.IndexByte(option, '='); equal < 0 {
out[option] = ""
} else {
out[option[:equal]] = ircUnescapeMessageTag(option[equal+1:])
}
}
}
func ircHandleWEBIRC(msg *message, c *client) {
if len(msg.params) < 4 {
c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
return
}
password, gateway, hostname := msg.params[0], msg.params[1], msg.params[2]
if config["webirc_password"] != password {
c.closeLink("Invalid WebIRC password")
return
}
options := make(map[string]string)
if len(msg.params) >= 5 {
ircParseWEBIRCOptions(msg.params[4], options)
}
c.hostname = hostname
c.port = "WebIRC-" + gateway
c.address = net.JoinHostPort(hostname, c.port)
// Note that this overrides the gateway's certificate, conditionally.
fp, _ := options["certfp-sha-256"]
if _, secure := options["secure"]; secure && ircIsValidFingerprint(fp) {
c.tlsCertFingerprint = strings.ToLower(fp)
}
}
func ircHandleCAP(msg *message, c *client) { func ircHandleCAP(msg *message, c *client) {
if len(msg.params) < 1 { if len(msg.params) < 1 {
c.sendReply(ERR_NEEDMOREPARAMS, msg.command) c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
@ -2908,6 +2947,7 @@ func ircHandleDIE(msg *message, c *client) {
// TODO: Add a minimal parameter count? // TODO: Add a minimal parameter count?
// TODO: Add a field for oper-only commands? Use flags? // TODO: Add a field for oper-only commands? Use flags?
var ircHandlers = map[string]*ircCommand{ var ircHandlers = map[string]*ircCommand{
"WEBIRC": {false, ircHandleWEBIRC, 0, 0},
"CAP": {false, ircHandleCAP, 0, 0}, "CAP": {false, ircHandleCAP, 0, 0},
"PASS": {false, ircHandlePASS, 0, 0}, "PASS": {false, ircHandlePASS, 0, 0},
"NICK": {false, ircHandleNICK, 0, 0}, "NICK": {false, ircHandleNICK, 0, 0},