-
Notifications
You must be signed in to change notification settings - Fork 2
/
cli.py
147 lines (123 loc) · 5.84 KB
/
cli.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# SPDX-License-Identifier: Apache-2.0
"""Command-line interface for auth_capture_proxy."""
from __future__ import annotations
import asyncio
import datetime
import json
import logging
import sys
import time
from functools import partial, wraps
from typing import Any, Dict, Text
import httpx
import typer
from yarl import URL
from authcaptureproxy import AuthCaptureProxy, __copyright__, __title__, __version__, metadata
from authcaptureproxy.examples.modifiers import autofill
logger = logging.getLogger(__package__)
cli = typer.Typer()
def coro(f):
"""Wrap f to run as async."""
@wraps(f)
def wrapper(*args, **kwargs):
return asyncio.run(f(*args, **kwargs))
return wrapper
@cli.command()
def info(n_seconds: float = 0.01, verbose: bool = False) -> None:
"""
Get info about auth_capture_proxy.
Args:
n_seconds: Number of seconds to wait between processing.
verbose: Output more info
"""
typer.echo(f"{__title__} version {__version__}, {__copyright__}")
if verbose:
typer.echo(str(metadata.__dict__))
total = 0
with typer.progressbar(range(100)) as progress:
for _ in progress:
time.sleep(n_seconds)
total += 1
typer.echo(f"Processed {total} things.")
@cli.command()
@coro
async def proxy_example(
proxy: str = "http://127.0.0.1",
host: str = "https://www.amazon.com/ap/signin?openid.pape.max_auth_age=0&openid.return_to=https%3A%2F%2Fwww.amazon.com%2F%3Fref_%3Dnav_signin&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.assoc_handle=usflex&openid.mode=checkid_setup&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&",
callback: str = "",
timeout: int = 300,
debug: bool = False,
):
"""Run proxy example for Amazon.com.
Args:
proxy (str, optional): The url to connect to the proxy. If no port specified, will generate random port. Defaults to "http://127.0.0.1".
host (str, optional): The signing page to proxy. Defaults to "https://www.amazon.com/ap/signin?openid.pape.max_auth_age=0&openid.return_to=https%3A%2F%2Fwww.amazon.com%2F%3Fref_%3Dnav_signin&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.assoc_handle=usflex&openid.mode=checkid_setup&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&".
callback (str, optional): Callback url to redirect browser to on success. Defaults to "".
timeout (int, optional): How long to leave the proxy running without success. Defaults to 300.
debug (bool, optional): Whether to print debug messages to console. Defaults to False.
"""
if debug:
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
proxy_url = URL()
host_url = URL()
callback_url = URL()
if proxy:
proxy_url = URL(proxy)
if host:
host_url = URL(host)
if callback:
callback_url = URL(callback)
proxy_obj: AuthCaptureProxy = AuthCaptureProxy(proxy_url=proxy_url, host_url=host_url)
def test_url(resp: httpx.Response, data: Dict[Text, Any], query: Dict[Text, Any]):
"""Test for a successful Amazon URL.
Args:
resp (httpx.Response): The httpx response.
data (Dict[Text, Any]): Dictionary of all post data captured through proxy with overwrites for duplicate keys.
query (Dict[Text, Any]): Dictionary of all query data with overwrites for duplicate keys.
Returns:
Optional[Union[URL, Text]]: URL for a http 302 redirect or Text to display on success. None indicates test did not pass.
"""
# Did we reach specific url?
typer.echo(f"URL {resp.url}")
if "https://www.amazon.com/?ref_=nav_signin" in str(resp.url):
# save any needed info from resp, data, or query
# cookies will be in proxy.session.cookie_jar
asyncio.create_task(proxy_obj.stop_proxy(3)) # stop proxy in 3 seconds
if callback_url:
return URL(callback_url) # 302 redirect
return f"Successfully logged in {data.get('email')} and {data.get('password')}. Please close the window.<br /><b>Post data</b><br />{json.dumps(data)}<br /><b>Query Data:</b><br />{json.dumps(query)}<br /><b>Cookies:</b></br>{json.dumps(list(proxy_obj.session.cookies.items()))}"
await proxy_obj.start_proxy()
# add tests and modifiers after the proxy has started so that port data is available for self.access_url()
# add tests. See :mod:`authcaptureproxy.examples.testers`.
proxy_obj.tests = {"test_url": test_url}
# add modifiers like autofill to manipulate html returned to browser. See :mod:`authcaptureproxy.examples.modifiers`.
# this will add to any default modifiers
proxy_obj.modifiers.update(
{
"text/html": {
"autofill": partial(
autofill,
{
"password": "CHANGEME",
},
)
}
}
)
# add filter to redirect check. Filter out all urls from redirect check.
proxy_obj.redirect_filters = {"url": ["^.*$"]}
# connect to proxy at proxy.access_url() and sign in
typer.echo(
f"Launching browser to connect to proxy at {proxy_obj.access_url()} and sign in using logged-out account."
)
typer.launch(str(proxy_obj.access_url()))
typer.echo(f"Proxy will timeout and close in {datetime.timedelta(seconds=timeout)}.")
asyncio.create_task(proxy_obj.stop_proxy(timeout))
# or stop the proxy when done manually
while proxy_obj.active:
# loop until proxy done
await asyncio.sleep(1)
typer.echo("Proxy completed; exiting")
raise typer.Exit()
if __name__ == "__main__":
cli()