parent
b655e81753
commit
ec415c2852
|
@ -0,0 +1,2 @@
|
||||||
|
vendor/* linguist-vendored
|
||||||
|
languages/* linguist-vendored
|
|
@ -0,0 +1,56 @@
|
||||||
|
# .goreleaser.yml
|
||||||
|
# Build customization
|
||||||
|
project_name: ergo
|
||||||
|
builds:
|
||||||
|
- main: ergo.go
|
||||||
|
binary: ergo
|
||||||
|
goos:
|
||||||
|
- freebsd
|
||||||
|
- windows
|
||||||
|
- darwin
|
||||||
|
- linux
|
||||||
|
goarch:
|
||||||
|
- "386"
|
||||||
|
- amd64
|
||||||
|
- arm
|
||||||
|
- arm64
|
||||||
|
goarm:
|
||||||
|
- 6
|
||||||
|
- 7
|
||||||
|
ignore:
|
||||||
|
- goos: windows
|
||||||
|
goarch: arm
|
||||||
|
- goos: darwin
|
||||||
|
goarch: arm
|
||||||
|
- goos: darwin
|
||||||
|
goarch: 386
|
||||||
|
- goos: freebsd
|
||||||
|
goarch: arm
|
||||||
|
- goos: freebsd
|
||||||
|
goarch: arm64
|
||||||
|
flags:
|
||||||
|
- -trimpath
|
||||||
|
|
||||||
|
archives:
|
||||||
|
- name_template: "{{ .ProjectName }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
|
||||||
|
format: tar.gz
|
||||||
|
replacements:
|
||||||
|
amd64: x86_64
|
||||||
|
darwin: macos
|
||||||
|
format_overrides:
|
||||||
|
- goos: windows
|
||||||
|
format: zip
|
||||||
|
files:
|
||||||
|
- README
|
||||||
|
- CHANGELOG.md
|
||||||
|
- ergo.motd
|
||||||
|
- default.yaml
|
||||||
|
- traditional.yaml
|
||||||
|
- docs/MANUAL.md
|
||||||
|
- docs/USERGUIDE.md
|
||||||
|
- languages/*.yaml
|
||||||
|
- languages/*.json
|
||||||
|
- languages/*.md
|
||||||
|
wrap_in_directory: true
|
||||||
|
checksum:
|
||||||
|
name_template: "{{ .ProjectName }}-{{ .Version }}-checksums.txt"
|
|
@ -0,0 +1,48 @@
|
||||||
|
## build ergo binary
|
||||||
|
FROM golang:1.17-alpine AS build-env
|
||||||
|
|
||||||
|
RUN apk add -U --force-refresh --no-cache --purge --clean-protected -l -u make
|
||||||
|
|
||||||
|
# copy ergo source
|
||||||
|
WORKDIR /go/src/github.com/ergochat/ergo
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# modify default config file so that it doesn't die on IPv6
|
||||||
|
# and so it can be exposed via 6667 by default
|
||||||
|
RUN sed -i 's/^\(\s*\)\"127.0.0.1:6667\":.*$/\1":6667":/' /go/src/github.com/ergochat/ergo/default.yaml && \
|
||||||
|
sed -i 's/^\s*\"\[::1\]:6667\":.*$//' /go/src/github.com/ergochat/ergo/default.yaml
|
||||||
|
|
||||||
|
# compile
|
||||||
|
RUN make
|
||||||
|
|
||||||
|
## build ergo container
|
||||||
|
FROM alpine:3.13
|
||||||
|
|
||||||
|
# metadata
|
||||||
|
LABEL maintainer="Daniel Oaks <daniel@danieloaks.net>,Daniel Thamdrup <dallemon@protonmail.com>" \
|
||||||
|
description="Ergo is a modern, experimental IRC server written in Go"
|
||||||
|
|
||||||
|
# standard ports listened on
|
||||||
|
EXPOSE 6667/tcp 6697/tcp
|
||||||
|
|
||||||
|
# ergo itself
|
||||||
|
COPY --from=build-env /go/bin/ergo \
|
||||||
|
/go/src/github.com/ergochat/ergo/default.yaml \
|
||||||
|
/go/src/github.com/ergochat/ergo/distrib/docker/run.sh \
|
||||||
|
/ircd-bin/
|
||||||
|
COPY --from=build-env /go/src/github.com/ergochat/ergo/languages /ircd-bin/languages/
|
||||||
|
|
||||||
|
# running volume holding config file, db, certs
|
||||||
|
VOLUME /ircd
|
||||||
|
WORKDIR /ircd
|
||||||
|
|
||||||
|
# default motd
|
||||||
|
COPY --from=build-env /go/src/github.com/ergochat/ergo/ergo.motd /ircd/ergo.motd
|
||||||
|
|
||||||
|
# launch
|
||||||
|
ENTRYPOINT ["/ircd-bin/run.sh"]
|
||||||
|
|
||||||
|
# # uncomment to debug
|
||||||
|
# RUN apk add --no-cache bash
|
||||||
|
# RUN apk add --no-cache vim
|
||||||
|
# CMD /bin/bash
|
1
LICENSE
1
LICENSE
|
@ -4,7 +4,6 @@ Copyright (c) 2012-2014 Jeremy Latt
|
||||||
Copyright (c) 2014-2015 Edmund Huber
|
Copyright (c) 2014-2015 Edmund Huber
|
||||||
Copyright (c) 2016-2020 Daniel Oaks
|
Copyright (c) 2016-2020 Daniel Oaks
|
||||||
Copyright (c) 2017-2020 Shivaram Lingamneni
|
Copyright (c) 2017-2020 Shivaram Lingamneni
|
||||||
Copyright (c) 2020-2022 kayos@tcp.direct
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
|
@ -194,8 +194,8 @@ func (am *AccountManager) buildNickToAccountIndex(config *Config) {
|
||||||
|
|
||||||
if config.Accounts.NickReservation.Method == NickEnforcementStrict {
|
if config.Accounts.NickReservation.Method == NickEnforcementStrict {
|
||||||
unregisteredPrefix := fmt.Sprintf(keyAccountUnregistered, "")
|
unregisteredPrefix := fmt.Sprintf(keyAccountUnregistered, "")
|
||||||
err := am.server.store.View(func(tx *buntdb.Tx) error {
|
am.server.store.View(func(tx *buntdb.Tx) error {
|
||||||
err = tx.AscendGreaterOrEqual("", unregisteredPrefix, func(key, value string) bool {
|
tx.AscendGreaterOrEqual("", unregisteredPrefix, func(key, value string) bool {
|
||||||
if !strings.HasPrefix(key, unregisteredPrefix) {
|
if !strings.HasPrefix(key, unregisteredPrefix) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -206,11 +206,8 @@ func (am *AccountManager) buildNickToAccountIndex(config *Config) {
|
||||||
skeletonToAccount[skeleton] = account
|
skeletonToAccount[skeleton] = account
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
return err
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
|
||||||
am.server.logger.Error("internal", "buildNickToAccountIndex buntdb transaction error during AscendGreaterOrEqual", err.Error())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -406,10 +403,7 @@ func (am *AccountManager) Register(client *Client, account string, callbackNames
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = creds.AddCertfp(certfp)
|
creds.AddCertfp(certfp)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
credStr, err := creds.Serialize()
|
credStr, err := creds.Serialize()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -477,7 +471,7 @@ func (am *AccountManager) Register(client *Client, account string, callbackNames
|
||||||
|
|
||||||
code, err := am.dispatchCallback(client, account, callbackNamespace, callbackValue)
|
code, err := am.dispatchCallback(client, account, callbackNamespace, callbackValue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = am.Unregister(casefoldedAccount, true)
|
am.Unregister(casefoldedAccount, true)
|
||||||
return ®istrationCallbackError{underlying: err}
|
return ®istrationCallbackError{underlying: err}
|
||||||
} else {
|
} else {
|
||||||
am.server.logger.Info("accounts",
|
am.server.logger.Info("accounts",
|
||||||
|
@ -543,11 +537,11 @@ func (am *AccountManager) setPassword(accountName string, password string, hasPr
|
||||||
|
|
||||||
credKey := fmt.Sprintf(keyAccountCredentials, cfAccount)
|
credKey := fmt.Sprintf(keyAccountCredentials, cfAccount)
|
||||||
var credStr string
|
var credStr string
|
||||||
err = am.server.store.View(func(tx *buntdb.Tx) error {
|
am.server.store.View(func(tx *buntdb.Tx) error {
|
||||||
// no need to check verification status here or below;
|
// no need to check verification status here or below;
|
||||||
// you either need to be auth'ed to the account or be an oper to do this
|
// you either need to be auth'ed to the account or be an oper to do this
|
||||||
credStr, err = tx.Get(credKey)
|
credStr, err = tx.Get(credKey)
|
||||||
return err
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -657,14 +651,12 @@ func (am *AccountManager) saveLastSeen(account string, lastSeen map[string]time.
|
||||||
val = string(text)
|
val = string(text)
|
||||||
}
|
}
|
||||||
err := am.server.store.Update(func(tx *buntdb.Tx) error {
|
err := am.server.store.Update(func(tx *buntdb.Tx) error {
|
||||||
var err error
|
if val != "" {
|
||||||
switch val {
|
tx.Set(key, val, nil)
|
||||||
case "":
|
} else {
|
||||||
_, err = tx.Delete(key)
|
tx.Delete(key)
|
||||||
default:
|
|
||||||
_, _, err = tx.Set(key, val, nil)
|
|
||||||
}
|
}
|
||||||
return err
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
am.server.logger.Error("internal", "error persisting lastSeen", account, err.Error())
|
am.server.logger.Error("internal", "error persisting lastSeen", account, err.Error())
|
||||||
|
@ -722,9 +714,9 @@ func (am *AccountManager) addRemoveCertfp(account, certfp string, add bool, hasP
|
||||||
|
|
||||||
credKey := fmt.Sprintf(keyAccountCredentials, cfAccount)
|
credKey := fmt.Sprintf(keyAccountCredentials, cfAccount)
|
||||||
var credStr string
|
var credStr string
|
||||||
err = am.server.store.View(func(tx *buntdb.Tx) error {
|
am.server.store.View(func(tx *buntdb.Tx) error {
|
||||||
credStr, err = tx.Get(credKey)
|
credStr, err = tx.Get(credKey)
|
||||||
return err
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -741,18 +733,16 @@ func (am *AccountManager) addRemoveCertfp(account, certfp string, add bool, hasP
|
||||||
return errCredsExternallyManaged
|
return errCredsExternallyManaged
|
||||||
}
|
}
|
||||||
|
|
||||||
switch add {
|
if add {
|
||||||
case true:
|
|
||||||
err = creds.AddCertfp(certfp)
|
err = creds.AddCertfp(certfp)
|
||||||
default:
|
} else {
|
||||||
err = creds.RemoveCertfp(certfp)
|
err = creds.RemoveCertfp(certfp)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if creds.Empty() {
|
if creds.Empty() && !hasPrivs {
|
||||||
return errEmptyCredentials
|
return errEmptyCredentials
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,8 @@ const (
|
||||||
// 'version' of the database schema
|
// 'version' of the database schema
|
||||||
keySchemaVersion = "db.version"
|
keySchemaVersion = "db.version"
|
||||||
// latest schema of the db
|
// latest schema of the db
|
||||||
latestDbSchema = 23
|
latestDbSchema = 22
|
||||||
|
|
||||||
keyCloakSecret = "crypto.cloak_secret"
|
keyCloakSecret = "crypto.cloak_secret"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1112,56 +1113,6 @@ func schemaChangeV21To22(config *Config, tx *buntdb.Tx) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func schemaChangeV22To23(config *Config, tx *buntdb.Tx) error {
|
|
||||||
type accountSettingsv23 struct {
|
|
||||||
NickEnforcement NickEnforcementMethod
|
|
||||||
AllowBouncer MulticlientAllowedSetting
|
|
||||||
AutoreplayMissed bool
|
|
||||||
AutoAway PersistentStatus
|
|
||||||
GitAuth bool
|
|
||||||
Email string
|
|
||||||
}
|
|
||||||
|
|
||||||
var accounts []string
|
|
||||||
var serializedSettings []string
|
|
||||||
settingsPrefix := "account.settings "
|
|
||||||
err := tx.AscendGreaterOrEqual("", settingsPrefix, func(key, value string) bool {
|
|
||||||
if !strings.HasPrefix(key, settingsPrefix) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if value == "" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
account := strings.TrimPrefix(key, settingsPrefix)
|
|
||||||
var settings accountSettingsv23
|
|
||||||
err := json.Unmarshal([]byte(value), &settings)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("error (v22-23) processing settings for %s: %v\n", account, err)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
b, err := json.Marshal(settings)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("error (v22-23) processing settings for %s: %v\n", account, err)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
accounts = append(accounts, account)
|
|
||||||
serializedSettings = append(serializedSettings, string(b))
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("error (v22-23) processing db transaction (invalid index): %v\n", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, account := range accounts {
|
|
||||||
tx.Set(settingsPrefix+account, serializedSettings[i], nil)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSchemaChange(initialVersion int) (result SchemaChange, ok bool) {
|
func getSchemaChange(initialVersion int) (result SchemaChange, ok bool) {
|
||||||
for _, change := range allChanges {
|
for _, change := range allChanges {
|
||||||
if initialVersion == change.InitialVersion {
|
if initialVersion == change.InitialVersion {
|
||||||
|
@ -1277,9 +1228,4 @@ var allChanges = []SchemaChange{
|
||||||
TargetVersion: 22,
|
TargetVersion: 22,
|
||||||
Changer: schemaChangeV21To22,
|
Changer: schemaChangeV21To22,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
InitialVersion: 22,
|
|
||||||
TargetVersion: 23,
|
|
||||||
Changer: schemaChangeV22To23,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -421,6 +421,15 @@ func displaySetting(service *ircService, settingName string, settings AccountSet
|
||||||
service.Notice(rb, client.t("Multiclient functionality is currently enabled for your account"))
|
service.Notice(rb, client.t("Multiclient functionality is currently enabled for your account"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case "always-on":
|
||||||
|
stored := settings.AlwaysOn
|
||||||
|
actual := persistenceEnabled(config.Accounts.Multiclient.AlwaysOn, stored)
|
||||||
|
service.Notice(rb, fmt.Sprintf(client.t("Your stored always-on setting is: %s"), userPersistentStatusToString(stored)))
|
||||||
|
if actual {
|
||||||
|
service.Notice(rb, client.t("Given current server settings, your client is always-on"))
|
||||||
|
} else {
|
||||||
|
service.Notice(rb, client.t("Given current server settings, your client is not always-on"))
|
||||||
|
}
|
||||||
case "auto-away":
|
case "auto-away":
|
||||||
stored := settings.AutoAway
|
stored := settings.AutoAway
|
||||||
alwaysOn := persistenceEnabled(config.Accounts.Multiclient.AlwaysOn, settings.AlwaysOn)
|
alwaysOn := persistenceEnabled(config.Accounts.Multiclient.AlwaysOn, settings.AlwaysOn)
|
||||||
|
@ -491,6 +500,22 @@ func nsSetHandler(service *ircService, server *Server, client *Client, command s
|
||||||
if err == nil {
|
if err == nil {
|
||||||
finalSettings.NickEnforcement = method // success
|
finalSettings.NickEnforcement = method // success
|
||||||
}
|
}
|
||||||
|
case "autoreplay-lines":
|
||||||
|
var newValue *int
|
||||||
|
if strings.ToLower(params[1]) != "default" {
|
||||||
|
val, err_ := strconv.Atoi(params[1])
|
||||||
|
if err_ != nil || val < 0 {
|
||||||
|
err = errInvalidParams
|
||||||
|
break
|
||||||
|
}
|
||||||
|
newValue = new(int)
|
||||||
|
*newValue = val
|
||||||
|
}
|
||||||
|
munger = func(in AccountSettings) (out AccountSettings, err error) {
|
||||||
|
out = in
|
||||||
|
out.AutoreplayLines = newValue
|
||||||
|
return
|
||||||
|
}
|
||||||
case "multiclient":
|
case "multiclient":
|
||||||
var newValue MulticlientAllowedSetting
|
var newValue MulticlientAllowedSetting
|
||||||
if strings.ToLower(params[1]) == "default" {
|
if strings.ToLower(params[1]) == "default" {
|
||||||
|
@ -521,6 +546,39 @@ func nsSetHandler(service *ircService, server *Server, client *Client, command s
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case "always-on":
|
||||||
|
// #821: it's problematic to alter the value of always-on if you're not
|
||||||
|
// the (actual or potential) always-on client yourself. make an exception
|
||||||
|
// for `saset` to give operators an escape hatch (any consistency problems
|
||||||
|
// can probably be fixed by restarting the server):
|
||||||
|
if command != "saset" {
|
||||||
|
details := client.Details()
|
||||||
|
if details.nick != details.accountName {
|
||||||
|
err = errNickAccountMismatch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
var newValue PersistentStatus
|
||||||
|
newValue, err = persistentStatusFromString(params[1])
|
||||||
|
// "opt-in" and "opt-out" don't make sense as user preferences
|
||||||
|
if err == nil && newValue != PersistentOptIn && newValue != PersistentOptOut {
|
||||||
|
munger = func(in AccountSettings) (out AccountSettings, err error) {
|
||||||
|
out = in
|
||||||
|
out.AlwaysOn = newValue
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "autoreplay-missed":
|
||||||
|
var newValue bool
|
||||||
|
newValue, err = utils.StringToBool(params[1])
|
||||||
|
if err == nil {
|
||||||
|
munger = func(in AccountSettings) (out AccountSettings, err error) {
|
||||||
|
out = in
|
||||||
|
out.AutoreplayMissed = newValue
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
case "auto-away":
|
case "auto-away":
|
||||||
var newValue PersistentStatus
|
var newValue PersistentStatus
|
||||||
newValue, err = persistentStatusFromString(params[1])
|
newValue, err = persistentStatusFromString(params[1])
|
||||||
|
|
Loading…
Reference in New Issue