summaryrefslogtreecommitdiff
path: root/deprecated-webircgateway/pkg
diff options
context:
space:
mode:
authorMistivia <i@mistivia.com>2025-11-05 15:34:49 +0800
committerMistivia <i@mistivia.com>2025-11-05 15:34:49 +0800
commit95caa5bdaff4e5b5a924a9141b51c756a57abc0f (patch)
treebb0ff8eddfe8a06558317464cea14405e76b7ebc /deprecated-webircgateway/pkg
parent8532af453ccc9071ddc919b063788d6b496af991 (diff)
remove deprecated
Diffstat (limited to 'deprecated-webircgateway/pkg')
-rw-r--r--deprecated-webircgateway/pkg/dnsbl/dnsbl.go121
-rw-r--r--deprecated-webircgateway/pkg/identd/identd.go86
-rw-r--r--deprecated-webircgateway/pkg/identd/rpcclient.go59
-rw-r--r--deprecated-webircgateway/pkg/irc/isupport.go56
-rw-r--r--deprecated-webircgateway/pkg/irc/message.go217
-rw-r--r--deprecated-webircgateway/pkg/irc/state.go79
-rw-r--r--deprecated-webircgateway/pkg/proxy/proxy.go129
-rw-r--r--deprecated-webircgateway/pkg/proxy/server.go237
-rw-r--r--deprecated-webircgateway/pkg/recaptcha/recaptcha.go59
-rw-r--r--deprecated-webircgateway/pkg/webircgateway/client.go741
-rw-r--r--deprecated-webircgateway/pkg/webircgateway/client_command_handlers.go495
-rw-r--r--deprecated-webircgateway/pkg/webircgateway/config.go385
-rw-r--r--deprecated-webircgateway/pkg/webircgateway/gateway.go278
-rw-r--r--deprecated-webircgateway/pkg/webircgateway/gateway_utils.go133
-rw-r--r--deprecated-webircgateway/pkg/webircgateway/hooks.go152
-rw-r--r--deprecated-webircgateway/pkg/webircgateway/letsencrypt.go41
-rw-r--r--deprecated-webircgateway/pkg/webircgateway/messagetags.go103
-rw-r--r--deprecated-webircgateway/pkg/webircgateway/transport_kiwiirc.go206
-rw-r--r--deprecated-webircgateway/pkg/webircgateway/transport_sockjs.go107
-rw-r--r--deprecated-webircgateway/pkg/webircgateway/transport_tcp.go113
-rw-r--r--deprecated-webircgateway/pkg/webircgateway/transport_websocket.go126
-rw-r--r--deprecated-webircgateway/pkg/webircgateway/utils.go147
22 files changed, 0 insertions, 4070 deletions
diff --git a/deprecated-webircgateway/pkg/dnsbl/dnsbl.go b/deprecated-webircgateway/pkg/dnsbl/dnsbl.go
deleted file mode 100644
index 318102e..0000000
--- a/deprecated-webircgateway/pkg/dnsbl/dnsbl.go
+++ /dev/null
@@ -1,121 +0,0 @@
-package dnsbl
-
-import (
- "encoding/hex"
- "fmt"
- "net"
- "strings"
-)
-
-type ResultList struct {
- Listed bool
- Results []Result
-}
-
-/*
-Result holds the individual IP lookup results for each RBL search
-*/
-type Result struct {
- // Blacklist is the DNSBL server that gave this result
- Blacklist string
- // Address is the IP address that was searched
- Address string
- // Listed indicates whether or not the IP was on the RBL
- Listed bool
- // RBL lists sometimes add extra information as a TXT record
- // if any info is present, it will be stored here.
- Text string
- // Error represents any error that was encountered (DNS timeout, host not
- // found, etc.) if any
- Error bool
- // ErrorType is the type of error encountered if any
- ErrorType error
-}
-
-/*
-Convert an IP to a hostname ready for a dnsbl lookup
-127.0.0.1 becomes 1.0.0.127
-1234:1234:1234:1234:1234:1234:1234:1234 becomes 4.3.2.1.4.3.2.1.4.3.2.1.4.3.2.1.4.3.2.1.4.3.2.1.4.3.2.1.4.3.2.1
-*/
-func toDnsBlHostname(ip net.IP) string {
- if ip.To4() != nil {
- // IPv4
- // Reverse the complete octects
- splitAddress := strings.Split(ip.String(), ".")
- for i, j := 0, len(splitAddress)-1; i < len(splitAddress)/2; i, j = i+1, j-1 {
- splitAddress[i], splitAddress[j] = splitAddress[j], splitAddress[i]
- }
-
- return strings.Join(splitAddress, ".")
- }
-
- // IPv6
- // Remove all : from a full expanded address, then reverse all the hex characters
- ipv6Str := expandIPv6(ip)
- addrHexStr := strings.ReplaceAll(ipv6Str, ":", "")
- chars := []rune(addrHexStr)
- for i, j := 0, len(chars)-1; i < j; i, j = i+1, j-1 {
- chars[i], chars[j] = chars[j], chars[i]
- }
-
- return strings.Join(strings.Split(string(chars), ""), ".")
-}
-
-func expandIPv6(ip net.IP) string {
- dst := make([]byte, hex.EncodedLen(len(ip)))
- _ = hex.Encode(dst, ip)
- return string(dst[0:4]) + ":" +
- string(dst[4:8]) + ":" +
- string(dst[8:12]) + ":" +
- string(dst[12:16]) + ":" +
- string(dst[16:20]) + ":" +
- string(dst[20:24]) + ":" +
- string(dst[24:28]) + ":" +
- string(dst[28:])
-}
-
-func query(rbl string, host string, r *Result) {
- r.Listed = false
-
- lookup := fmt.Sprintf("%s.%s", host, rbl)
- res, err := net.LookupHost(lookup)
-
- if len(res) > 0 {
- r.Listed = true
- txt, _ := net.LookupTXT(lookup)
- if len(txt) > 0 {
- r.Text = txt[0]
- }
- }
- if err != nil {
- r.Error = true
- r.ErrorType = err
- }
-
- return
-}
-
-func Lookup(dnsblList []string, targetHost string) (r ResultList) {
- ip, err := net.LookupIP(targetHost)
- if err != nil {
- return
- }
-
- for _, dnsbl := range dnsblList {
- for _, addr := range ip {
- res := Result{}
- res.Blacklist = dnsbl
- res.Address = addr.String()
-
- addr := toDnsBlHostname(addr)
- query(dnsbl, addr, &res)
- r.Results = append(r.Results, res)
-
- if res.Listed {
- r.Listed = true
- }
- }
- }
-
- return
-}
diff --git a/deprecated-webircgateway/pkg/identd/identd.go b/deprecated-webircgateway/pkg/identd/identd.go
deleted file mode 100644
index 9a84d76..0000000
--- a/deprecated-webircgateway/pkg/identd/identd.go
+++ /dev/null
@@ -1,86 +0,0 @@
-package identd
-
-import (
- "fmt"
- "net"
- "net/textproto"
- "strings"
- "sync"
-)
-
-// Server - An IdentD server
-type Server struct {
- Entries map[string]string
- EntriesLock sync.Mutex
-}
-
-// NewIdentdServer - Create a new IdentdServer instance
-func NewIdentdServer() Server {
- return Server{
- Entries: make(map[string]string),
- }
-}
-
-// AddIdent - Add an ident to be looked up
-func (i *Server) AddIdent(localPort, remotePort int, ident string, iface string) {
- i.EntriesLock.Lock()
- i.Entries[fmt.Sprintf("%d-%d", localPort, remotePort)] = ident
- i.EntriesLock.Unlock()
-}
-
-// RemoveIdent - Remove an ident from being looked up
-func (i *Server) RemoveIdent(localPort, remotePort int, iface string) {
- i.EntriesLock.Lock()
- delete(i.Entries, fmt.Sprintf("%d-%d", localPort, remotePort))
- i.EntriesLock.Unlock()
-}
-
-// Run - Start listening for ident lookups
-func (i *Server) Run() error {
- serv, err := net.Listen("tcp", ":113")
- if err != nil {
- return err
- }
-
- go i.ListenForRequests(&serv)
- return nil
-}
-
-// ListenForRequests - Listen on a net.Listener for ident lookups
-func (i *Server) ListenForRequests(serverSocket *net.Listener) {
- for {
- serv := *serverSocket
- client, err := serv.Accept()
- if err != nil {
- break
- }
-
- go func(conn net.Conn) {
- tc := textproto.NewConn(conn)
-
- line, err := tc.ReadLine()
- if err != nil {
- conn.Close()
- return
- }
-
- // Remove all spaces, some servers like to send "%d , %d" but the spec examples use "%d, %d"
- line = strings.ReplaceAll(line, " ", "")
-
- var localPort, remotePort int
- fmt.Sscanf(line, "%d,%d", &localPort, &remotePort)
- if localPort > 0 && remotePort > 0 {
- i.EntriesLock.Lock()
- ident, ok := i.Entries[fmt.Sprintf("%d-%d", localPort, remotePort)]
- i.EntriesLock.Unlock()
- if !ok {
- fmt.Fprintf(conn, "%d, %d : ERROR : NO-USER\r\n", localPort, remotePort)
- } else {
- fmt.Fprintf(conn, "%d, %d : USERID : UNIX : %s\r\n", localPort, remotePort, ident)
- }
- }
-
- conn.Close()
- }(client)
- }
-}
diff --git a/deprecated-webircgateway/pkg/identd/rpcclient.go b/deprecated-webircgateway/pkg/identd/rpcclient.go
deleted file mode 100644
index 37aec3e..0000000
--- a/deprecated-webircgateway/pkg/identd/rpcclient.go
+++ /dev/null
@@ -1,59 +0,0 @@
-package identd
-
-import "net"
-import "fmt"
-import "time"
-
-func MakeRpcClient(appName string) *RpcClient {
- return &RpcClient{AppName: appName}
-}
-
-type RpcClient struct {
- AppName string
- Conn *net.Conn
-}
-
-func (rpc *RpcClient) ConnectAndReconnect(serverAddress string) {
- for {
- if rpc.Conn == nil {
- println("Connecting to identd RPC...")
- rpc.Connect(serverAddress)
- }
-
- time.Sleep(time.Second * 3)
- }
-}
-
-func (rpc *RpcClient) Connect(serverAddress string) error {
- conn, err := net.Dial("tcp", serverAddress)
- if err != nil {
- return err
- }
-
- rpc.Conn = &conn
- rpc.Write("id " + rpc.AppName)
-
- return nil
-}
-
-func (rpc *RpcClient) Write(line string) error {
- if rpc.Conn == nil {
- return fmt.Errorf("not connected")
- }
-
- conn := *rpc.Conn
- _, err := conn.Write([]byte(line + "\n"))
- if err != nil {
- rpc.Conn = nil
- conn.Close()
- }
- return err
-}
-
-func (rpc *RpcClient) AddIdent(lport int, rport int, username string, iface string) {
- rpc.Write(fmt.Sprintf("add %s %d %d %s", username, lport, rport, iface))
-}
-
-func (rpc *RpcClient) RemoveIdent(lport int, rport int, username string, iface string) {
- rpc.Write(fmt.Sprintf("del %d %d %s", lport, rport, iface))
-}
diff --git a/deprecated-webircgateway/pkg/irc/isupport.go b/deprecated-webircgateway/pkg/irc/isupport.go
deleted file mode 100644
index fdb7bee..0000000
--- a/deprecated-webircgateway/pkg/irc/isupport.go
+++ /dev/null
@@ -1,56 +0,0 @@
-package irc
-
-import (
- "strings"
- "sync"
-)
-
-type ISupport struct {
- Received bool
- Injected bool
- Tags map[string]string
- tokens map[string]string
- tokensMutex sync.RWMutex
-}
-
-func (m *ISupport) ClearTokens() {
- m.tokensMutex.Lock()
- m.tokens = make(map[string]string)
- m.tokensMutex.Unlock()
-}
-
-func (m *ISupport) AddToken(tokenPair string) {
- m.tokensMutex.Lock()
- m.addToken(tokenPair)
- m.tokensMutex.Unlock()
-}
-
-func (m *ISupport) AddTokens(tokenPairs []string) {
- m.tokensMutex.Lock()
- for _, tp := range tokenPairs {
- m.addToken(tp)
- }
- m.tokensMutex.Unlock()
-}
-
-func (m *ISupport) HasToken(key string) (ok bool) {
- m.tokensMutex.RLock()
- _, ok = m.tokens[strings.ToUpper(key)]
- m.tokensMutex.RUnlock()
- return
-}
-
-func (m *ISupport) GetToken(key string) (val string) {
- m.tokensMutex.RLock()
- val = m.tokens[strings.ToUpper(key)]
- m.tokensMutex.RUnlock()
- return
-}
-
-func (m *ISupport) addToken(tokenPair string) {
- kv := strings.Split(tokenPair, "=")
- if len(kv) == 1 {
- kv = append(kv, "")
- }
- m.tokens[strings.ToUpper(kv[0])] = kv[1]
-}
diff --git a/deprecated-webircgateway/pkg/irc/message.go b/deprecated-webircgateway/pkg/irc/message.go
deleted file mode 100644
index 18477d6..0000000
--- a/deprecated-webircgateway/pkg/irc/message.go
+++ /dev/null
@@ -1,217 +0,0 @@
-package irc
-
-import (
- "errors"
- "strings"
-)
-
-type Mask struct {
- Nick string
- Username string
- Hostname string
- Mask string
-}
-type Message struct {
- Raw string
- Tags map[string]string
- Prefix *Mask
- Command string
- Params []string
-}
-
-func NewMessage() *Message {
- return &Message{
- Tags: make(map[string]string),
- Prefix: &Mask{},
- }
-}
-
-// GetParam - Get a param value, returning a default value if it doesn't exist
-func (m *Message) GetParam(idx int, def string) string {
- if idx < 0 || idx > len(m.Params)-1 {
- return def
- }
-
- return m.Params[idx]
-}
-
-// GetParamU - Get a param value in uppercase, returning a default value if it doesn't exist
-func (m *Message) GetParamU(idx int, def string) string {
- return strings.ToUpper(m.GetParam(idx, def))
-}
-
-// ToLine - Convert the Message struct to its raw IRC line
-func (m *Message) ToLine() string {
- line := ""
-
- if len(m.Tags) > 0 {
- line += "@"
- tagCount := 0
- for tagName, tagVal := range m.Tags {
- tagCount++
- line += tagName
- if tagVal != "" {
- line += "=" + tagVal
- }
- if tagCount < len(m.Tags) {
- line += ";"
- }
- }
- }
-
- if m.Prefix != nil && (m.Prefix.Nick != "" || m.Prefix.Username != "" || m.Prefix.Hostname != "") {
- prefix := ""
-
- if m.Prefix.Nick != "" {
- prefix += m.Prefix.Nick
- }
-
- if m.Prefix.Username != "" && m.Prefix.Nick != "" {
- prefix += "!" + m.Prefix.Username
- } else if m.Prefix.Username != "" {
- prefix += m.Prefix.Username
- }
-
- if m.Prefix.Hostname != "" && prefix != "" {
- prefix += "@" + m.Prefix.Username
- } else if m.Prefix.Hostname != "" {
- prefix += m.Prefix.Hostname
- }
-
- if line != "" {
- line += " :" + prefix
- } else {
- line += ":" + prefix
- }
- }
-
- if line != "" {
- line += " " + m.Command
- } else {
- line += m.Command
- }
-
- paramLen := len(m.Params)
- for idx, param := range m.Params {
- if idx == paramLen-1 && (strings.Contains(param, " ") || strings.HasPrefix(param, ":")) {
- line += " :" + param
- } else {
- line += " " + param
- }
- }
-
- return line
-}
-
-func createMask(maskStr string) *Mask {
- mask := &Mask{
- Mask: maskStr,
- }
-
- usernameStart := strings.Index(maskStr, "!")
- hostStart := strings.Index(maskStr, "@")
-
- if usernameStart == -1 && hostStart == -1 {
- mask.Nick = maskStr
- } else if usernameStart > -1 && hostStart > -1 {
- mask.Nick = maskStr[0:usernameStart]
- mask.Username = maskStr[usernameStart+1 : hostStart]
- mask.Hostname = maskStr[hostStart+1:]
- } else if usernameStart > -1 && hostStart == -1 {
- mask.Nick = maskStr[0:usernameStart]
- mask.Username = maskStr[usernameStart+1:]
- } else if usernameStart == -1 && hostStart > -1 {
- mask.Username = maskStr[0:hostStart]
- mask.Hostname = maskStr[hostStart+1:]
- }
-
- return mask
-}
-
-// ParseLine - Turn a raw IRC line into a message
-func ParseLine(input string) (*Message, error) {
- line := strings.Trim(input, "\r\n")
-
- message := NewMessage()
- message.Raw = line
-
- token := ""
- rest := ""
-
- token, rest = nextToken(line, false)
- if token == "" {
- return message, errors.New("Empty line")
- }
-
- // Tags. Starts with "@"
- if token[0] == 64 {
- tagsRaw := token[1:]
- tags := strings.Split(tagsRaw, ";")
- for _, tag := range tags {
- parts := strings.Split(tag, "=")
- if len(parts) > 0 && parts[0] == "" {
- continue
- }
-
- if len(parts) == 1 {
- message.Tags[parts[0]] = ""
- } else {
- message.Tags[parts[0]] = parts[1]
- }
- }
-
- token, rest = nextToken(rest, false)
- }
-
- // Prefix. Starts with ":"
- if token != "" && token[0] == 58 {
- message.Prefix = createMask(token[1:])
- token, rest = nextToken(rest, false)
- } else {
- message.Prefix = createMask("")
- }
-
- // Command
- if token == "" {
- return message, errors.New("Missing command")
- }
-
- message.Command = token
-
- // Params
- for {
- token, rest = nextToken(rest, true)
- if token == "" {
- break
- }
-
- message.Params = append(message.Params, token)
- }
-
- return message, nil
-}
-
-func nextToken(s string, allowTrailing bool) (string, string) {
- s = strings.TrimLeft(s, " ")
-
- if len(s) == 0 {
- return "", ""
- }
-
- // The last token (trailing) start with :
- if allowTrailing && s[0] == 58 {
- return s[1:], ""
- }
-
- token := ""
- spaceIdx := strings.Index(s, " ")
- if spaceIdx > -1 {
- token = s[:spaceIdx]
- s = s[spaceIdx+1:]
- } else {
- token = s
- s = ""
- }
-
- return token, s
-}
diff --git a/deprecated-webircgateway/pkg/irc/state.go b/deprecated-webircgateway/pkg/irc/state.go
deleted file mode 100644
index 69480fc..0000000
--- a/deprecated-webircgateway/pkg/irc/state.go
+++ /dev/null
@@ -1,79 +0,0 @@
-package irc
-
-import (
- "strings"
- "sync"
- "time"
-)
-
-type State struct {
- LocalPort int
- RemotePort int
- Username string
- Nick string
- RealName string
- Password string
- Account string
- Modes map[string]string
-
- channelsMutex sync.Mutex
- Channels map[string]*StateChannel
- ISupport *ISupport
-}
-
-type StateChannel struct {
- Name string
- Modes map[string]string
- Joined time.Time
-}
-
-func NewState() *State {
- return &State{
- Channels: make(map[string]*StateChannel),
- ISupport: &ISupport{
- tokens: make(map[string]string),
- },
- }
-}
-
-func NewStateChannel(name string) *StateChannel {
- return &StateChannel{
- Name: name,
- Modes: make(map[string]string),
- Joined: time.Now(),
- }
-}
-
-func (m *State) HasChannel(name string) (ok bool) {
- m.channelsMutex.Lock()
- _, ok = m.Channels[strings.ToLower(name)]
- m.channelsMutex.Unlock()
- return
-}
-
-func (m *State) GetChannel(name string) (channel *StateChannel) {
- m.channelsMutex.Lock()
- channel = m.Channels[strings.ToLower(name)]
- m.channelsMutex.Unlock()
- return
-}
-
-func (m *State) SetChannel(channel *StateChannel) {
- m.channelsMutex.Lock()
- m.Channels[strings.ToLower(channel.Name)] = channel
- m.channelsMutex.Unlock()
-}
-
-func (m *State) RemoveChannel(name string) {
- m.channelsMutex.Lock()
- delete(m.Channels, strings.ToLower(name))
- m.channelsMutex.Unlock()
-}
-
-func (m *State) ClearChannels() {
- m.channelsMutex.Lock()
- for i := range m.Channels {
- delete(m.Channels, i)
- }
- m.channelsMutex.Unlock()
-}
diff --git a/deprecated-webircgateway/pkg/proxy/proxy.go b/deprecated-webircgateway/pkg/proxy/proxy.go
deleted file mode 100644
index c332f40..0000000
--- a/deprecated-webircgateway/pkg/proxy/proxy.go
+++ /dev/null
@@ -1,129 +0,0 @@
-package proxy
-
-import (
- "encoding/json"
- "errors"
- "io"
- "net"
-)
-
-type KiwiProxyState int
-
-const KiwiProxyStateClosed KiwiProxyState = 0
-const KiwiProxyStateConnecting KiwiProxyState = 1
-const KiwiProxyStateHandshaking KiwiProxyState = 2
-const KiwiProxyStateConnected KiwiProxyState = 3
-
-type ConnError struct {
- Msg string
- Type string
-}
-
-func (err *ConnError) Error() string {
- return err.Msg
-}
-
-type KiwiProxyConnection struct {
- Username string
- ProxyInterface string
- DestHost string
- DestPort int
- DestTLS bool
- State KiwiProxyState
- Conn *net.Conn
-}
-
-func MakeKiwiProxyConnection() *KiwiProxyConnection {
- return &KiwiProxyConnection{
- State: KiwiProxyStateClosed,
- }
-}
-
-func (c *KiwiProxyConnection) Close() error {
- if c.State == KiwiProxyStateClosed {
- return errors.New("Connection already closed")
- }
-
- return (*c.Conn).Close()
-}
-
-func (c *KiwiProxyConnection) Dial(proxyServerAddr string) error {
- if c.State != KiwiProxyStateClosed {
- return errors.New("Connection in closed state")
- }
-
- c.State = KiwiProxyStateConnecting
-
- conn, err := net.Dial("tcp", proxyServerAddr)
- if err != nil {
- return err
- }
-
- c.Conn = &conn
- c.State = KiwiProxyStateHandshaking
-
- meta, _ := json.Marshal(map[string]interface{}{
- "username": c.Username,
- "interface": c.ProxyInterface,
- "host": c.DestHost,
- "port": c.DestPort,
- "ssl": c.DestTLS,
- })
-
- (*c.Conn).Write(append(meta, byte('\n')))
-
- buf := make([]byte, 1024)
- bufLen, readErr := (*c.Conn).Read(buf)
- if readErr != nil {
- (*c.Conn).Close()
- c.State = KiwiProxyStateClosed
- return readErr
- }
-
- response := string(buf)
- if bufLen > 0 && response[0] == '1' {
- c.State = KiwiProxyStateConnected
- } else {
- (*c.Conn).Close()
- c.State = KiwiProxyStateClosed
-
- if bufLen == 0 {
- return errors.New("The proxy could not connect to the destination")
- }
-
- switch response[0] {
- case '0':
- return errors.New("The proxy could not connect to the destination")
- case '2':
- return &ConnError{Msg: "Connection reset", Type: "conn_reset"}
- case '3':
- return &ConnError{Msg: "Connection refused", Type: "conn_refused"}
- case '4':
- return &ConnError{Msg: "Host not found", Type: "not_found"}
- case '5':
- return &ConnError{Msg: "Connection timed out", Type: "conn_timeout"}
- }
- }
-
- return nil
-}
-
-func (c *KiwiProxyConnection) Read(b []byte) (n int, err error) {
- if c.State == KiwiProxyStateConnecting || c.State == KiwiProxyStateHandshaking {
- return 0, nil
- } else if c.State == KiwiProxyStateClosed {
- return 0, io.EOF
- } else {
- return (*c.Conn).Read(b)
- }
-}
-
-func (c *KiwiProxyConnection) Write(b []byte) (n int, err error) {
- if c.State == KiwiProxyStateConnecting || c.State == KiwiProxyStateHandshaking {
- return 0, nil
- } else if c.State == KiwiProxyStateClosed {
- return 0, io.EOF
- } else {
- return (*c.Conn).Write(b)
- }
-}
diff --git a/deprecated-webircgateway/pkg/proxy/server.go b/deprecated-webircgateway/pkg/proxy/server.go
deleted file mode 100644
index 7e3f62f..0000000
--- a/deprecated-webircgateway/pkg/proxy/server.go
+++ /dev/null
@@ -1,237 +0,0 @@
-package proxy
-
-import (
- "bufio"
- "crypto/tls"
- "encoding/json"
- "fmt"
- "io"
- "log"
- "net"
- "strconv"
- "sync"
- "syscall"
- "time"
-
- "github.com/kiwiirc/webircgateway/pkg/identd"
-)
-
-const (
- ResponseError = "0"
- ResponseOK = "1"
- ResponseReset = "2"
- ResponseRefused = "3"
- ResponseUnknownHost = "4"
- ResponseTimeout = "5"
-)
-
-var identdRpc *identd.RpcClient
-var Server net.Listener
-
-type HandshakeMeta struct {
- Host string `json:"host"`
- Port int `json:"port"`
- TLS bool `json:"ssl"`
- Username string `json:"username"`
- Interface string `json:"interface"`
-}
-
-func MakeClient(conn net.Conn) *Client {
- return &Client{
- Client: conn,
- }
-}
-
-type Client struct {
- Client net.Conn
- Upstream net.Conn
- UpstreamAddr *net.TCPAddr
- Username string
- BindAddr *net.TCPAddr
- TLS bool
-}
-
-func (c *Client) Run() {
- var err error
-
- err = c.Handshake()
- if err != nil {
- log.Println(err.Error())
- return
- }
-
- err = c.ConnectUpstream()
- if err != nil {
- log.Println(err.Error())
- return
- }
-
- c.Pipe()
-}
-
-func (c *Client) Handshake() error {
- // Read the first line - it should be JSON
- reader := bufio.NewReader(c.Client)
- line, readErr := reader.ReadBytes('\n')
- if readErr != nil {
- return readErr
- }
-
- var meta = HandshakeMeta{
- Username: "user",
- Port: 6667,
- Interface: "0.0.0.0",
- }
- unmarshalErr := json.Unmarshal(line, &meta)
- if unmarshalErr != nil {
- c.Client.Write([]byte(ResponseError))
- return unmarshalErr
- }
-
- if meta.Host == "" || meta.Port == 0 || meta.Username == "" || meta.Interface == "" {
- c.Client.Write([]byte(ResponseError))
- return fmt.Errorf("missing args")
- }
-
- c.Username = meta.Username
- c.TLS = meta.TLS
-
- bindAddr, bindAddrErr := net.ResolveTCPAddr("tcp", meta.Interface+":")
- if bindAddrErr != nil {
- c.Client.Write([]byte(ResponseError))
- return fmt.Errorf("interface: " + bindAddrErr.Error())
- }
- c.BindAddr = bindAddr
-
- hostStr := net.JoinHostPort(meta.Host, strconv.Itoa(meta.Port))
- addr, addrErr := net.ResolveTCPAddr("tcp", hostStr)
- if addrErr != nil {
- c.Client.Write([]byte(ResponseUnknownHost))
- return fmt.Errorf("remote host: " + addrErr.Error())
- }
- c.UpstreamAddr = addr
-
- return nil
-}
-
-func (c *Client) ConnectUpstream() error {
- dialer := &net.Dialer{}
- dialer.LocalAddr = c.BindAddr
- dialer.Timeout = time.Second * 10
-
- conn, err := dialer.Dial("tcp", c.UpstreamAddr.String())
- if err != nil {
- response := ""
- errType := typeOfErr(err)
- switch errType {
- case "timeout":
- response = ResponseTimeout
- case "unknown_host":
- response = ResponseUnknownHost
- case "refused":
- response = ResponseRefused
- }
-
- c.Client.Write([]byte(response))
- return err
- }
-
- if identdRpc != nil {
- lAddr, lPortStr, _ := net.SplitHostPort(conn.LocalAddr().String())
- lPort, _ := strconv.Atoi(lPortStr)
- identdRpc.AddIdent(lPort, c.UpstreamAddr.Port, c.Username, lAddr)
- }
-
- if c.TLS {
- tlsConfig := &tls.Config{InsecureSkipVerify: true}
- tlsConn := tls.Client(conn, tlsConfig)
- err := tlsConn.Handshake()
- if err != nil {
- conn.Close()
- c.Client.Write([]byte(ResponseReset))
- return err
- }
-
- conn = net.Conn(tlsConn)
- }
-
- c.Upstream = conn
- c.Client.Write([]byte(ResponseOK))
- return nil
-}
-
-func (c *Client) Pipe() {
- wg := sync.WaitGroup{}
- wg.Add(2)
-
- go func() {
- io.Copy(c.Client, c.Upstream)
- c.Client.Close()
- wg.Done()
- }()
-
- go func() {
- io.Copy(c.Upstream, c.Client)
- c.Upstream.Close()
- wg.Done()
- }()
-
- wg.Wait()
-
- if identdRpc != nil {
- lAddr, lPortStr, _ := net.SplitHostPort(c.Upstream.LocalAddr().String())
- lPort, _ := strconv.Atoi(lPortStr)
- identdRpc.RemoveIdent(lPort, c.UpstreamAddr.Port, c.Username, lAddr)
- }
-}
-
-func Start(laddr string) {
- srv, err := net.Listen("tcp", laddr)
- if err != nil {
- log.Fatal(err.Error())
- }
-
- // Expose the server
- Server = srv
- log.Printf("Kiwi proxy listening on %s", srv.Addr().String())
-
- identdRpc = identd.MakeRpcClient("kiwiproxy" + laddr)
- go identdRpc.ConnectAndReconnect("127.0.0.1:1133")
-
- for {
- conn, err := srv.Accept()
- if err != nil {
- log.Print(err.Error())
- break
- }
-
- c := MakeClient(conn)
- go c.Run()
- }
-}
-
-func typeOfErr(err error) string {
- if err == nil {
- return ""
- }
-
- if netError, ok := err.(net.Error); ok && netError.Timeout() {
- return "timeout"
- }
-
- switch t := err.(type) {
- case *net.OpError:
- if t.Op == "dial" {
- return "unknown_host"
- } else if t.Op == "read" {
- return "refused"
- }
-
- case syscall.Errno:
- if t == syscall.ECONNREFUSED {
- return "refused"
- }
- }
-
- return ""
-}
diff --git a/deprecated-webircgateway/pkg/recaptcha/recaptcha.go b/deprecated-webircgateway/pkg/recaptcha/recaptcha.go
deleted file mode 100644
index 2d602fc..0000000
--- a/deprecated-webircgateway/pkg/recaptcha/recaptcha.go
+++ /dev/null
@@ -1,59 +0,0 @@
-// Google re-captcha package tweaked from http://github.com/haisum/recaptcha
-
-package recaptcha
-
-import (
- "encoding/json"
- "io/ioutil"
- "net/http"
- "net/url"
- "time"
-)
-
-// R type represents an object of Recaptcha and has public property Secret,
-// which is secret obtained from google recaptcha tool admin interface
-type R struct {
- URL string
- Secret string
- lastError []string
-}
-
-// Struct for parsing json in google's response
-type googleResponse struct {
- Success bool
- ErrorCodes []string `json:"error-codes"`
-}
-
-// VerifyResponse is a method similar to `Verify`; but doesn't parse the form for you. Useful if
-// you're receiving the data as a JSON object from a javascript app or similar.
-func (r *R) VerifyResponse(response string) bool {
- r.lastError = make([]string, 1)
- client := &http.Client{Timeout: 20 * time.Second}
- resp, err := client.PostForm(r.URL,
- url.Values{"secret": {r.Secret}, "response": {response}})
- if err != nil {
- r.lastError = append(r.lastError, err.Error())
- return false
- }
- defer resp.Body.Close()
- body, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- r.lastError = append(r.lastError, err.Error())
- return false
- }
- gr := new(googleResponse)
- err = json.Unmarshal(body, gr)
- if err != nil {
- r.lastError = append(r.lastError, err.Error())
- return false
- }
- if !gr.Success {
- r.lastError = append(r.lastError, gr.ErrorCodes...)
- }
- return gr.Success
-}
-
-// LastError returns errors occurred in last re-captcha validation attempt
-func (r R) LastError() []string {
- return r.lastError
-}
diff --git a/deprecated-webircgateway/pkg/webircgateway/client.go b/deprecated-webircgateway/pkg/webircgateway/client.go
deleted file mode 100644
index 43d3fe7..0000000
--- a/deprecated-webircgateway/pkg/webircgateway/client.go
+++ /dev/null
@@ -1,741 +0,0 @@
-package webircgateway
-
-import (
- "bufio"
- "crypto/tls"
- "errors"
- "fmt"
- "io"
- "net"
- "runtime/debug"
- "strconv"
- "strings"
- "sync"
- "sync/atomic"
- "syscall"
- "time"
-
- "golang.org/x/time/rate"
-
- "github.com/kiwiirc/webircgateway/pkg/dnsbl"
- "github.com/kiwiirc/webircgateway/pkg/irc"
- "github.com/kiwiirc/webircgateway/pkg/proxy"
-)
-
-const (
- // ClientStateIdle - Client connected and just sat there
- ClientStateIdle = "idle"
- // ClientStateConnecting - Connecting upstream
- ClientStateConnecting = "connecting"
- // ClientStateRegistering - Registering to the IRC network
- ClientStateRegistering = "registering"
- // ClientStateConnected - Connected upstream
- ClientStateConnected = "connected"
- // ClientStateEnding - Client is ending its connection
- ClientStateEnding = "ending"
-)
-
-type ClientSignal [3]string
-
-// Client - Connecting client struct
-type Client struct {
- Gateway *Gateway
- Id uint64
- State string
- EndWG sync.WaitGroup
- shuttingDownLock sync.Mutex
- shuttingDown bool
- SeenQuit bool
- Recv chan string
- ThrottledRecv *ThrottledStringChannel
- upstream io.ReadWriteCloser
- UpstreamRecv chan string
- UpstreamSend chan string
- UpstreamStarted bool
- UpstreamConfig *ConfigUpstream
- RemoteAddr string
- RemoteHostname string
- RemotePort int
- DestHost string
- DestPort int
- DestTLS bool
- IrcState *irc.State
- Encoding string
- // Tags get passed upstream via the WEBIRC command
- Tags map[string]string
- // Captchas may be needed to verify a client
- RequiresVerification bool
- Verified bool
- SentPass bool
- // Signals for the transport to make use of (data, connection state, etc)
- Signals chan ClientSignal
- Features struct {
- Messagetags bool
- Metadata bool
- ExtJwt bool
- }
- // The specific message-tags CAP that the client has requested if we are wrapping it
- RequestedMessageTagsCap string
- // Prefix used by the server when sending its own messages
- ServerMessagePrefix irc.Mask
-}
-
-var nextClientID uint64 = 1
-
-// NewClient - Makes a new client
-func NewClient(gateway *Gateway) *Client {
- thisID := atomic.AddUint64(&nextClientID, 1)
-
- recv := make(chan string, 50)
- c := &Client{
- Gateway: gateway,
- Id: thisID,
- State: ClientStateIdle,
- Recv: recv,
- ThrottledRecv: NewThrottledStringChannel(recv, rate.NewLimiter(rate.Inf, 1)),
- UpstreamSend: make(chan string, 50),
- UpstreamRecv: make(chan string, 50),
- Encoding: "UTF-8",
- Signals: make(chan ClientSignal, 50),
- Tags: make(map[string]string),
- IrcState: irc.NewState(),
- UpstreamConfig: &ConfigUpstream{},
- }
-
- // Auto enable some features by default. They may be disabled later on
- c.Features.ExtJwt = true
-
- c.RequiresVerification = gateway.Config.RequiresVerification
-
- // Handles data to/from the client and upstreams
- go c.clientLineWorker()
-
- // This Add(1) will be ended once the client starts shutting down in StartShutdown()
- c.EndWG.Add(1)
-
- // Add to the clients maps and wait until everything has been marked
- // as completed (several routines add themselves to EndWG so that we can catch
- // when they are all completed)
- gateway.Clients.Set(strconv.FormatUint(c.Id, 10), c)
- go func() {
- c.EndWG.Wait()
- gateway.Clients.Remove(strconv.FormatUint(c.Id, 10))
-
- hook := &HookClientState{
- Client: c,
- Connected: false,
- }
- hook.Dispatch("client.state")
- }()
-
- hook := &HookClientState{
- Client: c,
- Connected: true,
- }
- hook.Dispatch("client.state")
-
- return c
-}
-
-// Log - Log a line of text with context of this client
-func (c *Client) Log(level int, format string, args ...interface{}) {
- prefix := fmt.Sprintf("client:%d ", c.Id)
- c.Gateway.Log(level, prefix+format, args...)
-}
-
-// TrafficLog - Log out raw IRC traffic
-func (c *Client) TrafficLog(isUpstream bool, toGateway bool, traffic string) {
- label := ""
- if isUpstream && toGateway {
- label = "Upstream->"
- } else if isUpstream && !toGateway {
- label = "->Upstream"
- } else if !isUpstream && toGateway {
- label = "Client->"
- } else if !isUpstream && !toGateway {
- label = "->Client"
- }
- c.Log(1, "Traffic (%s) %s", label, traffic)
-}
-
-func (c *Client) Ready() {
- dnsblAction := c.Gateway.Config.DnsblAction
- validAction := dnsblAction == "verify" || dnsblAction == "deny"
- dnsblTookAction := ""
-
- if len(c.Gateway.Config.DnsblServers) > 0 && c.RemoteAddr != "" && !c.Verified && validAction {
- dnsblTookAction = c.checkDnsBl()
- }
-
- if dnsblTookAction == "" && c.Gateway.Config.RequiresVerification && !c.Verified {
- c.SendClientSignal("data", "CAPTCHA NEEDED")
- }
-}
-
-func (c *Client) checkDnsBl() (tookAction string) {
- dnsResult := dnsbl.Lookup(c.Gateway.Config.DnsblServers, c.RemoteAddr)
- if dnsResult.Listed && c.Gateway.Config.DnsblAction == "deny" {
- c.SendIrcError("Blocked by DNSBL")
- c.SendClientSignal("state", "closed", "dnsbl_listed")
- c.StartShutdown("dnsbl")
- tookAction = "deny"
- } else if dnsResult.Listed && c.Gateway.Config.DnsblAction == "verify" {
- c.RequiresVerification = true
- c.SendClientSignal("data", "CAPTCHA NEEDED")
- tookAction = "verify"
- }
-
- return
-}
-
-func (c *Client) IsShuttingDown() bool {
- c.shuttingDownLock.Lock()
- defer c.shuttingDownLock.Unlock()
- return c.shuttingDown
-}
-
-func (c *Client) StartShutdown(reason string) {
- c.shuttingDownLock.Lock()
- defer c.shuttingDownLock.Unlock()
-
- c.Log(1, "StartShutdown(%s) ShuttingDown=%t", reason, c.shuttingDown)
- if !c.shuttingDown {
- c.shuttingDown = true
- c.State = ClientStateEnding
-
- switch reason {
- case "upstream_closed":
- c.Log(2, "Upstream closed the connection")
- case "err_connecting_upstream":
- case "err_no_upstream":
- // Error has been logged already
- case "client_closed":
- c.Log(2, "Client disconnected")
- default:
- c.Log(2, "Closed: %s", reason)
- }
-
- close(c.Signals)
- c.EndWG.Done()
- }
-}
-
-func (c *Client) SendClientSignal(signal string, args ...string) {
- c.shuttingDownLock.Lock()
- defer c.shuttingDownLock.Unlock()
-
- if !c.shuttingDown {
- switch len(args) {
- case 0:
- c.Signals <- ClientSignal{signal}
- case 1:
- c.Signals <- ClientSignal{signal, args[0]}
- case 2:
- c.Signals <- ClientSignal{signal, args[0], args[1]}
- }
- }
-}
-
-func (c *Client) SendIrcError(message string) {
- c.SendClientSignal("data", "ERROR :"+message)
-}
-
-func (c *Client) SendIrcFail(params ...string) {
- failMessage := irc.Message{
- Command: "FAIL",
- Params: params,
- }
- c.SendClientSignal("data", failMessage.ToLine())
-}
-
-func (c *Client) connectUpstream() {
- client := c
-
- c.UpstreamStarted = true
-
- var upstreamConfig ConfigUpstream
-
- if client.DestHost == "" {
- client.Log(2, "Using configured upstream")
- var err error
- upstreamConfig, err = c.Gateway.findUpstream()
- if err != nil {
- client.Log(3, "No upstreams available")
- client.SendIrcError("The server has not been configured")
- client.StartShutdown("err_no_upstream")
- return
- }
- } else {
- if !c.Gateway.isIrcAddressAllowed(client.DestHost) {
- client.Log(2, "Server %s is not allowed. Closing connection", client.DestHost)
- client.SendIrcError("Not allowed to connect to " + client.DestHost)
- client.SendClientSignal("state", "closed", "err_forbidden")
- client.StartShutdown("err_no_upstream")
- return
- }
-
- client.Log(2, "Using client given upstream")
- upstreamConfig = c.configureUpstream()
- }
-
- c.UpstreamConfig = &upstreamConfig
-
- hook := &HookIrcConnectionPre{
- Client: client,
- UpstreamConfig: &upstreamConfig,
- }
- hook.Dispatch("irc.connection.pre")
- if hook.Halt {
- client.SendClientSignal("state", "closed", "err_forbidden")
- client.StartShutdown("err_connecting_upstream")
- return
- }
-
- client.State = ClientStateConnecting
-
- upstream, upstreamErr := client.makeUpstreamConnection()
- if upstreamErr != nil {
- // Error handling was already managed in makeUpstreamConnection()
- return
- }
-
- client.State = ClientStateRegistering
-
- client.upstream = upstream
- client.readUpstream()
- client.writeWebircLines(upstream)
- client.maybeSendPass(upstream)
- client.SendClientSignal("state", "connected")
-}
-
-func (c *Client) makeUpstreamConnection() (io.ReadWriteCloser, error) {
- client := c
- upstreamConfig := c.UpstreamConfig
-
- var connection io.ReadWriteCloser
-
- if upstreamConfig.Proxy == nil {
- // Connect directly to the IRCd
- dialer := net.Dialer{}
- dialer.Timeout = time.Second * time.Duration(upstreamConfig.Timeout)
-
- if upstreamConfig.LocalAddr != "" {
- parsedIP := net.ParseIP(upstreamConfig.LocalAddr)
- if parsedIP != nil {
- dialer.LocalAddr = &net.TCPAddr{
- IP: parsedIP,
- Port: 0,
- }
- } else {
- client.Log(3, "Failed to parse localaddr for upstream connection \"%s\"", upstreamConfig.LocalAddr)
- }
- }
-
- var conn net.Conn
- var connErr error
- if upstreamConfig.Protocol == "unix" {
- conn, connErr = dialer.Dial("unix", upstreamConfig.Hostname)
- } else {
- upstreamStr := fmt.Sprintf("%s:%d", upstreamConfig.Hostname, upstreamConfig.Port)
- conn, connErr = dialer.Dial(upstreamConfig.Protocol, upstreamStr)
- }
-
- if connErr != nil {
- client.Log(3, "Error connecting to the upstream IRCd. %s", connErr.Error())
- errString := ""
- if errString = typeOfErr(connErr); errString != "" {
- errString = "err_" + errString
- }
- client.SendClientSignal("state", "closed", errString)
- client.StartShutdown("err_connecting_upstream")
- return nil, errors.New("error connecting upstream")
- }
-
- // Add the ports into the identd before possible TLS handshaking. If we do it after then
- // there's a good chance the identd lookup will occur before the handshake has finished
- if c.Gateway.Config.Identd {
- // Keep track of the upstreams local and remote port numbers
- _, lPortStr, _ := net.SplitHostPort(conn.LocalAddr().String())
- client.IrcState.LocalPort, _ = strconv.Atoi(lPortStr)
- _, rPortStr, _ := net.SplitHostPort(conn.RemoteAddr().String())
- client.IrcState.RemotePort, _ = strconv.Atoi(rPortStr)
-
- c.Gateway.identdServ.AddIdent(client.IrcState.LocalPort, client.IrcState.RemotePort, client.IrcState.Username, "")
- }
-
- if upstreamConfig.TLS {
- tlsConfig := &tls.Config{InsecureSkipVerify: true}
- tlsConn := tls.Client(conn, tlsConfig)
- err := tlsConn.Handshake()
- if err != nil {
- client.Log(3, "Error connecting to the upstream IRCd. %s", err.Error())
- client.SendClientSignal("state", "closed", "err_tls")
- client.StartShutdown("err_connecting_upstream")
- return nil, errors.New("error connecting upstream")
- }
-
- conn = net.Conn(tlsConn)
- }
-
- connection = conn
- }
-
- if upstreamConfig.Proxy != nil {
- // Connect to the IRCd via a proxy
- conn := proxy.MakeKiwiProxyConnection()
- conn.DestHost = upstreamConfig.Hostname
- conn.DestPort = upstreamConfig.Port
- conn.DestTLS = upstreamConfig.TLS
- conn.Username = upstreamConfig.Proxy.Username
- conn.ProxyInterface = upstreamConfig.Proxy.Interface
-
- dialErr := conn.Dial(fmt.Sprintf(
- "%s:%d",
- upstreamConfig.Proxy.Hostname,
- upstreamConfig.Proxy.Port,
- ))
-
- if dialErr != nil {
- errString := ""
- if errString = typeOfErr(dialErr); errString != "" {
- errString = "err_" + errString
- } else {
- errString = "err_proxy"
- }
- client.Log(3,
- "Error connecting to the kiwi proxy, %s:%d. %s",
- upstreamConfig.Proxy.Hostname,
- upstreamConfig.Proxy.Port,
- dialErr.Error(),
- )
-
- client.SendClientSignal("state", "closed", errString)
- client.StartShutdown("err_connecting_upstream")
- return nil, errors.New("error connecting upstream")
- }
-
- connection = conn
- }
-
- return connection, nil
-}
-
-func (c *Client) writeWebircLines(upstream io.ReadWriteCloser) {
- // Send any WEBIRC lines
- if c.UpstreamConfig.WebircPassword == "" {
- c.Log(1, "No webirc to send")
- return
- }
-
- gatewayName := "webircgateway"
- if c.Gateway.Config.GatewayName != "" {
- gatewayName = c.Gateway.Config.GatewayName
- }
- if c.UpstreamConfig.GatewayName != "" {
- gatewayName = c.UpstreamConfig.GatewayName
- }
-
- webircTags := c.buildWebircTags()
- if strings.Contains(webircTags, " ") {
- webircTags = ":" + webircTags
- }
-
- clientHostname := c.RemoteHostname
- if c.Gateway.Config.ClientHostname != "" {
- clientHostname = makeClientReplacements(c.Gateway.Config.ClientHostname, c)
- }
-
- remoteAddr := c.RemoteAddr
- // Prefix IPv6 addresses that start with a : so they can be sent as an individual IRC
- // parameter. eg. ::1 would not parse correctly as a parameter, while 0::1 will
- if strings.HasPrefix(remoteAddr, ":") {
- remoteAddr = "0" + remoteAddr
- }
-
- webircLine := fmt.Sprintf(
- "WEBIRC %s %s %s %s %s\n",
- c.UpstreamConfig.WebircPassword,
- gatewayName,
- clientHostname,
- remoteAddr,
- webircTags,
- )
- c.Log(1, "->upstream: %s", webircLine)
- upstream.Write([]byte(webircLine))
-}
-
-func (c *Client) maybeSendPass(upstream io.ReadWriteCloser) {
- if c.UpstreamConfig.ServerPassword == "" {
- return
- }
- c.SentPass = true
- passLine := fmt.Sprintf(
- "PASS %s\n",
- c.UpstreamConfig.ServerPassword,
- )
- c.Log(1, "->upstream: %s", passLine)
- upstream.Write([]byte(passLine))
-}
-
-func (c *Client) processLineToUpstream(data string) {
- client := c
- upstreamConfig := c.UpstreamConfig
-
- if strings.HasPrefix(data, "PASS ") && c.SentPass {
- // Hijack the PASS command if we already sent a pass command
- return
- } else if strings.HasPrefix(data, "USER ") {
- // Hijack the USER command as we may have some overrides
- data = fmt.Sprintf(
- "USER %s 0 * :%s",
- client.IrcState.Username,
- client.IrcState.RealName,
- )
- } else if strings.HasPrefix(strings.ToUpper(data), "QUIT ") {
- client.SeenQuit = true
- }
-
- message, _ := irc.ParseLine(data)
-
- hook := &HookIrcLine{
- Client: client,
- UpstreamConfig: upstreamConfig,
- Line: data,
- Message: message,
- ToServer: true,
- }
- hook.Dispatch("irc.line")
- if hook.Halt {
- return
- }
-
- // Plugins may have modified the data
- data = hook.Line
-
- c.TrafficLog(true, false, data)
- data = utf8ToOther(data, client.Encoding)
- if data == "" {
- client.Log(1, "Failed to encode into '%s'. Dropping data", c.Encoding)
- return
- }
-
- if client.upstream != nil {
- client.upstream.Write([]byte(data + "\r\n"))
- } else {
- client.Log(2, "Tried sending data upstream before connected")
- }
-}
-
-func (c *Client) handleLineFromUpstream(data string) {
- client := c
- upstreamConfig := c.UpstreamConfig
-
- message, _ := irc.ParseLine(data)
-
- hook := &HookIrcLine{
- Client: client,
- UpstreamConfig: upstreamConfig,
- Line: data,
- Message: message,
- ToServer: false,
- }
- hook.Dispatch("irc.line")
- if hook.Halt {
- return
- }
-
- // Plugins may have modified the data
- data = hook.Line
-
- if data == "" {
- return
- }
-
- data = ensureUtf8(data, client.Encoding)
- if data == "" {
- client.Log(1, "Failed to decode as 'UTF-8'. Dropping data")
- return
- }
-
- data = client.ProcessLineFromUpstream(data)
- if data == "" {
- return
- }
-
- client.SendClientSignal("data", data)
-}
-
-func typeOfErr(err error) string {
- if err == nil {
- return ""
- }
-
- if netError, ok := err.(net.Error); ok && netError.Timeout() {
- return "timeout"
- }
-
- switch t := err.(type) {
- case *proxy.ConnError:
- switch t.Type {
- case "conn_reset":
- return ""
- case "conn_refused":
- return "refused"
- case "not_found":
- return "unknown_host"
- case "conn_timeout":
- return "timeout"
- default:
- return ""
- }
-
- case *net.OpError:
- if t.Op == "dial" {
- return "unknown_host"
- } else if t.Op == "read" {
- return "refused"
- }
-
- case syscall.Errno:
- if t == syscall.ECONNREFUSED {
- return "refused"
- }
- }
-
- return ""
-}
-
-func (c *Client) readUpstream() {
- client := c
-
- // Data from upstream to client
- go func() {
- reader := bufio.NewReader(client.upstream)
- for {
- data, err := reader.ReadString('\n')
- if err != nil {
- break
- }
-
- data = strings.Trim(data, "\n\r")
- client.UpstreamRecv <- data
- }
-
- close(client.UpstreamRecv)
- client.upstream.Close()
- client.upstream = nil
-
- if client.IrcState.RemotePort > 0 {
- c.Gateway.identdServ.RemoveIdent(client.IrcState.LocalPort, client.IrcState.RemotePort, "")
- }
- }()
-}
-
-// Handle lines sent from the client
-func (c *Client) clientLineWorker() {
- for {
- shouldQuit, _ := c.handleDataLine()
- if shouldQuit {
- break
- }
-
- }
-
- c.Log(1, "leaving clientLineWorker")
-}
-
-func (c *Client) handleDataLine() (shouldQuit bool, hadErr bool) {
- defer func() {
- if err := recover(); err != nil {
- c.Log(3, fmt.Sprint("Error handling data ", err))
- fmt.Println("Error handling data", err)
- debug.PrintStack()
- shouldQuit = false
- hadErr = true
- }
- }()
-
- // We only want to send data upstream if we have an upstream connection
- upstreamSend := c.UpstreamSend
- if c.upstream == nil {
- upstreamSend = nil
- }
-
- select {
- case clientData, ok := <-c.ThrottledRecv.Output:
- if !ok {
- c.Log(1, "client.Recv closed")
- if !c.SeenQuit && c.Gateway.Config.SendQuitOnClientClose != "" && c.State == ClientStateEnding {
- c.processLineToUpstream("QUIT :" + c.Gateway.Config.SendQuitOnClientClose)
- }
-
- c.StartShutdown("client_closed")
-
- if c.upstream != nil {
- c.upstream.Close()
- }
- return true, false
- }
- c.Log(1, "in c.ThrottledRecv.Output")
- c.TrafficLog(false, true, clientData)
-
- clientLine, err := c.ProcessLineFromClient(clientData)
- if err == nil && clientLine != "" {
- c.UpstreamSend <- clientLine
- }
-
- case line, ok := <-upstreamSend:
- if !ok {
- c.Log(1, "client.UpstreamSend closed")
- return true, false
- }
- c.Log(1, "in .UpstreamSend")
- c.processLineToUpstream(line)
-
- case upstreamData, ok := <-c.UpstreamRecv:
- if !ok {
- c.Log(1, "client.UpstreamRecv closed")
- c.SendClientSignal("state", "closed")
- c.StartShutdown("upstream_closed")
- return true, false
- }
- c.Log(1, "in .UpstreamRecv")
- c.TrafficLog(true, true, upstreamData)
-
- c.handleLineFromUpstream(upstreamData)
- }
-
- return false, false
-}
-
-// configureUpstream - Generate an upstream configuration from the information set on the client instance
-func (c *Client) configureUpstream() ConfigUpstream {
- upstreamConfig := ConfigUpstream{}
- upstreamConfig.Hostname = c.DestHost
- upstreamConfig.Port = c.DestPort
- upstreamConfig.TLS = c.DestTLS
- upstreamConfig.Timeout = c.Gateway.Config.GatewayTimeout
- upstreamConfig.Throttle = c.Gateway.Config.GatewayThrottle
- upstreamConfig.WebircPassword = c.Gateway.findWebircPassword(c.DestHost)
- upstreamConfig.Protocol = c.Gateway.Config.GatewayProtocol
- upstreamConfig.LocalAddr = c.Gateway.Config.GatewayLocalAddr
-
- return upstreamConfig
-}
-
-func (c *Client) buildWebircTags() string {
- str := ""
- for key, val := range c.Tags {
- if str != "" {
- str += " "
- }
-
- if val == "" {
- str += key
- } else {
- str += key + "=" + val
- }
- }
-
- return str
-}
diff --git a/deprecated-webircgateway/pkg/webircgateway/client_command_handlers.go b/deprecated-webircgateway/pkg/webircgateway/client_command_handlers.go
deleted file mode 100644
index d5d1fcc..0000000
--- a/deprecated-webircgateway/pkg/webircgateway/client_command_handlers.go
+++ /dev/null
@@ -1,495 +0,0 @@
-package webircgateway
-
-import (
- "errors"
- "strconv"
- "strings"
- "time"
-
- "github.com/golang-jwt/jwt/v4"
- "github.com/kiwiirc/webircgateway/pkg/irc"
- "github.com/kiwiirc/webircgateway/pkg/recaptcha"
- "golang.org/x/net/html/charset"
- "golang.org/x/time/rate"
-)
-
-var MAX_EXTJWT_SIZE = 200
-
-/*
- * ProcessLineFromUpstream
- * Processes and makes any changes to a line of data sent from an upstream
- */
-func (c *Client) ProcessLineFromUpstream(data string) string {
- client := c
-
- m, parseErr := irc.ParseLine(data)
- if parseErr != nil {
- return data
- }
-
- pLen := len(m.Params)
-
- if pLen > 0 && m.Command == "NICK" && m.Prefix.Nick == c.IrcState.Nick {
- client.IrcState.Nick = m.Params[0]
- }
- if pLen > 0 && m.Command == "001" {
- client.IrcState.Nick = m.Params[0]
- client.State = ClientStateConnected
- client.ServerMessagePrefix = *m.Prefix
-
- // Throttle writes if configured, but only after registration is complete. Typical IRCd
- // behavior is to not throttle registration commands.
- client.ThrottledRecv.Limiter = rate.NewLimiter(rate.Limit(client.UpstreamConfig.Throttle), 1)
- }
- if pLen > 0 && m.Command == "005" {
- tokenPairs := m.Params[1 : pLen-1]
- iSupport := c.IrcState.ISupport
- iSupport.Received = true
- iSupport.Tags = m.Tags
- iSupport.AddTokens(tokenPairs)
- }
- if c.IrcState.ISupport.Received && !c.IrcState.ISupport.Injected && m.Command != "005" {
- iSupport := c.IrcState.ISupport
- iSupport.Injected = true
-
- msg := irc.NewMessage()
- msg.Command = "005"
- msg.Prefix = &c.ServerMessagePrefix
- msg.Params = append(msg.Params, c.IrcState.Nick)
-
- if iSupport.HasToken("EXTJWT") {
- c.Log(1, "Upstream already supports EXTJWT, disabling feature")
- c.Features.ExtJwt = false
- } else {
- // Add EXTJWT ISupport token
- msg.Params = append(msg.Params, "EXTJWT=1")
- iSupport.AddToken("EXTJWT=1")
- }
-
- msg.Params = append(msg.Params, "are supported by this server")
- if timeTag, ok := c.IrcState.ISupport.Tags["time"]; ok {
- msg.Tags["time"] = timeTag
- }
- if len(msg.Params) > 2 {
- // Extra tokens were added, send the line
- c.SendClientSignal("data", msg.ToLine())
- }
- }
- if pLen > 0 && m.Command == "JOIN" && m.Prefix.Nick == c.IrcState.Nick {
- channel := irc.NewStateChannel(m.GetParam(0, ""))
- c.IrcState.SetChannel(channel)
- }
- if pLen > 0 && m.Command == "PART" && m.Prefix.Nick == c.IrcState.Nick {
- c.IrcState.RemoveChannel(m.GetParam(0, ""))
- }
- if pLen > 0 && m.Command == "QUIT" && m.Prefix.Nick == c.IrcState.Nick {
- c.IrcState.ClearChannels()
- }
- // :server.com 900 m m!m@irc-3jg.1ab.j4ep8h.IP prawnsalad :You are now logged in as prawnsalad
- if pLen > 0 && m.Command == "900" {
- c.IrcState.Account = m.GetParam(2, "")
- }
- // :server.com 901 itsonlybinary itsonlybinary!itsonlybina@user/itsonlybinary :You are now logged out
- if m.Command == "901" {
- c.IrcState.Account = ""
- }
- // :prawnsalad!prawn@kiwiirc/prawnsalad MODE #kiwiirc-dev +oo notprawn kiwi-n75
- if pLen > 0 && m.Command == "MODE" {
- if strings.HasPrefix(m.GetParam(0, ""), "#") {
- channelName := m.GetParam(0, "")
- modes := m.GetParam(1, "")
-
- channel := c.IrcState.GetChannel(channelName)
- if channel != nil {
- channel = irc.NewStateChannel(channelName)
- c.IrcState.SetChannel(channel)
- }
-
- adding := false
- paramIdx := 1
- for i := 0; i < len(modes); i++ {
- mode := string(modes[i])
-
- if mode == "+" {
- adding = true
- } else if mode == "-" {
- adding = false
- } else {
- paramIdx++
- param := m.GetParam(paramIdx, "")
- if strings.EqualFold(param, c.IrcState.Nick) {
- if adding {
- channel.Modes[mode] = ""
- } else {
- delete(channel.Modes, mode)
- }
- }
- }
- }
- }
- }
-
- // If upstream reports that it supports message-tags natively, disable the wrapping of this feature for
- // this client
- if pLen >= 3 &&
- strings.ToUpper(m.Command) == "CAP" &&
- m.GetParamU(1, "") == "LS" {
- // The CAPs could be param 2 or 3 depending on if were using multiple lines to list them all.
- caps := ""
- if pLen >= 4 && m.Params[2] == "*" {
- caps = m.GetParamU(3, "")
- } else {
- caps = m.GetParamU(2, "")
- }
-
- if containsOneOf(caps, []string{"DRAFT/MESSAGE-TAGS-0.2", "MESSAGE-TAGS"}) {
- c.Log(1, "Upstream already supports Messagetags, disabling feature")
- c.Features.Messagetags = false
- }
-
- // Inject message-tags cap into the last line of IRCd capabilities
- if c.Features.Messagetags && m.Params[2] != "*" {
- m.Params[2] += " message-tags"
- data = m.ToLine()
- }
- }
-
- // If we requested message-tags, make sure to include it in the ACK when
- // the IRCd sends the ACK through
- if m != nil &&
- client.RequestedMessageTagsCap != "" &&
- strings.ToUpper(m.Command) == "CAP" &&
- m.GetParamU(1, "") == "ACK" &&
- !strings.Contains(m.GetParamU(2, ""), "MESSAGE-TAGS") {
-
- m.Params[2] += " " + client.RequestedMessageTagsCap
- data = m.ToLine()
-
- client.RequestedMessageTagsCap = ""
- }
-
- if m != nil && client.Features.Messagetags && c.Gateway.messageTags.CanMessageContainClientTags(m) {
- // If we have any message tags stored for this message from a previous PRIVMSG sent
- // by a client, add them back in
- mTags, mTagsExists := c.Gateway.messageTags.GetTagsFromMessage(client, m.Prefix.Nick, m)
- if mTagsExists {
- for k, v := range mTags.Tags {
- m.Tags[k] = v
- }
-
- data = m.ToLine()
- }
- }
-
- return data
-}
-
-/*
- * ProcessLineFromClient
- * Processes and makes any changes to a line of data sent from a client
- */
-func (c *Client) ProcessLineFromClient(line string) (string, error) {
- message, err := irc.ParseLine(line)
- // Just pass any random data upstream
- if err != nil {
- return line, nil
- }
-
- maybeConnectUpstream := func() {
- verified := false
- if c.RequiresVerification && !c.Verified {
- verified = false
- } else {
- verified = true
- }
-
- if !c.UpstreamStarted && c.IrcState.Username != "" && c.IrcState.Nick != "" && verified {
- c.connectUpstream()
- }
- }
-
- if !c.Verified && strings.ToUpper(message.Command) == "CAPTCHA" {
- verified := false
- if len(message.Params) >= 1 {
- captcha := recaptcha.R{
- URL: c.Gateway.Config.ReCaptchaURL,
- Secret: c.Gateway.Config.ReCaptchaSecret,
- }
-
- verified = captcha.VerifyResponse(message.Params[0])
- }
-
- if !verified {
- c.SendIrcError("Invalid captcha")
- c.SendClientSignal("state", "closed", "bad_captcha")
- c.StartShutdown("unverifed")
- } else {
- c.Verified = true
- maybeConnectUpstream()
- }
-
- return "", nil
- }
-
- // NICK <nickname>
- if strings.ToUpper(message.Command) == "NICK" && !c.UpstreamStarted {
- if len(message.Params) > 0 {
- c.IrcState.Nick = message.Params[0]
- }
-
- if !c.UpstreamStarted {
- maybeConnectUpstream()
- }
- }
-
- // USER <username> <hostname> <servername> <realname>
- if strings.ToUpper(message.Command) == "USER" && !c.UpstreamStarted {
- if len(message.Params) < 4 {
- return line, errors.New("Invalid USER line")
- }
-
- if c.Gateway.Config.ClientUsername != "" {
- message.Params[0] = makeClientReplacements(c.Gateway.Config.ClientUsername, c)
- }
- if c.Gateway.Config.ClientRealname != "" {
- message.Params[3] = makeClientReplacements(c.Gateway.Config.ClientRealname, c)
- }
-
- line = message.ToLine()
-
- c.IrcState.Username = message.Params[0]
- c.IrcState.RealName = message.Params[3]
-
- maybeConnectUpstream()
- }
-
- if strings.ToUpper(message.Command) == "ENCODING" {
- if len(message.Params) > 0 {
- encoding, _ := charset.Lookup(message.Params[0])
- if encoding == nil {
- c.Log(1, "Requested unknown encoding, %s", message.Params[0])
- } else {
- c.Encoding = message.Params[0]
- c.Log(1, "Set encoding to %s", message.Params[0])
- }
- }
-
- // Don't send the ENCODING command upstream
- return "", nil
- }
-
- if strings.ToUpper(message.Command) == "HOST" && !c.UpstreamStarted {
- // HOST irc.network.net:6667
- // HOST irc.network.net:+6667
-
- if !c.Gateway.Config.Gateway {
- return "", nil
- }
-
- if len(message.Params) == 0 {
- return "", nil
- }
-
- addr := message.Params[0]
- if addr == "" {
- c.SendIrcError("Missing host")
- c.StartShutdown("missing_host")
- return "", nil
- }
-
- // Parse host:+port into the c.dest* vars
- portSep := strings.LastIndex(addr, ":")
- if portSep == -1 {
- c.DestHost = addr
- c.DestPort = 6667
- c.DestTLS = false
- } else {
- c.DestHost = addr[0:portSep]
- portParam := addr[portSep+1:]
- if len(portParam) > 0 && portParam[0:1] == "+" {
- c.DestTLS = true
- c.DestPort, err = strconv.Atoi(portParam[1:])
- if err != nil {
- c.DestPort = 6697
- }
- } else {
- c.DestPort, err = strconv.Atoi(portParam[0:])
- if err != nil {
- c.DestPort = 6667
- }
- }
- }
-
- // Don't send the HOST command upstream
- return "", nil
- }
-
- // If the client supports CAP, assume the client also supports parsing MessageTags
- // When upstream replies with its CAP listing, we check if message-tags is supported by the IRCd already and if so,
- // we disable this feature flag again to use the IRCds native support.
- if strings.ToUpper(message.Command) == "CAP" && len(message.Params) > 0 && strings.ToUpper(message.Params[0]) == "LS" {
- c.Log(1, "Enabling client Messagetags feature")
- c.Features.Messagetags = true
- }
-
- // If we are wrapping the Messagetags feature, make sure the clients REQ message-tags doesn't
- // get sent upstream
- if c.Features.Messagetags && strings.ToUpper(message.Command) == "CAP" && message.GetParamU(0, "") == "REQ" {
- reqCaps := strings.ToLower(message.GetParam(1, ""))
- capsThatEnableMessageTags := []string{"message-tags", "account-tag", "server-time", "batch"}
-
- if strings.Contains(reqCaps, "message-tags") {
- // Rebuild the list of requested caps, without message-tags
- caps := strings.Split(reqCaps, " ")
- newCaps := []string{}
- for _, cap := range caps {
- if !strings.Contains(strings.ToLower(cap), "message-tags") {
- newCaps = append(newCaps, cap)
- } else {
- c.RequestedMessageTagsCap = cap
- }
- }
-
- if len(newCaps) == 0 {
- // The only requested CAP was our emulated message-tags
- // the server will not be sending an ACK so we need to send our own
- c.SendClientSignal("data", "CAP * ACK :"+c.RequestedMessageTagsCap)
- return "", nil
- }
- message.Params[1] = strings.Join(newCaps, " ")
- line = message.ToLine()
- } else if !containsOneOf(reqCaps, capsThatEnableMessageTags) {
- // Didn't request anything that needs message-tags cap so disable it
- c.Features.Messagetags = false
- }
- }
-
- if c.Features.Messagetags && message.Command == "TAGMSG" {
- if len(message.Params) == 0 {
- return "", nil
- }
-
- // We can't be 100% sure what this users correct mask is, so just send the nick
- message.Prefix.Nick = c.IrcState.Nick
- message.Prefix.Hostname = ""
- message.Prefix.Username = ""
-
- thisHost := strings.ToLower(c.UpstreamConfig.Hostname)
- target := message.Params[0]
- for val := range c.Gateway.Clients.IterBuffered() {
- curClient := val.Val.(*Client)
- sameHost := strings.ToLower(curClient.UpstreamConfig.Hostname) == thisHost
- if !sameHost {
- continue
- }
-
- // Only send the message on to either the target nick, or the clients in a set channel
- if !strings.EqualFold(target, curClient.IrcState.Nick) && !curClient.IrcState.HasChannel(target) {
- continue
- }
-
- curClient.SendClientSignal("data", message.ToLine())
- }
-
- return "", nil
- }
-
- // Check for any client message tags so that we can store them for replaying to other clients
- if c.Features.Messagetags && c.Gateway.messageTags.CanMessageContainClientTags(message) {
- c.Gateway.messageTags.AddTagsFromMessage(c, c.IrcState.Nick, message)
- // Prevent any client tags heading upstream
- for k := range message.Tags {
- if len(k) > 0 && k[0] == '+' {
- delete(message.Tags, k)
- }
- }
-
- line = message.ToLine()
- }
-
- if c.Features.ExtJwt && strings.ToUpper(message.Command) == "EXTJWT" {
- tokenTarget := message.GetParam(0, "")
- tokenService := message.GetParam(1, "")
-
- tokenM := irc.Message{}
- tokenM.Command = "EXTJWT"
- tokenM.Prefix = &c.ServerMessagePrefix
- tokenData := jwt.MapClaims{
- "exp": time.Now().UTC().Add(1 * time.Minute).Unix(),
- "iss": c.UpstreamConfig.Hostname,
- "sub": c.IrcState.Nick,
- "account": c.IrcState.Account,
- "umodes": []string{},
-
- // Channel specific claims
- "channel": "",
- "joined": 0,
- "cmodes": []string{},
- }
-
- // Use the NetworkCommonAddress if a plugin as assigned one.
- // This allows plugins to associate different upstream hosts to the same network
- if c.UpstreamConfig.NetworkCommonAddress != "" {
- tokenData["iss"] = c.UpstreamConfig.NetworkCommonAddress
- }
-
- if tokenTarget == "" || tokenTarget == "*" {
- tokenM.Params = append(tokenM.Params, "*")
- } else {
- targetChan := c.IrcState.GetChannel(tokenTarget)
- if targetChan == nil {
- // Channel does not exist in IRC State, send so such channel message
- failMessage := irc.Message{
- Command: "403", // ERR_NOSUCHCHANNEL
- Prefix: &c.ServerMessagePrefix,
- Params: []string{c.IrcState.Nick, tokenTarget, "No such channel"},
- }
- c.SendClientSignal("data", failMessage.ToLine())
- return "", nil
- }
-
- tokenM.Params = append(tokenM.Params, tokenTarget)
-
- tokenData["channel"] = targetChan.Name
- tokenData["joined"] = targetChan.Joined.Unix()
-
- modes := []string{}
- for mode := range targetChan.Modes {
- modes = append(modes, mode)
- }
- tokenData["cmodes"] = modes
- }
-
- if tokenService == "" || tokenService == "*" {
- tokenM.Params = append(tokenM.Params, "*")
- } else {
- c.SendIrcFail("EXTJWT", "NO_SUCH_SERVICE", "No such service")
- return "", nil
- }
-
- token := jwt.NewWithClaims(jwt.SigningMethodHS256, tokenData)
- tokenSigned, tokenSignedErr := token.SignedString([]byte(c.Gateway.Config.Secret))
- if tokenSignedErr != nil {
- c.Log(3, "Error creating JWT token. %s", tokenSignedErr.Error())
- c.SendIrcFail("EXTJWT", "UNKNOWN_ERROR", "Failed to generate token")
- return "", nil
- }
-
- // Spit token if it exceeds max length
- for len(tokenSigned) > MAX_EXTJWT_SIZE {
- tokenSignedPart := tokenSigned[:MAX_EXTJWT_SIZE]
- tokenSigned = tokenSigned[MAX_EXTJWT_SIZE:]
-
- tokenPartM := tokenM
- tokenPartM.Params = append(tokenPartM.Params, "*", tokenSignedPart)
- c.SendClientSignal("data", tokenPartM.ToLine())
- }
-
- tokenM.Params = append(tokenM.Params, tokenSigned)
- c.SendClientSignal("data", tokenM.ToLine())
-
- return "", nil
- }
-
- return line, nil
-}
diff --git a/deprecated-webircgateway/pkg/webircgateway/config.go b/deprecated-webircgateway/pkg/webircgateway/config.go
deleted file mode 100644
index 019d955..0000000
--- a/deprecated-webircgateway/pkg/webircgateway/config.go
+++ /dev/null
@@ -1,385 +0,0 @@
-package webircgateway
-
-import (
- "errors"
- "net"
- "os"
- "os/exec"
- "path/filepath"
- "strconv"
- "strings"
-
- "github.com/gobwas/glob"
- "gopkg.in/ini.v1"
-)
-
-// ConfigUpstream - An upstream config
-type ConfigUpstream struct {
- // Plugins may assign an arbitary address to an upstream network
- NetworkCommonAddress string
- Hostname string
- Port int
- TLS bool
- Timeout int
- Throttle int
- WebircPassword string
- ServerPassword string
- GatewayName string
- Proxy *ConfigProxy
- Protocol string
- LocalAddr string
-}
-
-// ConfigServer - A web server config
-type ConfigServer struct {
- LocalAddr string
- BindMode os.FileMode
- Port int
- TLS bool
- CertFile string
- KeyFile string
- LetsEncryptCacheDir string
-}
-
-type ConfigProxy struct {
- Type string
- Hostname string
- Port int
- TLS bool
- Username string
- Interface string
-}
-
-// Config - Config options for the running app
-type Config struct {
- gateway *Gateway
- ConfigFile string
- LogLevel int
- Gateway bool
- GatewayName string
- GatewayWhitelist []glob.Glob
- GatewayThrottle int
- GatewayTimeout int
- GatewayWebircPassword map[string]string
- GatewayProtocol string
- GatewayLocalAddr string
- Proxy ConfigServer
- Upstreams []ConfigUpstream
- Servers []ConfigServer
- ServerTransports []string
- RemoteOrigins []glob.Glob
- ReverseProxies []net.IPNet
- Webroot string
- ClientRealname string
- ClientUsername string
- ClientHostname string
- Identd bool
- RequiresVerification bool
- SendQuitOnClientClose string
- ReCaptchaURL string
- ReCaptchaSecret string
- ReCaptchaKey string
- Secret string
- Plugins []string
- DnsblServers []string
- // DnsblAction - "deny" = deny the connection. "verify" = require verification
- DnsblAction string
-}
-
-func NewConfig(gateway *Gateway) *Config {
- return &Config{gateway: gateway}
-}
-
-// ConfigResolvePath - If relative, resolve a path to it's full absolute path relative to the config file
-func (c *Config) ResolvePath(path string) string {
- // Absolute paths should stay as they are
- if path[0:1] == "/" {
- return path
- }
-
- resolved := filepath.Dir(c.ConfigFile)
- resolved = filepath.Clean(resolved + "/" + path)
- return resolved
-}
-
-func (c *Config) SetConfigFile(configFile string) {
- // Config paths starting with $ is executed rather than treated as a path
- if strings.HasPrefix(configFile, "$ ") {
- c.ConfigFile = configFile
- } else {
- c.ConfigFile, _ = filepath.Abs(configFile)
- }
-}
-
-// CurrentConfigFile - Return the full path or command for the config file in use
-func (c *Config) CurrentConfigFile() string {
- return c.ConfigFile
-}
-
-func (c *Config) Load() error {
- var configSrc interface{}
-
- if strings.HasPrefix(c.ConfigFile, "$ ") {
- cmdRawOut, err := exec.Command("sh", "-c", c.ConfigFile[2:]).Output()
- if err != nil {
- return err
- }
-
- configSrc = cmdRawOut
- } else {
- configSrc = c.ConfigFile
- }
-
- cfg, err := ini.LoadSources(ini.LoadOptions{AllowBooleanKeys: true, SpaceBeforeInlineComment: true}, configSrc)
- if err != nil {
- return err
- }
-
- // Clear the existing config
- c.Gateway = false
- c.GatewayWebircPassword = make(map[string]string)
- c.Proxy = ConfigServer{}
- c.Upstreams = []ConfigUpstream{}
- c.Servers = []ConfigServer{}
- c.ServerTransports = []string{}
- c.RemoteOrigins = []glob.Glob{}
- c.GatewayWhitelist = []glob.Glob{}
- c.ReverseProxies = []net.IPNet{}
- c.Webroot = ""
- c.ReCaptchaURL = ""
- c.ReCaptchaSecret = ""
- c.ReCaptchaKey = ""
- c.RequiresVerification = false
- c.Secret = ""
- c.SendQuitOnClientClose = ""
- c.ClientRealname = ""
- c.ClientUsername = ""
- c.ClientHostname = ""
- c.DnsblServers = []string{}
- c.DnsblAction = ""
-
- for _, section := range cfg.Sections() {
- if strings.Index(section.Name(), "DEFAULT") == 0 {
- c.LogLevel = section.Key("logLevel").MustInt(3)
- if c.LogLevel < 1 || c.LogLevel > 3 {
- c.gateway.Log(3, "Config option logLevel must be between 1-3. Setting default value of 3.")
- c.LogLevel = 3
- }
-
- c.Identd = section.Key("identd").MustBool(false)
-
- c.GatewayName = section.Key("gateway_name").MustString("")
- if strings.Contains(c.GatewayName, " ") {
- c.gateway.Log(3, "Config option gateway_name must not contain spaces")
- c.GatewayName = ""
- }
-
- c.Secret = section.Key("secret").MustString("")
- c.SendQuitOnClientClose = section.Key("send_quit_on_client_close").MustString("Connection closed")
- }
-
- if section.Name() == "verify" {
- captchaSecret := section.Key("recaptcha_secret").MustString("")
- captchaKey := section.Key("recaptcha_key").MustString("")
- if captchaSecret != "" && captchaKey != "" {
- c.RequiresVerification = section.Key("required").MustBool(false)
- c.ReCaptchaSecret = captchaSecret
- }
- c.ReCaptchaURL = section.Key("recaptcha_url").MustString("https://www.google.com/recaptcha/api/siteverify")
- }
-
- if section.Name() == "dnsbl" {
- c.DnsblAction = section.Key("action").MustString("")
- }
-
- if section.Name() == "dnsbl.servers" {
- c.DnsblServers = append(c.DnsblServers, section.KeyStrings()...)
- }
-
- if section.Name() == "gateway" {
- c.Gateway = section.Key("enabled").MustBool(false)
- c.GatewayTimeout = section.Key("timeout").MustInt(10)
- c.GatewayThrottle = section.Key("throttle").MustInt(2)
-
- validProtocols := []string{"tcp", "tcp4", "tcp6"}
- c.GatewayProtocol = stringInSliceOrDefault(section.Key("protocol").MustString(""), "tcp", validProtocols)
- c.GatewayLocalAddr = section.Key("localaddr").MustString("")
- }
-
- if section.Name() == "gateway.webirc" {
- for _, serverAddr := range section.KeyStrings() {
- c.GatewayWebircPassword[serverAddr] = section.Key(serverAddr).MustString("")
- }
- }
-
- if strings.Index(section.Name(), "clients") == 0 {
- c.ClientUsername = section.Key("username").MustString("")
- c.ClientRealname = section.Key("realname").MustString("")
- c.ClientHostname = section.Key("hostname").MustString("")
- }
-
- if strings.Index(section.Name(), "fileserving") == 0 {
- if section.Key("enabled").MustBool(false) {
- c.Webroot = section.Key("webroot").MustString("")
- }
- }
-
- if strings.Index(section.Name(), "server.") == 0 {
- server := ConfigServer{}
- server.LocalAddr = confKeyAsString(section.Key("bind"), "127.0.0.1")
- rawMode := confKeyAsString(section.Key("bind_mode"), "")
- mode, err := strconv.ParseInt(rawMode, 8, 32)
- if err != nil {
- mode = 0755
- }
- server.BindMode = os.FileMode(mode)
- server.Port = confKeyAsInt(section.Key("port"), 80)
- server.TLS = confKeyAsBool(section.Key("tls"), false)
- server.CertFile = confKeyAsString(section.Key("cert"), "")
- server.KeyFile = confKeyAsString(section.Key("key"), "")
- server.LetsEncryptCacheDir = confKeyAsString(section.Key("letsencrypt_cache"), "")
-
- if strings.HasSuffix(server.LetsEncryptCacheDir, ".cache") {
- return errors.New("Syntax has changed. Please update letsencrypt_cache to a directory path (eg ./cache)")
- }
-
- c.Servers = append(c.Servers, server)
- }
-
- if section.Name() == "proxy" {
- server := ConfigServer{}
- server.LocalAddr = confKeyAsString(section.Key("bind"), "0.0.0.0")
- server.Port = confKeyAsInt(section.Key("port"), 7999)
- c.Proxy = server
- }
-
- if strings.Index(section.Name(), "upstream.") == 0 {
- upstream := ConfigUpstream{}
-
- validProtocols := []string{"tcp", "tcp4", "tcp6", "unix"}
- upstream.Protocol = stringInSliceOrDefault(section.Key("protocol").MustString(""), "tcp", validProtocols)
-
- hostname := section.Key("hostname").MustString("127.0.0.1")
- if strings.HasPrefix(strings.ToLower(hostname), "unix:") {
- upstream.Protocol = "unix"
- upstream.Hostname = hostname[5:]
- } else {
- upstream.Hostname = hostname
- upstream.Port = section.Key("port").MustInt(6667)
- upstream.TLS = section.Key("tls").MustBool(false)
- }
-
- upstream.Timeout = section.Key("timeout").MustInt(10)
- upstream.Throttle = section.Key("throttle").MustInt(2)
- upstream.WebircPassword = section.Key("webirc").MustString("")
- upstream.ServerPassword = section.Key("serverpassword").MustString("")
- upstream.LocalAddr = section.Key("localaddr").MustString("")
-
- upstream.GatewayName = section.Key("gateway_name").MustString("")
- if strings.Contains(upstream.GatewayName, " ") {
- c.gateway.Log(3, "Config option gateway_name must not contain spaces")
- upstream.GatewayName = ""
- }
-
- upstream.NetworkCommonAddress = section.Key("network_common_address").MustString("")
-
- c.Upstreams = append(c.Upstreams, upstream)
- }
-
- // "engines" is now legacy naming
- if section.Name() == "engines" || section.Name() == "transports" {
- for _, transport := range section.KeyStrings() {
- c.ServerTransports = append(c.ServerTransports, strings.Trim(transport, "\n"))
- }
- }
-
- if strings.Index(section.Name(), "plugins") == 0 {
- for _, plugin := range section.KeyStrings() {
- c.Plugins = append(c.Plugins, strings.Trim(plugin, "\n"))
- }
- }
-
- if strings.Index(section.Name(), "allowed_origins") == 0 {
- for _, origin := range section.KeyStrings() {
- match, err := glob.Compile(origin)
- if err != nil {
- c.gateway.Log(3, "Config section allowed_origins has invalid match, "+origin)
- continue
- }
- c.RemoteOrigins = append(c.RemoteOrigins, match)
- }
- }
-
- if strings.Index(section.Name(), "gateway.whitelist") == 0 {
- for _, origin := range section.KeyStrings() {
- match, err := glob.Compile(origin)
- if err != nil {
- c.gateway.Log(3, "Config section gateway.whitelist has invalid match, "+origin)
- continue
- }
- c.GatewayWhitelist = append(c.GatewayWhitelist, match)
- }
- }
-
- if strings.Index(section.Name(), "reverse_proxies") == 0 {
- for _, cidrRange := range section.KeyStrings() {
- _, validRange, cidrErr := net.ParseCIDR(cidrRange)
- if cidrErr != nil {
- c.gateway.Log(3, "Config section reverse_proxies has invalid entry, "+cidrRange)
- continue
- }
- c.ReverseProxies = append(c.ReverseProxies, *validRange)
- }
- }
- }
-
- return nil
-}
-
-func confKeyAsString(key *ini.Key, def string) string {
- val := def
-
- str := key.String()
- if len(str) > 1 && str[:1] == "$" {
- val = os.Getenv(str[1:])
- } else {
- val = key.MustString(def)
- }
-
- return val
-}
-
-func confKeyAsInt(key *ini.Key, def int) int {
- val := def
-
- str := key.String()
- if len(str) > 1 && str[:1] == "$" {
- envVal := os.Getenv(str[1:])
- envValInt, err := strconv.Atoi(envVal)
- if err == nil {
- val = envValInt
- }
- } else {
- val = key.MustInt(def)
- }
-
- return val
-}
-
-func confKeyAsBool(key *ini.Key, def bool) bool {
- val := def
-
- str := key.String()
- if len(str) > 1 && str[:1] == "$" {
- envVal := os.Getenv(str[1:])
- if envVal == "0" || envVal == "false" || envVal == "no" {
- val = false
- } else {
- val = true
- }
- } else {
- val = key.MustBool(def)
- }
-
- return val
-}
diff --git a/deprecated-webircgateway/pkg/webircgateway/gateway.go b/deprecated-webircgateway/pkg/webircgateway/gateway.go
deleted file mode 100644
index 47169ef..0000000
--- a/deprecated-webircgateway/pkg/webircgateway/gateway.go
+++ /dev/null
@@ -1,278 +0,0 @@
-package webircgateway
-
-import (
- "crypto/tls"
- "encoding/json"
- "fmt"
- "net"
- "net/http"
- "os"
- "strconv"
- "strings"
- "sync"
-
- "errors"
-
- "github.com/kiwiirc/webircgateway/pkg/identd"
- "github.com/kiwiirc/webircgateway/pkg/proxy"
- cmap "github.com/orcaman/concurrent-map"
-)
-
-var (
- Version = "-"
-)
-
-type Gateway struct {
- Config *Config
- HttpRouter *http.ServeMux
- LogOutput chan string
- messageTags *MessageTagManager
- identdServ identd.Server
- Clients cmap.ConcurrentMap
- Acme *LEManager
- Function string
- httpSrvs []*http.Server
- httpSrvsMu sync.Mutex
- closeWg sync.WaitGroup
-}
-
-func NewGateway(function string) *Gateway {
- s := &Gateway{}
- s.Function = function
- s.Config = NewConfig(s)
- s.HttpRouter = http.NewServeMux()
- s.LogOutput = make(chan string, 5)
- s.identdServ = identd.NewIdentdServer()
- s.messageTags = NewMessageTagManager()
- // Clients hold a map lookup for all the connected clients
- s.Clients = cmap.New()
- s.Acme = NewLetsEncryptManager(s)
-
- return s
-}
-
-func (s *Gateway) Log(level int, format string, args ...interface{}) {
- if level < s.Config.LogLevel {
- return
- }
-
- levels := [...]string{"L_DEBUG", "L_INFO", "L_WARN"}
- line := fmt.Sprintf(levels[level-1]+" "+format, args...)
- s.LogOutput <- line
-}
-
-func (s *Gateway) Start() {
- s.closeWg.Add(1)
-
- if s.Function == "gateway" {
- s.maybeStartStaticFileServer()
- s.initHttpRoutes()
- s.maybeStartIdentd()
-
- for _, serverConfig := range s.Config.Servers {
- go s.startServer(serverConfig)
- }
- }
-
- if s.Function == "proxy" {
- proxy.Start(fmt.Sprintf("%s:%d", s.Config.Proxy.LocalAddr, s.Config.Proxy.Port))
- }
-}
-
-func (s *Gateway) Close() {
- hook := HookGatewayClosing{}
- hook.Dispatch("gateway.closing")
-
- defer s.closeWg.Done()
-
- s.httpSrvsMu.Lock()
- defer s.httpSrvsMu.Unlock()
-
- for _, httpSrv := range s.httpSrvs {
- httpSrv.Close()
- }
-}
-
-func (s *Gateway) WaitClose() {
- s.closeWg.Wait()
-}
-
-func (s *Gateway) maybeStartStaticFileServer() {
- if s.Config.Webroot != "" {
- webroot := s.Config.ResolvePath(s.Config.Webroot)
- s.Log(2, "Serving files from %s", webroot)
- s.HttpRouter.Handle("/", http.FileServer(http.Dir(webroot)))
- }
-}
-
-func (s *Gateway) initHttpRoutes() error {
- // Add all the transport routes
- engineConfigured := false
- for _, transport := range s.Config.ServerTransports {
- switch transport {
- case "kiwiirc":
- t := &TransportKiwiirc{}
- t.Init(s)
- engineConfigured = true
- case "websocket":
- t := &TransportWebsocket{}
- t.Init(s)
- engineConfigured = true
- case "sockjs":
- t := &TransportSockjs{}
- t.Init(s)
- engineConfigured = true
- default:
- s.Log(3, "Invalid server engine: '%s'", transport)
- }
- }
-
- if !engineConfigured {
- s.Log(3, "No server engines configured")
- return errors.New("No server engines configured")
- }
-
- // Add some general server info about this webircgateway instance
- s.HttpRouter.HandleFunc("/webirc/info", func(w http.ResponseWriter, r *http.Request) {
- out, _ := json.Marshal(map[string]interface{}{
- "name": "webircgateway",
- "version": Version,
- })
-
- w.Write(out)
- })
-
- s.HttpRouter.HandleFunc("/webirc/_status", func(w http.ResponseWriter, r *http.Request) {
- if !isPrivateIP(s.GetRemoteAddressFromRequest(r)) {
- w.WriteHeader(403)
- return
- }
-
- out := ""
- for item := range s.Clients.IterBuffered() {
- c := item.Val.(*Client)
- line := fmt.Sprintf(
- "%s:%d %s %s!%s %s %s",
- c.UpstreamConfig.Hostname,
- c.UpstreamConfig.Port,
- c.State,
- c.IrcState.Nick,
- c.IrcState.Username,
- c.RemoteAddr,
- c.RemoteHostname,
- )
-
- // Allow plugins to add their own status data
- hook := HookStatus{}
- hook.Client = c
- hook.Line = line
- hook.Dispatch("status.client")
- if !hook.Halt {
- out += hook.Line + "\n"
- }
-
- }
-
- w.Write([]byte(out))
- })
-
- return nil
-}
-
-func (s *Gateway) maybeStartIdentd() {
- if s.Config.Identd {
- err := s.identdServ.Run()
- if err != nil {
- s.Log(3, "Error starting identd server: %s", err.Error())
- } else {
- s.Log(2, "Identd server started")
- }
- }
-}
-
-func (s *Gateway) startServer(conf ConfigServer) {
- addr := fmt.Sprintf("%s:%d", conf.LocalAddr, conf.Port)
-
- if strings.HasPrefix(strings.ToLower(conf.LocalAddr), "tcp:") {
- t := &TransportTcp{}
- t.Init(s)
- t.Start(conf.LocalAddr[4:] + ":" + strconv.Itoa(conf.Port))
- } else if conf.TLS && conf.LetsEncryptCacheDir == "" {
- if conf.CertFile == "" || conf.KeyFile == "" {
- s.Log(3, "'cert' and 'key' options must be set for TLS servers")
- return
- }
-
- tlsCert := s.Config.ResolvePath(conf.CertFile)
- tlsKey := s.Config.ResolvePath(conf.KeyFile)
-
- s.Log(2, "Listening with TLS on %s", addr)
- keyPair, keyPairErr := tls.LoadX509KeyPair(tlsCert, tlsKey)
- if keyPairErr != nil {
- s.Log(3, "Failed to listen with TLS, certificate error: %s", keyPairErr.Error())
- return
- }
- srv := &http.Server{
- Addr: addr,
- TLSConfig: &tls.Config{
- Certificates: []tls.Certificate{keyPair},
- },
- Handler: s.HttpRouter,
- }
- s.httpSrvsMu.Lock()
- s.httpSrvs = append(s.httpSrvs, srv)
- s.httpSrvsMu.Unlock()
-
- // Don't use HTTP2 since it doesn't support websockets
- srv.TLSNextProto = make(map[string]func(*http.Server, *tls.Conn, http.Handler))
-
- err := srv.ListenAndServeTLS("", "")
- if err != nil && err != http.ErrServerClosed {
- s.Log(3, "Failed to listen with TLS: %s", err.Error())
- }
- } else if conf.TLS && conf.LetsEncryptCacheDir != "" {
- s.Log(2, "Listening with letsencrypt TLS on %s", addr)
- leManager := s.Acme.Get(conf.LetsEncryptCacheDir)
- srv := &http.Server{
- Addr: addr,
- TLSConfig: &tls.Config{
- GetCertificate: leManager.GetCertificate,
- },
- Handler: s.HttpRouter,
- }
- s.httpSrvsMu.Lock()
- s.httpSrvs = append(s.httpSrvs, srv)
- s.httpSrvsMu.Unlock()
-
- // Don't use HTTP2 since it doesn't support websockets
- srv.TLSNextProto = make(map[string]func(*http.Server, *tls.Conn, http.Handler))
-
- err := srv.ListenAndServeTLS("", "")
- if err != nil && err != http.ErrServerClosed {
- s.Log(3, "Listening with letsencrypt failed: %s", err.Error())
- }
- } else if strings.HasPrefix(strings.ToLower(conf.LocalAddr), "unix:") {
- socketFile := conf.LocalAddr[5:]
- s.Log(2, "Listening on %s", socketFile)
- os.Remove(socketFile)
- server, serverErr := net.Listen("unix", socketFile)
- if serverErr != nil {
- s.Log(3, serverErr.Error())
- return
- }
- os.Chmod(socketFile, conf.BindMode)
- http.Serve(server, s.HttpRouter)
- } else {
- s.Log(2, "Listening on %s", addr)
- srv := &http.Server{Addr: addr, Handler: s.HttpRouter}
-
- s.httpSrvsMu.Lock()
- s.httpSrvs = append(s.httpSrvs, srv)
- s.httpSrvsMu.Unlock()
-
- err := srv.ListenAndServe()
- if err != nil && err != http.ErrServerClosed {
- s.Log(3, err.Error())
- }
- }
-}
diff --git a/deprecated-webircgateway/pkg/webircgateway/gateway_utils.go b/deprecated-webircgateway/pkg/webircgateway/gateway_utils.go
deleted file mode 100644
index 4b2a38d..0000000
--- a/deprecated-webircgateway/pkg/webircgateway/gateway_utils.go
+++ /dev/null
@@ -1,133 +0,0 @@
-package webircgateway
-
-import (
- "errors"
- "math/rand"
- "net"
- "net/http"
- "strings"
-)
-
-var v4LoopbackAddr = net.ParseIP("127.0.0.1")
-
-func (s *Gateway) NewClient() *Client {
- return NewClient(s)
-}
-
-func (s *Gateway) IsClientOriginAllowed(originHeader string) bool {
- // Empty list of origins = all origins allowed
- if len(s.Config.RemoteOrigins) == 0 {
- return true
- }
-
- // No origin header = running on the same page
- if originHeader == "" {
- return true
- }
-
- foundMatch := false
-
- for _, originMatch := range s.Config.RemoteOrigins {
- if originMatch.Match(originHeader) {
- foundMatch = true
- break
- }
- }
-
- return foundMatch
-}
-
-func (s *Gateway) isIrcAddressAllowed(addr string) bool {
- // Empty whitelist = all destinations allowed
- if len(s.Config.GatewayWhitelist) == 0 {
- return true
- }
-
- foundMatch := false
-
- for _, addrMatch := range s.Config.GatewayWhitelist {
- if addrMatch.Match(addr) {
- foundMatch = true
- break
- }
- }
-
- return foundMatch
-}
-
-func (s *Gateway) findUpstream() (ConfigUpstream, error) {
- var ret ConfigUpstream
-
- if len(s.Config.Upstreams) == 0 {
- return ret, errors.New("No upstreams available")
- }
-
- randIdx := rand.Intn(len(s.Config.Upstreams))
- ret = s.Config.Upstreams[randIdx]
-
- return ret, nil
-}
-
-func (s *Gateway) findWebircPassword(ircHost string) string {
- pass, exists := s.Config.GatewayWebircPassword[strings.ToLower(ircHost)]
- if !exists {
- pass = ""
- }
-
- return pass
-}
-
-func (s *Gateway) GetRemoteAddressFromRequest(req *http.Request) net.IP {
- remoteIP := remoteIPFromRequest(req)
-
- // If the remoteIP is not in a whitelisted reverse proxy range, don't trust
- // the headers and use the remoteIP as the users IP
- if !s.isTrustedProxy(remoteIP) {
- return remoteIP
- }
-
- headerVal := req.Header.Get("x-forwarded-for")
- ips := strings.Split(headerVal, ",")
- ipStr := strings.Trim(ips[0], " ")
- if ipStr != "" {
- ip := net.ParseIP(ipStr)
- if ip != nil {
- remoteIP = ip
- }
- }
-
- return remoteIP
-
-}
-
-func (s *Gateway) isRequestSecure(req *http.Request) bool {
- remoteIP := remoteIPFromRequest(req)
-
- // If the remoteIP is not in a whitelisted reverse proxy range, don't trust
- // the headers and check the request directly
- if !s.isTrustedProxy(remoteIP) {
- return req.TLS != nil
- }
-
- fwdProto := req.Header.Get("x-forwarded-proto")
- return strings.EqualFold(fwdProto, "https")
-}
-
-func (s *Gateway) isTrustedProxy(remoteIP net.IP) bool {
- for _, cidrRange := range s.Config.ReverseProxies {
- if cidrRange.Contains(remoteIP) {
- return true
- }
- }
- return false
-}
-
-func remoteIPFromRequest(req *http.Request) net.IP {
- if req.RemoteAddr == "@" {
- // remote address is unix socket, treat it as loopback interface
- return v4LoopbackAddr
- }
-
- remoteAddr, _, _ := net.SplitHostPort(req.RemoteAddr)
- return net.ParseIP(remoteAddr)
-}
diff --git a/deprecated-webircgateway/pkg/webircgateway/hooks.go b/deprecated-webircgateway/pkg/webircgateway/hooks.go
deleted file mode 100644
index 1bfd564..0000000
--- a/deprecated-webircgateway/pkg/webircgateway/hooks.go
+++ /dev/null
@@ -1,152 +0,0 @@
-package webircgateway
-
-import "github.com/kiwiirc/webircgateway/pkg/irc"
-
-var hooksRegistered map[string][]interface{}
-
-func init() {
- hooksRegistered = make(map[string][]interface{})
-}
-
-func HookRegister(hookName string, p interface{}) {
- _, exists := hooksRegistered[hookName]
- if !exists {
- hooksRegistered[hookName] = make([]interface{}, 0)
- }
-
- hooksRegistered[hookName] = append(hooksRegistered[hookName], p)
-}
-
-type Hook struct {
- ID string
- Halt bool
-}
-
-func (h *Hook) getCallbacks(eventType string) []interface{} {
- var f []interface{}
- f = make([]interface{}, 0)
-
- callbacks, exists := hooksRegistered[eventType]
- if exists {
- f = callbacks
- }
-
- return f
-}
-
-/**
- * HookIrcConnectionPre
- * Dispatched just before an IRC connection is attempted
- * Types: irc.connection.pre
- */
-type HookIrcConnectionPre struct {
- Hook
- Client *Client
- UpstreamConfig *ConfigUpstream
-}
-
-func (h *HookIrcConnectionPre) Dispatch(eventType string) {
- for _, p := range h.getCallbacks(eventType) {
- if f, ok := p.(func(*HookIrcConnectionPre)); ok {
- f(h)
- }
- }
-}
-
-/**
- * HookIrcLine
- * Dispatched when either:
- * * A line arrives from the IRCd, before sending to the client
- * * A line arrives from the client, before sending to the IRCd
- * Types: irc.line
- */
-type HookIrcLine struct {
- Hook
- Client *Client
- UpstreamConfig *ConfigUpstream
- Line string
- Message *irc.Message
- ToServer bool
-}
-
-func (h *HookIrcLine) Dispatch(eventType string) {
- for _, p := range h.getCallbacks(eventType) {
- if f, ok := p.(func(*HookIrcLine)); ok {
- f(h)
- }
- }
-}
-
-/**
- * HookClientState
- * Dispatched after a client connects or disconnects
- * Types: client.state
- */
-type HookClientState struct {
- Hook
- Client *Client
- Connected bool
-}
-
-func (h *HookClientState) Dispatch(eventType string) {
- for _, p := range h.getCallbacks(eventType) {
- if f, ok := p.(func(*HookClientState)); ok {
- f(h)
- }
- }
-}
-
-/**
- * HookClientInit
- * Dispatched directly after a new Client instance has been created
- * Types: client.init
- */
-type HookClientInit struct {
- Hook
- Client *Client
- Connected bool
-}
-
-func (h *HookClientInit) Dispatch(eventType string) {
- for _, p := range h.getCallbacks(eventType) {
- if f, ok := p.(func(*HookClientInit)); ok {
- f(h)
- }
- }
-}
-
-/**
- * HookStatus
- * Dispatched for each line output of the _status HTTP request
- * Types: status.client
- */
-type HookStatus struct {
- Hook
- Client *Client
- Line string
-}
-
-func (h *HookStatus) Dispatch(eventType string) {
- for _, p := range h.getCallbacks(eventType) {
- if f, ok := p.(func(*HookStatus)); ok {
- f(h)
- }
- }
-}
-
-/**
- * HookGatewayClosing
- * Dispatched when the gateway has been told to shutdown
- * Types: gateway.closing
- */
-type HookGatewayClosing struct {
- Hook
-}
-
-func (h *HookGatewayClosing) Dispatch(eventType string) {
- for _, p := range h.getCallbacks(eventType) {
- if f, ok := p.(func(*HookGatewayClosing)); ok {
- f(h)
- }
- }
-}
diff --git a/deprecated-webircgateway/pkg/webircgateway/letsencrypt.go b/deprecated-webircgateway/pkg/webircgateway/letsencrypt.go
deleted file mode 100644
index ffa6afe..0000000
--- a/deprecated-webircgateway/pkg/webircgateway/letsencrypt.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package webircgateway
-
-import (
- "context"
- "strings"
- "sync"
-
- "golang.org/x/crypto/acme/autocert"
-)
-
-type LEManager struct {
- // ensure only one instance of the manager and handler is running
- // while allowing multiple listeners to use it
- Mutex sync.Mutex
- Manager *autocert.Manager
- gateway *Gateway
-}
-
-func NewLetsEncryptManager(gateway *Gateway) *LEManager {
- return &LEManager{gateway: gateway}
-}
-
-func (le *LEManager) Get(certCacheDir string) *autocert.Manager {
- le.Mutex.Lock()
- defer le.Mutex.Unlock()
-
- // Create it if it doesn't already exist
- if le.Manager == nil {
- le.Manager = &autocert.Manager{
- Prompt: autocert.AcceptTOS,
- Cache: autocert.DirCache(strings.TrimRight(certCacheDir, "/")),
- HostPolicy: func(ctx context.Context, host string) error {
- le.gateway.Log(2, "Automatically requesting a HTTPS certificate for %s", host)
- return nil
- },
- }
- le.gateway.HttpRouter.Handle("/.well-known/", le.Manager.HTTPHandler(nil))
- }
-
- return le.Manager
-}
diff --git a/deprecated-webircgateway/pkg/webircgateway/messagetags.go b/deprecated-webircgateway/pkg/webircgateway/messagetags.go
deleted file mode 100644
index 9715ad6..0000000
--- a/deprecated-webircgateway/pkg/webircgateway/messagetags.go
+++ /dev/null
@@ -1,103 +0,0 @@
-package webircgateway
-
-import (
- "strings"
- "sync"
- "time"
-
- "github.com/OneOfOne/xxhash"
- "github.com/kiwiirc/webircgateway/pkg/irc"
-)
-
-type MessageTagManager struct {
- Mutex sync.Mutex
- knownTags map[uint64]MessageTags
- gcTimes map[uint64]time.Time
-}
-type MessageTags struct {
- Tags map[string]string
-}
-
-func NewMessageTagManager() *MessageTagManager {
- tm := &MessageTagManager{
- knownTags: make(map[uint64]MessageTags),
- gcTimes: make(map[uint64]time.Time),
- }
-
- go tm.RunGarbageCollectionLoop()
- return tm
-}
-
-func (tags *MessageTagManager) CanMessageContainClientTags(msg *irc.Message) bool {
- return stringInSlice(msg.Command, []string{
- "PRIVMSG",
- "NOTICE",
- "TAGMSG",
- })
-}
-
-func (tags *MessageTagManager) RunGarbageCollectionLoop() {
- for {
- tags.Mutex.Lock()
- for messageHash, timeCreated := range tags.gcTimes {
- if timeCreated.Add(time.Second * 30).After(time.Now()) {
- delete(tags.knownTags, messageHash)
- }
-
- }
- tags.Mutex.Unlock()
-
- time.Sleep(time.Second * 30)
- }
-}
-
-func (tags *MessageTagManager) AddTagsFromMessage(client *Client, fromNick string, msg *irc.Message) {
- if !tags.CanMessageContainClientTags(msg) {
- return
- }
-
- clientTags := MessageTags{
- Tags: make(map[string]string),
- }
- for tagName, tagVal := range msg.Tags {
- if len(tagName) > 0 && tagName[0] == '+' {
- clientTags.Tags[tagName] = tagVal
- }
- }
-
- if len(clientTags.Tags) > 0 {
- tags.Mutex.Lock()
- msgHash := tags.messageHash(client, fromNick, msg)
- tags.knownTags[msgHash] = clientTags
- tags.gcTimes[msgHash] = time.Now()
- tags.Mutex.Unlock()
- }
-}
-
-func (tags *MessageTagManager) GetTagsFromMessage(client *Client, fromNick string, msg *irc.Message) (MessageTags, bool) {
- if !tags.CanMessageContainClientTags(msg) {
- return MessageTags{}, false
- }
-
- msgHash := tags.messageHash(client, fromNick, msg)
-
- tags.Mutex.Lock()
- defer tags.Mutex.Unlock()
-
- clientTags, tagsExist := tags.knownTags[msgHash]
- if !tagsExist {
- return clientTags, false
- }
-
- return clientTags, true
-}
-
-func (tags *MessageTagManager) messageHash(client *Client, fromNick string, msg *irc.Message) uint64 {
- h := xxhash.New64()
- h.WriteString(strings.ToLower(client.UpstreamConfig.Hostname))
- h.WriteString(strings.ToLower(fromNick))
- // make target case insensitive
- h.WriteString(strings.ToLower(msg.GetParam(0, "")))
- h.WriteString(msg.GetParam(1, ""))
- return h.Sum64()
-}
diff --git a/deprecated-webircgateway/pkg/webircgateway/transport_kiwiirc.go b/deprecated-webircgateway/pkg/webircgateway/transport_kiwiirc.go
deleted file mode 100644
index e5247e8..0000000
--- a/deprecated-webircgateway/pkg/webircgateway/transport_kiwiirc.go
+++ /dev/null
@@ -1,206 +0,0 @@
-package webircgateway
-
-import (
- "fmt"
- "log"
- "net"
- "net/http"
- "runtime/debug"
- "strings"
- "sync"
-
- "github.com/gorilla/websocket"
- "github.com/igm/sockjs-go/v3/sockjs"
- cmap "github.com/orcaman/concurrent-map"
-)
-
-type TransportKiwiirc struct {
- gateway *Gateway
-}
-
-func (t *TransportKiwiirc) Init(g *Gateway) {
- t.gateway = g
- sockjsOptions := sockjs.DefaultOptions
- sockjsOptions.WebsocketUpgrader = &websocket.Upgrader{
- // Origin is checked within the session handler
- CheckOrigin: func(_ *http.Request) bool { return true },
- }
- handler := sockjs.NewHandler("/webirc/kiwiirc", sockjsOptions, t.sessionHandler)
- t.gateway.HttpRouter.Handle("/webirc/kiwiirc/", handler)
-}
-
-func (t *TransportKiwiirc) makeChannel(chanID string, ws sockjs.Session) *TransportKiwiircChannel {
- client := t.gateway.NewClient()
-
- originHeader := strings.ToLower(ws.Request().Header.Get("Origin"))
- if !t.gateway.IsClientOriginAllowed(originHeader) {
- client.Log(2, "Origin %s not allowed. Closing connection", originHeader)
- ws.Close(0, "Origin not allowed")
- return nil
- }
-
- client.RemoteAddr = t.gateway.GetRemoteAddressFromRequest(ws.Request()).String()
-
- clientHostnames, err := net.LookupAddr(client.RemoteAddr)
- if err != nil || len(clientHostnames) == 0 {
- client.RemoteHostname = client.RemoteAddr
- } else {
- // FQDNs include a . at the end. Strip it out
- potentialHostname := strings.Trim(clientHostnames[0], ".")
-
- // Must check that the resolved hostname also resolves back to the users IP
- addr, err := net.LookupIP(potentialHostname)
- if err == nil && len(addr) == 1 && addr[0].String() == client.RemoteAddr {
- client.RemoteHostname = potentialHostname
- } else {
- client.RemoteHostname = client.RemoteAddr
- }
- }
-
- if t.gateway.isRequestSecure(ws.Request()) {
- client.Tags["secure"] = ""
- }
-
- // This doesn't make sense to have since the remote port may change between requests. Only
- // here for testing purposes for now.
- _, remoteAddrPort, _ := net.SplitHostPort(ws.Request().RemoteAddr)
- client.Tags["remote-port"] = remoteAddrPort
-
- client.Log(2, "New kiwiirc channel on %s from %s %s", ws.Request().Host, client.RemoteAddr, client.RemoteHostname)
- client.Ready()
-
- channel := &TransportKiwiircChannel{
- Id: chanID,
- Client: client,
- Conn: ws,
- waitForClose: make(chan bool),
- Closed: false,
- }
-
- go channel.listenForSignals()
-
- return channel
-}
-
-func (t *TransportKiwiirc) sessionHandler(session sockjs.Session) {
- // Don't let a single users error kill the entire service for everyone
- defer func() {
- if r := recover(); r != nil {
- log.Printf("[ERROR] Recovered from %s\n%s", r, debug.Stack())
- }
- }()
-
- channels := cmap.New()
-
- // Read from sockjs
- go func() {
- for {
- msg, err := session.Recv()
- if err == nil && len(msg) > 0 {
- idEnd := strings.Index(msg, " ")
- if idEnd == -1 {
- // msg is in the form of ":chanId"
- chanID := msg[1:]
-
- c, channelExists := channels.Get(chanID)
- if channelExists {
- channel := c.(*TransportKiwiircChannel)
- channel.close()
- }
-
- if !channelExists {
- channel := t.makeChannel(chanID, session)
- if channel == nil {
- continue
- }
- channels.Set(chanID, channel)
-
- // When the channel closes, remove it from the map again
- go func() {
- <-channel.waitForClose
- channel.Client.Log(2, "Removing channel from connection")
- channels.Remove(chanID)
- }()
- }
-
- session.Send(":" + chanID)
-
- } else {
- // msg is in the form of ":chanId data"
- chanID := msg[1:idEnd]
- data := msg[idEnd+1:]
-
- channel, channelExists := channels.Get(chanID)
- if channelExists {
- c := channel.(*TransportKiwiircChannel)
- c.handleIncomingLine(data)
- }
- }
- } else if err != nil {
- t.gateway.Log(1, "kiwi connection closed (%s)", err.Error())
- break
- }
- }
-
- for channel := range channels.IterBuffered() {
- c := channel.Val.(*TransportKiwiircChannel)
- c.Closed = true
- c.Client.StartShutdown("client_closed")
- }
- }()
-}
-
-type TransportKiwiircChannel struct {
- Conn sockjs.Session
- Client *Client
- Id string
- waitForClose chan bool
- ClosedLock sync.Mutex
- Closed bool
-}
-
-func (c *TransportKiwiircChannel) listenForSignals() {
- for {
- signal, ok := <-c.Client.Signals
- if !ok {
- break
- }
- c.Client.Log(1, "signal:%s %s", signal[0], signal[1])
- if signal[0] == "state" {
- if signal[1] == "connected" {
- c.Conn.Send(fmt.Sprintf(":%s control connected", c.Id))
- } else if signal[1] == "closed" {
- c.Conn.Send(fmt.Sprintf(":%s control closed %s", c.Id, signal[2]))
- }
- }
-
- if signal[0] == "data" {
- toSend := strings.Trim(signal[1], "\r\n")
- c.Conn.Send(fmt.Sprintf(":%s %s", c.Id, toSend))
- }
- }
-
- c.ClosedLock.Lock()
-
- c.Closed = true
- close(c.Client.Recv)
- close(c.waitForClose)
-
- c.ClosedLock.Unlock()
-}
-
-func (c *TransportKiwiircChannel) handleIncomingLine(line string) {
- c.ClosedLock.Lock()
-
- if !c.Closed {
- c.Client.Recv <- line
- }
-
- c.ClosedLock.Unlock()
-}
-
-func (c *TransportKiwiircChannel) close() {
- if c.Client.upstream != nil {
- c.Client.upstream.Close()
- }
-}
diff --git a/deprecated-webircgateway/pkg/webircgateway/transport_sockjs.go b/deprecated-webircgateway/pkg/webircgateway/transport_sockjs.go
deleted file mode 100644
index da4891f..0000000
--- a/deprecated-webircgateway/pkg/webircgateway/transport_sockjs.go
+++ /dev/null
@@ -1,107 +0,0 @@
-package webircgateway
-
-import (
- "net"
- "net/http"
- "strings"
-
- "github.com/gorilla/websocket"
- "github.com/igm/sockjs-go/v3/sockjs"
-)
-
-type TransportSockjs struct {
- gateway *Gateway
-}
-
-func (t *TransportSockjs) Init(g *Gateway) {
- t.gateway = g
- sockjsOptions := sockjs.DefaultOptions
- sockjsOptions.WebsocketUpgrader = &websocket.Upgrader{
- // Origin is checked within the session handler
- CheckOrigin: func(_ *http.Request) bool { return true },
- }
- sockjsHandler := sockjs.NewHandler("/webirc/sockjs", sockjsOptions, t.sessionHandler)
- t.gateway.HttpRouter.Handle("/webirc/sockjs/", sockjsHandler)
-}
-
-func (t *TransportSockjs) sessionHandler(session sockjs.Session) {
- client := t.gateway.NewClient()
-
- originHeader := strings.ToLower(session.Request().Header.Get("Origin"))
- if !t.gateway.IsClientOriginAllowed(originHeader) {
- client.Log(2, "Origin %s not allowed. Closing connection", originHeader)
- session.Close(0, "Origin not allowed")
- return
- }
-
- client.RemoteAddr = t.gateway.GetRemoteAddressFromRequest(session.Request()).String()
-
- clientHostnames, err := net.LookupAddr(client.RemoteAddr)
- if err != nil {
- client.RemoteHostname = client.RemoteAddr
- } else {
- // FQDNs include a . at the end. Strip it out
- potentialHostname := strings.Trim(clientHostnames[0], ".")
-
- // Must check that the resolved hostname also resolves back to the users IP
- addr, err := net.LookupIP(potentialHostname)
- if err == nil && len(addr) == 1 && addr[0].String() == client.RemoteAddr {
- client.RemoteHostname = potentialHostname
- } else {
- client.RemoteHostname = client.RemoteAddr
- }
- }
-
- if t.gateway.isRequestSecure(session.Request()) {
- client.Tags["secure"] = ""
- }
-
- // This doesn't make sense to have since the remote port may change between requests. Only
- // here for testing purposes for now.
- _, remoteAddrPort, _ := net.SplitHostPort(session.Request().RemoteAddr)
- client.Tags["remote-port"] = remoteAddrPort
-
- client.Log(2, "New sockjs client on %s from %s %s", session.Request().Host, client.RemoteAddr, client.RemoteHostname)
- client.Ready()
-
- // Read from sockjs
- go func() {
- for {
- msg, err := session.Recv()
- if err == nil && len(msg) > 0 {
- client.Log(1, "client->: %s", msg)
- select {
- case client.Recv <- msg:
- default:
- client.Log(3, "Recv queue full. Dropping data")
- // TODO: Should this really just drop the data or close the connection?
- }
- } else if err != nil {
- client.Log(1, "sockjs connection closed (%s)", err.Error())
- break
- } else if len(msg) == 0 {
- client.Log(1, "Got 0 bytes from websocket")
- }
- }
-
- close(client.Recv)
- }()
-
- // Process signals for the client
- for {
- signal, ok := <-client.Signals
- if !ok {
- break
- }
-
- if signal[0] == "data" {
- line := strings.Trim(signal[1], "\r\n")
- client.Log(1, "->ws: %s", line)
- session.Send(line)
- }
-
- if signal[0] == "state" && signal[1] == "closed" {
- session.Close(0, "Closed")
- }
- }
-}
diff --git a/deprecated-webircgateway/pkg/webircgateway/transport_tcp.go b/deprecated-webircgateway/pkg/webircgateway/transport_tcp.go
deleted file mode 100644
index b4af7b3..0000000
--- a/deprecated-webircgateway/pkg/webircgateway/transport_tcp.go
+++ /dev/null
@@ -1,113 +0,0 @@
-package webircgateway
-
-import (
- "bufio"
- "net"
- "strings"
- "sync"
-)
-
-type TransportTcp struct {
- gateway *Gateway
-}
-
-func (t *TransportTcp) Init(g *Gateway) {
- t.gateway = g
-}
-
-func (t *TransportTcp) Start(lAddr string) {
- l, err := net.Listen("tcp", lAddr)
- if err != nil {
- t.gateway.Log(3, "TCP error listening: "+err.Error())
- return
- }
- // Close the listener when the application closes.
- defer l.Close()
- t.gateway.Log(2, "TCP listening on "+lAddr)
- for {
- // Listen for an incoming connection.
- conn, err := l.Accept()
- if err != nil {
- t.gateway.Log(3, "TCP error accepting: "+err.Error())
- break
- }
- // Handle connections in a new goroutine.
- go t.handleConn(conn)
- }
-}
-
-func (t *TransportTcp) handleConn(conn net.Conn) {
- client := t.gateway.NewClient()
-
- client.RemoteAddr = conn.RemoteAddr().String()
-
- clientHostnames, err := net.LookupAddr(client.RemoteAddr)
- if err != nil {
- client.RemoteHostname = client.RemoteAddr
- } else {
- // FQDNs include a . at the end. Strip it out
- potentialHostname := strings.Trim(clientHostnames[0], ".")
-
- // Must check that the resolved hostname also resolves back to the users IP
- addr, err := net.LookupIP(potentialHostname)
- if err == nil && len(addr) == 1 && addr[0].String() == client.RemoteAddr {
- client.RemoteHostname = potentialHostname
- } else {
- client.RemoteHostname = client.RemoteAddr
- }
- }
-
- _, remoteAddrPort, _ := net.SplitHostPort(conn.RemoteAddr().String())
- client.Tags["remote-port"] = remoteAddrPort
-
- client.Log(2, "New tcp client on %s from %s %s", conn.LocalAddr().String(), client.RemoteAddr, client.RemoteHostname)
- client.Ready()
-
- // We wait until the client send queue has been drained
- var sendDrained sync.WaitGroup
- sendDrained.Add(1)
-
- // Read from TCP
- go func() {
- reader := bufio.NewReader(conn)
- for {
- data, err := reader.ReadString('\n')
- if err == nil {
- message := strings.TrimRight(data, "\r\n")
- client.Log(1, "client->: %s", message)
- select {
- case client.Recv <- message:
- default:
- client.Log(3, "Recv queue full. Dropping data")
- // TODO: Should this really just drop the data or close the connection?
- }
-
- } else {
- client.Log(1, "TCP connection closed (%s)", err.Error())
- break
-
- }
- }
-
- close(client.Recv)
- }()
-
- // Process signals for the client
- for {
- signal, ok := <-client.Signals
- if !ok {
- sendDrained.Done()
- break
- }
-
- if signal[0] == "data" {
- //line := strings.Trim(signal[1], "\r\n")
- line := signal[1] + "\n"
- client.Log(1, "->tcp: %s", signal[1])
- conn.Write([]byte(line))
- }
- }
-
- sendDrained.Wait()
- conn.Close()
-}
diff --git a/deprecated-webircgateway/pkg/webircgateway/transport_websocket.go b/deprecated-webircgateway/pkg/webircgateway/transport_websocket.go
deleted file mode 100644
index 960718b..0000000
--- a/deprecated-webircgateway/pkg/webircgateway/transport_websocket.go
+++ /dev/null
@@ -1,126 +0,0 @@
-package webircgateway
-
-import (
- "fmt"
- "net"
- "net/http"
- "strings"
- "sync"
-
- "golang.org/x/net/websocket"
-)
-
-type TransportWebsocket struct {
- gateway *Gateway
- wsServer *websocket.Server
-}
-
-func (t *TransportWebsocket) Init(g *Gateway) {
- t.gateway = g
- t.wsServer = &websocket.Server{Handler: t.websocketHandler, Handshake: t.checkOrigin}
- t.gateway.HttpRouter.Handle("/webirc/websocket/", t.wsServer)
-}
-
-func (t *TransportWebsocket) checkOrigin(config *websocket.Config, req *http.Request) (err error) {
- config.Origin, err = websocket.Origin(config, req)
-
- var origin string
- if config.Origin != nil {
- origin = config.Origin.String()
- } else {
- origin = ""
- }
-
- if !t.gateway.IsClientOriginAllowed(origin) {
- err = fmt.Errorf("Origin %#v not allowed", origin)
- t.gateway.Log(2, "%s. Closing connection", err)
- return err
- }
-
- return err
-}
-
-func (t *TransportWebsocket) websocketHandler(ws *websocket.Conn) {
- client := t.gateway.NewClient()
-
- client.RemoteAddr = t.gateway.GetRemoteAddressFromRequest(ws.Request()).String()
-
- clientHostnames, err := net.LookupAddr(client.RemoteAddr)
- if err != nil {
- client.RemoteHostname = client.RemoteAddr
- } else {
- // FQDNs include a . at the end. Strip it out
- potentialHostname := strings.Trim(clientHostnames[0], ".")
-
- // Must check that the resolved hostname also resolves back to the users IP
- addr, err := net.LookupIP(potentialHostname)
- if err == nil && len(addr) == 1 && addr[0].String() == client.RemoteAddr {
- client.RemoteHostname = potentialHostname
- } else {
- client.RemoteHostname = client.RemoteAddr
- }
- }
-
- if t.gateway.isRequestSecure(ws.Request()) {
- client.Tags["secure"] = ""
- }
-
- _, remoteAddrPort, _ := net.SplitHostPort(ws.Request().RemoteAddr)
- client.Tags["remote-port"] = remoteAddrPort
-
- client.Log(2, "New websocket client on %s from %s %s", ws.Request().Host, client.RemoteAddr, client.RemoteHostname)
- client.Ready()
-
- // We wait until the client send queue has been drained
- var sendDrained sync.WaitGroup
- sendDrained.Add(1)
-
- // Read from websocket
- go func() {
- for {
- r := make([]byte, 1024)
- len, err := ws.Read(r)
- if err == nil && len > 0 {
- message := string(r[:len])
- client.Log(1, "client->: %s", message)
- select {
- case client.Recv <- message:
- default:
- client.Log(3, "Recv queue full. Dropping data")
- // TODO: Should this really just drop the data or close the connection?
- }
-
- } else if err != nil {
- client.Log(1, "Websocket connection closed (%s)", err.Error())
- break
-
- } else if len == 0 {
- client.Log(1, "Got 0 bytes from websocket")
- }
- }
-
- close(client.Recv)
- }()
-
- // Process signals for the client
- for {
- signal, ok := <-client.Signals
- if !ok {
- sendDrained.Done()
- break
- }
-
- if signal[0] == "data" {
- line := strings.Trim(signal[1], "\r\n")
- client.Log(1, "->ws: %s", line)
- ws.Write([]byte(line))
- }
-
- if signal[0] == "state" && signal[1] == "closed" {
- ws.Close()
- }
- }
-
- sendDrained.Wait()
- ws.Close()
-}
diff --git a/deprecated-webircgateway/pkg/webircgateway/utils.go b/deprecated-webircgateway/pkg/webircgateway/utils.go
deleted file mode 100644
index 1fc687a..0000000
--- a/deprecated-webircgateway/pkg/webircgateway/utils.go
+++ /dev/null
@@ -1,147 +0,0 @@
-package webircgateway
-
-import (
- "context"
- "fmt"
- "net"
- "strings"
- "unicode/utf8"
-
- "golang.org/x/net/html/charset"
- "golang.org/x/time/rate"
-)
-
-var privateIPBlocks []*net.IPNet
-
-func init() {
- for _, cidr := range []string{
- "127.0.0.0/8", // IPv4 loopback
- "10.0.0.0/8", // RFC1918
- "172.16.0.0/12", // RFC1918
- "192.168.0.0/16", // RFC1918
- "::1/128", // IPv6 loopback
- "fe80::/10", // IPv6 link-local
- } {
- _, block, _ := net.ParseCIDR(cidr)
- privateIPBlocks = append(privateIPBlocks, block)
- }
-}
-
-func isPrivateIP(ip net.IP) bool {
- for _, block := range privateIPBlocks {
- if block.Contains(ip) {
- return true
- }
- }
- return false
-}
-
-// Username / realname / webirc hostname can all have configurable replacements
-func makeClientReplacements(format string, client *Client) string {
- ret := format
- ret = strings.Replace(ret, "%a", client.RemoteAddr, -1)
- ret = strings.Replace(ret, "%i", Ipv4ToHex(client.RemoteAddr), -1)
- ret = strings.Replace(ret, "%h", client.RemoteHostname, -1)
- ret = strings.Replace(ret, "%n", client.IrcState.Nick, -1)
- return ret
-}
-
-func Ipv4ToHex(ip string) string {
- var ipParts [4]int
- fmt.Sscanf(ip, "%d.%d.%d.%d", &ipParts[0], &ipParts[1], &ipParts[2], &ipParts[3])
- ipHex := fmt.Sprintf("%02x%02x%02x%02x", ipParts[0], ipParts[1], ipParts[2], ipParts[3])
- return ipHex
-}
-
-func ensureUtf8(s string, fromEncoding string) string {
- if utf8.ValidString(s) {
- return s
- }
-
- encoding, encErr := charset.Lookup(fromEncoding)
- if encoding == nil {
- println("encErr:", encErr)
- return ""
- }
-
- d := encoding.NewDecoder()
- s2, _ := d.String(s)
- return s2
-}
-
-func utf8ToOther(s string, toEncoding string) string {
- if toEncoding == "UTF-8" && utf8.ValidString(s) {
- return s
- }
-
- encoding, _ := charset.Lookup(toEncoding)
- if encoding == nil {
- return ""
- }
-
- e := encoding.NewEncoder()
- s2, _ := e.String(s)
- return s2
-}
-
-func containsOneOf(s string, substrs []string) bool {
- for _, substr := range substrs {
- if strings.Contains(s, substr) {
- return true
- }
- }
-
- return false
-}
-
-func stringInSlice(s string, slice []string) bool {
- for _, v := range slice {
- if v == s {
- return true
- }
- }
- return false
-}
-
-func stringInSliceOrDefault(s, def string, validStrings []string) string {
- if stringInSlice(s, validStrings) {
- return s
- }
- return def
-}
-
-type ThrottledStringChannel struct {
- in chan string
- Input chan<- string
- out chan string
- Output <-chan string
- *rate.Limiter
-}
-
-func NewThrottledStringChannel(wrappedChan chan string, limiter *rate.Limiter) *ThrottledStringChannel {
- out := make(chan string, 50)
-
- c := &ThrottledStringChannel{
- in: wrappedChan,
- Input: wrappedChan,
- out: out,
- Output: out,
- Limiter: limiter,
- }
-
- go c.run()
-
- return c
-}
-
-func (c *ThrottledStringChannel) run() {
- for msg := range c.in {
- // start := time.Now()
- c.Wait(context.Background())
- c.out <- msg
- // elapsed := time.Since(start)
- // fmt.Printf("waited %v to send %v\n", elapsed, msg)
- }
-
- close(c.out)
-}