3
0
mirror of https://github.com/ergochat/ergo.git synced 2024-11-29 07:29:31 +01:00

impose throttle checks on HS TAKE

This commit is contained in:
Shivaram Lingamneni 2020-01-28 22:27:56 -05:00
parent dedf78d0e9
commit 955cdbdfef
2 changed files with 53 additions and 23 deletions

View File

@ -1142,12 +1142,40 @@ type PendingVHostRequest struct {
Account string Account string
} }
type vhostThrottleExceeded struct {
timeRemaining time.Duration
}
func (vhe *vhostThrottleExceeded) Error() string {
return fmt.Sprintf("Wait at least %v and try again", vhe.timeRemaining)
}
func (vh *VHostInfo) checkThrottle(cooldown time.Duration) (err error) {
if cooldown == 0 {
return nil
}
now := time.Now().UTC()
elapsed := now.Sub(vh.LastRequestTime)
if elapsed > cooldown {
// success
vh.LastRequestTime = now
return nil
} else {
return &vhostThrottleExceeded{timeRemaining: cooldown - elapsed}
}
}
// callback type implementing the actual business logic of vhost operations // callback type implementing the actual business logic of vhost operations
type vhostMunger func(input VHostInfo) (output VHostInfo, err error) type vhostMunger func(input VHostInfo) (output VHostInfo, err error)
func (am *AccountManager) VHostSet(account string, vhost string) (result VHostInfo, err error) { func (am *AccountManager) VHostSet(account string, vhost string, cooldown time.Duration) (result VHostInfo, err error) {
munger := func(input VHostInfo) (output VHostInfo, err error) { munger := func(input VHostInfo) (output VHostInfo, err error) {
output = input output = input
err = output.checkThrottle(cooldown)
if err != nil {
return
}
output.Enabled = true output.Enabled = true
output.ApprovedVHost = vhost output.ApprovedVHost = vhost
return return
@ -1156,9 +1184,17 @@ func (am *AccountManager) VHostSet(account string, vhost string) (result VHostIn
return am.performVHostChange(account, munger) return am.performVHostChange(account, munger)
} }
func (am *AccountManager) VHostRequest(account string, vhost string) (result VHostInfo, err error) { func (am *AccountManager) VHostRequest(account string, vhost string, cooldown time.Duration) (result VHostInfo, err error) {
munger := func(input VHostInfo) (output VHostInfo, err error) { munger := func(input VHostInfo) (output VHostInfo, err error) {
output = input output = input
// you can update your existing request, but if you were approved or rejected,
// you can't spam a new request
if output.RequestedVHost == "" {
err = output.checkThrottle(cooldown)
}
if err != nil {
return
}
output.RequestedVHost = vhost output.RequestedVHost = vhost
output.RejectedVHost = "" output.RejectedVHost = ""
output.RejectionReason = "" output.RejectionReason = ""

View File

@ -7,7 +7,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"regexp" "regexp"
"time"
) )
const hostservHelp = `HostServ lets you manage your vhost (i.e., the string displayed const hostservHelp = `HostServ lets you manage your vhost (i.e., the string displayed
@ -213,23 +212,13 @@ func hsRequestHandler(server *Server, client *Client, command string, params []s
} }
accountName := client.Account() accountName := client.Account()
account, err := server.accounts.LoadAccount(client.Account()) _, err := server.accounts.VHostRequest(accountName, vhost, server.Config().Accounts.VHosts.UserRequests.Cooldown)
if err != nil { if err != nil {
hsNotice(rb, client.t("An error occurred")) if throttled, ok := err.(*vhostThrottleExceeded); ok {
return hsNotice(rb, fmt.Sprintf(client.t("You must wait an additional %v before making another request"), throttled.timeRemaining))
} } else {
elapsed := time.Since(account.VHost.LastRequestTime) hsNotice(rb, client.t("An error occurred"))
remainingTime := server.AccountConfig().VHosts.UserRequests.Cooldown - elapsed }
// you can update your existing request, but if you were rejected,
// you can't spam a replacement request
if account.VHost.RequestedVHost == "" && remainingTime > 0 {
hsNotice(rb, fmt.Sprintf(client.t("You must wait an additional %v before making another request"), remainingTime))
return
}
_, err = server.accounts.VHostRequest(accountName, vhost)
if err != nil {
hsNotice(rb, client.t("An error occurred"))
} else { } else {
hsNotice(rb, client.t("Your vhost request will be reviewed by an administrator")) hsNotice(rb, client.t("Your vhost request will be reviewed by an administrator"))
chanMsg := fmt.Sprintf("Account %s requests vhost %s", accountName, vhost) chanMsg := fmt.Sprintf("Account %s requests vhost %s", accountName, vhost)
@ -309,7 +298,7 @@ func hsSetHandler(server *Server, client *Client, command string, params []strin
} }
// else: command == "del", vhost == "" // else: command == "del", vhost == ""
_, err := server.accounts.VHostSet(user, vhost) _, err := server.accounts.VHostSet(user, vhost, 0)
if err != nil { if err != nil {
hsNotice(rb, client.t("An error occurred")) hsNotice(rb, client.t("An error occurred"))
} else if vhost != "" { } else if vhost != "" {
@ -402,9 +391,10 @@ func hsOfferListHandler(server *Server, client *Client, command string, params [
} }
func hsTakeHandler(server *Server, client *Client, command string, params []string, rb *ResponseBuffer) { func hsTakeHandler(server *Server, client *Client, command string, params []string, rb *ResponseBuffer) {
config := server.Config()
vhost := params[0] vhost := params[0]
found := false found := false
for _, offered := range server.Config().Accounts.VHosts.OfferList { for _, offered := range config.Accounts.VHosts.OfferList {
if offered == vhost { if offered == vhost {
found = true found = true
} }
@ -414,9 +404,13 @@ func hsTakeHandler(server *Server, client *Client, command string, params []stri
return return
} }
_, err := server.accounts.VHostSet(client.Account(), vhost) _, err := server.accounts.VHostSet(client.Account(), vhost, config.Accounts.VHosts.UserRequests.Cooldown)
if err != nil { if err != nil {
hsNotice(rb, client.t("An error occurred")) if throttled, ok := err.(*vhostThrottleExceeded); ok {
hsNotice(rb, fmt.Sprintf(client.t("You must wait an additional %v before taking a vhost"), throttled.timeRemaining))
} else {
hsNotice(rb, client.t("An error occurred"))
}
} else if vhost != "" { } else if vhost != "" {
hsNotice(rb, client.t("Successfully set vhost")) hsNotice(rb, client.t("Successfully set vhost"))
} else { } else {