import argparse from datetime import datetime import stripe from collections import defaultdict, deque import re import logging from dataclasses import dataclass, field, asdict import os from dotenv import load_dotenv import json import asyncio logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s" ) load_dotenv() STRIPE_API_KEY = os.getenv("STRIPE_WRITE_API_KEY") stripe.api_key = STRIPE_API_KEY logging.getLogger("stripe").setLevel(logging.WARNING) async def create_value_list_item(value_list_id, fingerprint): return await asyncio.to_thread( stripe.radar.ValueListItem.create, value_list=value_list_id, value=fingerprint ) if __name__ == "__main__": parser = argparse.ArgumentParser(description="Update Stripe card fingerprint lists") parser.add_argument( "--fingerprints-file", required=True, help="Path to file containing Stripe card fingerprints (one per line)", ) parser.add_argument( "--stripe-list-prefix", required=True, help="Prefix for output lists created in Stripe", ) args = parser.parse_args() # Validate stripe list prefix contains only alphanumeric and underscores if not re.match(r"^[a-zA-Z0-9_]+$", args.stripe_list_prefix): raise ValueError( "stripe-list-prefix must contain only alphanumeric characters and underscores" ) LIST_SIZE = 50_000 # Read fingerprints from file with open(args.fingerprints_file, "r") as f: fingerprints = [line.strip() for line in f if line.strip()] total_fingerprints = len(fingerprints) # Split into batches of LIST_SIZE fingerprint_batches = [] for i in range(0, len(fingerprints), LIST_SIZE): batch = fingerprints[i : i + LIST_SIZE] fingerprint_batches.append(batch) logging.info( f"Split {len(fingerprints)} fingerprints into {len(fingerprint_batches)} batches of size {LIST_SIZE}" ) # print a human readable date and time string start_time = datetime.now().strftime("%Y_%m_%d_%H_%M") list_name_prefix = ( f"[Bots - Card Fingerprints] {args.stripe_list_prefix} ({start_time})" ) list_alias_prefix = f"card_fingerprint_{start_time}_{args.stripe_list_prefix}" fingerprints_added = 0 for i, batch in enumerate(fingerprint_batches): list_name = f"{list_name_prefix} {i + 1}" list_alias = f"{list_alias_prefix}_{i + 1}" print(f"Creating value list: {list_name} (alias: {list_alias})") try: # Create a new value list value_list = stripe.radar.ValueList.create( alias=list_alias, name=list_name, item_type="card_fingerprint" ) logging.info( f"Created value list: {list_name} - (alias: {list_alias}, id: {value_list.id})" ) # Process fingerprints in chunks of 10 chunk_size = 40 for i in range(0, len(batch), chunk_size): chunk = batch[i : i + chunk_size] tasks = [ create_value_list_item(value_list.id, fingerprint) for fingerprint in chunk ] asyncio.get_event_loop().run_until_complete(asyncio.gather(*tasks)) for fingerprint in chunk: logging.info( f"Added fingerprint: {fingerprint} to value list {list_name}" ) fingerprints_added += 1 logging.info( f"fingerprints added: {fingerprints_added} / {total_fingerprints}" ) logging.info(f"Added {len(batch)} fingerprints to value list {list_name}") except stripe.error.StripeError as e: logging.error(f"Error creating/updating value list {list_name}: {str(e)}") raise