cashless2ecash

cashless2ecash: pay with cards for digital cash (experimental)
Log | Files | Refs | README

commit a093e52eea3e7d0cf07afc3d6bae1e7dfd5d42f0
parent 1135b1636d351f2b7dbd38036cb8235b7e0fc465
Author: Joel-Haeberli <haebu@rubigen.ch>
Date:   Fri,  3 May 2024 10:22:23 +0200

extract simulation params to config

Diffstat:
Mc2ec/db-postgres.go | 53++++++++++++++++++++++++++++++++++++++++++-----------
Dc2ec/install/installation_notes.md | 113-------------------------------------------------------------------------------
Dc2ec/install/start.sh | 26--------------------------
Rc2ec/install/build_app.sh -> install/build_app.sh | 0
Rc2ec/install/build_cli.sh -> install/build_cli.sh | 0
Ainstall/installation_notes.md | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rc2ec/install/setup_db.sh -> install/setup_db.sh | 0
Rc2ec/install/wipe_db.sh -> install/wipe_db.sh | 0
Asimulation/.gitignore | 2++
Msimulation/c2ec-simulation | 0
Asimulation/config.yaml | 12++++++++++++
Msimulation/go.mod | 2++
Msimulation/go.sum | 4++++
Msimulation/main.go | 85++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Msimulation/sim-terminal.go | 44+++++++++++++++++---------------------------
Msimulation/sim-wallet.go | 24++++++++++++++----------
Mwallee-c2ec/app/src/main/java/ch/bfh/habej2/wallee_c2ec/client/wallee/WalleeResponseHandler.kt | 21++++++++++++++++++++-
Mwallee-c2ec/app/src/main/java/ch/bfh/habej2/wallee_c2ec/withdrawal/AmountScreen.kt | 5+++--
Mwallee-c2ec/app/src/main/java/ch/bfh/habej2/wallee_c2ec/withdrawal/AuthorizePaymentScreen.kt | 34++++++++++++++++++++++------------
Mwallee-c2ec/app/src/main/java/ch/bfh/habej2/wallee_c2ec/withdrawal/WithdrawalViewModel.kt | 25++++++++++++++-----------
20 files changed, 337 insertions(+), 227 deletions(-)

