a lot of changes
This commit is contained in:
parent
c2796a5075
commit
24ae540ea5
|
@ -87,7 +87,7 @@ class Application(sanic.Sanic):
|
||||||
|
|
||||||
def add_middleware(self, middleware):
|
def add_middleware(self, middleware):
|
||||||
mw = middleware(self)
|
mw = middleware(self)
|
||||||
self.register_middleware(mw.handler, mw.attach)
|
self.register_middleware(mw, mw.attach)
|
||||||
|
|
||||||
|
|
||||||
def get_menu_item(self, name):
|
def get_menu_item(self, name):
|
||||||
|
|
|
@ -14,9 +14,11 @@ class UserLevel(IntEnum):
|
||||||
AUTH = 1000
|
AUTH = 1000
|
||||||
|
|
||||||
|
|
||||||
|
# Note: sub-classing the Request class breaks things for some reason
|
||||||
class Config(DotDict):
|
class Config(DotDict):
|
||||||
defaults = dict(
|
defaults = dict(
|
||||||
name = 'IzzyLib Http Server',
|
name = 'IzzyLib Http Server',
|
||||||
|
title = None,
|
||||||
version = '0.0.1',
|
version = '0.0.1',
|
||||||
git_repo = 'https://git.barkshark.xyz/izaliamae/izzylib',
|
git_repo = 'https://git.barkshark.xyz/izaliamae/izzylib',
|
||||||
listen = 'localhost',
|
listen = 'localhost',
|
||||||
|
@ -50,6 +52,9 @@ class Config(DotDict):
|
||||||
if kwargs.get('host') and not kwargs.get('web_host'):
|
if kwargs.get('host') and not kwargs.get('web_host'):
|
||||||
self.web_host = self.host
|
self.web_host = self.host
|
||||||
|
|
||||||
|
if self.name and not self.title:
|
||||||
|
self.title = self.name
|
||||||
|
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
if key not in self.defaults.keys():
|
if key not in self.defaults.keys():
|
||||||
|
|
|
@ -30,6 +30,9 @@ class GenericError:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
if 'json' in request.headers.get('accept', ''):
|
||||||
|
return response.json(msg, status=status)
|
||||||
|
|
||||||
return response.error(msg, status, pprint=True)
|
return response.error(msg, status, pprint=True)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
%html
|
%html
|
||||||
%head
|
%head
|
||||||
%title << {{cfg.name}}: {{page}}
|
%title << {{cfg.title}}: {{page}}
|
||||||
%link(rel='stylesheet' type='text/css' href='/framework/style.css')
|
%link(rel='stylesheet' type='text/css' href='/framework/style.css')
|
||||||
%link(rel='manifest' href='/framework/manifest.json')
|
%link(rel='manifest' href='/framework/manifest.json')
|
||||||
%meta(charset='UTF-8')
|
%meta(charset='UTF-8')
|
||||||
|
@ -13,10 +13,10 @@
|
||||||
#header.flex-container
|
#header.flex-container
|
||||||
-if menu_left
|
-if menu_left
|
||||||
#btn.section
|
#btn.section
|
||||||
.page-title.section -> %a.title(href='/') << {{cfg.name}}
|
.page-title.section -> %a.title(href='/') << {{cfg.title}}
|
||||||
|
|
||||||
-else
|
-else
|
||||||
.page-title.section -> %a.title(href='/') << {{cfg.name}}
|
.page-title.section -> %a.title(href='/') << {{cfg.title}}
|
||||||
#btn.section
|
#btn.section
|
||||||
|
|
||||||
-if message
|
-if message
|
||||||
|
|
|
@ -4,6 +4,7 @@ from datetime import datetime, timedelta, timezone
|
||||||
from izzylib import izzylog as logging, logging as applog
|
from izzylib import izzylog as logging, logging as applog
|
||||||
|
|
||||||
from . import start_time
|
from . import start_time
|
||||||
|
from .response import Response
|
||||||
|
|
||||||
|
|
||||||
cache_types = [
|
cache_types = [
|
||||||
|
@ -42,7 +43,14 @@ class MiddlewareBase:
|
||||||
self.cfg = app.cfg
|
self.cfg = app.cfg
|
||||||
|
|
||||||
|
|
||||||
async def handler(self, request):
|
async def __call__(self, request, response=None):
|
||||||
|
if not response:
|
||||||
|
response = Response(self.app, request)
|
||||||
|
|
||||||
|
return await self.handler(request, response)
|
||||||
|
|
||||||
|
|
||||||
|
async def handler(self, request, response):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import json
|
||||||
|
|
||||||
from izzylib import LowerDotDict
|
from izzylib import LowerDotDict
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,3 +31,11 @@ class Headers(LowerDotDict):
|
||||||
|
|
||||||
def getall(self, key, default=[]):
|
def getall(self, key, default=[]):
|
||||||
return self.get(key.lower(), default)
|
return self.get(key.lower(), default)
|
||||||
|
|
||||||
|
|
||||||
|
def to_json(self, indent=None):
|
||||||
|
return json.dumps(self.to_dict(), indent=indent)
|
||||||
|
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
return {k: self.getone(k) for k in self}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import sanic
|
import sanic
|
||||||
|
|
||||||
from izzylib import DotDict
|
from izzylib import DotDict
|
||||||
|
from urllib.parse import parse_qsl
|
||||||
|
|
||||||
from .misc import Headers
|
from .misc import Headers
|
||||||
|
|
||||||
|
|
|
@ -62,11 +62,11 @@ class Response:
|
||||||
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.body
|
return str(self.body)
|
||||||
|
|
||||||
|
|
||||||
def __bytes__(self):
|
def __bytes__(self):
|
||||||
return self.body.encode('utf-8')
|
return self.body if isinstance(self.body, bytes) else self.body.encode('utf-8')
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
|
|
@ -11,7 +11,7 @@ from izzylib.exceptions import HttpFileDownloadedError
|
||||||
from ssl import SSLCertVerificationError
|
from ssl import SSLCertVerificationError
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
from .signature import sign_request
|
from .signature import sign_request, set_client
|
||||||
|
|
||||||
|
|
||||||
Client = None
|
Client = None
|
||||||
|
@ -111,7 +111,7 @@ class HttpRequestsClient(object):
|
||||||
|
|
||||||
|
|
||||||
class HttpRequestsRequest(object):
|
class HttpRequestsRequest(object):
|
||||||
def __init__(self, client, url, data=None, headers={}, query={}, method='get'):
|
def __init__(self, client, url, data=b'', headers={}, query={}, method='get'):
|
||||||
parsed = urlparse(url)
|
parsed = urlparse(url)
|
||||||
self.args = [url]
|
self.args = [url]
|
||||||
self.kwargs = DotDict({'params': query})
|
self.kwargs = DotDict({'params': query})
|
||||||
|
@ -119,6 +119,7 @@ class HttpRequestsRequest(object):
|
||||||
self.client = client
|
self.client = client
|
||||||
self.path = parsed.path
|
self.path = parsed.path
|
||||||
self.host = parsed.netloc
|
self.host = parsed.netloc
|
||||||
|
self.body = data
|
||||||
|
|
||||||
new_headers = client.headers.copy()
|
new_headers = client.headers.copy()
|
||||||
new_headers.update(headers)
|
new_headers.update(headers)
|
||||||
|
@ -129,7 +130,6 @@ class HttpRequestsRequest(object):
|
||||||
parsed_headers['user-agent'] = client.agent
|
parsed_headers['user-agent'] = client.agent
|
||||||
|
|
||||||
self.kwargs['headers'] = DotDict(new_headers)
|
self.kwargs['headers'] = DotDict(new_headers)
|
||||||
self.kwargs['data'] = data
|
|
||||||
|
|
||||||
if client.proxy.enabled:
|
if client.proxy.enabled:
|
||||||
self.kwargs['proxies'] = DotDict({self.proxy.ptype: f'{self.proxy.ptype}://{self.proxy.host}:{self.proxy.port}'})
|
self.kwargs['proxies'] = DotDict({self.proxy.ptype: f'{self.proxy.ptype}://{self.proxy.host}:{self.proxy.port}'})
|
||||||
|
@ -142,7 +142,7 @@ class HttpRequestsRequest(object):
|
||||||
|
|
||||||
@body.setter
|
@body.setter
|
||||||
def body(self, data):
|
def body(self, data):
|
||||||
self.kwargs.data = data
|
self.kwargs.data = data.encode('utf-8') if isinstance(data, str) else data
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -224,3 +224,4 @@ class HttpRequestsResponse(object):
|
||||||
def set_requests_client(client=None):
|
def set_requests_client(client=None):
|
||||||
global Client
|
global Client
|
||||||
Client = client or RequestsClient()
|
Client = client or RequestsClient()
|
||||||
|
set_client(Client)
|
||||||
|
|
|
@ -6,6 +6,7 @@ from Crypto.Hash import SHA256
|
||||||
from Crypto.PublicKey import RSA
|
from Crypto.PublicKey import RSA
|
||||||
from Crypto.Signature import PKCS1_v1_5
|
from Crypto.Signature import PKCS1_v1_5
|
||||||
from base64 import b64decode, b64encode
|
from base64 import b64decode, b64encode
|
||||||
|
from datetime import datetime
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from izzylib import DefaultDotDict, DotDict
|
from izzylib import DefaultDotDict, DotDict
|
||||||
from izzylib import izzylog as logging
|
from izzylib import izzylog as logging
|
||||||
|
@ -13,6 +14,15 @@ from tldextract import extract
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
|
||||||
|
Client = None
|
||||||
|
|
||||||
|
|
||||||
|
def set_client(client):
|
||||||
|
global Client
|
||||||
|
|
||||||
|
Client = client
|
||||||
|
|
||||||
|
|
||||||
@lru_cache(maxsize=512)
|
@lru_cache(maxsize=512)
|
||||||
def fetch_actor(url):
|
def fetch_actor(url):
|
||||||
if not Client:
|
if not Client:
|
||||||
|
@ -126,6 +136,7 @@ def parse_signature(signature: str):
|
||||||
sig.headers = sig.headers.split()
|
sig.headers = sig.headers.split()
|
||||||
sig.domain = urlparse(sig.keyid).netloc
|
sig.domain = urlparse(sig.keyid).netloc
|
||||||
sig.top_domain = '.'.join(extract(sig.domain)[1:])
|
sig.top_domain = '.'.join(extract(sig.domain)[1:])
|
||||||
|
sig.actor = sig.keyid.split('#')[0]
|
||||||
|
|
||||||
return sig
|
return sig
|
||||||
|
|
||||||
|
@ -152,7 +163,6 @@ def verify_headers(headers: dict, method: str, path: str, actor: dict=None, body
|
||||||
|
|
||||||
if not actor:
|
if not actor:
|
||||||
actor = fetch_actor(signature.keyid)
|
actor = fetch_actor(signature.keyid)
|
||||||
print(actor)
|
|
||||||
|
|
||||||
## Add digest header to missing headers list if it doesn't exist
|
## Add digest header to missing headers list if it doesn't exist
|
||||||
if method.lower() == 'post' and not digest:
|
if method.lower() == 'post' and not digest:
|
||||||
|
@ -181,9 +191,7 @@ async def verify_request(request, actor: dict=None):
|
||||||
actor: A dictionary containing the activitypub actor and the link to the pubkey used for verification
|
actor: A dictionary containing the activitypub actor and the link to the pubkey used for verification
|
||||||
'''
|
'''
|
||||||
|
|
||||||
body = (await request.body) if request.body else None
|
return verify_headers(request.Headers.to_dict(), request.method, request.path, actor, request.body)
|
||||||
headers = {k.lower(): v[0] for k,v in request.headers.items()}
|
|
||||||
return verify_headers(headers, request.method, request.path, actor, body)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -223,6 +231,8 @@ def sign_pkcs_headers(key: str, headers: dict, sig=None):
|
||||||
|
|
||||||
|
|
||||||
def sign_request(request, privkey, keyid):
|
def sign_request(request, privkey, keyid):
|
||||||
|
assert isinstance(request.body, bytes)
|
||||||
|
|
||||||
request.add_header('(request-target)', f'{request.method.lower()} {request.path}')
|
request.add_header('(request-target)', f'{request.method.lower()} {request.path}')
|
||||||
request.add_header('host', request.host)
|
request.add_header('host', request.host)
|
||||||
request.add_header('date', datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT'))
|
request.add_header('date', datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT'))
|
||||||
|
@ -230,7 +240,7 @@ def sign_request(request, privkey, keyid):
|
||||||
if request.body:
|
if request.body:
|
||||||
body_hash = b64encode(SHA256.new(request.body).digest()).decode("UTF-8")
|
body_hash = b64encode(SHA256.new(request.body).digest()).decode("UTF-8")
|
||||||
request.add_header('digest', f'SHA-256={body_hash}')
|
request.add_header('digest', f'SHA-256={body_hash}')
|
||||||
request.add_header('content-length', len(request.body))
|
request.add_header('content-length', str(len(request.body)))
|
||||||
|
|
||||||
sig = {
|
sig = {
|
||||||
'keyId': keyid,
|
'keyId': keyid,
|
||||||
|
|
Loading…
Reference in a new issue