mirror of
https://github.com/42wim/matterbridge.git
synced 2024-12-23 19:52:41 +01:00
Update lrstanley/girc vendor (#884)
This commit is contained in:
parent
9327810bbf
commit
1532f6e427
2
go.mod
2
go.mod
@ -23,7 +23,7 @@ require (
|
|||||||
github.com/jtolds/gls v4.2.1+incompatible // indirect
|
github.com/jtolds/gls v4.2.1+incompatible // indirect
|
||||||
github.com/keybase/go-keybase-chat-bot v0.0.0-20190816161829-561f10822eb2
|
github.com/keybase/go-keybase-chat-bot v0.0.0-20190816161829-561f10822eb2
|
||||||
github.com/labstack/echo/v4 v4.1.6
|
github.com/labstack/echo/v4 v4.1.6
|
||||||
github.com/lrstanley/girc v0.0.0-20190210212025-51b8e096d398
|
github.com/lrstanley/girc v0.0.0-20190801035559-4fc93959e1a7
|
||||||
github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5 // indirect
|
github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5 // indirect
|
||||||
github.com/lusis/slack-test v0.0.0-20180109053238-3c758769bfa6 // indirect
|
github.com/lusis/slack-test v0.0.0-20180109053238-3c758769bfa6 // indirect
|
||||||
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20190210153444-cc9d05784d5d
|
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20190210153444-cc9d05784d5d
|
||||||
|
4
go.sum
4
go.sum
@ -110,8 +110,8 @@ github.com/labstack/echo/v4 v4.1.6 h1:WOvLa4T1KzWCRpANwz0HGgWDelXSSGwIKtKBbFdHTv
|
|||||||
github.com/labstack/echo/v4 v4.1.6/go.mod h1:kU/7PwzgNxZH4das4XNsSpBSOD09XIF5YEPzjpkGnGE=
|
github.com/labstack/echo/v4 v4.1.6/go.mod h1:kU/7PwzgNxZH4das4XNsSpBSOD09XIF5YEPzjpkGnGE=
|
||||||
github.com/labstack/gommon v0.2.9 h1:heVeuAYtevIQVYkGj6A41dtfT91LrvFG220lavpWhrU=
|
github.com/labstack/gommon v0.2.9 h1:heVeuAYtevIQVYkGj6A41dtfT91LrvFG220lavpWhrU=
|
||||||
github.com/labstack/gommon v0.2.9/go.mod h1:E8ZTmW9vw5az5/ZyHWCp0Lw4OH2ecsaBP1C/NKavGG4=
|
github.com/labstack/gommon v0.2.9/go.mod h1:E8ZTmW9vw5az5/ZyHWCp0Lw4OH2ecsaBP1C/NKavGG4=
|
||||||
github.com/lrstanley/girc v0.0.0-20190210212025-51b8e096d398 h1:a40kRmhA1p2XFJ6gqXfCExSyuDDCp/U9LA8ZY27u2Lk=
|
github.com/lrstanley/girc v0.0.0-20190801035559-4fc93959e1a7 h1:BS9tqL0OCiOGuy/CYYk2gc33fxqaqh5/rhqMKu4tcYA=
|
||||||
github.com/lrstanley/girc v0.0.0-20190210212025-51b8e096d398/go.mod h1:7cRs1SIBfKQ7e3Tam6GKTILSNHzR862JD0JpINaZoJk=
|
github.com/lrstanley/girc v0.0.0-20190801035559-4fc93959e1a7/go.mod h1:liX5MxHPrwgHaKowoLkYGwbXfYABh1jbZ6FpElbGF1I=
|
||||||
github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5 h1:AsEBgzv3DhuYHI/GiQh2HxvTP71HCCE9E/tzGUzGdtU=
|
github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5 h1:AsEBgzv3DhuYHI/GiQh2HxvTP71HCCE9E/tzGUzGdtU=
|
||||||
github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5/go.mod h1:c2mYKRyMb1BPkO5St0c/ps62L4S0W2NAkaTXj9qEI+0=
|
github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5/go.mod h1:c2mYKRyMb1BPkO5St0c/ps62L4S0W2NAkaTXj9qEI+0=
|
||||||
github.com/lusis/slack-test v0.0.0-20180109053238-3c758769bfa6 h1:iOAVXzZyXtW408TMYejlUPo6BIn92HmOacWtIfNyYns=
|
github.com/lusis/slack-test v0.0.0-20180109053238-3c758769bfa6 h1:iOAVXzZyXtW408TMYejlUPo6BIn92HmOacWtIfNyYns=
|
||||||
|
6
vendor/github.com/lrstanley/girc/builtin.go
generated
vendored
6
vendor/github.com/lrstanley/girc/builtin.go
generated
vendored
@ -93,7 +93,11 @@ func handleConnect(c *Client, e Event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
c.RunHandlers(&Event{Command: CONNECTED, Params: []string{c.Server()}})
|
|
||||||
|
c.mu.RLock()
|
||||||
|
server := c.server()
|
||||||
|
c.mu.RUnlock()
|
||||||
|
c.RunHandlers(&Event{Command: CONNECTED, Params: []string{server}})
|
||||||
}
|
}
|
||||||
|
|
||||||
// nickCollisionHandler helps prevent the client from having conflicting
|
// nickCollisionHandler helps prevent the client from having conflicting
|
||||||
|
191
vendor/github.com/lrstanley/girc/cap.go
generated
vendored
191
vendor/github.com/lrstanley/girc/cap.go
generated
vendored
@ -5,7 +5,10 @@
|
|||||||
package girc
|
package girc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Something not in the list? Depending on the type of capability, you can
|
// Something not in the list? Depending on the type of capability, you can
|
||||||
@ -19,13 +22,20 @@ var possibleCap = map[string][]string{
|
|||||||
"chghost": nil,
|
"chghost": nil,
|
||||||
"extended-join": nil,
|
"extended-join": nil,
|
||||||
"invite-notify": nil,
|
"invite-notify": nil,
|
||||||
|
"message-tags": nil,
|
||||||
|
"msgid": nil,
|
||||||
"multi-prefix": nil,
|
"multi-prefix": nil,
|
||||||
"server-time": nil,
|
"server-time": nil,
|
||||||
"userhost-in-names": nil,
|
"userhost-in-names": nil,
|
||||||
|
|
||||||
|
// Supported draft versions, some may be duplicated above, this is for backwards
|
||||||
|
// compatibility.
|
||||||
"draft/message-tags-0.2": nil,
|
"draft/message-tags-0.2": nil,
|
||||||
"draft/msgid": nil,
|
"draft/msgid": nil,
|
||||||
|
|
||||||
|
// sts, sasl, etc are enabled dynamically/depending on client configuration,
|
||||||
|
// so aren't included on this list.
|
||||||
|
|
||||||
// "echo-message" is supported, but it's not enabled by default. This is
|
// "echo-message" is supported, but it's not enabled by default. This is
|
||||||
// to prevent unwanted confusion and utilize less traffic if it's not needed.
|
// to prevent unwanted confusion and utilize less traffic if it's not needed.
|
||||||
// echo messages aren't sent to girc.PRIVMSG and girc.NOTICE handlers,
|
// echo messages aren't sent to girc.PRIVMSG and girc.NOTICE handlers,
|
||||||
@ -51,6 +61,17 @@ func possibleCapList(c *Client) map[string][]string {
|
|||||||
out["sasl"] = nil
|
out["sasl"] = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !c.Config.DisableSTS && !c.Config.SSL {
|
||||||
|
// If fallback supported, and we failed recently, don't try negotiating STS.
|
||||||
|
// ONLY do this fallback if we're expired (primarily useful during the first
|
||||||
|
// sts negotation).
|
||||||
|
if time.Since(c.state.sts.lastFailed) < 5*time.Minute && !c.Config.DisableSTSFallback {
|
||||||
|
c.debug.Println("skipping strict transport policy negotiation; failed within the last 5 minutes")
|
||||||
|
} else {
|
||||||
|
out["sts"] = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for k := range c.Config.SupportedCaps {
|
for k := range c.Config.SupportedCaps {
|
||||||
out[k] = c.Config.SupportedCaps[k]
|
out[k] = c.Config.SupportedCaps[k]
|
||||||
}
|
}
|
||||||
@ -62,8 +83,8 @@ func possibleCapList(c *Client) map[string][]string {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseCap(raw string) map[string][]string {
|
func parseCap(raw string) map[string]map[string]string {
|
||||||
out := make(map[string][]string)
|
out := make(map[string]map[string]string)
|
||||||
parts := strings.Split(raw, " ")
|
parts := strings.Split(raw, " ")
|
||||||
|
|
||||||
var val int
|
var val int
|
||||||
@ -78,7 +99,16 @@ func parseCap(raw string) map[string][]string {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
out[parts[i][:val]] = strings.Split(parts[i][val+1:], ",")
|
out[parts[i][:val]] = make(map[string]string)
|
||||||
|
for _, option := range strings.Split(parts[i][val+1:], ",") {
|
||||||
|
j := strings.Index(option, "=")
|
||||||
|
|
||||||
|
if j < 0 {
|
||||||
|
out[parts[i][:val]][option] = ""
|
||||||
|
} else {
|
||||||
|
out[parts[i][:val]][option[:j]] = option[j+1 : len(option)]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return out
|
return out
|
||||||
@ -88,8 +118,15 @@ func parseCap(raw string) map[string][]string {
|
|||||||
// This will lock further registration until we have acknowledged (or denied)
|
// This will lock further registration until we have acknowledged (or denied)
|
||||||
// the capabilities.
|
// the capabilities.
|
||||||
func handleCAP(c *Client, e Event) {
|
func handleCAP(c *Client, e Event) {
|
||||||
if len(e.Params) >= 2 && (e.Params[1] == CAP_NEW || e.Params[1] == CAP_DEL) {
|
c.state.Lock()
|
||||||
c.listCAP()
|
defer c.state.Unlock()
|
||||||
|
|
||||||
|
if len(e.Params) >= 2 && e.Params[1] == CAP_DEL {
|
||||||
|
caps := parseCap(e.Last())
|
||||||
|
for cap := range caps {
|
||||||
|
// TODO: test the deletion.
|
||||||
|
delete(c.state.enabledCap, cap)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,27 +138,26 @@ func handleCAP(c *Client, e Event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
possible := possibleCapList(c)
|
possible := possibleCapList(c)
|
||||||
|
// TODO: test the addition.
|
||||||
if len(e.Params) >= 3 && e.Params[1] == CAP_LS {
|
if len(e.Params) >= 3 && (e.Params[1] == CAP_LS || e.Params[1] == CAP_NEW) {
|
||||||
c.state.Lock()
|
|
||||||
|
|
||||||
caps := parseCap(e.Last())
|
caps := parseCap(e.Last())
|
||||||
|
|
||||||
for k := range caps {
|
for capName := range caps {
|
||||||
if _, ok := possible[k]; !ok {
|
if _, ok := possible[capName]; !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(possible[k]) == 0 || len(caps[k]) == 0 {
|
if len(possible[capName]) == 0 || len(caps[capName]) == 0 {
|
||||||
c.state.tmpCap = append(c.state.tmpCap, k)
|
c.state.tmpCap[capName] = caps[capName]
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
var contains bool
|
var contains bool
|
||||||
for i := 0; i < len(caps[k]); i++ {
|
|
||||||
for j := 0; j < len(possible[k]); j++ {
|
for capAttr := range caps[capName] {
|
||||||
if caps[k][i] == possible[k][j] {
|
for i := 0; i < len(possible[capName]); i++ {
|
||||||
// Assume we have a matching split value.
|
if _, ok := caps[capName][capAttr]; ok {
|
||||||
|
// Assuming we have a matching attribute for the capability.
|
||||||
contains = true
|
contains = true
|
||||||
goto checkcontains
|
goto checkcontains
|
||||||
}
|
}
|
||||||
@ -133,9 +169,8 @@ func handleCAP(c *Client, e Event) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
c.state.tmpCap = append(c.state.tmpCap, k)
|
c.state.tmpCap[capName] = caps[capName]
|
||||||
}
|
}
|
||||||
c.state.Unlock()
|
|
||||||
|
|
||||||
// Indicates if this is a multi-line LS. (3 args means it's the
|
// Indicates if this is a multi-line LS. (3 args means it's the
|
||||||
// last LS).
|
// last LS).
|
||||||
@ -147,31 +182,113 @@ func handleCAP(c *Client, e Event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Let them know which ones we'd like to enable.
|
// Let them know which ones we'd like to enable.
|
||||||
c.write(&Event{Command: CAP, Params: []string{CAP_REQ, strings.Join(c.state.tmpCap, " ")}})
|
reqKeys := make([]string, len(c.state.tmpCap))
|
||||||
|
i := 0
|
||||||
// Re-initialize the tmpCap, so if we get multiple 'CAP LS' requests
|
for k := range c.state.tmpCap {
|
||||||
// due to cap-notify, we can re-evaluate what we can support.
|
reqKeys[i] = k
|
||||||
c.state.Lock()
|
i++
|
||||||
c.state.tmpCap = []string{}
|
}
|
||||||
c.state.Unlock()
|
c.write(&Event{Command: CAP, Params: []string{CAP_REQ, strings.Join(reqKeys, " ")}})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(e.Params) == 3 && e.Params[1] == CAP_ACK {
|
if len(e.Params) == 3 && e.Params[1] == CAP_ACK {
|
||||||
c.state.Lock()
|
enabled := strings.Split(e.Last(), " ")
|
||||||
c.state.enabledCap = strings.Split(e.Last(), " ")
|
for _, cap := range enabled {
|
||||||
|
if val, ok := c.state.tmpCap[cap]; ok {
|
||||||
// Do we need to do sasl auth?
|
c.state.enabledCap[cap] = val
|
||||||
wantsSASL := false
|
} else {
|
||||||
for i := 0; i < len(c.state.enabledCap); i++ {
|
c.state.enabledCap[cap] = nil
|
||||||
if c.state.enabledCap[i] == "sasl" {
|
|
||||||
wantsSASL = true
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.state.Unlock()
|
|
||||||
|
|
||||||
if wantsSASL {
|
// Anything client side that needs to be setup post-capability-acknowledgement,
|
||||||
|
// should be done here.
|
||||||
|
|
||||||
|
// Handle STS, and only if it's something specifically we enabled (client
|
||||||
|
// may choose to disable girc automatic STS, and do it themselves).
|
||||||
|
if sts, sok := c.state.enabledCap["sts"]; sok && !c.Config.DisableSTS {
|
||||||
|
var isError bool
|
||||||
|
|
||||||
|
// Some things are updated in the policy depending on if the current
|
||||||
|
// connection is over tls or not.
|
||||||
|
var hasTLSConnection bool
|
||||||
|
if tlsState, _ := c.TLSConnectionState(); tlsState != nil {
|
||||||
|
hasTLSConnection = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// "This key indicates the port number for making a secure connection.
|
||||||
|
// This key’s value MUST be a single port number. If the client is not
|
||||||
|
// already connected securely to the server at the requested hostname,
|
||||||
|
// it MUST close the insecure connection and reconnect securely on the
|
||||||
|
// stated port.
|
||||||
|
//
|
||||||
|
// To enforce an STS upgrade policy, servers MUST send this key to
|
||||||
|
// insecurely connected clients. Servers MAY send this key to securely
|
||||||
|
// connected clients, but it will be ignored."
|
||||||
|
//
|
||||||
|
// See: https://ircv3.net/specs/extensions/sts#the-port-key
|
||||||
|
if !hasTLSConnection {
|
||||||
|
if port, ok := sts["port"]; ok {
|
||||||
|
c.state.sts.upgradePort, _ = strconv.Atoi(port)
|
||||||
|
if c.state.sts.upgradePort < 21 {
|
||||||
|
isError = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
isError = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// "This key is used on secure connections to indicate how long clients
|
||||||
|
// MUST continue to use secure connections when connecting to the server
|
||||||
|
// at the requested hostname. The value of this key MUST be given as a
|
||||||
|
// single integer which represents the number of seconds until the persistence
|
||||||
|
// policy expires.
|
||||||
|
//
|
||||||
|
// To enforce an STS persistence policy, servers MUST send this key to
|
||||||
|
// securely connected clients. Servers MAY send this key to all clients,
|
||||||
|
// but insecurely connected clients MUST ignore it."
|
||||||
|
//
|
||||||
|
// See: https://ircv3.net/specs/extensions/sts#the-duration-key
|
||||||
|
if hasTLSConnection {
|
||||||
|
if duration, ok := sts["duration"]; ok {
|
||||||
|
c.state.sts.persistenceDuration, _ = strconv.Atoi(duration)
|
||||||
|
c.state.sts.persistenceReceived = time.Now()
|
||||||
|
} else {
|
||||||
|
isError = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// See: https://ircv3.net/specs/extensions/sts#the-preload-key
|
||||||
|
if hasTLSConnection {
|
||||||
|
if preload, ok := sts["preload"]; ok {
|
||||||
|
c.state.sts.preload, _ = strconv.ParseBool(preload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if isError {
|
||||||
|
c.rx <- &Event{Command: ERROR, Params: []string{
|
||||||
|
fmt.Sprintf("closing connection: strict transport policy provided by server is invalid; possible MITM? config: %#v", sts),
|
||||||
|
}}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only upgrade if not already upgraded.
|
||||||
|
if !hasTLSConnection {
|
||||||
|
c.state.sts.beginUpgrade = true
|
||||||
|
|
||||||
|
c.RunHandlers(&Event{Command: STS_UPGRADE_INIT})
|
||||||
|
c.debug.Println("strict transport security policy provided by server; closing connection to begin upgrade...")
|
||||||
|
c.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-initialize the tmpCap, so if we get multiple 'CAP LS' requests
|
||||||
|
// due to cap-notify, we can re-evaluate what we can support.
|
||||||
|
c.state.tmpCap = make(map[string]map[string]string)
|
||||||
|
|
||||||
|
if _, ok := c.state.enabledCap["sasl"]; ok && c.Config.SASL != nil {
|
||||||
c.write(&Event{Command: AUTHENTICATE, Params: []string{c.Config.SASL.Method()}})
|
c.write(&Event{Command: AUTHENTICATE, Params: []string{c.Config.SASL.Method()}})
|
||||||
// Don't "CAP END", since we want to authenticate.
|
// Don't "CAP END", since we want to authenticate.
|
||||||
return
|
return
|
||||||
|
13
vendor/github.com/lrstanley/girc/cap_tags.go
generated
vendored
13
vendor/github.com/lrstanley/girc/cap_tags.go
generated
vendored
@ -38,7 +38,7 @@ const (
|
|||||||
prefixTagValue byte = '='
|
prefixTagValue byte = '='
|
||||||
prefixUserTag byte = '+'
|
prefixUserTag byte = '+'
|
||||||
tagSeparator byte = ';'
|
tagSeparator byte = ';'
|
||||||
maxTagLength int = 511 // 510 + @ and " " (space), though space usually not included.
|
maxTagLength int = 4094 // 4094 + @ and " " (space) = 4096, though space usually not included.
|
||||||
)
|
)
|
||||||
|
|
||||||
// Tags represents the key-value pairs in IRCv3 message tags. The map contains
|
// Tags represents the key-value pairs in IRCv3 message tags. The map contains
|
||||||
@ -55,6 +55,9 @@ type Tags map[string]string
|
|||||||
// @aaa=bbb;ccc;example.com/ddd=eee
|
// @aaa=bbb;ccc;example.com/ddd=eee
|
||||||
// NOT:
|
// NOT:
|
||||||
// @aaa=bbb;ccc;example.com/ddd=eee :nick!ident@host.com PRIVMSG me :Hello
|
// @aaa=bbb;ccc;example.com/ddd=eee :nick!ident@host.com PRIVMSG me :Hello
|
||||||
|
//
|
||||||
|
// Technically, there is a length limit of 4096, but the server should reject
|
||||||
|
// tag messages longer than this.
|
||||||
func ParseTags(raw string) (t Tags) {
|
func ParseTags(raw string) (t Tags) {
|
||||||
t = make(Tags)
|
t = make(Tags)
|
||||||
|
|
||||||
@ -79,11 +82,11 @@ func ParseTags(raw string) (t Tags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if tag key or decoded value are invalid.
|
// Check if tag key or decoded value are invalid.
|
||||||
if !validTag(parts[i][:hasValue]) || !validTagValue(tagDecoder.Replace(parts[i][hasValue+1:])) {
|
// if !validTag(parts[i][:hasValue]) || !validTagValue(tagDecoder.Replace(parts[i][hasValue+1:])) {
|
||||||
continue
|
// continue
|
||||||
}
|
// }
|
||||||
|
|
||||||
t[parts[i][:hasValue]] = parts[i][hasValue+1:]
|
t[parts[i][:hasValue]] = tagDecoder.Replace(parts[i][hasValue+1:])
|
||||||
}
|
}
|
||||||
|
|
||||||
return t
|
return t
|
||||||
|
89
vendor/github.com/lrstanley/girc/client.go
generated
vendored
89
vendor/github.com/lrstanley/girc/client.go
generated
vendored
@ -12,8 +12,11 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@ -95,6 +98,16 @@ type Config struct {
|
|||||||
// configuration (e.g. to not force hostname checking). This only has an
|
// configuration (e.g. to not force hostname checking). This only has an
|
||||||
// affect during the dial process.
|
// affect during the dial process.
|
||||||
SSL bool
|
SSL bool
|
||||||
|
// DisableSTS disables the use of automatic STS connection upgrades
|
||||||
|
// when the server supports STS. STS can also be disabled using the environment
|
||||||
|
// variable "GIRC_DISABLE_STS=true". As many clients may not propagate options
|
||||||
|
// like this back to the user, this allows to directly disable such automatic
|
||||||
|
// functionality.
|
||||||
|
DisableSTS bool
|
||||||
|
// DisableSTSFallback disables the "fallback" to a non-tls connection if the
|
||||||
|
// strict transport policy expires and the first attempt to reconnect back to
|
||||||
|
// the tls version fails.
|
||||||
|
DisableSTSFallback bool
|
||||||
// TLSConfig is an optional user-supplied tls configuration, used during
|
// TLSConfig is an optional user-supplied tls configuration, used during
|
||||||
// socket creation to the server. SSL must be enabled for this to be used.
|
// socket creation to the server. SSL must be enabled for this to be used.
|
||||||
// This only has an affect during the dial process.
|
// This only has an affect during the dial process.
|
||||||
@ -146,7 +159,7 @@ type Config struct {
|
|||||||
|
|
||||||
// disableTracking disables all channel and user-level tracking. Useful
|
// disableTracking disables all channel and user-level tracking. Useful
|
||||||
// for highly embedded scripts with single purposes. This has an exported
|
// for highly embedded scripts with single purposes. This has an exported
|
||||||
// method which enables this and ensures prop cleanup, see
|
// method which enables this and ensures proper cleanup, see
|
||||||
// Client.DisableTracking().
|
// Client.DisableTracking().
|
||||||
disableTracking bool
|
disableTracking bool
|
||||||
// HandleNickCollide when set, allows the client to handle nick collisions
|
// HandleNickCollide when set, allows the client to handle nick collisions
|
||||||
@ -247,19 +260,34 @@ func New(config Config) *Client {
|
|||||||
c.Config.PingDelay = 600 * time.Second
|
c.Config.PingDelay = 600 * time.Second
|
||||||
}
|
}
|
||||||
|
|
||||||
|
envDebug, _ := strconv.ParseBool(os.Getenv("GIRC_DEBUG"))
|
||||||
if c.Config.Debug == nil {
|
if c.Config.Debug == nil {
|
||||||
c.debug = log.New(ioutil.Discard, "", 0)
|
if envDebug {
|
||||||
|
c.debug = log.New(os.Stderr, "debug:", log.Ltime|log.Lshortfile)
|
||||||
} else {
|
} else {
|
||||||
|
c.debug = log.New(ioutil.Discard, "", 0)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if envDebug {
|
||||||
|
if c.Config.Debug != os.Stdout && c.Config.Debug != os.Stderr {
|
||||||
|
c.Config.Debug = io.MultiWriter(os.Stderr, c.Config.Debug)
|
||||||
|
}
|
||||||
|
}
|
||||||
c.debug = log.New(c.Config.Debug, "debug:", log.Ltime|log.Lshortfile)
|
c.debug = log.New(c.Config.Debug, "debug:", log.Ltime|log.Lshortfile)
|
||||||
c.debug.Print("initializing debugging")
|
c.debug.Print("initializing debugging")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
envDisableSTS, _ := strconv.ParseBool((os.Getenv("GIRC_DISABLE_STS")))
|
||||||
|
if envDisableSTS {
|
||||||
|
c.Config.DisableSTS = envDisableSTS
|
||||||
|
}
|
||||||
|
|
||||||
// Setup the caller.
|
// Setup the caller.
|
||||||
c.Handlers = newCaller(c.debug)
|
c.Handlers = newCaller(c.debug)
|
||||||
|
|
||||||
// Give ourselves a new state.
|
// Give ourselves a new state.
|
||||||
c.state = &state{}
|
c.state = &state{}
|
||||||
c.state.reset()
|
c.state.reset(true)
|
||||||
|
|
||||||
// Register builtin handlers.
|
// Register builtin handlers.
|
||||||
c.registerBuiltins()
|
c.registerBuiltins()
|
||||||
@ -323,6 +351,18 @@ func (c *Client) Close() {
|
|||||||
c.mu.RUnlock()
|
c.mu.RUnlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Quit sends a QUIT message to the server with a given reason to close the
|
||||||
|
// connection. Underlying this event being sent, Client.Close() is called as well.
|
||||||
|
// This is different than just calling Client.Close() in that it provides a reason
|
||||||
|
// as to why the connection was closed (for bots to tell users the bot is restarting,
|
||||||
|
// or shutting down, etc).
|
||||||
|
//
|
||||||
|
// NOTE: servers may delay showing of QUIT reasons, until you've been connected to
|
||||||
|
// the server for a certain period of time (e.g. 5 minutes). Keep this in mind.
|
||||||
|
func (c *Client) Quit(reason string) {
|
||||||
|
c.Send(&Event{Command: QUIT, Params: []string{reason}})
|
||||||
|
}
|
||||||
|
|
||||||
// ErrEvent is an error returned when the server (or library) sends an ERROR
|
// ErrEvent is an error returned when the server (or library) sends an ERROR
|
||||||
// message response. The string returned contains the trailing text from the
|
// message response. The string returned contains the trailing text from the
|
||||||
// message.
|
// message.
|
||||||
@ -400,9 +440,21 @@ func (c *Client) DisableTracking() {
|
|||||||
c.registerBuiltins()
|
c.registerBuiltins()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Server returns the string representation of host+port pair for net.Conn.
|
// Server returns the string representation of host+port pair for the connection.
|
||||||
func (c *Client) Server() string {
|
func (c *Client) Server() string {
|
||||||
return fmt.Sprintf("%s:%d", c.Config.Server, c.Config.Port)
|
c.state.Lock()
|
||||||
|
defer c.state.Lock()
|
||||||
|
|
||||||
|
return c.server()
|
||||||
|
}
|
||||||
|
|
||||||
|
// server returns the string representation of host+port pair for net.Conn, and
|
||||||
|
// takes into consideration STS. Must lock state mu first!
|
||||||
|
func (c *Client) server() string {
|
||||||
|
if c.state.sts.enabled() {
|
||||||
|
return net.JoinHostPort(c.Config.Server, strconv.Itoa(c.state.sts.upgradePort))
|
||||||
|
}
|
||||||
|
return net.JoinHostPort(c.Config.Server, strconv.Itoa(c.Config.Port))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lifetime returns the amount of time that has passed since the client was
|
// Lifetime returns the amount of time that has passed since the client was
|
||||||
@ -688,8 +740,9 @@ func (c *Client) HasCapability(name string) (has bool) {
|
|||||||
name = strings.ToLower(name)
|
name = strings.ToLower(name)
|
||||||
|
|
||||||
c.state.RLock()
|
c.state.RLock()
|
||||||
for i := 0; i < len(c.state.enabledCap); i++ {
|
for key := range c.state.enabledCap {
|
||||||
if strings.ToLower(c.state.enabledCap[i]) == name {
|
key = strings.ToLower(key)
|
||||||
|
if key == name {
|
||||||
has = true
|
has = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -713,3 +766,25 @@ func (c *Client) panicIfNotTracking() {
|
|||||||
|
|
||||||
panic(fmt.Sprintf("%s used when tracking is disabled (caller %s:%d)", fn.Name(), file, line))
|
panic(fmt.Sprintf("%s used when tracking is disabled (caller %s:%d)", fn.Name(), file, line))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) debugLogEvent(e *Event, dropped bool) {
|
||||||
|
var prefix string
|
||||||
|
|
||||||
|
if dropped {
|
||||||
|
prefix = "dropping event (disconnected):"
|
||||||
|
} else {
|
||||||
|
prefix = ">"
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.Sensitive {
|
||||||
|
c.debug.Printf(prefix, " %s ***redacted***", e.Command)
|
||||||
|
} else {
|
||||||
|
c.debug.Print(prefix, " ", StripRaw(e.String()))
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Config.Out != nil {
|
||||||
|
if pretty, ok := e.Pretty(); ok {
|
||||||
|
fmt.Fprintln(c.Config.Out, StripRaw(pretty))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
106
vendor/github.com/lrstanley/girc/conn.go
generated
vendored
106
vendor/github.com/lrstanley/girc/conn.go
generated
vendored
@ -58,7 +58,7 @@ type Dialer interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// newConn sets up and returns a new connection to the server.
|
// newConn sets up and returns a new connection to the server.
|
||||||
func newConn(conf Config, dialer Dialer, addr string) (*ircConn, error) {
|
func newConn(conf Config, dialer Dialer, addr string, sts *strictTransport) (*ircConn, error) {
|
||||||
if err := conf.isValid(); err != nil {
|
if err := conf.isValid(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -83,13 +83,29 @@ func newConn(conf Config, dialer Dialer, addr string) (*ircConn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if conn, err = dialer.Dial("tcp", addr); err != nil {
|
if conn, err = dialer.Dial("tcp", addr); err != nil {
|
||||||
|
if sts.enabled() {
|
||||||
|
err = &ErrSTSUpgradeFailed{Err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
if sts.expired() && !conf.DisableSTSFallback {
|
||||||
|
sts.lastFailed = time.Now()
|
||||||
|
sts.reset()
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if conf.SSL {
|
if conf.SSL || sts.enabled() {
|
||||||
var tlsConn net.Conn
|
var tlsConn net.Conn
|
||||||
tlsConn, err = tlsHandshake(conn, conf.TLSConfig, conf.Server, true)
|
tlsConn, err = tlsHandshake(conn, conf.TLSConfig, conf.Server, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if sts.enabled() {
|
||||||
|
err = &ErrSTSUpgradeFailed{Err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
if sts.expired() && !conf.DisableSTSFallback {
|
||||||
|
sts.lastFailed = time.Now()
|
||||||
|
sts.reset()
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,6 +261,7 @@ func (c *Client) MockConnect(conn net.Conn) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) internalConnect(mock net.Conn, dialer Dialer) error {
|
func (c *Client) internalConnect(mock net.Conn, dialer Dialer) error {
|
||||||
|
startConn:
|
||||||
// We want to be the only one handling connects/disconnects right now.
|
// We want to be the only one handling connects/disconnects right now.
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
|
|
||||||
@ -253,13 +270,20 @@ func (c *Client) internalConnect(mock net.Conn, dialer Dialer) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reset the state.
|
// Reset the state.
|
||||||
c.state.reset()
|
c.state.reset(false)
|
||||||
|
|
||||||
|
addr := c.server()
|
||||||
|
|
||||||
if mock == nil {
|
if mock == nil {
|
||||||
// Validate info, and actually make the connection.
|
// Validate info, and actually make the connection.
|
||||||
c.debug.Printf("connecting to %s...", c.Server())
|
c.debug.Printf("connecting to %s... (sts: %v, config-ssl: %v)", addr, c.state.sts.enabled(), c.Config.SSL)
|
||||||
conn, err := newConn(c.Config, dialer, c.Server())
|
conn, err := newConn(c.Config, dialer, addr, &c.state.sts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if _, ok := err.(*ErrSTSUpgradeFailed); ok {
|
||||||
|
if !c.state.sts.enabled() {
|
||||||
|
c.RunHandlers(&Event{Command: STS_ERR_FALLBACK})
|
||||||
|
}
|
||||||
|
}
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -312,16 +336,18 @@ func (c *Client) internalConnect(mock net.Conn, dialer Dialer) error {
|
|||||||
c.write(&Event{Command: USER, Params: []string{c.Config.User, "*", "*", c.Config.Name}})
|
c.write(&Event{Command: USER, Params: []string{c.Config.User, "*", "*", c.Config.Name}})
|
||||||
|
|
||||||
// Send a virtual event allowing hooks for successful socket connection.
|
// Send a virtual event allowing hooks for successful socket connection.
|
||||||
c.RunHandlers(&Event{Command: INITIALIZED, Params: []string{c.Server()}})
|
c.RunHandlers(&Event{Command: INITIALIZED, Params: []string{addr}})
|
||||||
|
|
||||||
// Wait for the first error.
|
// Wait for the first error.
|
||||||
var result error
|
var result error
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
|
if !c.state.sts.beginUpgrade {
|
||||||
c.debug.Print("received request to close, beginning clean up")
|
c.debug.Print("received request to close, beginning clean up")
|
||||||
c.RunHandlers(&Event{Command: CLOSED, Params: []string{c.Server()}})
|
}
|
||||||
|
c.RunHandlers(&Event{Command: CLOSED, Params: []string{addr}})
|
||||||
case err := <-errs:
|
case err := <-errs:
|
||||||
c.debug.Print("received error, beginning clean up")
|
c.debug.Printf("received error, beginning cleanup: %v", err)
|
||||||
result = err
|
result = err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,7 +362,7 @@ func (c *Client) internalConnect(mock net.Conn, dialer Dialer) error {
|
|||||||
c.conn.mu.Unlock()
|
c.conn.mu.Unlock()
|
||||||
c.mu.RUnlock()
|
c.mu.RUnlock()
|
||||||
|
|
||||||
c.RunHandlers(&Event{Command: DISCONNECTED, Params: []string{c.Server()}})
|
c.RunHandlers(&Event{Command: DISCONNECTED, Params: []string{addr}})
|
||||||
|
|
||||||
// Once we have our error/result, let all other functions know we're done.
|
// Once we have our error/result, let all other functions know we're done.
|
||||||
c.debug.Print("waiting for all routines to finish")
|
c.debug.Print("waiting for all routines to finish")
|
||||||
@ -350,6 +376,18 @@ func (c *Client) internalConnect(mock net.Conn, dialer Dialer) error {
|
|||||||
// clients, not multiple instances of Connect().
|
// clients, not multiple instances of Connect().
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
c.conn = nil
|
c.conn = nil
|
||||||
|
|
||||||
|
if result == nil {
|
||||||
|
if c.state.sts.beginUpgrade {
|
||||||
|
c.state.sts.beginUpgrade = false
|
||||||
|
c.mu.Unlock()
|
||||||
|
goto startConn
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.state.sts.enabled() {
|
||||||
|
c.state.sts.persistenceReceived = time.Now()
|
||||||
|
}
|
||||||
|
}
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
|
|
||||||
return result
|
return result
|
||||||
@ -392,8 +430,23 @@ func (c *Client) readLoop(ctx context.Context, errs chan error, wg *sync.WaitGro
|
|||||||
// Send sends an event to the server. Use Client.RunHandlers() if you are
|
// Send sends an event to the server. Use Client.RunHandlers() if you are
|
||||||
// simply looking to trigger handlers with an event.
|
// simply looking to trigger handlers with an event.
|
||||||
func (c *Client) Send(event *Event) {
|
func (c *Client) Send(event *Event) {
|
||||||
|
var delay time.Duration
|
||||||
|
|
||||||
if !c.Config.AllowFlood {
|
if !c.Config.AllowFlood {
|
||||||
<-time.After(c.conn.rate(event.Len()))
|
c.mu.RLock()
|
||||||
|
|
||||||
|
// Drop the event early as we're disconnected, this way we don't have to wait
|
||||||
|
// the (potentially long) rate limit delay before dropping.
|
||||||
|
if c.conn == nil {
|
||||||
|
c.debugLogEvent(event, true)
|
||||||
|
c.mu.RUnlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.conn.mu.Lock()
|
||||||
|
delay = c.conn.rate(event.Len())
|
||||||
|
c.conn.mu.Unlock()
|
||||||
|
c.mu.RUnlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Config.GlobalFormat && len(event.Params) > 0 && event.Params[len(event.Params)-1] != "" &&
|
if c.Config.GlobalFormat && len(event.Params) > 0 && event.Params[len(event.Params)-1] != "" &&
|
||||||
@ -401,12 +454,21 @@ func (c *Client) Send(event *Event) {
|
|||||||
event.Params[len(event.Params)-1] = Fmt(event.Params[len(event.Params)-1])
|
event.Params[len(event.Params)-1] = Fmt(event.Params[len(event.Params)-1])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<-time.After(delay)
|
||||||
c.write(event)
|
c.write(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
// write is the lower level function to write an event. It does not have a
|
// write is the lower level function to write an event. It does not have a
|
||||||
// write-delay when sending events.
|
// write-delay when sending events.
|
||||||
func (c *Client) write(event *Event) {
|
func (c *Client) write(event *Event) {
|
||||||
|
c.mu.RLock()
|
||||||
|
defer c.mu.RUnlock()
|
||||||
|
|
||||||
|
if c.conn == nil {
|
||||||
|
// Drop the event if disconnected.
|
||||||
|
c.debugLogEvent(event, true)
|
||||||
|
return
|
||||||
|
}
|
||||||
c.tx <- event
|
c.tx <- event
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -415,14 +477,10 @@ func (c *Client) write(event *Event) {
|
|||||||
func (c *ircConn) rate(chars int) time.Duration {
|
func (c *ircConn) rate(chars int) time.Duration {
|
||||||
_time := time.Second + ((time.Duration(chars) * time.Second) / 100)
|
_time := time.Second + ((time.Duration(chars) * time.Second) / 100)
|
||||||
|
|
||||||
c.mu.Lock()
|
|
||||||
if c.writeDelay += _time - time.Now().Sub(c.lastWrite); c.writeDelay < 0 {
|
if c.writeDelay += _time - time.Now().Sub(c.lastWrite); c.writeDelay < 0 {
|
||||||
c.writeDelay = 0
|
c.writeDelay = 0
|
||||||
}
|
}
|
||||||
c.mu.Unlock()
|
|
||||||
|
|
||||||
c.mu.RLock()
|
|
||||||
defer c.mu.RUnlock()
|
|
||||||
if c.writeDelay > (8 * time.Second) {
|
if c.writeDelay > (8 * time.Second) {
|
||||||
return _time
|
return _time
|
||||||
}
|
}
|
||||||
@ -445,7 +503,7 @@ func (c *Client) sendLoop(ctx context.Context, errs chan error, wg *sync.WaitGro
|
|||||||
c.state.RLock()
|
c.state.RLock()
|
||||||
var in bool
|
var in bool
|
||||||
for i := 0; i < len(c.state.enabledCap); i++ {
|
for i := 0; i < len(c.state.enabledCap); i++ {
|
||||||
if c.state.enabledCap[i] == "message-tags" {
|
if _, ok := c.state.enabledCap["message-tags"]; ok {
|
||||||
in = true
|
in = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -457,17 +515,7 @@ func (c *Client) sendLoop(ctx context.Context, errs chan error, wg *sync.WaitGro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log the event.
|
c.debugLogEvent(event, false)
|
||||||
if event.Sensitive {
|
|
||||||
c.debug.Printf("> %s ***redacted***", event.Command)
|
|
||||||
} else {
|
|
||||||
c.debug.Print("> ", StripRaw(event.String()))
|
|
||||||
}
|
|
||||||
if c.Config.Out != nil {
|
|
||||||
if pretty, ok := event.Pretty(); ok {
|
|
||||||
fmt.Fprintln(c.Config.Out, StripRaw(pretty))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.conn.mu.Lock()
|
c.conn.mu.Lock()
|
||||||
c.conn.lastWrite = time.Now()
|
c.conn.lastWrite = time.Now()
|
||||||
@ -488,6 +536,12 @@ func (c *Client) sendLoop(ctx context.Context, errs chan error, wg *sync.WaitGro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if event.Command == QUIT {
|
||||||
|
c.Close()
|
||||||
|
wg.Done()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs <- err
|
errs <- err
|
||||||
wg.Done()
|
wg.Done()
|
||||||
|
4
vendor/github.com/lrstanley/girc/constants.go
generated
vendored
4
vendor/github.com/lrstanley/girc/constants.go
generated
vendored
@ -28,6 +28,8 @@ const (
|
|||||||
INITIALIZED = "CLIENT_INIT" // verifies successful socket connection, trailing is host:port
|
INITIALIZED = "CLIENT_INIT" // verifies successful socket connection, trailing is host:port
|
||||||
DISCONNECTED = "CLIENT_DISCONNECTED" // occurs when we're disconnected from the server (user-requested or not)
|
DISCONNECTED = "CLIENT_DISCONNECTED" // occurs when we're disconnected from the server (user-requested or not)
|
||||||
CLOSED = "CLIENT_CLOSED" // occurs when Client.Close() has been called
|
CLOSED = "CLIENT_CLOSED" // occurs when Client.Close() has been called
|
||||||
|
STS_UPGRADE_INIT = "STS_UPGRADE_INIT" // when an STS upgrade initially happens.
|
||||||
|
STS_ERR_FALLBACK = "STS_ERR_FALLBACK" // when an STS connection fails and fallbacks are supported.
|
||||||
)
|
)
|
||||||
|
|
||||||
// User/channel prefixes :: RFC1459.
|
// User/channel prefixes :: RFC1459.
|
||||||
@ -225,6 +227,7 @@ const (
|
|||||||
ERR_NOTOPLEVEL = "413"
|
ERR_NOTOPLEVEL = "413"
|
||||||
ERR_WILDTOPLEVEL = "414"
|
ERR_WILDTOPLEVEL = "414"
|
||||||
ERR_BADMASK = "415"
|
ERR_BADMASK = "415"
|
||||||
|
ERR_INPUTTOOLONG = "417"
|
||||||
ERR_UNKNOWNCOMMAND = "421"
|
ERR_UNKNOWNCOMMAND = "421"
|
||||||
ERR_NOMOTD = "422"
|
ERR_NOMOTD = "422"
|
||||||
ERR_NOADMININFO = "423"
|
ERR_NOADMININFO = "423"
|
||||||
@ -286,6 +289,7 @@ const (
|
|||||||
CAP_CHGHOST = "CHGHOST"
|
CAP_CHGHOST = "CHGHOST"
|
||||||
CAP_AWAY = "AWAY"
|
CAP_AWAY = "AWAY"
|
||||||
CAP_ACCOUNT = "ACCOUNT"
|
CAP_ACCOUNT = "ACCOUNT"
|
||||||
|
CAP_TAGMSG = "TAGMSG"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Numeric IRC reply mapping for ircv3 :: http://ircv3.net/irc/.
|
// Numeric IRC reply mapping for ircv3 :: http://ircv3.net/irc/.
|
||||||
|
5
vendor/github.com/lrstanley/girc/event.go
generated
vendored
5
vendor/github.com/lrstanley/girc/event.go
generated
vendored
@ -49,6 +49,7 @@ func ParseEvent(raw string) (e *Event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
raw = raw[i+1:]
|
raw = raw[i+1:]
|
||||||
|
i = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if raw[0] == messagePrefix {
|
if raw[0] == messagePrefix {
|
||||||
@ -91,7 +92,7 @@ func ParseEvent(raw string) (e *Event) {
|
|||||||
|
|
||||||
if trailerIndex == -1 {
|
if trailerIndex == -1 {
|
||||||
// No trailing argument found, assume the rest is just params.
|
// No trailing argument found, assume the rest is just params.
|
||||||
e.Params = strings.Split(raw[j:], string(eventSpace))
|
e.Params = strings.Fields(raw[j:])
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,7 +115,7 @@ func ParseEvent(raw string) (e *Event) {
|
|||||||
// Check if we need to parse arguments. If so, take everything after the
|
// Check if we need to parse arguments. If so, take everything after the
|
||||||
// command, and right before the trailing prefix, and cut it up.
|
// command, and right before the trailing prefix, and cut it up.
|
||||||
if i > j {
|
if i > j {
|
||||||
e.Params = strings.Split(raw[j:i-1], string(eventSpace))
|
e.Params = strings.Fields(raw[j : i-1])
|
||||||
}
|
}
|
||||||
|
|
||||||
e.Params = append(e.Params, raw[i+1:])
|
e.Params = append(e.Params, raw[i+1:])
|
||||||
|
2
vendor/github.com/lrstanley/girc/go.mod
generated
vendored
2
vendor/github.com/lrstanley/girc/go.mod
generated
vendored
@ -1 +1,3 @@
|
|||||||
module github.com/lrstanley/girc
|
module github.com/lrstanley/girc
|
||||||
|
|
||||||
|
go 1.12
|
||||||
|
15
vendor/github.com/lrstanley/girc/handler.go
generated
vendored
15
vendor/github.com/lrstanley/girc/handler.go
generated
vendored
@ -431,17 +431,27 @@ func recoverHandlerPanic(client *Client, event *Event, id string, skip int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var file string
|
var file, function string
|
||||||
var line int
|
var line int
|
||||||
var ok bool
|
var ok bool
|
||||||
|
|
||||||
_, file, line, ok = runtime.Caller(skip)
|
var pcs [10]uintptr
|
||||||
|
frames := runtime.CallersFrames(pcs[:runtime.Callers(skip, pcs[:])])
|
||||||
|
for {
|
||||||
|
frame, _ := frames.Next()
|
||||||
|
file = frame.File
|
||||||
|
line = frame.Line
|
||||||
|
function = frame.Function
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
err := &HandlerError{
|
err := &HandlerError{
|
||||||
Event: *event,
|
Event: *event,
|
||||||
ID: id,
|
ID: id,
|
||||||
File: file,
|
File: file,
|
||||||
Line: line,
|
Line: line,
|
||||||
|
Func: function,
|
||||||
Panic: perr,
|
Panic: perr,
|
||||||
Stack: debug.Stack(),
|
Stack: debug.Stack(),
|
||||||
callOk: ok,
|
callOk: ok,
|
||||||
@ -460,6 +470,7 @@ type HandlerError struct {
|
|||||||
ID string // ID is the CUID of the handler.
|
ID string // ID is the CUID of the handler.
|
||||||
File string // File is the file from where the panic originated.
|
File string // File is the file from where the panic originated.
|
||||||
Line int // Line number where panic originated.
|
Line int // Line number where panic originated.
|
||||||
|
Func string // Function name where panic originated.
|
||||||
Panic interface{} // Panic is the error that was passed to panic().
|
Panic interface{} // Panic is the error that was passed to panic().
|
||||||
Stack []byte // Stack is the call stack. Note you may have to skip 1 or 2 due to debug functions.
|
Stack []byte // Stack is the call stack. Note you may have to skip 1 or 2 due to debug functions.
|
||||||
callOk bool
|
callOk bool
|
||||||
|
66
vendor/github.com/lrstanley/girc/state.go
generated
vendored
66
vendor/github.com/lrstanley/girc/state.go
generated
vendored
@ -5,6 +5,7 @@
|
|||||||
package girc
|
package girc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@ -22,27 +23,28 @@ type state struct {
|
|||||||
// users represents all of users that we're tracking.
|
// users represents all of users that we're tracking.
|
||||||
users map[string]*User
|
users map[string]*User
|
||||||
// enabledCap are the capabilities which are enabled for this connection.
|
// enabledCap are the capabilities which are enabled for this connection.
|
||||||
enabledCap []string
|
enabledCap map[string]map[string]string
|
||||||
// tmpCap are the capabilties which we share with the server during the
|
// tmpCap are the capabilties which we share with the server during the
|
||||||
// last capability check. These will get sent once we have received the
|
// last capability check. These will get sent once we have received the
|
||||||
// last capability list command from the server.
|
// last capability list command from the server.
|
||||||
tmpCap []string
|
tmpCap map[string]map[string]string
|
||||||
// serverOptions are the standard capabilities and configurations
|
// serverOptions are the standard capabilities and configurations
|
||||||
// supported by the server at connection time. This also includes
|
// supported by the server at connection time. This also includes
|
||||||
// RPL_ISUPPORT entries.
|
// RPL_ISUPPORT entries.
|
||||||
serverOptions map[string]string
|
serverOptions map[string]string
|
||||||
// motd is the servers message of the day.
|
// motd is the servers message of the day.
|
||||||
motd string
|
motd string
|
||||||
}
|
|
||||||
|
|
||||||
// notify sends state change notifications so users can update their refs
|
// sts are strict transport security configurations, if specified by the
|
||||||
// when state changes.
|
// server.
|
||||||
func (s *state) notify(c *Client, ntype string) {
|
//
|
||||||
c.RunHandlers(&Event{Command: ntype})
|
// TODO: ideally, this would be a configurable policy store that the user could
|
||||||
|
// optionally override (to store STS information on disk, memory, etc).
|
||||||
|
sts strictTransport
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset resets the state back to it's original form.
|
// reset resets the state back to it's original form.
|
||||||
func (s *state) reset() {
|
func (s *state) reset(initial bool) {
|
||||||
s.Lock()
|
s.Lock()
|
||||||
s.nick = ""
|
s.nick = ""
|
||||||
s.ident = ""
|
s.ident = ""
|
||||||
@ -50,8 +52,13 @@ func (s *state) reset() {
|
|||||||
s.channels = make(map[string]*Channel)
|
s.channels = make(map[string]*Channel)
|
||||||
s.users = make(map[string]*User)
|
s.users = make(map[string]*User)
|
||||||
s.serverOptions = make(map[string]string)
|
s.serverOptions = make(map[string]string)
|
||||||
s.enabledCap = []string{}
|
s.enabledCap = make(map[string]map[string]string)
|
||||||
|
s.tmpCap = make(map[string]map[string]string)
|
||||||
s.motd = ""
|
s.motd = ""
|
||||||
|
|
||||||
|
if initial {
|
||||||
|
s.sts.reset()
|
||||||
|
}
|
||||||
s.Unlock()
|
s.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -500,3 +507,44 @@ func (s *state) renameUser(from, to string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type strictTransport struct {
|
||||||
|
beginUpgrade bool
|
||||||
|
upgradePort int
|
||||||
|
persistenceDuration int
|
||||||
|
persistenceReceived time.Time
|
||||||
|
preload bool
|
||||||
|
lastFailed time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *strictTransport) reset() {
|
||||||
|
s.upgradePort = -1
|
||||||
|
s.persistenceDuration = -1
|
||||||
|
s.preload = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *strictTransport) expired() bool {
|
||||||
|
return int(time.Since(s.persistenceReceived).Seconds()) > s.persistenceDuration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *strictTransport) enabled() bool {
|
||||||
|
return s.upgradePort > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrSTSUpgradeFailed is an error that occurs when a connection that was attempted
|
||||||
|
// to be upgraded via a strict transport policy, failed. This does not necessarily
|
||||||
|
// indicate that STS was to blame, but the underlying connection failed for some
|
||||||
|
// reason.
|
||||||
|
type ErrSTSUpgradeFailed struct {
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrSTSUpgradeFailed) Error() string {
|
||||||
|
return fmt.Sprintf("fail to upgrade to secure (sts) connection: %v", e.Err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// notify sends state change notifications so users can update their refs
|
||||||
|
// when state changes.
|
||||||
|
func (s *state) notify(c *Client, ntype string) {
|
||||||
|
c.RunHandlers(&Event{Command: ntype})
|
||||||
|
}
|
||||||
|
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@ -91,7 +91,7 @@ github.com/labstack/gommon/color
|
|||||||
github.com/labstack/gommon/log
|
github.com/labstack/gommon/log
|
||||||
github.com/labstack/gommon/bytes
|
github.com/labstack/gommon/bytes
|
||||||
github.com/labstack/gommon/random
|
github.com/labstack/gommon/random
|
||||||
# github.com/lrstanley/girc v0.0.0-20190210212025-51b8e096d398
|
# github.com/lrstanley/girc v0.0.0-20190801035559-4fc93959e1a7
|
||||||
github.com/lrstanley/girc
|
github.com/lrstanley/girc
|
||||||
# github.com/magiconair/properties v1.8.0
|
# github.com/magiconair/properties v1.8.0
|
||||||
github.com/magiconair/properties
|
github.com/magiconair/properties
|
||||||
|
Loading…
Reference in New Issue
Block a user