Merge branch 'mediaproxy-integration' into 'master'

Mediaproxy integration

See merge request litecord/litecord!11
This commit is contained in:
Luna Mendes 2018-12-05 06:16:45 +00:00
commit c934582628
7 changed files with 175 additions and 53 deletions

View File

@ -11,8 +11,9 @@ websockets = "==6.0"
Earl-ETF = "==2.1.2" Earl-ETF = "==2.1.2"
logbook = "==1.4.0" logbook = "==1.4.0"
Cerberus = "==1.2" Cerberus = "==1.2"
quart = {editable = true, ref = "e23714d5", git = "https://gitlab.com/pgjones/quart"} quart = {editable = true,ref = "e23714d5",git = "https://gitlab.com/pgjones/quart"}
pillow = "*" pillow = "*"
aiohttp = "==3.4.4"
[dev-packages] [dev-packages]
pytest = "==3.10.1" pytest = "==3.10.1"

144
Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{ {
"_meta": { "_meta": {
"hash": { "hash": {
"sha256": "277049fb25e5f182fc611cc27c1d07792cea31f137375bd48f654ddb94d2eb62" "sha256": "b546ad1edfe79457cb4da95e19fd17506b7adabe6a43acbc0906fb12cfda68b2"
}, },
"pipfile-spec": 6, "pipfile-spec": 6,
"requires": { "requires": {
@ -23,6 +23,41 @@
], ],
"version": "==0.4.0" "version": "==0.4.0"
}, },
"aiohttp": {
"hashes": [
"sha256:0419705a36b43c0ac6f15469f9c2a08cad5c939d78bd12a5c23ea167c8253b2b",
"sha256:1812fc4bc6ac1bde007daa05d2d0f61199324e0cc893b11523e646595047ca08",
"sha256:2214b5c0153f45256d5d52d1e0cafe53f9905ed035a142191727a5fb620c03dd",
"sha256:275909137f0c92c61ba6bb1af856a522d5546f1de8ea01e4e726321c697754ac",
"sha256:3983611922b561868428ea1e7269e757803713f55b53502423decc509fef1650",
"sha256:51afec6ffa50a9da4cdef188971a802beb1ca8e8edb40fa429e5e529db3475fa",
"sha256:589f2ec8a101a0f340453ee6945bdfea8e1cd84c8d88e5be08716c34c0799d95",
"sha256:789820ddc65e1f5e71516adaca2e9022498fa5a837c79ba9c692a9f8f916c330",
"sha256:7a968a0bdaaf9abacc260911775611c9a602214a23aeb846f2eb2eeaa350c4dc",
"sha256:7aeefbed253f59ea39e70c5848de42ed85cb941165357fc7e87ab5d8f1f9592b",
"sha256:7b2eb55c66512405103485bd7d285a839d53e7fdc261ab20e5bcc51d7aaff5de",
"sha256:87bc95d3d333bb689c8d755b4a9d7095a2356108002149523dfc8e607d5d32a4",
"sha256:9d80e40db208e29168d3723d1440ecbb06054d349c5ece6a2c5a611490830dd7",
"sha256:a1b442195c2a77d33e4dbee67c9877ccbdd3a1f686f91eb479a9577ed8cc326b",
"sha256:ab3d769413b322d6092f169f316f7b21cd261a7589f7e31db779d5731b0480d8",
"sha256:b066d3dec5d0f5aee6e34e5765095dc3d6d78ef9839640141a2b20816a0642bd",
"sha256:b24e7845ae8de3e388ef4bcfcf7f96b05f52c8e633b33cf8003a6b1d726fc7c2",
"sha256:c59a953c3f8524a7c86eaeaef5bf702555be12f5668f6384149fe4bb75c52698",
"sha256:cf2cc6c2c10d242790412bea7ccf73726a9a44b4c4b073d2699ef3b48971fd95",
"sha256:e0c9c8d4150ae904f308ff27b35446990d2b1dfc944702a21925937e937394c6",
"sha256:f1839db4c2b08a9c8f9788112644f8a8557e8e0ecc77b07091afabb941dc55d0",
"sha256:f3df52362be39908f9c028a65490fae0475e4898b43a03d8aa29d1e765b45e07"
],
"index": "pypi",
"version": "==3.4.4"
},
"async-timeout": {
"hashes": [
"sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f",
"sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3"
],
"version": "==3.0.1"
},
"asyncpg": { "asyncpg": {
"hashes": [ "hashes": [
"sha256:08a0afa32588a04581975fb09dc7c32a873e84481347d8701aba2c4360b70253", "sha256:08a0afa32588a04581975fb09dc7c32a873e84481347d8701aba2c4360b70253",
@ -45,6 +80,13 @@
"index": "pypi", "index": "pypi",
"version": "==0.18.2" "version": "==0.18.2"
}, },
"attrs": {
"hashes": [
"sha256:10cbf6e27dbce8c30807caf056c8eb50917e0eaafe86347671b57254006c3e69",
"sha256:ca4be454458f9dec299268d472aaa5a11f67a4ff70093396e1ceae9c76cf4bbb"
],
"version": "==18.2.0"
},
"bcrypt": { "bcrypt": {
"hashes": [ "hashes": [
"sha256:01477981abf74e306e8ee31629a940a5e9138de000c6b0898f7f850461c4a0a5", "sha256:01477981abf74e306e8ee31629a940a5e9138de000c6b0898f7f850461c4a0a5",
@ -135,6 +177,13 @@
], ],
"version": "==1.11.5" "version": "==1.11.5"
}, },
"chardet": {
"hashes": [
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
],
"version": "==3.0.4"
},
"click": { "click": {
"hashes": [ "hashes": [
"sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13",
@ -190,12 +239,19 @@
], ],
"version": "==5.1.0" "version": "==5.1.0"
}, },
"idna": {
"hashes": [
"sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
"sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"
],
"version": "==2.8"
},
"itsdangerous": { "itsdangerous": {
"hashes": [ "hashes": [
"sha256:cbb3fcf8d3e33df861709ecaf89d9e6629cff0a217bc2848f1b41cd30d360519" "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19",
"sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"
], ],
"index": "pypi", "version": "==1.1.0"
"version": "==0.24"
}, },
"jinja2": { "jinja2": {
"hashes": [ "hashes": [
@ -250,37 +306,37 @@
}, },
"multidict": { "multidict": {
"hashes": [ "hashes": [
"sha256:05eeab69bf2b0664644c62bd92fabb045163e5b8d4376a31dfb52ce0210ced7b", "sha256:024b8129695a952ebd93373e45b5d341dbb87c17ce49637b34000093f243dd4f",
"sha256:0c85880efa7cadb18e3b5eef0aa075dc9c0a3064cbbaef2e20be264b9cf47a64", "sha256:041e9442b11409be5e4fc8b6a97e4bcead758ab1e11768d1e69160bdde18acc3",
"sha256:136f5a4a6a4adeacc4dc820b8b22f0a378fb74f326e259c54d1817639d1d40a0", "sha256:045b4dd0e5f6121e6f314d81759abd2c257db4634260abcfe0d3f7083c4908ef",
"sha256:14906ad3347c7d03e9101749b16611cf2028547716d0840838d3c5e2b3b0f2d3", "sha256:047c0a04e382ef8bd74b0de01407e8d8632d7d1b4db6f2561106af812a68741b",
"sha256:1ade4a3b71b1bf9e90c5f3d034a87fe4949c087ef1f6cd727fdd766fe8bbd121", "sha256:068167c2d7bbeebd359665ac4fff756be5ffac9cda02375b5c5a7c4777038e73",
"sha256:22939a00a511a59f9ecc0158b8db728afef57975ce3782b3a265a319d05b9b12", "sha256:148ff60e0fffa2f5fad2eb25aae7bef23d8f3b8bdaf947a65cdbe84a978092bc",
"sha256:2b86b02d872bc5ba5b3a4530f6a7ba0b541458ab4f7c1429a12ac326231203f7", "sha256:1d1c77013a259971a72ddaa83b9f42c80a93ff12df6a4723be99d858fa30bee3",
"sha256:3c11e92c3dfc321014e22fb442bc9eb70e01af30d6ce442026b0c35723448c66", "sha256:1d48bc124a6b7a55006d97917f695effa9725d05abe8ee78fd60d6588b8344cd",
"sha256:4ba3bd26f282b201fdbce351f1c5d17ceb224cbedb73d6e96e6ce391b354aacc", "sha256:31dfa2fc323097f8ad7acd41aa38d7c614dd1960ac6681745b6da124093dc351",
"sha256:4c6e78d042e93751f60672989efbd6a6bc54213ed7ff695fff82784bbb9ea035", "sha256:34f82db7f80c49f38b032c5abb605c458bac997a6c3142e0d6c130be6fb2b941",
"sha256:4d80d1901b89cc935a6cf5b9fd89df66565272722fe2e5473168927a9937e0ca", "sha256:3d5dd8e5998fb4ace04789d1d008e2bb532de501218519d70bb672c4c5a2fc5d",
"sha256:4fcf71d33178a00cc34a57b29f5dab1734b9ce0f1c97fb34666deefac6f92037", "sha256:4a6ae52bd3ee41ee0f3acf4c60ceb3f44e0e3bc52ab7da1c2b2aa6703363a3d1",
"sha256:52f7670b41d4b4d97866ebc38121de8bcb9813128b7c4942b07794d08193c0ab", "sha256:4b02a3b2a2f01d0490dd39321c74273fed0568568ea0e7ea23e02bd1fb10a10b",
"sha256:5368e2b7649a26b7253c6c9e53241248aab9da49099442f5be238fde436f18c9", "sha256:4b843f8e1dd6a3195679d9838eb4670222e8b8d01bc36c9894d6c3538316fa0a",
"sha256:5bb65fbb48999044938f0c0508e929b14a9b8bf4939d8263e9ea6691f7b54663", "sha256:5de53a28f40ef3c4fd57aeab6b590c2c663de87a5af76136ced519923d3efbb3",
"sha256:60672bb5577472800fcca1ac9dae232d1461db9f20f055184be8ce54b0052572", "sha256:61b2b33ede821b94fa99ce0b09c9ece049c7067a33b279f343adfe35108a4ea7",
"sha256:669e9be6d148fc0283f53e17dd140cde4dc7c87edac8319147edd5aa2a830771", "sha256:6a3a9b0f45fd75dc05d8e93dc21b18fc1670135ec9544d1ad4acbcf6b86781d0",
"sha256:6a0b7a804e8d1716aa2c72e73210b48be83d25ba9ec5cf52cf91122285707bb1", "sha256:76ad8e4c69dadbb31bad17c16baee61c0d1a4a73bed2590b741b2e1a46d3edd0",
"sha256:79034ea3da3cf2a815e3e52afdc1f6c1894468c98bdce5d2546fa2342585497f", "sha256:7ba19b777dc00194d1b473180d4ca89a054dd18de27d0ee2e42a103ec9b7d014",
"sha256:79247feeef6abcc11137ad17922e865052f23447152059402fc320f99ff544bb", "sha256:7c1b7eab7a49aa96f3db1f716f0113a8a2e93c7375dd3d5d21c4941f1405c9c5",
"sha256:81671c2049e6bf42c7fd11a060f8bc58f58b7b3d6f3f951fc0b15e376a6a5a98", "sha256:7fc0eee3046041387cbace9314926aa48b681202f8897f8bff3809967a049036",
"sha256:82ac4a5cb56cc9280d4ae52c2d2ebcd6e0668dd0f9ef17f0a9d7c82bd61e24fa", "sha256:8ccd1c5fff1aa1427100ce188557fc31f1e0a383ad8ec42c559aabd4ff08802d",
"sha256:9436267dbbaa49dad18fbbb54f85386b0f5818d055e7b8e01d219661b6745279", "sha256:8e08dd76de80539d613654915a2f5196dbccc67448df291e69a88712ea21e24a",
"sha256:94e4140bb1343115a1afd6d84ebf8fca5fb7bfb50e1c2cbd6f2fb5d3117ef102", "sha256:c18498c50c59263841862ea0501da9f2b3659c00db54abfbf823a80787fde8ce",
"sha256:a2cab366eae8a0ffe0813fd8e335cf0d6b9bb6c5227315f53bb457519b811537", "sha256:c49db89d602c24928e68c0d510f4fcf8989d77defd01c973d6cbe27e684833b1",
"sha256:a596019c3eafb1b0ae07db9f55a08578b43c79adb1fe1ab1fd818430ae59ee6f", "sha256:ce20044d0317649ddbb4e54dab3c1bcc7483c78c27d3f58ab3d0c7e6bc60d26a",
"sha256:e8848ae3cd6a784c29fae5055028bee9bffcc704d8bcad09bd46b42b44a833e2", "sha256:d1071414dd06ca2eafa90c85a079169bfeb0e5f57fd0b45d44c092546fcd6fd9",
"sha256:e8a048bfd7d5a280f27527d11449a509ddedf08b58a09a24314828631c099306", "sha256:d3be11ac43ab1a3e979dac80843b42226d5d3cccd3986f2e03152720a4297cd7",
"sha256:f6dd28a0ac60e2426a6918f36f1b4e2620fc785a0de7654cd206ba842eee57fd" "sha256:db603a1c235d110c860d5f39988ebc8218ee028f07a7cbc056ba6424372ca31b"
], ],
"version": "==4.4.2" "version": "==4.5.2"
}, },
"pillow": { "pillow": {
"hashes": [ "hashes": [
@ -344,10 +400,10 @@
}, },
"sortedcontainers": { "sortedcontainers": {
"hashes": [ "hashes": [
"sha256:220bb2e3e1886297fd7cdd6d164cb5cf237be1cfae1a3a3e526d149c52816682", "sha256:974e9a32f56b17c1bac2aebd9dcf197f3eb9cd30553c5852a3187ad162e1a03a",
"sha256:b74f2756fb5e23512572cc76f0fe0832fd86310f77dfee54335a35fb33f6b950" "sha256:d9e96492dd51fae31e60837736b38fe42a187b5404c16606ff7ee7cd582d4c60"
], ],
"version": "==2.0.5" "version": "==2.1.0"
}, },
"typing-extensions": { "typing-extensions": {
"hashes": [ "hashes": [
@ -390,6 +446,20 @@
"sha256:6a51cf18d9de612892b9c1d38a8c1bdadec0cfe15de61cd5c0f09174bf0c7e82" "sha256:6a51cf18d9de612892b9c1d38a8c1bdadec0cfe15de61cd5c0f09174bf0c7e82"
], ],
"version": "==0.12.0" "version": "==0.12.0"
},
"yarl": {
"hashes": [
"sha256:2556b779125621b311844a072e0ed367e8409a18fa12cbd68eb1258d187820f9",
"sha256:4aec0769f1799a9d4496827292c02a7b1f75c0bab56ab2b60dd94ebb57cbd5ee",
"sha256:55369d95afaacf2fa6b49c84d18b51f1704a6560c432a0f9a1aeb23f7b971308",
"sha256:6c098b85442c8fe3303e708bbb775afd0f6b29f77612e8892627bcab4b939357",
"sha256:9182cd6f93412d32e009020a44d6d170d2093646464a88aeec2aef50592f8c78",
"sha256:c8cbc21bbfa1dd7d5386d48cc814fe3d35b80f60299cdde9279046f399c3b0d8",
"sha256:db6f70a4b09cde813a4807843abaaa60f3b15fb4a2a06f9ae9c311472662daa1",
"sha256:f17495e6fe3d377e3faac68121caef6f974fcb9e046bc075bcff40d8e5cc69a4",
"sha256:f85900b9cca0c67767bb61b2b9bd53208aaa7373dae633dbe25d179b4bf38aa7"
],
"version": "==1.2.6"
} }
}, },
"develop": { "develop": {

View File

@ -28,12 +28,16 @@ class Config:
# e.g 'gateway.example.com' for reverse proxies. # e.g 'gateway.example.com' for reverse proxies.
WEBSOCKET_URL = 'localhost:5001' WEBSOCKET_URL = 'localhost:5001'
# Where to host the websocket? #: Where to host the websocket?
# (a local address the server will bind to) # (a local address the server will bind to)
WS_HOST = '0.0.0.0' WS_HOST = '0.0.0.0'
WS_PORT = 5001 WS_PORT = 5001
# Postgres credentials #: Mediaproxy URL on the internet
# mediaproxy is made to prevent client IPs being leaked.
MEDIA_PROXY = 'localhost:5002'
#: Postgres credentials
POSTGRES = {} POSTGRES = {}

View File

@ -12,7 +12,7 @@ from litecord.snowflake import get_snowflake
from litecord.schemas import validate, MESSAGE_CREATE from litecord.schemas import validate, MESSAGE_CREATE
from litecord.utils import pg_set_json from litecord.utils import pg_set_json
from litecord.embed import sanitize_embed from litecord.embed.sanitizer import fill_embed
log = Logger(__name__) log = Logger(__name__)
@ -260,7 +260,10 @@ async def _create_message(channel_id):
'tts': is_tts, 'tts': is_tts,
'nonce': int(j.get('nonce', 0)), 'nonce': int(j.get('nonce', 0)),
'everyone_mention': mentions_everyone or mentions_here, 'everyone_mention': mentions_everyone or mentions_here,
'embeds': [sanitize_embed(j['embed'])] if 'embed' in j else [],
# fill_embed takes care of filling proxy and width/height
'embeds': ([await fill_embed(j['embed'])]
if 'embed' in j else []),
}) })
payload = await app.storage.get_message(message_id, user_id) payload = await app.storage.get_message(message_id, user_id)

View File

@ -4,7 +4,9 @@ litecord.embed.sanitizer
such as type: rich such as type: rich
""" """
from typing import Dict, Any from typing import Dict, Any
from logbook import Logger from logbook import Logger
from quart import current_app as app
log = Logger(__name__) log = Logger(__name__)
Embed = Dict[str, Any] Embed = Dict[str, Any]
@ -12,7 +14,7 @@ Embed = Dict[str, Any]
def sanitize_embed(embed: Embed) -> Embed: def sanitize_embed(embed: Embed) -> Embed:
"""Sanitize an embed object. """Sanitize an embed object.
This is non-complex sanitization as it doesn't This is non-complex sanitization as it doesn't
need the app object. need the app object.
""" """
@ -53,21 +55,58 @@ def path_exists(embed: Embed, components: str):
return False return False
def proxify(url) -> str:
"""Return a mediaproxy url for the given EmbedURL."""
md_base_url = app.config['MEDIA_PROXY']
parsed = url.parsed
proto = 'https' if app.config['IS_SSL'] else 'http'
return (
# base mediaproxy url
f'{proto}://{md_base_url}/img/'
f'{parsed.scheme}/{parsed.netloc}{parsed.path}'
)
async def fetch_metadata(url) -> dict:
"""Fetch metadata for a url."""
parsed = url.parsed
md_path = f'{parsed.scheme}/{parsed.netloc}{parsed.path}'
md_base_url = app.config['MEDIA_PROXY']
proto = 'https' if app.config['IS_SSL'] else 'http'
request_url = f'{proto}://{md_base_url}/meta/{md_path}'
async with app.session.get(request_url) as resp:
if resp.status != 200:
return
return await resp.json()
async def fill_embed(embed: Embed) -> Embed: async def fill_embed(embed: Embed) -> Embed:
"""Fill an embed with more information.""" """Fill an embed with more information."""
embed = sanitize_embed(embed) embed = sanitize_embed(embed)
if path_exists(embed, 'footer.icon_url'): if path_exists(embed, 'footer.icon_url'):
# TODO: make proxy_icon_url embed['footer']['proxy_icon_url'] = \
log.warning('embed with footer.icon_url, ignoring') proxify(embed['footer']['icon_url'])
if path_exists(embed, 'image.url'):
# TODO: make proxy_icon_url, width, height
log.warning('embed with footer.image_url, ignoring')
if path_exists(embed, 'author.icon_url'): if path_exists(embed, 'author.icon_url'):
# TODO: should we check icon_url and convert it into embed['author']['proxy_icon_url'] = \
# a proxied icon url? proxify(embed['author']['icon_url'])
log.warning('embed with author.icon_url, ignoring')
if path_exists(embed, 'image.url'):
image_url = embed['image']['url']
meta = await fetch_metadata(image_url)
embed['image']['proxy_url'] = proxify(image_url)
if meta and meta['image']:
embed['image']['width'] = meta['width']
embed['image']['height'] = meta['height']
return embed return embed

View File

@ -54,6 +54,8 @@ EMBED_AUTHOR = {
'icon_url': { 'icon_url': {
'coerce': EmbedURL, 'required': False, 'coerce': EmbedURL, 'required': False,
} }
# NOTE: proxy_icon_url set by us
} }
EMBED_FIELD = { EMBED_FIELD = {

3
run.py
View File

@ -8,6 +8,7 @@ import websockets
from quart import Quart, g, jsonify, request from quart import Quart, g, jsonify, request
from logbook import StreamHandler, Logger from logbook import StreamHandler, Logger
from logbook.compat import redirect_logging from logbook.compat import redirect_logging
from aiohttp import ClientSession
# import the config set by instance owner # import the config set by instance owner
import config import config
@ -281,6 +282,8 @@ async def app_before_serving():
g.app = app g.app = app
g.loop = asyncio.get_event_loop() g.loop = asyncio.get_event_loop()
app.session = ClientSession()
init_app_managers(app) init_app_managers(app)
# start the websocket, etc # start the websocket, etc