mirror of
https://github.com/idanoo/autobrr
synced 2025-07-23 00:39:13 +00:00
feat(irc): attempt SASL login with fallback to nickserv (#333)
* IRC: attempt SASL, ignore SASL failure * update Ergo integration testing config * refactor(irc): rework auth and join based on events
This commit is contained in:
parent
94a3810f57
commit
95471a4cf7
2 changed files with 924 additions and 878 deletions
|
@ -76,6 +76,8 @@ type Handler struct {
|
||||||
|
|
||||||
connectionErrors []string
|
connectionErrors []string
|
||||||
failedNickServAttempts int
|
failedNickServAttempts int
|
||||||
|
|
||||||
|
authenticated bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHandler(log logger.Logger, network domain.IrcNetwork, definitions []*domain.IndexerDefinition, releaseSvc release.Service, notificationSvc notification.Service) *Handler {
|
func NewHandler(log logger.Logger, network domain.IrcNetwork, definitions []*domain.IndexerDefinition, releaseSvc release.Service, notificationSvc notification.Service) *Handler {
|
||||||
|
@ -90,6 +92,7 @@ func NewHandler(log logger.Logger, network domain.IrcNetwork, definitions []*dom
|
||||||
validAnnouncers: map[string]struct{}{},
|
validAnnouncers: map[string]struct{}{},
|
||||||
validChannels: map[string]struct{}{},
|
validChannels: map[string]struct{}{},
|
||||||
channelHealth: map[string]*channelHealth{},
|
channelHealth: map[string]*channelHealth{},
|
||||||
|
authenticated: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
// init indexer, announceProcessor
|
// init indexer, announceProcessor
|
||||||
|
@ -152,6 +155,9 @@ func (h *Handler) Run() error {
|
||||||
User: h.network.NickServ.Account,
|
User: h.network.NickServ.Account,
|
||||||
RealName: h.network.NickServ.Account,
|
RealName: h.network.NickServ.Account,
|
||||||
Password: h.network.Pass,
|
Password: h.network.Pass,
|
||||||
|
SASLLogin: h.network.NickServ.Account,
|
||||||
|
SASLPassword: h.network.NickServ.Password,
|
||||||
|
SASLOptional: true,
|
||||||
Server: addr,
|
Server: addr,
|
||||||
KeepAlive: 4 * time.Minute,
|
KeepAlive: 4 * time.Minute,
|
||||||
Timeout: 2 * time.Minute,
|
Timeout: 2 * time.Minute,
|
||||||
|
@ -176,6 +182,7 @@ func (h *Handler) Run() error {
|
||||||
h.client.AddCallback("PRIVMSG", h.onMessage)
|
h.client.AddCallback("PRIVMSG", h.onMessage)
|
||||||
h.client.AddCallback("NOTICE", h.onNotice)
|
h.client.AddCallback("NOTICE", h.onNotice)
|
||||||
h.client.AddCallback("NICK", h.onNick)
|
h.client.AddCallback("NICK", h.onNick)
|
||||||
|
h.client.AddCallback("903", h.handleSASLSuccess)
|
||||||
|
|
||||||
if err := h.client.Connect(); err != nil {
|
if err := h.client.Connect(); err != nil {
|
||||||
h.log.Error().Stack().Err(err).Msg("connect error")
|
h.log.Error().Stack().Err(err).Msg("connect error")
|
||||||
|
@ -219,6 +226,10 @@ func (h *Handler) isOurNick(nick string) bool {
|
||||||
return h.network.NickServ.Account == nick
|
return h.network.NickServ.Account == nick
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *Handler) isOurCurrentNick(nick string) bool {
|
||||||
|
return h.client.CurrentNick() == nick
|
||||||
|
}
|
||||||
|
|
||||||
func (h *Handler) setConnectionStatus() {
|
func (h *Handler) setConnectionStatus() {
|
||||||
h.m.Lock()
|
h.m.Lock()
|
||||||
// set connected since now
|
// set connected since now
|
||||||
|
@ -293,9 +304,10 @@ func (h *Handler) Restart() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) onConnect(m ircmsg.Message) {
|
func (h *Handler) onConnect(m ircmsg.Message) {
|
||||||
|
// 0. Authenticated via SASL - join
|
||||||
// 1. No nickserv, no invite command - join
|
// 1. No nickserv, no invite command - join
|
||||||
// 2. Nickserv - join after auth
|
// 2. Nickserv password - join after auth
|
||||||
// 3. nickserv and invite command - join after nickserv
|
// 3. nickserv and invite command - send nickserv pass, wait for mode to send invite cmd, then join
|
||||||
// 4. invite command - join
|
// 4. invite command - join
|
||||||
|
|
||||||
h.resetConnectErrors()
|
h.resetConnectErrors()
|
||||||
|
@ -313,9 +325,28 @@ func (h *Handler) onConnect(m ircmsg.Message) {
|
||||||
|
|
||||||
h.log.Debug().Msgf("connected to: %v", h.network.Name)
|
h.log.Debug().Msgf("connected to: %v", h.network.Name)
|
||||||
|
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
if h.network.NickServ.Password != "" {
|
// if already authenticated via SASL then join channels
|
||||||
|
if h.authenticated {
|
||||||
|
h.log.Trace().Msg("on connect - already authenticated: join channels")
|
||||||
|
|
||||||
|
// check for invite command
|
||||||
|
if h.network.InviteCommand != "" {
|
||||||
|
if err := h.sendConnectCommands(h.network.InviteCommand); err != nil {
|
||||||
|
h.log.Error().Stack().Err(err).Msgf("error sending connect command %v", h.network.InviteCommand)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// let's return because MODE will change, and we join when we have the correct mode
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// if authenticated and no invite command lets join
|
||||||
|
h.JoinChannels()
|
||||||
|
|
||||||
|
} else if h.network.NickServ.Password != "" {
|
||||||
|
h.log.Trace().Msg("on connect not authenticated and password not empty: send nickserv identify")
|
||||||
if err := h.NickServIdentify(h.network.NickServ.Password); err != nil {
|
if err := h.NickServIdentify(h.network.NickServ.Password); err != nil {
|
||||||
h.log.Error().Stack().Err(err).Msg("error nickserv")
|
h.log.Error().Stack().Err(err).Msg("error nickserv")
|
||||||
return
|
return
|
||||||
|
@ -323,20 +354,21 @@ func (h *Handler) onConnect(m ircmsg.Message) {
|
||||||
|
|
||||||
// return and wait for NOTICE of nickserv auth
|
// return and wait for NOTICE of nickserv auth
|
||||||
return
|
return
|
||||||
}
|
|
||||||
|
|
||||||
if h.network.InviteCommand != "" && h.network.NickServ.Password == "" {
|
} else if h.network.InviteCommand != "" {
|
||||||
|
h.log.Trace().Msg("on connect invite command not empty: send connect commands")
|
||||||
if err := h.sendConnectCommands(h.network.InviteCommand); err != nil {
|
if err := h.sendConnectCommands(h.network.InviteCommand); err != nil {
|
||||||
h.log.Error().Stack().Err(err).Msgf("error sending connect command %v", h.network.InviteCommand)
|
h.log.Error().Stack().Err(err).Msgf("error sending connect command %v", h.network.InviteCommand)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
|
||||||
|
|
||||||
|
} else {
|
||||||
// join channels if no password or no invite command
|
// join channels if no password or no invite command
|
||||||
|
h.log.Trace().Msg("on connect - no nickserv or invite command: join channels")
|
||||||
h.JoinChannels()
|
h.JoinChannels()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) onDisconnect(m ircmsg.Message) {
|
func (h *Handler) onDisconnect(m ircmsg.Message) {
|
||||||
|
@ -345,6 +377,7 @@ func (h *Handler) onDisconnect(m ircmsg.Message) {
|
||||||
h.haveDisconnected = true
|
h.haveDisconnected = true
|
||||||
|
|
||||||
h.resetConnectionStatus()
|
h.resetConnectionStatus()
|
||||||
|
h.resetAuthenticated()
|
||||||
|
|
||||||
// check if we are responsible for disconnect
|
// check if we are responsible for disconnect
|
||||||
if !h.manuallyDisconnected {
|
if !h.manuallyDisconnected {
|
||||||
|
@ -360,8 +393,14 @@ func (h *Handler) onDisconnect(m ircmsg.Message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) onNotice(msg ircmsg.Message) {
|
func (h *Handler) onNotice(msg ircmsg.Message) {
|
||||||
if msg.Nick() == "NickServ" {
|
switch msg.Nick() {
|
||||||
h.log.Debug().Msgf("NOTICE from nickserv: %v", msg.Params)
|
case "NickServ":
|
||||||
|
h.handleNickServ(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) handleNickServ(msg ircmsg.Message) {
|
||||||
|
h.log.Trace().Msgf("NOTICE from nickserv: %v", msg.Params)
|
||||||
|
|
||||||
if contains(msg.Params[1],
|
if contains(msg.Params[1],
|
||||||
"Invalid account credentials",
|
"Invalid account credentials",
|
||||||
|
@ -415,29 +454,14 @@ func (h *Handler) onNotice(msg ircmsg.Message) {
|
||||||
h.failedNickServAttempts++
|
h.failedNickServAttempts++
|
||||||
}
|
}
|
||||||
|
|
||||||
// params: [test-bot You're now logged in as test-bot]
|
// You're now logged in as test-bot
|
||||||
// Password accepted - you are now recognized.
|
// Password accepted - you are now recognized.
|
||||||
if contains(msg.Params[1], "you're now logged in as", "password accepted", "you are now recognized") {
|
if contains(msg.Params[1], "you're now logged in as", "password accepted", "you are now recognized") {
|
||||||
h.log.Debug().Msgf("NOTICE nickserv logged in: %v", msg.Params)
|
h.log.Debug().Msgf("NOTICE nickserv logged in: %v", msg.Params)
|
||||||
|
|
||||||
h.resetConnectErrors()
|
|
||||||
h.failedNickServAttempts = 0
|
|
||||||
|
|
||||||
// if no invite command, join
|
|
||||||
if h.network.InviteCommand == "" {
|
|
||||||
h.JoinChannels()
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// else send connect commands
|
|
||||||
if err := h.sendConnectCommands(h.network.InviteCommand); err != nil {
|
|
||||||
h.log.Error().Stack().Err(err).Msgf("error sending connect command %v", h.network.InviteCommand)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//[test-bot Invalid parameters. For usage, do /msg NickServ HELP IDENTIFY]
|
|
||||||
// fallback for networks that require both password and nick to NickServ IDENTIFY
|
// fallback for networks that require both password and nick to NickServ IDENTIFY
|
||||||
|
// Invalid parameters. For usage, do /msg NickServ HELP IDENTIFY
|
||||||
if contains(msg.Params[1], "invalid parameters", "help identify") {
|
if contains(msg.Params[1], "invalid parameters", "help identify") {
|
||||||
h.log.Debug().Msgf("NOTICE nickserv invalid: %v", msg.Params)
|
h.log.Debug().Msgf("NOTICE nickserv invalid: %v", msg.Params)
|
||||||
|
|
||||||
|
@ -445,9 +469,25 @@ func (h *Handler) onNotice(msg ircmsg.Message) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Your nickname is not registered
|
// handleSASLSuccess we get here early so set authenticated before we hit onConnect
|
||||||
}
|
func (h *Handler) handleSASLSuccess(msg ircmsg.Message) {
|
||||||
|
h.setAuthenticated()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) setAuthenticated() {
|
||||||
|
h.m.Lock()
|
||||||
|
defer h.m.Unlock()
|
||||||
|
|
||||||
|
h.authenticated = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) resetAuthenticated() {
|
||||||
|
h.m.Lock()
|
||||||
|
defer h.m.Unlock()
|
||||||
|
|
||||||
|
h.authenticated = false
|
||||||
}
|
}
|
||||||
|
|
||||||
func contains(s string, substr ...string) bool {
|
func contains(s string, substr ...string) bool {
|
||||||
|
@ -464,7 +504,7 @@ func contains(s string, substr ...string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) onNick(msg ircmsg.Message) {
|
func (h *Handler) onNick(msg ircmsg.Message) {
|
||||||
h.log.Debug().Msgf("NICK event: %v params: %v", msg.Nick(), msg.Params)
|
h.log.Trace().Msgf("NICK event: %v params: %v", msg.Nick(), msg.Params)
|
||||||
|
|
||||||
if h.client.CurrentNick() != h.client.PreferredNick() {
|
if h.client.CurrentNick() != h.client.PreferredNick() {
|
||||||
h.log.Debug().Msgf("nick miss-match: got %v want %v", h.client.CurrentNick(), h.client.PreferredNick())
|
h.log.Debug().Msgf("nick miss-match: got %v want %v", h.client.CurrentNick(), h.client.PreferredNick())
|
||||||
|
@ -565,7 +605,7 @@ func (h *Handler) JoinChannel(channel string, password string) error {
|
||||||
|
|
||||||
func (h *Handler) handlePart(msg ircmsg.Message) {
|
func (h *Handler) handlePart(msg ircmsg.Message) {
|
||||||
if !h.isOurNick(msg.Nick()) {
|
if !h.isOurNick(msg.Nick()) {
|
||||||
h.log.Debug().Msgf("MODE OTHER USER: %+v", msg)
|
h.log.Trace().Msgf("PART other user: %+v", msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -573,8 +613,7 @@ func (h *Handler) handlePart(msg ircmsg.Message) {
|
||||||
|
|
||||||
h.log.Debug().Msgf("PART channel %v", channel)
|
h.log.Debug().Msgf("PART channel %v", channel)
|
||||||
|
|
||||||
err := h.client.Part(channel)
|
if err := h.client.Part(channel); err != nil {
|
||||||
if err != nil {
|
|
||||||
h.log.Error().Err(err).Msgf("error handling part: %v", channel)
|
h.log.Error().Err(err).Msgf("error handling part: %v", channel)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -589,7 +628,7 @@ func (h *Handler) handlePart(msg ircmsg.Message) {
|
||||||
|
|
||||||
// TODO remove announceProcessor
|
// TODO remove announceProcessor
|
||||||
|
|
||||||
h.log.Debug().Msgf("Left channel '%v'", channel)
|
h.log.Debug().Msgf("Left channel %v", channel)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -613,14 +652,14 @@ func (h *Handler) PartChannel(channel string) error {
|
||||||
|
|
||||||
// TODO remove announceProcessor
|
// TODO remove announceProcessor
|
||||||
|
|
||||||
h.log.Info().Msgf("Left channel '%v' on network '%v'", channel, h.network.Server)
|
h.log.Info().Msgf("Left channel: %v", channel)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) handleJoined(msg ircmsg.Message) {
|
func (h *Handler) handleJoined(msg ircmsg.Message) {
|
||||||
if !h.isOurNick(msg.Params[0]) {
|
if !h.isOurNick(msg.Params[0]) {
|
||||||
h.log.Debug().Msgf("OTHER USER JOINED: %+v", msg)
|
h.log.Trace().Msgf("JOINED other user: %+v", msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -705,7 +744,7 @@ func (h *Handler) NickServIdentify(password string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) NickChange(nick string) error {
|
func (h *Handler) NickChange(nick string) error {
|
||||||
h.log.Debug().Msgf("Nick change: %v", nick)
|
h.log.Debug().Msgf("NICK change: %v", nick)
|
||||||
|
|
||||||
h.client.SetNick(nick)
|
h.client.SetNick(nick)
|
||||||
|
|
||||||
|
@ -721,23 +760,34 @@ func (h *Handler) PreferredNick() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) handleMode(msg ircmsg.Message) {
|
func (h *Handler) handleMode(msg ircmsg.Message) {
|
||||||
h.log.Debug().Msgf("MODE: %+v", msg)
|
h.log.Trace().Msgf("MODE: %+v", msg)
|
||||||
|
|
||||||
if !h.isOurNick(msg.Params[0]) {
|
// if our nick and user mode +r (Identifies the nick as being Registered (settable by services only)) then return
|
||||||
h.log.Trace().Msgf("MODE OTHER USER: %+v", msg)
|
if h.isOurCurrentNick(msg.Params[0]) && strings.Contains(msg.Params[1], "+r") {
|
||||||
|
h.setAuthenticated()
|
||||||
|
|
||||||
|
h.resetConnectErrors()
|
||||||
|
h.failedNickServAttempts = 0
|
||||||
|
|
||||||
|
// if invite command send
|
||||||
|
if h.network.InviteCommand != "" {
|
||||||
|
// send connect commands
|
||||||
|
if err := h.sendConnectCommands(h.network.InviteCommand); err != nil {
|
||||||
|
h.log.Error().Stack().Err(err).Msgf("error sending connect command %v", h.network.InviteCommand)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if h.network.NickServ.Password != "" && !strings.Contains(msg.Params[0], h.client.Nick) || !strings.Contains(msg.Params[1], "+r") {
|
|
||||||
h.log.Trace().Msgf("MODE: Not correct permission yet: %v", msg.Params)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
// join channels
|
//join channels
|
||||||
h.JoinChannels()
|
h.JoinChannels()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
# This is the "traditional" or "mainstream" config file for Ergo.
|
# Ergo config for integration testing, based on Ergo's `default.yaml`
|
||||||
# It tries to replicate the behavior of other ircds, at the cost of not
|
|
||||||
# taking full advantage of Ergo's features. This config is suitable for use
|
|
||||||
# in IRCv3 conformance testing.
|
|
||||||
|
|
||||||
# network configuration
|
# network configuration
|
||||||
network:
|
network:
|
||||||
|
@ -15,10 +12,7 @@ server:
|
||||||
|
|
||||||
# addresses to listen on
|
# addresses to listen on
|
||||||
listeners:
|
listeners:
|
||||||
# This version of the config provides a public plaintext listener on
|
# XXX enable public plaintext listener to simplify Docker configuration:
|
||||||
# port 6667 for testing and compatibility with legacy applications.
|
|
||||||
# We recommend disabling this listener in a production setting
|
|
||||||
# and replacing it with loopback-only listeners (see default.yaml):
|
|
||||||
":6667":
|
":6667":
|
||||||
|
|
||||||
# The standard SSL/TLS port for IRC is 6697. This will listen on all interfaces:
|
# The standard SSL/TLS port for IRC is 6697. This will listen on all interfaces:
|
||||||
|
@ -32,8 +26,8 @@ server:
|
||||||
# always send a PROXY protocol header ahead of the connection. See the
|
# always send a PROXY protocol header ahead of the connection. See the
|
||||||
# manual ("Reverse proxies") for more details.
|
# manual ("Reverse proxies") for more details.
|
||||||
proxy: false
|
proxy: false
|
||||||
# optionally set the minimum TLS version (defaults to 1.0):
|
# set the minimum TLS version:
|
||||||
# min-tls-version: 1.2
|
min-tls-version: 1.2
|
||||||
|
|
||||||
# Example of a Unix domain socket for proxying:
|
# Example of a Unix domain socket for proxying:
|
||||||
# "/tmp/ergo_sock":
|
# "/tmp/ergo_sock":
|
||||||
|
@ -121,22 +115,22 @@ server:
|
||||||
enforce-utf8: true
|
enforce-utf8: true
|
||||||
|
|
||||||
# whether to look up user hostnames with reverse DNS. there are 3 possibilities:
|
# whether to look up user hostnames with reverse DNS. there are 3 possibilities:
|
||||||
# 1. [enabled here] lookup-hostnames enabled, IP cloaking disabled; users will see each other's hostnames
|
# 1. lookup-hostnames enabled, IP cloaking disabled; users will see each other's hostnames
|
||||||
# 2. lookup-hostnames disabled, IP cloaking disabled; users will see each other's numeric IPs
|
# 2. lookup-hostnames disabled, IP cloaking disabled; users will see each other's numeric IPs
|
||||||
# 3. IP cloaking enabled; users will see cloaked hostnames
|
# 3. [the default] IP cloaking enabled; users will see cloaked hostnames
|
||||||
lookup-hostnames: true
|
lookup-hostnames: false
|
||||||
# whether to confirm hostname lookups using "forward-confirmed reverse DNS", i.e., for
|
# whether to confirm hostname lookups using "forward-confirmed reverse DNS", i.e., for
|
||||||
# any hostname returned from reverse DNS, resolve it back to an IP address and reject it
|
# any hostname returned from reverse DNS, resolve it back to an IP address and reject it
|
||||||
# unless it matches the connecting IP
|
# unless it matches the connecting IP
|
||||||
forward-confirm-hostnames: true
|
forward-confirm-hostnames: true
|
||||||
|
|
||||||
# use ident protocol to get usernames
|
# use ident protocol to get usernames
|
||||||
check-ident: true
|
check-ident: false
|
||||||
|
|
||||||
# ignore the supplied user/ident string from the USER command, always setting user/ident
|
# ignore the supplied user/ident string from the USER command, always setting user/ident
|
||||||
# to the following literal value; this can potentially reduce confusion and simplify bans.
|
# to the following literal value; this can potentially reduce confusion and simplify bans.
|
||||||
# the value must begin with a '~' character. comment out / omit to disable:
|
# the value must begin with a '~' character. comment out / omit to disable:
|
||||||
#coerce-ident: '~u'
|
coerce-ident: '~u'
|
||||||
|
|
||||||
# password to login to the server, generated using `ergo genpasswd`:
|
# password to login to the server, generated using `ergo genpasswd`:
|
||||||
#password: "$2a$04$0123456789abcdef0123456789abcdef0123456789abcdef01234"
|
#password: "$2a$04$0123456789abcdef0123456789abcdef0123456789abcdef01234"
|
||||||
|
@ -180,7 +174,7 @@ server:
|
||||||
certfp: "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789"
|
certfp: "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789"
|
||||||
|
|
||||||
# password the gateway uses to connect, made with `ergo genpasswd`
|
# password the gateway uses to connect, made with `ergo genpasswd`
|
||||||
password: "$2a$04$abcdef0123456789abcdef0123456789abcdef0123456789abcde" # test
|
password: "$2a$04$abcdef0123456789abcdef0123456789abcdef0123456789abcde"
|
||||||
|
|
||||||
# IPs/CIDRs that can use this webirc command
|
# IPs/CIDRs that can use this webirc command
|
||||||
# you should also add these addresses to the connection limits and throttling exemption lists
|
# you should also add these addresses to the connection limits and throttling exemption lists
|
||||||
|
@ -213,7 +207,7 @@ server:
|
||||||
# allow-truncation to false, in which case Ergo will reject the message
|
# allow-truncation to false, in which case Ergo will reject the message
|
||||||
# and return an error to the client. (note that this option defaults to true
|
# and return an error to the client. (note that this option defaults to true
|
||||||
# when unset.)
|
# when unset.)
|
||||||
allow-truncation: true
|
allow-truncation: false
|
||||||
|
|
||||||
# IP-based DoS protection
|
# IP-based DoS protection
|
||||||
ip-limits:
|
ip-limits:
|
||||||
|
@ -284,9 +278,10 @@ server:
|
||||||
# DNS, users see fake domain names like pwbs2ui4377257x8.irc. These names are
|
# DNS, users see fake domain names like pwbs2ui4377257x8.irc. These names are
|
||||||
# generated deterministically from the underlying IP address, but if the underlying
|
# generated deterministically from the underlying IP address, but if the underlying
|
||||||
# IP is not already known, it is infeasible to recover it from the cloaked name.
|
# IP is not already known, it is infeasible to recover it from the cloaked name.
|
||||||
|
# If you disable this, you should probably enable lookup-hostnames in its place.
|
||||||
ip-cloaking:
|
ip-cloaking:
|
||||||
# whether to enable IP cloaking
|
# whether to enable IP cloaking
|
||||||
enabled: false
|
enabled: true
|
||||||
|
|
||||||
# whether to use these cloak settings (specifically, `netname` and `num-bits`)
|
# whether to use these cloak settings (specifically, `netname` and `num-bits`)
|
||||||
# to produce unique hostnames for always-on clients. you can enable this even if
|
# to produce unique hostnames for always-on clients. you can enable this even if
|
||||||
|
@ -418,7 +413,7 @@ accounts:
|
||||||
|
|
||||||
# enable login to accounts via the PASS command, e.g., PASS account:password
|
# enable login to accounts via the PASS command, e.g., PASS account:password
|
||||||
# this is useful for compatibility with old clients that don't support SASL
|
# this is useful for compatibility with old clients that don't support SASL
|
||||||
login-via-pass-command: false
|
login-via-pass-command: true
|
||||||
|
|
||||||
# require-sasl controls whether clients are required to have accounts
|
# require-sasl controls whether clients are required to have accounts
|
||||||
# (and sign into them using SASL) to connect to the server
|
# (and sign into them using SASL) to connect to the server
|
||||||
|
@ -442,7 +437,7 @@ accounts:
|
||||||
# how many nicknames, in addition to the account name, can be reserved?
|
# how many nicknames, in addition to the account name, can be reserved?
|
||||||
# (note that additional nicks are unusable under force-nick-equals-account
|
# (note that additional nicks are unusable under force-nick-equals-account
|
||||||
# or if the client is always-on)
|
# or if the client is always-on)
|
||||||
additional-nick-limit: 2
|
additional-nick-limit: 0
|
||||||
|
|
||||||
# method describes how nickname reservation is handled
|
# method describes how nickname reservation is handled
|
||||||
# strict: users must already be logged in to their account (via
|
# strict: users must already be logged in to their account (via
|
||||||
|
@ -450,11 +445,11 @@ accounts:
|
||||||
# in order to use their reserved nickname(s)
|
# in order to use their reserved nickname(s)
|
||||||
# optional: no enforcement by default, but allow users to opt in to
|
# optional: no enforcement by default, but allow users to opt in to
|
||||||
# the enforcement level of their choice
|
# the enforcement level of their choice
|
||||||
method: optional
|
method: strict
|
||||||
|
|
||||||
# allow users to set their own nickname enforcement status, e.g.,
|
# allow users to set their own nickname enforcement status, e.g.,
|
||||||
# to opt out of strict enforcement
|
# to opt out of strict enforcement
|
||||||
allow-custom-enforcement: true
|
allow-custom-enforcement: false
|
||||||
|
|
||||||
# format for guest nicknames:
|
# format for guest nicknames:
|
||||||
# 1. these nicknames cannot be registered or reserved
|
# 1. these nicknames cannot be registered or reserved
|
||||||
|
@ -475,7 +470,7 @@ accounts:
|
||||||
# account name as their nickname. when combined with strict nickname
|
# account name as their nickname. when combined with strict nickname
|
||||||
# enforcement, this lets users treat nicknames and account names
|
# enforcement, this lets users treat nicknames and account names
|
||||||
# as equivalent for the purpose of ban/invite/exception lists.
|
# as equivalent for the purpose of ban/invite/exception lists.
|
||||||
force-nick-equals-account: false
|
force-nick-equals-account: true
|
||||||
|
|
||||||
# parallel setting to force-nick-equals-account: if true, this forbids
|
# parallel setting to force-nick-equals-account: if true, this forbids
|
||||||
# anonymous users (i.e., users not logged into an account) to change their
|
# anonymous users (i.e., users not logged into an account) to change their
|
||||||
|
@ -495,12 +490,12 @@ accounts:
|
||||||
# if this is disabled, clients have to opt in to bouncer functionality
|
# if this is disabled, clients have to opt in to bouncer functionality
|
||||||
# using nickserv or the cap system. if it's enabled, they can opt out
|
# using nickserv or the cap system. if it's enabled, they can opt out
|
||||||
# via nickserv
|
# via nickserv
|
||||||
allowed-by-default: false
|
allowed-by-default: true
|
||||||
|
|
||||||
# whether to allow clients that remain on the server even
|
# whether to allow clients that remain on the server even
|
||||||
# when they have no active connections. The possible values are:
|
# when they have no active connections. The possible values are:
|
||||||
# "disabled", "opt-in", "opt-out", or "mandatory".
|
# "disabled", "opt-in", "opt-out", or "mandatory".
|
||||||
always-on: "disabled"
|
always-on: "opt-in"
|
||||||
|
|
||||||
# whether to mark always-on clients away when they have no active connections:
|
# whether to mark always-on clients away when they have no active connections:
|
||||||
auto-away: "opt-in"
|
auto-away: "opt-in"
|
||||||
|
@ -526,7 +521,7 @@ accounts:
|
||||||
# if unset, no user modes will be set by default
|
# if unset, no user modes will be set by default
|
||||||
# +i is invisible (a user's channels are hidden from whois replies)
|
# +i is invisible (a user's channels are hidden from whois replies)
|
||||||
# see /QUOTE HELP umodes for more user modes
|
# see /QUOTE HELP umodes for more user modes
|
||||||
# default-user-modes: +i
|
default-user-modes: +i
|
||||||
|
|
||||||
# pluggable authentication mechanism, via subprocess invocation
|
# pluggable authentication mechanism, via subprocess invocation
|
||||||
# see the manual for details on how to write an authentication plugin script
|
# see the manual for details on how to write an authentication plugin script
|
||||||
|
@ -548,9 +543,10 @@ accounts:
|
||||||
# channel options
|
# channel options
|
||||||
channels:
|
channels:
|
||||||
# modes that are set when new channels are created
|
# modes that are set when new channels are created
|
||||||
# +n is no-external-messages and +t is op-only-topic
|
# +n is no-external-messages, +t is op-only-topic,
|
||||||
|
# +C is no CTCPs (besides ACTION)
|
||||||
# see /QUOTE HELP cmodes for more channel modes
|
# see /QUOTE HELP cmodes for more channel modes
|
||||||
default-modes: +nt
|
default-modes: +ntC
|
||||||
|
|
||||||
# how many channels can a client be in at once?
|
# how many channels can a client be in at once?
|
||||||
max-channels-per-client: 100
|
max-channels-per-client: 100
|
||||||
|
@ -631,13 +627,13 @@ opers:
|
||||||
|
|
||||||
# traditionally, operator status is visible to unprivileged users in
|
# traditionally, operator status is visible to unprivileged users in
|
||||||
# WHO and WHOIS responses. this can be disabled with 'hidden'.
|
# WHO and WHOIS responses. this can be disabled with 'hidden'.
|
||||||
hidden: false
|
hidden: true
|
||||||
|
|
||||||
# custom whois line (if `hidden` is enabled, visible only to other operators)
|
# custom whois line (if `hidden` is enabled, visible only to other operators)
|
||||||
whois-line: is the server administrator
|
whois-line: is the server administrator
|
||||||
|
|
||||||
# custom hostname (ignored if `hidden` is enabled)
|
# custom hostname (ignored if `hidden` is enabled)
|
||||||
vhost: "staff"
|
#vhost: "staff"
|
||||||
|
|
||||||
# modes are modes to auto-set upon opering-up. uncomment this to automatically
|
# modes are modes to auto-set upon opering-up. uncomment this to automatically
|
||||||
# enable snomasks ("server notification masks" that alert you to server events;
|
# enable snomasks ("server notification masks" that alert you to server events;
|
||||||
|
@ -842,19 +838,19 @@ roleplay:
|
||||||
# in effect, the server can sign a token attesting that the client is present on
|
# in effect, the server can sign a token attesting that the client is present on
|
||||||
# the server, is a member of a particular channel, etc.
|
# the server, is a member of a particular channel, etc.
|
||||||
extjwt:
|
extjwt:
|
||||||
# # default service config (for `EXTJWT #channel`).
|
# # default service config (for `EXTJWT #channel`).
|
||||||
# # expiration time for the token:
|
# # expiration time for the token:
|
||||||
# expiration: 45s
|
# expiration: 45s
|
||||||
# # you can configure tokens to be signed either with HMAC and a symmetric secret:
|
# # you can configure tokens to be signed either with HMAC and a symmetric secret:
|
||||||
# secret: "65PHvk0K1_sM-raTsCEhatVkER_QD8a0zVV8gG2EWcI"
|
# secret: "65PHvk0K1_sM-raTsCEhatVkER_QD8a0zVV8gG2EWcI"
|
||||||
# # or with an RSA private key:
|
# # or with an RSA private key:
|
||||||
# #rsa-private-key-file: "extjwt.pem"
|
# #rsa-private-key-file: "extjwt.pem"
|
||||||
|
|
||||||
# # named services (for `EXTJWT #channel service_name`):
|
# # named services (for `EXTJWT #channel service_name`):
|
||||||
# services:
|
# services:
|
||||||
# "jitsi":
|
# "jitsi":
|
||||||
# expiration: 30s
|
# expiration: 30s
|
||||||
# secret: "qmamLKDuOzIzlO8XqsGGewei_At11lewh6jtKfSTbkg"
|
# secret: "qmamLKDuOzIzlO8XqsGGewei_At11lewh6jtKfSTbkg"
|
||||||
|
|
||||||
# history message storage: this is used by CHATHISTORY, HISTORY, znc.in/playback,
|
# history message storage: this is used by CHATHISTORY, HISTORY, znc.in/playback,
|
||||||
# various autoreplay features, and the resume extension
|
# various autoreplay features, and the resume extension
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue