[]byte{0x00, 0x69}, // fieldUserLogin
loginLen,
- []byte(NegatedUserString([]byte(a.Login))),
+ negateString([]byte(a.Login)),
[]byte{0x00, 0x6e}, // fieldUserAccess
[]byte{0x00, 0x08},
tranLogin, nil,
NewField(fieldUserName, []byte(c.pref.Username)),
NewField(fieldUserIconID, c.pref.IconBytes()),
- NewField(fieldUserLogin, []byte(NegatedUserString([]byte(login)))),
- NewField(fieldUserPassword, []byte(NegatedUserString([]byte(password)))),
+ NewField(fieldUserLogin, negateString([]byte(login))),
+ NewField(fieldUserPassword, negateString([]byte(password))),
NewField(fieldVersion, []byte{0, 2}),
),
)
}
func (tt *testCase) Setup(srv *Server) error {
- if err := srv.NewUser(tt.account.Login, tt.account.Name, NegatedUserString([]byte(tt.account.Password)), *tt.account.Access); err != nil {
+ if err := srv.NewUser(tt.account.Login, tt.account.Name, string(negateString([]byte(tt.account.Password))), *tt.account.Access); err != nil {
return err
}
func HandleGetUser(cc *ClientConn, t *Transaction) (res []Transaction, err error) {
userLogin := string(t.GetField(fieldUserLogin).Data)
- decodedUserLogin := NegatedUserString(t.GetField(fieldUserLogin).Data)
account := cc.Server.Accounts[userLogin]
if account == nil {
errorT := cc.NewErrReply(t, "Account does not exist.")
res = append(res, cc.NewReply(t,
NewField(fieldUserName, []byte(account.Name)),
- NewField(fieldUserLogin, []byte(decodedUserLogin)),
+ NewField(fieldUserLogin, negateString(t.GetField(fieldUserLogin).Data)),
NewField(fieldUserPassword, []byte(account.Password)),
NewField(fieldUserAccess, *account.Access),
))
// DecodeUserString decodes an obfuscated user string from a client
// e.g. 98 8a 9a 8c 8b => "guest"
-func DecodeUserString(encodedString []byte) (decodedString string) {
- for _, char := range encodedString {
- decodedString += string(rune(255 - uint(char)))
+func DecodeUserString(obfuText []byte) (clearText string) {
+ for _, char := range obfuText {
+ clearText += string(rune(255 - uint(char)))
}
- return decodedString
+ return clearText
}
-// Take a []byte of uncoded ascii as input and encode it
-// TODO: change the method signature to take a string and return []byte
-func NegatedUserString(encodedString []byte) string {
- var decodedString string
- for _, char := range encodedString {
- decodedString += string(255 - uint8(char))[1:]
+// negateString takes []byte s containing cleartext and rotates by 255 into obfuscated cleartext.
+// The Hotline protocol uses this format for sending passwords over network.
+// Not secure, but hey, it was the 90s!
+func negateString(clearText []byte) []byte {
+ obfuText := make([]byte, len(clearText))
+ for i := 0; i < len(clearText); i++ {
+ obfuText[i] = 255 - clearText[i]
}
- return decodedString
+ return obfuText
}
package hotline
import (
+ "bytes"
"github.com/stretchr/testify/assert"
"testing"
)
tests := []struct {
name string
args args
- want string
+ want []byte
}{
{
- name: "encodes bytes to string",
+ name: "encodes bytes to expected string",
args: args{
encodedString: []byte("guest"),
},
- want: string([]byte{0x98, 0x8a, 0x9a, 0x8c, 0x8b}),
+ want: []byte{0x98, 0x8a, 0x9a, 0x8c, 0x8b},
+ },
+ {
+ name: "encodes bytes with numerals to expected string",
+ args: args{
+ encodedString: []byte("foo1"),
+ },
+ want: []byte{0x99, 0x90, 0x90, 0xce },
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- if got := NegatedUserString(tt.args.encodedString); got != tt.want {
- t.Errorf("NegatedUserString() = %v, want %v", got, tt.want)
+ if got := negateString(tt.args.encodedString); !bytes.Equal(got, tt.want) {
+ t.Errorf("NegatedUserString() = %x, want %x", got, tt.want)
}
})
}