4.3 KiB
4.3 KiB
pub struct Api
Api manages the HTTP interface for the application
Members:
host: String- the hostname of the service for checking NIP 98 auth, fromHOSTport: u16- a port to run the server on fromPORTadmins: Vec<String>- a list of admin pubkeys fromADMINSorigins: Vec<String>- to be used in CORS headers, fromALLOW_ORIGINSrepo: Repo
Notes:
- Authentication is done using NIP 98 comparing
utoself.host, not the incoming request - Each route is responsible for authorization using
self.is_admin(pubkey)orself.is_tenant(authorized_pubkey, tenant_pubkey) - Successful API responses should be of the form
{data, code: "ok"}with an appropriate http status code. - Unsuccessful API responses should be of the form
{error, code}with an appropriate http status code.codeis a short error code (e.g.duplicate-subdomain) anderroris a human-readable error message.
pub fn new() -> Self
- Reads environment and populates members
pub fn serve(&self) -> Result<()>
- Initializes an
axum::Router - Adds CORS middleware based on
origins - Calls
axum::servewith a listener
--- Tenant routes
async fn list_tenants(...) -> Response
- Serves
GET /tenants - Authorizes admin only
- Return
datais a list of tenant structs fromrepo.list_tenants
async fn get_tenant(...) -> Response
- Serves
GET /tenants/:pubkey - Authorizes admin or matching tenant
- Return
datais a single tenant struct fromrepo.get_tenant
async fn create_tenant(...) -> Response
- Serves
POST /tenants - Authorizes anyone, but must be authorized
- Creates a new tenant using
repo.create_tenantbased on the authorized pubkey - If tenant is a duplicate, return a
422withcode=pubkey-exists - Return
datais a single tenant struct. Use HTTP201.
--- Relay routes
async fn list_relays(...) -> Response
- Serves
GET /relays?tenant=<pubkey> - Authorizes admin or existing tenants
- If user is admin,
tenantquery parameter is optional - If user is a tenant,
tenantquery parameter is not ok; authenticatedpubkeyis used - Return
datais a list of relay structs fromrepo.list_relays
async fn get_relay(...) -> Response
- Serves
GET /relays/:id - Authorizes admin or relay owner
- Return
datais a single relay struct fromrepo.get_relay
async fn create_relay(...) -> Response
- Serves
POST /relays - Authorizes admin or matching tenant pubkey in request body
- Validates/prepares the relay data to be saved using
prepare_relay - Creates a new relay using
repo.create_relay - If relay is a duplicate by subdomain, return a
422withcode=subdomain-exists - Return
datais a single relay struct. Use HTTP201.
async fn update_relay(...) -> Response
- Serves
PUT /relays/:id - Authorizes admin or relay owner
- Validates/prepares the relay data to be saved using
prepare_relay - Updates the given relay using
repo.update_relay - If relay is a duplicate by subdomain, return a
422withcode=subdomain-exists - Return
datais a single relay struct.
async fn deactivate_relay(...) -> Response
- Serves
POST /relays/:id/deactivate - Authorizes admin or relay owner
- Deactivates relay using
repo.deactivate_relay - Return
datais empty
--- Billing routes
async fn list_invoices(...) -> Response
- Serves
GET /invoices?tenant=<pubkey> - Authorizes admin or existing tenants
- If user is admin,
tenantquery parameter is optional - If user is a tenant,
tenantquery parameter is not ok; authenticatedpubkeyis used - Return
datais a list of invoice structs fromrepo.list_invoices
Utility functions
extract_auth_pubkey(headers: &HeaderMap, method: &Method, uri: &Uri) -> Result<String>
- Parses
Authorizationheader - Validates event kind and signature using
nostr_sdk - Validates event
uandmethodtags against parameters - Returns pubkey if header is valid
Refer to https://github.com/nostr-protocol/nips/blob/master/98.md for details. Use nostr_sdk functionality where possible.
prepare_relay(relay: Relay) -> anyhow::Result<Relay>
- Validate
subdomain - If
planis free andblossomis enabled, returnpremium-feature - If
planis free andlivekitis enabled, returnpremium-feature - Populate
schemaif not already set - Populate missing fields using reasonable defaults