ergo/irc/hostserv.go

195 lines
5.8 KiB
Go
Raw Normal View History

2018-04-23 08:38:35 +02:00
// Copyright (c) 2018 Shivaram Lingamneni <slingamn@cs.stanford.edu>
2018-04-19 08:48:19 +02:00
// released under the MIT license
package irc
import (
"errors"
"fmt"
"regexp"
2020-02-02 08:03:08 +01:00
2020-05-08 07:16:49 +02:00
"github.com/goshuirc/irc-go/ircfmt"
"github.com/oragono/oragono/irc/utils"
2018-04-19 08:48:19 +02:00
)
2020-03-18 11:01:19 +01:00
const (
hostservHelp = `HostServ lets you manage your vhost (i.e., the string displayed
in place of your client's hostname/IP).`
2020-03-18 11:01:19 +01:00
)
2018-04-19 08:48:19 +02:00
var (
errVHostBadCharacters = errors.New("Vhost contains prohibited characters")
errVHostTooLong = errors.New("Vhost is too long")
// ascii only for now
2018-04-23 08:38:35 +02:00
defaultValidVhostRegex = regexp.MustCompile(`^[0-9A-Za-z.\-_/]+$`)
2018-04-19 08:48:19 +02:00
)
2019-01-04 04:32:07 +01:00
func hostservEnabled(config *Config) bool {
return config.Accounts.VHosts.Enabled
2018-04-19 08:48:19 +02:00
}
var (
hostservCommands = map[string]*serviceCommand{
"on": {
handler: hsOnOffHandler,
help: `Syntax: $bON$b
ON enables your vhost, if you have one approved.`,
helpShort: `$bON$b enables your vhost, if you have one approved.`,
authRequired: true,
enabled: hostservEnabled,
},
"off": {
handler: hsOnOffHandler,
help: `Syntax: $bOFF$b
OFF disables your vhost, if you have one approved.`,
helpShort: `$bOFF$b disables your vhost, if you have one approved.`,
authRequired: true,
enabled: hostservEnabled,
},
"status": {
handler: hsStatusHandler,
2019-01-04 04:32:07 +01:00
help: `Syntax: $bSTATUS [user]$b
2018-04-19 08:48:19 +02:00
STATUS displays your current vhost, if any, and the status of your most recent
2019-01-04 04:32:07 +01:00
request for a new one. A server operator can view someone else's status.`,
helpShort: `$bSTATUS$b shows your vhost and request status.`,
enabled: hostservEnabled,
2018-04-19 08:48:19 +02:00
},
"set": {
handler: hsSetHandler,
help: `Syntax: $bSET <user> <vhost>$b
SET sets a user's vhost, bypassing the request system.`,
helpShort: `$bSET$b sets a user's vhost.`,
2018-04-23 08:38:35 +02:00
capabs: []string{"vhosts"},
2018-04-19 08:48:19 +02:00
enabled: hostservEnabled,
2019-01-04 04:32:07 +01:00
minParams: 2,
2018-04-19 08:48:19 +02:00
},
"del": {
handler: hsSetHandler,
help: `Syntax: $bDEL <user>$b
2018-12-28 17:07:08 +01:00
DEL deletes a user's vhost.`,
2018-04-19 08:48:19 +02:00
helpShort: `$bDEL$b deletes a user's vhost.`,
2018-04-23 08:38:35 +02:00
capabs: []string{"vhosts"},
2018-04-19 08:48:19 +02:00
enabled: hostservEnabled,
2019-01-04 04:32:07 +01:00
minParams: 1,
2018-04-19 08:48:19 +02:00
},
2020-05-08 07:16:49 +02:00
"setcloaksecret": {
handler: hsSetCloakSecretHandler,
help: `Syntax: $bSETCLOAKSECRET$b <secret> [code]
SETCLOAKSECRET can be used to set or rotate the cloak secret. You should use
a cryptographically strong secret. To prevent accidental modification, a
verification code is required; invoking the command without a code will
display the necessary code.`,
helpShort: `$bSETCLOAKSECRET$b modifies the IP cloaking secret.`,
capabs: []string{"vhosts", "rehash"},
minParams: 1,
maxParams: 2,
},
2018-04-19 08:48:19 +02:00
}
)
func hsOnOffHandler(service *ircService, server *Server, client *Client, command string, params []string, rb *ResponseBuffer) {
2018-04-19 08:48:19 +02:00
enable := false
if command == "on" {
enable = true
}
2018-04-23 08:38:35 +02:00
_, err := server.accounts.VHostSetEnabled(client, enable)
2019-05-22 05:55:04 +02:00
if err == errNoVhost {
service.Notice(rb, client.t(err.Error()))
2019-05-22 05:55:04 +02:00
} else if err != nil {
service.Notice(rb, client.t("An error occurred"))
2018-04-19 08:48:19 +02:00
} else if enable {
service.Notice(rb, client.t("Successfully enabled your vhost"))
2018-04-19 08:48:19 +02:00
} else {
service.Notice(rb, client.t("Successfully disabled your vhost"))
2018-04-19 08:48:19 +02:00
}
}
func hsStatusHandler(service *ircService, server *Server, client *Client, command string, params []string, rb *ResponseBuffer) {
2019-01-04 04:32:07 +01:00
var accountName string
if len(params) > 0 {
if !client.HasRoleCapabs("vhosts") {
service.Notice(rb, client.t("Command restricted"))
2019-01-04 04:32:07 +01:00
return
}
accountName = params[0]
} else {
accountName = client.Account()
2019-02-14 19:10:35 +01:00
if accountName == "" {
service.Notice(rb, client.t("You're not logged into an account"))
2019-02-14 19:10:35 +01:00
return
}
2019-01-04 04:32:07 +01:00
}
2018-04-19 08:48:19 +02:00
account, err := server.accounts.LoadAccount(accountName)
if err != nil {
2019-01-04 04:32:07 +01:00
if err != errAccountDoesNotExist {
server.logger.Warning("internal", "error loading account info", accountName, err.Error())
}
service.Notice(rb, client.t("No such account"))
2018-04-19 08:48:19 +02:00
return
}
if account.VHost.ApprovedVHost != "" {
service.Notice(rb, fmt.Sprintf(client.t("Account %[1]s has vhost: %[2]s"), accountName, account.VHost.ApprovedVHost))
2018-04-19 08:48:19 +02:00
if !account.VHost.Enabled {
service.Notice(rb, client.t("This vhost is currently disabled, but can be enabled with /HS ON"))
2018-04-19 08:48:19 +02:00
}
} else {
service.Notice(rb, fmt.Sprintf(client.t("Account %s has no vhost"), accountName))
2018-04-19 08:48:19 +02:00
}
}
func validateVhost(server *Server, vhost string, oper bool) error {
2020-03-16 12:54:50 +01:00
config := server.Config()
if len(vhost) > config.Accounts.VHosts.MaxLength {
2018-04-19 08:48:19 +02:00
return errVHostTooLong
}
2020-10-22 18:19:19 +02:00
if !config.Accounts.VHosts.validRegexp.MatchString(vhost) {
2018-04-19 08:48:19 +02:00
return errVHostBadCharacters
}
return nil
}
func hsSetHandler(service *ircService, server *Server, client *Client, command string, params []string, rb *ResponseBuffer) {
2019-01-04 04:32:07 +01:00
user := params[0]
var vhost string
2018-04-19 08:48:19 +02:00
if command == "set" {
2019-01-04 04:32:07 +01:00
vhost = params[1]
2018-04-19 08:48:19 +02:00
if validateVhost(server, vhost, true) != nil {
service.Notice(rb, client.t("Invalid vhost"))
2018-04-19 08:48:19 +02:00
return
}
}
2019-01-04 04:32:07 +01:00
// else: command == "del", vhost == ""
2018-04-19 08:48:19 +02:00
2020-02-02 04:19:33 +01:00
_, err := server.accounts.VHostSet(user, vhost)
2018-04-19 08:48:19 +02:00
if err != nil {
service.Notice(rb, client.t("An error occurred"))
2018-04-19 08:48:19 +02:00
} else if vhost != "" {
service.Notice(rb, client.t("Successfully set vhost"))
2018-04-19 08:48:19 +02:00
} else {
service.Notice(rb, client.t("Successfully cleared vhost"))
2018-04-19 08:48:19 +02:00
}
}
func hsSetCloakSecretHandler(service *ircService, server *Server, client *Client, command string, params []string, rb *ResponseBuffer) {
2020-05-08 07:16:49 +02:00
secret := params[0]
expectedCode := utils.ConfirmationCode(secret, server.ctime)
if len(params) == 1 || params[1] != expectedCode {
service.Notice(rb, ircfmt.Unescape(client.t("$bWarning: changing the cloak secret will invalidate stored ban/invite/exception lists.$b")))
service.Notice(rb, fmt.Sprintf(client.t("To confirm, run this command: %s"), fmt.Sprintf("/HS SETCLOAKSECRET %s %s", secret, expectedCode)))
2020-05-08 07:16:49 +02:00
return
}
StoreCloakSecret(server.store, secret)
service.Notice(rb, client.t("Rotated the cloak secret; you must rehash or restart the server for it to take effect"))
2020-05-08 07:16:49 +02:00
}