forked from External/ergo
sync #1
20 changed files with 111 additions and 42 deletions
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
|
|
@ -19,7 +19,7 @@ jobs:
|
||||||
- name: "setup go"
|
- name: "setup go"
|
||||||
uses: "actions/setup-go@v3"
|
uses: "actions/setup-go@v3"
|
||||||
with:
|
with:
|
||||||
go-version: "1.22"
|
go-version: "1.23"
|
||||||
- name: "install python3-pytest"
|
- name: "install python3-pytest"
|
||||||
run: "sudo apt install -y python3-pytest"
|
run: "sudo apt install -y python3-pytest"
|
||||||
- name: "make install"
|
- name: "make install"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
## build ergo binary
|
## build ergo binary
|
||||||
FROM docker.io/golang:1.22-alpine AS build-env
|
FROM docker.io/golang:1.23-alpine AS build-env
|
||||||
|
|
||||||
RUN apk upgrade -U --force-refresh --no-cache && apk add --no-cache --purge --clean-protected -l -u make git
|
RUN apk upgrade -U --force-refresh --no-cache && apk add --no-cache --purge --clean-protected -l -u make git
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -820,7 +820,7 @@ lock-file: "ircd.lock"
|
||||||
|
|
||||||
# datastore configuration
|
# datastore configuration
|
||||||
datastore:
|
datastore:
|
||||||
# path to the datastore
|
# path to the database file (used to store account and channel registrations):
|
||||||
path: ircd.db
|
path: ircd.db
|
||||||
|
|
||||||
# if the database schema requires an upgrade, `autoupgrade` will attempt to
|
# if the database schema requires an upgrade, `autoupgrade` will attempt to
|
||||||
|
|
|
||||||
|
|
@ -219,6 +219,12 @@ CAPDEFS = [
|
||||||
url="https://github.com/ircv3/ircv3-specifications/pull/527",
|
url="https://github.com/ircv3/ircv3-specifications/pull/527",
|
||||||
standard="proposed IRCv3",
|
standard="proposed IRCv3",
|
||||||
),
|
),
|
||||||
|
CapDef(
|
||||||
|
identifier="ExtendedISupport",
|
||||||
|
name="draft/extended-isupport",
|
||||||
|
url="https://github.com/ircv3/ircv3-specifications/pull/543",
|
||||||
|
standard="proposed IRCv3",
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
def validate_defs():
|
def validate_defs():
|
||||||
|
|
|
||||||
4
go.mod
4
go.mod
|
|
@ -1,6 +1,6 @@
|
||||||
module github.com/ergochat/ergo
|
module github.com/ergochat/ergo
|
||||||
|
|
||||||
go 1.22
|
go 1.23
|
||||||
|
|
||||||
require (
|
require (
|
||||||
code.cloudfoundry.org/bytefmt v0.0.0-20200131002437-cf55d5288a48
|
code.cloudfoundry.org/bytefmt v0.0.0-20200131002437-cf55d5288a48
|
||||||
|
|
@ -8,7 +8,7 @@ require (
|
||||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
|
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
|
||||||
github.com/ergochat/confusables v0.0.0-20201108231250-4ab98ab61fb1
|
github.com/ergochat/confusables v0.0.0-20201108231250-4ab98ab61fb1
|
||||||
github.com/ergochat/go-ident v0.0.0-20230911071154-8c30606d6881
|
github.com/ergochat/go-ident v0.0.0-20230911071154-8c30606d6881
|
||||||
github.com/ergochat/irc-go v0.5.0-rc1
|
github.com/ergochat/irc-go v0.5.0-rc2
|
||||||
github.com/go-sql-driver/mysql v1.7.0
|
github.com/go-sql-driver/mysql v1.7.0
|
||||||
github.com/go-test/deep v1.0.6 // indirect
|
github.com/go-test/deep v1.0.6 // indirect
|
||||||
github.com/gofrs/flock v0.8.1
|
github.com/gofrs/flock v0.8.1
|
||||||
|
|
|
||||||
2
go.sum
2
go.sum
|
|
@ -12,6 +12,8 @@ github.com/ergochat/go-ident v0.0.0-20230911071154-8c30606d6881 h1:+J5m88nvybxB5
|
||||||
github.com/ergochat/go-ident v0.0.0-20230911071154-8c30606d6881/go.mod h1:ASYJtQujNitna6cVHsNQTGrfWvMPJ5Sa2lZlmsH65uM=
|
github.com/ergochat/go-ident v0.0.0-20230911071154-8c30606d6881/go.mod h1:ASYJtQujNitna6cVHsNQTGrfWvMPJ5Sa2lZlmsH65uM=
|
||||||
github.com/ergochat/irc-go v0.5.0-rc1 h1:kFoIHExoNFQ2CV+iShAVna/H4xrXQB4t4jK5Sep2j9k=
|
github.com/ergochat/irc-go v0.5.0-rc1 h1:kFoIHExoNFQ2CV+iShAVna/H4xrXQB4t4jK5Sep2j9k=
|
||||||
github.com/ergochat/irc-go v0.5.0-rc1/go.mod h1:2vi7KNpIPWnReB5hmLpl92eMywQvuIeIIGdt/FQCph0=
|
github.com/ergochat/irc-go v0.5.0-rc1/go.mod h1:2vi7KNpIPWnReB5hmLpl92eMywQvuIeIIGdt/FQCph0=
|
||||||
|
github.com/ergochat/irc-go v0.5.0-rc2 h1:VuSQJF5K4hWvYSzGa4b8vgL6kzw8HF6LSOejE+RWpAo=
|
||||||
|
github.com/ergochat/irc-go v0.5.0-rc2/go.mod h1:2vi7KNpIPWnReB5hmLpl92eMywQvuIeIIGdt/FQCph0=
|
||||||
github.com/ergochat/scram v1.0.2-ergo1 h1:2bYXiRFQH636pT0msOG39fmEYl4Eq+OuutcyDsCix/g=
|
github.com/ergochat/scram v1.0.2-ergo1 h1:2bYXiRFQH636pT0msOG39fmEYl4Eq+OuutcyDsCix/g=
|
||||||
github.com/ergochat/scram v1.0.2-ergo1/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
|
github.com/ergochat/scram v1.0.2-ergo1/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
|
||||||
github.com/ergochat/websocket v1.4.2-oragono1 h1:plMUunFBM6UoSCIYCKKclTdy/TkkHfUslhOfJQzfueM=
|
github.com/ergochat/websocket v1.4.2-oragono1 h1:plMUunFBM6UoSCIYCKKclTdy/TkkHfUslhOfJQzfueM=
|
||||||
|
|
|
||||||
|
|
@ -64,10 +64,11 @@ const (
|
||||||
BotTagName = "bot"
|
BotTagName = "bot"
|
||||||
// https://ircv3.net/specs/extensions/chathistory
|
// https://ircv3.net/specs/extensions/chathistory
|
||||||
ChathistoryTargetsBatchType = "draft/chathistory-targets"
|
ChathistoryTargetsBatchType = "draft/chathistory-targets"
|
||||||
|
ExtendedISupportBatchType = "draft/extended-isupport"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
nameToCapability = make(map[string]Capability)
|
nameToCapability = make(map[string]Capability, numCapabs)
|
||||||
for capab, name := range capabilityNames {
|
for capab, name := range capabilityNames {
|
||||||
nameToCapability[name] = Capability(capab)
|
nameToCapability[name] = Capability(capab)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ package caps
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// number of recognized capabilities:
|
// number of recognized capabilities:
|
||||||
numCapabs = 34
|
numCapabs = 35
|
||||||
// length of the uint32 array that represents the bitset:
|
// length of the uint32 array that represents the bitset:
|
||||||
bitsetLen = 2
|
bitsetLen = 2
|
||||||
)
|
)
|
||||||
|
|
@ -53,6 +53,10 @@ const (
|
||||||
// https://github.com/ircv3/ircv3-specifications/pull/362
|
// https://github.com/ircv3/ircv3-specifications/pull/362
|
||||||
EventPlayback Capability = iota
|
EventPlayback Capability = iota
|
||||||
|
|
||||||
|
// ExtendedISupport is the proposed IRCv3 capability named "draft/extended-isupport":
|
||||||
|
// https://github.com/ircv3/ircv3-specifications/pull/543
|
||||||
|
ExtendedISupport Capability = iota
|
||||||
|
|
||||||
// Languages is the proposed IRCv3 capability named "draft/languages":
|
// Languages is the proposed IRCv3 capability named "draft/languages":
|
||||||
// https://gist.github.com/DanielOaks/8126122f74b26012a3de37db80e4e0c6
|
// https://gist.github.com/DanielOaks/8126122f74b26012a3de37db80e4e0c6
|
||||||
Languages Capability = iota
|
Languages Capability = iota
|
||||||
|
|
@ -163,6 +167,7 @@ var (
|
||||||
"draft/channel-rename",
|
"draft/channel-rename",
|
||||||
"draft/chathistory",
|
"draft/chathistory",
|
||||||
"draft/event-playback",
|
"draft/event-playback",
|
||||||
|
"draft/extended-isupport",
|
||||||
"draft/languages",
|
"draft/languages",
|
||||||
"draft/message-redaction",
|
"draft/message-redaction",
|
||||||
"draft/multiline",
|
"draft/multiline",
|
||||||
|
|
|
||||||
|
|
@ -179,6 +179,8 @@ type Session struct {
|
||||||
|
|
||||||
batchCounter atomic.Uint32
|
batchCounter atomic.Uint32
|
||||||
|
|
||||||
|
isupportSentPrereg bool
|
||||||
|
|
||||||
quitMessage string
|
quitMessage string
|
||||||
|
|
||||||
awayMessage string
|
awayMessage string
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,10 @@ func init() {
|
||||||
handler: isonHandler,
|
handler: isonHandler,
|
||||||
minParams: 1,
|
minParams: 1,
|
||||||
},
|
},
|
||||||
|
"ISUPPORT": {
|
||||||
|
handler: isupportHandler,
|
||||||
|
usablePreReg: true,
|
||||||
|
},
|
||||||
"JOIN": {
|
"JOIN": {
|
||||||
handler: joinHandler,
|
handler: joinHandler,
|
||||||
minParams: 1,
|
minParams: 1,
|
||||||
|
|
|
||||||
|
|
@ -1656,6 +1656,7 @@ func (config *Config) generateISupport() (err error) {
|
||||||
isupport.Add("RPCHAN", "E")
|
isupport.Add("RPCHAN", "E")
|
||||||
isupport.Add("RPUSER", "E")
|
isupport.Add("RPUSER", "E")
|
||||||
}
|
}
|
||||||
|
isupport.Add("SAFELIST", "")
|
||||||
isupport.Add("STATUSMSG", "~&@%+")
|
isupport.Add("STATUSMSG", "~&@%+")
|
||||||
isupport.Add("TARGMAX", fmt.Sprintf("NAMES:1,LIST:1,KICK:,WHOIS:1,USERHOST:10,PRIVMSG:%s,TAGMSG:%s,NOTICE:%s,MONITOR:%d", maxTargetsString, maxTargetsString, maxTargetsString, config.Limits.MonitorEntries))
|
isupport.Add("TARGMAX", fmt.Sprintf("NAMES:1,LIST:1,KICK:,WHOIS:1,USERHOST:10,PRIVMSG:%s,TAGMSG:%s,NOTICE:%s,MONITOR:%d", maxTargetsString, maxTargetsString, maxTargetsString, config.Limits.MonitorEntries))
|
||||||
isupport.Add("TOPICLEN", strconv.Itoa(config.Limits.TopicLen))
|
isupport.Add("TOPICLEN", strconv.Itoa(config.Limits.TopicLen))
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build !plan9
|
//go:build !(plan9 || solaris)
|
||||||
|
|
||||||
package flock
|
package flock
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build plan9
|
//go:build plan9 || solaris
|
||||||
|
|
||||||
package flock
|
package flock
|
||||||
|
|
||||||
|
|
@ -855,7 +855,6 @@ func debugHandler(server *Server, client *Client, msg ircmsg.Message, rb *Respon
|
||||||
switch param {
|
switch param {
|
||||||
case "GCSTATS":
|
case "GCSTATS":
|
||||||
stats := debug.GCStats{
|
stats := debug.GCStats{
|
||||||
Pause: make([]time.Duration, 10),
|
|
||||||
PauseQuantiles: make([]time.Duration, 5),
|
PauseQuantiles: make([]time.Duration, 5),
|
||||||
}
|
}
|
||||||
debug.ReadGCStats(&stats)
|
debug.ReadGCStats(&stats)
|
||||||
|
|
@ -1321,6 +1320,15 @@ func isonHandler(server *Server, client *Client, msg ircmsg.Message, rb *Respons
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ISUPPORT
|
||||||
|
func isupportHandler(server *Server, client *Client, msg ircmsg.Message, rb *ResponseBuffer) bool {
|
||||||
|
server.RplISupport(client, rb)
|
||||||
|
if !client.registered {
|
||||||
|
rb.session.isupportSentPrereg = true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// JOIN <channel>{,<channel>} [<key>{,<key>}]
|
// JOIN <channel>{,<channel>} [<key>{,<key>}]
|
||||||
func joinHandler(server *Server, client *Client, msg ircmsg.Message, rb *ResponseBuffer) bool {
|
func joinHandler(server *Server, client *Client, msg ircmsg.Message, rb *ResponseBuffer) bool {
|
||||||
// #1417: allow `JOIN 0` with a confirmation code
|
// #1417: allow `JOIN 0` with a confirmation code
|
||||||
|
|
|
||||||
|
|
@ -259,6 +259,11 @@ appropriate channel privs.`,
|
||||||
text: `ISON <nickname>{ <nickname>}
|
text: `ISON <nickname>{ <nickname>}
|
||||||
|
|
||||||
Returns whether the given nicks exist on the network.`,
|
Returns whether the given nicks exist on the network.`,
|
||||||
|
},
|
||||||
|
"isupport": {
|
||||||
|
text: `ISUPPORT
|
||||||
|
|
||||||
|
Returns RPL_ISUPPORT lines describing the server's capabilities.`,
|
||||||
},
|
},
|
||||||
"join": {
|
"join": {
|
||||||
text: `JOIN <channel>{,<channel>} [<key>{,<key>}]
|
text: `JOIN <channel>{,<channel>} [<key>{,<key>}]
|
||||||
|
|
|
||||||
|
|
@ -434,7 +434,9 @@ func (server *Server) playRegistrationBurst(session *Session) {
|
||||||
session.Send(nil, server.name, RPL_MYINFO, d.nick, server.name, Ver, rplMyInfo1, rplMyInfo2, rplMyInfo3)
|
session.Send(nil, server.name, RPL_MYINFO, d.nick, server.name, Ver, rplMyInfo1, rplMyInfo2, rplMyInfo3)
|
||||||
|
|
||||||
rb := NewResponseBuffer(session)
|
rb := NewResponseBuffer(session)
|
||||||
server.RplISupport(c, rb)
|
if !(rb.session.capabilities.Has(caps.ExtendedISupport) && rb.session.isupportSentPrereg) {
|
||||||
|
server.RplISupport(c, rb)
|
||||||
|
}
|
||||||
if d.account != "" && session.capabilities.Has(caps.Persistence) {
|
if d.account != "" && session.capabilities.Has(caps.Persistence) {
|
||||||
reportPersistenceStatus(c, rb, false)
|
reportPersistenceStatus(c, rb, false)
|
||||||
}
|
}
|
||||||
|
|
@ -456,10 +458,17 @@ func (server *Server) playRegistrationBurst(session *Session) {
|
||||||
|
|
||||||
// RplISupport outputs our ISUPPORT lines to the client. This is used on connection and in VERSION responses.
|
// RplISupport outputs our ISUPPORT lines to the client. This is used on connection and in VERSION responses.
|
||||||
func (server *Server) RplISupport(client *Client, rb *ResponseBuffer) {
|
func (server *Server) RplISupport(client *Client, rb *ResponseBuffer) {
|
||||||
|
server.sendRplISupportLines(client, rb, server.Config().Server.isupport.CachedReply)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (server *Server) sendRplISupportLines(client *Client, rb *ResponseBuffer, lines [][]string) {
|
||||||
|
if rb.session.capabilities.Has(caps.ExtendedISupport) {
|
||||||
|
batchID := rb.StartNestedBatch(caps.ExtendedISupportBatchType)
|
||||||
|
defer rb.EndNestedBatch(batchID)
|
||||||
|
}
|
||||||
translatedISupport := client.t("are supported by this server")
|
translatedISupport := client.t("are supported by this server")
|
||||||
nick := client.Nick()
|
nick := client.Nick()
|
||||||
config := server.Config()
|
for _, cachedTokenLine := range lines {
|
||||||
for _, cachedTokenLine := range config.Server.isupport.CachedReply {
|
|
||||||
length := len(cachedTokenLine) + 2
|
length := len(cachedTokenLine) + 2
|
||||||
tokenline := make([]string, length)
|
tokenline := make([]string, length)
|
||||||
tokenline[0] = nick
|
tokenline[0] = nick
|
||||||
|
|
@ -794,13 +803,19 @@ func (server *Server) applyConfig(config *Config) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !initial {
|
if !initial {
|
||||||
// push new info to all of our clients
|
// send 005 updates (somewhat rare)
|
||||||
for _, sClient := range server.clients.AllClients() {
|
if len(newISupportReplies) != 0 {
|
||||||
for _, tokenline := range newISupportReplies {
|
for _, sClient := range server.clients.AllClients() {
|
||||||
sClient.Send(nil, server.name, RPL_ISUPPORT, append([]string{sClient.nick}, tokenline...)...)
|
for _, session := range sClient.Sessions() {
|
||||||
|
rb := NewResponseBuffer(session)
|
||||||
|
server.sendRplISupportLines(sClient, rb, newISupportReplies)
|
||||||
|
rb.Send(false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if sendRawOutputNotice {
|
if sendRawOutputNotice {
|
||||||
|
for _, sClient := range server.clients.AllClients() {
|
||||||
sClient.Notice(sClient.t("This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect."))
|
sClient.Notice(sClient.t("This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect."))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -791,7 +791,7 @@ lock-file: "ircd.lock"
|
||||||
|
|
||||||
# datastore configuration
|
# datastore configuration
|
||||||
datastore:
|
datastore:
|
||||||
# path to the datastore
|
# path to the database file (used to store account and channel registrations):
|
||||||
path: ircd.db
|
path: ircd.db
|
||||||
|
|
||||||
# if the database schema requires an upgrade, `autoupgrade` will attempt to
|
# if the database schema requires an upgrade, `autoupgrade` will attempt to
|
||||||
|
|
|
||||||
20
vendor/github.com/ergochat/irc-go/ircmsg/message.go
generated
vendored
20
vendor/github.com/ergochat/irc-go/ircmsg/message.go
generated
vendored
|
|
@ -196,6 +196,15 @@ func trimInitialSpaces(str string) string {
|
||||||
return str[i:]
|
return str[i:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isASCII(str string) bool {
|
||||||
|
for i := 0; i < len(str); i++ {
|
||||||
|
if str[i] > 127 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func parseLine(line string, maxTagDataLength int, truncateLen int) (ircmsg Message, err error) {
|
func parseLine(line string, maxTagDataLength int, truncateLen int) (ircmsg Message, err error) {
|
||||||
// remove either \n or \r\n from the end of the line:
|
// remove either \n or \r\n from the end of the line:
|
||||||
line = strings.TrimSuffix(line, "\n")
|
line = strings.TrimSuffix(line, "\n")
|
||||||
|
|
@ -265,11 +274,16 @@ func parseLine(line string, maxTagDataLength int, truncateLen int) (ircmsg Messa
|
||||||
commandEnd = len(line)
|
commandEnd = len(line)
|
||||||
paramStart = len(line)
|
paramStart = len(line)
|
||||||
}
|
}
|
||||||
// normalize command to uppercase:
|
baseCommand := line[:commandEnd]
|
||||||
ircmsg.Command = strings.ToUpper(line[:commandEnd])
|
if len(baseCommand) == 0 {
|
||||||
if len(ircmsg.Command) == 0 {
|
|
||||||
return ircmsg, ErrorLineIsEmpty
|
return ircmsg, ErrorLineIsEmpty
|
||||||
}
|
}
|
||||||
|
// technically this must be either letters or a 3-digit numeric:
|
||||||
|
if !isASCII(baseCommand) {
|
||||||
|
return ircmsg, ErrorLineContainsBadChar
|
||||||
|
}
|
||||||
|
// normalize command to uppercase:
|
||||||
|
ircmsg.Command = strings.ToUpper(baseCommand)
|
||||||
line = line[paramStart:]
|
line = line[paramStart:]
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
|
|
||||||
44
vendor/github.com/ergochat/irc-go/ircutils/sasl.go
generated
vendored
44
vendor/github.com/ergochat/irc-go/ircutils/sasl.go
generated
vendored
|
|
@ -3,7 +3,6 @@ package ircutils
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -25,6 +24,7 @@ func EncodeSASLResponse(raw []byte) (result []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
response := base64.StdEncoding.EncodeToString(raw)
|
response := base64.StdEncoding.EncodeToString(raw)
|
||||||
|
result = make([]string, 0, (len(response)/400)+1)
|
||||||
lastLen := 0
|
lastLen := 0
|
||||||
for len(response) > 0 {
|
for len(response) > 0 {
|
||||||
// TODO once we require go 1.21, this can be: lastLen = min(len(response), 400)
|
// TODO once we require go 1.21, this can be: lastLen = min(len(response), 400)
|
||||||
|
|
@ -48,11 +48,11 @@ func EncodeSASLResponse(raw []byte) (result []string) {
|
||||||
// Do not copy a SASLBuffer after first use.
|
// Do not copy a SASLBuffer after first use.
|
||||||
type SASLBuffer struct {
|
type SASLBuffer struct {
|
||||||
maxLength int
|
maxLength int
|
||||||
buffer strings.Builder
|
buf []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSASLBuffer returns a new SASLBuffer. maxLength is the maximum amount of
|
// NewSASLBuffer returns a new SASLBuffer. maxLength is the maximum amount of
|
||||||
// base64'ed data to buffer (0 for no limit).
|
// data to buffer (0 for no limit).
|
||||||
func NewSASLBuffer(maxLength int) *SASLBuffer {
|
func NewSASLBuffer(maxLength int) *SASLBuffer {
|
||||||
result := new(SASLBuffer)
|
result := new(SASLBuffer)
|
||||||
result.Initialize(maxLength)
|
result.Initialize(maxLength)
|
||||||
|
|
@ -69,37 +69,43 @@ func (b *SASLBuffer) Initialize(maxLength int) {
|
||||||
// response along with any decoding or protocol errors detected.
|
// response along with any decoding or protocol errors detected.
|
||||||
func (b *SASLBuffer) Add(value string) (done bool, output []byte, err error) {
|
func (b *SASLBuffer) Add(value string) (done bool, output []byte, err error) {
|
||||||
if value == "+" {
|
if value == "+" {
|
||||||
output, err = b.getAndReset()
|
// total size is a multiple of 400 (possibly 0)
|
||||||
return true, output, err
|
output = b.buf
|
||||||
|
b.Clear()
|
||||||
|
return true, output, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(value) > 400 {
|
if len(value) > 400 {
|
||||||
b.buffer.Reset()
|
b.Clear()
|
||||||
return true, nil, ErrSASLTooLong
|
return true, nil, ErrSASLTooLong
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.maxLength != 0 && (b.buffer.Len()+len(value)) > b.maxLength {
|
curLen := len(b.buf)
|
||||||
b.buffer.Reset()
|
chunkDecodedLen := base64.StdEncoding.DecodedLen(len(value))
|
||||||
|
if b.maxLength != 0 && (curLen+chunkDecodedLen) > b.maxLength {
|
||||||
|
b.Clear()
|
||||||
return true, nil, ErrSASLLimitExceeded
|
return true, nil, ErrSASLLimitExceeded
|
||||||
}
|
}
|
||||||
|
|
||||||
b.buffer.WriteString(value)
|
// "append-make pattern" as in the bytes.Buffer implementation:
|
||||||
|
b.buf = append(b.buf, make([]byte, chunkDecodedLen)...)
|
||||||
|
n, err := base64.StdEncoding.Decode(b.buf[curLen:], []byte(value))
|
||||||
|
b.buf = b.buf[0 : curLen+n]
|
||||||
|
if err != nil {
|
||||||
|
b.Clear()
|
||||||
|
return true, nil, err
|
||||||
|
}
|
||||||
if len(value) < 400 {
|
if len(value) < 400 {
|
||||||
output, err = b.getAndReset()
|
output = b.buf
|
||||||
return true, output, err
|
b.Clear()
|
||||||
|
return true, output, nil
|
||||||
} else {
|
} else {
|
||||||
// 400 bytes, wait for continuation line or +
|
|
||||||
return false, nil, nil
|
return false, nil, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear resets the buffer state.
|
// Clear resets the buffer state.
|
||||||
func (b *SASLBuffer) Clear() {
|
func (b *SASLBuffer) Clear() {
|
||||||
b.buffer.Reset()
|
// we can't reuse this buffer in general since we may have returned it
|
||||||
}
|
b.buf = nil
|
||||||
|
|
||||||
func (b *SASLBuffer) getAndReset() (output []byte, err error) {
|
|
||||||
output, err = base64.StdEncoding.DecodeString(b.buffer.String())
|
|
||||||
b.buffer.Reset()
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
|
|
@ -16,7 +16,7 @@ github.com/ergochat/confusables
|
||||||
# github.com/ergochat/go-ident v0.0.0-20230911071154-8c30606d6881
|
# github.com/ergochat/go-ident v0.0.0-20230911071154-8c30606d6881
|
||||||
## explicit; go 1.18
|
## explicit; go 1.18
|
||||||
github.com/ergochat/go-ident
|
github.com/ergochat/go-ident
|
||||||
# github.com/ergochat/irc-go v0.5.0-rc1
|
# github.com/ergochat/irc-go v0.5.0-rc2
|
||||||
## explicit; go 1.15
|
## explicit; go 1.15
|
||||||
github.com/ergochat/irc-go/ircfmt
|
github.com/ergochat/irc-go/ircfmt
|
||||||
github.com/ergochat/irc-go/ircmsg
|
github.com/ergochat/irc-go/ircmsg
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue