-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.py
More file actions
147 lines (109 loc) · 4.32 KB
/
Copy pathapp.py
File metadata and controls
147 lines (109 loc) · 4.32 KB
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
import http.client
import re
import urllib
import json
import requests
from flask import Flask, Blueprint, request, Response, url_for, abort
from werkzeug.datastructures import Headers
from werkzeug.exceptions import NotFound
app = Flask(__name__)
# Default Configuration
DEBUG_FLAG = True
LISTEN_PORT = 7788
proxy = Blueprint('proxy', __name__)
# You can insert Authentication here.
# proxy.before_request(check_login)
# Filters.
HTML_REGEX = re.compile(r'((?:src|action|href)=["\'])/')
JQUERY_REGEX = re.compile(r'(\$\.(?:get|post)\(["\'])/')
JS_LOCATION_REGEX = re.compile(r'((?:window|document)\.location.*=.*["\'])/')
CSS_REGEX = re.compile(r'(url\(["\']?)/')
REGEXES = [HTML_REGEX, JQUERY_REGEX, JS_LOCATION_REGEX, CSS_REGEX]
def iterform(multidict):
for key in multidict.keys():
for value in multidict.getlist(key):
yield (key.encode("utf8"), value.encode("utf8"))
def parse_host_port(h):
"""Parses strings in the form host[:port]"""
host_port = h.split(":", 1)
if len(host_port) == 1:
return (h, 80)
else:
host_port[1] = int(host_port[1])
return host_port
@proxy.route('/')
def index():
return ""
# For RESTful Service
@proxy.route('/proxy/<host>/', methods=["GET", "POST", "PUT", "DELETE"])
@proxy.route('/proxy/<host>/<path:file>', methods=["GET", "POST", "PUT", "DELETE"])
def proxy_request(host, file=""):
hostname, port = parse_host_port(host)
if "proxy" in hostname:
abort(403)
response = requests.get("https://proxy-filter.herokuapp.com/is_blacklisted", params={'hostname': hostname})
json_response = response.content.decode()
response_dictionary = json.loads(json_response)
success = response_dictionary['success']
message = response_dictionary['message']
if success == 0:
abort(403)
else:
# Whitelist a few headers to pass on
request_headers = {}
for h in ["Cookie", "Referer", "X-Csrf-Token"]:
if h in request.headers:
request_headers[h] = request.headers[h]
if request.query_string:
path = "/%s?%s" % (file, request.query_string)
else:
path = "/" + file
if request.method == "POST" or request.method == "PUT":
form_data = list(iterform(request.form))
form_data = urllib.urlencode(form_data)
request_headers["Content-Length"] = len(form_data)
else:
form_data = None
conn = http.client.HTTPConnection(hostname, port)
conn.request(request.method, path, body=form_data, headers=request_headers)
resp = conn.getresponse()
# Clean up response headers for forwarding
d = {}
response_headers = Headers()
for key, value in resp.getheaders():
d[key.lower()] = value
if key in ["content-length", "connection", "content-type"]:
continue
if key == "set-cookie":
cookies = value.split(",")
[response_headers.add(key, c) for c in cookies]
else:
response_headers.add(key, value)
# If this is a redirect, munge the Location URL
if "location" in response_headers:
redirect = response_headers["location"]
response = requests.get(redirect)
return response.content
# Rewrite URLs in the content to point to our URL schemt.method == " instead.
# Ugly, but seems to mostly work.
root = url_for(".proxy_request", host=host)
contents = resp.read()
# Restructing Contents.
if d["content-type"].find("application/json") >= 0:
# JSON format contents will be modified here.
jc = json.loads(contents)
if jc.has_key("nodes"):
del jc["nodes"]
contents = json.dumps(jc)
else:
# Generic HTTP.
for regex in REGEXES:
contents = regex.sub(r'\1%s' % root, contents)
flask_response = Response(response=contents,
status=resp.status,
headers=response_headers,
content_type=resp.getheader('content-type'))
return flask_response.data
app.register_blueprint(proxy)
if __name__ == '__main__':
app.run(debug=DEBUG_FLAG, port=LISTEN_PORT)