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

All Requests are Failing with "Request Failed with status 400 - Bad Request" Even with Updated Key #233

Open
BigThunderSR opened this issue Sep 27, 2023 · 262 comments

Comments

@BigThunderSR
Copy link
Contributor

All requests are failing with "Request Failed with status 400 - Bad Request". Updated key in #232 does not seem to make a difference.

@Maliron
Copy link

Maliron commented Sep 27, 2023

Why are they SOOO upset that we can interface with their API faster than the terrible MyGMC/Chevrolet app? The apps are so incredibly slow, it is so much faster to bring is all in to HomeAssistant and use that for remote starting and such. We seem to lose access to the API every couple weeks though. This really sucks.

Do we know if this is them shutting us out of the API or simply them changing it? I believe the API is not officially documented or open and this was all reverse engineered right?

@LightningManGTS
Copy link

LightningManGTS commented Sep 28, 2023

I started doing the homeassitant > node red implementation myself because of gm dropping support for google home (big thanks Bigthundersr by the way). The least they can do is not be insufferable about their API access when their own web developers can't code their website to unhide authenticator elements properly.

@tbclark3
Copy link

Why are they SOOO upset that we can interface with their API faster than the terrible MyGMC/Chevrolet app? The apps are so incredibly slow, it is so much faster to bring is all in to HomeAssistant and use that for remote starting and such. We seem to lose access to the API every couple weeks though. This really sucks.

I also like the API being faster, but it's so much more than that. Integrating into Home Assistant lets me issue a warning if we arm the security system at night while the car is still plugged in (don't want it to catch fire while we're asleep) or early in the morning if I forgot to charge it. It sends me an email to put air in the tires if needed. I'm on my second Bolt, but if GM doesn't want me to use the API, I will switch to a different brand when my lease is up in a couple of months.

@BennyDaBee
Copy link

@joelvandal @coelho I know you two were a big help with the last big issue we had, anything you guys would be able to take a look at?

@LightningManGTS
Copy link

Is "appId" and "appSecret" in src/onStarAppConfig.json something we should be making unique in every deployment of this library like device UUID's? Is it possible that all these unique instances are showing up as one "device" and then that's what causing it to get blocked? (due to the total number and frequency of requests?)

I ask not being too familiar with how the reverse engineering works.

My only other question is, what if we ask GM directly? or is there enough trepidation that they would outright deny this by making it harder for the api requests to function? https://www.onstar.com/business-solutions/api-data-services

@BrettEBowman
Copy link

All requests are failing with "Request Failed with status 400 - Bad Request". Updated key in #232 does not seem to make a difference.

@BigThunderSR: I think that #232 was updated earlier today (Monday, 10/2/23) with another new key pair. Have you been able to test if that gets it working again?

@BigThunderSR
Copy link
Contributor Author

All requests are failing with "Request Failed with status 400 - Bad Request". Updated key in #232 does not seem to make a difference.

@BigThunderSR: I think that #232 was updated earlier today (Monday, 10/2/23) with another new key pair. Have you been able to test if that gets it working again?

I tried it earlier today even though I knew it wouldn't work either and it did not work as expected.

We need @samrum and others to figure out what changed in the API and make the necessary modifications to OnStarJS to make things work again. Thanks.

@BrettEBowman
Copy link

BrettEBowman commented Oct 2, 2023 via email

@BennyDaBee
Copy link

Between #214 and #208, I am trying to get SSL pinning setup to be able to see the requests in real time. Having issues getting the app just to work on Genymotion

@BennyDaBee
Copy link

Yea I cant even get the normal app to work on Genymotion before I add anything else to the "device". Any help would be appreciated.

@BrettEBowman
Copy link

Flespi.com seems to have a [Changelog] general-motors-onstar protocol.

The last entry there (from 4 days ago) says:

general-motors-onstar protocol has been updated, new parameters added:

EHPE - flespi name position.accuracy
AGEIND - flespi name position.valid

That probably does indicate/confirm that there was a recent change to the OnStar API. Those items seems to only relate to getting location, not the authentication call. But maybe it is at least some clue.

@nilathedragon
Copy link
Contributor

