#!/usr/bin/env python3
"""
Test AWS Signature V4 Implementation
Based on reverse-engineered Canada Post app code
"""

import requests
import hashlib
import hmac
import json
from datetime import datetime
from urllib.parse import urlparse, quote

class AWSSignatureV4:
    """
    AWS Signature Version 4 implementation
    Based on o6 package from decompiled app
    """
    
    def __init__(self, access_key, secret_key, region='ca-central-1', service='execute-api'):
        self.access_key = access_key
        self.secret_key = secret_key
        self.region = region
        self.service = service
    
    def sign_request(self, method, url, headers=None, payload=''):
        """
        Sign HTTP request with AWS Signature V4
        Returns signed headers dict
        """
        if headers is None:
            headers = {}
        
        # Parse URL
        parsed = urlparse(url)
        host = parsed.netloc
        path = parsed.path or '/'
        query = parsed.query or ''
        
        # Timestamp
        now = datetime.utcnow()
        amz_date = now.strftime('%Y%m%dT%H%M%SZ')
        date_stamp = now.strftime('%Y%m%d')
        
        # Required headers
        headers['Host'] = host
        headers['X-Amz-Date'] = amz_date
        
        # Payload hash (X-Amz-Content-Sha256)
        payload_hash = hashlib.sha256(payload.encode() if isinstance(payload, str) else payload).hexdigest()
        headers['X-Amz-Content-Sha256'] = payload_hash
        
        # Step 1: Create canonical request
        canonical_headers = ''
        signed_headers = ''
        header_names = sorted(headers.keys(), key=str.lower)
        for name in header_names:
            canonical_headers += f"{name.lower()}:{headers[name]}\n"
            if signed_headers:
                signed_headers += ';'
            signed_headers += name.lower()
        
        canonical_request = (
            f"{method}\n"
            f"{path}\n"
            f"{query}\n"
            f"{canonical_headers}\n"
            f"{signed_headers}\n"
            f"{payload_hash}"
        )
        
        print(f"[DEBUG] Canonical Request:\n{canonical_request}\n")
        
        # Step 2: Create string to sign
        credential_scope = f"{date_stamp}/{self.region}/{self.service}/aws4_request"
        canonical_request_hash = hashlib.sha256(canonical_request.encode()).hexdigest()
        
        string_to_sign = (
            "AWS4-HMAC-SHA256\n"
            f"{amz_date}\n"
            f"{credential_scope}\n"
            f"{canonical_request_hash}"
        )
        
        print(f"[DEBUG] String to Sign:\n{string_to_sign}\n")
        
        # Step 3: Calculate signature
        def sign(key, msg):
            return hmac.new(key, msg.encode(), hashlib.sha256).digest()
        
        k_date = sign(('AWS4' + self.secret_key).encode(), date_stamp)
        k_region = sign(k_date, self.region)
        k_service = sign(k_region, self.service)
        k_signing = sign(k_service, 'aws4_request')
        
        signature = hmac.new(k_signing, string_to_sign.encode(), hashlib.sha256).hexdigest()
        
        print(f"[DEBUG] Signature: {signature}\n")
        
        # Step 4: Add authorization header
        authorization = (
            f"AWS4-HMAC-SHA256 "
            f"Credential={self.access_key}/{credential_scope}, "
            f"SignedHeaders={signed_headers}, "
            f"Signature={signature}"
        )
        
        headers['Authorization'] = authorization
        
        return headers

def test_mymail_api_with_aws_sig():
    """
    Test MyMail API with AWS Signature V4
    """
    print("=" * 80)
    print("AWS SIGNATURE V4 TEST - MyMail API")
    print("=" * 80)
    
    # NOTE: These are PLACEHOLDER credentials
    # Real AWS credentials would need to be extracted from:
    # 1. App's remote config
    # 2. Hardcoded in app
    # 3. Retrieved during runtime
    
    aws_access_key = "PLACEHOLDER_ACCESS_KEY"
    aws_secret_key = "PLACEHOLDER_SECRET_KEY"
    
    # User token from OAuth (you have this)
    user_token = "UFI25QJm5zBOEtYV6ncy3XTXTvhrQLj9RM56TLNE"
    
    # MyMail API endpoint
    url = "https://1i5z3519d0.execute-api.ca-central-1.amazonaws.com/mailmanager/v1/holidays"
    
    # Initialize AWS signer
    signer = AWSSignatureV4(
        access_key=aws_access_key,
        secret_key=aws_secret_key,
        region='ca-central-1',
        service='execute-api'
    )
    
    # Prepare headers
    headers = {
        'User-Agent': 'okhttp/4.9.1',
        'X-Platform': 'android',
        'X-Platform-JWTToken': user_token,
        'Content-Type': 'application/json'
    }
    
    # Sign request
    signed_headers = signer.sign_request('GET', url, headers)
    
    print("\n[REQUEST] GET " + url)
    print("[HEADERS]")
    for k, v in signed_headers.items():
        print(f"  {k}: {v}")
    
    print("\n[NOTES]")
    print("- AWS credentials are PLACEHOLDERS")
    print("- Real credentials need to be extracted from app")
    print("- May be in Firebase Remote Config, env vars, or hardcoded")
    print("- Use Frida to hook o6.e class to get real config")
    
    return signed_headers

def test_tracking_api_with_aws_sig():
    """
    Test Tracking API with AWS Signature V4
    """
    print("\n" + "=" * 80)
    print("AWS SIGNATURE V4 TEST - Tracking API")
    print("=" * 80)
    
    aws_access_key = "PLACEHOLDER_ACCESS_KEY"
    aws_secret_key = "PLACEHOLDER_SECRET_KEY"
    user_token = "UFI25QJm5zBOEtYV6ncy3XTXTvhrQLj9RM56TLNE"
    
    url = "https://q26ff9ws86.execute-api.ca-central-1.amazonaws.com/prod/track/123456789"
    
    signer = AWSSignatureV4(
        access_key=aws_access_key,
        secret_key=aws_secret_key,
        region='ca-central-1',
        service='execute-api'
    )
    
    headers = {
        'User-Agent': 'okhttp/4.9.1',
        'X-Platform': 'android',
        'X-Platform-JWTToken': user_token
    }
    
    signed_headers = signer.sign_request('GET', url, headers)
    
    print("\n[REQUEST] GET " + url)
    print("[HEADERS]")
    for k, v in signed_headers.items():
        print(f"  {k}: {v}")
    
    return signed_headers

if __name__ == "__main__":
    print("""
╔═══════════════════════════════════════════════════════════════════╗
║              AWS Signature V4 Test Suite                         ║
║         Canada Post App - Authentication Research                ║
╚═══════════════════════════════════════════════════════════════════╝

This script demonstrates AWS Signature V4 signing based on the
decompiled Canada Post app code (o6 package).

⚠️  AWS CREDENTIALS ARE PLACEHOLDERS ⚠️

To get real credentials, you need to:
1. Use Frida to hook 'o6.e' (AWS config class)
2. Check Firebase Remote Config for AWS keys
3. Search for hardcoded credentials in app
4. Intercept runtime API calls with proper signing

""")
    
    # Test both APIs
    test_mymail_api_with_aws_sig()
    test_tracking_api_with_aws_sig()
    
    print("\n" + "=" * 80)
    print("NEXT STEPS:")
    print("=" * 80)
    print("1. Run Frida hook: frida -U -f ca.canadapost.android -l frida_comprehensive_hook.js")
    print("2. Log into the app to capture real user token")
    print("3. Check Frida output for AWS configuration")
    print("4. Update AWS credentials and re-run this script")
    print("5. Try API requests with proper AWS signature")
    print("=" * 80)
