package auditrelay import ( "bytes" "encoding/base64" "encoding/json" "errors" "io" "os" "regexp" ) var keyIDPattern = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$`) type keyFile struct { Version int `json:"version"` Keys []struct { KeyID string `json:"key_id"` Secret string `json:"secret_base64url"` } `json:"keys"` } func LoadKey(path, keyID string) ([]byte, error) { raw, err := os.ReadFile(path) if err != nil { return nil, errors.New("read audit relay key file") } var document keyFile decoder := json.NewDecoder(bytes.NewReader(raw)) decoder.DisallowUnknownFields() if err := decoder.Decode(&document); err != nil || document.Version != 1 || len(document.Keys) == 0 { return nil, errors.New("invalid audit relay key file") } var trailing any if err := decoder.Decode(&trailing); !errors.Is(err, io.EOF) { return nil, errors.New("invalid audit relay key file") } values := make(map[string][]byte, len(document.Keys)) for _, candidate := range document.Keys { secret, err := base64.RawURLEncoding.DecodeString(candidate.Secret) if err != nil || !keyIDPattern.MatchString(candidate.KeyID) || len(secret) < 32 { return nil, errors.New("invalid audit relay secret") } if _, duplicate := values[candidate.KeyID]; duplicate { return nil, errors.New("duplicate audit relay key ID") } values[candidate.KeyID] = secret } if secret, exists := values[keyID]; exists { return secret, nil } return nil, errors.New("audit relay key ID not found") }