I think the reason for the 400 / bad_application is that they now require the X-Firebase-AppCheck header on the auth endpoints for the request to go through.

The value for that header comes from that thing:

@BennyDaBee
Copy link

Im working on getting a Android device to root. I am an iOS person myself so I did not have any on hand. I should have one tonight/tomorrow to be able to test.

@Maliron
Copy link

Maliron commented Oct 9, 2023

I don't think it's all about the Google app-check blocking us. GM does offer partner API access for fleets. I've reached out their business fleet API people and asked if there is any free API access include for personal use with our OnStar membership. We'll if they reply. I seem to recall applying for GM API access before and never hearing back.

@nilathedragon
Copy link
Contributor

The thing is this project uses (sort of) public client credentials from their android app, fleet customers will have their own credentials that come with their own rules applied to them. I have tried and I know that passing a valid app-check token in that Firebase header will make the token request work again.

My guess is that GM saw that people were using this reverse engineered API for free and they looked for a quick way to put an end to that by adding app check. I guess thats also why its only on the token endpoint. No token, no service.

@Maliron
Copy link

Maliron commented Oct 9, 2023

That is the pits.. It's such a small subset of users you'd really think it shouldn't be a bit deal to them. I'm sure what they are worried about is someone making money off it. What would be nice is if we could get our own private set of client credentials we could use based off our OnStar subscription. That way it would be unique for each of us, and they wouldn't have to worry, and we'd have our own private API access. I can't see them making a code change like that out of the kindness of their hearts for such a small subset of users though.

@Maliron
Copy link

Maliron commented Oct 9, 2023

Just spitballing here, I was able to sign up for the GM developers site for making in vehicle apps, I wonder if we can get a client ID for access to the API by "designing" an in vehicle app? I've requested commercial API access through there as well now, I won't be holding my breath though.

@BigThunderSR
Copy link
Contributor Author

Thanks much @nilathedragon, #234 has fixed the issue (until OnStar finds another way to block us out again)!!!

@BennyDaBee
Copy link

@nilathedragon Just for future issues that may arise, how did you go about the SSL Pinning to grab the request credentials for iOS?

@nilathedragon
Copy link
Contributor

I do all my iOS work using Frida and Objection. You are able to get around their SSL pinning easily using one of the publicly available Frida scripts.

I chose a different route though, I hooked the systems cryptography API's and caught the credentials there. Once again, there are publicly available Frida scripts for this too :)

@jianyu-li
Copy link

Thanks @nilathedragon !

@Maliron
Copy link

Maliron commented Oct 10, 2023

Thank you @nilathedragon !! Good job! I can confirm, I recreated my containers and re-pulled with bigthundersr/onstar2mqtt:latest and all is right in the world again. Hopefully one day GM will let us get access to our own personal client id for personal use and we can do this offically,

@stamanf
Copy link

stamanf commented Oct 11, 2023

Also back in business. Thanks everyone, happy again 👍👍

@BigThunderSR
Copy link
Contributor Author

BigThunderSR commented Oct 12, 2023

@nilathedragon, could you please see if there is a new key available? The issue is back again this morning, but this time as a 403 - Forbidden. Thanks!

@nilathedragon
Copy link
Contributor

As far as I can see, there was no update to the iOS app. Last updated Oct. 2nd

So they must flag something else. I will look into it.

@evilpig
Copy link

evilpig commented Dec 18, 2024

Okay yeah, everything was working fine yesterday and just stopped today. Haven't changed anything, other than now uploading a new microsoft_tokens file. Don't see a gm_tokens.json though.

I deleted all files and even tried a new folder.

Reinstalled the addon, still no luck.

I appreciate all the work you guys do. Not sure whats wrong here.
image

@BigThunderSR
Copy link
Contributor Author

Okay yeah, everything was working fine yesterday and just stopped today. Haven't changed anything, other than now uploading a new microsoft_tokens file. Don't see a gm_tokens.json though.

I deleted all files and even tried a new folder.

Reinstalled the addon, still no luck.

I appreciate all the work you guys do. Not sure whats wrong here.

@evilpig see below:
image

@evilpig
Copy link

evilpig commented Dec 19, 2024

