Skip to content

Commit 505e1ad

Browse files
committed
feat: Implement and integrate --export functionality
This commit introduces the new `--export` (-e) feature to PyAte. The export functionality allows users to specify a file containing OTP URIs which will then be processed to generate QR codes for each valid URI. Key changes include: Added logic to handle the `--export` argument, specifying the input file for QR code generation. Implemented file reading and URI parsing to extract valid `otpauth://` URIs. Integrated QR code generation using `generateQrcodeFromUri` to create PNG files in a 'qrcodes' directory. Improved error handling for file operations and URI parsing during export. Corrected the logic to properly use the `--export` argument's value (or its default) for reading the account file, resolving a previous issue where `args.read` was incorrectly used.
1 parent e0fb1e3 commit 505e1ad

1 file changed

Lines changed: 48 additions & 2 deletions

File tree

pyate.py

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from cli.parser import setupArgParse
1414
from utils.terminal import clearTerminal, banner
1515
from utils.file_handler import loadAccounts
16-
from utils.qr_decoder import getOtpUriFromQrcode
16+
from utils.qr_utils import getOtpUriFromQrcode, generateQrcodeFromUri
1717
from core.ykman_exporter import generateYkmanCommands
1818
from utils.migration import getOTPAuthPerLineFromOPTAuthMigration
1919

@@ -119,7 +119,53 @@ def main():
119119

120120
# Exit after generating ykman commands
121121
return
122+
123+
if args.export:
122124

125+
inputFileExport = args.export
126+
print(f"Exporting accounts from '{Fore.LIGHTMAGENTA_EX}{inputFileExport}{Style.RESET_ALL}' to QR codes.")
127+
128+
outputDir = "export" # Directory to save QR codes
129+
os.makedirs(outputDir, exist_ok=True) # Create directory if it doesn't exist
130+
131+
exported_count = 0
132+
try:
133+
with open(inputFileExport, 'r') as f: # Gunakan inputFileExport di sini
134+
lines = f.readlines()
135+
136+
for line in lines:
137+
line = line.strip()
138+
if line.startswith("otpauth://"):
139+
try:
140+
import urllib.parse
141+
parsedUri = urllib.parse.urlparse(line)
142+
queryParams = urllib.parse.parse_qs(parsedUri.query)
143+
label = parsedUri.path.strip('/')
144+
issuer = queryParams.get('issuer', [label])[0]
145+
146+
safeIssuer = "".join(c if c.isalnum() else "_" for c in issuer)
147+
safeLabel = "".join(c if c.isalnum() else "_" for c in label)
148+
149+
fileNamePrefix = f"{safeIssuer}_{safeLabel}"
150+
outputFileName = os.path.join(outputDir, f"qrcode_{fileNamePrefix}.png")
151+
152+
if generateQrcodeFromUri(line, outputFileName):
153+
exported_count += 1
154+
except Exception as e:
155+
print(f"{Fore.RED}Warning: Could not parse URI '{line}'. Skipping. Error: {e}{Style.RESET_ALL}")
156+
157+
if exported_count > 0:
158+
print(f"\n{Fore.GREEN}Successfully exported {exported_count} QR codes to the '{Fore.LIGHTMAGENTA_EX}{outputDir}' directory.{Style.RESET_ALL}")
159+
else:
160+
print(f"{Fore.RED}No valid 'otpauth://' URIs found to export.{Style.RESET_ALL}")
161+
162+
except FileNotFoundError:
163+
print(f"{Fore.RED}Error: File '{inputFileExport}' not found.{Style.RESET_ALL}")
164+
except Exception as e:
165+
print(f"{Fore.RED}An error occurred during export: {e}{Style.RESET_ALL}")
166+
167+
return
168+
123169
# Load accounts from the file after all imports are complete
124170
accounts = loadAccounts(args.read)
125171

@@ -207,7 +253,7 @@ def main():
207253
sys.stdout.flush()
208254

209255
time.sleep(1)
210-
256+
211257
except KeyboardInterrupt:
212258
print(f"\n\n{Fore.RED}Program stopped.{Style.RESET_ALL}")
213259
except Exception as e:

0 commit comments

Comments
 (0)