mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-14 07:59:31 +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,
|
||||
minParams: 0,
|
||||
},
|
||||
"REG": {
|
||||
handler: regHandler,
|
||||
minParams: 3,
|
||||
},
|
||||
/*TODO(dan): Add this back in
|
||||
"THEATRE": Command{
|
||||
handler: theatreHandler,
|
||||
|
@ -44,16 +44,32 @@ func (conf *PassConfig) PasswordBytes() []byte {
|
||||
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 {
|
||||
Network struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
Datastore struct {
|
||||
Path string
|
||||
SQLitePath string `yaml:"sqlite-path"`
|
||||
}
|
||||
|
||||
Server struct {
|
||||
PassConfig
|
||||
Password string
|
||||
@ -67,6 +83,15 @@ type Config struct {
|
||||
ProxyAllowedFrom []string `yaml:"proxy-allowed-from"`
|
||||
}
|
||||
|
||||
Datastore struct {
|
||||
Path string
|
||||
SQLitePath string `yaml:"sqlite-path"`
|
||||
}
|
||||
|
||||
Registration struct {
|
||||
Accounts AccountRegistrationConfig
|
||||
}
|
||||
|
||||
Operator map[string]*PassConfig
|
||||
|
||||
Theater map[string]*PassConfig
|
||||
|
@ -117,6 +117,7 @@ const (
|
||||
ERR_NICKNAMEINUSE = "433"
|
||||
ERR_NICKCOLLISION = "436"
|
||||
ERR_UNAVAILRESOURCE = "437"
|
||||
ERR_REG_UNAVAILABLE = "440"
|
||||
ERR_USERNOTINCHANNEL = "441"
|
||||
ERR_NOTONCHANNEL = "442"
|
||||
ERR_USERONCHANNEL = "443"
|
||||
@ -147,4 +148,13 @@ const (
|
||||
ERR_NOOPERHOST = "491"
|
||||
ERR_UMODEUNKNOWNFLAG = "501"
|
||||
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 {
|
||||
accounts map[string]Account
|
||||
channels ChannelNameMap
|
||||
clients *ClientLookupSet
|
||||
commands chan Command
|
||||
@ -39,6 +40,7 @@ type Server struct {
|
||||
newConns chan clientConn
|
||||
operators map[Name][]byte
|
||||
password []byte
|
||||
accountRegistration *AccountRegistration
|
||||
signals chan os.Signal
|
||||
proxyAllowedFrom []string
|
||||
whoWas *WhoWasList
|
||||
@ -63,6 +65,7 @@ type clientConn struct {
|
||||
|
||||
func NewServer(config *Config) *Server {
|
||||
server := &Server{
|
||||
accounts: make(map[string]Account),
|
||||
channels: make(ChannelNameMap),
|
||||
clients: NewClientLookupSet(),
|
||||
commands: make(chan Command),
|
||||
@ -127,6 +130,10 @@ func NewServer(config *Config) *Server {
|
||||
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.
|
||||
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("NICKLEN", strconv.Itoa(config.Limits.NickLen))
|
||||
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("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()
|
||||
|
||||
return server
|
||||
|
22
oragono.yaml
22
oragono.yaml
@ -5,17 +5,6 @@ network:
|
||||
# name of the network
|
||||
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:
|
||||
# server name
|
||||
@ -65,6 +54,17 @@ operator:
|
||||
# generated using "oragono genpasswd"
|
||||
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:
|
||||
# nicklen is the max nick length allowed
|
||||
|
Loading…
Reference in New Issue
Block a user