diff --git a/irc/chanserv.go b/irc/chanserv.go index 6fb748e5..9817ccc2 100644 --- a/irc/chanserv.go +++ b/irc/chanserv.go @@ -4,17 +4,15 @@ package irc import ( - "bytes" "fmt" - "hash/crc32" "sort" - "strconv" "strings" "time" "github.com/goshuirc/irc-go/ircfmt" "github.com/oragono/oragono/irc/modes" "github.com/oragono/oragono/irc/sno" + "github.com/oragono/oragono/irc/utils" ) const chanservHelp = `ChanServ lets you register and manage channels.` @@ -352,7 +350,7 @@ func csUnregisterHandler(server *Server, client *Client, command string, params } info := channel.ExportRegistration(0) - expectedCode := unregisterConfirmationCode(info.Name, info.RegisteredAt) + expectedCode := utils.ConfirmationCode(info.Name, info.RegisteredAt) if expectedCode != verificationCode { csNotice(rb, ircfmt.Unescape(client.t("$bWarning: unregistering this channel will remove all stored channel attributes.$b"))) csNotice(rb, fmt.Sprintf(client.t("To confirm channel unregistration, type: /CS UNREGISTER %[1]s %[2]s"), channelKey, expectedCode)) @@ -363,14 +361,6 @@ func csUnregisterHandler(server *Server, client *Client, command string, params csNotice(rb, fmt.Sprintf(client.t("Channel %s is now unregistered"), channelKey)) } -// deterministically generates a confirmation code for unregistering a channel / account -func unregisterConfirmationCode(name string, registeredAt time.Time) (code string) { - var codeInput bytes.Buffer - codeInput.WriteString(name) - codeInput.WriteString(strconv.FormatInt(registeredAt.Unix(), 16)) - return strconv.Itoa(int(crc32.ChecksumIEEE(codeInput.Bytes()))) -} - func csClearHandler(server *Server, client *Client, command string, params []string, rb *ResponseBuffer) { channel := server.channels.Get(params[0]) if channel == nil { @@ -426,7 +416,7 @@ func csTransferHandler(server *Server, client *Client, command string, params [] return } if targetAccount.NameCasefolded != account { - expectedCode := unregisterConfirmationCode(regInfo.Name, regInfo.RegisteredAt) + expectedCode := utils.ConfirmationCode(regInfo.Name, regInfo.RegisteredAt) codeValidated := 2 < len(params) && params[2] == expectedCode if !codeValidated { csNotice(rb, ircfmt.Unescape(client.t("$bWarning: you are about to transfer control of your channel to another user.$b"))) diff --git a/irc/handlers.go b/irc/handlers.go index f5999daa..b3799a23 100644 --- a/irc/handlers.go +++ b/irc/handlers.go @@ -804,6 +804,26 @@ func debugHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Res case "STOPCPUPROFILE": pprof.StopCPUProfile() rb.Notice(fmt.Sprintf("CPU profiling stopped")) + + case "CRASHSERVER": + if !client.HasRoleCapabs("oper:rehash") { + rb.Notice(client.t("You must have rehash permissions in order to execute DEBUG CRASHSERVER")) + return false + } + code := utils.ConfirmationCode(server.name, server.ctime) + if len(msg.Params) == 1 || msg.Params[1] != code { + rb.Notice(fmt.Sprintf(client.t("To crash the server, issue the following command: /DEBUG CRASHSERVER %s"), code)) + return false + } + server.logger.Error("server", fmt.Sprintf("DEBUG CRASHSERVER executed by operator %s", client.Oper().Name)) + go func() { + // intentional nil dereference on a new goroutine, bypassing recover-from-errors + var i, j *int + *i = *j + }() + + default: + rb.Notice(client.t("Unrecognized DEBUG subcommand")) } return false } diff --git a/irc/help.go b/irc/help.go index abcce6de..e3742f11 100644 --- a/irc/help.go +++ b/irc/help.go @@ -153,13 +153,14 @@ https://gist.github.com/DanielOaks/c104ad6e8759c01eb5c826d627caf80d`, oper: true, text: `DEBUG