cryptnox-pos 1.0.0
Standalone USDC payment terminal firmware (ESP32 + Cryptnox smart card)
Loading...
Searching...
No Matches
provision.h File Reference

The config portal: one web app for setting a terminal up and for administering it afterwards, in two modes. More...

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "net.h"
#include "ui.h"
Include dependency graph for provision.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define PROV_WINDOW_MIN   15U
 How long the portal stays up before closing itself, minutes.

Enumerations

enum  prov_mode_t { PROV_MODE_OFF , PROV_MODE_WIZARD , PROV_MODE_ADMIN }
 Which of the two portals is running. More...
enum  prov_step_t {
  PROV_STEP_IDLE , PROV_STEP_AUTH , PROV_STEP_ADDR , PROV_STEP_WIFI ,
  PROV_STEP_DONE , PROV_STEP_ADMIN
}
 Where the wizard has got to. More...
enum  prov_ask_t {
  PROV_ASK_NONE , PROV_ASK_PAYOUT_ETH , PROV_ASK_PAYOUT_TRON , PROV_ASK_CONTRACT_ETH ,
  PROV_ASK_CONTRACT_TRON
}
 What the panel is being asked to accept, for prov_pending. More...

Functions

bool prov_start (prov_mode_t mode, ui_event_cb_t cb)
 Raise the portal.
void prov_stop (void)
 Stop the portal, drop the AP, and withdraw anything unaccepted.
prov_mode_t prov_mode (void)
 Which mode is running, or PROV_MODE_OFF.
void prov_set_step (prov_step_t step)
 Tell the portal which wizard step is current.
prov_step_t prov_step (void)
 The current step.
unsigned prov_window_left_min (void)
 Minutes left before the portal closes itself, 0 once it has.
const char * prov_ap_ssid (void)
 AP SSID, or "" while no portal is up.
const char * prov_ap_pass (void)
 AP passphrase, or "" while no portal is up.
const char * prov_qr_payload (void)
 What the panel's QR code should carry.
bool prov_auth_pending (void)
 Whether a browser has asked to be authorised.
void prov_auth_resolve (bool grant)
 Answer a pending authorisation request from the panel.
bool prov_authed (void)
 Whether the browser session is authorised to change anything.
bool prov_pair_code (char *out, size_t out_size)
 The 4-digit pairing code of the browser asking to be let in.
void prov_set_wifi_only (void)
 Cut the wizard down to the Wi-Fi step, with no admin code.
bool prov_wifi_only (void)
 Whether the portal is the cut-down Wi-Fi-only flow.
void prov_set_note (const char *note)
 Put a one-line message on the page.
void prov_set_scan (const net_wifi_ap_t *aps, uint16_t n)
 Hand the portal a Wi-Fi scan for the browser to choose from.
bool prov_pending (prov_ask_t *kind, char *label, size_t label_n, char *value, size_t value_n)
 Fetch the value a browser proposed but nobody has accepted.
bool prov_pending_commit (bool accept)
 Resolve a pending proposal from the panel.
bool prov_propose (prov_ask_t kind, const char *addr)
 Propose a value on behalf of the panel itself.

Detailed Description

The config portal: one web app for setting a terminal up and for administering it afterwards, in two modes.

Why a portal at all

Typing a 42-character recipient address on a 240x320 resistive panel is the worst part of setting one of these up, and telling an operator to type an IP address is only marginally better. Scanning a QR code should land them on the form.

One transport: the terminal's own SoftAP

Both modes raise a WPA2 SoftAP with a fresh per-session passphrase and run a captive portal on it: a DNS responder answers every lookup with the AP's address, and the HTTP server deliberately fails each OS's connectivity probe so the phone concludes the network is captive and opens the browser by itself. Miss either half and the phone joins in silence. The QR code on the panel carries "WIFI:T:WPA;S:...;P:...;;", which both iOS and Android cameras join from directly — so there is never a URL to type.

The AP is the only interface while a portal is up: net_ap_start drops the station association and net_ap_stop restores it. That is not tidiness. esp_http_server binds every interface and offers no bind address, so a portal running beside a station association also answers the venue LAN — where every device holding the venue PSK can reach the payout forms, and where the perimeter this module actually relies on (a passphrase on the panel, in front of the person asking) means nothing at all. So there is no remote administration here, by construction: you are in front of the terminal or you are nowhere.

What that buys, besides the smaller attack surface, is one transport instead of two — no TLS server, no self-signed identity in NVS, no certificate warning to explain on a panel, and no second code path through the same forms.

The two modes

PROV_MODE_WIZARD — a blank terminal, or one whose saved network has become unreachable. Walks the setup steps one at a time and stays up until setup ends.

PROV_MODE_ADMIN — a configured terminal, opened from behind the admin code in the settings menu. Serves everything at once and closes itself after PROV_WINDOW_MIN, because it has taken a working terminal off its network to do this.

Authorisation: the panel, never the wire

The browser has no admin-code field. It asks to be let in, and the terminal shows its admin-code screen; the operator types the code on the panel, and the portal session becomes authorised. So the code never crosses the network in either direction, on either mode's transport, and a browser that reaches the page without the terminal in reach can do nothing at all.

One exception, and it is the wizard's alone: prov_set_wifi_only, the flow a configured terminal gets when all it has lost is its network. See there.

Everything that changes where money goes goes further than that: a browser may propose a payout address or a token contract, and the value is then displayed on the panel for somebody to accept there. Nothing is stored until they do. Firmware follows the same rule — an upload is verified and staged, and only an on-screen accept makes it bootable.

Why plain HTTP, in both modes

Not an oversight:

  • A captive-portal probe fetches a bare http:// URL on port 80 and will not follow us to 443. TLS means the browser never opens by itself, which is the entire point of a captive portal.
  • The link is already encrypted. It is a WPA2 SoftAP whose random per-session passphrase is on the panel in front of the operator, it admits one station at a time, and it only exists while the portal does.
  • The admin code is not on that link (see above), and the values that are get confirmed on the panel.
  • There is nothing else on the wire to protect it from: the AP is the radio's only interface for as long as the portal is up. So the AP passphrase is the perimeter, and TLS on top of WPA2 would buy a certificate warning and nothing else.

Definition in file provision.h.

Macro Definition Documentation

◆ PROV_WINDOW_MIN

#define PROV_WINDOW_MIN   15U

How long the portal stays up before closing itself, minutes.

Definition at line 101 of file provision.h.

Referenced by prov_start().

Enumeration Type Documentation

◆ prov_ask_t

enum prov_ask_t

What the panel is being asked to accept, for prov_pending.

Enumerator
PROV_ASK_NONE 
PROV_ASK_PAYOUT_ETH 

Ethereum payout address.

PROV_ASK_PAYOUT_TRON 

Tron payout address.

PROV_ASK_CONTRACT_ETH 

ERC-20 token contract.

PROV_ASK_CONTRACT_TRON 

TRC-20 token contract.

Definition at line 128 of file provision.h.

◆ prov_mode_t

Which of the two portals is running.

Enumerator
PROV_MODE_OFF 

Not running.

PROV_MODE_WIZARD 

Setup: one step at a time, no self-close.

PROV_MODE_ADMIN 

Administration: everything at once, times out.

Definition at line 104 of file provision.h.

◆ prov_step_t

Where the wizard has got to.

The order is the flow: create the admin code on the panel, show the QR code, have the browser authorised from the panel, set the payout addresses, join the venue network, done. Only the wizard walks these; admin mode sits on PROV_STEP_ADMIN and serves everything at once.

Enumerator
PROV_STEP_IDLE 

Nothing to do — the page says so.

PROV_STEP_AUTH 

Waiting for the admin code to be typed on the panel.

PROV_STEP_ADDR 

Payout addresses.

PROV_STEP_WIFI 

Join the venue's Wi-Fi.

PROV_STEP_DONE 

Setup finished; thank the operator.

PROV_STEP_ADMIN 

Not a wizard step — the full admin page.

Definition at line 118 of file provision.h.

Function Documentation

◆ prov_ap_pass()

const char * prov_ap_pass ( void )

AP passphrase, or "" while no portal is up.

Definition at line 1452 of file provision.cpp.

References s_pass.

Referenced by build_prov(), and open_portal_window().

◆ prov_ap_ssid()

const char * prov_ap_ssid ( void )

AP SSID, or "" while no portal is up.

Definition at line 1451 of file provision.cpp.

References s_ssid.

Referenced by build_prov(), and open_portal_window().

◆ prov_auth_pending()

bool prov_auth_pending ( void )

Whether a browser has asked to be authorised.

Set by POST /api/auth. The panel answers by taking the admin code and calling prov_auth_resolve. Reported as UI_EVENT_PROV_AUTH.

Definition at line 1455 of file provision.cpp.

References s_auth_pending.

◆ prov_auth_resolve()

void prov_auth_resolve ( bool grant)

Answer a pending authorisation request from the panel.

Parameters
[in]granttrue if the operator entered the correct admin code.

Definition at line 1457 of file provision.cpp.

References s_auth_pending, s_authed, s_cb, s_token, TAG, and UI_EVENT_PROV_NEXT.

Referenced by admin_submit(), and btn_event_cb().

◆ prov_authed()

bool prov_authed ( void )

Whether the browser session is authorised to change anything.

Definition at line 1475 of file provision.cpp.

References s_authed.

Referenced by build_prov(), and run_wizard().

◆ prov_mode()

prov_mode_t prov_mode ( void )

Which mode is running, or PROV_MODE_OFF.

Definition at line 1436 of file provision.cpp.

References s_mode.

Referenced by admin_submit(), app_main(), btn_event_cb(), run_wizard(), and ui_task().

◆ prov_pair_code()

bool prov_pair_code ( char * out,
size_t out_size )

The 4-digit pairing code of the browser asking to be let in.

Derived from the session token (its first 16 bits, mod 10000), so the page can compute the same number from the token it holds. Shown on the panel's admin prompt and on the page, so the operator approves the browser in their hand and not whichever one on the access point asked first.

Parameters
[out]outNUL-terminated code on success.
[in]out_size>= 5.
Returns
false when no browser has asked.

Definition at line 1477 of file provision.cpp.

References s_token.

Referenced by build_admin_unlock().

◆ prov_pending()

bool prov_pending ( prov_ask_t * kind,
char * label,
size_t label_n,
char * value,
size_t value_n )

Fetch the value a browser proposed but nobody has accepted.

Parameters
[out]kindWhat is being asked, may be NULL.
[out]labelHuman name for the panel ("Ethereum payout"), may be NULL.
[in]label_nCapacity of label.
[out]valueThe proposed address, may be NULL.
[in]value_nCapacity of value.
Returns
true if a proposal is pending.

Definition at line 1547 of file provision.cpp.

References ask_label(), PROV_ASK_NONE, s_ask, s_ask_lock, and s_ask_val.

Referenced by build_prov_confirm(), and state_get().

◆ prov_pending_commit()

bool prov_pending_commit ( bool accept)

Resolve a pending proposal from the panel.

Parameters
[in]accepttrue to commit it to NVS, false to discard it.
Returns
true if a value was committed — the caller then has to restart to apply it, since the recipient and contract dual stores are built at boot.

Definition at line 1569 of file provision.cpp.

References POS_CHAIN_ETH_USDC, POS_CHAIN_TRON_USDT, PROV_ASK_CONTRACT_ETH, PROV_ASK_CONTRACT_TRON, PROV_ASK_NONE, PROV_ASK_PAYOUT_ETH, PROV_ASK_PAYOUT_TRON, s_ask, s_ask_lock, s_ask_val, s_cb, settings_set_contract(), settings_set_payout(), UI_EVENT_PROV_VALUE_NO, and UI_EVENT_PROV_VALUE_SET.

Referenced by btn_event_cb().

◆ prov_propose()

bool prov_propose ( prov_ask_t kind,
const char * addr )

Propose a value on behalf of the panel itself.

Used by the card-derived route: the terminal reads an address off a Cryptnox card, then puts it through the very same accept-on-the-panel handshake a browser submission goes through, so there is one code path that stores an address and one screen that approves one.

Parameters
[in]kindWhat the value is.
[in]addrThe address; checked by the caller.
Returns
false if another proposal is already waiting.

Definition at line 1527 of file provision.cpp.

References ask_label(), PROV_ASK_NONE, s_ask, s_ask_lock, s_ask_val, s_cb, TAG, and UI_EVENT_PROV_VALUE.

Referenced by app_main(), run_wizard(), and value_post().

◆ prov_qr_payload()

const char * prov_qr_payload ( void )

What the panel's QR code should carry.

"WIFI:T:WPA;S:<ssid>;P:<pass>;;" — a camera joins the AP from it and the captive portal takes over, so one code is enough and there is no URL to read off the panel. Empty while no portal is up.

Definition at line 1453 of file provision.cpp.

References s_qr.

Referenced by build_prov(), and open_portal_window().

◆ prov_set_note()

void prov_set_note ( const char * note)

Put a one-line message on the page.

For the things only the device can know — a Wi-Fi network that would not join, a step that cannot be left yet. The browser is where the operator is looking, so that is where the reason has to appear; the panel is showing a QR code.

Parameters
[in]noteMessage, copied. NULL or "" clears it.

Definition at line 1493 of file provision.cpp.

References s_note, and s_share_mux.

Referenced by app_main(), and run_wizard().

◆ prov_set_scan()

void prov_set_scan ( const net_wifi_ap_t * aps,
uint16_t n )

Hand the portal a Wi-Fi scan for the browser to choose from.

The scan itself stays on the main task — scanning makes the radio hop channels, which briefly drops anyone joined to the SoftAP, so it happens deliberately at known moments (entering the Wi-Fi step, or a rescan the browser asked for) and never inside an HTTP handler.

Parameters
[in]apsScanned networks; copied.
[in]nHow many.

Definition at line 1516 of file provision.cpp.

References PROV_MAX_APS, s_ap_count, s_aps, s_scan_gen, and s_share_mux.

Referenced by app_main(), and run_wizard().

◆ prov_set_step()

void prov_set_step ( prov_step_t step)

Tell the portal which wizard step is current.

Definition at line 1438 of file provision.cpp.

References s_step.

Referenced by run_wizard().

◆ prov_set_wifi_only()

void prov_set_wifi_only ( void )

Cut the wizard down to the Wi-Fi step, with no admin code.

For a terminal that is already configured and has only lost its network. Call it right after prov_start (which clears it) and before any browser arrives; the first browser to ask is then let in without the panel demanding the code, and the panel drops the step numbering, since steps 1 and 3-4 do not happen.

The relaxation is bounded: the perimeter here is the AP's per-device passphrase, which is on the panel in front of whoever is asking, and everything that decides where money goes still has to be accepted on that panel. What it buys is an operator whose till has moved venues typing a password instead of walking three screens to be allowed to.

Definition at line 1489 of file provision.cpp.

References s_wifi_only.

Referenced by run_wizard().

◆ prov_start()

bool prov_start ( prov_mode_t mode,
ui_event_cb_t cb )

Raise the portal.

Idempotent for the same mode; a different mode is refused rather than silently switched, since the two serve different steps to the same page. Stop it first.

Raising the portal takes the terminal off its network for the duration (see above); prov_stop puts it back.

A new AP passphrase is drawn on every call and never stored: it is shown on a screen a customer can see, so a photograph of it must not still open the wifi_only portal — which asks for no admin code — weeks later. prov_stop() wipes it, and a reboot mid-setup simply shows the next one.

Parameters
[in]modeWhich portal to run.
[in]cbWhere submissions are reported; the same callback the UI task uses, so a form and a screen tap are indistinguishable to the main task. Must outlive the call.
Returns
true if the portal is up and reachable; false if the SoftAP or the HTTP server would not start.

Definition at line 1221 of file provision.cpp.

References ap_pass_load(), ap_ssid_build(), dns_task(), net_ap_start(), net_ap_stop(), net_wifi_init(), PORTAL_URL, PROV_MODE_ADMIN, PROV_MODE_OFF, PROV_MODE_WIZARD, PROV_STEP_ADMIN, PROV_STEP_AUTH, PROV_WINDOW_MIN, register_handlers(), s_ask_lock, s_auth_pending, s_authed, s_cb, s_deadline_us, s_dns_run, s_dns_task, s_httpd, s_mode, s_pass, s_qr, s_ssid, s_step, s_token, s_wifi_only, and TAG.

Referenced by open_portal_window(), and run_wizard().

◆ prov_step()

prov_step_t prov_step ( void )

The current step.

Definition at line 1440 of file provision.cpp.

References s_step.

Referenced by run_wizard().

◆ prov_stop()

void prov_stop ( void )

Stop the portal, drop the AP, and withdraw anything unaccepted.

Also re-joins the network the AP displaced, so a configured terminal is back online when the page closes rather than at the next reboot.

Definition at line 1374 of file provision.cpp.

References net_ap_stop(), ota_abort(), PROV_ASK_NONE, PROV_MODE_OFF, PROV_STEP_IDLE, s_ask, s_ask_lock, s_ask_val, s_auth_pending, s_authed, s_deadline_us, s_dns_run, s_dns_task, s_httpd, s_mode, s_pass, s_qr, s_step, s_token, s_wifi_only, and TAG.

Referenced by app_main(), and run_wizard().

◆ prov_wifi_only()

bool prov_wifi_only ( void )

Whether the portal is the cut-down Wi-Fi-only flow.

Definition at line 1491 of file provision.cpp.

References s_wifi_only.

Referenced by build_prov().

◆ prov_window_left_min()

unsigned prov_window_left_min ( void )

Minutes left before the portal closes itself, 0 once it has.

Definition at line 1442 of file provision.cpp.

References s_deadline_us, and s_httpd.

Referenced by open_portal_window(), state_get(), and ui_task().