Skip to content
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

Lock codes not working and not able to edit/delete in Schlage app #56

Open
AxelTheGerman opened this issue Apr 19, 2023 · 33 comments
Open

Comments

@AxelTheGerman
Copy link

Hi @dknowles2 apologies for logging an issue against this library, but I used it to write a Ruby equivalent and having issues - was wondering if you had the same at some point.

I can authorize against Schlage API no problem, retrieve existing locks and codes as well. However, when I create lock codes they are visible in the user's Schlage app but A) the code doesn't work on the lock and B) the user is unable to edit or delete the codes created.

I'm not getting any errors creating the codes, and the JSON looks the exact same as other existing codes.

Have you ever noticed anything like that? Any pointers where to look?

@dknowles2
Copy link
Owner

Oh, that's interesting. I've actually never tried to use a code created through my library! 🤣

I just tried this myself and it does indeed not work. Let me go dig through my decompiled Android app again and see if I can find a clue.

@dknowles2
Copy link
Owner

Nice catch. It appears I'm calling the wrong endpoint. I guess this one just stores the code in the cloud database and doesn't sync it to the lock? Why on earth is that even there?!?

It looks like the correct endpoint is /devices/{device_id}/commands with a payload of {"name": "addaccesscode", "data": <access code object>}. The other commands are "updateaccesscode", "deleteaccesscode" and "deleteallaccesscodes".

I tried this out on one of my locks and it appears to work.

Thanks for the heads-up! I'll have a patch here shortly. (I just happened to be fixing a different problem with the library anyway)

@AxelTheGerman
Copy link
Author

AxelTheGerman commented Apr 19, 2023

Why on earth is that even there?!?

I stopped asking myself those questions a long time ago 😂

But thanks for tracking that down and again, thank you for the amazing work of sharing that knowledge.

I'll leave the issue open until your patch, but already know what I need to do for my Ruby implementation.

Edit: But now the /storage part in the previous URL makes sense - still not sure what for though

@AxelTheGerman
Copy link
Author

AxelTheGerman commented Apr 20, 2023

BTW I also noticed that I was getting 504 Gateway Timeout from time to time creating new codes - wondering how quickly this usually works with the app. Or if the point of the "storage" is to add the codes to the lock first and then "activate" them or something...

EDIT: and also a 502 Bad Gateway with the response body {"errorCode":36,"errorMessage":""} when trying to update an access code 🤔 you don't happen to see some kind of error codes in the decompiled app, do you?

@AxelTheGerman
Copy link
Author

Also seeing 502 Bad Gateway and {"errorCode":2,"errorMessage":""} when creating codes sometimes - not sure if there's something wrong with the payload but as I'm getting some kind of code I guess it might

@JLSone
Copy link

JLSone commented Mar 28, 2024

@dknowles2 I'm new to this lock, and not a skilled coder, but I have managed to create access codes using your program. however, I'm having the same issues as @AxelTheGerman where I can't edit or delete the codes within the app. And I'm struggling with the "delete" feature (which may have more to do with my own limitations in python than anything else...) but wondering what the status of this is... Thanks!

@robnewton
Copy link

@dknowles2 This appears to be happening to me as well. I can create access codes through the library however they do not function on the lock and when I try to edit them in the app I get an error: "Access code required", despite an access code obviously being present.

I've used ProxyMan on iOS with a cert for SSL MITM to see what I can see but it appears they're using SSL pinning to prevent it. It's a bit more difficult on iOS (without jailbreaking) to get an idea of what the payloads look like for any endpoints on api.allegion.yonomi.cloud.

I was able to see some traffic on api.allegionengage.com which I've provided below incase this helps to know firmware versions.

https://api.allegionengage.com/api/firmware/be489wifi2?page=1&sni=1

[
  {
    "name": "release.bin",
    "description": "Performance Improvements.",
    "deviceType": "be489wifi2",
    "extendedVersion": "10.0",
    "isPublic": false,
    "releaseDate": "2024-06-17T09:08:17",
    "version": "4.0.815524",
    "links": [
      {
        "href": "https://fws.lockwebserv.com/firmware-container/be489wifi2_4.0.815524_release.bin",
        "rel": "self"
      }
    ]
  },
  ...
]

@AxelTheGerman
Copy link
Author

Just FYI as I originally reported the issue. I have moved on to a commercial offering that has worked great in general. It is called Seam

While I hope libraries like this succeed as folks should be able to freely access their own devices, I am in need of a commercially viable path and therefore better off using a commercial alternative.

@robnewton
Copy link

robnewton commented Jul 16, 2024

Thanks @AxelTheGerman

I am aware of Seam but hoping to see an open source alternative so figured I'd give it a little effort first.

@dknowles2

The app using SSL pinning made it complicated but I was able to get around it in an Android emulator with Frida. I had to write a script to bypass the root detector as well since the app just throws a message and exits without it on a rooted device.

So once I got all that setup, this is what I see for adding a new access code with a temporary schedule.

Adding An Access Code

POST

https://api.allegion.yonomi.cloud/v1/devices/{device_id}/commands

Payload Body

{
  "name": "addaccesscode",
  "data": {
    "accessCode": {access_code},
    "accessCodeLength": 4,
    "schedule1": {
      "startHour": 0,
      "startMinute": 0,
      "endHour": 23,
      "endMinute": 59,
      "daysOfWeek": "7F"
    },
    "disabled": 0,
    "notificationEnabled": 1,
    "expirationSecs": 1721695980,
    "activationSecs": 1721091180,
    "friendlyName": "07/19 Rob Test HA-123456"
  }
}

POST

https://api.allegion.yonomi.cloud/v1/notifications?deviceId={device_id}

Payload Body

{
  "notificationDefinitionId": "onunlockstateaction",
  "devicetypeId": "{device_type_id}",
  "notificationId": "{notification_id}",
  "active": true,
  "filterValue": "07/19 Rob Test HA-123456",
  "deviceId": "{device_id}",
  "userId": "{user_id}",
  "createdAt": "2024-07-16T04:54:20.648Z",
  "updatedAt": "2024-07-16T04:54:20.648Z"
}

Here's some screenshots from the app to correlate screen data to the API call.

@robnewton
Copy link

@dknowles2

I modified the same access code and here's what was recorded.

POST

https://api.allegion.yonomi.cloud/v1/devices/{device_id}/commands

Payload Body

{
  "name": "updateaccesscode",
  "data": {
    "accessCode":{access_code},
    "accessCodeLength": 4,
    "schedule1": {
      "startHour": 0,
      "startMinute": 0,
      "endHour": 23,
      "endMinute": 59,
      "daysOfWeek": "7F"
    },
    "disabled": 0,
    "notificationEnabled": 1,
    "expirationSecs": 1721695980,
    "activationSecs": 1721091180,
    "friendlyName": "07/19 Rob Test HA-123457",
    "accesscodeId": "{access_code_id}"
  }
}

PUT

https://api.allegion.yonomi.cloud/v1/notifications/{notfication_id}

Payload Body

{
  "notificationDefinitionId": "onunlockstateaction",
  "devicetypeId": "{device_type_id}",
  "notificationId": "{notificaiton_id}",
  "active": true,
  "filterValue": "07/19 Rob Test HA-123457"
}

@dknowles2
Copy link
Owner

Thanks! That's super helpful.

When you created the access code, did you happen to notice if the notificationId passed to the /notifciations endpoint match the accesscodeId returned by the "addaccesscode" call? My assumption would be that they would match, otherwise I'm not sure how the access code would be tied to the notification request.

@dknowles2
Copy link
Owner

Based on inspection of my existing notifications, it seems the notificationId is {user_id}_{access_code_id}. Easy enough.

@robnewton
Copy link

I was wondering where the notification id was coming from but didn't have time to dive in so nice catch.

I started a fork and began the improvements required but got busy and haven't gotten back to it. I think some of the code organization is based upon shared urls that are not shared anymore. Might make sense to rethink it.

I'm up for a quick rewrite if you'd like a hand.

@dknowles2
Copy link
Owner

I've got it mostly done already. I'll try and get back to it later tonight

@robnewton
Copy link

Dang, nice work man. Let me know how I can help. I'm available the rest of the night and some of tomorrow. I can also do some real world testing after my guests leave at 11am ET tomorrow if you need.

@robnewton
Copy link

@dknowles2 Would you mind committing what you have to a branch? I'd like to finish this up tonight but would prefer not to duplicate effort.

If you're able to do that, I can get the last bit coded for you then tested on my locks tonight. Happy to do that on a fork from your branch or you can grant me access, whichever works.

@dknowles2
Copy link
Owner

@robnewton I just pushed the PR that should fix this. There's still some tests that I need to update, but I think this fixes most everything. Let me know if this doesn't work and I can take another look later this week. (or send a PR! 😄)

@robnewton
Copy link

Taking a look now! Thanks man. If I see anything that doesn't work I will go ahead and fix it and put in a PR. Appreciate your work on this

@robgwi
Copy link

robgwi commented Jul 30, 2024

Was anything changed in the recent update? I was following your posts, and had the same issues others were having about the user codes not working with the lock, but showing up in the schlage app. I just updated my source from git, and now having issues with connectivity. keeps saying bad gateway, and it appears I cannot ping api.schlage.com, did the url change for the API?

@dknowles2
Copy link
Owner

Was anything changed in the recent update? I was following your posts, and had the same issues others were having about the user codes not working with the lock, but showing up in the schlage app. I just updated my source from git, and now having issues with connectivity. keeps saying bad gateway

Bad gateway could mean a few different things. What model lock do you have?

and it appears I cannot ping api.schlage.com, did the url change for the API?

That's never been the API endpoint, and being able to ping it doesn't really tell you much.

@robgwi
Copy link

robgwi commented Jul 31, 2024

Weird, I found the correct API url, which I am able to ping to. All my locks are Schlage encode, the previous version before git pull worked flawless with the exception of me stumbling to figure out why codes entered using API never worked, thankfully these other guys on here determined the cause. But now doesn't connect.

@robgwi
Copy link

robgwi commented Aug 26, 2024

@dknowles2 can you give me a bit of help? since your latest update I cannot seem to create users using the API. This is the info I'm sending to the API. I've read the docs, updated my code to reflect the changes, but continue to get failed. I don't see any other way to contact you, other than through an issue.

Updated,

[2024-08-26 11:38:00,135] INFO in views: API Request to add user code: {
"name": "addaccesscode",
"data": {
"accessCode": "9909",
"accessCodeLength": 4,
"schedule1": {
"startHour": 0,
"startMinute": 0,
"endHour": 23,
"endMinute": 59,
"daysOfWeek": "7F"
},
"disabled": 0,
"notificationEnabled": 0,
"expirationSecs": 4294967295,
"activationSecs": 0,
"friendlyName": "hannah"
}
}
Failed to add user code: Bad Gateway

@dknowles2
Copy link
Owner

@robgwi What model of lock do you have?

@robgwi
Copy link

robgwi commented Aug 30, 2024 via email

@robgwi
Copy link

robgwi commented Sep 11, 2024

@dknowles2 Still looking for some assistance.

@dknowles2
Copy link
Owner

Sorry, I don't have time to debug this much further right now. It's also hard to debug without your specific lock model.

The most recent changes were based on sniffing the HTTP traffic from an android emulator running the Schlage app. https://httptoolkit.com/ makes this really easy--you just need to grab an android emulator to run (it's bundled with https://developer.android.com/studio)

If you can do that and give the output of adding/editing/removing access codes (like #56 (comment)) the fix will probably be fairly straightforward.

@robgwi
Copy link

robgwi commented Sep 11, 2024

@dknowles2 in my last message, I said they are all Schlage Encode WIFI locks, I can read everything, I can lock/unlock, but when I go to create a new user i get "bad gatewy" Where can I share some code for you to look at? Here is the post your are looking for

https://api.allegion.yonomi.cloud/v1/devices/{device_id}/commands

2024-08-26 11:38:00,135] INFO in views: API Request to add user code: {
"name": "addaccesscode",
"data": {
"accessCode": "9909",
"accessCodeLength": 4,
"schedule1": {
"startHour": 0,
"startMinute": 0,
"endHour": 23,
"endMinute": 59,
"daysOfWeek": "7F"
},
"disabled": 0,
"notificationEnabled": 0,
"expirationSecs": 4294967295,
"activationSecs": 0,
"friendlyName": "hannah"
}
}
Failed to add user code: Bad Gateway

@robgwi
Copy link

robgwi commented Sep 30, 2024

{
"name": "addaccesscode",
"data": {
"accessCode": {access_code},
"accessCodeLength": 4,
"schedule1": {
"startHour": 0,
"startMinute": 0,
"endHour": 23,
"endMinute": 59,
"daysOfWeek": "7F"
},
"disabled": 0,
"notificationEnabled": 1,
"expirationSecs": 1721695980,
"activationSecs": 1721091180,
"friendlyName": "07/19 Rob Test HA-123456"
}
}

@robnewton can you help me figure out the android emulator and friday, I tried this but everytime i get the schlage app on an emulator i get some "app detected securiy threat" and closes, i assume this is the ssl pinning.

@robnewton
Copy link

robnewton commented Sep 30, 2024

@robgwi

I will try to take a look at it. I think Frida is still configured on my laptop. The key though is to use Frida with scripts that rewrite parts of the app to remove those security checks at runtime to overcome the ssl pinning and root detection.

@robgwi
Copy link

robgwi commented Sep 30, 2024

@robnewton If you can share those scripts that would be helpful, been pounding my head on the desk here for days... trying to get my application to add access codes, I can do everything else, I have tried numerous emulator's in Android studio, tried http toolkit proxy, but never get successful. You can [e] mail me at rcguentherwi {@} google email software. Thanks.

@robnewton
Copy link

@dknowles2

I'm getting a 502 Gateway error when trying to add a code now. I tried to get the emulator with Frida back up and running but something isn't working and I don't have the time to dive into it.

Are you seeing the same thing?

Traceback (most recent call last):

  File "/tmp/__pdg__/dist/python/pyschlage/auth.py", line 60, in wrapper
    resp.raise_for_status()

  File "/nano-py/pkgs/requests/models.py", line 960, in raise_for_status
    raise HTTPError(http_error_msg, response=self)

requests.exceptions.HTTPError: 502 Server Error: Bad Gateway for url: https://api.allegion.yonomi.cloud/v1/devices/[...]/commands



...
lock.add_access_code(AccessCode(

  File "/tmp/__pdg__/dist/python/pyschlage/lock.py", line 374, in add_access_code
    code.save()

  File "/tmp/__pdg__/dist/python/pyschlage/code.py", line 247, in save
    resp = self._device.send_command(command, self.to_json())
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  File "/tmp/__pdg__/dist/python/pyschlage/device.py", line 67, in send_command
    return self._auth.request("post", path, json=json)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  File "/tmp/__pdg__/dist/python/pyschlage/auth.py", line 67, in wrapper
    raise UnknownError(message) from ex

pyschlage.exceptions.UnknownError: Bad Gateway

@robnewton
Copy link

Here's a CuRL of what the library is attempting when it gets a 502

curl -X POST 'https://api.allegion.yonomi.cloud/v1/devices/[...]/commands' -H 'X-Api-Key: hnuu9jbbJr7MssFDWm5nU2Z7nG5Q5rxsaqWsE7e9' -H 'Authorization: Bearer eyJ...ew' -H 'Content-Type: application/json' -d '{"data": {"friendlyName": "Rob Test Code", "accessCode": 1020, "notification": 0, "disabled": 0, "activationSecs": 1743710400, "expirationSecs": 1743796800, "schedule1": {"daysOfWeek": "7F", "startHour": 0, "startMinute": 0, "endHour": 23, "endMinute": 59}}, "name": "addaccesscode"}'

@rockymountainnative
Copy link

I have also been unable to create new access codes which have yielded the same/similar 502 responses as above.

Doing some digging around, I am seeing that the Schlage mobile app's POST for commands is different than what the library currently does. After doing some changes, I have been able to get this to work, although, I am remote to the property so I am unable to check if the lock actually works after successfully adding it through the API.

Here is my PR that attempts to fix the error:
#203

Please be kind, this is my first open source change, so there are many things I might be missing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants