mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-25 13:29:27 +01:00
commit
c445b45f31
@ -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")))
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -153,13 +153,14 @@ https://gist.github.com/DanielOaks/c104ad6e8759c01eb5c826d627caf80d`,
|
||||
oper: true,
|
||||
text: `DEBUG <option>
|
||||
|
||||
Prints debug information about the IRCd. <option> can be one of:
|
||||
Provides various debugging commands for the IRCd. <option> can be one of:
|
||||
|
||||
* GCSTATS: Garbage control statistics.
|
||||
* NUMGOROUTINE: Number of goroutines in use.
|
||||
* STARTCPUPROFILE: Starts the CPU profiler.
|
||||
* STOPCPUPROFILE: Stops the CPU profiler.
|
||||
* PROFILEHEAP: Writes out the CPU profiler info.`,
|
||||
* PROFILEHEAP: Writes a memory profile.
|
||||
* CRASHSERVER: Crashes the server (for use in failover testing)`,
|
||||
},
|
||||
"deoper": {
|
||||
oper: true,
|
||||
|
@ -732,7 +732,7 @@ func nsUnregisterHandler(server *Server, client *Client, command string, params
|
||||
return
|
||||
}
|
||||
|
||||
expectedCode := unregisterConfirmationCode(account.Name, account.RegisteredAt)
|
||||
expectedCode := utils.ConfirmationCode(account.Name, account.RegisteredAt)
|
||||
if expectedCode != verificationCode {
|
||||
nsNotice(rb, ircfmt.Unescape(client.t("$bWarning: unregistering this account will remove its stored privileges.$b")))
|
||||
nsNotice(rb, fmt.Sprintf(client.t("To confirm account unregistration, type: /NS UNREGISTER %[1]s %[2]s"), cfname, expectedCode))
|
||||
|
22
irc/utils/confirmation.go
Normal file
22
irc/utils/confirmation.go
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2020 Shivaram Lingamneni <slingamn@cs.stanford.edu>
|
||||
// released under the MIT license
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Deterministically generates a confirmation code for some destructive activity;
|
||||
// `name` is typically the name of the identity being destroyed (a channel being
|
||||
// unregistered, or the server being crashed) and `createdAt` means a different
|
||||
// value is required each time.
|
||||
func ConfirmationCode(name string, createdAt time.Time) (code string) {
|
||||
buf := make([]byte, len(name)+8)
|
||||
binary.BigEndian.PutUint64(buf, uint64(createdAt.UnixNano()))
|
||||
copy(buf[8:], name[:])
|
||||
out := sha256.Sum256(buf)
|
||||
return B32Encoder.EncodeToString(out[:3])
|
||||
}
|
36
irc/utils/confirmation_test.go
Normal file
36
irc/utils/confirmation_test.go
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2020 Shivaram Lingamneni <slingamn@cs.stanford.edu>
|
||||
// released under the MIT license
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func easyParse(timestamp string) time.Time {
|
||||
result, err := time.Parse("2006-01-02 15:04:05Z", timestamp)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func TestConfirmation(t *testing.T) {
|
||||
set := make(map[string]struct{})
|
||||
|
||||
set[ConfirmationCode("#darwin", easyParse("2006-01-01 00:00:00Z"))] = struct{}{}
|
||||
set[ConfirmationCode("#darwin", easyParse("2006-01-02 00:00:00Z"))] = struct{}{}
|
||||
set[ConfirmationCode("#xelpers", easyParse("2006-01-01 00:00:00Z"))] = struct{}{}
|
||||
set[ConfirmationCode("#xelpers", easyParse("2006-01-02 00:00:00Z"))] = struct{}{}
|
||||
|
||||
if len(set) != 4 {
|
||||
t.Error("confirmation codes are not unique")
|
||||
}
|
||||
|
||||
for code := range set {
|
||||
if len(code) <= 2 || len(code) >= 8 {
|
||||
t.Errorf("bad code: %s", code)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user