Rewrite HomeKit client
This commit is contained in:
+53
-48
@@ -37,9 +37,9 @@ type Client struct {
|
||||
ClientPrivate []byte
|
||||
|
||||
OnEvent func(res *http.Response)
|
||||
Output func(msg any)
|
||||
//Output func(msg any)
|
||||
|
||||
conn net.Conn
|
||||
Conn net.Conn
|
||||
reader *bufio.Reader
|
||||
}
|
||||
|
||||
@@ -89,21 +89,21 @@ func (c *Client) Dial() (err error) {
|
||||
return false
|
||||
})
|
||||
|
||||
if c.conn, err = net.DialTimeout("tcp", c.DeviceAddress, ConnDialTimeout); err != nil {
|
||||
if c.Conn, err = net.DialTimeout("tcp", c.DeviceAddress, ConnDialTimeout); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
c.reader = bufio.NewReader(c.conn)
|
||||
c.reader = bufio.NewReader(c.Conn)
|
||||
|
||||
// STEP M1: send our session public to device
|
||||
sessionPublic, sessionPrivate := curve25519.GenerateKeyPair()
|
||||
|
||||
// 1. Send sessionPublic
|
||||
plainM1 := struct {
|
||||
PublicKey []byte `tlv8:"3"`
|
||||
PublicKey string `tlv8:"3"`
|
||||
State byte `tlv8:"6"`
|
||||
}{
|
||||
PublicKey: sessionPublic,
|
||||
PublicKey: string(sessionPublic),
|
||||
State: StateM1,
|
||||
}
|
||||
res, err := c.Post(PathPairVerify, MimeTLV8, tlv8.MarshalReader(plainM1))
|
||||
@@ -113,19 +113,19 @@ func (c *Client) Dial() (err error) {
|
||||
|
||||
// STEP M2: unpack deviceID from response
|
||||
var cipherM2 struct {
|
||||
PublicKey []byte `tlv8:"3"`
|
||||
EncryptedData []byte `tlv8:"5"`
|
||||
PublicKey string `tlv8:"3"`
|
||||
EncryptedData string `tlv8:"5"`
|
||||
State byte `tlv8:"6"`
|
||||
}
|
||||
if err = tlv8.UnmarshalReader(res.Body, &cipherM2); err != nil {
|
||||
return err
|
||||
}
|
||||
if cipherM2.State != StateM2 {
|
||||
return NewResponseError(plainM1, cipherM2)
|
||||
return newResponseError(plainM1, cipherM2)
|
||||
}
|
||||
|
||||
// 1. generate session shared key
|
||||
sessionShared, err := curve25519.SharedSecret(sessionPrivate, cipherM2.PublicKey)
|
||||
sessionShared, err := curve25519.SharedSecret(sessionPrivate, []byte(cipherM2.PublicKey))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -138,7 +138,7 @@ func (c *Client) Dial() (err error) {
|
||||
}
|
||||
|
||||
// 2. decrypt M2 response with session key
|
||||
b, err := chacha20poly1305.Decrypt(sessionKey, "PV-Msg02", cipherM2.EncryptedData)
|
||||
b, err := chacha20poly1305.Decrypt(sessionKey, "PV-Msg02", []byte(cipherM2.EncryptedData))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -146,7 +146,7 @@ func (c *Client) Dial() (err error) {
|
||||
// 3. unpack payload from TLV8
|
||||
var plainM2 struct {
|
||||
Identifier string `tlv8:"1"`
|
||||
Signature []byte `tlv8:"10"`
|
||||
Signature string `tlv8:"10"`
|
||||
}
|
||||
if err = tlv8.Unmarshal(b, &plainM2); err != nil {
|
||||
return
|
||||
@@ -156,7 +156,7 @@ func (c *Client) Dial() (err error) {
|
||||
// device session + device id + our session
|
||||
if c.DevicePublic != nil {
|
||||
b = Append(cipherM2.PublicKey, plainM2.Identifier, sessionPublic)
|
||||
if !ed25519.ValidateSignature(c.DevicePublic, b, plainM2.Signature) {
|
||||
if !ed25519.ValidateSignature(c.DevicePublic, b, []byte(plainM2.Signature)) {
|
||||
return errors.New("hap: ValidateSignature")
|
||||
}
|
||||
}
|
||||
@@ -172,10 +172,10 @@ func (c *Client) Dial() (err error) {
|
||||
// 2. generate payload
|
||||
plainM3 := struct {
|
||||
Identifier string `tlv8:"1"`
|
||||
Signature []byte `tlv8:"10"`
|
||||
Signature string `tlv8:"10"`
|
||||
}{
|
||||
Identifier: c.ClientID,
|
||||
Signature: b,
|
||||
Signature: string(b),
|
||||
}
|
||||
if b, err = tlv8.Marshal(plainM3); err != nil {
|
||||
return
|
||||
@@ -188,11 +188,11 @@ func (c *Client) Dial() (err error) {
|
||||
|
||||
// 4. generate request
|
||||
cipherM3 := struct {
|
||||
EncryptedData []byte `tlv8:"5"`
|
||||
EncryptedData string `tlv8:"5"`
|
||||
State byte `tlv8:"6"`
|
||||
}{
|
||||
State: StateM3,
|
||||
EncryptedData: b,
|
||||
EncryptedData: string(b),
|
||||
}
|
||||
if res, err = c.Post(PathPairVerify, MimeTLV8, tlv8.MarshalReader(cipherM3)); err != nil {
|
||||
return
|
||||
@@ -206,25 +206,25 @@ func (c *Client) Dial() (err error) {
|
||||
return
|
||||
}
|
||||
if plainM4.State != StateM4 {
|
||||
return NewResponseError(cipherM3, plainM4)
|
||||
return newResponseError(cipherM3, plainM4)
|
||||
}
|
||||
|
||||
// like tls.Client wrapper over net.Conn
|
||||
if c.conn, err = secure.Client(c.conn, sessionShared, true); err != nil {
|
||||
if c.Conn, err = secure.Client(c.Conn, sessionShared, true); err != nil {
|
||||
return
|
||||
}
|
||||
// new reader for new conn
|
||||
c.reader = bufio.NewReaderSize(c.conn, 32*1024) // 32K like default request body
|
||||
c.reader = bufio.NewReaderSize(c.Conn, 32*1024) // 32K like default request body
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Client) Close() error {
|
||||
if c.conn == nil {
|
||||
if c.Conn == nil {
|
||||
return nil
|
||||
}
|
||||
conn := c.conn
|
||||
c.conn = nil
|
||||
conn := c.Conn
|
||||
c.Conn = nil
|
||||
return conn.Close()
|
||||
}
|
||||
|
||||
@@ -234,23 +234,26 @@ func (c *Client) GetAccessories() ([]*Accessory, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ac Accessories
|
||||
if err = json.NewDecoder(res.Body).Decode(&ac); err != nil {
|
||||
var v JSONAccessories
|
||||
if err = json.NewDecoder(res.Body).Decode(&v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, accs := range ac.Accessories {
|
||||
for _, serv := range accs.Services {
|
||||
for _, char := range serv.Characters {
|
||||
char.AID = accs.AID
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ac.Accessories, nil
|
||||
return v.Value, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetCharacters(query string) ([]*Character, error) {
|
||||
func (c *Client) GetFirstAccessory() (*Accessory, error) {
|
||||
accs, err := c.GetAccessories()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(accs) == 0 {
|
||||
return nil, errors.New("hap: GetAccessories zero answer")
|
||||
}
|
||||
return accs[0], nil
|
||||
}
|
||||
|
||||
func (c *Client) GetCharacters(query string) ([]JSONCharacter, error) {
|
||||
res, err := c.Get(PathCharacteristics + "?id=" + query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -261,15 +264,15 @@ func (c *Client) GetCharacters(query string) ([]*Character, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ch Characters
|
||||
if err = json.Unmarshal(data, &ch); err != nil {
|
||||
var v JSONCharacters
|
||||
if err = json.Unmarshal(data, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ch.Characters, nil
|
||||
return v.Value, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetCharacter(char *Character) error {
|
||||
query := fmt.Sprintf("%d.%d", char.AID, char.IID)
|
||||
query := fmt.Sprintf("%d.%d", DeviceAID, char.IID)
|
||||
chars, err := c.GetCharacters(query)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -279,20 +282,21 @@ func (c *Client) GetCharacter(char *Character) error {
|
||||
}
|
||||
|
||||
func (c *Client) PutCharacters(characters ...*Character) error {
|
||||
var v JSONCharacters
|
||||
for i, char := range characters {
|
||||
if char.Event != nil {
|
||||
char = &Character{AID: char.AID, IID: char.IID, Event: char.Event}
|
||||
} else {
|
||||
char = &Character{AID: char.AID, IID: char.IID, Value: char.Value}
|
||||
}
|
||||
v.Value = append(v.Value, JSONCharacter{
|
||||
AID: 1,
|
||||
IID: char.IID,
|
||||
Value: char.Value,
|
||||
})
|
||||
characters[i] = char
|
||||
}
|
||||
data, err := json.Marshal(Characters{characters})
|
||||
body, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = c.Put(PathCharacteristics, MimeJSON, bytes.NewReader(data))
|
||||
_, err = c.Put(PathCharacteristics, MimeJSON, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -312,8 +316,9 @@ func (c *Client) GetImage(width, height int) ([]byte, error) {
|
||||
return io.ReadAll(res.Body)
|
||||
}
|
||||
|
||||
func (c *Client) LocalAddr() string {
|
||||
return c.conn.LocalAddr().String()
|
||||
func (c *Client) LocalIP() string {
|
||||
addr := c.Conn.LocalAddr().(*net.TCPAddr)
|
||||
return addr.IP.To4().String()
|
||||
}
|
||||
|
||||
func DecodeKey(s string) []byte {
|
||||
|
||||
Reference in New Issue
Block a user