// SPDX-License-Identifier: Apache-2.0 package provision import ( "encoding/hex" "encoding/json" "fmt" ) // AuthenticationCredentials returns an isolated snapshot; never log it. func (s *Store) AuthenticationCredentials() Credentials { s.mu.Lock() defer s.mu.Unlock() b, _ := json.Marshal(s.data.HomeKey) var c Credentials _ = json.Unmarshal(b, &c) return c } func authorized(current, expected Credentials, iid, eid, pub string) bool { if current.ReaderPrivateKey != expected.ReaderPrivateKey || current.ReaderIdentifier != expected.ReaderIdentifier { return false } issuer, ok := current.Issuers[iid] if !ok { return false } ep, ok := issuer.Endpoints[eid] return ok && ep.PublicKey == pub && ep.KeyState == 1 && ep.KeyType == 2 } func (s *Store) SaveAuthenticatedKey(expected Credentials, iid, eid, pub string, key []byte) error { if len(key) != 32 { return fmt.Errorf("invalid persistent key") } return s.update(func(d *Data) error { if !authorized(d.HomeKey, expected, iid, eid, pub) { return fmt.Errorf("credentials revoked or changed during authentication") } issuer := d.HomeKey.Issuers[iid] ep := issuer.Endpoints[eid] ep.PersistentKey = hex.EncodeToString(key) issuer.Endpoints[eid] = ep d.HomeKey.Issuers[iid] = issuer return nil }) } // WithAuthorization serializes the final unlock with HomeKit revocations. // The callback must not call back into Store. func (s *Store) WithAuthorization(expected Credentials, iid, eid, pub string, fn func() error) error { s.mu.Lock() defer s.mu.Unlock() if !authorized(s.data.HomeKey, expected, iid, eid, pub) { return fmt.Errorf("credentials revoked or changed before unlock") } return fn() }