Skip to content

minimal no-dependency version (vibe-coded) #6

@rushiagr

Description

@rushiagr

i don't use poetry, so just gave this repository to claude-code and asked to generate a version with only standard library. sharing, as i thought you might appreciate it.

Using the example provided in readme. works with absolutely any relatively-recent python:

% python minimal_decoder.py "otpauth-migration://offline?data=CjEKCkhlbGxvId6tvu8SGEV4YW1wbGU6YWxpY2VAZ29vZ2xlLmNvbRoHRXhhbXBsZTAC"
otpauth://totp/Example%3Aalice%40google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example

source:

#!/usr/bin/env python3
"""
Minimal otpauth-migration decoder using only Python standard library
Decodes Google Authenticator export data to standard otpauth URLs
"""

import base64
import sys
from urllib.parse import quote, unquote, urlparse, parse_qs


def read_varint(data, offset):
    """Read a varint (variable-length integer) from protobuf data"""
    result = 0
    shift = 0
    while offset < len(data):
        byte = data[offset]
        offset += 1
        result |= (byte & 0x7F) << shift
        if (byte & 0x80) == 0:
            break
        shift += 7
    return result, offset


def read_length_delimited(data, offset):
    """Read a length-delimited field from protobuf data"""
    length, offset = read_varint(data, offset)
    return data[offset : offset + length], offset + length


def parse_otp_parameters(data):
    """Parse OtpParameters protobuf message"""
    offset = 0
    otp = {
        "secret": b"",
        "name": "",
        "issuer": "",
        "algorithm": 1,  # SHA1
        "digits": 1,  # 6 digits
        "type": 2,  # TOTP
    }

    while offset < len(data):
        if offset >= len(data):
            break

        tag, offset = read_varint(data, offset)
        field_number = tag >> 3
        wire_type = tag & 0x7

        if field_number == 1 and wire_type == 2:  # secret
            otp["secret"], offset = read_length_delimited(data, offset)
        elif field_number == 2 and wire_type == 2:  # name
            name_bytes, offset = read_length_delimited(data, offset)
            otp["name"] = name_bytes.decode("utf-8", errors="replace")
        elif field_number == 3 and wire_type == 2:  # issuer
            issuer_bytes, offset = read_length_delimited(data, offset)
            otp["issuer"] = issuer_bytes.decode("utf-8", errors="replace")
        elif field_number == 4 and wire_type == 0:  # algorithm
            otp["algorithm"], offset = read_varint(data, offset)
        elif field_number == 5 and wire_type == 0:  # digits
            otp["digits"], offset = read_varint(data, offset)
        elif field_number == 6 and wire_type == 0:  # type
            otp["type"], offset = read_varint(data, offset)
        elif field_number == 7 and wire_type == 0:  # counter (skip)
            _, offset = read_varint(data, offset)
        else:
            # Skip unknown fields
            if wire_type == 0:  # varint
                _, offset = read_varint(data, offset)
            elif wire_type == 2:  # length-delimited
                _, offset = read_length_delimited(data, offset)
            else:
                # Unknown wire type, stop parsing
                break

    return otp


def parse_payload(data):
    """Parse main Payload protobuf message"""
    offset = 0
    otp_parameters = []

    while offset < len(data):
        if offset >= len(data):
            break

        tag, offset = read_varint(data, offset)
        field_number = tag >> 3
        wire_type = tag & 0x7

        if field_number == 1 and wire_type == 2:  # otp_parameters
            otp_data, offset = read_length_delimited(data, offset)
            otp_params = parse_otp_parameters(otp_data)
            otp_parameters.append(otp_params)
        else:
            # Skip other fields (version, batch_size, etc.)
            if wire_type == 0:
                _, offset = read_varint(data, offset)
            elif wire_type == 2:
                _, offset = read_length_delimited(data, offset)
            else:
                break

    return otp_parameters


def build_otpauth_url(otp):
    """Build otpauth URL from OTP parameters"""
    # Enum mappings
    algorithms = {1: "SHA1", 2: "SHA256", 3: "SHA512", 4: "MD5"}
    digits_map = {1: "6", 2: "8"}
    types = {1: "hotp", 2: "totp"}

    otp_type = types.get(otp["type"], "totp")
    algorithm = algorithms.get(otp["algorithm"], "SHA1")
    digits = digits_map.get(otp["digits"], "6")

    # Convert secret to base32 (no padding)
    secret = base64.b32encode(otp["secret"]).decode("ascii").rstrip("=")
    name = quote(otp["name"])

    # Build URL parameters
    params = [f"secret={secret}"]
    if otp["issuer"]:
        params.append(f'issuer={quote(otp["issuer"])}')
    if algorithm != "SHA1":
        params.append(f"algorithm={algorithm}")
    if digits != "6":
        params.append(f"digits={digits}")

    return f"otpauth://{otp_type}/{name}?" + "&".join(params)


def decode_migration_data(data_b64):
    """Decode base64 otpauth-migration data to otpauth URLs"""
    # Handle URL encoding
    data_b64 = unquote(data_b64)

    # Decode base64
    try:
        data = base64.b64decode(data_b64)
    except Exception as e:
        raise ValueError(f"Invalid base64 data: {e}")

    # Parse protobuf and generate URLs
    otp_parameters = parse_payload(data)
    return [build_otpauth_url(otp) for otp in otp_parameters]


def parse_input(input_str):
    """Extract data from full URL or return input if it's just base64 data"""
    if input_str.startswith("otpauth-migration://"):
        parsed = urlparse(input_str)
        if parsed.scheme != "otpauth-migration" or parsed.hostname != "offline":
            raise ValueError("Invalid otpauth-migration URL format")

        query_params = parse_qs(parsed.query)
        if "data" not in query_params:
            raise ValueError("Missing 'data' parameter in URL")

        return query_params["data"][0]

    return input_str


def main():
    if len(sys.argv) != 2:
        print(
            "Usage: python minimal_decoder.py 'otpauth-migration://...' or 'base64-data'"
        )
        print(
            "Example: python minimal_decoder.py 'otpauth-migration://offline?data=...'"
        )
        sys.exit(1)

    try:
        data_b64 = parse_input(sys.argv[1])
        urls = decode_migration_data(data_b64)

        if not urls:
            print("No OTP parameters found in the data", file=sys.stderr)
            sys.exit(1)

        for url in urls:
            print(url)

    except ValueError as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)
    except Exception as e:
        print(f"Unexpected error: {e}", file=sys.stderr)
        sys.exit(1)


if __name__ == "__main__":
    main()

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions