package queue import ( "crypto/sha3" "encoding/base64" "fmt" "io" "github.com/go-json-experiment/json/jsontext" ) // sender is an obfuscated sender ID. // // It acts approximately as a quotient type: since it is unexported, the only // way to obtain values of type sender without unusual effort is to use the // constructors provided by this package. // This helps to prevent misuse that exposes actual user IDs. type sender [28]byte // Sender constructs an obfuscated sender ID. // The salt must be shared by all ingesters. // While the salt may be of any length, a length between 16 and 64 bytes is suggested. func Sender(salt []byte, channel, user string) sender { b := make([]byte, 128) b = append(b, channel...) b = append(b, 0) b = append(b, salt...) b = append(b, 0) b = append(b, user...) return sender(sha3.Sum224(b)) } func (s sender) String() string { b := base64.RawStdEncoding.AppendEncode(make([]byte, 0, 38), s[:]) return string(b) } func (s sender) MarshalJSONTo(e *jsontext.Encoder) error { return e.WriteToken(jsontext.String(s.String())) } func (s *sender) UnmarshalJSONFrom(d *jsontext.Decoder) error { t, err := d.ReadToken() switch err { case nil: // do nothing case io.EOF: return io.ErrUnexpectedEOF default: return err } e := t.String() if t.Kind() != '"' { return fmt.Errorf("invalid token for sender %q", e) } if len(e) != 38 { return fmt.Errorf("invalid string for sender %q", e) } b, err := base64.RawStdEncoding.AppendDecode(make([]byte, 0, 28), []byte(e)) if err != nil { return err } *s = sender(b) return nil }