#!/usr/bin/env python3
"""Start a customer-controlled HTTP client with a deliberate proxy environment."""
import os
from pathlib import Path
import stat
import sys
from urllib.parse import urlsplit


def proxy_url(env):
    value = env.get('QG_PROXY_URL', '')
    if not value:
        location = env.get('QG_PROXY_FILE')
        if not location:
            raise ValueError('Set QG_PROXY_URL or QG_PROXY_FILE through local secret storage.')
        path = Path(location).expanduser()
        with path.open(encoding='utf-8') as source:
            info = os.fstat(source.fileno())
            if not stat.S_ISREG(info.st_mode) or info.st_mode & 0o077:
                raise ValueError('Proxy secret must be a regular file with owner-only permissions.')
            if hasattr(os, 'getuid') and info.st_uid != os.getuid():
                raise ValueError('Proxy secret must belong to the current user.')
            value = source.read(8193).strip()
    if len(value) > 8192 or any(c.isspace() for c in value):
        raise ValueError('Proxy URL contains whitespace or is too long.')
    try:
        parsed = urlsplit(value)
        valid = (parsed.scheme in ('http', 'https') and parsed.hostname
                 and parsed.port and parsed.username and parsed.password
                 and parsed.path in ('', '/') and not parsed.query and not parsed.fragment)
    except ValueError:
        valid = False
    if not valid:
        raise ValueError('Use the complete authenticated HTTP or HTTPS proxy URL from QuotaGuard.')
    return value


def routed_env(env):
    result = dict(env)
    value = proxy_url(env)
    for key in ('http_proxy', 'HTTP_PROXY', 'https_proxy', 'HTTPS_PROXY'):
        result[key] = value
    bypass = env.get('QG_NO_PROXY', 'localhost,127.0.0.1,::1')
    if '*' in bypass:
        raise ValueError('Choose explicit bypass hosts; wildcard bypass is not accepted.')
    result['no_proxy'] = result['NO_PROXY'] = bypass
    result.pop('ALL_PROXY', None)
    result.pop('all_proxy', None)
    # Children get only the standard proxy variables, not the source secret inputs.
    result.pop('QG_PROXY_URL', None)
    result.pop('QG_PROXY_FILE', None)
    return result


def main(argv):
    if not argv:
        print('Usage: python3 qg_route.py COMMAND [ARG ...]', file=sys.stderr)
        return 2
    try:
        env = routed_env(os.environ)
        os.execvpe(argv[0], argv, env)
    except (ValueError, OSError) as exc:
        # Exception strings from exec/path parsing may contain sensitive input.
        print('Proxy launcher failed (' + type(exc).__name__ + '); check secret inputs and executable.', file=sys.stderr)
        return 2


if __name__ == '__main__':
    sys.exit(main(sys.argv[1:]))
