Merge branch 'dev' into 'main'

v0.5

See merge request oscar.krause/fastapi-dls!7
This commit is contained in:
Oscar Krause 2022-12-21 11:10:18 +01:00
commit 8a7f5d9cbe
7 changed files with 118 additions and 37 deletions

View File

@ -8,6 +8,8 @@ build:
rules: rules:
- if: $CI_COMMIT_BRANCH - if: $CI_COMMIT_BRANCH
tags: [ docker ] tags: [ docker ]
before_script:
- echo "COMMIT=${CI_COMMIT_SHA}" >> version.env # COMMIT=`git rev-parse HEAD`
script: script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build . --tag ${CI_REGISTRY}/${CI_PROJECT_PATH}/${CI_BUILD_REF_NAME}:${CI_BUILD_REF} - docker build . --tag ${CI_REGISTRY}/${CI_PROJECT_PATH}/${CI_BUILD_REF_NAME}:${CI_BUILD_REF}
@ -22,9 +24,13 @@ deploy:
stage: deploy stage: deploy
rules: rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
before_script:
- echo "COMMIT=${CI_COMMIT_SHA}" >> version.env
- source version.env
- Building docker image for commit "${COMMIT}" with version "${VERSION}"
script: script:
- docker login -u $PUBLIC_REGISTRY_USER -p $PUBLIC_REGISTRY_TOKEN - docker login -u $PUBLIC_REGISTRY_USER -p $PUBLIC_REGISTRY_TOKEN
- docker build . --tag $PUBLIC_REGISTRY_USER/${CI_PROJECT_NAME}:${CI_BUILD_REF} - docker build . --tag $PUBLIC_REGISTRY_USER/${CI_PROJECT_NAME}:${VERSION}
- docker build . --tag $PUBLIC_REGISTRY_USER/${CI_PROJECT_NAME}:latest - docker build . --tag $PUBLIC_REGISTRY_USER/${CI_PROJECT_NAME}:latest
- docker push $PUBLIC_REGISTRY_USER/${CI_PROJECT_NAME}:${CI_BUILD_REF} - docker push $PUBLIC_REGISTRY_USER/${CI_PROJECT_NAME}:${VERSION}
- docker push $PUBLIC_REGISTRY_USER/${CI_PROJECT_NAME}:latest - docker push $PUBLIC_REGISTRY_USER/${CI_PROJECT_NAME}:latest

View File

@ -11,6 +11,8 @@ RUN apk update \
&& apk del build-deps && apk del build-deps
COPY app /app COPY app /app
COPY version.env /version.env
COPY README.md /README.md
HEALTHCHECK --start-period=30s --interval=10s --timeout=5s --retries=3 CMD curl --insecure --fail https://localhost/status || exit 1 HEALTHCHECK --start-period=30s --interval=10s --timeout=5s --retries=3 CMD curl --insecure --fail https://localhost/status || exit 1
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "443", "--app-dir", "/app", "--proxy-headers", "--ssl-keyfile", "/app/cert/webserver.key", "--ssl-certfile", "/app/cert/webserver.crt"] CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "443", "--app-dir", "/app", "--proxy-headers", "--ssl-keyfile", "/app/cert/webserver.key", "--ssl-certfile", "/app/cert/webserver.crt"]

View File

@ -6,11 +6,15 @@ Minimal Delegated License Service (DLS).
### `GET /` ### `GET /`
Just a simple *hello world* endpoint. HTML rendered README.md.
### `GET /status` ### `GET /status`
Status endpoint, used for *healthcheck*. Status endpoint, used for *healthcheck*. Shows also current version and commit hash.
### `GET /docs`
OpenAPI specifications rendered from `GET /openapi.json`.
### `GET /-/origins` ### `GET /-/origins`
@ -20,6 +24,14 @@ List registered origins.
List current leases. List current leases.
### `GET /client-token`
Generate client token, (see [installation](#installation)).
### Others
There are some more internal api endpoints for handling authentication and lease process.
# Setup (Docker) # Setup (Docker)
**Run this on the Docker-Host** **Run this on the Docker-Host**
@ -28,20 +40,57 @@ List current leases.
WORKING_DIR=/opt/docker/fastapi-dls/cert WORKING_DIR=/opt/docker/fastapi-dls/cert
mkdir -p $WORKING_DIR mkdir -p $WORKING_DIR
cd $WORKING_DIR cd $WORKING_DIR
# create instance private and public key for singing JWT's
openssl genrsa -out $WORKING_DIR/instance.private.pem 2048 openssl genrsa -out $WORKING_DIR/instance.private.pem 2048
openssl rsa -in $WORKING_DIR/instance.private.pem -outform PEM -pubout -out $WORKING_DIR/instance.public.pem openssl rsa -in $WORKING_DIR/instance.private.pem -outform PEM -pubout -out $WORKING_DIR/instance.public.pem
# create ssl certificate for integrated webserver (uvicorn) - because clients rely on ssl
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout $WORKING_DIR/webserver.key -out $WORKING_DIR/webserver.crt openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout $WORKING_DIR/webserver.key -out $WORKING_DIR/webserver.crt
docker run -e DLS_URL=`hostname -i` -e DLS_PORT=443 -p 443:443 -v $WORKING_DIR:/app/cert collinwebdesigns/fastapi-dls:latest ```
**Start container**
```shell
docker volume create dls-db
docker run -e DLS_URL=`hostname -i` -e DLS_PORT=443 -p 443:443 -v $WORKING_DIR:/app/cert -v dls-db:/app/database collinwebdesigns/fastapi-dls:latest
```
**Docker-Compose / Deploy stack**
```yaml
version: '3.9'
x-dls-variables: &dls-variables
DLS_URL: localhost # REQUIRED
DLS_PORT: 443
LEASE_EXPIRE_DAYS: 90
DATABASE: sqlite:////app/database/db.sqlite
services:
dls:
image: collinwebdesigns/fastapi-dls:latest
restart: always
environment:
<<: *dls-variables
ports:
- "443:443"
volumes:
- /opt/docker/fastapi-dls/cert:/app/cert
- dls-db:/app/database
volumes:
dls-db:
``` ```
# Configuration # Configuration
| Variable | Default | Usage | | Variable | Default | Usage |
|---------------------|-----------------------|---------------------------------------------------------------------------------------| |---------------------|-----------------------|---------------------------------------------------------------------------------------|
| `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 |
| `LEASE_EXPIRE_DAYS` | `90` | Lease time in days | | `LEASE_EXPIRE_DAYS` | `90` | Lease time in days |
| `DATABASE` | `sqlite:///db.sqlite` | See [official dataset docs](https://dataset.readthedocs.io/en/latest/quickstart.html) | | `DATABASE` | `sqlite:///db.sqlite` | See [official dataset docs](https://dataset.readthedocs.io/en/latest/quickstart.html) |
| `CORS_ORIGINS` | `https://{DLS_URL}` | Sets `Access-Control-Allow-Origin` header (comma separated string) |
# Installation # Installation

View File

@ -1,9 +0,0 @@
# FastAPI-DLS Server
## ToDo
- Create Client Token (`.tok`-file)
- Docker Image
- Create Certificates if not exist
- Keep track of clients and Leases

View File

@ -1,8 +1,11 @@
import logging
from base64 import b64encode as b64enc from base64 import b64encode as b64enc
from hashlib import sha256 from hashlib import sha256
from uuid import uuid4 from uuid import uuid4
from os.path import join, dirname from os.path import join, dirname
from os import getenv from os import getenv
from dotenv import load_dotenv
from fastapi import FastAPI, HTTPException from fastapi import FastAPI, HTTPException
from fastapi.requests import Request from fastapi.requests import Request
from fastapi.encoders import jsonable_encoder from fastapi.encoders import jsonable_encoder
@ -12,11 +15,17 @@ from dateutil.relativedelta import relativedelta
from calendar import timegm from calendar import timegm
from jose import jws, jwk, jwt from jose import jws, jwk, jwt
from jose.constants import ALGORITHMS from jose.constants import ALGORITHMS
from starlette.responses import StreamingResponse, JSONResponse from starlette.middleware.cors import CORSMiddleware
from starlette.responses import StreamingResponse, JSONResponse, HTMLResponse
import dataset import dataset
from Crypto.PublicKey import RSA from Crypto.PublicKey import RSA
from Crypto.PublicKey.RSA import RsaKey from Crypto.PublicKey.RSA import RsaKey
logger = logging.getLogger()
load_dotenv('../version.env')
VERSION, COMMIT, DEBUG = getenv('VERSION', 'unknown'), getenv('COMMIT', 'unknown'), bool(getenv('DEBUG', False))
def load_file(filename) -> bytes: def load_file(filename) -> bytes:
with open(filename, 'rb') as file: with open(filename, 'rb') as file:
@ -30,7 +39,13 @@ def load_key(filename) -> RsaKey:
# todo: initialize certificate (or should be done by user, and passed through "volumes"?) # todo: initialize certificate (or should be done by user, and passed through "volumes"?)
app, db = FastAPI(), dataset.connect(str(getenv('DATABASE', 'sqlite:///db.sqlite'))) __details = dict(
title='FastAPI-DLS',
description='Minimal Delegated License Service (DLS).',
version=VERSION,
)
app, db = FastAPI(**__details), dataset.connect(str(getenv('DATABASE', 'sqlite:///db.sqlite')))
TOKEN_EXPIRE_DELTA = relativedelta(hours=1) # days=1 TOKEN_EXPIRE_DELTA = relativedelta(hours=1) # days=1
LEASE_EXPIRE_DELTA = relativedelta(days=int(getenv('LEASE_EXPIRE_DAYS', 90))) LEASE_EXPIRE_DELTA = relativedelta(days=int(getenv('LEASE_EXPIRE_DAYS', 90)))
@ -41,24 +56,39 @@ SITE_KEY_XID = getenv('SITE_KEY_XID', '00000000-0000-0000-0000-000000000000')
INSTANCE_KEY_RSA = load_key(join(dirname(__file__), 'cert/instance.private.pem')) INSTANCE_KEY_RSA = load_key(join(dirname(__file__), 'cert/instance.private.pem'))
INSTANCE_KEY_PUB = load_key(join(dirname(__file__), 'cert/instance.public.pem')) INSTANCE_KEY_PUB = load_key(join(dirname(__file__), 'cert/instance.public.pem'))
CORS_ORIGINS = getenv('CORS_ORIGINS').split(',') if (getenv('CORS_ORIGINS')) else f'https://{DLS_URL}' # todo: prevent static https
jwt_encode_key = jwk.construct(INSTANCE_KEY_RSA.export_key().decode('utf-8'), algorithm=ALGORITHMS.RS256) jwt_encode_key = jwk.construct(INSTANCE_KEY_RSA.export_key().decode('utf-8'), algorithm=ALGORITHMS.RS256)
jwt_decode_key = jwk.construct(INSTANCE_KEY_PUB.export_key().decode('utf-8'), algorithm=ALGORITHMS.RS512) jwt_decode_key = jwk.construct(INSTANCE_KEY_PUB.export_key().decode('utf-8'), algorithm=ALGORITHMS.RS512)
app.debug = DEBUG
app.add_middleware(
CORSMiddleware,
allow_origins=CORS_ORIGINS,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
logger.setLevel(logging.DEBUG if DEBUG else logging.INFO)
def get_token(request: Request) -> dict: def get_token(request: Request) -> dict:
authorization_header = request.headers['authorization'] authorization_header = request.headers['authorization']
token = authorization_header.split(' ')[1] token = authorization_header.split(' ')[1]
return jwt.decode(token=token, key=jwt_decode_key, algorithms='RS256', options={'verify_aud': False}) return jwt.decode(token=token, key=jwt_decode_key, algorithms=ALGORITHMS.RS256, options={'verify_aud': False})
@app.get('/') @app.get('/')
async def index(): async def index():
return JSONResponse({'hello': 'world'}) from markdown import markdown
content = load_file('../README.md').decode('utf-8')
return HTMLResponse(markdown(text=content, extensions=['tables', 'fenced_code', 'md_in_html', 'nl2br', 'toc']))
@app.get('/status') @app.get('/status')
async def status(request: Request): async def status(request: Request):
return JSONResponse({'status': 'up'}) return JSONResponse({'status': 'up', 'version': VERSION, 'commit': COMMIT, 'debug': DEBUG})
@app.get('/-/origins') @app.get('/-/origins')
@ -112,7 +142,7 @@ async def client_token():
"service_instance_public_key_configuration": service_instance_public_key_configuration, "service_instance_public_key_configuration": service_instance_public_key_configuration,
} }
content = jws.sign(payload, key=jwt_encode_key, headers=None, algorithm='RS256') content = jws.sign(payload, key=jwt_encode_key, headers=None, algorithm=ALGORITHMS.RS256)
response = StreamingResponse(iter([content]), media_type="text/plain") response = StreamingResponse(iter([content]), media_type="text/plain")
filename = f'client_configuration_token_{datetime.now().strftime("%d-%m-%y-%H-%M-%S")}' filename = f'client_configuration_token_{datetime.now().strftime("%d-%m-%y-%H-%M-%S")}'
@ -124,11 +154,11 @@ async def client_token():
# venv/lib/python3.9/site-packages/nls_services_auth/test/test_origins_controller.py # venv/lib/python3.9/site-packages/nls_services_auth/test/test_origins_controller.py
# {"candidate_origin_ref":"00112233-4455-6677-8899-aabbccddeeff","environment":{"fingerprint":{"mac_address_list":["ff:ff:ff:ff:ff:ff"]},"hostname":"my-hostname","ip_address_list":["192.168.178.123","fe80::","fe80::1%enp6s18"],"guest_driver_version":"510.85.02","os_platform":"Debian GNU/Linux 11 (bullseye) 11","os_version":"11 (bullseye)"},"registration_pending":false,"update_pending":false} # {"candidate_origin_ref":"00112233-4455-6677-8899-aabbccddeeff","environment":{"fingerprint":{"mac_address_list":["ff:ff:ff:ff:ff:ff"]},"hostname":"my-hostname","ip_address_list":["192.168.178.123","fe80::","fe80::1%enp6s18"],"guest_driver_version":"510.85.02","os_platform":"Debian GNU/Linux 11 (bullseye) 11","os_version":"11 (bullseye)"},"registration_pending":false,"update_pending":false}
@app.post('/auth/v1/origin') @app.post('/auth/v1/origin')
async def auth_origin(request: Request): async def auth_v1_origin(request: Request):
j = json.loads((await request.body()).decode('utf-8')) j = json.loads((await request.body()).decode('utf-8'))
origin_ref = j['candidate_origin_ref'] origin_ref = j['candidate_origin_ref']
print(f'> [ origin ]: {origin_ref}: {j}') logging.info(f'> [ origin ]: {origin_ref}: {j}')
data = dict( data = dict(
origin_ref=origin_ref, origin_ref=origin_ref,
@ -157,11 +187,11 @@ async def auth_origin(request: Request):
# venv/lib/python3.9/site-packages/nls_core_auth/auth.py - CodeResponse # venv/lib/python3.9/site-packages/nls_core_auth/auth.py - CodeResponse
# {"code_challenge":"...","origin_ref":"00112233-4455-6677-8899-aabbccddeeff"} # {"code_challenge":"...","origin_ref":"00112233-4455-6677-8899-aabbccddeeff"}
@app.post('/auth/v1/code') @app.post('/auth/v1/code')
async def auth_code(request: Request): async def auth_v1_code(request: Request):
j = json.loads((await request.body()).decode('utf-8')) j = json.loads((await request.body()).decode('utf-8'))
origin_ref = j['origin_ref'] origin_ref = j['origin_ref']
print(f'> [ code ]: {origin_ref}: {j}') logging.info(f'> [ code ]: {origin_ref}: {j}')
cur_time = datetime.utcnow() cur_time = datetime.utcnow()
delta = relativedelta(minutes=15) delta = relativedelta(minutes=15)
@ -176,7 +206,7 @@ async def auth_code(request: Request):
'kid': SITE_KEY_XID 'kid': SITE_KEY_XID
} }
auth_code = jws.sign(payload, key=jwt_encode_key, headers={'kid': payload.get('kid')}, algorithm='RS256') auth_code = jws.sign(payload, key=jwt_encode_key, headers={'kid': payload.get('kid')}, algorithm=ALGORITHMS.RS256)
db['auth'].delete(origin_ref=origin_ref, expires={'<=': cur_time - delta}) db['auth'].delete(origin_ref=origin_ref, expires={'<=': cur_time - delta})
db['auth'].insert(dict(origin_ref=origin_ref, code_challenge=j['code_challenge'], expires=expires)) db['auth'].insert(dict(origin_ref=origin_ref, code_challenge=j['code_challenge'], expires=expires))
@ -194,14 +224,14 @@ async def auth_code(request: Request):
# venv/lib/python3.9/site-packages/nls_core_auth/auth.py - TokenResponse # venv/lib/python3.9/site-packages/nls_core_auth/auth.py - TokenResponse
# {"auth_code":"...","code_verifier":"..."} # {"auth_code":"...","code_verifier":"..."}
@app.post('/auth/v1/token') @app.post('/auth/v1/token')
async def auth_token(request: Request): async def auth_v1_token(request: Request):
j = json.loads((await request.body()).decode('utf-8')) j = json.loads((await request.body()).decode('utf-8'))
payload = jwt.decode(token=j['auth_code'], key=jwt_decode_key) payload = jwt.decode(token=j['auth_code'], key=jwt_decode_key)
code_challenge = payload['origin_ref'] code_challenge = payload['origin_ref']
origin_ref = db['auth'].find_one(code_challenge=code_challenge)['origin_ref'] origin_ref = db['auth'].find_one(code_challenge=code_challenge)['origin_ref']
print(f'> [ auth ]: {origin_ref} ({code_challenge}): {j}') logging.info(f'> [ auth ]: {origin_ref} ({code_challenge}): {j}')
# validate the code challenge # validate the code challenge
if payload['challenge'] != b64enc(sha256(j['code_verifier'].encode('utf-8')).digest()).rstrip(b'=').decode('utf-8'): if payload['challenge'] != b64enc(sha256(j['code_verifier'].encode('utf-8')).digest()).rstrip(b'=').decode('utf-8'):
@ -221,7 +251,7 @@ async def auth_token(request: Request):
'kid': SITE_KEY_XID, 'kid': SITE_KEY_XID,
} }
auth_token = jwt.encode(new_payload, key=jwt_encode_key, headers={'kid': payload.get('kid')}, algorithm='RS256') auth_token = jwt.encode(new_payload, key=jwt_encode_key, headers={'kid': payload.get('kid')}, algorithm=ALGORITHMS.RS256)
response = { response = {
"expires": access_expires_on.isoformat(), "expires": access_expires_on.isoformat(),
@ -234,7 +264,7 @@ async def auth_token(request: Request):
# {'fulfillment_context': {'fulfillment_class_ref_list': []}, 'lease_proposal_list': [{'license_type_qualifiers': {'count': 1}, 'product': {'name': 'NVIDIA RTX Virtual Workstation'}}], 'proposal_evaluation_mode': 'ALL_OF', 'scope_ref_list': ['00112233-4455-6677-8899-aabbccddeeff']} # {'fulfillment_context': {'fulfillment_class_ref_list': []}, 'lease_proposal_list': [{'license_type_qualifiers': {'count': 1}, 'product': {'name': 'NVIDIA RTX Virtual Workstation'}}], 'proposal_evaluation_mode': 'ALL_OF', 'scope_ref_list': ['00112233-4455-6677-8899-aabbccddeeff']}
@app.post('/leasing/v1/lessor') @app.post('/leasing/v1/lessor')
async def leasing_lessor(request: Request): async def leasing_v1_lessor(request: Request):
j, token = json.loads((await request.body()).decode('utf-8')), get_token(request) j, token = json.loads((await request.body()).decode('utf-8')), get_token(request)
code_challenge = token['origin_ref'] code_challenge = token['origin_ref']
@ -242,7 +272,7 @@ async def leasing_lessor(request: Request):
origin_ref = db['auth'].find_one(code_challenge=code_challenge)['origin_ref'] origin_ref = db['auth'].find_one(code_challenge=code_challenge)['origin_ref']
print(f'> [ create ]: {origin_ref} ({code_challenge}): create leases for scope_ref_list {scope_ref_list}') logging.info(f'> [ create ]: {origin_ref} ({code_challenge}): create leases for scope_ref_list {scope_ref_list}')
cur_time = datetime.utcnow() cur_time = datetime.utcnow()
lease_result_list = [] lease_result_list = []
@ -278,14 +308,14 @@ async def leasing_lessor(request: Request):
# venv/lib/python3.9/site-packages/nls_services_lease/test/test_lease_multi_controller.py # venv/lib/python3.9/site-packages/nls_services_lease/test/test_lease_multi_controller.py
# venv/lib/python3.9/site-packages/nls_dal_service_instance_dls/schema/service_instance/V1_0_21__product_mapping.sql # venv/lib/python3.9/site-packages/nls_dal_service_instance_dls/schema/service_instance/V1_0_21__product_mapping.sql
@app.get('/leasing/v1/lessor/leases') @app.get('/leasing/v1/lessor/leases')
async def leasing_lessor_lease(request: Request): async def leasing_v1_lessor_lease(request: Request):
token = get_token(request) token = get_token(request)
code_challenge = token['origin_ref'] code_challenge = token['origin_ref']
origin_ref = db['auth'].find_one(code_challenge=code_challenge)['origin_ref'] origin_ref = db['auth'].find_one(code_challenge=code_challenge)['origin_ref']
active_lease_list = list(map(lambda x: x['lease_ref'], db['lease'].find(origin_ref=origin_ref))) active_lease_list = list(map(lambda x: x['lease_ref'], db['lease'].find(origin_ref=origin_ref)))
print(f'> [ leases ]: {origin_ref} ({code_challenge}): found {len(active_lease_list)} active leases') logging.info(f'> [ leases ]: {origin_ref} ({code_challenge}): found {len(active_lease_list)} active leases')
cur_time = datetime.utcnow() cur_time = datetime.utcnow()
response = { response = {
@ -299,13 +329,13 @@ async def leasing_lessor_lease(request: Request):
# venv/lib/python3.9/site-packages/nls_core_lease/lease_single.py # venv/lib/python3.9/site-packages/nls_core_lease/lease_single.py
@app.put('/leasing/v1/lease/{lease_ref}') @app.put('/leasing/v1/lease/{lease_ref}')
async def leasing_lease_renew(request: Request, lease_ref: str): async def leasing_v1_lease_renew(request: Request, lease_ref: str):
token = get_token(request) token = get_token(request)
code_challenge = token['origin_ref'] code_challenge = token['origin_ref']
origin_ref = db['auth'].find_one(code_challenge=code_challenge)['origin_ref'] origin_ref = db['auth'].find_one(code_challenge=code_challenge)['origin_ref']
print(f'> [ renew ]: {origin_ref} ({code_challenge}): renew {lease_ref}') logging.info(f'> [ renew ]: {origin_ref} ({code_challenge}): renew {lease_ref}')
if db['lease'].count(origin_ref=origin_ref, lease_ref=lease_ref) == 0: if db['lease'].count(origin_ref=origin_ref, lease_ref=lease_ref) == 0:
raise HTTPException(status_code=404, detail='requested lease not available') raise HTTPException(status_code=404, detail='requested lease not available')
@ -328,7 +358,7 @@ async def leasing_lease_renew(request: Request, lease_ref: str):
@app.delete('/leasing/v1/lessor/leases') @app.delete('/leasing/v1/lessor/leases')
async def leasing_lessor_lease_remove(request: Request): async def leasing_v1_lessor_lease_remove(request: Request):
token = get_token(request) token = get_token(request)
code_challenge = token['origin_ref'] code_challenge = token['origin_ref']
@ -336,7 +366,7 @@ async def leasing_lessor_lease_remove(request: Request):
origin_ref = db['auth'].find_one(code_challenge=code_challenge)['origin_ref'] origin_ref = db['auth'].find_one(code_challenge=code_challenge)['origin_ref']
released_lease_list = list(map(lambda x: x['lease_ref'], db['lease'].find(origin_ref=origin_ref))) released_lease_list = list(map(lambda x: x['lease_ref'], db['lease'].find(origin_ref=origin_ref)))
deletions = db['lease'].delete(origin_ref=origin_ref) deletions = db['lease'].delete(origin_ref=origin_ref)
print(f'> [ remove ]: {origin_ref} ({code_challenge}): removed {deletions} leases') logging.info(f'> [ remove ]: {origin_ref} ({code_challenge}): removed {deletions} leases')
cur_time = datetime.utcnow() cur_time = datetime.utcnow()
response = { response = {
@ -359,7 +389,7 @@ if __name__ == '__main__':
# #
### ###
print(f'> Starting dev-server ...') logging.info(f'> Starting dev-server ...')
ssl_keyfile = join(dirname(__file__), 'cert/webserver.key') ssl_keyfile = join(dirname(__file__), 'cert/webserver.key')
ssl_certfile = join(dirname(__file__), 'cert/webserver.crt') ssl_certfile = join(dirname(__file__), 'cert/webserver.crt')

View File

@ -4,3 +4,5 @@ python-jose==3.3.0
pycryptodome==3.16.0 pycryptodome==3.16.0
python-dateutil==2.8.2 python-dateutil==2.8.2
dataset==1.5.2 dataset==1.5.2
markdown==3.4.1
python-dotenv==0.21.0

1
version.env Normal file
View File

@ -0,0 +1 @@
VERSION=0.5