moth/pkg/microchat/hmac.go

52 lines
1.3 KiB
Go
Raw Normal View History

2022-05-10 13:20:54 -06:00
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"fmt"
"log"
"strings"
)
// HmacResolverSeparator is the string used to separater username from hmac
const HmacResolverSeparator = "::"
// HmacResolver resolves usernames using SHA256 HMAC
type HmacResolver struct {
key string
}
// Resolve resolves usernames using HMAC.
//
// User strings are expected to be the concatenation of:
// desired username, HmacResolverSeparator, MAC
//
// If there is no separator, the correct user string is computed and printed to the log.
// So you can use this to compute the correct usernames.
func (h *HmacResolver) Resolve(event string, user string) (string, error) {
userparts := strings.Split(user, HmacResolverSeparator)
username := userparts[0]
mac := hmac.New(sha256.New, []byte(h.key))
fmt.Fprint(mac, event)
fmt.Fprint(mac, user)
expectedMAC := mac.Sum(nil)
if len(userparts) == 1 {
expectedEnc := base64.URLEncoding.EncodeToString(expectedMAC)
log.Printf("Authenticated username: %s%s%s", username, HmacResolverSeparator, expectedEnc)
return "", fmt.Errorf("No authentication provided")
}
givenMAC, err := base64.URLEncoding.DecodeString(userparts[1])
if err != nil {
return "", err
}
if hmac.Equal(givenMAC, expectedMAC) {
return username, nil
}
return "", fmt.Errorf("Authentication failed")
}