Skip to content

Instantly share code, notes, and snippets.

@julian-klode
Created September 29, 2020 21:31
Show Gist options
  • Save julian-klode/39d128acba970f20ae95e3504047cca3 to your computer and use it in GitHub Desktop.
Save julian-klode/39d128acba970f20ae95e3504047cca3 to your computer and use it in GitHub Desktop.
#!/usr/bin/python3
#
# Copyright (C) 2020 Julian Andres Klode <[email protected]>
#
# SPDX-License-Identifier: AGPL-3.0-or-later
"""Takes a Chrome CSV on stdin, and produces a Bitwarden JSON export on stdout.
The output only contains relevant fields, and logins are merged together based
on user name and password.
"""
import csv, sys, uuid, json
def remove_prefix(s, prefix):
"""Remove a prefix from a string."""
return s[len(prefix) :] if s.startswith(prefix) else s
def clean_name(name, x):
"""Produce a clean name without useless noise like www in it"""
if not name and x["url"].startswith("android://"):
name = ".".join(reversed(x["url"].split("/")[2].split("@")[-1].split(".")))
print("Found android app", name, file=sys.stderr)
if not any(c.isalpha() for c in name):
print("Ignoring IP", name, file=sys.stderr)
return name
inp = name
name = remove_prefix(name, "www.")
name = remove_prefix(name, "login.")
name = remove_prefix(name, "signin.")
name = remove_prefix(name, "passport.")
name = remove_prefix(name, "auth.")
name = remove_prefix(name, "console.")
name = remove_prefix(name, "config.")
name = remove_prefix(name, "app.")
name = remove_prefix(name, "m.")
name = remove_prefix(name, "mobile.")
name = remove_prefix(name, "my.")
name = remove_prefix(name, "id.")
name = remove_prefix(name, "account.")
name = remove_prefix(name, "shop.")
name = remove_prefix(name, "accounts.login.idm.")
name = remove_prefix(name, "identity.")
name = remove_prefix(name, "co2offset.")
name = remove_prefix(name, "sso.")
if name.endswith(".ikea.com"):
name = "ikea.com"
if name.endswith(".auth0.com"):
name = name.replace(".auth0.com", "")
if name.endswith(".shopgate.com"):
name = name.replace(".shopgate.com", "")
if name.endswith("wikipedia.org"):
name = "wikipedia.org"
if name.endswith("tutanota.com"):
name = "tutanota.com"
out = ".".join(name.split(".")[-2:])
pre = ".".join(name.split(".")[:-2])
if pre:
out = f"{out} - {pre}"
print("Replacing", pre, "in", name, "=>", out, file=sys.stderr)
return out
def convert(fobj=sys.stdin):
"""Convert Chrome CSV file in fobj to BitWarden JSON file."""
passwds = list(csv.DictReader(fobj))
by_login = [((k["username"], k["password"]), k) for k in passwds]
by_login1 = {k: [v1 for k1, v1 in by_login if k1 == k] for k, v in by_login}
return {
"folders": [],
"items": [
{
"type": 1,
"name": (", ".join(set(clean_name(x["name"], x) for x in v))),
"login": {
"uris": [{"match": None, "uri": x["url"]} for x in v],
"username": v[0]["username"],
"password": v[0]["password"],
},
}
for v in by_login1.values()
],
}
print(json.dumps(convert(), indent=4,))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment