Browse Source

factor out confirmation codes into utils, change their format

tags/v2.0.0-rc1
Shivaram Lingamneni 4 years ago
parent
commit
85a536977c
5 changed files with 63 additions and 15 deletions
  1. 3
    13
      irc/chanserv.go
  2. 1
    1
      irc/handlers.go
  3. 1
    1
      irc/nickserv.go
  4. 22
    0
      irc/utils/confirmation.go
  5. 36
    0
      irc/utils/confirmation_test.go

+ 3
- 13
irc/chanserv.go View File

4
 package irc
4
 package irc
5
 
5
 
6
 import (
6
 import (
7
-	"bytes"
8
 	"fmt"
7
 	"fmt"
9
-	"hash/crc32"
10
 	"sort"
8
 	"sort"
11
-	"strconv"
12
 	"strings"
9
 	"strings"
13
 	"time"
10
 	"time"
14
 
11
 
15
 	"github.com/goshuirc/irc-go/ircfmt"
12
 	"github.com/goshuirc/irc-go/ircfmt"
16
 	"github.com/oragono/oragono/irc/modes"
13
 	"github.com/oragono/oragono/irc/modes"
17
 	"github.com/oragono/oragono/irc/sno"
14
 	"github.com/oragono/oragono/irc/sno"
15
+	"github.com/oragono/oragono/irc/utils"
18
 )
16
 )
19
 
17
 
20
 const chanservHelp = `ChanServ lets you register and manage channels.`
18
 const chanservHelp = `ChanServ lets you register and manage channels.`
352
 	}
350
 	}
353
 
351
 
354
 	info := channel.ExportRegistration(0)
352
 	info := channel.ExportRegistration(0)
355
-	expectedCode := unregisterConfirmationCode(info.Name, info.RegisteredAt)
353
+	expectedCode := utils.ConfirmationCode(info.Name, info.RegisteredAt)
356
 	if expectedCode != verificationCode {
354
 	if expectedCode != verificationCode {
357
 		csNotice(rb, ircfmt.Unescape(client.t("$bWarning: unregistering this channel will remove all stored channel attributes.$b")))
355
 		csNotice(rb, ircfmt.Unescape(client.t("$bWarning: unregistering this channel will remove all stored channel attributes.$b")))
358
 		csNotice(rb, fmt.Sprintf(client.t("To confirm channel unregistration, type: /CS UNREGISTER %[1]s %[2]s"), channelKey, expectedCode))
356
 		csNotice(rb, fmt.Sprintf(client.t("To confirm channel unregistration, type: /CS UNREGISTER %[1]s %[2]s"), channelKey, expectedCode))
363
 	csNotice(rb, fmt.Sprintf(client.t("Channel %s is now unregistered"), channelKey))
361
 	csNotice(rb, fmt.Sprintf(client.t("Channel %s is now unregistered"), channelKey))
364
 }
362
 }
365
 
363
 
