Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: first frontend version #12

Merged
merged 6 commits into from
Dec 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ RUN poetry install --only main

# Copy app files to workdir
COPY secure_qrcode ./secure_qrcode
COPY templates ./templates
COPY static ./static

##### Final Stage #####
FROM python:3.12-slim-bookworm
Expand Down
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@

Encrypt your data using the modern ChaCha20-Poly1305 cipher and export it into a secure QR code.

## access via browser

Open the url https://secure-qrcode.onrender.com on your browser.

If you want to run this on your local machine, see the next section.

## run the api

The server can be started using a docker image:
Expand All @@ -12,7 +18,7 @@ The server can be started using a docker image:
docker run --rm -p 8000:8000 quay.io/allisson/secure-qrcode
```

Now the API server will be running on port 8000.
Now the API server will be running on port 8000 and you can open the url http://localhost:8000 on your browser.

## api documentation

Expand Down
108 changes: 97 additions & 11 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pycryptodome = "^3.19.0"
fastapi = "^0.104.1"
uvicorn = {extras = ["standard"], version = "^0.24.0.post1"}
pydantic-settings = "^2.1.0"
jinja2 = "^3.1.2"

[tool.poetry.group.test.dependencies]
pytest = "^7.4.3"
Expand Down
20 changes: 18 additions & 2 deletions secure_qrcode/api.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from base64 import b64encode

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from fastapi.responses import HTMLResponse, JSONResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates

from secure_qrcode.config import settings
from secure_qrcode.crypto import decrypt, encrypt
Expand All @@ -12,13 +14,16 @@
DecryptErrorResponse,
EncodeRequest,
EncodeResponse,
HealthResponse,
)
from secure_qrcode.qrcode import make

app = FastAPI(
title="Secure QR code",
description="Encrypt your data using the modern ChaCha20-Poly1305 cipher and export it into a secure QR code",
)
app.mount("/static", StaticFiles(directory="static"), name="static")
templates = Jinja2Templates(directory="templates")


@app.exception_handler(DecryptError)
Expand All @@ -29,7 +34,12 @@ def decrypt_error_exception_handler(request: Request, exc: DecryptError):
)


@app.post("/v1/encode", status_code=201)
@app.get("/", response_class=HTMLResponse, tags=["home"])
def index(request: Request):
return templates.TemplateResponse("index.html", {"request": request})


@app.post("/v1/encode", status_code=201, tags=["api"])
def encode(request: EncodeRequest) -> EncodeResponse:
encrypted_data = encrypt(request.plaintext, request.key, settings.left_padding_char)
img_io = make(
Expand All @@ -45,7 +55,13 @@ def encode(request: EncodeRequest) -> EncodeResponse:
"/v1/decode",
status_code=201,
responses={400: {"model": DecryptErrorResponse, "description": "Incorrect decryption"}},
tags=["api"],
)
def decode(request: DecodeRequest) -> DecodeResponse:
decrypted_data = decrypt(request.encrypted_data, request.key, settings.left_padding_char)
return DecodeResponse(decrypted_data=decrypted_data)


@app.get("/healthz", tags=["healthcheck"])
def healthz() -> HealthResponse:
return HealthResponse(success=True)
4 changes: 4 additions & 0 deletions secure_qrcode/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,7 @@ class DecodeResponse(BaseModel):

class DecryptErrorResponse(BaseModel):
message: str


class HealthResponse(BaseModel):
success: bool
1 change: 1 addition & 0 deletions static/github.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
126 changes: 126 additions & 0 deletions static/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
html,
body {
margin: 0;
padding: 0;
}

body {
background: linear-gradient(90deg, #00d2ff 0%, #3a47d5 100%);
}

#root {
display: flex;
justify-content: center;
align-items: center;
}

main {
display: flex;
flex-direction: column;
}

.container {
background-color: #e8eef2;
border-radius: 2px;
box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 4px;
padding: 0;
}

img {
width: 300px;
height: 300px;
}

.nav-link {
text-transform: uppercase;
}

.nav-tabs .nav-item.show .nav-link,
.nav-tabs .nav-link,
.nav-tabs .nav-link.active {
background-color: transparent;
border: none;
color: white;
font-weight: bold;
margin: 2px;
}

.nav-tabs .nav-link.active {
border-bottom: 3px solid white;
}

.nav-tabs {
border: none;
}

.feature {
display: flex;
flex-direction: row;
}

@media only screen and (max-width: 600px) {
.feature {
flex-direction: column;
}
}

form {
padding: 20px;
max-width: 400px;
width: 400px;
overflow: hidden;
}

.qrCode {
background-color: white;
padding: 20px;
width: 340px;
}

.json {
background: #f2f2f2;
padding: 10px;
overflow: auto;
/* first line not indented */
& > .line {
margin-left: 0;
}
.line {
margin-left: 4px;
}
.key {
margin-right: 2px;
color: black;
font-weight: 600;
}
.string {
color: green;
}
.number {
color: blue;
}
.boolean {
color: purple;
}
.null {
color: red;
}
}

footer a {
color: white;
font-size: 16px;
}

img.icon-footer {
width: 24px;
height: 24px;
margin-right: 10px;
}

.upload {
display: flex;
justify-content: center;
align-items: center;
padding: 20px 0;
}
Loading