@@ -67,22 +67,107 @@ def _get_header_client_id(self):
67
67
md5 .update (self ._device_identifier .encode ())
68
68
return base64 .b64encode (md5 .digest ()).decode ()
69
69
70
- def _get_hawk_authentication (self , rriot : RRiot , url : str ) -> str :
70
+ def _process_extra_hawk_values (self , values : dict | None ) -> str :
71
+ if values is None :
72
+ return ""
73
+ else :
74
+ sorted_keys = sorted (values .keys ())
75
+ result = []
76
+ for key in sorted_keys :
77
+ value = values .get (key )
78
+ result .append (f"{ key } ={ value } " )
79
+ return hashlib .md5 ("&" .join (result ).encode ()).hexdigest ()
80
+
81
+ def _get_hawk_authentication (
82
+ self , rriot : RRiot , url : str , formdata : dict | None = None , params : dict | None = None
83
+ ) -> str :
71
84
timestamp = math .floor (time .time ())
72
85
nonce = secrets .token_urlsafe (6 )
86
+ formdata_str = self ._process_extra_hawk_values (formdata )
87
+ params_str = self ._process_extra_hawk_values (params )
88
+
73
89
prestr = ":" .join (
74
90
[
75
91
rriot .u ,
76
92
rriot .s ,
77
93
nonce ,
78
94
str (timestamp ),
79
95
hashlib .md5 (url .encode ()).hexdigest (),
80
- "" ,
81
- "" ,
96
+ params_str ,
97
+ formdata_str ,
82
98
]
83
99
)
84
100
mac = base64 .b64encode (hmac .new (rriot .h .encode (), prestr .encode (), hashlib .sha256 ).digest ()).decode ()
85
- return f'Hawk id="{ rriot .u } ", s="{ rriot .s } ", ts="{ timestamp } ", nonce="{ nonce } ", mac="{ mac } "'
101
+ return f'Hawk id="{ rriot .u } ",s="{ rriot .s } ",ts="{ timestamp } ",nonce="{ nonce } ",mac="{ mac } "'
102
+
103
+ async def nc_prepare (self , user_data : UserData , timezone : str ) -> dict :
104
+ """This gets a few critical parameters for adding a device to your account."""
105
+ if (
106
+ user_data .rriot is None
107
+ or user_data .rriot .r is None
108
+ or user_data .rriot .u is None
109
+ or user_data .rriot .r .a is None
110
+ ):
111
+ raise RoborockException ("Your userdata is missing critical attributes." )
112
+ base_url = user_data .rriot .r .a
113
+ prepare_request = PreparedRequest (base_url )
114
+ hid = await self ._get_home_id (user_data )
115
+ from aiohttp import FormData
116
+
117
+ data = FormData ()
118
+ data .add_field ("hid" , hid )
119
+ data .add_field ("tzid" , timezone )
120
+
121
+ prepare_response = await prepare_request .request (
122
+ "post" ,
123
+ "/nc/prepare" ,
124
+ headers = {
125
+ "Authorization" : self ._get_hawk_authentication (
126
+ user_data .rriot , "/nc/prepare" , {"hid" : hid , "tzid" : timezone }
127
+ ),
128
+ },
129
+ data = data ,
130
+ )
131
+
132
+ if prepare_response is None :
133
+ raise RoborockException ("prepare_response is None" )
134
+ if not prepare_response .get ("success" ):
135
+ raise RoborockException (f"{ prepare_response .get ('msg' )} - response code: { prepare_response .get ('code' )} " )
136
+
137
+ return prepare_response ["result" ]
138
+
139
+ async def add_device (self , user_data : UserData , s : str , t : str ) -> dict :
140
+ """This will add a new device to your account
141
+ it is recommended to only use this if you know what you are doing."""
142
+ if (
143
+ user_data .rriot is None
144
+ or user_data .rriot .r is None
145
+ or user_data .rriot .u is None
146
+ or user_data .rriot .r .a is None
147
+ ):
148
+ raise RoborockException ("Your userdata is missing critical attributes." )
149
+ base_url = user_data .rriot .r .a
150
+ add_device_request = PreparedRequest (base_url )
151
+
152
+ add_device_response = await add_device_request .request (
153
+ "GET" ,
154
+ "/user/devices/newadd" ,
155
+ headers = {
156
+ "Authorization" : self ._get_hawk_authentication (
157
+ user_data .rriot , "/user/devices/newadd" , params = {"s" : s , "t" : t }
158
+ ),
159
+ },
160
+ params = {"s" : s , "t" : t },
161
+ )
162
+
163
+ if add_device_response is None :
164
+ raise RoborockException ("add_device is None" )
165
+ if not add_device_response .get ("success" ):
166
+ raise RoborockException (
167
+ f"{ add_device_response .get ('msg' )} - response code: { add_device_response .get ('code' )} "
168
+ )
169
+
170
+ return add_device_response ["result" ]
86
171
87
172
async def request_code (self ) -> None :
88
173
base_url = await self ._get_base_url ()
0 commit comments