mirror of
https://github.com/YunoHost/check-http.git
synced 2024-09-03 19:56:42 +02:00
Implement nonce mechanism
This commit is contained in:
parent
b593e6ba77
commit
9a68ffabc1
1 changed files with 35 additions and 7 deletions
42
server.py
42
server.py
|
@ -1,3 +1,4 @@
|
|||
import re
|
||||
import time
|
||||
import asyncio
|
||||
import aiodns
|
||||
|
@ -65,8 +66,13 @@ async def query_dns(host, dns_entry_type):
|
|||
async def check_http(request):
|
||||
"""
|
||||
This function received an HTTP request from a YunoHost instance while this
|
||||
server is hosted on our infrastructure. The expected request body is:
|
||||
{"domain": "domain-to-check.tld"} and the method POST
|
||||
server is hosted on our infrastructure. The request is expected to be a
|
||||
POST request with a body like {"domain": "domain-to-check.tld",
|
||||
"nonce": "1234567890abcdef" }
|
||||
|
||||
The nonce value is a single-use ID, and we will try to reach
|
||||
http://domain.tld/.well-known/ynh-{nonce} which should return 200 if we
|
||||
are indeed reaching the right server.
|
||||
|
||||
The general workflow is the following:
|
||||
|
||||
|
@ -75,7 +81,7 @@ async def check_http(request):
|
|||
- get json from body and domain from it
|
||||
- check for domain based rate limit (see RATE_LIMIT_SECONDS value)
|
||||
- check domain is in valid format
|
||||
- now try to do an http request on the ip using the domain as target host
|
||||
- try to do an http request on the ip (using the domain as target host) for the page /.well-known/ynh-diagnosis/{nonce}
|
||||
- answer saying if the domain can be reached
|
||||
"""
|
||||
|
||||
|
@ -83,6 +89,10 @@ async def check_http(request):
|
|||
now = time.time()
|
||||
clear_rate_limit_db(now)
|
||||
|
||||
# ############################################# #
|
||||
# Validate request and extract the parameters #
|
||||
# ############################################# #
|
||||
|
||||
ip = request.ip
|
||||
|
||||
check_rate_limit_ip = check_rate_limit(ip, now)
|
||||
|
@ -99,12 +109,12 @@ async def check_http(request):
|
|||
"content": "Invalid usage, body isn't proper json",
|
||||
}, status=400)
|
||||
|
||||
if not data or "domain" not in data:
|
||||
logger.info(f"Unvalid request didn't specified a domain (body is : {request.body}")
|
||||
if not data or "domain" not in data or "nonce" not in data:
|
||||
logger.info(f"Unvalid request didn't specified a domain and a nonce id (body is : {request.body}")
|
||||
return json_response({
|
||||
"status": "error",
|
||||
"code": "error_no_domain",
|
||||
"content": "Request must specify a domain",
|
||||
"content": "Request must specify a domain and a nonce",
|
||||
}, status=400)
|
||||
|
||||
domain = data["domain"]
|
||||
|
@ -121,14 +131,32 @@ async def check_http(request):
|
|||
"content": "domain is not in the right format (do not include http:// or https://)",
|
||||
}, status=400)
|
||||
|
||||
nonce = data["nonce"]
|
||||
|
||||
# nonce id is arbitrarily defined to be a
|
||||
# 16-digit hexadecimal string
|
||||
if not re.match(r"^[a-f0-9]{16}$", nonce):
|
||||
logger.info(f"Invalid request, is not in the right format (nonce is : {nonce})")
|
||||
return json_response({
|
||||
"status": "error",
|
||||
"code": "error_nonce_bad_format",
|
||||
"content": "nonce is not in the right format (it should be a 16-digit hexadecimal string)",
|
||||
}, status=400)
|
||||
|
||||
# ############################################# #
|
||||
# Run the actual check #
|
||||
# ############################################# #
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
try:
|
||||
async with session.get("http://" + ip,
|
||||
url = "http://" + ip + "/.well-known/ynh-diagnosis/" + nonce
|
||||
async with session.get(url,
|
||||
headers={"Host": domain},
|
||||
timeout=aiohttp.ClientTimeout(total=30)) as response:
|
||||
# XXX in the futur try to do a double check with the server to
|
||||
# see if the correct content is get
|
||||
await response.text()
|
||||
assert response.status == 200
|
||||
logger.info(f"Success when checking http access for {domain} asked by {ip}")
|
||||
# TODO various kind of errors
|
||||
except aiohttp.client_exceptions.ClientConnectorError:
|
||||
|
|
Loading…
Reference in a new issue