aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xextract_token_from_browser.py98
1 files changed, 52 insertions, 46 deletions
diff --git a/extract_token_from_browser.py b/extract_token_from_browser.py
index 5db183f..37549b4 100755
--- a/extract_token_from_browser.py
+++ b/extract_token_from_browser.py
@@ -15,6 +15,7 @@ import sys
from pathlib import Path
from secretstorage.exceptions import SecretStorageException
from sqlite3 import OperationalError
+
try:
import_err = None
from Crypto.Cipher import AES
@@ -27,16 +28,15 @@ except ModuleNotFoundError as e:
class AESCipher:
-
def __init__(self, key):
self.key = key
def decrypt(self, text):
- cipher = AES.new(self.key, AES.MODE_CBC, IV=(b' ' * 16))
+ cipher = AES.new(self.key, AES.MODE_CBC, IV=(b" " * 16))
return self._unpad(cipher.decrypt(text))
-
+
def _unpad(self, s):
- return s[:-ord(s[len(s) - 1:])]
+ return s[: -ord(s[len(s) - 1 :])]
parser = argparse.ArgumentParser(
@@ -45,24 +45,24 @@ parser = argparse.ArgumentParser(
parser.add_argument(
"browser", help="Which browser to extract from", metavar="<browser>"
)
+parser.add_argument("--token", help="Extracted token", metavar="<token>", nargs="?")
parser.add_argument(
- "--token", help="Extracted token", metavar="<token>", nargs='?'
-)
-parser.add_argument(
- "--profile", help="Profile to look up cookies for", metavar="<profile>", nargs='?'
+ "--profile", help="Profile to look up cookies for", metavar="<profile>", nargs="?"
)
args = parser.parse_args()
if args.browser not in ["firefox", "firefox-snap", "chrome", "chrome-beta"]:
- print("Currently only firefox. firefox-snap, chrome, "
- "chrome-beta are supported by this script", file=sys.stderr)
+ print(
+ "Currently only firefox. firefox-snap, chrome, "
+ "chrome-beta are supported by this script",
+ file=sys.stderr,
+ )
sys.exit(1)
if sys.platform.startswith("linux"):
iterations = 1
if args.browser == "firefox-snap":
- browser_data = Path.home().joinpath(
- "snap/firefox/common/.mozilla/firefox")
+ browser_data = Path.home().joinpath("snap/firefox/common/.mozilla/firefox")
elif args.browser == "firefox":
browser_data = Path.home().joinpath(".mozilla/firefox")
else:
@@ -71,43 +71,40 @@ elif sys.platform.startswith("darwin"):
iterations = 1003
if args.browser in ["firefox", "firefox-snap"]:
browser_data = Path.home().joinpath(
- "Library/Application Support/Firefox/Profiles")
+ "Library/Application Support/Firefox/Profiles"
+ )
else:
- browser_data = Path.home().joinpath(
- "Library/Application Support/Chrome")
+ browser_data = Path.home().joinpath("Library/Application Support/Chrome")
else:
- print("Currently only Linux and macOS is supported by this script",
- file=sys.stderr)
+ print("Currently only Linux and macOS is supported by this script", file=sys.stderr)
sys.exit(1)
leveldb_path = None
profile = args.profile
if args.browser in ["firefox", "firefox-snap"]:
cookie_d_query = (
- "SELECT value FROM moz_cookies WHERE host = '.slack.com' "
- "AND name = 'd'"
+ "SELECT value FROM moz_cookies WHERE host = '.slack.com' " "AND name = 'd'"
)
cookie_ds_query = (
- "SELECT value FROM moz_cookies WHERE host = '.slack.com' "
- "AND name = 'd-s'"
+ "SELECT value FROM moz_cookies WHERE host = '.slack.com' " "AND name = 'd-s'"
)
if not profile:
profile = "*.default*"
default_profile_path = max(
- [ x for x in browser_data.glob(profile)], key=os.path.getctime)
+ [x for x in browser_data.glob(profile)], key=os.path.getctime
+ )
if not default_profile_path:
print("Couldn't find the default profile for Firefox", file=sys.stderr)
sys.exit(1)
cookies_path = default_profile_path.joinpath("cookies.sqlite")
else:
if import_err:
- print("Missing required modules for Chrome browser support",
- file=sys.stderr)
+ print("Missing required modules for Chrome browser support", file=sys.stderr)
raise import_err
# b'v10' is for Chromium, but not Chrome, it seems?
- prefix = b'v11'
+ prefix = b"v11"
cookie_d_query = (
"SELECT encrypted_value FROM cookies WHERE "
"host_key = '.slack.com' AND name = 'd'"
@@ -142,27 +139,30 @@ if args.browser in ["chrome", "chrome-beta"]:
try:
collection = secretstorage.get_default_collection(bus)
for item in collection.get_all_items():
- if item.get_label() == 'Chrome Safe Storage':
+ if item.get_label() == "Chrome Safe Storage":
passwd = item.get_secret()
break
else:
- raise Exception('Chrome password not found!')
+ raise Exception("Chrome password not found!")
except SecretStorageException:
- print("Error communicating org.freedesktop.secrets, trying 'peanuts' "
- "as a password", file=sys.stderr)
- passwd = 'peanuts'
-
- salt = b'saltysalt'
+ print(
+ "Error communicating org.freedesktop.secrets, trying 'peanuts' "
+ "as a password",
+ file=sys.stderr,
+ )
+ passwd = "peanuts"
+
+ salt = b"saltysalt"
length = 16
key = PBKDF2(passwd, salt, length, iterations)
cipher = AESCipher(key)
-
+
if cookie_d_value[:3] == prefix:
- cookie_d_value = cipher.decrypt(cookie_d_value[3:]).decode('utf8')
+ cookie_d_value = cipher.decrypt(cookie_d_value[3:]).decode("utf8")
if cookie_ds_value and cookie_ds_value[:3] == prefix:
- cookie_ds_value = cipher.decrypt(cookie_ds_value[3:]).decode('utf8')
+ cookie_ds_value = cipher.decrypt(cookie_ds_value[3:]).decode("utf8")
if cookie_ds_value:
cookie_value = f"d={cookie_d_value};d-s={cookie_ds_value}"
@@ -179,10 +179,13 @@ try:
local_config = json.loads(local_config_str)
except (OperationalError, TypeError):
if not args.token and args.browser not in ["chrome", "chrome-beta"]:
- print("Couldn't find the token for team, extract it manually "
- "by running 'window.prompt(\"Session token:\", "
- "TS.boot_data.api_token)' in your browser dev console "
- "and specify it in --token", file=sys.stderr)
+ print(
+ "Couldn't find the token for team, extract it manually "
+ 'by running \'window.prompt("Session token:", '
+ "TS.boot_data.api_token)' in your browser dev console "
+ "and specify it in --token",
+ file=sys.stderr,
+ )
sys.exit(1)
finally:
con.close()
@@ -193,17 +196,20 @@ if not local_config and leveldb_path:
except pIOErr:
leveldb_copy = str(leveldb_path) + ".bak"
os.makedirs(leveldb_copy, exist_ok=True)
- shutil.copytree(leveldb_path, leveldb_copy,
- dirs_exist_ok=True)
- print(f"Leveldb was locked by a running browser - made an online copy "
- "of it in {leveldb_copy}", file=sys.stderr)
+ shutil.copytree(leveldb_path, leveldb_copy, dirs_exist_ok=True)
+ print(
+ f"Leveldb was locked by a running browser - made an online copy "
+ "of it in {leveldb_copy}",
+ file=sys.stderr,
+ )
db = DB(str(leveldb_copy))
- local_storage_value = db.get(
- b'_https://app.slack.com\x00\x01localConfig_v2')
+ local_storage_value = db.get(b"_https://app.slack.com\x00\x01localConfig_v2")
local_config = json.loads(local_storage_value[1:])
teams = [
- team for team in local_config["teams"].values() if not team["id"].startswith("E")
+ team
+ for team in local_config["teams"].values()
+ if not team["id"].startswith("E")
]
if not teams: