diff --git a/pyproject.toml b/pyproject.toml index 3d8899b..c678e99 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta" [project] name = 'quorra' dynamic = ["version"] -description = 'Quorra API server' +description = 'Quorra server' readme = 'README.md' requires-python = '>=3.8' license = {file = 'LICENSE'} @@ -24,13 +24,13 @@ dependencies = [ "pillow", "python-multipart", "deepmerge", - "python-jose" + "python-jose", + "bech32 @ git+https://github.com/Quorra-Auth/bech32.git" ] [tool.setuptools] packages = ["quorra", "quorra.routers"] -# Doesn't work, need to figure out how to add static files to Python project [tool.setuptools.package-data] "quorra" = ["fe/**"] diff --git a/quorra/classes.py b/quorra/classes.py index ddabf48..764d59c 100644 --- a/quorra/classes.py +++ b/quorra/classes.py @@ -34,7 +34,7 @@ class QRDataResponse(BaseModel): qr_image: str class DeviceRegistrationRequest(SQLModel): - pubkey: str + pubkey: str = Field(unique=True) name: str | None = None class Device(DeviceRegistrationRequest, table=True): @@ -42,21 +42,6 @@ class Device(DeviceRegistrationRequest, table=True): user_id: str = Field(default=None, foreign_key="user.id") -class AQRMobileStateEnum(str, Enum): - accepted = "accepted" - rejected = "rejected" - -# TODO: Send a device UUID as well so that the server can get a hint -class AQRMobileIdentifyRequest(BaseModel): - signature: str - message: str - -class AQRMobileAuthenticateRequest(BaseModel): - state: AQRMobileStateEnum - signature: str - message: str - - class TokenResponse(BaseModel): access_token: str token_type: Literal["Bearer"] = "Bearer" @@ -65,7 +50,7 @@ class TokenResponse(BaseModel): class TransactionTypes(str, Enum): onboarding = "onboarding" - aqr_oidc_login = "aqr-oidc-login" + ln_oidc_login = "ln-oidc-login" class TransactionGetRequest(BaseModel): tx_type: TransactionTypes @@ -84,7 +69,7 @@ class Transaction(BaseModel): tx_id: str | None = None # TODO: shorten - _expiry: int = 500 + _expiry: int = 30 _key_name: str | None = None def __init__(self, **data): @@ -139,8 +124,10 @@ def add_private_data(self, path, data): def set_contents(self, contents): vk.json().set(self._key_name, Path.root_path(), contents) - def prolong(self): - vk.expire(self._key_name, self._expiry) + def prolong(self, expiry: int | None = None): + if expiry is None: + expiry = self._expiry + vk.expire(self._key_name, expiry) def delete(self): vk.delete(self._key_name) @@ -154,12 +141,20 @@ class OnboardingTransaction(Transaction): # TODO: Move transition checks here tx_type: TransactionTypes = TransactionTypes.onboarding -class AqrOIDCLoginTransaction(Transaction): - tx_type: TransactionTypes = TransactionTypes.aqr_oidc_login +class LnOIDCLoginTransaction(Transaction): + tx_type: TransactionTypes = TransactionTypes.ln_oidc_login -class AqrOIDCLoginTransactionStates(str, Enum): +class LnOIDCLoginTransactionStates(str, Enum): created = "created" identified = "identified" confirmed = "confirmed" - rejected = "rejected" - token_issued = "token-issued" + finished = "finished" + + +class LNStatusEnum(str, Enum): + ok = "OK" + error = "error" + +class LNStatusResponse(BaseModel): + status: LNStatusEnum + reason: str | None = None diff --git a/quorra/fe/auth/auth.js b/quorra/fe/auth/auth.js index ca10de0..7e53dbc 100644 --- a/quorra/fe/auth/auth.js +++ b/quorra/fe/auth/auth.js @@ -4,6 +4,12 @@ window.onload = async function() { await startAqr(); }; +async function findReplace(objClass, text) { + document.querySelectorAll(`.${objClass}`).forEach(el => { + el.textContent = text; + }); +} + async function startAqr() { const params = new Proxy(new URLSearchParams(window.location.search), { get: (searchParams, prop) => searchParams.get(prop), @@ -12,17 +18,24 @@ async function startAqr() { if (params.nonce) { args = args + `&nonce=${params.nonce}` } - const response = await fetch(`/login/start?${args}`); + const response = await fetch(`../../processes/login/start?${args}`); if (!response.ok) throw new Error("Request failed"); data = await response.json(); txId = data.tx_id; + await findReplace("clientName", params.client_name); + const url = new URL(params.redirect_uri); + var urlString = url.origin + if (url.protocol !== "https:") { + urlString = `⚠️ ${url.origin} ⚠️` + } + await findReplace("redirectURI", urlString); await showQrCode(); startPolling(); } async function showQrCode() { - const payload = { "tx_type": "aqr-oidc-login", "tx_id": txId }; - const response = await fetch("/login/qr", { + const payload = { "tx_type": "ln-oidc-login", "tx_id": txId }; + const response = await fetch("../../lnurl-auth/qr", { method: "POST", headers: { "Content-Type": "application/json" @@ -35,8 +48,8 @@ async function showQrCode() { } function startPolling() { - const pollingUrl = `/tx/transaction`; - const payload = { "tx_id": txId, "tx_type": "aqr-oidc-login" } + const pollingUrl = `../../tx/transaction`; + const payload = { "tx_id": txId, "tx_type": "ln-oidc-login" } const encodeGetParams = p => Object.entries(p).map(kv => kv.map(encodeURIComponent).join("=")).join("&"); @@ -55,32 +68,21 @@ function startPolling() { return response.json(); }) .then(data => { - console.log("Polling data:", data); if (data.state == "identified") { // Hide qr_code_div and show identified_div if (!qr_div.classList.contains("hidden")) { - qr_div.classList.add("hidden"); - } - if (identified_div.classList.contains("hidden")) { - identified_div.classList.remove("hidden"); + showStep("identified_div"); } } // TODO: rejected state else if (data.state == "confirmed") { - // Hide identified_div and qr_code_div, show finished_div - if (!qr_div.classList.contains("hidden")) { - qr_div.classList.add("hidden"); - } - if (!identified_div.classList.contains("hidden")) { - identified_div.classList.add("hidden"); - } - if (finished_div.classList.contains("hidden")) { - finished_div.classList.remove("hidden"); - } + showStep("finished_div"); clearInterval(intervalId); redirectParams = {"code": data.data.oidc_data.code, "state": params.state, "nonce": params.nonce}; - window.location.href = params.redirect_uri + "?" + encodeGetParams(redirectParams); + const redirectAddress = params.redirect_uri + "?" + encodeGetParams(redirectParams); + manual_redirect.href = redirectAddress; + window.location.href = redirectAddress; } }) .catch(error => { diff --git a/quorra/fe/auth/index.html b/quorra/fe/auth/index.html index 59736b7..1aaeae1 100644 --- a/quorra/fe/auth/index.html +++ b/quorra/fe/auth/index.html @@ -3,29 +3,33 @@ - + Quorra -

Quorra

-
-

Scan this QR code on your device

+
+

You're signing into

+

+ +

Scan the below code using your device to proceed

AQR Code
OR
- Use a local install + Use a local application
-