diff --git a/c2ec/db-postgres.go b/c2ec/db-postgres.go @@ -122,13 +122,49 @@ type C2ECPostgres struct { } func PostgresConnectionString(cfg *C2ECDatabseConfig) string { + + pgHost := os.Getenv("PGHOST") + if pgHost != "" { + LogInfo("postgres", "pghost was set") + } else { + pgHost = cfg.Host + } + + pgPort := os.Getenv("PGPORT") + if pgPort != "" { + LogInfo("postgres", "pgport was set") + } else { + pgPort = strconv.Itoa(cfg.Port) + } + + pgUsername := os.Getenv("PGUSER") + if pgUsername != "" { + LogInfo("postgres", "pghost was set") + } else { + pgUsername = cfg.Username + } + + pgPassword := os.Getenv("PGPASSWORD") + if pgPassword != "" { + LogInfo("postgres", "pghost was set") + } else { + pgHost = cfg.Host + } + + pgDb := os.Getenv(" PGDATABASE") + if pgDb != "" { + LogInfo("postgres", "pghost was set") + } else { + pgDb = cfg.Host + } + return fmt.Sprintf( - "postgres://%s:%s@%s:%d/%s", - cfg.Username, - cfg.Password, - cfg.Host, - cfg.Port, - cfg.Database, + "postgres://%s:%s@%s:%s/%s", + pgUsername, + pgPassword, + pgHost, + pgPort, + pgDb, ) } @@ -138,11 +174,6 @@ func NewC2ECPostgres(cfg *C2ECDatabseConfig) (*C2ECPostgres, error) { db := new(C2ECPostgres) connectionString := PostgresConnectionString(cfg) - pgHost := os.Getenv("PGHOST") - if pgHost != "" { - LogInfo("postgres", "pghost was set") - connectionString = pgHost - } dbConnCfg, err := pgxpool.ParseConfig(connectionString) if err != nil { diff --git a/c2ec/install/installation_notes.md b/c2ec/install/installation_notes.md @@ -1,113 +0,0 @@ -# Installation of C2EC and surrounding components - -how to install exchange and C2EC - -## Prerequisites - -- Debian -- git -- postgres >= 15.6 -- go ([installing Go](https://go.dev/doc/install)) -- it's a good idea to read [Exchange Operator Manual](https://docs.taler.net/taler-exchange-manual.html) first - -## Required Exchange binaries - -To allow the withdrawal of Taler, I will need following binaries: - -- taler-exchange-httpd -- taler-exchange-secmod-rsa -- taler-exchange-secmod-cs -- taler-exchange-secmod-eddsa -- taler-exchange-closer -- taler-exchange-wirewatch - -## Setup Commands - -```bash - -# Add taler repo and install -sudo echo "deb [signed-by=/etc/apt/keyrings/taler-systems.gpg] https://deb.taler.net/apt/debian bookworm main" > /etc/apt/sources.list.d/taler.list` -sudo wget -O /etc/apt/keyrings/taler-systems.gpg https://taler.net/taler-systems.gpg -sudo apt update -sudo apt install taler-exchange - -# install git -sudo apt install git - -# download Go and install -export GO_TAR=go1.22.2.linux-amd64.tar.gz -sudo wget -O $GO_TAR https://go.dev/dl/$GO_TAR -sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf $GO_TAR -echo 'export PATH=$PATH:/usr/local/go/bin' >> $HOME/.profile -source $HOME/.profile -go version -``` - -## Configure - -### Getting the source - -`git clone https://git.taler.net/cashless2ecash.git` - -### Preparing the database - -```bash -sudo passwd postgres # change default password of postgres user -su postgres -psql -``` - -```sql -CREATE DATABASE c2ec; -CREATE USER c2ec_admin WITH ENCRYPTED PASSWORD [..]; -- keepass -GRANT ALL PRIVILEGES ON DATABASE c2ec TO c2ec_admin; ---For CLI (managing terminals and providers): -CREATE USER c2ec_operator WITH ENCRYPTED PASSWORD [..]; -- keepass ---For the API (handling withdrawals): -CREATE USER c2ec_api WITH ENCRYPTED PASSWORD [..]; -- keepass -``` - -exit psql, change back to normal user (type 2x 'exit') - -### Setting up c2ec schmema -find src directory of cashless2ecash, find c2ec/install/setup_db.sh - -```bash -export PGHOST=localhost` -export PGPORT=5432 -./setup_db.sh c2ec_admin [PASSWORD OBFUSCATED] c2ec ./.. -su postgres -psql -d c2ec -``` - -Grant rights on tables, triggers and functions to the users `c2ec_api` and `c2ec_operator` - -```sql -GRANT ALL PRIVILEGES ON c2ec.withdrawal TO c2ec_api; -GRANT SELECT ON c2ec.terminal TO c2ec_api; -GRANT SELECT ON c2ec.provider TO c2ec_api; -GRANT EXECUTE ON FUNCTION c2ec.emit_withdrawal_status TO c2ec_api; -GRANT EXECUTE ON FUNCTION c2ec.emit_payment_notification TO c2ec_api; -GRANT EXECUTE ON FUNCTION c2ec.emit_retry_notification TO c2ec_api; -GRANT EXECUTE ON FUNCTION c2ec.emit_transfer_notification TO c2ec_api; -GRANT ALL PRIVILEGES ON c2ec.terminal TO c2ec_operator; -GRANT ALL PRIVILEGES ON c2ec.provider TO c2ec_operator; -``` - -### Building and Running the app - -Building the cli (used to manage terminals and providers) - -```bash -./build_cli.sh ./../../cli $HOME -.$HOME/cli -``` - -Building c2ec - -```bash -./build_app.sh ./.. $HOME -cp $HOME/cashless2ecash/c2ec/c2ec-config.yaml $HOME -# configure correctly -.$HOME/c2ec -``` diff --git a/c2ec/install/start.sh b/c2ec/install/start.sh @@ -1,25 +0,0 @@ -#!/bin/bash - -if [ "$#" -ne 1 ]; then - echo "Usage: $0 <config-file-path>" - exit 1 -fi -CONFIG_FILE=$1 - -build_and_run_go_app() { - go build -o app - if [ $? -ne 0 ]; then - echo "Failed to build Go application" - exit 1 - fi - - ./app "$CONFIG_FILE" - if [ $? -ne 0 ]; then - echo "Failed to run Go application" - exit 1 - fi -} - -build_and_run_go_app - -rm -f app -\ No newline at end of file diff --git a/c2ec/install/build_app.sh b/install/build_app.sh diff --git a/c2ec/install/build_cli.sh b/install/build_cli.sh diff --git a/install/installation_notes.md b/install/installation_notes.md @@ -0,0 +1,114 @@ +# Installation of C2EC and surrounding components + +how to install exchange and C2EC + +## Prerequisites + +- Debian +- git +- postgres >= 15.6 +- go ([installing Go](https://go.dev/doc/install)) +- it's a good idea to read [Exchange Operator Manual](https://docs.taler.net/taler-exchange-manual.html) first + +## Required Exchange binaries + +To allow the withdrawal of Taler, I will need following binaries: + +- taler-exchange-httpd +- taler-exchange-secmod-rsa +- taler-exchange-secmod-cs +- taler-exchange-secmod-eddsa +- taler-exchange-closer +- taler-exchange-wirewatch + +## Setup Commands + +```bash +# Add taler repo and install +sudo echo "deb [signed-by=/etc/apt/keyrings/taler-systems.gpg] https://deb.taler.net/apt/debian bookworm main" > /etc/apt/sources.list.d/taler.list` +sudo wget -O /etc/apt/keyrings/taler-systems.gpg https://taler.net/taler-systems.gpg +sudo apt update +sudo apt install taler-exchange + +# install git +sudo apt install git + +# download Go and install +export GO_TAR=go1.22.2.linux-amd64.tar.gz +sudo wget -O $GO_TAR https://go.dev/dl/$GO_TAR +sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf $GO_TAR +echo 'export PATH=$PATH:/usr/local/go/bin' >> $HOME/.profile +source $HOME/.profile +go version +``` + +## Configure + +### Getting the source + +`git clone https://git.taler.net/cashless2ecash.git` + +### Preparing the database + +```bash +sudo passwd postgres # change default password of postgres user +su postgres +psql +``` + +```sql +CREATE DATABASE c2ec; +CREATE USER c2ec_admin WITH ENCRYPTED PASSWORD [..]; -- keepass +GRANT ALL PRIVILEGES ON DATABASE c2ec TO c2ec_admin; +--For CLI (managing terminals and providers): +CREATE USER c2ec_operator WITH ENCRYPTED PASSWORD [..]; -- keepass +--For the API (handling withdrawals): +CREATE USER c2ec_api WITH ENCRYPTED PASSWORD [..]; -- keepass +``` + +exit psql, change back to normal user (type 2x 'exit') + +### Setting up c2ec schmema +find src directory of cashless2ecash, find c2ec/install/setup_db.sh + +```bash +export PGHOST=localhost` +export PGPORT=5432 +./setup_db.sh c2ec_admin [PASSWORD OBFUSCATED] c2ec ./.. +su postgres +psql -d c2ec +``` + +Grant rights on tables, triggers and functions to the users `c2ec_api` and `c2ec_operator` + +```sql +GRANT USAGE ON SCHEMA c2ec TO c2ec_api; +GRANT USAGE ON SCHEMA c2ec TO c2ec_operator; +GRANT ALL PRIVILEGES ON c2ec.withdrawal TO c2ec_api; +GRANT SELECT ON c2ec.terminal TO c2ec_api; +GRANT SELECT ON c2ec.provider TO c2ec_api; +GRANT EXECUTE ON FUNCTION c2ec.emit_withdrawal_status TO c2ec_api; +GRANT EXECUTE ON FUNCTION c2ec.emit_payment_notification TO c2ec_api; +GRANT EXECUTE ON FUNCTION c2ec.emit_retry_notification TO c2ec_api; +GRANT EXECUTE ON FUNCTION c2ec.emit_transfer_notification TO c2ec_api; +GRANT ALL PRIVILEGES ON c2ec.terminal TO c2ec_operator; +GRANT ALL PRIVILEGES ON c2ec.provider TO c2ec_operator; +``` + +### Building and Running the app + +Building the cli (used to manage terminals and providers) + +```bash +./build_cli.sh ./../cli $HOME +.$HOME/cli +``` + +Building c2ec + +```bash +./build_app.sh ./../c2ec $HOME +cp $HOME/cashless2ecash/c2ec/c2ec-config.yaml $HOME +# configure correctly +.$HOME/c2ec +``` diff --git a/c2ec/install/setup_db.sh b/install/setup_db.sh diff --git a/c2ec/install/wipe_db.sh b/install/wipe_db.sh diff --git a/simulation/.gitignore b/simulation/.gitignore @@ -0,0 +1 @@ +local-config.yaml +\ No newline at end of file diff --git a/simulation/c2ec-simulation b/simulation/c2ec-simulation Binary files differ. diff --git a/simulation/config.yaml b/simulation/config.yaml @@ -0,0 +1,11 @@ +disable-delays: false +c2ec-base-url: "http://localhost:8080" +provider-backend-payment-delay: 1000 +terminal-accept-card-delay: 5000 +terminal-provider: "Simulation" +terminal-id: "1" +terminal-access-token: "bliblablu" +terminal-long-poll-ms: "20000" +terminal-qr-base: "http://localhost:8080" +wallet-scan-qr-delay: 5000 +wallet-long-poll-ms: "10000" +\ No newline at end of file diff --git a/simulation/go.mod b/simulation/go.mod @@ -3,3 +3,5 @@ module c2ec-simulation go 1.22.1 require github.com/gofrs/uuid v4.4.0+incompatible + +require gopkg.in/yaml.v3 v3.0.1 diff --git a/simulation/go.sum b/simulation/go.sum @@ -1,2 +1,6 @@ github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/simulation/main.go b/simulation/main.go @@ -3,30 +3,35 @@ package main import ( "fmt" "os" -) - -const DISABLE_DELAYS = true - -const C2EC_BASE_URL = "http://localhost:8082" -// simulates the terminal talking to its backend system and executing the payment. -const PROVIDER_BACKEND_PAYMENT_DELAY_MS = 1000 - -// simulates the provider client fetching attestation at the providers backend. -const PROVIDER_BACKEND_ATTESTATION_DELAY_MS = 1000 + "gopkg.in/yaml.v3" +) -// simulates the user presenting his card to the terminal const TERMINAL_ACCEPT_CARD_DELAY_MS = 5000 -// simulates the user scanning the QR code presented at the terminal const WALLET_SCAN_QR_CODE_DELAY_MS = 5000 +var CONFIG SimulationConfig + type SimulatedPhysicalInteraction struct { Msg string } func main() { + p := "./config.yaml" + if len(os.Args) > 1 && os.Args[1] != "" { + p = os.Args[1] + } + + cfg, err := parseSimulationConfig(p) + if err != nil { + fmt.Println(err.Error()) + return + } + CONFIG = *cfg + TERMINAL_USER_ID = "Simulation-" + CONFIG.TerminalId + if !c2ecAlive() { fmt.Println("start c2ec first.") return @@ -54,11 +59,63 @@ func main() { func c2ecAlive() bool { - cfg, status, err := HttpGet(C2EC_BANK_CONFIG_URL, map[string]string{}, NewJsonCodec[BankIntegrationConfig]()) + cfg, status, err := HttpGet( + CONFIG.C2ecBaseUrl+"/config", + map[string]string{ + "Authorization": TerminalAuth(), + }, + NewJsonCodec[TerminalConfig]()) if err != nil || status != 200 { + fmt.Println("Error from c2ec:", err) + fmt.Println("Status from c2ec:", status) return false } - fmt.Println("C2EC-Config:", cfg.Name, cfg.Version, cfg.Currency, cfg.CurrencySpecification.AltUnitNames) + fmt.Println("C2EC-Config:", cfg.Name, cfg.Version, cfg.ProviderName, cfg.WireType) return true } + +type SimulationConfig struct { + DisableDelays bool `yaml:"disable-delays"` + C2ecBaseUrl string `yaml:"c2ec-base-url"` + // simulates the terminal talking to its backend system and executing the payment. + ProviderBackendPaymentDelay int `yaml:"provider-backend-payment-delay"` + // simulates the user presenting his card to the terminal + TerminalAcceptCardDelay int `yaml:"terminal-accept-card-delay"` + TerminalProvider string `yaml:"terminal-provider"` + TerminalId string `yaml:"terminal-id"` + TerminalUserId string `yaml:"terminal-user-id"` + TerminalAccessToken string `yaml:"terminal-access-token"` + TerminalLongPollMs string `yaml:"terminal-long-poll-ms"` + TerminalQrCodeBase string `yaml:"terminal-qr-base"` + // simulates the user scanning the QR code presented at the terminal + WalletScanQrDelay int `yaml:"wallet-scan-qr-delay"` + WalletLongPollMs string `yaml:"wallet-long-poll-ms"` +} + +func parseSimulationConfig(path string) (*SimulationConfig, error) { + + f, err := os.Open(path) + if err != nil { + return nil, err + } + defer f.Close() + + stat, err := f.Stat() + if err != nil { + return nil, err + } + + content := make([]byte, stat.Size()) + _, err = f.Read(content) + if err != nil { + return nil, err + } + + cfg := new(SimulationConfig) + err = yaml.Unmarshal(content, cfg) + if err != nil { + return nil, err + } + return cfg, nil +} diff --git a/simulation/sim-terminal.go b/simulation/sim-terminal.go @@ -10,28 +10,17 @@ import ( "github.com/gofrs/uuid" ) -const C2EC_TERMINAL_CONFIG_API = C2EC_BASE_URL + "/config" -const C2EC_TERMINAL_SETUP_WITHDRAWAL_API = C2EC_BASE_URL + "/withdrawals" -const C2EC_TERMINAL_STATUS_WITHDRAWAL_API = C2EC_BASE_URL + "/withdrawals/:wopid" -const C2EC_TERMINAL_CHECK_WITHDRAWAL_API = C2EC_BASE_URL + "/withdrawals/:wopid/check" - -const TERMINAL_PROVIDER = "Simulation" - -// this must be the id retrieved by the cli -const TERMINAL_ID = "2" - -// retrieved from the cli tool when added the terminal -const TERMINAL_USER_ID = "Simulation-" + TERMINAL_ID - // retrieved from the cli tool when added the terminal -const TERMINAL_ACCESS_TOKEN = "oVclsDlWVl0LaQg83e05M7/vCk2PfdJ785GaI0MQ0wc=" - -const SIM_TERMINAL_LONG_POLL_MS_STR = "20000" // 20 seconds - -const QR_CODE_CONTENT_BASE = "taler://withdraw/localhost:8082/taler-integration/" +var TERMINAL_USER_ID string func Terminal(in chan *SimulatedPhysicalInteraction, out chan *SimulatedPhysicalInteraction, kill chan error) { + var C2EC_TERMINAL_CONFIG_API = CONFIG.C2ecBaseUrl + "/config" + var C2EC_TERMINAL_SETUP_WITHDRAWAL_API = CONFIG.C2ecBaseUrl + "/withdrawals" + var C2EC_TERMINAL_STATUS_WITHDRAWAL_API = CONFIG.C2ecBaseUrl + "/withdrawals/:wopid" + var C2EC_TERMINAL_CHECK_WITHDRAWAL_API = CONFIG.C2ecBaseUrl + "/withdrawals/:wopid/check" + TERMINAL_USER_ID = "Simulation-" + CONFIG.TerminalId + fmt.Println("TERMINAL: Terminal idle... awaiting readiness message of sim-wallet") <-in @@ -105,7 +94,7 @@ func Terminal(in chan *SimulatedPhysicalInteraction, out chan *SimulatedPhysical } wopidEncoded = FormatWopid(wopidDecoded) - uri := QR_CODE_CONTENT_BASE + wopidEncoded + uri := CONFIG.TerminalQrCodeBase + wopidEncoded fmt.Println("TERMINAL: Taler Withdrawal URI:", uri) // note for realworld implementation @@ -119,7 +108,7 @@ func Terminal(in chan *SimulatedPhysicalInteraction, out chan *SimulatedPhysical url := FormatUrl( C2EC_TERMINAL_STATUS_WITHDRAWAL_API, map[string]string{"wopid": wopidEncoded}, - map[string]string{"long_poll_ms": SIM_TERMINAL_LONG_POLL_MS_STR}, + map[string]string{"long_poll_ms": CONFIG.TerminalLongPollMs}, ) fmt.Println("TERMINAL: requesting status update for withdrawal", url) response, status, err := HttpGet( @@ -142,7 +131,7 @@ func Terminal(in chan *SimulatedPhysicalInteraction, out chan *SimulatedPhysical fmt.Println("need to sleep a bit that long polling request is guaranteed to be executed before the POST of the registration. This won't be a problem in real world appliance.") time.Sleep(time.Duration(10) * time.Millisecond) - if !DISABLE_DELAYS { + if !CONFIG.DisableDelays { fmt.Println("TERMINAL: simulating QR Code scan. delay:", WALLET_SCAN_QR_CODE_DELAY_MS) time.Sleep(time.Duration(WALLET_SCAN_QR_CODE_DELAY_MS) * time.Millisecond) } else { @@ -153,15 +142,15 @@ func Terminal(in chan *SimulatedPhysicalInteraction, out chan *SimulatedPhysical select { case w := <-awaitSelection: fmt.Println("TERMINAL: parameters selected:", w.ReservePubKey) - if !DISABLE_DELAYS { + if !CONFIG.DisableDelays { fmt.Println("TERMINAL: simulating user interaction. customer presents card. delay:", TERMINAL_ACCEPT_CARD_DELAY_MS) time.Sleep(time.Duration(TERMINAL_ACCEPT_CARD_DELAY_MS) * time.Millisecond) } else { fmt.Println("TERMINAL: simulating user interaction. customer presents card.") } - if !DISABLE_DELAYS { - fmt.Println("TERMINAL: card accepted. terminal waits for response of provider backend. delay:", PROVIDER_BACKEND_PAYMENT_DELAY_MS) - time.Sleep(time.Duration(PROVIDER_BACKEND_PAYMENT_DELAY_MS) * time.Millisecond) + if !CONFIG.DisableDelays { + fmt.Println("TERMINAL: card accepted. terminal waits for response of provider backend. delay:", CONFIG.ProviderBackendPaymentDelay) + time.Sleep(time.Duration(CONFIG.ProviderBackendPaymentDelay) * time.Millisecond) } else { fmt.Println("TERMINAL: card accepted. terminal waits for response of provider backend.") } @@ -196,7 +185,8 @@ func Terminal(in chan *SimulatedPhysicalInteraction, out chan *SimulatedPhysical fmt.Println("TERMINAL: error while check payment POST: " + strconv.Itoa(status)) kill <- errors.New("payment check request by terminal failed") } - fmt.Println("TERMINAL: Terminal flow ended") + fmt.Println("TERMINAL: Terminal flow ended succesful") + return case f := <-longPollFailed: fmt.Println("TERMINAL: long-polling for selection failed... error:", err) kill <- f @@ -206,7 +196,7 @@ func Terminal(in chan *SimulatedPhysicalInteraction, out chan *SimulatedPhysical func TerminalAuth() string { - userAndPw := fmt.Sprintf("%s:%s", TERMINAL_USER_ID, TERMINAL_ACCESS_TOKEN) + userAndPw := fmt.Sprintf("%s:%s", TERMINAL_USER_ID, CONFIG.TerminalAccessToken) return "Basic " + base64.StdEncoding.EncodeToString([]byte(userAndPw)) } diff --git a/simulation/sim-wallet.go b/simulation/sim-wallet.go @@ -12,20 +12,20 @@ import ( "time" ) -const C2EC_BANK_BASE_URL = C2EC_BASE_URL + "/taler-integration" -const C2EC_BANK_CONFIG_URL = C2EC_BANK_BASE_URL + "/config" -const C2EC_BANK_WITHDRAWAL_STATUS_URL = C2EC_BANK_BASE_URL + "/withdrawal-operation/:wopid" -const C2EC_BANK_WITHDRAWAL_REGISTRATION_URL = C2EC_BANK_BASE_URL + "/withdrawal-operation/:wopid" - -const SIM_WALLET_LONG_POLL_MS_STR = "10000" // 10 seconds +var C2EC_BANK_BASE_URL string func Wallet(in chan *SimulatedPhysicalInteraction, out chan *SimulatedPhysicalInteraction, kill chan error) { + C2EC_BANK_BASE_URL = CONFIG.C2ecBaseUrl + "/taler-integration" + var C2EC_BANK_WITHDRAWAL_STATUS_URL = C2EC_BANK_BASE_URL + "/withdrawal-operation/:wopid" + var C2EC_BANK_WITHDRAWAL_REGISTRATION_URL = C2EC_BANK_BASE_URL + "/withdrawal-operation/:wopid" + var SIM_WALLET_LONG_POLL_MS_STR = CONFIG.WalletLongPollMs + fmt.Println("WALLET : Wallet started. Signaling terminal readiness (this is simulation specific)") out <- &SimulatedPhysicalInteraction{Msg: "wallet ready"} uriFromQrCode := <-in - if !DISABLE_DELAYS { + if !CONFIG.DisableDelays { time.Sleep(time.Duration(WALLET_SCAN_QR_CODE_DELAY_MS) * time.Millisecond) } fmt.Println("WALLET : simulated QR code scanning... scanned", uriFromQrCode) @@ -75,13 +75,17 @@ func Wallet(in chan *SimulatedPhysicalInteraction, out chan *SimulatedPhysicalIn awaitConfirmationOrAbortion := make(chan *C2ECWithdrawalStatus) longPollFailed := make(chan error) - // long poll for parameter selection notification by c2ec + // long poll for confirmation or abortion by c2ec (whihc proves that it worked) go func() { url := FormatUrl( C2EC_BANK_WITHDRAWAL_STATUS_URL, map[string]string{"wopid": wopid}, - map[string]string{"long_poll_ms": SIM_WALLET_LONG_POLL_MS_STR}, + map[string]string{ + "long_poll_ms": SIM_WALLET_LONG_POLL_MS_STR, + "old_state": string(SELECTED), + }, ) + println("WALLET : asking for confirmation or abortion of the withdrawal.") response, status, err := HttpGet( url, map[string]string{"Authorization": TerminalAuth()}, @@ -120,7 +124,7 @@ func Wallet(in chan *SimulatedPhysicalInteraction, out chan *SimulatedPhysicalIn // returns wopid. func parseTalerWithdrawUri(s string) (string, error) { - wopid, found := strings.CutPrefix(s, QR_CODE_CONTENT_BASE) + wopid, found := strings.CutPrefix(s, CONFIG.TerminalQrCodeBase) if !found { return "", errors.New("invalid uri " + s) } diff --git a/wallee-c2ec/app/src/main/java/ch/bfh/habej2/wallee_c2ec/client/wallee/WalleeResponseHandler.kt b/wallee-c2ec/app/src/main/java/ch/bfh/habej2/wallee_c2ec/client/wallee/WalleeResponseHandler.kt @@ -11,15 +11,34 @@ class WalleeResponseHandler( private val model: WithdrawalViewModel ) : ResponseHandler() { + override fun authorizeTransactionReply(response: TransactionResponse?) { + + println("C2EC-TRANSACTION-RESPONSE: $response") + + if (response == null) { + model.withdrawalOperationFailed() + activity.finish() + return + } + + println("C2EC-TRANSACTION-RESPONSE: ${response}") + + model.updateWalleeTransactionReply(response) + } + override fun completeTransactionReply(response: TransactionCompletionResponse?) { + println("C2EC-COMPLETION-RESPONSE: $response") + if (response == null) { model.withdrawalOperationFailed() activity.finish() return } - model.updateWalleeTransaction(response) + println("C2EC-COMPLETION-RESPONSE: ${response.transactionCompletion}") + + model.updateWalleeTransactionCompletion(response) } override fun checkApiServiceCompatibilityReply( diff --git a/wallee-c2ec/app/src/main/java/ch/bfh/habej2/wallee_c2ec/withdrawal/AmountScreen.kt b/wallee-c2ec/app/src/main/java/ch/bfh/habej2/wallee_c2ec/withdrawal/AmountScreen.kt @@ -37,14 +37,15 @@ fun AmountScreen(model: WithdrawalViewModel, navigateToWhenAmountEntered: () -> ) ) - Button(onClick = { + Button(onClick = { + println("clicked 'pay'") val success = model.setupWithdrawal() if (!success) { activity.finish() } model.withdrawalOperationFailed() navigateToWhenAmountEntered() - }, enabled = (model.uiState.value.amount.value > 0 || model.uiState.value.amount.frac > 0)) { + } /*, enabled = (model.uiState.value.amount.value > 0 || model.uiState.value.amount.frac > 0)*/) { Text(text = "pay") } diff --git a/wallee-c2ec/app/src/main/java/ch/bfh/habej2/wallee_c2ec/withdrawal/AuthorizePaymentScreen.kt b/wallee-c2ec/app/src/main/java/ch/bfh/habej2/wallee_c2ec/withdrawal/AuthorizePaymentScreen.kt @@ -12,6 +12,7 @@ import androidx.compose.ui.platform.LocalContext import com.wallee.android.till.sdk.ApiClient import com.wallee.android.till.sdk.data.LineItem import com.wallee.android.till.sdk.data.Transaction +import com.wallee.android.till.sdk.data.TransactionCompletion import com.wallee.android.till.sdk.data.TransactionProcessingBehavior import java.math.BigDecimal import java.util.Currency @@ -22,10 +23,28 @@ fun AuthorizePaymentScreen(model: WithdrawalViewModel, client: ApiClient) { val uiState by model.uiState.collectAsState() val activity = LocalContext.current as Activity +// val withdrawalAmount = LineItem +// .ListBuilder( +// uiState.encodedWopid, +// BigDecimal("${uiState.amount.value}.${uiState.amount.frac}") +// ) +// .build() + + Column( + horizontalAlignment = Alignment.CenterHorizontally + ) { + + Text(text = "Authorizing transaction...") + + Button(onClick = { activity.finish() }) { + Text(text = "finish") + } + } + val withdrawalAmount = LineItem .ListBuilder( uiState.encodedWopid, - BigDecimal("${uiState.amount.value}.${uiState.amount.frac}") + BigDecimal("3.0") ) .build() @@ -38,20 +57,11 @@ fun AuthorizePaymentScreen(model: WithdrawalViewModel, client: ApiClient) { try { client.authorizeTransaction(transaction) + //client.completeTransaction(TransactionCompletion.Builder(transaction.lineItems).build()) } catch (e: Exception) { + println("FAILED authorizing transaction ${e.message}") model.withdrawalOperationFailed() activity.finish() e.printStackTrace() } - - Column( - horizontalAlignment = Alignment.CenterHorizontally - ) { - - Text(text = "Transaction Executed") - - Button(onClick = { activity.finish() }) { - Text(text = "finish") - } - } } diff --git a/wallee-c2ec/app/src/main/java/ch/bfh/habej2/wallee_c2ec/withdrawal/WithdrawalViewModel.kt b/wallee-c2ec/app/src/main/java/ch/bfh/habej2/wallee_c2ec/withdrawal/WithdrawalViewModel.kt @@ -9,18 +9,17 @@ import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import ch.bfh.habej2.wallee_c2ec.client.taler.TerminalClient -import ch.bfh.habej2.wallee_c2ec.client.taler.TerminalClientImplementation import ch.bfh.habej2.wallee_c2ec.client.taler.TerminalClientMock import ch.bfh.habej2.wallee_c2ec.client.taler.config.TalerTerminalConfig import ch.bfh.habej2.wallee_c2ec.client.taler.model.TerminalWithdrawalConfirmationRequest import ch.bfh.habej2.wallee_c2ec.client.taler.model.TerminalWithdrawalSetup import com.wallee.android.till.sdk.data.State import com.wallee.android.till.sdk.data.TransactionCompletionResponse +import com.wallee.android.till.sdk.data.TransactionResponse import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch import java.io.Closeable -import java.math.BigDecimal import java.util.Optional import java.util.UUID @@ -46,7 +45,8 @@ interface WithdrawalOperationState{ val amountError: String val currency: String val payed: Boolean - val transaction: TransactionCompletionResponse? + val transaction: TransactionResponse? + val transactionCompletion: TransactionCompletionResponse? } private class MutableWithdrawalOperationState: WithdrawalOperationState { @@ -58,7 +58,8 @@ private class MutableWithdrawalOperationState: WithdrawalOperationState { override var amountError: String by mutableStateOf("") override var currency: String by mutableStateOf("") override var payed: Boolean by mutableStateOf(false) - override var transaction: TransactionCompletionResponse? by mutableStateOf(null) + override var transaction: TransactionResponse? by mutableStateOf(null) + override var transactionCompletion: TransactionCompletionResponse? by mutableStateOf(null) } class WithdrawalViewModel( @@ -75,7 +76,7 @@ class WithdrawalViewModel( _uiState.value = MutableWithdrawalOperationState() // reset withdrawal operation val optionalApiCfg = terminalClient!!.terminalsConfig() if (!optionalApiCfg.isPresent) { - println("no config") + println("unable to fetch config from c2ec") activity.finish() } updateCurrency(optionalApiCfg.get().currency) @@ -93,6 +94,7 @@ class WithdrawalViewModel( return false } + println("retrieved WOPID from c2ec: ${res.get().withdrawalId}") _uiState.value.encodedWopid = res.get().withdrawalId return true } @@ -109,16 +111,17 @@ class WithdrawalViewModel( } } - fun updateAmount(amount: String) { - _uiState.value.amount = parseAmount(amount).orElse(Amount(0,0)) - } - private fun updateCurrency(currency: String) { _uiState.value.currency = currency } - fun updateWalleeTransaction(completion: TransactionCompletionResponse) { - _uiState.value.transaction = completion + fun updateWalleeTransactionReply(transaction: TransactionResponse) { + + _uiState.value.transaction = transaction + } + + fun updateWalleeTransactionCompletion(completion: TransactionCompletionResponse) { + _uiState.value.transactionCompletion = completion if (completion.state == State.FAILED) { withdrawalOperationFailed()