mirror of
https://github.com/MeshCore-Beacon/beacon-server.git
synced 2026-09-02 00:58:22 +00:00
73 lines
2.3 KiB
Go
73 lines
2.3 KiB
Go
// Copyright 2026 Beacon Contributors
|
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
// Package keystore provides channel key lookup for the ingest pipeline.
|
|
// Keys are loaded from config at startup and never written at runtime.
|
|
// Future: add a DB-backed fallback that checks the channel_keys table.
|
|
package keystore
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
)
|
|
|
|
// Entry holds a resolved channel key along with its metadata.
|
|
type Entry struct {
|
|
Key []byte // raw key bytes (16 bytes for hashtag channels)
|
|
Fingerprint []byte // first 8 bytes of SHA256(key)
|
|
Hashtag string // set if derived from a hashtag, empty otherwise
|
|
Name string // display name, may be empty
|
|
}
|
|
|
|
// MapKeyStore maps channel hash hex → list of known key entries.
|
|
// Multiple entries per hash are supported to handle 1-byte hash collisions.
|
|
type MapKeyStore struct {
|
|
entries map[string][]Entry // channel hash hex → entries
|
|
}
|
|
|
|
// NewMapKeyStore creates a keystore from a pre-built map of entries.
|
|
// Use BuildFromConfig to construct entries from a config.ChannelKeysConfig.
|
|
func NewMapKeyStore(entries map[string][]Entry) *MapKeyStore {
|
|
store := &MapKeyStore{entries: make(map[string][]Entry)}
|
|
for hash, list := range entries {
|
|
store.entries[hash] = append(store.entries[hash], list...)
|
|
}
|
|
return store
|
|
}
|
|
|
|
// GetKey returns all known key entries for the given channel hash byte.
|
|
// Returns nil if no keys are known for this hash.
|
|
func (s *MapKeyStore) GetKey(channelHash []byte) []Entry {
|
|
return s.entries[hex.EncodeToString(channelHash)]
|
|
}
|
|
|
|
// DeriveHashtagKey derives the channel secret and hash for a hashtag name.
|
|
//
|
|
// secret = SHA256("#" + tag)[:16]
|
|
// channel_hash = SHA256(secret)[0]
|
|
// fingerprint = SHA256(secret)[:8]
|
|
func DeriveHashtagKey(tag string) (secret []byte, channelHash byte, fingerprint []byte) {
|
|
input := sha256.Sum256([]byte("#" + tag))
|
|
secret = input[:16]
|
|
secretHash := sha256.Sum256(secret)
|
|
channelHash = secretHash[0]
|
|
fingerprint = secretHash[:8]
|
|
return
|
|
}
|
|
|
|
// Fingerprint returns the first 8 bytes of SHA256(key).
|
|
func Fingerprint(key []byte) []byte {
|
|
h := sha256.Sum256(key)
|
|
return h[:8]
|
|
}
|
|
|
|
func EntryExists(entries []Entry, e Entry) bool {
|
|
for _, existing := range entries {
|
|
if bytes.Equal(existing.Key, e.Key) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|