feat: implement graceful fallback to config.json for OTP secret storage when the keyring module is unavailable.
This commit is contained in:
parent
d52743d69c
commit
252a7ed239
1 changed files with 59 additions and 36 deletions
95
wrapper.py
95
wrapper.py
|
|
@ -13,7 +13,11 @@ import hashlib
|
|||
import os
|
||||
import shutil
|
||||
import configparser
|
||||
import keyring
|
||||
try:
|
||||
import keyring
|
||||
HAS_KEYRING = True
|
||||
except ImportError:
|
||||
HAS_KEYRING = False
|
||||
import getpass
|
||||
|
||||
import urllib.parse
|
||||
|
|
@ -172,42 +176,51 @@ def detect_launch_command():
|
|||
def get_secret(config, config_path):
|
||||
"""
|
||||
Retrieves the OTP secret in the following priority:
|
||||
1. System Keyring (SERVICE_NAME, USERNAME)
|
||||
2. config.json (Legacy) - if found, migrates to Keyring and removes from config.
|
||||
3. User Input - prompts user and saves to Keyring.
|
||||
1. System Keyring (SERVICE_NAME, USERNAME) - if available
|
||||
2. config.json - if Keyring unavailable or secret found there (and Keyring unavailable for migration)
|
||||
3. User Input - prompts user and saves to Keyring (if available) or config.json.
|
||||
"""
|
||||
SERVICE_NAME = "XIVLauncherWrapper"
|
||||
USERNAME = "OTP_SECRET"
|
||||
|
||||
# 1. Try Keyring
|
||||
try:
|
||||
secret = keyring.get_password(SERVICE_NAME, USERNAME)
|
||||
if secret:
|
||||
return secret
|
||||
except Exception as e:
|
||||
print(f"Warning: Failed to access keyring: {e}")
|
||||
if HAS_KEYRING:
|
||||
try:
|
||||
secret = keyring.get_password(SERVICE_NAME, USERNAME)
|
||||
if secret:
|
||||
return secret
|
||||
except Exception as e:
|
||||
print(f"Warning: Failed to access keyring: {e}")
|
||||
|
||||
# 2. Try Config (Legacy/Migration)
|
||||
# 2. Try Config
|
||||
if config and "secret" in config:
|
||||
secret = config["secret"]
|
||||
if secret and secret != "YOUR_BASE32_SECRET_HERE":
|
||||
print("Migrating secret from config.json to system keyring...")
|
||||
try:
|
||||
keyring.set_password(SERVICE_NAME, USERNAME, secret)
|
||||
|
||||
# Remove from config
|
||||
del config["secret"]
|
||||
with open(config_path, 'w') as f:
|
||||
json.dump(config, f, indent=4)
|
||||
print("Secret migrated successfully and removed from config.json.")
|
||||
return secret
|
||||
except Exception as e:
|
||||
print(f"Error migrating to keyring: {e}")
|
||||
print("Continuing with secret from config...")
|
||||
return secret
|
||||
if HAS_KEYRING:
|
||||
print("Migrating secret from config.json to system keyring...")
|
||||
try:
|
||||
keyring.set_password(SERVICE_NAME, USERNAME, secret)
|
||||
|
||||
# Remove from config
|
||||
del config["secret"]
|
||||
with open(config_path, 'w') as f:
|
||||
json.dump(config, f, indent=4)
|
||||
print("Secret migrated successfully and removed from config.json.")
|
||||
return secret
|
||||
except Exception as e:
|
||||
print(f"Error migrating to keyring: {e}")
|
||||
print("Continuing with secret from config...")
|
||||
return secret
|
||||
else:
|
||||
# No keyring, just use config
|
||||
return secret
|
||||
|
||||
# 3. Prompt User
|
||||
print("\nOTP Secret not found in keyring.")
|
||||
if HAS_KEYRING:
|
||||
print("\nOTP Secret not found in keyring.")
|
||||
else:
|
||||
print("\nOTP Secret not found in config.json and keyring module is missing.")
|
||||
|
||||
print("Please enter your TOTP Secret (base32) or otpauth:// URL.")
|
||||
while True:
|
||||
try:
|
||||
|
|
@ -222,16 +235,26 @@ def get_secret(config, config_path):
|
|||
print("Invalid secret format. Please try again.")
|
||||
continue
|
||||
|
||||
try:
|
||||
keyring.set_password(SERVICE_NAME, USERNAME, parsed)
|
||||
print("Secret saved to system keyring.")
|
||||
return parsed
|
||||
except Exception as e:
|
||||
print(f"Error saving to keyring: {e}")
|
||||
# If we can't save to keyring, we might just return it in memory for this session
|
||||
# But typically we want persistence.
|
||||
print("Proceeding with in-memory secret for this session.")
|
||||
return parsed
|
||||
if HAS_KEYRING:
|
||||
try:
|
||||
keyring.set_password(SERVICE_NAME, USERNAME, parsed)
|
||||
print("Secret saved to system keyring.")
|
||||
return parsed
|
||||
except Exception as e:
|
||||
print(f"Error saving to keyring: {e}")
|
||||
print("Proceeding with in-memory secret for this session.")
|
||||
return parsed
|
||||
else:
|
||||
# Save to config.json
|
||||
try:
|
||||
config['secret'] = parsed
|
||||
with open(config_path, 'w') as f:
|
||||
json.dump(config, f, indent=4)
|
||||
print(f"Secret saved to {config_path}")
|
||||
return parsed
|
||||
except Exception as e:
|
||||
print(f"Error saving to config.json: {e}")
|
||||
return parsed
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("\nOperation cancelled.")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue