-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[DO NOT MERGE] SRP POC #519
base: main
Are you sure you want to change the base?
Conversation
This new spr.py file only needs renault-api installed in the system (I tested it in WSL), so it does not depend on other files in this repository. There are also stacktraces in the output logs, this is due to issue 512 |
spr.py
Outdated
strExec = ( | ||
'renault-api --debug http get "/commerce/v1/accounts/' | ||
+ AccountId | ||
+ "/kamereon/kca/car-adapter/v1/cars/" | ||
+ vin | ||
+ '/res-state?country=RU"' | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this would be good to add to the recognised endpoints with some sample fixtures.
{
"data":{
"type":"ResState",
"id":"X7LHSRP1234567890",
"attributes":{
"details":"Stopped, ready for RES",
"code":"10"
}
}
}
res
might mean "Remote engine start"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: I think this would be useful to add to HA, independantly of the SRP methods
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't even fully know what it does, maybe it just checks if engine is ready to start
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems to work like this:
- GET
res-state
=> checks the state of the remote engine. I wonder what other codes are available. - POST
actions-srp-sets
=> starts authentication - GET
notifications
=> wait for authentication confirmation (actionType = COMMAND_RESPONSE) - GET
notifications
=> wait for authentication confirmation (actionType = SRP_SALT_REQUEST) - POST
actions-engine-start
=> send the actual start-engine command
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the number of notification responses could be different, sometimes you get the list of all jsons at once, sometimes it takes 3 notifications (especially if you don't do delays) to provide SRP_SALT_REQUEST. In the traces I had from the app, notifications with the result after step 5 took 6 notifications to provide the result.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
btw, res-state is just the state of the engine from what I see now:
- this returned when the engine is started and running
{"data":{"type":"ResState","id":"X7LABCD1234567890","attributes":{"details":"Running","code":"42"}}} - this returned when the engine is stopped
{'data': {'type': 'ResState', 'id': 'X7LABCD1234567890', 'attributes': {'details': 'Stopped, ready for RES', 'code': '10'}}}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's great - do you want to add these to RenaultVehicle class (ie. replicate the work from Lock-Status)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I can do that tomorrow.
stream = os.popen(strExec) | ||
# output = stream.read() | ||
time.sleep(5) | ||
|
||
output = " ".join(stream) | ||
output = output.replace('"', "") | ||
output = output.replace("'", "") | ||
output = output.replace(" ", "") | ||
|
||
ParseList1 = output.split("SrpSets,id:") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is very difficult to understand.
You should use JSON parsing utilities instead to convert it into an object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it was never supposed to be clean code, this was a dirty script according to my non-existing skills in python and time to spent of course.
I just replaced some of the quotation marks there to simplify the split() actions at some point, though it is not really required.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I know - I am just comparing your script with the traces you sent me previously and your parsing/splitting makes it hard to reconcile.
Maybe you need to adjust your commands to use renault-api --log --json http get/post
This should create log files (easier to share) and return json (easier to parse)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, so then I can just describe what is being parsed then:
- First step is GET res-state endpoint. Again not sure what it does, maybe resets the flow, maybe checks that engine is not started already. We don't parse there anything.
- At this step we start SRP auth. We generate so called "A" for srp based on SRP username and password, and send "A" in POST srp-sets. The length of this thing is 512 and servers checks this fact. For the POST to srp-sets, the server replies with the Notification ID, where we will then find the server result. So we need to parse the "id" in the bodyof POST response.
- Now we GET kmr notification endpoint with the id we received above. If the body response has Salt and LoginB, we try to parse them, if not - try the same GET kmr request again after a delay. Those Salt and LoginB are the Server's response for SRP, these are used to calculate the final SRP key (M in the code, but also called "srp" in the following http request)
- When we calculated M we can send it in the POST to engine-start. The request body has the command and M value inside the "srp" field. This is where the server can completely verify srp auth. Just like at the step 2, we don't get the server response immediately, but instead we get the "id" of the notification to check.
- We request the notification with that new id and see the response if it fails or not. If we don't find the command response, we try again after a delay.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was able to work out all that, but it is still much harder to read than if you used json :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean, come on! I basicaly googled every other line to write in python, don't make me do any of that :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't worry - I won't make you do that.
I'm still trying to do some tests on my side.
I try writing down the procedure, is this correct? But which is the raw url for "GET kmr notification"? And is this the javascript equivalent for SPR authentication?
A couple of SRP-related functions from here:
|
The URL for notifications is And from what I remember you can skip the last part after "kmr" and it will give you all your notifications in a single response. Regarding SRP implementation, there are different ones exist, and several exist for python. And it is known that the SRP protocol spec is not 100% strict for the implementation details, plus there were different versions and flavors on the market. This was never a big industry standard, though Apple used it with its own implementation and some other companies. So in the end, different SRP implementations will not work with each other just because they have minor differences in the way they calculate crypto payloads. I actually stumbled upon a github community that tried to fix this issue and list compatible ones, but they did not went too far and still had some questions on the spec interpretation. I don't think I can comment on your code, as I already forgot some of the details. But you can refer to my SRP sample - that's best of my previous understanding anyway. |
I don't understand if this pull request is currently working and if SRP authentication is requested also for lock-status or just for engine start. |
SRP is only required for remote engine start, and this PR provides reproducible steps for SRP authentication... but it doesn't work. Lock-status is working fine already, but is not supported by all vehicles. |
Did you already try with the ID provided in notifications, kmrUserId ? actionType: "COMMAND_RESPONSE" |
I think yes. |
I don't know how to install/use a not-accpeted PR. |
You just need this one file, download it at https://github.com/hacf-fr/renault-api/blob/2c003ef0634b8b0f1c69621c400abdb6cd98aecd/spr.py To run it you also need renault-api installed. I don't remember exactly, but maybe you also need this srp library installed. |
Which values did you test as "pin"? |
That's my pin code from the Renault app. This pin code is required by the app when starting engine or locking the doors. |
@jumpjack, I think that if the Renault app doesn't allow you to start the engine or to lock the doors, then you won't be able to test it with any integration... |
Received an "unimplemented" error rather than a "forbidden" error would be already a good result, there are a couple of dozens of restricted endpoints to test!
https://gitlab.com/tobiaswkjeldsen/dartnissanconnect/-/issues/1 |
No description provided.