pairing package - code.pfad.fr/gohmekit
import "code.pfad.fr/gohmekit/pairing"
Constants
const ContentType = "application/pairing+tlv8"
Functions
func NewEncryptableDialer
func NewEncryptableDialer(dial func(ctx context.Context, network string, address string) (net.Conn, error)) (dialContext func(ctx context.Context, network string, address string) (net.Conn, error), encrypt func(sharedKey [32]byte) error)
NewEncryptableDialer should be used for homekit client, to wrap a (&net.Dialer{...}).DialContext (see Example).
Example
dial, encrypt := pairing.NewEncryptableDialer((&net.Dialer{
Timeout: 5 * time.Second,
KeepAlive: 5 * time.Second,
}).DialContext)
httpClient := http.Client{
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: dial,
ForceAttemptHTTP2: false,
MaxIdleConns: 1,
IdleConnTimeout: 5 * time.Second,
TLSHandshakeTimeout: 5 * time.Second,
ExpectContinueTimeout: 5 * time.Second,
},
}
// do whatever you need with the httpClient
// call encrypt(sharedKey) to encrypt further communications.
_ = encrypt
_ = httpClient
func NewRandomPairingID
func NewRandomPairingID() []byte
NewRandomPin generates a random 48-bits pairingID.
func NewRandomPin
func NewRandomPin() string
NewRandomPin generates a random pin (XXX-XX-XXX).
func WithIdentify
func WithIdentify(cb func()) option
WithIdentify allows to specify a function to call when the device should physically identify itself (before pairing).
func WithLogger
func WithLogger(logger *slog.Logger) option
WithLogger adds structured logging to the pairing server.
Types
type AccessoryDevice
type AccessoryDevice interface {
Device
SRPSession() (sess AccessorySRPSession, salt []byte, err error)
}
AccessoryDevice interface must be implemented by the accessory to support pairing.
func NewDeviceWithPin
func NewDeviceWithPin(deviceID []byte, pin string, privateKey ed25519.PrivateKey) (AccessoryDevice, error)
NewDeviceWithPin creates a new AccessoryDevice with the given id, pin and private key.
type AccessorySRPSession
type AccessorySRPSession interface {
PublicKey() []byte
PairSetupSharedSecret([]byte) ([]byte, error)
ExchangeProof([]byte) ([]byte, bool)
}
type Controller
type Controller struct {
PairingID []byte
LongTermPublicKey []byte
}
Controller is used to store the devices in the Database.
type Database
type Database interface {
IsPaired() bool
GetLongTermPublicKey([]byte) ([]byte, error)
AddLongTermPublicKey(Controller) error
RemoveLongTermPublicKey(id []byte) error
ListLongTermPublicKey() ([]Controller, error)
}
Database interface for the accessory to store its state.
type Device
type Device interface {
PairingID() []byte
Ed25519Sign([]byte) ([]byte, error)
OwnLongTermPublicKey() []byte
}
Device interface must be implemented by the controller to support pairing.
type HTTPServer
type HTTPServer struct {
Identify func() // when called, the device must identify itself (by sound, light...)
Logger *slog.Logger
Device AccessoryDevice
Database Database
// contains filtered or unexported fields
}
HTTPServer must be created with NewServer and can be adjusted afterwards.
func NewServer
func NewServer(server *http.Server, device AccessoryDevice, db Database, options ...option) *HTTPServer
NewServer creates a new pairing server. Once the accessory is paired, it will forward all decrypted communications to the given server.
func (*HTTPServer) ListenAndServe
func (srv *HTTPServer) ListenAndServe() error
ListenAndServe listens on the TCP network address of the underlying http.Server (server.Addr) and then calls Serve to handle requests on incoming connections.
If the address is blank, ":http" is used.
ListenAndServe always returns a non-nil error. After Shutdown or Close, the returned error is ErrServerClosed.
func (*HTTPServer) Listener
func (srv *HTTPServer) Listener() (net.Listener, error)
Listener returns a new listener on the TCP network address of the underlying http.Server (server.Addr).
If the address is blank, ":http" is used.
func (*HTTPServer) Serve
func (srv *HTTPServer) Serve(ln net.Listener) error
Serve accepts incoming connections on the Listener l, creating a new service goroutine for each.
Serve always returns a non-nil error and closes l. After Shutdown or Close, the returned error is ErrServerClosed.
func (*HTTPServer) Shutdown
func (srv *HTTPServer) Shutdown(ctx context.Context) error
Shutdown gracefully shuts down the underlying http.Server.
type VerifyClientController
type VerifyClientController struct {
// contains filtered or unexported fields
}
VerifyClientController implements the client logic for the pairing-verify step.
func NewVerifyClientController
func NewVerifyClientController(client Device, database Database) (*VerifyClientController, error)
NewVerifyClientController implements the client logic for the pairing-verify step.
func (VerifyClientController) FinishRequest
func (c VerifyClientController) FinishRequest(r io.Reader) (response []byte, sharedSecret []byte, err error)
FinishRequest checks the accessory initial response and generate the finish request.
func (VerifyClientController) FinishResponse
func (c VerifyClientController) FinishResponse(r io.Reader) error
FinishResponse checks the response of the accessory. From now on, the connection must be encrypted using the sharedSecret computed in the FinishRequest step.
func (VerifyClientController) StartRequest
func (c VerifyClientController) StartRequest() []byte
StartRequest is the initial pairing-verify request.
Files
conn.go
database.go
device.go
dial.go
kltv.go
listener.go
pair_setup.go
pair_verify.go
pairings.go
server.go
verify_client_controller.go
Directories
crypto
Breadcrumb
code.pfad.fr/gohmekit