mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-10 22:19:31 +01:00
formalize token munging code
This commit is contained in:
parent
84fe2c60dd
commit
7d53dd5d81
@ -777,12 +777,6 @@ func stripMaskFromNick(nickMask string) (nick string) {
|
|||||||
return nickMask[0:index]
|
return nickMask[0:index]
|
||||||
}
|
}
|
||||||
|
|
||||||
// munge the msgid corresponding to a replayable event,
|
|
||||||
// yielding a consistent msgid for the fake PRIVMSG from HistServ
|
|
||||||
func mungeMsgidForHistserv(token string) (result string) {
|
|
||||||
return fmt.Sprintf("_%s", token)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.Item, autoreplay bool) {
|
func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.Item, autoreplay bool) {
|
||||||
chname := channel.Name()
|
chname := channel.Name()
|
||||||
client := rb.target
|
client := rb.target
|
||||||
@ -823,7 +817,7 @@ func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.I
|
|||||||
} else {
|
} else {
|
||||||
message = fmt.Sprintf(client.t("%[1]s [account: %[2]s] joined the channel"), nick, item.AccountName)
|
message = fmt.Sprintf(client.t("%[1]s [account: %[2]s] joined the channel"), nick, item.AccountName)
|
||||||
}
|
}
|
||||||
rb.AddFromClient(item.Message.Time, mungeMsgidForHistserv(item.Message.Msgid), "HistServ", "*", nil, "PRIVMSG", chname, message)
|
rb.AddFromClient(item.Message.Time, utils.MungeSecretToken(item.Message.Msgid), "HistServ", "*", nil, "PRIVMSG", chname, message)
|
||||||
}
|
}
|
||||||
case history.Part:
|
case history.Part:
|
||||||
if eventPlayback {
|
if eventPlayback {
|
||||||
@ -833,14 +827,14 @@ func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.I
|
|||||||
continue // #474
|
continue // #474
|
||||||
}
|
}
|
||||||
message := fmt.Sprintf(client.t("%[1]s left the channel (%[2]s)"), nick, item.Message.Message)
|
message := fmt.Sprintf(client.t("%[1]s left the channel (%[2]s)"), nick, item.Message.Message)
|
||||||
rb.AddFromClient(item.Message.Time, mungeMsgidForHistserv(item.Message.Msgid), "HistServ", "*", nil, "PRIVMSG", chname, message)
|
rb.AddFromClient(item.Message.Time, utils.MungeSecretToken(item.Message.Msgid), "HistServ", "*", nil, "PRIVMSG", chname, message)
|
||||||
}
|
}
|
||||||
case history.Kick:
|
case history.Kick:
|
||||||
if eventPlayback {
|
if eventPlayback {
|
||||||
rb.AddFromClient(item.Message.Time, item.Message.Msgid, item.Nick, item.AccountName, nil, "HEVENT", "KICK", chname, item.Params[0], item.Message.Message)
|
rb.AddFromClient(item.Message.Time, item.Message.Msgid, item.Nick, item.AccountName, nil, "HEVENT", "KICK", chname, item.Params[0], item.Message.Message)
|
||||||
} else {
|
} else {
|
||||||
message := fmt.Sprintf(client.t("%[1]s kicked %[2]s (%[3]s)"), nick, item.Params[0], item.Message.Message)
|
message := fmt.Sprintf(client.t("%[1]s kicked %[2]s (%[3]s)"), nick, item.Params[0], item.Message.Message)
|
||||||
rb.AddFromClient(item.Message.Time, mungeMsgidForHistserv(item.Message.Msgid), "HistServ", "*", nil, "PRIVMSG", chname, message)
|
rb.AddFromClient(item.Message.Time, utils.MungeSecretToken(item.Message.Msgid), "HistServ", "*", nil, "PRIVMSG", chname, message)
|
||||||
}
|
}
|
||||||
case history.Quit:
|
case history.Quit:
|
||||||
if eventPlayback {
|
if eventPlayback {
|
||||||
@ -850,14 +844,14 @@ func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.I
|
|||||||
continue // #474
|
continue // #474
|
||||||
}
|
}
|
||||||
message := fmt.Sprintf(client.t("%[1]s quit (%[2]s)"), nick, item.Message.Message)
|
message := fmt.Sprintf(client.t("%[1]s quit (%[2]s)"), nick, item.Message.Message)
|
||||||
rb.AddFromClient(item.Message.Time, mungeMsgidForHistserv(item.Message.Msgid), "HistServ", "*", nil, "PRIVMSG", chname, message)
|
rb.AddFromClient(item.Message.Time, utils.MungeSecretToken(item.Message.Msgid), "HistServ", "*", nil, "PRIVMSG", chname, message)
|
||||||
}
|
}
|
||||||
case history.Nick:
|
case history.Nick:
|
||||||
if eventPlayback {
|
if eventPlayback {
|
||||||
rb.AddFromClient(item.Message.Time, item.Message.Msgid, item.Nick, item.AccountName, nil, "HEVENT", "NICK", item.Params[0])
|
rb.AddFromClient(item.Message.Time, item.Message.Msgid, item.Nick, item.AccountName, nil, "HEVENT", "NICK", item.Params[0])
|
||||||
} else {
|
} else {
|
||||||
message := fmt.Sprintf(client.t("%[1]s changed nick to %[2]s"), nick, item.Params[0])
|
message := fmt.Sprintf(client.t("%[1]s changed nick to %[2]s"), nick, item.Params[0])
|
||||||
rb.AddFromClient(item.Message.Time, mungeMsgidForHistserv(item.Message.Msgid), "HistServ", "*", nil, "PRIVMSG", chname, message)
|
rb.AddFromClient(item.Message.Time, utils.MungeSecretToken(item.Message.Msgid), "HistServ", "*", nil, "PRIVMSG", chname, message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,29 @@ func GenerateSecretToken() string {
|
|||||||
return B32Encoder.EncodeToString(buf[:])
|
return B32Encoder.EncodeToString(buf[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// "munge" a secret token to a new value. requirements:
|
||||||
|
// 1. MUST be roughly as unlikely to collide with `GenerateSecretToken` outputs
|
||||||
|
// as those outputs are with each other
|
||||||
|
// 2. SHOULD be deterministic (motivation: if a JOIN line has msgid x,
|
||||||
|
// create a deterministic msgid y for the fake HistServ PRIVMSG that "replays" it)
|
||||||
|
// 3. SHOULD be in the same "namespace" as `GenerateSecretToken` outputs
|
||||||
|
// (same length and character set)
|
||||||
|
func MungeSecretToken(token string) (result string) {
|
||||||
|
bytes, err := B32Encoder.DecodeString(token)
|
||||||
|
if err != nil {
|
||||||
|
// this should never happen
|
||||||
|
return GenerateSecretToken()
|
||||||
|
}
|
||||||
|
// add 1 with carrying
|
||||||
|
for i := len(bytes) - 1; 0 <= i; i -= 1 {
|
||||||
|
bytes[i] += 1
|
||||||
|
if bytes[i] != 0 {
|
||||||
|
break
|
||||||
|
} // else: overflow, carry to the next place
|
||||||
|
}
|
||||||
|
return B32Encoder.EncodeToString(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
// securely check if a supplied token matches a stored token
|
// securely check if a supplied token matches a stored token
|
||||||
func SecretTokensMatch(storedToken string, suppliedToken string) bool {
|
func SecretTokensMatch(storedToken string, suppliedToken string) bool {
|
||||||
// XXX fix a potential gotcha: if the stored token is uninitialized,
|
// XXX fix a potential gotcha: if the stored token is uninitialized,
|
||||||
|
@ -47,8 +47,37 @@ func TestTokenCompare(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMunging(t *testing.T) {
|
||||||
|
count := 131072
|
||||||
|
set := make(map[string]bool)
|
||||||
|
var token string
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
|
token = GenerateSecretToken()
|
||||||
|
set[token] = true
|
||||||
|
}
|
||||||
|
// all tokens generated thus far should be unique
|
||||||
|
assertEqual(len(set), count, t)
|
||||||
|
|
||||||
|
// iteratively munge the last generated token an additional `count` times
|
||||||
|
mungedToken := token
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
|
mungedToken = MungeSecretToken(mungedToken)
|
||||||
|
assertEqual(len(mungedToken), len(token), t)
|
||||||
|
set[mungedToken] = true
|
||||||
|
}
|
||||||
|
// munged tokens should not collide with generated tokens, or each other
|
||||||
|
assertEqual(len(set), count*2, t)
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkGenerateSecretToken(b *testing.B) {
|
func BenchmarkGenerateSecretToken(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
GenerateSecretToken()
|
GenerateSecretToken()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkMungeSecretToken(b *testing.B) {
|
||||||
|
t := GenerateSecretToken()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
t = MungeSecretToken(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user