From 21682dc7cf115c9d7f73c51ebf4b6f0f6cc06c72 Mon Sep 17 00:00:00 2001 From: motailab Date: Fri, 16 Dec 2022 15:23:22 +0600 Subject: [PATCH 1/5] dockerized the application. --- Dockerfile | 11 +++++++++++ app.db | Bin 0 -> 61440 bytes docker-compose.yml | 10 ++++++++++ serles/__init__.py | 12 ++++++++---- serles/configloader.py | 10 +++++++--- 5 files changed, 36 insertions(+), 7 deletions(-) create mode 100644 Dockerfile create mode 100644 app.db create mode 100644 docker-compose.yml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..43ec6b5 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +FROM python:3.8-slim + +RUN pip install serles-acme + +COPY . /app + +WORKDIR /app + +EXPOSE 8443 + +CMD ["python", "-m", "serles"] diff --git a/app.db b/app.db new file mode 100644 index 0000000000000000000000000000000000000000..3d971518460a64cd36c713eabdc3fb7824a5bd20 GIT binary patch literal 61440 zcmeI%U2oe|7{GCR>*B<1k_rS?)r-36MH>weUN<2w5G2JL(b8mO0a5KDGLFm4f;}9U zZsP*d?HY;C!l&S4z^C96ztm1oY1Sd&0_z_s&hc^l^8B91$BEAUPrGjD=!bsrjTP#< z(yAoO(nq>3Ns(M)V#p_GiO7tn8X)kIj(mQv5uGasMYUKw~{bv2w+D~<*daq`$ ztX1DweslTv$}j3~RbHs1fl2OIIu5)5lJ}@jY?d zG_=B_X};BXw;Av8oi%aCR_KiNkE7EKJNstb>jZ%x=tJ|1VRBUek>e$6!pW?o@ZqzO zcs23Y?+rTpt-*nQ*F4a7+;MW6+x>yrxzmgLcC!7N`oO$x4$R)3d0&q^{lI-@g|6=< zyQxj1R?^H3S#rIx^JMz%B>FKnioWM3>!aLcWaQ2I$@OJL+uW32Y$mSm*zrR5&~<`& zYekTq_x~N*-OTRD`KyZ`jGf>Dmn`l)1yS~1#Vb3W;MGWa8~+S=ccrA=*<1uXrx_XZ zc6HXNDB9MRd~%SMt`o$!!E+S-~t>m+!d@7c~YT`mcHXfw{(JzT|{A;2bFIM9PF9Z-k009ILKmY**5I_I{1P~~y zfEowJ|No+009ILKmY**5I_I{1Q19BnE$5`5I_I{1Q0*~0R#|0009ILD82ym z|HaQS5h8#90tg_000IagfB*srAi(@THGlvD2q1s}0tg_000IagfI#sDnEx++j)@Qf z1Q0*~0R#|0009ILKmY;e|EU245I_I{1Q0*~0R#|0009JwFTnhN@pDXs2q1s}0tg_0 z00IagfB*srF#k^tAb Date: Fri, 16 Dec 2022 15:23:40 +0600 Subject: [PATCH 2/5] dockerized the application. --- app.db | Bin 61440 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 app.db diff --git a/app.db b/app.db deleted file mode 100644 index 3d971518460a64cd36c713eabdc3fb7824a5bd20..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61440 zcmeI%U2oe|7{GCR>*B<1k_rS?)r-36MH>weUN<2w5G2JL(b8mO0a5KDGLFm4f;}9U zZsP*d?HY;C!l&S4z^C96ztm1oY1Sd&0_z_s&hc^l^8B91$BEAUPrGjD=!bsrjTP#< z(yAoO(nq>3Ns(M)V#p_GiO7tn8X)kIj(mQv5uGasMYUKw~{bv2w+D~<*daq`$ ztX1DweslTv$}j3~RbHs1fl2OIIu5)5lJ}@jY?d zG_=B_X};BXw;Av8oi%aCR_KiNkE7EKJNstb>jZ%x=tJ|1VRBUek>e$6!pW?o@ZqzO zcs23Y?+rTpt-*nQ*F4a7+;MW6+x>yrxzmgLcC!7N`oO$x4$R)3d0&q^{lI-@g|6=< zyQxj1R?^H3S#rIx^JMz%B>FKnioWM3>!aLcWaQ2I$@OJL+uW32Y$mSm*zrR5&~<`& zYekTq_x~N*-OTRD`KyZ`jGf>Dmn`l)1yS~1#Vb3W;MGWa8~+S=ccrA=*<1uXrx_XZ zc6HXNDB9MRd~%SMt`o$!!E+S-~t>m+!d@7c~YT`mcHXfw{(JzT|{A;2bFIM9PF9Z-k009ILKmY**5I_I{1P~~y zfEowJ|No+009ILKmY**5I_I{1Q19BnE$5`5I_I{1Q0*~0R#|0009ILD82ym z|HaQS5h8#90tg_000IagfB*srAi(@THGlvD2q1s}0tg_000IagfI#sDnEx++j)@Qf z1Q0*~0R#|0009ILKmY;e|EU245I_I{1Q0*~0R#|0009JwFTnhN@pDXs2q1s}0tg_0 z00IagfB*srF#k^tAb Date: Fri, 16 Dec 2022 15:35:45 +0600 Subject: [PATCH 3/5] updated port. --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 4eaba62..57b0240 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,7 +3,7 @@ services: app: build: . ports: - - "5000:5000" + - "8443:8443" environment: - CONFIG=./config.ini volumes: From 4322e88d2e7e60d3c883b55313b0561088cc7cdd Mon Sep 17 00:00:00 2001 From: motailab Date: Sat, 17 Dec 2022 14:43:14 +0600 Subject: [PATCH 4/5] added gunicorn support and application is now running behind the gunicorn --- Dockerfile | 3 ++- gunicorn.conf.py | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 gunicorn.conf.py diff --git a/Dockerfile b/Dockerfile index 43ec6b5..6a48e76 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,4 +8,5 @@ WORKDIR /app EXPOSE 8443 -CMD ["python", "-m", "serles"] +# CMD ["python", "-m", "serles"] +CMD ["gunicorn", "-c", "gunicorn.conf.py", "serles:create_app()"] diff --git a/gunicorn.conf.py b/gunicorn.conf.py new file mode 100644 index 0000000..10b9676 --- /dev/null +++ b/gunicorn.conf.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- + +import multiprocessing +import os + +from distutils.util import strtobool + + +bind = os.getenv('WEB_BIND', '0.0.0.0:8443') +accesslog = '-' +access_log_format = "%(h)s %(l)s %(u)s %(t)s '%(r)s' %(s)s %(b)s '%(f)s' '%(a)s' in %(D)sµs" # noqa: E501 +timeout = 300 + +workers = int(os.getenv('WEB_CONCURRENCY', multiprocessing.cpu_count() * 2)) +threads = int(os.getenv('PYTHON_MAX_THREADS', 1)) + +reload = bool(strtobool(os.getenv('WEB_RELOAD', 'false'))) From 6c2567ac453da7e4fd42bd590987d21f394f752a Mon Sep 17 00:00:00 2001 From: motailab Date: Tue, 20 Dec 2022 12:39:27 +0600 Subject: [PATCH 5/5] added https scheme --- serles/__init__.py | 1 + serles/views.py | 37 ++++++++++++++++++++++++------------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/serles/__init__.py b/serles/__init__.py index ea64faf..6c9e886 100644 --- a/serles/__init__.py +++ b/serles/__init__.py @@ -22,6 +22,7 @@ def create_app(): app.config["SQLALCHEMY_DATABASE_URI"] = config["database"] app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False app.config["SERVER_NAME"] = config["server_name"] + app.config['PREFERRED_URL_SCHEME'] = 'https' init_config() # views.init_config() api.init_app(app) diff --git a/serles/views.py b/serles/views.py index 2f46b4f..de5d975 100644 --- a/serles/views.py +++ b/serles/views.py @@ -27,10 +27,11 @@ def get(self): """ Displays the URLs for accessing certain functions, and some metadata. """ + return { - "newNonce": api.url_for(NewNonce, _external=True), - "newAccount": api.url_for(NewAccount, _external=True), - "newOrder": api.url_for(NewOrder, _external=True), + "newNonce": api.url_for(NewNonce, _external=True, _scheme='https'), + "newAccount": api.url_for(NewAccount, _external=True, _scheme='https'), + "newOrder": api.url_for(NewOrder, _external=True, _scheme='https'), # "newAuthz": MUST be absent if pre-authorization not supported # "revokeCert": not offered # optional: meta:{termsOfService"",website"",caaIdentities[""],externalAccountRequired?} @@ -61,7 +62,8 @@ def post(self): contact = g.payload.get("contact", []) contact = contact[0] if len(contact) > 0 else None # only 1 email! if contact and not contact.startswith("mailto:"): - raise ACMEError("only (one) email supported", 400, "unsupportedContact") + raise ACMEError("only (one) email supported", + 400, "unsupportedContact") if contact: contact = contact.replace("mailto:", "") termsOfServiceAgreed = g.payload.get("termsOfServiceAgreed", False) @@ -84,7 +86,8 @@ def post(self): else: # At this point, the user has no account, but wants one account = Account(jwk=jwk_pem, contact=contact) db.session.add(account) - db.session.commit() # note: accessing `account` after the commit requires setting expire_on_commit=False + # note: accessing `account` after the commit requires setting expire_on_commit=False + db.session.commit() preexisting = False return ( @@ -101,7 +104,8 @@ def post(self): Submit a new Order. The request will include a list of Identifers (domain names) the client wants on the certificate. """ - notBefore = g.payload.get("notBefore") # optional, we ignore it for now + notBefore = g.payload.get( + "notBefore") # optional, we ignore it for now notAfter = g.payload.get("notAfter") # optional, we ignore it for now identifiers = g.payload.get("identifiers") if not identifiers: @@ -144,11 +148,13 @@ def post(self): ) db.session.add(order) - db.session.commit() # note: accessing `order` after the commit requires setting expire_on_commit=False + # note: accessing `order` after the commit requires setting expire_on_commit=False + db.session.commit() return ( order.serialized, 201, - {"Location": api.url_for(OrderMain, orderid=order.id, _external=True)}, + {"Location": api.url_for( + OrderMain, orderid=order.id, _external=True)}, ) @@ -158,7 +164,8 @@ class NewAuthz(Resource): pass -@api.resource("/revokeCert") # RFC8555 §7.6 (Certificate Revocation, not offered) +# RFC8555 §7.6 (Certificate Revocation, not offered) +@api.resource("/revokeCert") class RevokeCert(Resource): "not offered." pass @@ -177,7 +184,8 @@ def post(self, kid): JSON-serialized Account object (post-update). """ if kid != g.kid: - raise ACMEError(f"{kid}, {g.kid}Unexpected Account ID", 403, "unauthorized") + raise ACMEError( + f"{kid}, {g.kid}Unexpected Account ID", 403, "unauthorized") account = Account.query.filter_by(id=kid).first() if not account: raise ACMEError("", 400, "accountDoesNotExist") @@ -188,11 +196,13 @@ def post(self, kid): if contact is not None: contact = contact[0] if len(contact) > 0 else None # only 1 email! if contact and not contact.startswith("mailto:"): - raise ACMEError("only (one) email supported", 400, "unsupportedContact") + raise ACMEError("only (one) email supported", + 400, "unsupportedContact") if contact: contact = contact.replace("mailto:", "") account.contact = contact - db.session.commit() # note: accessing `account` after the commit requires setting expire_on_commit=False + # note: accessing `account` after the commit requires setting expire_on_commit=False + db.session.commit() return account.serialized @@ -324,5 +334,6 @@ def post(self, certid): pem_cert = pkcs7_to_pem_chain(cert) return make_response( - pem_cert, 200, {"Content-Type": "application/pem-certificate-chain"} + pem_cert, 200, { + "Content-Type": "application/pem-certificate-chain"} )