#!/usr/bin/env python3
"""Find OAuth audience IDs without printing environment values, API keys or private credentials."""
import argparse
import importlib.util
import json
from pathlib import Path
import subprocess

ROOT = Path(__file__).resolve().parents[1]
SCAN = r'''
import json,os,re
from pathlib import Path
audience=re.compile(r'[0-9]+-[A-Za-z0-9_-]+\.apps\.googleusercontent\.com')
skip={'vendor','node_modules','.git','.deploy','uploads','logs','sessions','testing','output','tmp'}
results=[]
for location in LOCATIONS:
 root=Path(location)
 for directory,folders,names in os.walk(root):
  folders[:]=[name for name in folders if name not in skip and not (Path(directory)/name).is_symlink()]
  for name in names:
   path=Path(directory)/name
   if not (name.startswith('.env') or path.suffix in ['.php','.json','.js','.xml','.yaml','.yml','.ini']): continue
   try:
    if path.is_symlink() or path.stat().st_size>2_000_000: continue
    text=path.read_text(errors='replace')
   except OSError:
    results.append({'file':str(path),'unreadable':True})
    continue
   hits=[]
   for number,line in enumerate(text.splitlines(),1):
    for value in sorted(set(audience.findall(line))):
     hits.append({'line':number,'oauth_client_id':value})
   if name.startswith('.env'):
    keys=[]
    for line in text.splitlines():
     match=re.match(r'^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=(.*)$',line)
     if match and re.search(r'GOOGLE|OAUTH|FIREBASE|CLIENT_ID',match[1],re.I):
      value=match[2].strip().strip('"\'')
      entry={'name':match[1],'configured':bool(value),'contains_oauth_client_id':bool(audience.search(value))}
      if match[1]=='FIREBASE_CREDENTIALS' and value:
       credential=Path(value) if Path(value).is_absolute() else root/value
       try:
        metadata=json.loads(credential.read_text())
        entry['referenced_project_id']=metadata.get('project_id')
       except (OSError,ValueError,AttributeError):
        entry['referenced_credential_readable']=False
      keys.append(entry)
    results.append({'file':str(path),'environment_keys':keys,'audiences':hits})
   elif hits:
    results.append({'file':str(path),'audiences':hits})
   elif path.suffix=='.json' and re.search(r'google|firebase|service.?account|credential',name,re.I):
    try:
     value=json.loads(text)
     if isinstance(value,dict):
      results.append({'file':str(path),'credential_type':value.get('type'),
       'project_id':value.get('project_id',value.get('project_info',{}).get('project_id')),
       'service_account_numeric_client_id_present':bool(value.get('type')=='service_account' and value.get('client_id'))})
    except (ValueError,AttributeError): pass
print(json.dumps(results,indent=2))
'''


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument('--production', action='store_true', help='Read-only scan over pinned SSH')
    args = parser.parse_args()
    if not args.production:
        code = 'LOCATIONS=' + repr([str(ROOT.parent / 'bondvia-php/app.connectlyvideochat.com'), str(ROOT)]) + '\n' + SCAN
        subprocess.run(['python3', '-'], input=code, text=True, check=True)
        return
    spec = importlib.util.spec_from_file_location('deployment_client', ROOT / 'scripts/deploy.py')
    client = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(client)
    config = client.configuration(ROOT / '.deploy/config.json')
    code = 'LOCATIONS=' + repr(['/www/wwwroot/app.connectlyvideochat.com', config['app_dir']]) + '\n' + SCAN
    subprocess.run(['ssh', '-p', str(config['port']), *client.ssh_options(config),
                    f'{config["user"]}@{config["host"]}', 'python3 -'], input=code, text=True, check=True)


if __name__ == '__main__':
    main()
