Help us shape the future of Go! Take the 2026 Go Developer Survey

store

package
v0.12.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 25, 2026 License: Apache-2.0 Imports: 13 Imported by: 1

Documentation

Overview

Package store persists the Matter bridge's operational state: fabrics, node identities (NOC chain + private key + IPK), group keys, and access-control lists.

This package is purely the typed access surface — it borrows an already-migrated *sql.DB from whatever opened it and never opens one. The DDL its queries are written against is embedded here and reachable as Schema; a host either feeds that text through its own migration tool or calls Apply, but does not transcribe it. A tool that needs versioned steps takes Migrations, and SchemaFingerprint tells a host whether its database carries this release's schema.

Persistence model (Matter Core Spec §11.18 / §11.2 / §11.2.10):

  • Fabric (matter_fabrics) — keyed by stack-assigned fabric_index (1..254). Holds FabricID, NodeID, RootPublicKey, VendorID, Label, CompressedFabricID.
  • NodeIdentity (matter_node_identities) — one per fabric. Holds NOC (raw bytes), optional ICAC, the P-256 private scalar matching the NOC's public key, and the IPK.
  • GroupKeySet (matter_group_keys) — per (fabric, group_key_set_id). Up to three EpochKey/EpochStart pairs per spec.
  • GroupKeyMap (matter_group_key_map) — binds GroupID → GroupKeySetID per fabric; the key set need not exist yet.
  • GroupTable (matter_group_table) — the endpoints of each group.
  • Groupcast groups (matter_groupcast_groups) — the Groupcast cluster's per-group multicast policy and auxiliary-ACL flag.
  • ACL (matter_acl_entries) — per-fabric ordered list of ACEs. Subjects and Targets ride as JSON because the access path is always "load whole ACL for fabric".

Cascade-delete on fabric removal is handled at the schema level (FOREIGN KEY ... ON DELETE CASCADE).

The private key persists raw. File-system level protection is the operator's responsibility; the module does not encrypt at rest.

Index

Constants

View Source
const (
	// SettingNodeLabel holds the commissioner-written
	// BasicInformation.NodeLabel.
	SettingNodeLabel = "basic_information.node_label"
	// SettingLocation holds the commissioner-written
	// BasicInformation.Location (ISO-3166 2-letter code).
	SettingLocation = "basic_information.location"
	// SettingUniqueID holds BasicInformation.UniqueID. The attribute
	// carries quality F (fixed for the lifetime of the device, Matter
	// §11.1.5.13), which a derivation can only approximate: it is stable
	// exactly as long as its inputs are, so a config edit to the bridge
	// label would move the node's identity under every controller cache.
	// Persisting the value on first boot and feeding it back through
	// core.Config.UniqueID makes the attribute genuinely fixed — the same
	// shape matter.js uses (BasicInformationServer's uniqueId, quality
	// "FN": created once, restored from state afterwards).
	SettingUniqueID = "basic_information.unique_id"
)

Setting keys for persisted writable cluster attributes. Matter §11.1.6 marks NodeLabel (0x0005) and Location (0x0006) with the "N" (non-volatile) quality — a commissioner write must survive a daemon restart. matter.js persists them through the behavior state storage (BasicInformationServer state with persistent qualities).

View Source
const MetadataKeyEventNumber = "event_number_ceiling"

