Created
April 27, 2021 06:16
-
-
Save marcus-crane/76235a1c6a7740dc1e103b44ee16513a to your computer and use it in GitHub Desktop.
A python script for bulk deleting old devices
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Roughly based off https://gist.github.com/gbaman/b3137e18c739e0cf98539bf4ec4366ad | |
To grab your access token, log into https://accounts.firefox.com/settings | |
Open your browser dev tools (Right click -> Inspect Element), go to the Network tab | |
and refresh the page to populate the network stream. | |
Click on any one of the POST requests to https://graphql.accounts.firefox.com/graphql | |
and then under the Request Headers portion (at the bottom of the Headers tab), | |
copy the value for the Authorization Header. Just the token, not the Bearer text itself. | |
Paste that where it says "<token_goes_here>" and then you can run the script as normal | |
> pip install requests | |
> python3 delete-firefox-devices.py | |
Found 75 devices | |
Successfully detached Firefox Nightly on Google Pixel 3a | |
Successfully detached marcus’s Firefox Developer Edition on skeith | |
... | |
NOTE: The script may break if/when it detaches the browser you're actively in. | |
This seems to cause your token to be revoked causing a catch 22. | |
Feel free to log back in and continue on. | |
""" | |
import requests | |
token = "<token_goes_here>" | |
headers = { | |
"Content-Type": "application/json", | |
"Authorization": f"Bearer {token}" | |
} | |
def run_query(query, variables): | |
joined_query = {'query': query, 'variables': variables} | |
request = requests.post( | |
'https://graphql.accounts.firefox.com/graphql', | |
json=joined_query, | |
headers=headers) | |
res = request.json() | |
if 'errors' in res: | |
for error in res['errors']: | |
raise BaseException(error['message']) | |
else: | |
return res | |
deviceQuery = """ | |
{ | |
account { | |
attachedClients { | |
clientId | |
deviceId | |
name | |
sessionTokenId | |
refreshTokenId | |
} | |
} | |
} | |
""" | |
disconnectDeviceMutation = """ | |
mutation attachedClientDisconnect($input: AttachedClientDisconnectInput!) { | |
attachedClientDisconnect(input: $input) { | |
clientMutationId | |
__typename | |
} | |
} | |
""" | |
deviceResult = run_query(deviceQuery, {}) | |
attachedDevices = deviceResult['data']['account']['attachedClients'] | |
print(f"Found {len(attachedDevices)} devices") | |
for device in attachedDevices: | |
disconnectDeviceVariables = { | |
"input": { | |
"clientId": device['clientId'], | |
"deviceId": device['deviceId'], | |
"sessionTokenId": device['sessionTokenId'], | |
"refreshTokenId": device['refreshTokenId'] | |
} | |
} | |
detachResult = run_query(disconnectDeviceMutation, disconnectDeviceVariables) | |
if 'errors' in detachResult.keys(): | |
print("Error attempting to detach {}: {}".format(device['name'], detachResult['errors']['message'])) | |
else: | |
print('Successfully detached {}'.format(device['name'])) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment