mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-25 13:29:27 +01:00
accounts: Add very initial, extremely broken account work (not including config changes)
This commit is contained in:
parent
1746be2bb8
commit
e4b6c1852b
16
irc/accounts.go
Normal file
16
irc/accounts.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright (c) 2016- Daniel Oaks <daniel@danieloaks.net>
|
||||||
|
// released under the MIT license
|
||||||
|
|
||||||
|
package irc
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// Account represents a user account.
|
||||||
|
type Account struct {
|
||||||
|
// Name of the account.
|
||||||
|
Name string
|
||||||
|
// RegisteredAt represents the time that the account was registered.
|
||||||
|
RegisteredAt time.Time
|
||||||
|
// Clients that are currently logged into this account (useful for notifications).
|
||||||
|
Clients []Client
|
||||||
|
}
|
@ -152,6 +152,10 @@ var Commands = map[string]Command{
|
|||||||
usablePreReg: true,
|
usablePreReg: true,
|
||||||
minParams: 0,
|
minParams: 0,
|
||||||
},
|
},
|
||||||
|
"REG": {
|
||||||
|
handler: regHandler,
|
||||||
|
minParams: 3,
|
||||||
|
},
|
||||||
/*TODO(dan): Add this back in
|
/*TODO(dan): Add this back in
|
||||||
"THEATRE": Command{
|
"THEATRE": Command{
|
||||||
handler: theatreHandler,
|
handler: theatreHandler,
|
||||||
|
@ -44,16 +44,32 @@ func (conf *PassConfig) PasswordBytes() []byte {
|
|||||||
return bytes
|
return bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AccountRegistrationConfig struct {
|
||||||
|
Enabled bool
|
||||||
|
EnabledCallbacks []string `yaml:"enabled-callbacks"`
|
||||||
|
Callbacks struct {
|
||||||
|
Mailto struct {
|
||||||
|
Server string
|
||||||
|
Port int
|
||||||
|
TLS struct {
|
||||||
|
Enabled bool
|
||||||
|
InsecureSkipVerify bool `yaml:"insecure_skip_verify"`
|
||||||
|
ServerName string `yaml:"servername"`
|
||||||
|
}
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
Sender string
|
||||||
|
VerifyMessageSubject string `yaml:"verify-message-subject"`
|
||||||
|
VerifyMessage string `yaml:"verify-message"`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Network struct {
|
Network struct {
|
||||||
Name string
|
Name string
|
||||||
}
|
}
|
||||||
|
|
||||||
Datastore struct {
|
|
||||||
Path string
|
|
||||||
SQLitePath string `yaml:"sqlite-path"`
|
|
||||||
}
|
|
||||||
|
|
||||||
Server struct {
|
Server struct {
|
||||||
PassConfig
|
PassConfig
|
||||||
Password string
|
Password string
|
||||||
@ -67,6 +83,15 @@ type Config struct {
|
|||||||
ProxyAllowedFrom []string `yaml:"proxy-allowed-from"`
|
ProxyAllowedFrom []string `yaml:"proxy-allowed-from"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Datastore struct {
|
||||||
|
Path string
|
||||||
|
SQLitePath string `yaml:"sqlite-path"`
|
||||||
|
}
|
||||||
|
|
||||||
|
Registration struct {
|
||||||
|
Accounts AccountRegistrationConfig
|
||||||
|
}
|
||||||
|
|
||||||
Operator map[string]*PassConfig
|
Operator map[string]*PassConfig
|
||||||
|
|
||||||
Theater map[string]*PassConfig
|
Theater map[string]*PassConfig
|
||||||
|
@ -117,6 +117,7 @@ const (
|
|||||||
ERR_NICKNAMEINUSE = "433"
|
ERR_NICKNAMEINUSE = "433"
|
||||||
ERR_NICKCOLLISION = "436"
|
ERR_NICKCOLLISION = "436"
|
||||||
ERR_UNAVAILRESOURCE = "437"
|
ERR_UNAVAILRESOURCE = "437"
|
||||||
|
ERR_REG_UNAVAILABLE = "440"
|
||||||
ERR_USERNOTINCHANNEL = "441"
|
ERR_USERNOTINCHANNEL = "441"
|
||||||
ERR_NOTONCHANNEL = "442"
|
ERR_NOTONCHANNEL = "442"
|
||||||
ERR_USERONCHANNEL = "443"
|
ERR_USERONCHANNEL = "443"
|
||||||
@ -147,4 +148,13 @@ const (
|
|||||||
ERR_NOOPERHOST = "491"
|
ERR_NOOPERHOST = "491"
|
||||||
ERR_UMODEUNKNOWNFLAG = "501"
|
ERR_UMODEUNKNOWNFLAG = "501"
|
||||||
ERR_USERSDONTMATCH = "502"
|
ERR_USERSDONTMATCH = "502"
|
||||||
|
RPL_REGISTRATION_SUCCESS = "920"
|
||||||
|
ERR_ACCOUNT_ALREADY_EXISTS = "921"
|
||||||
|
ERR_REG_UNSPECIFIED_ERROR = "922"
|
||||||
|
RPL_VERIFYSUCCESS = "923"
|
||||||
|
ERR_ACCOUNT_ALREADY_VERIFIED = "924"
|
||||||
|
ERR_ACCOUNT_INVALID_VERIFY_CODE = "925"
|
||||||
|
RPL_REG_VERIFICATION_REQUIRED = "927"
|
||||||
|
ERR_REG_INVALID_CALLBACK = "929"
|
||||||
|
ERR_REG_INVALID_CRED_TYPE = "982"
|
||||||
)
|
)
|
||||||
|
84
irc/registration.go
Normal file
84
irc/registration.go
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
// Copyright (c) 2016- Daniel Oaks <daniel@danieloaks.net>
|
||||||
|
// released under the MIT license
|
||||||
|
|
||||||
|
package irc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/DanielOaks/girc-go/ircmsg"
|
||||||
|
"github.com/tidwall/buntdb"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errAccountCreation = errors.New("Account could not be created")
|
||||||
|
)
|
||||||
|
|
||||||
|
// AccountRegistration manages the registration of accounts.
|
||||||
|
type AccountRegistration struct {
|
||||||
|
Enabled bool
|
||||||
|
EnabledRegistrationCallbackTypes []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAccountRegistration returns a new AccountRegistration, configured correctly.
|
||||||
|
func NewAccountRegistration(config AccountRegistrationConfig) (accountReg AccountRegistration) {
|
||||||
|
if config.Enabled {
|
||||||
|
accountReg.Enabled = true
|
||||||
|
accountReg.EnabledRegistrationCallbackTypes = config.EnabledCallbacks
|
||||||
|
}
|
||||||
|
return accountReg
|
||||||
|
}
|
||||||
|
|
||||||
|
// regHandler parses the REG command.
|
||||||
|
func regHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
||||||
|
subcommand := strings.ToLower(msg.Params[0])
|
||||||
|
|
||||||
|
if subcommand == "create" {
|
||||||
|
client.Notice("Parsing CREATE")
|
||||||
|
|
||||||
|
// get and sanitise account name
|
||||||
|
account := NewName(msg.Params[1])
|
||||||
|
if !account.IsNickname() || msg.Params[1] == "*" {
|
||||||
|
client.Send(nil, server.nameString, ERR_REG_UNSPECIFIED_ERROR, client.nickString, msg.Params[1], "Account name is not valid")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
accountString := account.String()
|
||||||
|
|
||||||
|
// check whether account exists
|
||||||
|
// do it all in one write tx to prevent races
|
||||||
|
err := server.store.Update(func(tx *buntdb.Tx) error {
|
||||||
|
accountKey := fmt.Sprintf("account %s exists", accountString)
|
||||||
|
|
||||||
|
_, err := tx.Get(accountKey)
|
||||||
|
if err != buntdb.ErrNotFound {
|
||||||
|
//TODO(dan): if account verified key doesn't exist account is not verified, calc the maximum time without verification and expire and continue if need be
|
||||||
|
client.Send(nil, server.nameString, ERR_ACCOUNT_ALREADY_EXISTS, client.nickString, msg.Params[1], "Account already exists")
|
||||||
|
return errAccountCreation
|
||||||
|
}
|
||||||
|
|
||||||
|
registeredTimeKey := fmt.Sprintf("account %s registered.time", accountString)
|
||||||
|
|
||||||
|
tx.Set(accountKey, "1", nil)
|
||||||
|
tx.Set(registeredTimeKey, strconv.FormatInt(time.Now().Unix(), 10), nil)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
// account could not be created and relevant numerics have been dispatched, abort
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// account didn't already exist, continue with account creation and dispatching verification (if required)
|
||||||
|
|
||||||
|
} else if subcommand == "verify" {
|
||||||
|
client.Notice("Parsing VERIFY")
|
||||||
|
} else {
|
||||||
|
client.Send(nil, server.nameString, ERR_UNKNOWNERROR, client.nickString, "REG", msg.Params[0], "Unknown subcommand")
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
@ -26,6 +26,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
|
accounts map[string]Account
|
||||||
channels ChannelNameMap
|
channels ChannelNameMap
|
||||||
clients *ClientLookupSet
|
clients *ClientLookupSet
|
||||||
commands chan Command
|
commands chan Command
|
||||||
@ -39,6 +40,7 @@ type Server struct {
|
|||||||
newConns chan clientConn
|
newConns chan clientConn
|
||||||
operators map[Name][]byte
|
operators map[Name][]byte
|
||||||
password []byte
|
password []byte
|
||||||
|
accountRegistration *AccountRegistration
|
||||||
signals chan os.Signal
|
signals chan os.Signal
|
||||||
proxyAllowedFrom []string
|
proxyAllowedFrom []string
|
||||||
whoWas *WhoWasList
|
whoWas *WhoWasList
|
||||||
@ -63,6 +65,7 @@ type clientConn struct {
|
|||||||
|
|
||||||
func NewServer(config *Config) *Server {
|
func NewServer(config *Config) *Server {
|
||||||
server := &Server{
|
server := &Server{
|
||||||
|
accounts: make(map[string]Account),
|
||||||
channels: make(ChannelNameMap),
|
channels: make(ChannelNameMap),
|
||||||
clients: NewClientLookupSet(),
|
clients: NewClientLookupSet(),
|
||||||
commands: make(chan Command),
|
commands: make(chan Command),
|
||||||
@ -127,6 +130,10 @@ func NewServer(config *Config) *Server {
|
|||||||
server.wslisten(config.Server.Wslisten, config.Server.TLSListeners)
|
server.wslisten(config.Server.Wslisten, config.Server.TLSListeners)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// registration
|
||||||
|
accountReg := NewAccountRegistration(config.Registration.Accounts)
|
||||||
|
server.accountRegistration = &accountReg
|
||||||
|
|
||||||
// Attempt to clean up when receiving these signals.
|
// Attempt to clean up when receiving these signals.
|
||||||
signal.Notify(server.signals, SERVER_SIGNALS...)
|
signal.Notify(server.signals, SERVER_SIGNALS...)
|
||||||
|
|
||||||
@ -144,9 +151,25 @@ func NewServer(config *Config) *Server {
|
|||||||
server.isupport.Add("NETWORK", config.Network.Name)
|
server.isupport.Add("NETWORK", config.Network.Name)
|
||||||
server.isupport.Add("NICKLEN", strconv.Itoa(config.Limits.NickLen))
|
server.isupport.Add("NICKLEN", strconv.Itoa(config.Limits.NickLen))
|
||||||
server.isupport.Add("PREFIX", "(qaohv)~&@%+")
|
server.isupport.Add("PREFIX", "(qaohv)~&@%+")
|
||||||
// server.isupport.Add("STATUSMSG", "@+") //TODO(dan): Autogenerate based on PREFIXes, support STATUSMSG
|
// server.isupport.Add("STATUSMSG", "@+") //TODO(dan): Support STATUSMSG
|
||||||
// server.isupport.Add("TARGMAX", "") //TODO(dan): Support this
|
// server.isupport.Add("TARGMAX", "") //TODO(dan): Support this
|
||||||
// server.isupport.Add("TOPICLEN", "") //TODO(dan): Support topic length
|
// server.isupport.Add("TOPICLEN", "") //TODO(dan): Support topic length
|
||||||
|
|
||||||
|
// account registration
|
||||||
|
if server.accountRegistration.Enabled {
|
||||||
|
// 'none' isn't shown in the REGCALLBACKS vars
|
||||||
|
var enabledCallbackTypes []string
|
||||||
|
for _, name := range server.accountRegistration.EnabledRegistrationCallbackTypes {
|
||||||
|
if name != "none" {
|
||||||
|
enabledCallbackTypes = append(enabledCallbackTypes, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server.isupport.Add("REGCOMMANDS", "CREATE,VERIFY")
|
||||||
|
server.isupport.Add("REGCALLBACKS", strings.Join(enabledCallbackTypes, ","))
|
||||||
|
server.isupport.Add("REGCREDTYPES", "passphrase,certfp")
|
||||||
|
}
|
||||||
|
|
||||||
server.isupport.RegenerateCachedReply()
|
server.isupport.RegenerateCachedReply()
|
||||||
|
|
||||||
return server
|
return server
|
||||||
|
22
oragono.yaml
22
oragono.yaml
@ -5,17 +5,6 @@ network:
|
|||||||
# name of the network
|
# name of the network
|
||||||
name: OragonoTest
|
name: OragonoTest
|
||||||
|
|
||||||
# datastore configuration
|
|
||||||
datastore:
|
|
||||||
# path to the datastore
|
|
||||||
# this can also be ":memory:" for an in-memory-only db
|
|
||||||
path: ircd.db
|
|
||||||
|
|
||||||
# path to our sqlite db
|
|
||||||
# currently used to lookup masks and store persistent chan data
|
|
||||||
# but planned to be deprecated in a future release
|
|
||||||
sqlite-path: ircd-sqlite.db
|
|
||||||
|
|
||||||
# server configuration
|
# server configuration
|
||||||
server:
|
server:
|
||||||
# server name
|
# server name
|
||||||
@ -65,6 +54,17 @@ operator:
|
|||||||
# generated using "oragono genpasswd"
|
# generated using "oragono genpasswd"
|
||||||
password: JDJhJDA0JE1vZmwxZC9YTXBhZ3RWT2xBbkNwZnV3R2N6VFUwQUI0RUJRVXRBRHliZVVoa0VYMnlIaGsu
|
password: JDJhJDA0JE1vZmwxZC9YTXBhZ3RWT2xBbkNwZnV3R2N6VFUwQUI0RUJRVXRBRHliZVVoa0VYMnlIaGsu
|
||||||
|
|
||||||
|
# datastore configuration
|
||||||
|
datastore:
|
||||||
|
# path to the datastore
|
||||||
|
# this can also be ":memory:" for an in-memory-only db
|
||||||
|
path: ircd.db
|
||||||
|
|
||||||
|
# path to our sqlite db
|
||||||
|
# currently used to lookup masks and store persistent chan data
|
||||||
|
# but planned to be deprecated in a future release
|
||||||
|
sqlite-path: ircd-sqlite.db
|
||||||
|
|
||||||
# limits - these need to be the same across the network
|
# limits - these need to be the same across the network
|
||||||
limits:
|
limits:
|
||||||
# nicklen is the max nick length allowed
|
# nicklen is the max nick length allowed
|
||||||
|
Loading…
Reference in New Issue
Block a user