366
-// deterministically generates a confirmation code for unregistering a channel / account
367
-func unregisterConfirmationCode(name string, registeredAt time.Time) (code string) {
368
-	var codeInput bytes.Buffer
369
-	codeInput.WriteString(name)
370
-	codeInput.WriteString(strconv.FormatInt(registeredAt.Unix(), 16))
371
-	return strconv.Itoa(int(crc32.ChecksumIEEE(codeInput.Bytes())))
372
-}
373
-
374
 func csClearHandler(server *Server, client *Client, command string, params []string, rb *ResponseBuffer) {
364
 func csClearHandler(server *Server, client *Client, command string, params []string, rb *ResponseBuffer) {
375
 	channel := server.channels.Get(params[0])
365
 	channel := server.channels.Get(params[0])
376
 	if channel == nil {
366
 	if channel == nil {
426
 		return
416
 		return
427
 	}
417
 	}
428
 	if targetAccount.NameCasefolded != account {
418
 	if targetAccount.NameCasefolded != account {
429
-		expectedCode := unregisterConfirmationCode(regInfo.Name, regInfo.RegisteredAt)
419
+		expectedCode := utils.ConfirmationCode(regInfo.Name, regInfo.RegisteredAt)
430
 		codeValidated := 2 < len(params) && params[2] == expectedCode
420
 		codeValidated := 2 < len(params) && params[2] == expectedCode
431
 		if !codeValidated {
421
 		if !codeValidated {
432
 			csNotice(rb, ircfmt.Unescape(client.t("$bWarning: you are about to transfer control of your channel to another user.$b")))
422
 			csNotice(rb, ircfmt.Unescape(client.t("$bWarning: you are about to transfer control of your channel to another user.$b")))

+ 1
- 1
irc/handlers.go View File

810
 			rb.Notice(client.t("You must have rehash permissions in order to execute DEBUG CRASHSERVER"))
810
 			rb.Notice(client.t("You must have rehash permissions in order to execute DEBUG CRASHSERVER"))
811
 			return false
811
 			return false
812
 		}
812
 		}
813
-		code := unregisterConfirmationCode(server.name, server.ctime)
813
+		code := utils.ConfirmationCode(server.name, server.ctime)
814
 		if len(msg.Params) == 1 || msg.Params[1] != code {
814
 		if len(msg.Params) == 1 || msg.Params[1] != code {
815
 			rb.Notice(fmt.Sprintf(client.t("To crash the server, issue the following command: /DEBUG CRASHSERVER %s"), code))
815
 			rb.Notice(fmt.Sprintf(client.t("To crash the server, issue the following command: /DEBUG CRASHSERVER %s"), code))
816
 			return false
816
 			return false

+ 1
- 1
irc/nickserv.go View File

732
 		return
732
 		return
733
 	}
733
 	}
734
 
734
 
735
-	expectedCode := unregisterConfirmationCode(account.Name, account.RegisteredAt)
735
+	expectedCode := utils.ConfirmationCode(account.Name, account.RegisteredAt)
736
 	if expectedCode != verificationCode {
736
 	if expectedCode != verificationCode {
737
 		nsNotice(rb, ircfmt.Unescape(client.t("$bWarning: unregistering this account will remove its stored privileges.$b")))
737
 		nsNotice(rb, ircfmt.Unescape(client.t("$bWarning: unregistering this account will remove its stored privileges.$b")))
738
 		nsNotice(rb, fmt.Sprintf(client.t("To confirm account unregistration, type: /NS UNREGISTER %[1]s %[2]s"), cfname, expectedCode))
738
 		nsNotice(rb, fmt.Sprintf(client.t("To confirm account unregistration, type: /NS UNREGISTER %[1]s %[2]s"), cfname, expectedCode))

+ 22
- 0
irc/utils/confirmation.go View File

1
+// Copyright (c) 2020 Shivaram Lingamneni <slingamn@cs.stanford.edu>
2
+// released under the MIT license
3
+
4
+package utils
5
+
6
+import (
7
+	"crypto/sha256"
8
+	"encoding/binary"
9
+	"time"
10
+)
11
+
12
+// Deterministically generates a confirmation code for some destructive activity;
13
+// `name` is typically the name of the identity being destroyed (a channel being
14
+// unregistered, or the server being crashed) and `createdAt` means a different
15
+// value is required each time.
16
+func ConfirmationCode(name string, createdAt time.Time) (code string) {
17
+	buf := make([]byte, len(name)+8)
18
+	binary.BigEndian.PutUint64(buf, uint64(createdAt.UnixNano()))
19
+	copy(buf[8:], name[:])
20
+	out := sha256.Sum256(buf)
21
+	return B32Encoder.EncodeToString(out[:3])
22
+}

+ 36
- 0
irc/utils/confirmation_test.go View File

1
+// Copyright (c) 2020 Shivaram Lingamneni <slingamn@cs.stanford.edu>
2
+// released under the MIT license
3
+
4
+package utils
5
+
6
+import (
7
+	"testing"
8
+	"time"
9
+)
10
+
11
+func easyParse(timestamp string) time.Time {
12
+	result, err := time.Parse("2006-01-02 15:04:05Z", timestamp)
13
+	if err != nil {
14
+		panic(err)
15
+	}
16
+	return result
17
+}
18
+
19
+func TestConfirmation(t *testing.T) {
20
+	set := make(map[string]struct{})
21
+
22
+	set[ConfirmationCode("#darwin", easyParse("2006-01-01 00:00:00Z"))] = struct{}{}
23
+	set[ConfirmationCode("#darwin", easyParse("2006-01-02 00:00:00Z"))] = struct{}{}
24
+	set[ConfirmationCode("#xelpers", easyParse("2006-01-01 00:00:00Z"))] = struct{}{}
25
+	set[ConfirmationCode("#xelpers", easyParse("2006-01-02 00:00:00Z"))] = struct{}{}
26
+
27
+	if len(set) != 4 {
28
+		t.Error("confirmation codes are not unique")
29
+	}
30
+
31
+	for code := range set {
32
+		if len(code) <= 2 || len(code) >= 8 {
33
+			t.Errorf("bad code: %s", code)
34
+		}
35
+	}
36
+}

Loading…
Cancel
Save