new database schema
This commit is contained in:
parent
12e342cb61
commit
cacd32801e
|
@ -1,2 +0,0 @@
|
||||||
vendor/* linguist-vendored
|
|
||||||
languages/* linguist-vendored
|
|
|
@ -1,56 +0,0 @@
|
||||||
# .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"
|
|
48
Dockerfile
48
Dockerfile
|
@ -1,48 +0,0 @@
|
||||||
## 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,6 +4,7 @@ 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, "")
|
||||||
am.server.store.View(func(tx *buntdb.Tx) error {
|
err := am.server.store.View(func(tx *buntdb.Tx) error {
|
||||||
tx.AscendGreaterOrEqual("", unregisteredPrefix, func(key, value string) bool {
|
err = tx.AscendGreaterOrEqual("", unregisteredPrefix, func(key, value string) bool {
|
||||||
if !strings.HasPrefix(key, unregisteredPrefix) {
|
if !strings.HasPrefix(key, unregisteredPrefix) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -206,8 +206,11 @@ func (am *AccountManager) buildNickToAccountIndex(config *Config) {
|
||||||
skeletonToAccount[skeleton] = account
|
skeletonToAccount[skeleton] = account
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
return nil
|
return err
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
am.server.logger.Error("internal", "buildNickToAccountIndex buntdb transaction error during AscendGreaterOrEqual", err.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -403,7 +406,10 @@ func (am *AccountManager) Register(client *Client, account string, callbackNames
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
creds.AddCertfp(certfp)
|
err = 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
|
||||||
|
@ -471,7 +477,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",
|
||||||
|
@ -537,11 +543,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
|
||||||
am.server.store.View(func(tx *buntdb.Tx) error {
|
err = 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 nil
|
return err
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -651,12 +657,14 @@ 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 {
|
||||||
if val != "" {
|
var err error
|
||||||
tx.Set(key, val, nil)
|
switch val {
|
||||||
} else {
|
case "":
|
||||||
tx.Delete(key)
|
_, err = tx.Delete(key)
|
||||||
|
default:
|
||||||
|
_, _, err = tx.Set(key, val, nil)
|
||||||
}
|
}
|
||||||
return nil
|
return err
|
||||||
})
|
})
|
||||||
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())
|
||||||
|
@ -714,9 +722,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
|
||||||
am.server.store.View(func(tx *buntdb.Tx) error {
|
err = am.server.store.View(func(tx *buntdb.Tx) error {
|
||||||
credStr, err = tx.Get(credKey)
|
credStr, err = tx.Get(credKey)
|
||||||
return nil
|
return err
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -733,16 +741,18 @@ func (am *AccountManager) addRemoveCertfp(account, certfp string, add bool, hasP
|
||||||
return errCredsExternallyManaged
|
return errCredsExternallyManaged
|
||||||
}
|
}
|
||||||
|
|
||||||
if add {
|
switch add {
|
||||||
|
case true:
|
||||||
err = creds.AddCertfp(certfp)
|
err = creds.AddCertfp(certfp)
|
||||||
} else {
|
default:
|
||||||
err = creds.RemoveCertfp(certfp)
|
err = creds.RemoveCertfp(certfp)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if creds.Empty() && !hasPrivs {
|
if creds.Empty() {
|
||||||
return errEmptyCredentials
|
return errEmptyCredentials
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,7 @@ 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 = 22
|
latestDbSchema = 23
|
||||||
|
|
||||||
keyCloakSecret = "crypto.cloak_secret"
|
keyCloakSecret = "crypto.cloak_secret"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1113,6 +1112,56 @@ 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 {
|
||||||
|
@ -1228,4 +1277,9 @@ var allChanges = []SchemaChange{
|
||||||
TargetVersion: 22,
|
TargetVersion: 22,
|
||||||
Changer: schemaChangeV21To22,
|
Changer: schemaChangeV21To22,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
InitialVersion: 22,
|
||||||
|
TargetVersion: 23,
|
||||||
|
Changer: schemaChangeV22To23,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -421,15 +421,6 @@ 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)
|
||||||
|
@ -500,22 +491,6 @@ 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" {
|
||||||
|
@ -546,39 +521,6 @@ 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