Files
swingmusic-extended/test_simple_token.py
Tomas Dvorak cbf646e25b Fix CI/CD pipeline and code quality issues
## Major Changes
- Fixed all TypeScript errors in web client for successful compilation
- Resolved 82+ Python lint errors across backend services
- Updated Flutter SDK compatibility for mobile app
- Fixed security workflow configuration

## Web Client Fixes
- Fixed import path in DragonflyDashboard.vue (dragonflyApi import)
- All TypeScript compilation now passes without errors

## Backend Lint Fixes
- Updated type annotations to modern Python syntax (dict instead of Dict, X | None instead of Optional[X])
- Replaced try-except-pass with contextlib.suppress(Exception)
- Removed unused imports (Dict, Optional, Any, Iterator, etc.)
- Fixed bare except clauses to use Exception
- Sorted and formatted imports with ruff
- Applied ruff format to 27 files

## Workflow Fixes
- Updated Flutter SDK constraint from ^3.10.4 to ^3.5.0 (compatible with Flutter 3.24.0)
- Changed pip-audit format from github to json in security.yml
- Added comprehensive CI workflows (readiness-gate.yml, security.yml)

## Infrastructure
- Added DragonflyDB caching system integration
- Enhanced Docker configuration with multi-stage builds
- Added pytest configuration and test infrastructure
- Improved production readiness with proper error handling

## Verification
- backend-lint job:  Succeeded
- web job:  Succeeded
- Ready for GitHub deployment

All CI/CD issues resolved. Codebase now passes all quality checks.
2026-03-21 10:01:14 +01:00

188 lines
6.3 KiB
Python

#!/usr/bin/env python3
"""
Simple test to verify tokens work with basic Spotify API calls
"""
import json
import logging
import time
from urllib.parse import urlencode
import requests
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
def get_tokener_token():
"""Get token from tokener API"""
response = requests.get("https://spotify-tokener-api.vercel.app/api/getToken", timeout=10)
if response.status_code == 200:
data = response.json()
return data.get('accessToken'), data.get('clientId')
return None, None
def get_totp_token():
"""Get token from TOTP method"""
import base64
import hashlib
import hmac
SPOTIFY_TOTP_SECRET = "GM3TMMJTGYZTQNZVGM4DINJZHA4TGOBYGMZTCMRTGEYDSMJRHE4TEOBUG4YTCMRUGQ4DQOJUGQYTAMRRGA2TCMJSHE3TCMBY"
SPOTIFY_TOTP_VERSION = 61
# Generate TOTP
secret_bytes = base64.b32decode(SPOTIFY_TOTP_SECRET)
current_time = int(time.time() // 30)
time_bytes = current_time.to_bytes(8, 'big')
h = hmac.new(secret_bytes, time_bytes, hashlib.sha1)
hmac_result = h.digest()
offset = hmac_result[-1] & 0x0f
code = ((hmac_result[offset] & 0x7f) << 24) | ((hmac_result[offset + 1] & 0xff) << 16) | ((hmac_result[offset + 2] & 0xff) << 8) | (hmac_result[offset + 3] & 0xff)
totp_code = str(code % 1000000).zfill(6)
# Get token
params = {
"reason": "init",
"productType": "web-player",
"totp": totp_code,
"totpVer": SPOTIFY_TOTP_VERSION,
"totpServer": totp_code,
}
url = f"https://open.spotify.com/api/token?{urlencode(params)}"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
}
response = requests.get(url, headers=headers, timeout=30)
if response.status_code == 200:
data = response.json()
return data.get('accessToken'), data.get('clientId')
return None, None
def test_public_api(token, method_name):
"""Test token with public Spotify API endpoints"""
logger.info(f"Testing {method_name} token with public API...")
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
}
# Test with public track endpoint (should work with any token)
track_url = "https://api.spotify.com/v1/tracks/4cOdK2wGLETOMrsVzAojDx"
response = requests.get(track_url, headers=headers, timeout=10)
if response.status_code == 200:
data = response.json()
logger.info(f"{method_name} public API SUCCESS!")
logger.info(f"Track: {data.get('name', 'Unknown')}")
logger.info(f"Artists: {[artist.get('name', 'Unknown') for artist in data.get('artists', [])]}")
return True
elif response.status_code == 401:
logger.error(f"{method_name} public API: Token invalid (401)")
return False
else:
logger.error(f"{method_name} public API: HTTP {response.status_code}")
logger.error(f"Response: {response.text[:200]}")
return False
def test_web_player_api(token, method_name):
"""Test token with web player GraphQL API"""
logger.info(f"Testing {method_name} token with web player API...")
# Simple query that should work
payload = {
"variables": {
"uri": "spotify:track:4cOdK2wGLETOMrsVzAojDx"
},
"operationName": "getTrack",
"extensions": {
"persistedQuery": {
"version": 1,
"sha256Hash": "612585ae06ba435ad26369870deaae23b5c8800a256cd8a57e08eddc25a37294"
}
}
}
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
}
response = requests.post(
"https://api-partner.spotify.com/pathfinder/v1/query",
json=payload,
headers=headers,
timeout=30
)
if response.status_code == 200:
data = response.json()
logger.info(f"{method_name} web player API SUCCESS!")
logger.info(f"Response keys: {list(data.keys())}")
if "data" in data:
logger.info(f"Data keys: {list(data['data'].keys())}")
return True
elif response.status_code == 401:
logger.error(f"{method_name} web player API: Token invalid (401)")
return False
else:
logger.error(f"{method_name} web player API: HTTP {response.status_code}")
logger.error(f"Response: {response.text[:200]}")
return False
def main():
"""Run token tests"""
print("=" * 60)
print("Simple Token Validation Test")
print("=" * 60)
# Test TOTP method
print("\n1. Testing TOTP Token")
print("-" * 40)
totp_token, totp_client_id = get_totp_token()
if totp_token:
print("✅ TOTP token obtained")
public_success = test_public_api(totp_token, "TOTP")
web_success = test_web_player_api(totp_token, "TOTP")
totp_success = public_success or web_success
else:
print("❌ Failed to get TOTP token")
totp_success = False
# Test tokener API method
print("\n2. Testing Tokener API Token")
print("-" * 40)
tokener_token, tokener_client_id = get_tokener_token()
if tokener_token:
print("✅ Tokener API token obtained")
public_success = test_public_api(tokener_token, "Tokener")
web_success = test_web_player_api(tokener_token, "Tokener")
tokener_success = public_success or web_success
else:
print("❌ Failed to get tokener API token")
tokener_success = False
# Summary
print("\n" + "=" * 60)
print("Token Validation Results")
print("=" * 60)
print(f"TOTP Token: {'✅ VALID' if totp_success else '❌ INVALID'}")
print(f"Tokener Token: {'✅ VALID' if tokener_success else '❌ INVALID'}")
if totp_success and tokener_success:
print("🎉 Both tokens are valid!")
elif totp_success or tokener_success:
print("✅ At least one token is valid!")
else:
print("⚠️ Both tokens are invalid")
print("=" * 60)
if __name__ == "__main__":
main()