Okay yeah, everything was working fine yesterday and just stopped today. Haven't changed anything, other than now uploading a new microsoft_tokens file. Don't see a gm_tokens.json though.
I deleted all files and even tried a new folder.
Reinstalled the addon, still no luck.
I appreciate all the work you guys do. Not sure whats wrong here.

@evilpig see below: !)
@BigThunderSR

Here you go. Same folders I've been using for a month so not much has changed. Unless I need to use that full path in the plugin? /root/homeassistant/ssl/vehicle1

image

EDIT: Ah, I am dumb, had it in the wrong directory. moved it to root/ssl. I think I made this same mistake last time. It works again!

@BigThunderSR
Copy link
Contributor Author

BigThunderSR commented Dec 19, 2024

Okay yeah, everything was working fine yesterday and just stopped today. Haven't changed anything, other than now uploading a new microsoft_tokens file. Don't see a gm_tokens.json though.
I deleted all files and even tried a new folder.
Reinstalled the addon, still no luck.
I appreciate all the work you guys do. Not sure whats wrong here.

@evilpig see below: !)
@BigThunderSR

Here you go. Same folders I've been using for a month so not much has changed. Unless I need to use that full path in the plugin? /root/homeassistant/ssl/vehicle1

image

This confirms my original suspicion of what you were doing by putting the tokens in the wrong directory path. I cannot explain how it worked before, so let's not bother going down that path (no pun intended). The bottom line is that your directory path is incorrect. Please look at the full path in my screenshot and compare it to what you have and you will hopefully see the issue.

@BigThunderSR
Copy link
Contributor Author

@evilpig, please beware that "/root/ssl" is currently symbolically linked to "/ssl", but if the HA folks change their file system links like they have in the past on occasion, things will break again for you. Therefore, I recommend that you update your notes to place the token in "/ssl/vehicle1" and not in "/root/ssl/vehicle1" .

@Frazou1
Copy link

Frazou1 commented Dec 19, 2024

Are you aware each time i reboot HA, the token expired and i need the regenetare a new one ?

@BigThunderSR
Copy link
Contributor Author

Are you aware each time i reboot HA, the token expired and i need the regenetare a new one ?

How are you running HA? I run HA in a VM and don't have any issues even if I restart the HA VM.

@ericvandamme
Copy link

Are you aware each time i reboot HA, the token expired and i need the regenetare a new one ?

How are you running HA? I run HA in a VM and don't have any issues even if I restart the HA VM.

I have this issue only when restarting the Onstar2Mqtt Add-on. It does appear to have a problem pulling the existing token and refreshing it. It seems to want to start a new authentication session using the fake TOTP I have entered in order for it to get going again.

@Frazou1
Copy link

Frazou1 commented Dec 19, 2024

Same thing, i run into a VM HA.

@Frazou1
Copy link

Frazou1 commented Dec 19, 2024

Oh found something, the file rename as .OLD himself !
image

@BigThunderSR
Copy link
Contributor Author

Oh found something, the file rename as .OLD himself !
image

I just installed the HAOS 14.1 update which rebooted my HA VM and everything came back online after the VM rebooted, so I cannot replicate your issues.

@BigThunderSR
Copy link
Contributor Author

Are you aware each time i reboot HA, the token expired and i need the regenetare a new one ?

How are you running HA? I run HA in a VM and don't have any issues even if I restart the HA VM.

I have this issue only when restarting the Onstar2Mqtt Add-on. It does appear to have a problem pulling the existing token and refreshing it. It seems to want to start a new authentication session using the fake TOTP I have entered in order for it to get going again.

I restarted my HA add-on multiple times, but cannot replicate this issue.

@ericvandamme
Copy link

Perhaps this is helpful. When this happens, this is what I start to get:

error: Error Polling Data: {"error":{"error":{"message":"Request Failed with status 504 - Gateway Timeout","request":{"method":"POST"},"response":{"data":"","headers":{"cache-control":"no-store","connection":"keep-alive","content-length":"0","date":"Wed, 18 Dec 2024 07:03:21 GMT","pragma":"no-cache","request-context":"appId=cid-v1:UUID"},"status":504,"statusText":"Gateway Timeout"},"stack":"Error: Request Failed with status 504 - Gateway Timeout\n    at RequestService.<anonymous> (/app/node_modules/onstarjs2/dist/index.cjs:41321:32)\n    at Generator.throw (<anonymous>)\n    at rejected (/app/node_modules/onstarjs2/dist/index.cjs:44:65)\n    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)"}},"timestamp":"2024-12-18 02:03:21"}
info: pollingStatusTopicState: homeassistant/VIN/polling_status/state {"timestamp":"2024-12-18 02:33:04"}
info: pollingStatusTopicTF, homeassistant/VIN/polling_status/lastpollsuccessful {"timestamp":"2024-12-18 02:33:04"}
info: Requesting diagnostics {"timestamp":"2024-12-18 02:33:04"}
Returned GM API token was missing vehicle information. Deleting existing tokens for reauth.
Authentication failed: Error: Only TOTP via "Third-Party Authenticator" is currently supported by this implementation. Please update your OnStar account to use this method, if possible.
    at GMAuth.<anonymous> (/app/node_modules/onstarjs2/dist/index.cjs:40666:23)
    at Generator.next (<anonymous>)
    at fulfilled (/app/node_modules/onstarjs2/dist/index.cjs:43:58)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
Request Error: Only TOTP via "Third-Party Authenticator" is currently supported by this implementation. Please update your OnStar account to use this method, if possible.
Authentication failed: Error: Only TOTP via "Third-Party Authenticator" is currently supported by this implementation. Please update your OnStar account to use this method, if possible.
    at GMAuth.<anonymous> (/app/node_modules/onstarjs2/dist/index.cjs:40666:23)
    at Generator.next (<anonymous>)
    at fulfilled (/app/node_modules/onstarjs2/dist/index.cjs:43:58)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

@BigThunderSR
Copy link
Contributor Author

Perhaps this is helpful. When this happens, this is what I start to get:

error: Error Polling Data: {"error":{"error":{"message":"Request Failed with status 504 - Gateway Timeout","request":{"method":"POST"},"response":{"data":"","headers":{"cache-control":"no-store","connection":"keep-alive","content-length":"0","date":"Wed, 18 Dec 2024 07:03:21 GMT","pragma":"no-cache","request-context":"appId=cid-v1:UUID"},"status":504,"statusText":"Gateway Timeout"},"stack":"Error: Request Failed with status 504 - Gateway Timeout\n    at RequestService.<anonymous> (/app/node_modules/onstarjs2/dist/index.cjs:41321:32)\n    at Generator.throw (<anonymous>)\n    at rejected (/app/node_modules/onstarjs2/dist/index.cjs:44:65)\n    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)"}},"timestamp":"2024-12-18 02:03:21"}
info: pollingStatusTopicState: homeassistant/VIN/polling_status/state {"timestamp":"2024-12-18 02:33:04"}
info: pollingStatusTopicTF, homeassistant/VIN/polling_status/lastpollsuccessful {"timestamp":"2024-12-18 02:33:04"}
info: Requesting diagnostics {"timestamp":"2024-12-18 02:33:04"}
Returned GM API token was missing vehicle information. Deleting existing tokens for reauth.
Authentication failed: Error: Only TOTP via "Third-Party Authenticator" is currently supported by this implementation. Please update your OnStar account to use this method, if possible.
    at GMAuth.<anonymous> (/app/node_modules/onstarjs2/dist/index.cjs:40666:23)
    at Generator.next (<anonymous>)
    at fulfilled (/app/node_modules/onstarjs2/dist/index.cjs:43:58)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
Request Error: Only TOTP via "Third-Party Authenticator" is currently supported by this implementation. Please update your OnStar account to use this method, if possible.
Authentication failed: Error: Only TOTP via "Third-Party Authenticator" is currently supported by this implementation. Please update your OnStar account to use this method, if possible.
    at GMAuth.<anonymous> (/app/node_modules/onstarjs2/dist/index.cjs:40666:23)
    at Generator.next (<anonymous>)
    at fulfilled (/app/node_modules/onstarjs2/dist/index.cjs:43:58)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

This part is returned by @metheos code, so hoping he can provide some pointers as to what you may be doing to cause this:

Returned GM API token was missing vehicle information. Deleting existing tokens for reauth.

@metheos
Copy link

metheos commented Dec 19, 2024

@ericvandamme The GM token that gets issued using the microsoft token should contain vehicle VINs for the vehicles it's allowed to access. If those are missing it assumes there was an issue and tries to reauthenticate to get all new tokens. I'm not sure why your token would not contain VIN information if there isn't some kind of account issue.

@ericvandamme
Copy link

I am not entirely sure either. It is pretty stable and the refresh token looks fairly long lived that I shouldn't be recreating tokens to have it continue to work approximately weekly. I do have long periods of 504 gateway timeouts in the evening. I tried adjusting the polling from 30 minutes to 1 hour in case I was hitting limits; but 504 is a pretty consistent problem in the evening.

@BigThunderSR
Copy link
Contributor Author

I am not entirely sure either. It is pretty stable and the refresh token looks fairly long lived that I shouldn't be recreating tokens to have it continue to work approximately weekly. I do have long periods of 504 gateway timeouts in the evening. I tried adjusting the polling from 30 minutes to 1 hour in case I was hitting limits; but 504 is a pretty consistent problem in the evening.

The 504 errors aren't strictly related to the authentication process related to the tokens. FWIW, I was getting 504's when I was trying to replicate your issue as well as the one above.

@ericvandamme
Copy link

What I will try to do is catch it when it needs a new token because the old one fails. My logs don't go back far enough to view what happened before I needed a new token and that might provide more insight. TBF, this is more of a nuisance, but the Microsoft token is so much handier than being dead in the water until the keys were update and the fix is relatively easy to rectify.

@dexameth
Copy link

I think they are working on trying to get the Third Party App piece working for Canadian Customers. I got an email from the case I started a while back about it that it's been referred to Tier 3 support a couple of days ago. I tried to enable it today, and the site is no longer linking out to the microsoft site when trying to enable third party auth app. It's also not reenabling the email authentication like it used to. I've also been needing to update my token file every couple of days for the last week due to "Failed to extract csrf token or transId during MFA" errors. Deleting the "gm_tokens.json" and "microsoft_tokens.json" and placing the new token file resolves it.

@LeBizz333
Copy link

@dexameth I think you're right that they are working on the Canadian side of their service. I have had the same behaviour where they seem to be revoking my token every 2-3 days. I even had high hopes a few days ago when I had a 48 hour period where every single request went through without errors. Reaction time was pretty snappy too (around 15 seconds).

@sargelavoie
Copy link

@dexameth This is a great news. I tried myself to change the MFA option for my account, but I was redirected to the microsoft site like usual. Just for the record, i have communicated with GM last week, and I have received this feedback: "J'apprécie beaucoup vos efforts. Je comprends l'importance de cette fonction pour vous. Sur base des informations fournies, il m'a été suggèré que vous en discutiez avec le département OnStar. Ils seront en mesure de clarifier les détails de cette fonction. Vous pouvez les joindre au 1-888-466-7827. Je reste à votre disposition en cas de besoin ultérieur". Do you thinks I should reply back, or I am wasting my time?

@Frazou1
Copy link

Frazou1 commented Dec 20, 2024

@BigThunderSR i found a command to grep info in a log and put a put a binary sensor on and off. ```binary_sensor:

  • platform: command_line
    command: if grep -i 'Fatal read error on socket transport' .homeassistant/home-assistant.log >/dev/null; then echo ON; else echo OFF; fi``` Where is located the log file of the addon ?

@BigThunderSR
Copy link
Contributor Author

@BigThunderSR i found a command to grep info in a log and put a put a binary sensor on and off. ```binary_sensor:

  • platform: command_line
    command: if grep -i 'Fatal read error on socket transport' .homeassistant/home-assistant.log >/dev/null; then echo ON; else echo OFF; fi``` Where is located the log file of the addon ?

The add-on logs for any add-on aren't directly accessible through the HA shell since they are all running in different Docker containers which is why I said this is not something simple to implement.

@jpenns
Copy link

jpenns commented Dec 20, 2024 via email

@dexameth
Copy link

@metheos Does your token that gets generated contain your VIN in the string in plain text? My error is a bit different than Eric's

Returned GM API token was missing vehicle information. Deleting existing tokens for reauth.
reqer
Response data: <title>Object moved</title>

Object moved to here.

HTTP Error 302: Moved Temporarily Authentication failed: Error: Failed to extract csrf token or transId during MFA at GMAuth. (/app/node_modules/onstarjs2/dist/index.cjs:40648:23) at Generator.next () at fulfilled (/app/node_modules/onstarjs2/dist/index.cjs:43:58) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) Request Error: Failed to extract csrf token or transId during MFA Authentication failed: Error: Failed to extract csrf token or transId during MFA at GMAuth. (/app/node_modules/onstarjs2/dist/index.cjs:40648:23) at Generator.next () at fulfilled (/app/node_modules/onstarjs2/dist/index.cjs:43:58) at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

@metheos
Copy link

metheos commented Dec 22, 2024

The gm token contains the vin in the jwt payload. Not exactly plaintext, but not encrypted.

@Maliron
Copy link

Maliron commented Dec 22, 2024

So I've been out of the loop and there is a lot of back and forth and troubleshooting here. Is there a guide somewhere on what we need to do to get things working again? If I understand things, GM is forcing OAUTH now, so we need to use some external method to generate a refresh token OnStarJS can use to send requests and receive data. Is that the gist of it?

@Maliron
Copy link

Maliron commented Dec 22, 2024

OK, so to answer my own question it's fairly summed up here: https://github.com/BigThunderSR/OnStarJS?tab=readme-ov-file#new-requirement-as-of-2024-11-19

The basics of it are enable authenticator app through the OnStar web portal (I had to disable email before I could enable anything else), use an authenticator app that allows you to copy the secret, I used Stratum. Then add that key to the config either in the HA Addon or the OnStar2MQTT app. Poof it works again! Thanks everyone!

@rproudfoot
Copy link

I can't seem to get it to work. Canadian account using email MFA. Generated the Microsoft token and stored it in /ssl/vehicle1 verified it's in the root folder. I get this error when starting the addon.

[13:59:38] INFO: Starting OnStar2MQTT for ****...

[email protected] start
node src/index.js
info: OnStar Config: {"onstarConfig":{"allowCommands":true,"checkRequestStatus":true,"deviceId":""","onStarPin":"####","onStarTOTP":"","password":"","refreshInterval":2500000,"requestPollingIntervalSeconds":600,"requestPollingTimeoutSeconds":90,"tokenLocation":"/ssl/vehicle1","username":"[email protected]","vin":""},"timestamp":"2024-12-23 13:59:39"}
info: MQTT Config: {"mqttConfig":{"host":"homeassistant.local","listAllSensorsTogether":false,"namePrefix":"","password":"********","pollingStatusTopic":"","port":1883,"prefix":"homeassistant","rejectUnauthorized":true,"tls":false,"username":"
**"},"timestamp":"2024-12-23 13:59:39"}
info: !-- Starting OnStar2MQTT Polling --! {"timestamp":"2024-12-23 13:59:39"}
info: Requesting vehicles {"timestamp":"2024-12-23 13:59:39"}
Authentication failed: Error: Token expired and no refresh token available.
at GMAuth. (/app/node_modules/onstarjs2/dist/index.cjs:41007:27)
at Generator.next ()
at /app/node_modules/onstarjs2/dist/index.cjs:46:71
at new Promise ()
at __awaiter (/app/node_modules/onstarjs2/dist/index.cjs:42:12)
at GMAuth.loadMSToken (/app/node_modules/onstarjs2/dist/index.cjs:40959:16)
at GMAuth. (/app/node_modules/onstarjs2/dist/index.cjs:40578:49)
at Generator.next ()
at /app/node_modules/onstarjs2/dist/index.cjs:46:71
at new Promise ()
error: Main function error: {"error":{"message":"Token expired and no refresh token available."},"timestamp":"2024-12-23 13:59:39"}

@thib5
Copy link

thib5 commented Dec 29, 2024

Hey it work great on my side but i have to regenerate the token about once a week... do you know how could i fix that ? ( reminder: i'm Canadian and can't use totp )

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