initial commit

This commit is contained in:
Bullet64 2024-08-10 15:32:28 +02:00
commit 833e35de70
3 changed files with 194 additions and 0 deletions

138
converter.py Normal file
View file

@ -0,0 +1,138 @@
###############################################
# Standard library imports
###############################################
import argparse
import uuid
import json
from urllib.parse import urlparse, parse_qs, unquote
###############################################
# Functions
###############################################
def generate_uuid():
"""
Generates a unique identifier (UUID) and returns it as a string.
:return: A string representation of the generated UUID.
"""
return str(uuid.uuid4())
def parse_totp_url(totp_url):
"""
:param totp_url: The URL representing the TOTP (Time-based One-Time Password) authentication data.
:return: A dictionary containing the parsed TOTP information, including the issuer, account name, secret, algorithm,
digits, and period.
This method takes a TOTP URL as input and parses it to extract the relevant information. It then returns a
dictionary containing the parsed TOTP information.
The TOTP URL should be in the following format:
totp://issuer:account_name?secret=<secret>&algorithm=<algorithm>&digits=<digits>&period=<period>
Example usage:
totp_url = 'totp://MyIssuer:MyAccountName?secret=ABC123&algorithm=SHA256&digits=6&period=30'
parsed_info = parse_totp_url(totp_url)
# parsed_info will be {'issuer': 'MyIssuer',
'account_name': 'MyAccountName',
'secret': 'ABC123',
'algorithm': 'SHA256',
'digits': '6',
'period': '30'}
"""
# Parse the URL
parsed_url = urlparse(totp_url)
# Extract the path and query components
path = parsed_url.path.strip('/')
query = parsed_url.query
# URL-decode the entire path
decoded_path = unquote(path)
# Split the path into issuer and account name
path_parts = decoded_path.split(':', 1)
issuer = path_parts[0]
account_name = path_parts[1] if len(path_parts) > 1 else ''
query_params = parse_qs(query)
secret = query_params.get('secret', [''])[0]
algorithm = query_params.get('algorithm', [''])[0]
digits = query_params.get('digits', [''])[0]
period = query_params.get('period', [''])[0]
return {
'issuer': issuer,
'account_name': account_name,
'secret': secret,
'algorithm': algorithm,
'digits': digits,
'period': period
}
###############################################
# Usage: python converter.py -i import.txt -o output.json
###############################################
def main(input_file, output_file):
"""
:param input_file: The path to the input file containing TOTP URLs.
:param output_file: The path to the output file where the generated JSON will be written.
:return: None
Reads TOTP URLs from the input file, parses them, and generates a JSON file with the parsed information.
The generated JSON file includes entries for each parsed URL, with each entry having a generated UUID,
a login with TOTP and username fields, a name field extracted from the issuer, and a type field set to 1.
The final JSON object is written to the output file.
Additionally, the number of generated entries and the output file path are printed to the console.
"""
# List to hold all entries
entries = []
with open(input_file, 'r') as file:
for line in file:
totp = line.strip()
if not totp:
continue # Skip empty lines
# Parse the URL
parsed_data = parse_totp_url(totp)
# Create a new entry with a generated UUID
entry = {
"favorite": False,
"id": generate_uuid(),
"login": {
"totp": totp,
"username": parsed_data['account_name']
},
"name": parsed_data['issuer'],
"type": 1
}
entries.append(entry)
# Construct the final JSON object
data = {
"encrypted": False,
"items": entries
}
# Output JSON to a file
with open(output_file, 'w') as json_file:
json.dump(data, json_file, indent=4)
print(f"Total entries: {len(entries)}")
print(f"Output written to {output_file}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Parse TOTP URLs and export to JSON.')
parser.add_argument('-i', '--input', required=True, help='Input file containing TOTP URLs')
parser.add_argument('-o', '--output', required=True, help='Output JSON file')
args = parser.parse_args()
main(args.input, args.output)

55
example.json Normal file
View file

@ -0,0 +1,55 @@
{
"encrypted": false,
"items": [
{
"favorite": false,
"id": "52A4DFB0-F19E-4C9D-82A1-BBEE95BBEF81",
"login": {
"totp": "otpauth://totp/Amazon:alice@bitwarden.com?secret=IIO5SCP3766LMSAB5HJCQPNDCCNAZ532&issuer=Amazon&algorithm=SHA1&digits=6&period=30",
"username": "alice@bitwarden.com"
},
"name": "Amazon",
"type": 1
},
{
"favorite": false,
"id": "DC81A830-ED98-4F45-9B73-B147E40134AB",
"login": {
"totp": "otpauth://totp/Apple:alice@bitwarden.com?secret=IIO5SCQ3766LMSBB5HJCQPNDCCNAZ532&issuer=Apple&algorithm=SHA1&digits=6&period=30",
"username": "alice@bitwarden.com"
},
"name": "Apple",
"type": 1
},
{
"favorite": false,
"id": "4EF44090-4B6A-4E98-A94C-CF7B0F2CC35D",
"login": {
"totp": "otpauth://totp/Bitwarden:alice@bitwarden.com?secret=IIO5SCP3766LMSBB5HJCQPNDCCNAZ532&issuer=Bitwarden&algorithm=SHA1&digits=6&period=30",
"username": "alice@bitwarden.com"
},
"name": "Bitwarden",
"type": 1
},
{
"favorite": false,
"id": "59B09168-502A-4D38-B218-FACF66E6A365",
"login": {
"totp": "otpauth://totp/Microsoft:alice@bitwarden.com?secret=IIO5SCP3766LMSBB5HJCHPNDCCNAZ532&issuer=Microsoft&algorithm=SHA1&digits=6&period=30",
"username": "alice@bitwarden.com"
},
"name": "Microsoft",
"type": 1
},
{
"favorite": false,
"id": "789F095B-95B2-4816-A5F7-01095116C10E",
"login": {
"totp": "otpauth://totp/Reddit:alice@bitwarden.com?secret=IIO5SCP3766LNSBB5HJCQPNDCCNAZ532&issuer=Reddit&algorithm=SHA1&digits=6&period=30",
"username": "alice@bitwarden.com"
},
"name": "Reddit",
"type": 1
}
]
}

1
import.txt Normal file
View file

@ -0,0 +1 @@
otpauth://totp/Radforum%20D%C3%BCsseldorf%3Afrankm%40radforum-duesseldorf.de?secret=<SECRET>&algorithm=SHA1&digits=6&period=30