💾 Archived View for code.pfad.fr › gohmekit › pairing captured on 2023-06-16 at 16:23:36. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-04-26)

➡️ Next capture (2024-07-09)

-=-=-=-=-=-=-

pairing package

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

package main

import (
	"net"
	"net/http"
	"time"

	"code.pfad.fr/gohmekit/pairing"
)

func main() {
	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 log.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, ed25519PrivateKey []byte) (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   log.Logger // github.com/go-kit/log.NewNopLogger() if you don't want any log

	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

Forge

https://codeberg.org/pfad.fr/gohmekit

git clone

https://codeberg.org/pfad.fr/gohmekit
git@codeberg.org:pfad.fr/gohmekit