From 05cb80507f4a2e04a4bb0875dc11b099879cf4f3 Mon Sep 17 00:00:00 2001 From: Shivaram Lingamneni Date: Sat, 11 Jan 2020 22:43:40 -0500 Subject: [PATCH] fix #741 --- irc/accounts.go | 13 +++++- irc/config.go | 7 ++++ irc/hostserv.go | 107 ++++++++++++++++++++++++++++++++++++++++++++++++ oragono.yaml | 4 ++ 4 files changed, 130 insertions(+), 1 deletion(-) diff --git a/irc/accounts.go b/irc/accounts.go index ce18984b..784d9dd3 100644 --- a/irc/accounts.go +++ b/irc/accounts.go @@ -1129,6 +1129,7 @@ func (am *AccountManager) ModifyAccountSettings(account string, munger settingsM type VHostInfo struct { ApprovedVHost string Enabled bool + Forbidden bool RequestedVHost string RejectedVHost string RejectionReason string @@ -1207,6 +1208,16 @@ func (am *AccountManager) VHostSetEnabled(client *Client, enabled bool) (result return am.performVHostChange(client.Account(), munger) } +func (am *AccountManager) VHostForbid(account string, forbid bool) (result VHostInfo, err error) { + munger := func(input VHostInfo) (output VHostInfo, err error) { + output = input + output.Forbidden = forbid + return + } + + return am.performVHostChange(account, munger) +} + func (am *AccountManager) performVHostChange(account string, munger vhostMunger) (result VHostInfo, err error) { account, err = CasefoldName(account) if err != nil || account == "" { @@ -1322,7 +1333,7 @@ func (am *AccountManager) applyVHostInfo(client *Client, info VHostInfo) { } vhost := "" - if info.Enabled { + if info.Enabled && !info.Forbidden { vhost = info.ApprovedVHost } oldNickmask := client.NickMaskString() diff --git a/irc/config.go b/irc/config.go index 93e31836..3feb27a5 100644 --- a/irc/config.go +++ b/irc/config.go @@ -117,6 +117,7 @@ type VHostConfig struct { Channel string Cooldown time.Duration } `yaml:"user-requests"` + OfferList []string `yaml:"offer-list"` } type NickEnforcementMethod int @@ -810,6 +811,12 @@ func LoadConfig(filename string) (config *Config, err error) { config.Accounts.VHosts.ValidRegexp = defaultValidVhostRegex } + for _, vhost := range config.Accounts.VHosts.OfferList { + if !config.Accounts.VHosts.ValidRegexp.MatchString(vhost) { + return nil, fmt.Errorf("invalid offered vhost: %s", vhost) + } + } + if !config.Accounts.LoginThrottling.Enabled { config.Accounts.LoginThrottling.MaxAttempts = 0 // limit of 0 means disabled } diff --git a/irc/hostserv.go b/irc/hostserv.go index 8b1242e8..89696583 100644 --- a/irc/hostserv.go +++ b/irc/hostserv.go @@ -121,6 +121,51 @@ for the rejection.`, maxParams: 2, unsplitFinalParam: true, }, + "forbid": { + handler: hsForbidHandler, + help: `Syntax: $bFORBID $b + +FORBID prevents a user from using any vhost, including ones on the offer list.`, + helpShort: `$bFORBID$b prevents a user from using vhosts.`, + capabs: []string{"vhosts"}, + enabled: hostservEnabled, + minParams: 1, + maxParams: 1, + }, + "permit": { + handler: hsForbidHandler, + help: `Syntax: $bPERMIT $b + +PERMIT undoes FORBID, allowing the user to TAKE vhosts again.`, + helpShort: `$bPERMIT$b allows a user to use vhosts again.`, + capabs: []string{"vhosts"}, + enabled: hostservEnabled, + minParams: 1, + maxParams: 1, + }, + "offerlist": { + handler: hsOfferListHandler, + help: `Syntax: $bOFFERLIST$b + +OFFERLIST lists vhosts that can be chosen without requiring operator approval; +to use one of the listed vhosts, take it with /HOSTSERV TAKE.`, + helpShort: `$bOFFERLIST$b lists vhosts that can be taken without operator approval.`, + enabled: hostservEnabled, + minParams: 0, + maxParams: 0, + }, + "take": { + handler: hsTakeHandler, + help: `Syntax: $bTAKE$b + +TAKE sets your vhost to one of the vhosts in the server's offer list; to see +the offered vhosts, use /HOSTSERV OFFERLIST.`, + helpShort: `$bTAKE$b sets your vhost to one of the options from the offer list.`, + enabled: hostservEnabled, + authRequired: true, + minParams: 1, + maxParams: 1, + }, } ) @@ -218,6 +263,11 @@ func hsStatusHandler(server *Server, client *Client, command string, params []st return } + if account.VHost.Forbidden { + hsNotice(rb, client.t("An administrator has denied you the ability to use vhosts")) + return + } + if account.VHost.ApprovedVHost != "" { hsNotice(rb, fmt.Sprintf(client.t("Account %[1]s has vhost: %[2]s"), accountName, account.VHost.ApprovedVHost)) if !account.VHost.Enabled { @@ -316,3 +366,60 @@ func hsRejectHandler(server *Server, client *Client, command string, params []st } } } + +func hsForbidHandler(server *Server, client *Client, command string, params []string, rb *ResponseBuffer) { + user := params[0] + forbidden := command == "forbid" + + _, err := server.accounts.VHostForbid(user, forbidden) + if err == errAccountDoesNotExist { + hsNotice(rb, client.t("No such account")) + } else if err != nil { + hsNotice(rb, client.t("An error occurred")) + } else { + if forbidden { + hsNotice(rb, fmt.Sprintf(client.t("Successfully forbidden vhosts to user %s"), user)) + } else { + hsNotice(rb, fmt.Sprintf(client.t("Successfully permitted vhosts for user %s"), user)) + } + } +} + +func hsOfferListHandler(server *Server, client *Client, command string, params []string, rb *ResponseBuffer) { + vhostConfig := server.Config().Accounts.VHosts + if len(vhostConfig.OfferList) == 0 { + if vhostConfig.UserRequests.Enabled { + hsNotice(rb, client.t("The server does not offer any vhosts (but you can request one with /HOSTSERV REQUEST)")) + } else { + hsNotice(rb, client.t("The server does not offer any vhosts)")) + } + } else { + hsNotice(rb, client.t("The following vhosts are available and can be chosen with /HOSTSERV TAKE:")) + for i, vhost := range vhostConfig.OfferList { + hsNotice(rb, fmt.Sprintf("%d. %s", i+1, vhost)) + } + } +} + +func hsTakeHandler(server *Server, client *Client, command string, params []string, rb *ResponseBuffer) { + vhost := params[0] + found := false + for _, offered := range server.Config().Accounts.VHosts.OfferList { + if offered == vhost { + found = true + } + } + if !found { + hsNotice(rb, client.t("That vhost isn't being offered by the server")) + return + } + + _, err := server.accounts.VHostSet(client.Account(), vhost) + if err != nil { + hsNotice(rb, client.t("An error occurred")) + } else if vhost != "" { + hsNotice(rb, client.t("Successfully set vhost")) + } else { + hsNotice(rb, client.t("Successfully cleared vhost")) + } +} diff --git a/oragono.yaml b/oragono.yaml index 70f24754..61137587 100644 --- a/oragono.yaml +++ b/oragono.yaml @@ -380,6 +380,10 @@ accounts: # before they can request a new one. cooldown: 168h + # vhosts that users can take without approval, using `/HS TAKE` + offer-list: + #- "oragono.test" + # channel options channels: # modes that are set when new channels are created