mirror of
https://git.collinwebdesigns.de/oscar.krause/fastapi-dls.git
synced 2024-11-23 15:31:00 +03:00
implemented "SUPPORT_MALFORMED_JSON" variable
This commit is contained in:
parent
018d7c34fc
commit
15f14cac11
@ -48,6 +48,7 @@ package() {
|
|||||||
install -Dm755 "$srcdir/$pkgname/app/main.py" "$pkgdir/opt/$pkgname/main.py"
|
install -Dm755 "$srcdir/$pkgname/app/main.py" "$pkgdir/opt/$pkgname/main.py"
|
||||||
install -Dm755 "$srcdir/$pkgname/app/orm.py" "$pkgdir/opt/$pkgname/orm.py"
|
install -Dm755 "$srcdir/$pkgname/app/orm.py" "$pkgdir/opt/$pkgname/orm.py"
|
||||||
install -Dm755 "$srcdir/$pkgname/app/util.py" "$pkgdir/opt/$pkgname/util.py"
|
install -Dm755 "$srcdir/$pkgname/app/util.py" "$pkgdir/opt/$pkgname/util.py"
|
||||||
|
install -Dm755 "$srcdir/$pkgname/app/middleware.py" "$pkgdir/opt/$pkgname/middleware.py"
|
||||||
install -Dm644 "$srcdir/$pkgname.default" "$pkgdir/etc/default/$pkgname"
|
install -Dm644 "$srcdir/$pkgname.default" "$pkgdir/etc/default/$pkgname"
|
||||||
install -Dm644 "$srcdir/$pkgname.service" "$pkgdir/usr/lib/systemd/system/$pkgname.service"
|
install -Dm644 "$srcdir/$pkgname.service" "$pkgdir/usr/lib/systemd/system/$pkgname.service"
|
||||||
install -Dm644 "$srcdir/$pkgname.tmpfiles" "$pkgdir/usr/lib/tmpfiles.d/$pkgname.conf"
|
install -Dm644 "$srcdir/$pkgname.tmpfiles" "$pkgdir/usr/lib/tmpfiles.d/$pkgname.conf"
|
||||||
|
@ -140,6 +140,7 @@ test:
|
|||||||
- test/**/*
|
- test/**/*
|
||||||
variables:
|
variables:
|
||||||
DATABASE: sqlite:///../app/db.sqlite
|
DATABASE: sqlite:///../app/db.sqlite
|
||||||
|
SUPPORT_MALFORMED_JSON: true
|
||||||
parallel:
|
parallel:
|
||||||
matrix:
|
matrix:
|
||||||
- IMAGE: [ 'python:3.12-slim-bookworm' ]
|
- IMAGE: [ 'python:3.12-slim-bookworm' ]
|
||||||
|
31
README.md
31
README.md
@ -410,21 +410,22 @@ After first success you have to replace `--issue` with `--renew`.
|
|||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
|
|
||||||
| Variable | Default | Usage |
|
| Variable | Default | Usage |
|
||||||
|------------------------|----------------------------------------|------------------------------------------------------------------------------------------------------|
|
|--------------------------|----------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `DEBUG` | `false` | Toggles `fastapi` debug mode |
|
| `DEBUG` | `false` | Toggles `fastapi` debug mode |
|
||||||
| `DLS_URL` | `localhost` | Used in client-token to tell guest driver where dls instance is reachable |
|
| `DLS_URL` | `localhost` | Used in client-token to tell guest driver where dls instance is reachable |
|
||||||
| `DLS_PORT` | `443` | Used in client-token to tell guest driver where dls instance is reachable |
|
| `DLS_PORT` | `443` | Used in client-token to tell guest driver where dls instance is reachable |
|
||||||
| `TOKEN_EXPIRE_DAYS` | `1` | Client auth-token validity (used for authenticate client against api, **not `.tok` file!**) |
|
| `TOKEN_EXPIRE_DAYS` | `1` | Client auth-token validity (used for authenticate client against api, **not `.tok` file!**) |
|
||||||
| `LEASE_EXPIRE_DAYS` | `90` | Lease time in days |
|
| `LEASE_EXPIRE_DAYS` | `90` | Lease time in days |
|
||||||
| `LEASE_RENEWAL_PERIOD` | `0.15` | The percentage of the lease period that must elapse before a licensed client can renew a license \*1 |
|
| `LEASE_RENEWAL_PERIOD` | `0.15` | The percentage of the lease period that must elapse before a licensed client can renew a license \*1 |
|
||||||
| `DATABASE` | `sqlite:///db.sqlite` | See [official SQLAlchemy docs](https://docs.sqlalchemy.org/en/14/core/engines.html) |
|
| `DATABASE` | `sqlite:///db.sqlite` | See [official SQLAlchemy docs](https://docs.sqlalchemy.org/en/14/core/engines.html) |
|
||||||
| `CORS_ORIGINS` | `https://{DLS_URL}` | Sets `Access-Control-Allow-Origin` header (comma separated string) \*2 |
|
| `CORS_ORIGINS` | `https://{DLS_URL}` | Sets `Access-Control-Allow-Origin` header (comma separated string) \*2 |
|
||||||
| `SITE_KEY_XID` | `00000000-0000-0000-0000-000000000000` | Site identification uuid |
|
| `SITE_KEY_XID` | `00000000-0000-0000-0000-000000000000` | Site identification uuid |
|
||||||
| `INSTANCE_REF` | `10000000-0000-0000-0000-000000000001` | Instance identification uuid |
|
| `INSTANCE_REF` | `10000000-0000-0000-0000-000000000001` | Instance identification uuid |
|
||||||
| `ALLOTMENT_REF` | `20000000-0000-0000-0000-000000000001` | Allotment identification uuid |
|
| `ALLOTMENT_REF` | `20000000-0000-0000-0000-000000000001` | Allotment identification uuid |
|
||||||
| `INSTANCE_KEY_RSA` | `<app-dir>/cert/instance.private.pem` | Site-wide private RSA key for singing JWTs \*3 |
|
| `INSTANCE_KEY_RSA` | `<app-dir>/cert/instance.private.pem` | Site-wide private RSA key for singing JWTs \*3 |
|
||||||
| `INSTANCE_KEY_PUB` | `<app-dir>/cert/instance.public.pem` | Site-wide public key \*3 |
|
| `INSTANCE_KEY_PUB` | `<app-dir>/cert/instance.public.pem` | Site-wide public key \*3 |
|
||||||
|
| `SUPPORT_MALFORMED_JSON` | `false` | Support parsing for mal formatted "mac_address_list" ([Issue](https://git.collinwebdesigns.de/oscar.krause/fastapi-dls/-/issues/1)) |
|
||||||
|
|
||||||
\*1 For example, if the lease period is one day and the renewal period is 20%, the client attempts to renew its license
|
\*1 For example, if the lease period is one day and the renewal period is 20%, the client attempts to renew its license
|
||||||
every 4.8 hours. If network connectivity is lost, the loss of connectivity is detected during license renewal and the
|
every 4.8 hours. If network connectivity is lost, the loss of connectivity is detected during license renewal and the
|
||||||
|
@ -96,6 +96,11 @@ app.add_middleware(
|
|||||||
allow_methods=['*'],
|
allow_methods=['*'],
|
||||||
allow_headers=['*'],
|
allow_headers=['*'],
|
||||||
)
|
)
|
||||||
|
if bool(env('SUPPORT_MALFORMED_JSON', False)):
|
||||||
|
from middleware import PatchMalformedJsonMiddleware
|
||||||
|
|
||||||
|
logger.info(f'Enabled "PatchMalformedJsonMiddleware"!')
|
||||||
|
app.add_middleware(PatchMalformedJsonMiddleware, enabled=True)
|
||||||
|
|
||||||
|
|
||||||
# Helper
|
# Helper
|
||||||
|
40
app/middleware.py
Normal file
40
app/middleware.py
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import re
|
||||||
|
|
||||||
|
from starlette.middleware.base import BaseHTTPMiddleware
|
||||||
|
from starlette.requests import Request
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class PatchMalformedJsonMiddleware(BaseHTTPMiddleware):
|
||||||
|
# see oscar.krause/fastapi-dls#1
|
||||||
|
|
||||||
|
def __init__(self, app, enabled: bool):
|
||||||
|
super().__init__(app)
|
||||||
|
self.enabled = enabled
|
||||||
|
|
||||||
|
async def dispatch(self, request: Request, call_next):
|
||||||
|
body = await request.body()
|
||||||
|
content_type = request.headers.get('Content-Type')
|
||||||
|
|
||||||
|
if self.enabled and content_type == 'application/json':
|
||||||
|
body = body.decode()
|
||||||
|
try:
|
||||||
|
json.loads(body)
|
||||||
|
except json.decoder.JSONDecodeError:
|
||||||
|
logger.warning(f'Malformed json received! Try to fix it, "PatchMalformedJsonMiddleware" is enabled.')
|
||||||
|
body = body.replace('\t', '')
|
||||||
|
body = body.replace('\n', '')
|
||||||
|
|
||||||
|
regex = '(\"mac_address_list\"\:\s?\[)([\w\d])'
|
||||||
|
s = re.sub(regex, r'\1"\2', body)
|
||||||
|
logger.debug(f'Fixed JSON: "{s}"')
|
||||||
|
s = json.loads(s) # ensure json is now valid
|
||||||
|
|
||||||
|
# set new body
|
||||||
|
request._body = json.dumps(s).encode('utf-8')
|
||||||
|
|
||||||
|
response = await call_next(request)
|
||||||
|
return response
|
39
test/main.py
39
test/main.py
@ -1,7 +1,8 @@
|
|||||||
|
import sys
|
||||||
from base64 import b64encode as b64enc
|
from base64 import b64encode as b64enc
|
||||||
from hashlib import sha256
|
|
||||||
from calendar import timegm
|
from calendar import timegm
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from hashlib import sha256
|
||||||
from os.path import dirname, join
|
from os.path import dirname, join
|
||||||
from uuid import uuid4, UUID
|
from uuid import uuid4, UUID
|
||||||
|
|
||||||
@ -9,7 +10,8 @@ from dateutil.relativedelta import relativedelta
|
|||||||
from jose import jwt, jwk
|
from jose import jwt, jwk
|
||||||
from jose.constants import ALGORITHMS
|
from jose.constants import ALGORITHMS
|
||||||
from starlette.testclient import TestClient
|
from starlette.testclient import TestClient
|
||||||
import sys
|
|
||||||
|
from middleware import PatchMalformedJsonMiddleware
|
||||||
|
|
||||||
# add relative path to use packages as they were in the app/ dir
|
# add relative path to use packages as they were in the app/ dir
|
||||||
sys.path.append('../')
|
sys.path.append('../')
|
||||||
@ -18,6 +20,7 @@ sys.path.append('../app')
|
|||||||
from app import main
|
from app import main
|
||||||
from app.util import load_key
|
from app.util import load_key
|
||||||
|
|
||||||
|
main.app.add_middleware(PatchMalformedJsonMiddleware, enabled=True)
|
||||||
client = TestClient(main.app)
|
client = TestClient(main.app)
|
||||||
|
|
||||||
ORIGIN_REF, ALLOTMENT_REF, SECRET = str(uuid4()), '20000000-0000-0000-0000-000000000001', 'HelloWorld'
|
ORIGIN_REF, ALLOTMENT_REF, SECRET = str(uuid4()), '20000000-0000-0000-0000-000000000001', 'HelloWorld'
|
||||||
@ -106,40 +109,14 @@ def test_auth_v1_origin():
|
|||||||
assert response.json().get('origin_ref') == ORIGIN_REF
|
assert response.json().get('origin_ref') == ORIGIN_REF
|
||||||
|
|
||||||
|
|
||||||
def test_auth_v1_origin_malformed_json():
|
def test_auth_v1_origin_malformed_json(): # see oscar.krause/fastapi-dls#1
|
||||||
import re
|
import re
|
||||||
import json
|
|
||||||
|
|
||||||
# see oscar.krause/fastapi-dls#1
|
|
||||||
payload = f'''{{
|
|
||||||
"registration_pending": "false",
|
|
||||||
"environment": {{
|
|
||||||
"guest_driver_version": "guest_driver_version",
|
|
||||||
"hostname": "myhost",
|
|
||||||
"ip_address_list": ["192.168.1.123"],
|
|
||||||
"os_version": "os_version",
|
|
||||||
"os_platform": "os_platform",
|
|
||||||
"fingerprint": {{"mac_address_list": [ff:ff:ff:ff:ff:ff"]}},
|
|
||||||
"host_driver_version": "host_driver_version"
|
|
||||||
}},
|
|
||||||
"update_pending": "false",
|
|
||||||
"candidate_origin_ref": "{ORIGIN_REF}"
|
|
||||||
}}'''
|
|
||||||
|
|
||||||
# test regex (temporary, until this section is merged into main.py
|
# test regex (temporary, until this section is merged into main.py
|
||||||
|
|
||||||
json_test = '{"environment": {"fingerprint": {"mac_address_list": [ff:ff:ff:ff:ff:ff"]}}'
|
json_test = '{"environment": {"fingerprint": {"mac_address_list": [ff:ff:ff:ff:ff:ff"]}}'
|
||||||
regex = r'(\"mac_address_list\"\:\s?\[)([\w\d])'
|
regex = '(\"mac_address_list\"\:\s?\[)([\w\d])'
|
||||||
replaced = re.sub(regex, r'\1"\2', json_test)
|
replaced = re.sub(regex, r'\1"\2', json_test)
|
||||||
assert replaced == '{"environment": {"fingerprint": {"mac_address_list": ["ff:ff:ff:ff:ff:ff"]}}'
|
assert replaced == '{"environment": {"fingerprint": {"mac_address_list": ["ff:ff:ff:ff:ff:ff"]}}'
|
||||||
|
|
||||||
payload = re.sub(regex, r'\1"\2', payload)
|
|
||||||
payload = json.loads(payload)
|
|
||||||
#
|
|
||||||
|
|
||||||
response = client.post('/auth/v1/origin', json=payload)
|
|
||||||
assert response.status_code == 200
|
|
||||||
assert response.json().get('origin_ref') == ORIGIN_REF
|
|
||||||
|
|
||||||
|
|
||||||
def auth_v1_origin_update():
|
def auth_v1_origin_update():
|
||||||
|
Loading…
Reference in New Issue
Block a user