瀏覽代碼

Merge pull request #491 from slingamn/munge

formalize token munging code
tags/v1.1.0-rc1
Daniel Oaks 5 年之前
父節點
當前提交
45fb9cade0
No account linked to committer's email address
共有 3 個文件被更改,包括 57 次插入11 次删除
  1. 5
    11
      irc/channel.go
  2. 23
    0
      irc/utils/crypto.go
  3. 29
    0
      irc/utils/crypto_test.go

+ 5
- 11
irc/channel.go 查看文件

@@ -777,12 +777,6 @@ func stripMaskFromNick(nickMask string) (nick string) {
777 777
 	return nickMask[0:index]
778 778
 }
779 779
 
780
-// munge the msgid corresponding to a replayable event,
781
-// yielding a consistent msgid for the fake PRIVMSG from HistServ
782
-func mungeMsgidForHistserv(token string) (result string) {
783
-	return fmt.Sprintf("_%s", token)
784
-}
785
-
786 780
 func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.Item, autoreplay bool) {
787 781
 	chname := channel.Name()
788 782
 	client := rb.target
@@ -823,7 +817,7 @@ func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.I
823 817
 				} else {
824 818
 					message = fmt.Sprintf(client.t("%[1]s [account: %[2]s] joined the channel"), nick, item.AccountName)
825 819
 				}
826
-				rb.AddFromClient(item.Message.Time, mungeMsgidForHistserv(item.Message.Msgid), "HistServ", "*", nil, "PRIVMSG", chname, message)
820
+				rb.AddFromClient(item.Message.Time, utils.MungeSecretToken(item.Message.Msgid), "HistServ", "*", nil, "PRIVMSG", chname, message)
827 821
 			}
828 822
 		case history.Part:
829 823
 			if eventPlayback {
@@ -833,14 +827,14 @@ func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.I
833 827
 					continue // #474
834 828
 				}
835 829
 				message := fmt.Sprintf(client.t("%[1]s left the channel (%[2]s)"), nick, item.Message.Message)
836
-				rb.AddFromClient(item.Message.Time, mungeMsgidForHistserv(item.Message.Msgid), "HistServ", "*", nil, "PRIVMSG", chname, message)
830
+				rb.AddFromClient(item.Message.Time, utils.MungeSecretToken(item.Message.Msgid), "HistServ", "*", nil, "PRIVMSG", chname, message)
837 831
 			}
838 832
 		case history.Kick:
839 833
 			if eventPlayback {
840 834
 				rb.AddFromClient(item.Message.Time, item.Message.Msgid, item.Nick, item.AccountName, nil, "HEVENT", "KICK", chname, item.Params[0], item.Message.Message)
841 835
 			} else {
842 836
 				message := fmt.Sprintf(client.t("%[1]s kicked %[2]s (%[3]s)"), nick, item.Params[0], item.Message.Message)
843
-				rb.AddFromClient(item.Message.Time, mungeMsgidForHistserv(item.Message.Msgid), "HistServ", "*", nil, "PRIVMSG", chname, message)
837
+				rb.AddFromClient(item.Message.Time, utils.MungeSecretToken(item.Message.Msgid), "HistServ", "*", nil, "PRIVMSG", chname, message)
844 838
 			}
845 839
 		case history.Quit:
846 840
 			if eventPlayback {
@@ -850,14 +844,14 @@ func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.I
850 844
 					continue // #474
851 845
 				}
852 846
 				message := fmt.Sprintf(client.t("%[1]s quit (%[2]s)"), nick, item.Message.Message)
853
-				rb.AddFromClient(item.Message.Time, mungeMsgidForHistserv(item.Message.Msgid), "HistServ", "*", nil, "PRIVMSG", chname, message)
847
+				rb.AddFromClient(item.Message.Time, utils.MungeSecretToken(item.Message.Msgid), "HistServ", "*", nil, "PRIVMSG", chname, message)
854 848
 			}
855 849
 		case history.Nick:
856 850
 			if eventPlayback {
857 851
 				rb.AddFromClient(item.Message.Time, item.Message.Msgid, item.Nick, item.AccountName, nil, "HEVENT", "NICK", item.Params[0])
858 852
 			} else {
859 853
 				message := fmt.Sprintf(client.t("%[1]s changed nick to %[2]s"), nick, item.Params[0])
860
-				rb.AddFromClient(item.Message.Time, mungeMsgidForHistserv(item.Message.Msgid), "HistServ", "*", nil, "PRIVMSG", chname, message)
854
+				rb.AddFromClient(item.Message.Time, utils.MungeSecretToken(item.Message.Msgid), "HistServ", "*", nil, "PRIVMSG", chname, message)
861 855
 			}
862 856
 		}
863 857
 	}

+ 23
- 0
irc/utils/crypto.go 查看文件

@@ -28,6 +28,29 @@ func GenerateSecretToken() string {
28 28
 	return B32Encoder.EncodeToString(buf[:])
29 29
 }
30 30
 
31
+// "munge" a secret token to a new value. requirements:
32
+// 1. MUST be roughly as unlikely to collide with `GenerateSecretToken` outputs
33
+// as those outputs are with each other
34
+// 2. SHOULD be deterministic (motivation: if a JOIN line has msgid x,
35
+// create a deterministic msgid y for the fake HistServ PRIVMSG that "replays" it)
36
+// 3. SHOULD be in the same "namespace" as `GenerateSecretToken` outputs
37
+// (same length and character set)
38
+func MungeSecretToken(token string) (result string) {
39
+	bytes, err := B32Encoder.DecodeString(token)
40
+	if err != nil {
41
+		// this should never happen
42
+		return GenerateSecretToken()
43
+	}
44
+	// add 1 with carrying
45
+	for i := len(bytes) - 1; 0 <= i; i -= 1 {
46
+		bytes[i] += 1
47
+		if bytes[i] != 0 {
48
+			break
49
+		} // else: overflow, carry to the next place
50
+	}
51
+	return B32Encoder.EncodeToString(bytes)
52
+}
53
+
31 54
 // securely check if a supplied token matches a stored token
32 55
 func SecretTokensMatch(storedToken string, suppliedToken string) bool {
33 56
 	// XXX fix a potential gotcha: if the stored token is uninitialized,

+ 29
- 0
irc/utils/crypto_test.go 查看文件

@@ -47,8 +47,37 @@ func TestTokenCompare(t *testing.T) {
47 47
 	}
48 48
 }
49 49
 
50
+func TestMunging(t *testing.T) {
51
+	count := 131072
52
+	set := make(map[string]bool)
53
+	var token string
54
+	for i := 0; i < count; i++ {
55
+		token = GenerateSecretToken()
56
+		set[token] = true
57
+	}
58
+	// all tokens generated thus far should be unique
59
+	assertEqual(len(set), count, t)
60
+
61
+	// iteratively munge the last generated token an additional `count` times
62
+	mungedToken := token
63
+	for i := 0; i < count; i++ {
64
+		mungedToken = MungeSecretToken(mungedToken)
65
+		assertEqual(len(mungedToken), len(token), t)
66
+		set[mungedToken] = true
67
+	}
68
+	// munged tokens should not collide with generated tokens, or each other
69
+	assertEqual(len(set), count*2, t)
70
+}
71
+
50 72
 func BenchmarkGenerateSecretToken(b *testing.B) {
51 73
 	for i := 0; i < b.N; i++ {
52 74
 		GenerateSecretToken()
53 75
 	}
54 76
 }
77
+
78
+func BenchmarkMungeSecretToken(b *testing.B) {
79
+	t := GenerateSecretToken()
80
+	for i := 0; i < b.N; i++ {
81
+		t = MungeSecretToken(t)
82
+	}
83
+}

Loading…
取消
儲存