MetadataKeyEventNumber is the matter_metadata key holding the persisted EventNumber ceiling. The event log seeds its counter from this value at boot and re-persists a new ceiling ahead of use, so event numbers stay monotonic across restarts (Matter §7.14.2.1; chip EventManagement's counter-epoch pattern).

View Source
const SettingDoorLockCredentialKey = "door_lock.credential_key" //nolint:gosec // the name of a settings key, not a credential

SettingDoorLockCredentialKey holds the node's DoorLock credential key: the random 16-byte key, hex-encoded, the DoorLock server encrypts every stored credential with. The server generates it once, on first use, and reads it back on every start — matter.js keeps the same key as nonvolatile state (DoorLockServer.ts:153-164 initialize, :1569-1573 State.credentialKey). One key serves every lock endpoint of the node.

Variables

View Source
var (
	// ErrFabricNotFound is returned when a fabric_index lookup misses.
	ErrFabricNotFound = errors.New("store: fabric not found")
	// ErrFabricExhausted is returned when [Store.AddFabric] runs out
	// of free fabric_index slots (1..254 are all taken).
	ErrFabricExhausted = errors.New("store: fabric index exhausted")
	// ErrIdentityNotFound is returned when [Store.GetIdentity] misses.
	ErrIdentityNotFound = errors.New("store: identity not found")
	// ErrGroupKeySetNotFound is returned when a (fabric, group_key_set_id)
	// lookup misses.
	ErrGroupKeySetNotFound = errors.New("store: group key set not found")
)

Sentinel errors. Callers use errors.Is to detect them.

View Source
var ErrResumptionNotFound = errors.New("store: resumption record not found")

ErrResumptionNotFound is returned when a lookup misses.

Functions

func Apply

func Apply(ctx context.Context, db *sql.DB) error

Apply executes Schema against db.

Every statement is idempotent (`IF NOT EXISTS`, `INSERT OR IGNORE`), so calling this on every boot is the intended use rather than a first-run special case. It does not open a database and does not set pragmas: the cascade deletes in the schema need `PRAGMA foreign_keys(1)` on every pooled connection, which is a property of the DSN the host opened and cannot be fixed up from here.

After the DDL it runs Upgrade, which brings a database created by an earlier release of this package in line with the current schema.

func Schema

func Schema() string

Schema returns the DDL for the matter_* tables this package reads and writes, as one SQL script.

A host that owns a migration tool feeds this text through it — as the body of a new migration, or as a fixture its own migration is diffed against — and keeps ownership of when it runs. A host without one calls Apply. Either way the text is the module's, so a column added here arrives with the dependency bump instead of being missed.

A host whose migration tool needs the schema as versioned steps rather than one idempotent script takes Migrations instead; the two produce the same schema (SchemaFingerprint).

It creates no endpoint table: endpoint identity is keyed on the host's own source identity and lives behind endpoint.Store, whose SQLite implementation ships its own schema.

func SchemaFingerprint added in v0.3.1

func SchemaFingerprint(ctx context.Context, db *sql.DB) (string, error)

SchemaFingerprint returns the SHA-256, hex-encoded, of db's matter_* schema: every table Schema creates, every index its DDL declares by name and the automatic indexes SQLite derives from those tables' own PRIMARY KEY / UNIQUE constraints, as sqlite_schema records them (type, name, table, and the CREATE statement normalised — identifier quotes dropped, whitespace collapsed — so a table rebuilt and renamed hashes like one created under its name). Rows and other tables do not count.

After Apply it is the release's value, recorded in the CHANGELOG; a host that carries the schema through its own migrations compares its database's fingerprint with that value to know its tables match this release's at column and constraint level, not only by name. An index a host adds on one of these tables, another table and the rows do not count.

func Upgrade added in v0.2.0

func Upgrade(ctx context.Context, db *sql.DB) error

Upgrade rewrites the parts of an existing database that an idempotent `CREATE TABLE IF NOT EXISTS` cannot reach: a table created by an earlier release keeps its old definition, so a changed constraint needs an explicit rebuild. Each step detects whether it is due and does nothing otherwise, so Upgrade is safe on every boot and on a fresh database.

Apply runs it. A host that feeds Schema through its own migration tool calls it once after that tool has run.

Steps:

  • matter_group_key_map loses the foreign key from (fabric_index, group_key_set_id) to matter_group_keys. A GroupKeyMap entry may name a key set that does not exist yet — matter.js accepts the write (GroupKeyManagementServer.ts #validateGroupKeyMap, the key-set check left commented out because certification tests write the map first) — and the constraint turned that write into a Failure.

Types

type ACL added in v0.10.5

type ACL interface {
	// ListACL returns the fabric's entries in list order.
	ListACL(ctx context.Context, fabricIndex uint8) ([]ACLEntry, error)
	// ReplaceACL swaps the fabric's entries for entries, renumbering
	// Position 0..n-1 in input order.
	ReplaceACL(ctx context.Context, fabricIndex uint8, entries []ACLEntry) error
}

ACL is the AccessControl cluster's per-fabric entry list (Matter §9.10).

type ACLEntry

type ACLEntry struct {
	ID          int64
	FabricIndex uint8
	Privilege   Privilege
	AuthMode    AuthMode
	Subjects    []uint64
	Targets     []ACLTarget
	Position    uint16
}

ACLEntry is one access-control entry. The list of entries per fabric is ordered (position field) — Matter evaluates ACEs in list order.

type ACLTarget

type ACLTarget struct {
	Cluster    *uint32 `json:"cluster,omitempty"`
	Endpoint   *uint16 `json:"endpoint,omitempty"`
	DeviceType *uint32 `json:"deviceType,omitempty"`
}

ACLTarget is one entry in the Targets list of an ACE. Each field is optional (nullable) per Matter §11.2.12.4: a missing field matches anything in that dimension.

type AuthMode

type AuthMode uint8

AuthMode mirrors Matter §11.2.12 AccessControlEntryAuthMode.

const (
	AuthModePASE  AuthMode = 1
	AuthModeCASE  AuthMode = 2
	AuthModeGroup AuthMode = 3
)

AuthMode values per Matter §11.2.12.

type DoorLockAuth added in v0.8.4

type DoorLockAuth struct {
	Users            []DoorLockUser
	Credentials      []DoorLockCredential
	WeekDaySchedules []DoorLockWeekDaySchedule
	YearDaySchedules []DoorLockYearDaySchedule
	HolidaySchedules []DoorLockHolidaySchedule
}

DoorLockAuth is what a lock endpoint keeps across restarts: the five lists of matter.js's DoorLockServer State (DoorLockServer.ts:1538-1574) but the credential key, which is SettingDoorLockCredentialKey.

type DoorLockCredential added in v0.8.4

type DoorLockCredential struct {
	Type                    uint8
	Index                   uint16
	Data                    []byte
	CreatorFabricIndex      uint8
	LastModifiedFabricIndex uint8
}

DoorLockCredential is one stored credential: matter.js LockAuth.Credential (LockAuth.ts:87-102). Data is the credential data as the DoorLock server encrypted it; this package never sees it in clear.

type DoorLockCredentialRef added in v0.8.4

type DoorLockCredentialRef struct {
	Type  uint8  `json:"type"`
	Index uint16 `json:"index"`
}

DoorLockCredentialRef names one credential of a user: matter.js LockAuth.CredentialRef (LockAuth.ts:33-39), the DoorLock CredentialStruct.

type DoorLockHolidaySchedule added in v0.8.4

type DoorLockHolidaySchedule struct {
	HolidayIndex   uint8
	LocalStartTime uint32
	LocalEndTime   uint32
	OperatingMode  uint8
}

DoorLockHolidaySchedule is matter.js LockSchedule.Holiday (LockSchedule.ts:60-72).

type DoorLockUser added in v0.8.4

type DoorLockUser struct {
	UserIndex      uint16
	UserName       string
	UserUniqueID   *uint32 // nil is null
	UserStatus     uint8
	UserType       uint8
	CredentialRule uint8
	Credentials    []DoorLockCredentialRef
	// CreatorFabricIndex and LastModifiedFabricIndex are the fabrics that
	// created and last changed the user.
	CreatorFabricIndex      uint8
	LastModifiedFabricIndex uint8
	// ExpiringUserExpiresAt is the wall-clock deadline of an ExpiringUser
	// in Unix milliseconds, set on its first use; nil until then.
	ExpiringUserExpiresAt *int64
}

DoorLockUser is one entry of a lock's user database: matter.js LockAuth.User (LockAuth.ts:44-82).

type DoorLockWeekDaySchedule added in v0.8.4

type DoorLockWeekDaySchedule struct {
	WeekDayIndex uint8
	UserIndex    uint16
	DaysMask     uint8
	StartHour    uint8
	StartMinute  uint8
	EndHour      uint8
	EndMinute    uint8
}

DoorLockWeekDaySchedule is matter.js LockSchedule.WeekDay (LockSchedule.ts:17-38).

type DoorLockYearDaySchedule added in v0.8.4

type DoorLockYearDaySchedule struct {
	YearDayIndex   uint8
	UserIndex      uint16
	LocalStartTime uint32
	LocalEndTime   uint32
}

DoorLockYearDaySchedule is matter.js LockSchedule.YearDay (LockSchedule.ts:43-55): the window in local epoch seconds.

type DoorLocks added in v0.10.5

type DoorLocks interface {
	// LoadDoorLockAuth returns saved false until SaveDoorLockAuth ran for
	// the endpoint; users, credentials and schedules come back by index.
	LoadDoorLockAuth(ctx context.Context, endpointKey string) (auth DoorLockAuth, saved bool, err error)
	// SaveDoorLockAuth replaces the endpoint's records; a duplicate index
	// is refused.
	SaveDoorLockAuth(ctx context.Context, endpointKey string, auth DoorLockAuth) error
}

DoorLocks is the DoorLock server's user database, credentials and schedules, per endpoint. (The lock's credential key is a setting.)

type FabricRecord

type FabricRecord struct {
	// FabricIndex is the stack-assigned identifier in [1, 254]. The
	// special value 0 means "not yet assigned" — callers passing a
	// zero index to [Store.AddFabric] receive a freshly allocated one.
	FabricIndex uint8
	// FabricID is the 64-bit fabric identifier set by the commissioner.
	FabricID uint64
	// NodeID is the 64-bit operational node identifier of this bridge
	// inside the fabric.
	NodeID uint64
	// RootPublicKey is the trust anchor — the issuing root CA public
	// key in uncompressed P-256 form (65 bytes, 0x04 prefix). Cached
	// alongside RootCert so the CASE sigma key lookup +
	// CompressedFabricID HKDF (Matter §4.13.2.4) can skip the cert
	// decode on every Sigma1.
	RootPublicKey []byte
	// RootCert is the full Matter Certificate TLV envelope received via
	// AddTrustedRootCertificate (Matter §11.18.7.12). Mirrors matter.js
	// `Fabric.rootCert` (Fabric.ts:68); served verbatim as each entry
	// of OperationalCredentials.TrustedRootCertificates
	// (matter.js OperationalCredentialsServer.ts:470-472). Apple Home
	// validates every entry as a Matter Certificate TLV and silently
	// drops the entire ReportData stream on schema mismatch.
	//
	// May be nil on legacy fabric rows persisted before the 012
	// migration; those fabrics are omitted from TrustedRootCertificates
	// rather than re-served as the old EC-pubkey-as-cert (which
	// triggers Bug I again).
	RootCert []byte
	// VendorID is the 16-bit IANA-assigned vendor identifier embedded
	// in the NOC.
	VendorID uint16
	// Label is the user-visible fabric name (max 32 utf-8 chars per
	// Matter spec; not enforced here — that's a cluster-server concern).
	Label string
	// CompressedID is the 8-byte compressed fabric identifier
	// (HKDF over RootPublicKey + FabricID per §4.13.2.4).
	CompressedID [8]byte
}

FabricRecord mirrors the Fabric Descriptor from Matter Core Spec §11.18.5. fabric_index is stack-assigned (1..254); the remaining fields are commissioner-supplied or derived.

type Fabrics added in v0.10.5

type Fabrics interface {
	AddFabric(ctx context.Context, rec FabricRecord) (uint8, error)
	// GetFabric returns [ErrFabricNotFound] for an index the table does
	// not hold.
	GetFabric(ctx context.Context, fabricIndex uint8) (FabricRecord, error)
	// ListFabrics returns every fabric by index ascending.
	ListFabrics(ctx context.Context) ([]FabricRecord, error)
	UpdateFabricLabel(ctx context.Context, fabricIndex uint8, label string) error
	UpdateFabricVendorID(ctx context.Context, fabricIndex uint8, vendorID uint16) error
	UpdateFabricNodeID(ctx context.Context, fabricIndex uint8, nodeID uint64) error
	// RemoveFabric removes the fabric and every row it owns; see the
	// cascade above.
	RemoveFabric(ctx context.Context, fabricIndex uint8) error
}

Fabrics is the fabric table (Matter §11.18.5, FabricDescriptorStruct). AddFabric allocates the index from the persisted next-fabric-index counter when the record carries none.

type GroupKeyMapping

type GroupKeyMapping struct {
	FabricIndex   uint8
	GroupID       uint16
	GroupKeySetID uint16
}

GroupKeyMapping binds a GroupID to a GroupKeySetID inside a fabric (Matter §11.2.10.4 GroupKeyMap attribute).

type GroupKeySet

type GroupKeySet struct {
	FabricIndex    uint8
	GroupKeySetID  uint16
	SecurityPolicy SecurityPolicy
	EpochKey0      []byte
	EpochStart0    uint64
	EpochKey1      []byte // nil when slot empty
	EpochStart1    uint64
	EpochKey2      []byte // nil when slot empty
	EpochStart2    uint64
}

GroupKeySet mirrors a single (fabric, group_key_set_id) row in matter_group_keys. The three (EpochKey, EpochStart) pairs are independent: EpochKey1/2 are nil when the slot is empty.

type GroupKeys added in v0.10.5

type GroupKeys interface {
	UpsertGroupKeySet(ctx context.Context, rec GroupKeySet) error
	// GetGroupKeySet returns [ErrGroupKeySetNotFound] for a missing set.
	GetGroupKeySet(ctx context.Context, fabricIndex uint8, groupKeySetID uint16) (GroupKeySet, error)
	// ListGroupKeySets returns the fabric's sets by GroupKeySetID ascending.
	ListGroupKeySets(ctx context.Context, fabricIndex uint8) ([]GroupKeySet, error)
	// RemoveGroupKeySet removes the set and the key-map entries naming it.
	RemoveGroupKeySet(ctx context.Context, fabricIndex uint8, groupKeySetID uint16) error
	// RemoveGroupKeysByFabric removes every set and key-map entry of the
	// fabric.
	RemoveGroupKeysByFabric(ctx context.Context, fabricIndex uint8) error
	SetGroupKeyMapping(ctx context.Context, m GroupKeyMapping) error
	RemoveGroupKeyMapping(ctx context.Context, fabricIndex uint8, groupID uint16) error
	// ListGroupKeyMappings returns the fabric's key map by GroupID
	// ascending.
	ListGroupKeyMappings(ctx context.Context, fabricIndex uint8) ([]GroupKeyMapping, error)
}

GroupKeys is GroupKeyManagement's key sets and key map (Matter §11.2).

type GroupTableEntry added in v0.2.0

type GroupTableEntry struct {
	FabricIndex uint8
	GroupID     uint16
	GroupName   string
	Endpoints   []uint16
}

GroupTableEntry is one row of the group table: the endpoints of this node that are members of GroupID on FabricIndex, and the group's name (Matter §11.2.6.2 GroupInfoMapStruct). Endpoints keeps the order the endpoints joined in.

type GroupcastGroup added in v0.2.0

type GroupcastGroup struct {
	FabricIndex uint8
	GroupID     uint16
	// McastAddrPolicy is MulticastAddrPolicyEnum: 0 IanaAddr, 1 PerGroup.
	McastAddrPolicy uint8
	// HasAuxiliaryACL reports whether the group's listener endpoints carry
	// an auxiliary access control entry.
	HasAuxiliaryACL bool
}

GroupcastGroup is one row of matter_groupcast_groups: the Groupcast cluster's properties of one group of a fabric. Mirrors matter.js GroupcastServer GroupPropertiesStruct (GroupId, McastAddrPolicy, HasAuxiliaryAcl, FabricIndex).

type Groups added in v0.10.5

type Groups interface {
	// UpsertGroupTableEntry refuses an entry without endpoints.
	UpsertGroupTableEntry(ctx context.Context, e GroupTableEntry) error
	RemoveGroupTableEntry(ctx context.Context, fabricIndex uint8, groupID uint16) error
	// ListGroupTable returns the fabric's entries by GroupID ascending.
	ListGroupTable(ctx context.Context, fabricIndex uint8) ([]GroupTableEntry, error)
	UpsertGroupcastGroup(ctx context.Context, g GroupcastGroup) error
	RemoveGroupcastGroup(ctx context.Context, fabricIndex uint8, groupID uint16) error
	// ListGroupcastGroups returns the fabric's groups by GroupID ascending.
	ListGroupcastGroups(ctx context.Context, fabricIndex uint8) ([]GroupcastGroup, error)
}

Groups is the group table (GroupKeyManagement.GroupTable, the Groups cluster's membership) and the Groupcast cluster's groups. groups.Store is this area plus the fabric and key-set reads the group manager needs.

type ICD added in v0.12.0

type ICD interface {
	// ListICDRegistrations returns every fabric's registrations, by
	// fabric and then in the order they first registered.
	ListICDRegistrations(ctx context.Context) ([]ICDRegistration, error)
	// ReplaceICDRegistrations replaces one fabric's registrations; a
	// removed fabric takes its registrations along.
	ReplaceICDRegistrations(ctx context.Context, fabricIndex uint8, regs []ICDRegistration) error
	// LoadICDCounter returns ok false before the first SaveICDCounter.
	LoadICDCounter(ctx context.Context) (counter uint32, ok bool, err error)
	SaveICDCounter(ctx context.Context, counter uint32) error
}

ICD is the ICD Management server's nonvolatile state: the registered Check-In clients with their keys, per fabric, and the ICDCounter. A node that is no ICD never touches it.

type ICDRegistration added in v0.12.0

type ICDRegistration struct {
	FabricIndex      uint8
	CheckInNodeID    uint64
	MonitoredSubject uint64
	// Key is the 16-byte ICDToken the client registered.
	Key []byte
	// ClientType is ClientTypeEnum: 0 Permanent, 1 Ephemeral.
	ClientType uint8
}

ICDRegistration is one registered Check-In client of an ICD node: the RegisteredClients entry of the ICD Management cluster (quality "N", fabric-scoped) together with its ICDToken key, which matter.js keeps beside the attribute in the server's nonvolatile icdKeys (IcdManagementServer.ts:777-791).

type Identity added in v0.10.5

type Identity interface {
	UpsertIdentity(ctx context.Context, rec IdentityRecord) error
	// GetIdentity returns [ErrIdentityNotFound] for a fabric without one.
	GetIdentity(ctx context.Context, fabricIndex uint8) (IdentityRecord, error)
}

Identity is the node's operational identity on each fabric: NOC, ICAC, operational key and IPK.

type IdentityRecord

type IdentityRecord struct {
	// FabricIndex links this identity to matter_fabrics.fabric_index.
	FabricIndex uint8
	// NOC is the Node Operational Certificate bytes (Matter-cert TLV
	// per §11.18.5.2).
	NOC []byte
	// ICAC is the optional Intermediate CA certificate. nil means
	// the NOC is signed directly by the fabric root.
	ICAC []byte
	// PrivateKey is the 32-byte raw P-256 scalar matching the NOC's
	// public key. Persisted as-is; at-rest encryption is the
	// operator's responsibility.
	PrivateKey []byte
	// IPK is the 16-byte Identity Protection Key for this fabric
	// (used in CASE Sigma).
	IPK []byte
}

IdentityRecord is the per-fabric node operational credential bundle. One identity per fabric: the bridge has exactly one operational node per fabric.

type Migration added in v0.3.1

type Migration struct {
	// Version names the step: "v1", "v2", … in order. It is never reused
	// and a released step's text never changes.
	Version string
	// Up moves a database from the previous step to this one.
	Up string
	// Down reverts Up. It is DROP TABLE for an additive step and the
	// reverse rebuild for a rebuild. v3's Down is lossy: it restores the
	// foreign key from matter_group_key_map into matter_group_keys, so a
	// GroupKeyMap entry naming a key set that does not exist is dropped
	// rather than failing the step.
	Down string
}

Migration is one versioned step of the matter_* schema, for a host that runs its own migration tool and cannot call Apply (issue #62).

Up and Down are SQL scripts of one or more statements. A host embeds each step as one migration of its own tool, in Migrations order, and pins len(Migrations()) and the last Version: the next release's step then fails that pin at the dependency bump rather than at a live write.

func Migrations added in v0.3.1

func Migrations() []Migration

Migrations returns the schema's steps in order. Applied to an empty database one after the other, they produce the schema Apply produces — the same SchemaFingerprint — which TestMigrationsMatchApply holds. Schema stays the flattened form of the list, and Apply / Upgrade keep working as before.

type OTA added in v0.10.5

type OTA interface {
	// ListDefaultOTAProviders returns every fabric's entries, by fabric
	// and then in the order they were written.
	ListDefaultOTAProviders(ctx context.Context) ([]OTAProviderLocation, error)
	ReplaceDefaultOTAProviders(ctx context.Context, fabricIndex uint8, entries []OTAProviderLocation) error
	LoadOTARequestorState(ctx context.Context) (state []byte, ok bool, err error)
	SaveOTARequestorState(ctx context.Context, state []byte) error
}

OTA is the OTA Software Update Requestor's nonvolatile state: the fabric-scoped DefaultOTAProviders and the requestor's own encoding of the rest.

type OTAProviderLocation added in v0.3.0

type OTAProviderLocation struct {
	FabricIndex    uint8
	ProviderNodeID uint64
	Endpoint       uint16
}

OTAProviderLocation is one DefaultOTAProviders entry of the OTA Software Update Requestor (the ProviderLocation struct).

type Port added in v0.10.5

Port is the whole persistence port: every area. Store and store/memstore implement it; node.Config.Store.Credentials takes one.

type Privilege

type Privilege uint8

Privilege mirrors Matter §11.2.12 AccessControlEntryPrivilege.

const (
	PrivilegeView       Privilege = 1
	PrivilegeProxyView  Privilege = 2
	PrivilegeOperate    Privilege = 3
	PrivilegeManage     Privilege = 4
	PrivilegeAdminister Privilege = 5
)

Privilege values per Matter §11.2.12.

type Resumption added in v0.10.5

type Resumption interface {
	// UpsertResumption refuses a ResumptionID that is not 16 bytes and a
	// SharedSecret that is not 32.
	UpsertResumption(ctx context.Context, rec ResumptionRecord) error
	// GetResumptionByID and GetResumptionByPeer return
	// [ErrResumptionNotFound] on a miss.
	GetResumptionByID(ctx context.Context, resumptionID []byte) (ResumptionRecord, error)
	GetResumptionByPeer(ctx context.Context, fabricIndex uint8, peerNodeID uint64) (ResumptionRecord, error)
	RemoveResumption(ctx context.Context, fabricIndex uint8, peerNodeID uint64) error
	RemoveResumptionsByFabric(ctx context.Context, fabricIndex uint8) error
}

Resumption is the CASE session-resumption records, one per (fabric, peer), found by resumption id or by peer.

type ResumptionRecord

type ResumptionRecord struct {
	FabricIndex  uint8
	PeerNodeID   uint64
	ResumptionID []byte   // 16 bytes
	SharedSecret []byte   // 32 bytes (HKDF input for resumed sessions)
	CASEAuthTags []uint32 // optional; nil == no CATs (Matter §6.6.5.1)
}

ResumptionRecord is a CASE resumption-id row (Matter §4.13.2.4). One per (fabric, peer_node) pair; reused on every successful resumption.

CASEAuthTags carries the set of CASE Authenticated Tags extracted from the peer's operational certificate (Matter §6.6.5.1 / Core §4.13.2.2). Tags allow the responder to grant fabric-scoped ACL privilege to resumed sessions without re-validating the full NOC. Persisted as JSON in the `case_authenticated_tags` column (migration 010). An empty or nil slice means no CATs were present. matter.js ref: packages/protocol/src/session/case/

type SecurityPolicy

type SecurityPolicy uint8

SecurityPolicy mirrors Matter §11.2.10 GroupKeySecurityPolicy.

const (
	// SecurityPolicyTrustFirst (value 0) — trust the most recent
	// epoch first.
	SecurityPolicyTrustFirst SecurityPolicy = 0
	// SecurityPolicyCacheAndSync (value 1) — cache all three epoch
	// keys, sync via timing.
	SecurityPolicyCacheAndSync SecurityPolicy = 1
)

type ServerSubscriptions added in v0.10.5

type ServerSubscriptions interface {
	SaveServerSubscription(ctx context.Context, subscriptionID uint32, fabricIndex uint8, peerNodeID uint64, payload []byte) error
	DeleteServerSubscription(ctx context.Context, subscriptionID uint32) error
	DeleteServerSubscriptionsByFabric(ctx context.Context, fabricIndex uint8) error
	// LoadServerSubscriptions returns every payload, the least recently
	// saved first.
	LoadServerSubscriptions(ctx context.Context) ([][]byte, error)
	ClearServerSubscriptions(ctx context.Context) error
}

ServerSubscriptions is the server subscriptions of active CASE sessions, kept so they can be re-established after a restart (ADR 0008). The payload is opaque to the store.

type Settings added in v0.10.5

type Settings interface {
	GetSetting(ctx context.Context, key string) (value string, ok bool, err error)
	SetSetting(ctx context.Context, key, value string) error
	GetMetadataCounter(ctx context.Context, key string) (value uint64, ok bool, err error)
	SetMetadataCounter(ctx context.Context, key string, value uint64) error
}

Settings is the node's string settings and its counters. The keys are the callers' (the Setting… and MetadataKey… constants, each cluster's own); a counter is a uint64 at most 1<<62.

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store is the typed access surface over the matter_* tables defined in migration 006. The DB connection is supplied by the shared sqlite layer the host owns; this package never opens a database.

func New

func New(db *sql.DB) *Store

New returns a Store backed by db. The DB must already have the matter_* tables — typically because [sqlite.Open] applied migration 006 at startup.

func (*Store) AddFabric

func (s *Store) AddFabric(ctx context.Context, rec FabricRecord) (uint8, error)

AddFabric inserts a new fabric. If rec.FabricIndex is 0 the next free 1..254 slot is allocated; otherwise the caller's value is used (and the insert fails on collision).

Returns the assigned fabric_index. Returns ErrFabricExhausted when no free slot exists.

Index allocation follows the matter.js FabricManager #nextFabricIndex monotonic-counter strategy (FabricManager.ts:163-164,186-188): a persisted counter advances after each successful AddFabric so a freshly-removed index is not immediately reused — Apple Home caches fabric metadata by fabricIndex and may conflate old and new entries on rapid re-use. Falls back to the lowest-free-slot scan when the matter_metadata table is absent (pre-013 schema).

func (*Store) ClearServerSubscriptions added in v0.2.0

func (s *Store) ClearServerSubscriptions(ctx context.Context) error

ClearServerSubscriptions removes every row. The bridge calls it once it has loaded the former subscriptions at start-up — matter.js SubscriptionsServer.beginRun starts each run's record from empty.

func (*Store) DeleteServerSubscription added in v0.2.0

func (s *Store) DeleteServerSubscription(ctx context.Context, subscriptionID uint32) error

DeleteServerSubscription removes the row of subscriptionID. Idempotent.

func (*Store) DeleteServerSubscriptionsByFabric added in v0.2.0

func (s *Store) DeleteServerSubscriptionsByFabric(ctx context.Context, fabricIndex uint8) error

DeleteServerSubscriptionsByFabric removes every row of fabricIndex. Called when the fabric is removed.

func (*Store) GetFabric

func (s *Store) GetFabric(ctx context.Context, fabricIndex uint8) (FabricRecord, error)

GetFabric returns the fabric record for fabricIndex. Returns ErrFabricNotFound when no row exists.

func (*Store) GetGroupKeySet

func (s *Store) GetGroupKeySet(ctx context.Context, fabricIndex uint8, groupKeySetID uint16) (GroupKeySet, error)

GetGroupKeySet returns one key-set. Returns ErrGroupKeySetNotFound when no row exists.

func (*Store) GetIdentity

func (s *Store) GetIdentity(ctx context.Context, fabricIndex uint8) (IdentityRecord, error)

GetIdentity returns the identity for fabricIndex. Returns ErrIdentityNotFound when no row exists.

func (*Store) GetMetadataCounter

func (s *Store) GetMetadataCounter(ctx context.Context, key string) (value uint64, ok bool, err error)

GetMetadataCounter returns the persisted integer counter for key from matter_metadata. ok=false when the key has never been written.

func (*Store) GetResumptionByID

func (s *Store) GetResumptionByID(ctx context.Context, resumptionID []byte) (ResumptionRecord, error)

GetResumptionByID looks up a row by ResumptionID alone (the Sigma1 path, where the responder receives the ID before it knows which fabric/peer it points at).

func (*Store) GetResumptionByPeer

func (s *Store) GetResumptionByPeer(ctx context.Context, fabricIndex uint8, peerNodeID uint64) (ResumptionRecord, error)

GetResumptionByPeer looks up by (fabric_index, peer_node_id).

func (*Store) GetSetting

func (s *Store) GetSetting(ctx context.Context, key string) (value string, ok bool, err error)

GetSetting returns the persisted string for key. ok=false when the key has never been written (callers keep their configured default).

func (*Store) ListACL

func (s *Store) ListACL(ctx context.Context, fabricIndex uint8) ([]ACLEntry, error)

ListACL returns every ACE for fabricIndex ordered by position ascending.

func (*Store) ListDefaultOTAProviders added in v0.3.0

func (s *Store) ListDefaultOTAProviders(ctx context.Context) ([]OTAProviderLocation, error)

ListDefaultOTAProviders returns every fabric's DefaultOTAProviders entries, by fabric and then in the order they were written.

func (*Store) ListFabrics

func (s *Store) ListFabrics(ctx context.Context) ([]FabricRecord, error)

ListFabrics returns every fabric ordered by fabric_index ascending.

func (*Store) ListGroupKeyMappings

func (s *Store) ListGroupKeyMappings(ctx context.Context, fabricIndex uint8) ([]GroupKeyMapping, error)

ListGroupKeyMappings returns every (group_id → group_key_set_id) row for fabricIndex ordered by group_id ascending.

func (*Store) ListGroupKeySets

func (s *Store) ListGroupKeySets(ctx context.Context, fabricIndex uint8) ([]GroupKeySet, error)

ListGroupKeySets returns every key-set for fabricIndex ordered by group_key_set_id ascending.

func (*Store) ListGroupTable added in v0.2.0

func (s *Store) ListGroupTable(ctx context.Context, fabricIndex uint8) ([]GroupTableEntry, error)

ListGroupTable returns every group table row of fabricIndex ordered by group id ascending.

func (*Store) ListGroupcastGroups added in v0.2.0

func (s *Store) ListGroupcastGroups(ctx context.Context, fabricIndex uint8) ([]GroupcastGroup, error)

ListGroupcastGroups returns every row of fabricIndex ordered by group id.

func (*Store) ListICDRegistrations added in v0.12.0

func (s *Store) ListICDRegistrations(ctx context.Context) ([]ICDRegistration, error)

ListICDRegistrations returns every fabric's registrations, by fabric and then in the order they first registered.

func (*Store) LoadDoorLockAuth added in v0.8.4

func (s *Store) LoadDoorLockAuth(ctx context.Context, endpointKey string) (auth DoorLockAuth, saved bool, err error)

LoadDoorLockAuth returns the records of the lock endpoint endpointKey. saved is false when Store.SaveDoorLockAuth never ran for it; the lock then starts from its configured initial records.

func (*Store) LoadICDCounter added in v0.12.0

func (s *Store) LoadICDCounter(ctx context.Context) (counter uint32, ok bool, err error)

LoadICDCounter returns the ICDCounter SaveICDCounter stored last; ok is false before the first save.

func (*Store) LoadOTARequestorState added in v0.3.0

func (s *Store) LoadOTARequestorState(ctx context.Context) (state []byte, ok bool, err error)

LoadOTARequestorState returns what SaveOTARequestorState stored last; ok is false when nothing was stored.

func (*Store) LoadServerSubscriptions added in v0.2.0

func (s *Store) LoadServerSubscriptions(ctx context.Context) ([][]byte, error)

LoadServerSubscriptions returns every row's payload, oldest first.

func (*Store) LoadThermostatPresets added in v0.8.3

func (s *Store) LoadThermostatPresets(ctx context.Context, endpointKey string) (presets, activeHandle []byte, ok bool, err error)

LoadThermostatPresets returns what SaveThermostatPresets stored for the Thermostat endpoint endpointKey: the TLV encoding of its Presets list and its active preset handle (nil for none). ok is false when nothing was stored.

func (*Store) RemoveFabric

func (s *Store) RemoveFabric(ctx context.Context, fabricIndex uint8) error

RemoveFabric deletes the fabric and (via FK CASCADE) its node_identity, group_keys, group_key_map and acl_entries. Returns ErrFabricNotFound when no row exists.

func (*Store) RemoveGroupKeyMapping

func (s *Store) RemoveGroupKeyMapping(ctx context.Context, fabricIndex uint8, groupID uint16) error

RemoveGroupKeyMapping deletes a (fabric, group_id) binding.

func (*Store) RemoveGroupKeySet

func (s *Store) RemoveGroupKeySet(ctx context.Context, fabricIndex uint8, groupKeySetID uint16) error

RemoveGroupKeySet deletes one key-set together with the GroupKeyMap entries of the same fabric that name it, in one transaction. Mirrors matter.js GroupKeyManagementServer.keySetRemove, which filters those entries out of groupKeyMap (core§11.2.7.4.1). The map carries no foreign key to the key sets (an entry may name a set not written yet), so the removal is explicit rather than a cascade.

func (*Store) RemoveGroupKeysByFabric

func (s *Store) RemoveGroupKeysByFabric(ctx context.Context, fabricIndex uint8) error

RemoveGroupKeysByFabric deletes all key-sets and GroupKeyMap entries for fabricIndex. Called in the AddNOC failure rollback path after the fabric row exists but a subsequent step fails, so no orphaned key material persists for a fabric that never completed commissioning.

func (*Store) RemoveGroupTableEntry added in v0.2.0

func (s *Store) RemoveGroupTableEntry(ctx context.Context, fabricIndex uint8, groupID uint16) error

RemoveGroupTableEntry deletes the row of (fabricIndex, groupID). A missing row is not an error.

func (*Store) RemoveGroupcastGroup added in v0.2.0

func (s *Store) RemoveGroupcastGroup(ctx context.Context, fabricIndex uint8, groupID uint16) error

RemoveGroupcastGroup deletes the row of (fabricIndex, groupID). A missing row is not an error.

func (*Store) RemoveResumption

func (s *Store) RemoveResumption(ctx context.Context, fabricIndex uint8, peerNodeID uint64) error

RemoveResumption deletes a row. Idempotent.

func (*Store) RemoveResumptionsByFabric

func (s *Store) RemoveResumptionsByFabric(ctx context.Context, fabricIndex uint8) error

RemoveResumptionsByFabric deletes every resumption record bound to fabricIndex. Called from the OnFabricRemoved hook to clean up resumption state for a fabric that was just removed via RemoveFabric; mirrors chip src/credentials/FabricTable.cpp Delete() resumption teardown. Independent of the matter_fabrics FK so callers don't have to rely on SQLite's CASCADE behaviour for defense-in-depth.

func (*Store) ReplaceACL

func (s *Store) ReplaceACL(ctx context.Context, fabricIndex uint8, entries []ACLEntry) error

ReplaceACL atomically swaps the ACL of fabricIndex with entries. Position values are rewritten to be 0..len(entries)-1 in input order; callers do not need to set Position themselves.

func (*Store) ReplaceDefaultOTAProviders added in v0.3.0

func (s *Store) ReplaceDefaultOTAProviders(ctx context.Context, fabricIndex uint8, entries []OTAProviderLocation) error

ReplaceDefaultOTAProviders replaces fabricIndex's DefaultOTAProviders entries with entries, in order — the fabric-scoped list write, which leaves every other fabric's entries as they are. The entries' FabricIndex is ignored: they belong to fabricIndex.

func (*Store) ReplaceICDRegistrations added in v0.12.0

func (s *Store) ReplaceICDRegistrations(ctx context.Context, fabricIndex uint8, regs []ICDRegistration) error

ReplaceICDRegistrations replaces fabricIndex's registrations with regs, in order, leaving every other fabric's as they are. The entries' FabricIndex is ignored: they belong to fabricIndex. A removed fabric takes its registrations along.

func (*Store) SaveDoorLockAuth added in v0.8.4

func (s *Store) SaveDoorLockAuth(ctx context.Context, endpointKey string, auth DoorLockAuth) error

SaveDoorLockAuth replaces the records of the lock endpoint endpointKey with auth, in one transaction.

func (*Store) SaveICDCounter added in v0.12.0

func (s *Store) SaveICDCounter(ctx context.Context, counter uint32) error

SaveICDCounter stores the ICDCounter.

func (*Store) SaveOTARequestorState added in v0.3.0

func (s *Store) SaveOTARequestorState(ctx context.Context, state []byte) error

SaveOTARequestorState stores the requestor's encoded state.

func (*Store) SaveServerSubscription added in v0.2.0

func (s *Store) SaveServerSubscription(ctx context.Context, subscriptionID uint32, fabricIndex uint8, peerNodeID uint64, payload []byte) error

SaveServerSubscription inserts or replaces the row of subscriptionID.

func (*Store) SaveThermostatPresets added in v0.8.3

func (s *Store) SaveThermostatPresets(ctx context.Context, endpointKey string, presets, activeHandle []byte) error

SaveThermostatPresets replaces what is stored for the Thermostat endpoint endpointKey: presets is the TLV encoding of its Presets list, activeHandle its active preset handle (nil stores NULL, no active preset).

func (*Store) SetGroupKeyMapping

func (s *Store) SetGroupKeyMapping(ctx context.Context, m GroupKeyMapping) error

SetGroupKeyMapping upserts a GroupID → GroupKeySetID binding for fabricIndex. The fabric must exist (FK); the key set need not — see the matter_group_key_map comment in schema.sql.

func (*Store) SetMetadataCounter

func (s *Store) SetMetadataCounter(ctx context.Context, key string, value uint64) error

SetMetadataCounter upserts the integer counter for key in matter_metadata.

func (*Store) SetSetting

func (s *Store) SetSetting(ctx context.Context, key, value string) error

SetSetting upserts the persisted string for key.

func (*Store) UpdateFabricLabel

func (s *Store) UpdateFabricLabel(ctx context.Context, fabricIndex uint8, label string) error

UpdateFabricLabel rewrites the label for fabricIndex. Returns ErrFabricNotFound when no row exists.

func (*Store) UpdateFabricNodeID

func (s *Store) UpdateFabricNodeID(ctx context.Context, fabricIndex uint8, nodeID uint64) error

UpdateFabricNodeID rewrites the operational NodeID for fabricIndex. UpdateNOC installs a NOC that may carry a new NodeID for the same fabric; the stored row must follow so destinationID resolution and the operational mDNS instance name (<compressedID>-<nodeID>) match the new certificate. Mirrors matter.js Fabric.ts:548 lifting nodeId from the new NOC into the rebuilt fabric. Returns ErrFabricNotFound when no row exists.

func (*Store) UpdateFabricVendorID added in v0.2.0

func (s *Store) UpdateFabricVendorID(ctx context.Context, fabricIndex uint8, vendorID uint16) error

UpdateFabricVendorID rewrites the vendor id of fabricIndex — the VendorID a SetVIDVerificationStatement supplies, which matter.js Fabric.updateVendorVerificationData stores as the fabric's rootVendorId. Returns ErrFabricNotFound when no row exists.

func (*Store) UpsertGroupKeySet

func (s *Store) UpsertGroupKeySet(ctx context.Context, rec GroupKeySet) error

UpsertGroupKeySet inserts or replaces a key-set row. The fabric must already exist (FK constraint).

func (*Store) UpsertGroupTableEntry added in v0.2.0

func (s *Store) UpsertGroupTableEntry(ctx context.Context, e GroupTableEntry) error

UpsertGroupTableEntry inserts or replaces the row of (FabricIndex, GroupID). The fabric must exist (FK). An entry without endpoints is a caller error — a group whose last endpoint left is removed instead, as matter.js removeEndpoint does.

func (*Store) UpsertGroupcastGroup added in v0.2.0

func (s *Store) UpsertGroupcastGroup(ctx context.Context, g GroupcastGroup) error

UpsertGroupcastGroup inserts or replaces the row of (FabricIndex, GroupID). The fabric must exist (FK).

func (*Store) UpsertIdentity

func (s *Store) UpsertIdentity(ctx context.Context, rec IdentityRecord) error

UpsertIdentity inserts or replaces the identity row for rec.FabricIndex. The fabric must already exist (FK constraint).

func (*Store) UpsertResumption

func (s *Store) UpsertResumption(ctx context.Context, rec ResumptionRecord) error

UpsertResumption inserts or replaces the resumption row for (fabric_index, peer_node_id). CASEAuthTags is serialised as JSON; nil and empty slice both persist as '[]'.

type ThermostatPresetStore added in v0.8.3

type ThermostatPresetStore struct {
	// contains filtered or unexported fields
}

ThermostatPresetStore is the store of one Thermostat endpoint's presets — the thermo.PresetStore a host hands the Thermostat server (thermo.ThermostatConfig.PresetStore).

func NewThermostatPresetStore added in v0.10.5

func NewThermostatPresetStore(s ThermostatPresets, endpointKey string) *ThermostatPresetStore

NewThermostatPresetStore returns the preset store of the Thermostat endpoint endpointKey (the host's name for it — its StableKey) on s, any implementation of the ThermostatPresets area.

func (*ThermostatPresetStore) LoadPresets added in v0.8.3

func (p *ThermostatPresetStore) LoadPresets(ctx context.Context) (presets, activeHandle []byte, ok bool, err error)

LoadPresets is ThermostatPresets.LoadThermostatPresets for the store's endpoint.

func (*ThermostatPresetStore) SavePresets added in v0.8.3

func (p *ThermostatPresetStore) SavePresets(ctx context.Context, presets, activeHandle []byte) error

SavePresets is ThermostatPresets.SaveThermostatPresets for the store's endpoint.

type ThermostatPresets added in v0.10.5

type ThermostatPresets interface {
	LoadThermostatPresets(ctx context.Context, endpointKey string) (presets, activeHandle []byte, ok bool, err error)
	SaveThermostatPresets(ctx context.Context, endpointKey string, presets, activeHandle []byte) error
}

ThermostatPresets is the Thermostat server's persisted presets and active preset handle, per endpoint (the host's key for it).

Directories

Path Synopsis
Package memstore is the in-memory implementation of the persistence port store.Port: the second implementation beside SQLite's store.Store, held to the same contract by store/storetest.
Package memstore is the in-memory implementation of the persistence port store.Port: the second implementation beside SQLite's store.Store, held to the same contract by store/storetest.
Package storetest is the contract test of the persistence port store.Port.
Package storetest is the contract test of the persistence port store.Port.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL