#!/usr/bin/env python3
"""
Purolator SOAP API - Account Number Extractor

This script analyzes the Purolator mobile app to find hardcoded or extractable
account numbers for SOAP API testing.

Key Findings from Code Analysis:
================================

1. **MOBILE Account (Credit Card Payments)**
   - Location: PackageDetailsHelper.java line 41
   - Code: paymentInfoElement.setBillingAccountNumber("MOBILE")
   - Usage: For credit card payments, app uses "MOBILE" as placeholder
   - Limitation: This is STAGING ONLY (does NOT work in production)

2. **BusinessAccount Database**
   - Location: BusinessAccount.java
   - Storage: ActiveAndroid database (@Table "BusinessAccounts")
   - Fields:
     * accountNumber - Real Purolator account number
     * accountKey - Account key (possibly billing)
     * accountName - Account name
     * accountNickname - User nickname
   - Security: Fields are ENCRYPTED using SecureModel
   - Retrieval: Loaded from user login or Salesforce API

3. **Encrypted Credentials (X.java)**
   - TNUOCCA (ACCOUNT reversed): Account credentials
     * Hardcoded prefix: "FQ/E1KpKybV2Kn87ao2UAcZXf3JbzOsZHek7d09yXrsn+nghl"
     * Suffix from Firebase Remote Config
     * Decryption: AES/CBC with key from Firebase
   
   - DRAC_TIDERC (CREDITCARD reversed): Credit card data
     * Hardcoded prefix: "FQ/E1KpK3qZubmgVYoyUEsZWf3FUkesZCew7cGIpXZUkpW0Ijyv"
     * Suffix from Firebase Remote Config
     * Decryption: AES/CBC with key from Firebase

4. **How Mobile App Gets Account Numbers**
   - User logs in with Purolator credentials
   - App calls Salesforce API to fetch user's business accounts
   - Accounts are stored encrypted in BusinessAccounts table
   - Selected account is used for SOAP API calls

EXTRACTION METHODS:
===================

Method 1: Intercept Account Login (RECOMMENDED)
------------------------------------------------
Use Frida to hook the account loading process:

```javascript
Java.perform(function() {
    var BusinessAccount = Java.use("com.purolator.mobileapp.api.models.accounts.BusinessAccount");
    
    BusinessAccount.getBusinessAccounts.implementation = function(context) {
        var accounts = this.getBusinessAccounts(context);
        console.log("[+] Found " + accounts.size() + " business accounts:");
        
        for (var i = 0; i < accounts.size(); i++) {
            var account = accounts.get(i);
            console.log("  Account " + (i+1) + ":");
            console.log("    Number: " + account.accountNumber.value);
            console.log("    Key: " + account.accountKey.value);
            console.log("    Name: " + account.accountName.value);
        }
        
        return accounts;
    };
});
```

Method 2: Extract from Salesforce API
--------------------------------------
The app calls Salesforce to get accounts. Use MITM to capture:
- Endpoint: Salesforce REST API
- OAuth Token: (from earlier extraction)
- SOQL Query: Look for Account or BusinessAccount objects

Method 3: Decrypt Firebase Remote Config
-----------------------------------------
Decrypt the TNUOCCA credential which might contain account info:

Steps:
1. Extract Firebase Remote Config JSON
2. Get EncryptionData fields (TNUOCCA suffix, SSAP key, ROTCEV IV)
3. Decrypt using AES/CBC
4. Result might be account credentials or account number

Method 4: Database Extraction (Requires Root)
----------------------------------------------
Extract the ActiveAndroid database directly:

```bash
# Connect to device
adb shell

# Switch to app context
run-as com.purolator.mobileapp

# Find database
ls databases/
# Look for: purolator.db or ActiveAndroid.db

# Copy to SD card (if accessible)
cp databases/purolator.db /sdcard/
exit
adb pull /sdcard/purolator.db

# Decrypt using app's SecureModel logic
```

WHAT WE KNOW:
=============

✅ API Keys: Already extracted (working perfectly)
   - Account Key: ef7475ef70b44f4687158fbbb9ff3f47:|HXY2).6
   - Credit Card Key: 000b94d6601f4c96ba75d8443317a2a9:xyA}FWoD

✅ Production Endpoint: webservices.purolator.com (confirmed)

✅ XML Structure: Complete SOAP format validated

❌ Account Numbers: NOT hardcoded in app
   - Loaded from user login
   - Stored encrypted in database
   - Retrieved from Salesforce API

NEXT STEPS:
===========

1. **Check Salesforce for Account Numbers**
   Use existing Salesforce credentials to query for Purolator accounts:
   
   ```sql
   SELECT Id, Name, AccountNumber, BillingAccountNumber__c 
   FROM Account 
   WHERE Name LIKE '%Purolator%' OR Type = 'Shipping'
   ```

2. **Hook Account Loading with Frida**
   Run the app with Frida script above to capture real account numbers
   during login or account selection

3. **Test with Demo/Test Account**
   Check if Purolator provides test account numbers for development:
   - Contact Purolator API support
   - Check developer documentation
   - Look for sandbox credentials

4. **Decrypt Firebase Config**
   Extract and decrypt the TNUOCCA field which might contain
   account information or default account numbers

CONCLUSION:
===========

🔍 Account numbers are NOT hardcoded in the app
📱 They are user-specific and loaded dynamically after login
🔒 Stored encrypted in local database
🌐 Retrieved from Salesforce API based on user's business profile

To proceed with testing, you need REAL account numbers from:
- Actual Purolator business account holder
- Salesforce account database query
- Runtime interception during app usage
- Purolator developer test accounts (if available)
"""

import os


def main():
    print(__doc__)
    
    print("\n" + "="*70)
    print("RECOMMENDED ACTION")
    print("="*70)
    print()
    print("1. Check Salesforce for Purolator Account Numbers")
    print("   - Use salesforce_shell.py from earlier")
    print("   - Query Account objects for shipping accounts")
    print("   - Look for AccountNumber or custom fields")
    print()
    print("2. Use Frida to Hook Account Loading")
    print("   - Create frida_extract_accounts.js")
    print("   - Hook BusinessAccount.getBusinessAccounts()")
    print("   - Capture decrypted account numbers at runtime")
    print()
    print("3. Extract Firebase Remote Config")
    print("   - Use adb or Frida to capture config")
    print("   - Decrypt TNUOCCA credential")
    print("   - Check if it contains account info")
    print()
    print("="*70)


if __name__ == "__main__":
    main()
