Browse Source

Initial commit

master
Ecmel Berk Canlıer 3 years ago
commit
b91c57b578
No known key found for this signature in database GPG Key ID: 8644746865C262D2
  1. 2
      .gitignore
  2. 14
      Pipfile
  3. 117
      Pipfile.lock
  4. 14
      README.md
  5. 8
      config.conf
  6. 24
      patches/example.com.patch
  7. 81
      proxy.py

2
.gitignore

@ -0,0 +1,2 @@
.idea/
__pycache__/

14
Pipfile

@ -0,0 +1,14 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
flask = "*"
requests = "*"
pyhocon = "*"
[dev-packages]
[requires]
python_version = "3.6"

117
Pipfile.lock

@ -0,0 +1,117 @@
{
"_meta": {
"hash": {
"sha256": "994af8ec76daff05c50171a4463ca63a08fac9ebb0b4b7c33ca72f584e729784"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.6"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {
"certifi": {
"hashes": [
"sha256:13e698f54293db9f89122b0581843a782ad0934a4fe0172d2a980ba77fc61bb7",
"sha256:9fa520c1bacfb634fa7af20a76bcbd3d5fb390481724c597da32c719a7dca4b0"
],
"version": "==2018.4.16"
},
"chardet": {
"hashes": [
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
],
"version": "==3.0.4"
},
"click": {
"hashes": [
"sha256:29f99fc6125fbc931b758dc053b3114e55c77a6e4c6c3a2674a2dc986016381d",
"sha256:f15516df478d5a56180fbf80e68f206010e6d160fc39fa508b65e035fd75130b"
],
"version": "==6.7"
},
"flask": {
"hashes": [
"sha256:2271c0070dbcb5275fad4a82e29f23ab92682dc45f9dfbc22c02ba9b9322ce48",
"sha256:a080b744b7e345ccfcbc77954861cb05b3c63786e93f2b3875e0913d44b43f05"
],
"index": "pypi",
"version": "==1.0.2"
},
"idna": {
"hashes": [
"sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f",
"sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4"
],
"version": "==2.6"
},
"itsdangerous": {
"hashes": [
"sha256:cbb3fcf8d3e33df861709ecaf89d9e6629cff0a217bc2848f1b41cd30d360519"
],
"version": "==0.24"
},
"jinja2": {
"hashes": [
"sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd",
"sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"
],
"version": "==2.10"
},
"markupsafe": {
"hashes": [
"sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665"
],
"version": "==1.0"
},
"pyhocon": {
"hashes": [
"sha256:ff5c43d6e8e1699c2262b1c79a57a35f392d09cd7bbfd7459e122d9e9b87822f"
],
"index": "pypi",
"version": "==0.3.42"
},
"pyparsing": {
"hashes": [
"sha256:0832bcf47acd283788593e7a0f542407bd9550a55a8a8435214a1960e04bcb04",
"sha256:281683241b25fe9b80ec9d66017485f6deff1af5cde372469134b56ca8447a07",
"sha256:8f1e18d3fd36c6795bb7e02a39fd05c611ffc2596c1e0d995d34d67630426c18",
"sha256:9e8143a3e15c13713506886badd96ca4b579a87fbdf49e550dbfc057d6cb218e",
"sha256:b8b3117ed9bdf45e14dcc89345ce638ec7e0e29b2b579fa1ecf32ce45ebac8a5",
"sha256:e4d45427c6e20a59bf4f88c639dcc03ce30d193112047f94012102f235853a58",
"sha256:fee43f17a9c4087e7ed1605bd6df994c6173c1e977d7ade7b651292fab2bd010"
],
"version": "==2.2.0"
},
"requests": {
"hashes": [
"sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b",
"sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e"
],
"index": "pypi",
"version": "==2.18.4"
},
"urllib3": {
"hashes": [
"sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b",
"sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f"
],
"version": "==1.22"
},
"werkzeug": {
"hashes": [
"sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c",
"sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b"
],
"version": "==0.14.1"
}
},
"develop": {}
}

14
README.md

@ -0,0 +1,14 @@
# patchproxy
Proxy sites and patch specific files on the fly.
This is a "fork" of [urlmirror](https://git.issizler.club/admicos/urlmirror).
## Requirements
- `pipenv`
- `patch` command. (Only tested under GNU patch 2.7.6, but any other implementation should work fine.)
## Installation
1. `pipenv install`
2. ...edit Configuration...
3. `pipenv run python proxy.py`

8
config.conf

@ -0,0 +1,8 @@
# Patches are stored in "$patch_dir/<src domain>/<...subdirs>/<file>.patch"
# Patches for folder indexes are stored in "$patch_dir/<src domain>/<...subdirs>.patch"
patch_dir = "patches/"
# Map urls pointing to this server to outside (source) domains.
site_map {
"http://example.com.localhost:3131/": "https://example.com/",
}

24
patches/example.com.patch

@ -0,0 +1,24 @@
--- example.html 2013-08-10 02:54:35.000000000 +0300
+++ example-new.html 2018-05-12 01:16:42.752016111 +0300
@@ -1,7 +1,7 @@
<!doctype html>
<html>
<head>
- <title>Example Domain</title>
+ <title>patchproxy example</title>
<meta charset="utf-8" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
@@ -41,10 +41,8 @@
<body>
<div>
- <h1>Example Domain</h1>
- <p>This domain is established to be used for illustrative examples in documents. You may use this
- domain in examples without prior coordination or asking for permission.</p>
- <p><a href="http://www.iana.org/domains/example">More information...</a></p>
+ <h1>patchproxy Example</h1>
+ <p>This a patch for example.com.</p>
</div>
</body>
</html>

81
proxy.py

@ -0,0 +1,81 @@
import uuid
from urllib.parse import urlsplit
import os
import subprocess
import requests
from flask import Flask, Response, request
from pyhocon import ConfigParser
from requests import Response as RequestsResponse
from werkzeug.routing import Rule
with open("config.conf") as f:
cfg = ConfigParser.parse(f.read())
app = Flask(__name__)
app.url_map.add(Rule("/", endpoint="mirror"))
app.url_map.add(Rule("/<string:path>", endpoint="mirror"))
def unquote(host: str) -> str:
return host.replace('"', "").replace("'", "")
def get_mirror_of(host: str) -> str:
return cfg["site_map"]['"' + unquote(host) + '"']
def get_mirror_url(url: str) -> str:
return url.replace(request.url_root, get_mirror_of(request.url_root))
def search_patch(url: str) -> str:
_us = urlsplit(url)
domain = _us.netloc
path = _us.path
if path == "/":
path = ""
return os.path.abspath(os.path.join(
cfg["patch_dir"],
f"{domain}{path}.patch")
)
def mirrorize_page_content(r: RequestsResponse):
patch_path = search_patch(r.url)
if not (os.path.exists(patch_path) and not os.path.isdir(patch_path)):
return r.content
tmp_file = str(uuid.uuid4())
with open(tmp_file, "w") as f:
f.write(r.text)
patch_proc = subprocess.run(
["patch", tmp_file, patch_path, "-o", "-"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE # hide stderr
)
os.remove(tmp_file)
return patch_proc.stdout
@app.endpoint("mirror")
@app.errorhandler(404)
def mirror(path: str = "/") -> Response:
murl = get_mirror_url(request.url)
r = requests.request(request.method, murl, data=request.data)
return Response(
mirrorize_page_content(r),
status=r.status_code,
content_type=r.headers["Content-Type"],
)
if __name__ == "__main__":
app.run("0.0.0.0", 3131, True)