From 9603456cd6f76554f0be8af1eb23c20872ad8e3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Eric=20Janouch?= Date: Tue, 15 Mar 2022 18:58:27 +0100 Subject: 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. --- hid/main.go | 50 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/hid/main.go b/hid/main.go index fd8d8fb..43a04f2 100644 --- a/hid/main.go +++ b/hid/main.go @@ -1,5 +1,5 @@ // -// Copyright (c) 2014 - 2018, Přemysl Eric Janouch +// Copyright (c) 2014 - 2022, Přemysl Eric Janouch // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted. @@ -414,6 +414,7 @@ var configTable = []simpleConfigItem{ {"bind", ":6667", "Bind addresses of the IRC server"}, {"tls_cert", "", "Server TLS certificate (PEM)"}, {"tls_key", "", "Server TLS private key (PEM)"}, + {"webirc_password", "", "Password for WebIRC"}, {"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 // 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) { if len(msg.params) < 1 { c.sendReply(ERR_NEEDMOREPARAMS, msg.command) @@ -2908,10 +2947,11 @@ func ircHandleDIE(msg *message, c *client) { // TODO: Add a minimal parameter count? // TODO: Add a field for oper-only commands? Use flags? var ircHandlers = map[string]*ircCommand{ - "CAP": {false, ircHandleCAP, 0, 0}, - "PASS": {false, ircHandlePASS, 0, 0}, - "NICK": {false, ircHandleNICK, 0, 0}, - "USER": {false, ircHandleUSER, 0, 0}, + "WEBIRC": {false, ircHandleWEBIRC, 0, 0}, + "CAP": {false, ircHandleCAP, 0, 0}, + "PASS": {false, ircHandlePASS, 0, 0}, + "NICK": {false, ircHandleNICK, 0, 0}, + "USER": {false, ircHandleUSER, 0, 0}, "USERHOST": {true, ircHandleUSERHOST, 0, 0}, "LUSERS": {true, ircHandleLUSERS, 0, 0}, -- cgit v1.2.3