commit 4a4a3b3d17e3eb6133e13cb04ff8a6b982b8a5a7 parent e6a4d687e8290d15900c743af6538a67643b5130 Author: Joel-Haeberli <haebu@rubigen.ch> Date: Mon, 20 May 2024 20:56:46 +0200 fix: wire gateway api Diffstat:
22 files changed, 242 insertions(+), 35 deletions(-)
diff --git a/c2ec/api-auth.go b/c2ec/api-auth.go @@ -85,7 +85,34 @@ func AuthenticateTerminal(req *http.Request) bool { return ValidPassword(password, terminal.AccessToken) } + LogWarn("auth", "basic auth prefix did not match") + return false +} + +func AuthenticateWirewatcher(req *http.Request) bool { + + auth := req.Header.Get(AUTHORIZATION_HEADER) + if basicAuth, found := strings.CutPrefix(auth, BASIC_AUTH_PREFIX); found { + decoded, err := base64.StdEncoding.DecodeString(basicAuth) + if err != nil { + LogWarn("auth", "failed decoding basic auth header from base64") + return false + } + + username, password, err := parseBasicAuth(string(decoded)) + if err != nil { + LogWarn("auth", "failed parsing username password from basic auth") + return false + } + + if strings.EqualFold(username, CONFIG.Server.WireGateway.Username) && + strings.EqualFold(password, CONFIG.Server.WireGateway.Password) { + + return true + } + } + LogWarn("auth", "basic auth prefix did not match") return false } diff --git a/c2ec/api-wire-gateway.go b/c2ec/api-wire-gateway.go @@ -148,6 +148,12 @@ func wireGatewayConfig(res http.ResponseWriter, req *http.Request) { func transfer(res http.ResponseWriter, req *http.Request) { + auth := AuthenticateWirewatcher(req) + if !auth { + res.WriteHeader(HTTP_UNAUTHORIZED) + return + } + jsonCodec := NewJsonCodec[TransferRequest]() transfer, err := ReadStructFromBody(req, jsonCodec) if err != nil { @@ -262,7 +268,14 @@ func transfer(res http.ResponseWriter, req *http.Request) { // immediately or after waiting only a fraction of ``long_poll_ms``. func historyIncoming(res http.ResponseWriter, req *http.Request) { + auth := AuthenticateWirewatcher(req) + if !auth { + res.WriteHeader(HTTP_UNAUTHORIZED) + return + } + // read and validate request query parameters + timeOfReq := time.Now() shouldStartLongPoll := true var longPollMilli int if longPollMilliPtr, accepted := AcceptOptionalParamOrWriteResponse( @@ -305,7 +318,7 @@ func historyIncoming(res http.ResponseWriter, req *http.Request) { time.Sleep(time.Duration(longPollMilli) * time.Millisecond) } - withdrawals, err := DB.GetConfirmedWithdrawals(start, delta) + withdrawals, err := DB.GetConfirmedWithdrawals(start, delta, timeOfReq) if err != nil { LogError("wire-gateway-api", err) @@ -346,7 +359,14 @@ func historyIncoming(res http.ResponseWriter, req *http.Request) { func historyOutgoing(res http.ResponseWriter, req *http.Request) { + auth := AuthenticateWirewatcher(req) + if !auth { + res.WriteHeader(HTTP_UNAUTHORIZED) + return + } + // read and validate request query parameters + timeOfReq := time.Now() shouldStartLongPoll := true var longPollMilli int if longPollMilliPtr, accepted := AcceptOptionalParamOrWriteResponse( @@ -392,7 +412,7 @@ func historyOutgoing(res http.ResponseWriter, req *http.Request) { time.Sleep(time.Duration(longPollMilli) * time.Millisecond) } - transfers, err := DB.GetTransfers(start, delta) + transfers, err := DB.GetTransfers(start, delta, timeOfReq) if err != nil { LogError("wire-gateway-api", err) diff --git a/c2ec/db-postgres.go b/c2ec/db-postgres.go @@ -93,6 +93,7 @@ const PS_UPDATE_TRANSFER = "UPDATE " + TRANSFER_TABLE_NAME + " SET (" + const PS_CONFIRMED_TRANSACTIONS_ASC = "SELECT * FROM " + WITHDRAWAL_TABLE_NAME + " WHERE " + WITHDRAWAL_FIELD_NAME_STATUS + "='" + string(CONFIRMED) + "'" + + " AND " + WITHDRAWAL_FIELD_NAME_TS + ">=$3" + " ORDER BY " + WITHDRAWAL_FIELD_NAME_ID + " ASC" + " LIMIT $1" + " OFFSET $2" @@ -107,15 +108,17 @@ const PS_CONFIRMED_TRANSACTIONS_ASC_MAX = "SELECT * FROM " + WITHDRAWAL_TABLE_NA " WHERE " + WITHDRAWAL_FIELD_NAME_STATUS + "='" + string(CONFIRMED) + "'" + " ORDER BY " + WITHDRAWAL_FIELD_NAME_ID + " ASC" + " LIMIT $1" + - " OFFSET ((SELECT COUNT(*) FROM " + WITHDRAWAL_TABLE_NAME + - " WHERE " + WITHDRAWAL_FIELD_NAME_STATUS + "='" + string(CONFIRMED) + "')-1)" // TODO (-time since request) + " OFFSET (SELECT COUNT(*) FROM " + WITHDRAWAL_TABLE_NAME + + " WHERE " + WITHDRAWAL_FIELD_NAME_STATUS + "='" + string(CONFIRMED) + "'" + + " AND " + WITHDRAWAL_FIELD_NAME_TS + "<$2)" const PS_CONFIRMED_TRANSACTIONS_DESC_MAX = "SELECT * FROM " + WITHDRAWAL_TABLE_NAME + " WHERE " + WITHDRAWAL_FIELD_NAME_STATUS + "='" + string(CONFIRMED) + "'" + " ORDER BY " + WITHDRAWAL_FIELD_NAME_ID + " DESC" + " LIMIT $1" + - " OFFSET ((SELECT COUNT(*) FROM " + WITHDRAWAL_TABLE_NAME + - " WHERE " + WITHDRAWAL_FIELD_NAME_STATUS + "='" + string(CONFIRMED) + "')-1)" // TODO (-time since request) + " OFFSET (SELECT COUNT(*) FROM " + WITHDRAWAL_TABLE_NAME + + " WHERE " + WITHDRAWAL_FIELD_NAME_STATUS + "='" + string(CONFIRMED) + "'" + + " AND " + WITHDRAWAL_FIELD_NAME_TS + "<$2)" const PS_GET_TRANSFERS_ASC = "SELECT * FROM " + TRANSFER_TABLE_NAME + " ORDER BY " + TRANSFER_FIELD_NAME_ROW_ID + " ASC" + @@ -130,14 +133,16 @@ const PS_GET_TRANSFERS_DESC = "SELECT * FROM " + TRANSFER_TABLE_NAME + const PS_GET_TRANSFERS_ASC_MAX = "SELECT * FROM " + TRANSFER_TABLE_NAME + " ORDER BY " + TRANSFER_FIELD_NAME_ROW_ID + " ASC" + " LIMIT $1" + - " OFFSET ((SELECT COUNT(*) FROM " + TRANSFER_TABLE_NAME + - " WHERE " + TRANSFER_FIELD_NAME_STATUS + "=0)-1)" // TODO Timestamp based offset (-time since request) + " OFFSET (SELECT COUNT(*) FROM " + TRANSFER_TABLE_NAME + + " WHERE " + TRANSFER_FIELD_NAME_STATUS + "=0" + + " AND " + TRANSFER_FIELD_NAME_TS + ">=$2)" const PS_GET_TRANSFERS_DESC_MAX = "SELECT * FROM " + TRANSFER_TABLE_NAME + " ORDER BY " + TRANSFER_FIELD_NAME_ROW_ID + " DESC" + " LIMIT $1" + - " OFFSET ((SELECT COUNT(*) FROM " + TRANSFER_TABLE_NAME + - " WHERE " + TRANSFER_FIELD_NAME_STATUS + "=0)-1)" // TODO Timestamp based offset (-time since request) + " OFFSET (SELECT COUNT(*) FROM " + TRANSFER_TABLE_NAME + + " WHERE " + TRANSFER_FIELD_NAME_STATUS + "=0" + + " AND " + TRANSFER_FIELD_NAME_TS + ">=$2)" const PS_GET_TRANSFERS_BY_STATUS = "SELECT * FROM " + TRANSFER_TABLE_NAME + " WHERE " + TRANSFER_FIELD_NAME_STATUS + "=$1" @@ -492,7 +497,7 @@ func (db *C2ECPostgres) SetRetryCounter(withdrawalId int, retryCounter int) erro // The query at the postgres database works as specified by the // wire gateway api. -func (db *C2ECPostgres) GetConfirmedWithdrawals(start int, delta int) ([]*Withdrawal, error) { +func (db *C2ECPostgres) GetConfirmedWithdrawals(start int, delta int, since time.Time) ([]*Withdrawal, error) { query := PS_CONFIRMED_TRANSACTIONS_ASC if delta < 0 { @@ -518,13 +523,14 @@ func (db *C2ECPostgres) GetConfirmedWithdrawals(start int, delta int) ([]*Withdr var row pgx.Rows var err error if start < 0 { - // use MAX(id) instead of a concrete id, because start + // use latest id instead of a concrete id, because start // identifier was negative. Inidicates to read the most // recent ids. row, err = db.pool.Query( db.ctx, query, limit, + since.Unix(), ) } else { row, err = db.pool.Query( @@ -746,7 +752,7 @@ func (db *C2ECPostgres) UpdateTransfer( return nil } -func (db *C2ECPostgres) GetTransfers(start int, delta int) ([]*Transfer, error) { +func (db *C2ECPostgres) GetTransfers(start int, delta int, since time.Time) ([]*Transfer, error) { query := PS_GET_TRANSFERS_ASC if delta < 0 { @@ -779,6 +785,7 @@ func (db *C2ECPostgres) GetTransfers(start int, delta int) ([]*Transfer, error) db.ctx, query, limit, + since.Unix(), ) } else { row, err = db.pool.Query( diff --git a/c2ec/db.go b/c2ec/db.go @@ -2,6 +2,7 @@ package main import ( "context" + "time" ) const PROVIDER_TABLE_NAME = "c2ec.provider" @@ -178,7 +179,7 @@ type C2ECDatabase interface { // if the delta is negative, previous transactions relative to the // starting point are considered. When start is negative, the latest // id shall be used as starting point. - GetConfirmedWithdrawals(start int, delta int) ([]*Withdrawal, error) + GetConfirmedWithdrawals(start int, delta int, since time.Time) ([]*Withdrawal, error) // Get the provider of a terminal by the terminals id GetProviderByTerminal(terminalId int) (*Provider, error) @@ -218,7 +219,7 @@ type C2ECDatabase interface { // if the delta is negative, previous transactions relative to the // starting point are considered. When start is negative, the latest // id shall be used as starting point. - GetTransfers(start int, delta int) ([]*Transfer, error) + GetTransfers(start int, delta int, since time.Time) ([]*Transfer, error) // Returns the transfer entries in the given state. // This can be used for retry operations. diff --git a/c2ec/db/migrate.sh b/c2ec/db/migrate.sh @@ -13,7 +13,7 @@ ACCESS_WITH_PASSWORDS="./access-with-passwords.sql" INITIAL_SETUP=0 if [ "$#" -eq 6 ]; then if [[ ($4 = $5) || ($5 = $6) || ($4 = $6) ]]; then - echo "PROBLEM: passwords for db admin, operator and must be different..." + echo "PROBLEM: passwords for db admin, operator and api user must be different..." echo "Usage: $0 <db-username> <db-password> <db-name> <source-root> <new-db-admin-pw> <new-db-admin-pw> <new-db-admin-pw>" exit 1 fi @@ -33,7 +33,7 @@ fi SQL_SCRIPTS=( "./versioning.sql" - "./0001-c2ec_schema.sql" + "./0001-c2ec_schema.sql" "./proc-c2ec_status_listener.sql" "./proc-c2ec_payment_notification_listener.sql" "./proc-c2ec_retry_listener.sql" diff --git a/c2ec/db/test_wire_gateway.sql b/c2ec/db/test_wire_gateway.sql @@ -0,0 +1,24 @@ +INSERT INTO c2ec.withdrawal VALUES (100001, 'a1d76a78-4016-45b6-9d3e-086bf9f097d7', '\xd413de0f93e27a49d2b413d5890b5b6a3a02772641d864d997fe069705a2ce6a', NULL, 1716042715, '(10,0,CHF)', '(0,0,"")', '(0,0,"")', 'pending', 3, '', NULL, 0, NULL); +INSERT INTO c2ec.withdrawal VALUES (100002,'018f8bc5-8e14-7878-9ef9-7da00377ad96', '\x46b500e8f32ee819c338c921fb201d44819422238cb9d361c4dbf4841e528d91', '\xb3e8e8b43dda33b555a1897a97f478068d15c641d7b9826894daba1aa3fd11fd', 1716036939, '(10,50,CHF)', '(10,50,CHF)', '(0,10,CHF)', 'confirmed', 1, 'simulation-transaction-id-0', NULL, 1, '\x7468697320697320612073696d756c61746564207472616e73616374696f6e20616e64207468657265666f726520686173206e6f20636f6e74656e742e'); +INSERT INTO c2ec.withdrawal VALUES (100003,'018f8b1d-9326-7e2a-98b0-6f75dfda9661', '\xf09969a5bb2381f23d4e6034f45573a412deae063a81f0a94059b4a15afd7696', '\x1c05b275f727d91061dd5e6f09b45abe77e1d0481694475836c7defc9f4445c8', 1716025922, '(10,50,CHF)', '(10,50,CHF)', '(0,10,CHF)', 'confirmed', 1, 'simulation-transaction-id-0', NULL, 0, '\x7468697320697320612073696d756c61746564207472616e73616374696f6e20616e64207468657265666f726520686173206e6f20636f6e74656e742e'); +INSERT INTO c2ec.withdrawal VALUES (100004,'018f8c07-9be7-710c-834b-4c07b17e8205', '\x451c6e8c5734a4d727d8d67f94525dd10db11a56ab64c3451ae4a0d13e001317', '\x3aa911d843fe7f3982c71baf5dd16a428890606a9bc0b86c1bd431bf45866130', 1716041260, '(10,50,CHF)', '(10,50,CHF)', '(0,10,CHF)', 'confirmed', 1, 'simulation-transaction-id-0', NULL, 1, '\x7468697320697320612073696d756c61746564207472616e73616374696f6e20616e64207468657265666f726520686173206e6f20636f6e74656e742e'); +INSERT INTO c2ec.withdrawal VALUES (100005,'018f8b1a-c66b-776f-946f-53024247d4e2', '\xe0df21aa810b21f006cf91463dcd54ce37e75dd76b4b3d93ab3a0dc2e822c89f', '\xc1965e78839a6bad88e5753ae89cb58b5d9f157dfa9ee11373000b73d8d4254d', 1716025748, '(10,50,CHF)', '(10,50,CHF)', '(0,0,"")', 'confirmed', 1, '', NULL, 1, '\x7468697320697320612073696d756c61746564207472616e73616374696f6e20616e64207468657265666f726520686173206e6f20636f6e74656e742e'); +INSERT INTO c2ec.withdrawal VALUES (100006, '94abb96d-d376-4707-8dd8-b7050834ba3f', '\x60c49c5cb362d4b6c8899bb52d1c3523a4b8872e65c0822960f3a093a3a8b8d2', '\x60c49c5cb362d4b6c8899bb52d1c3523a4b8872e65c0822960f3a093a3a8b8d2', 1716042376, '(12,0,"")', '(0,0,"")', '(0,0,"")', 'aborted', 3, '', NULL, 4, '\x'); +INSERT INTO c2ec.withdrawal VALUES (100007,'018f8c05-aad0-7e44-a358-7bfe213d40e6', '\xf8a3af5391e0973c02d8247358f2c3aca2940a096bc8b78f19847b3168e732d7', '\xef11d586953be9e94fde479e52722b876ef3bfe668aacc0a4b6abfd62668154c', 1716041140, '(10,50,CHF)', '(10,50,CHF)', '(0,10,CHF)', 'confirmed', 1, 'simulation-transaction-id-0', NULL, 1, '\x7468697320697320612073696d756c61746564207472616e73616374696f6e20616e64207468657265666f726520686173206e6f20636f6e74656e742e'); +INSERT INTO c2ec.withdrawal VALUES (100008,'018f8bb6-9175-72ed-a2f3-a82650809445', '\xc2cf4f8de6000cbb5278bbb59ad0a132134b5a29034d81629358386e48f448f0', '\xa611ec9ccb2073297346bced1424111022b14f503e9b0167dfe4ae7b8c35e454', 1716035957, '(10,50,CHF)', '(10,50,CHF)', '(0,10,CHF)', 'confirmed', 1, 'simulation-transaction-id-0', NULL, 1, '\x7468697320697320612073696d756c61746564207472616e73616374696f6e20616e64207468657265666f726520686173206e6f20636f6e74656e742e'); +INSERT INTO c2ec.withdrawal VALUES (100009, '0a52deb8-c2df-4b63-bd06-690e03c9e13d', '\xa302f36f1ad104bb3b4312a7edc91c2df5faf23835bf3addb28fe3072fc79135', '\xa302f36f1ad104bb3b4312a7edc91c2df5faf23835bf3addb28fe3072fc79135', 1716042533, '(10,0,CHF)', '(0,0,"")', '(0,0,"")', 'confirmed', 3, '8XP6K51NGPHXD80JJEF660HT277Q2WCW248SS2SR30V2DSTH8V8G', NULL, 10, '\x7b2250726f76696465725472616e73616374696f6e223a6e756c6c2c22616363657074486561646572223a6e756c6c2c226163636570744c616e6775616765486561646572223a6e756c6c2c22616c6c6f7765645061796d656e744d6574686f644272616e6473223a5b5d2c22616c6c6f7765645061796d656e744d6574686f64436f6e66696775726174696f6e73223a5b5d2c22617574686f72697a6174696f6e416d6f756e74223a31302c22617574686f72697a6174696f6e456e7669726f6e6d656e74223a2254455354222c22617574686f72697a6174696f6e53616c65734368616e6e656c223a313538323831393135313333302c22617574686f72697a6174696f6e54696d656f75744f6e223a22323032342d30352d31395431343a32393a30322e3732395a222c22617574686f72697a65644f6e223a22323032342d30352d31385431343a32393a30332e3038335a222c226175746f436f6e6669726d6174696f6e456e61626c6564223a66616c73652c2262696c6c696e6741646472657373223a6e756c6c2c226368617267655265747279456e61626c6564223a747275652c22636f6d706c65746564416d6f756e74223a31302c22636f6d706c657465644f6e223a22323032342d30352d31385431343a33333a33362e3439315a222c22636f6d706c6574696f6e4265686176696f72223a225553455f434f4e46494755524154494f4e222c22636f6d706c6574696f6e54696d656f75744f6e223a6e756c6c2c22636f6e6669726d65644279223a302c22636f6e6669726d65644f6e223a22323032342d30352d31385431343a32393a30322e3535345a222c22637265617465644279223a302c22637265617465644f6e223a22323032342d30352d31385431343a32393a30322e31355a222c2263757272656e6379223a22434846222c22637573746f6d6572456d61696c41646472657373223a6e756c6c2c22637573746f6d65724964223a6e756c6c2c22637573746f6d65727350726573656e6365223a22504859534943414c5f50524553454e54222c2264656c69766572794465636973696f6e4d6164654f6e223a22323032342d30352d31385431343a33333a33362e3735345a222c2264657669636553657373696f6e4964656e746966696572223a6e756c6c2c22656d61696c7344697361626c6564223a66616c73652c22656e644f664c696665223a22323032342d30382d32365431343a32393a30332e3038335a222c22656e7669726f6e6d656e74223a224c495645222c22656e7669726f6e6d656e7453656c656374696f6e5374726174656779223a225553455f434f4e46494755524154494f4e222c226661696c65644f6e223a6e756c6c2c226661696c656455726c223a6e756c6c2c226661696c757265526561736f6e223a6e756c6c2c2267726f7570223a7b22626567696e44617465223a22323032342d30352d31385431343a32393a30322e3136355a222c22637573746f6d65724964223a6e756c6c2c22656e6444617465223a22323032342d30352d31385431343a32393a30322e3136355a222c226964223a3231343839343334302c226c696e6b656453706163654964223a35343239352c22706c616e6e6564507572676544617465223a22323032342d30352d31385431343a33343a30322e3136355a222c227374617465223a225355434345535346554c222c2276657273696f6e223a327d2c226964223a3231343838313335352c22696e7465726e657450726f746f636f6c41646472657373223a6e756c6c2c22696e7465726e657450726f746f636f6c41646472657373436f756e747279223a6e756c6c2c22696e766f6963654d65726368616e745265666572656e6365223a223338222c226a617661456e61626c6564223a6e756c6c2c226c616e6775616765223a22656e2d4742222c226c696e654974656d73223a5b7b226167677265676174656454617852617465223a302c22616d6f756e744578636c7564696e67546178223a31302c22616d6f756e74496e636c7564696e67546178223a31302c2261747472696275746573223a7b7d2c22646973636f756e744578636c7564696e67546178223a302c22646973636f756e74496e636c7564696e67546178223a302c226e616d65223a225061796d656e74222c227175616e74697479223a312c227368697070696e675265717569726564223a66616c73652c22736b75223a227061796d656e74222c22746178416d6f756e74223a302c22746178416d6f756e74506572556e6974223a302c227461786573223a5b5d2c2274797065223a2250524f44554354222c22756e646973636f756e746564416d6f756e744578636c7564696e67546178223a31302c22756e646973636f756e746564416d6f756e74496e636c7564696e67546178223a31302c22756e646973636f756e746564556e697450726963654578636c7564696e67546178223a31302c22756e646973636f756e746564556e69745072696365496e636c7564696e67546178223a31302c22756e697175654964223a227061796d656e74222c22756e697450726963654578636c7564696e67546178223a31302c22756e69745072696365496e636c7564696e67546178223a31307d5d2c226c696e6b656453706163654964223a35343239352c226d65726368616e745265666572656e6365223a22385850364b35314e475048584438304a4a4546363630485432373751325743573234385353325352333056324453544838563847222c226d65746144617461223a7b7d2c22706172656e74223a6e756c6c2c227061796d656e74436f6e6e6563746f72436f6e66696775726174696f6e223a7b226170706c696361626c65466f725472616e73616374696f6e50726f63657373696e67223a747275652c22636f6e646974696f6e73223a5b5d2c22636f6e6e6563746f72223a313535323635343135393236342c22656e61626c656453616c65734368616e6e656c73223a5b7b226465736372697074696f6e223a7b2264652d4445223a225a61686c756e67656e20616e207068797369736368656e205465726d696e616c7320616b7a657074696572656e2e222c22656e2d5553223a22436f6c6c656374207061796d656e7473206f6e20706879736963616c207465726d696e616c732e222c2266722d4652223a22416363657074657a206c657320706169656d656e747320c3a020646573207465726d696e617578207068797369717565732e222c2269742d4954223a2241636365747461726520706167616d656e7469207375207465726d696e616c69206669736963692e227d2c2269636f6e223a22636172642d7465726d696e616c222c226964223a313538323831393135313333302c226e616d65223a7b2264652d4445223a2250687973697363686573205465726d696e616c222c22656e2d5553223a22506879736963616c205465726d696e616c222c2266722d4652223a225465726d696e616c207068797369717565222c2269742d4954223a225465726d696e616c652066697369636f227d2c22736f72744f72646572223a34307d5d2c22656e61626c656453706163655669657773223a5b5d2c226964223a3332363039322c22696d61676550617468223a2268747470733a2f2f6170702d77616c6c65652e636f6d2f732f35343239352f7265736f757263652f7765622f696d6167652f7061796d656e742f636172642d6272616e642f6d6173746572636172642e737667222c226c696e6b656453706163654964223a35343239352c226e616d65223a22436f6e63617264697320416371756972696e67202d204d617374657263617264222c227061796d656e744d6574686f64436f6e66696775726174696f6e223a7b2264617461436f6c6c656374696f6e54797065223a224f4e53495445222c226465736372697074696f6e223a7b7d2c226964223a3233363732342c22696d6167655265736f7572636550617468223a6e756c6c2c226c696e6b656453706163654964223a35343239352c226e616d65223a224b72656469742d2f44656269746b61727465222c226f6e65436c69636b5061796d656e744d6f6465223a2244495341424c4544222c227061796d656e744d6574686f64223a313435373534363039373539372c22706c616e6e6564507572676544617465223a6e756c6c2c227265736f6c7665644465736372697074696f6e223a7b2264652d4445223a2242657a61686c656e205369652062657175656d20706572204b72656469742d206f6465722044656269746b617274652e222c22656e2d5553223a2250617920636f6e76656e69656e746c79207769746820796f757220637265646974206f7220646562697420636172642e222c2266722d4652223a22506179657a207472616e7175696c6c656d656e74206176656320756e65206361727465206465206372c3a9646974206f752064652064c3a96269742e222c2269742d4954223a225061676120636f6d6f64616d656e746520636f6e206361727461206469206372656469746f206f2064692064656269746f2e227d2c227265736f6c766564496d61676555726c223a2268747470733a2f2f6170702d77616c6c65652e636f6d2f656e2d55532f732f35343239352f7265736f757263652f7765622f696d6167652f7061796d656e742f6d6574686f642f6372656469742d64656269742d636172642e7376673f73747261746567793d736e617073686f745c7530303236736e617073686f743d323335303336222c227265736f6c7665645469746c65223a7b2264652d4445223a224b72656469742d2f44656269746b61727465222c22656e2d5553223a22437265646974202f2044656269742043617264222c2266722d4652223a224361727465206465206372c3a96469742f64c3a9626974222c2269742d4954223a224361727461206469206372656469746f2f64656269746f227d2c22736f72744f72646572223a312c2273706163654964223a35343239352c227374617465223a22414354495645222c227469746c65223a7b7d2c2276657273696f6e223a317d2c22706c616e6e6564507572676544617465223a6e756c6c2c227072696f72697479223a302c2270726f636573736f72436f6e66696775726174696f6e223a7b226170706c69636174696f6e4d616e61676564223a66616c73652c22636f6e74726163744964223a6e756c6c2c226964223a3237363333312c226c696e6b656453706163654964223a35343239352c226e616d65223a22436f6e63617264697320416371756972696e67222c22706c616e6e6564507572676544617465223a6e756c6c2c2270726f636573736f72223a313535323635333433303636362c227374617465223a22414354495645222c2276657273696f6e223a317d2c227374617465223a22414354495645222c2276657273696f6e223a327d2c22706c616e6e6564507572676544617465223a22323032342d30382d32365431343a32393a30332e3038335a222c2270726f63657373696e674f6e223a22323032342d30352d31385431343a32393a30322e3539325a222c22726566756e646564416d6f756e74223a302c2273637265656e436f6c6f724465707468223a6e756c6c2c2273637265656e486569676874223a6e756c6c2c2273637265656e5769647468223a6e756c6c2c227368697070696e6741646472657373223a6e756c6c2c227368697070696e674d6574686f64223a6e756c6c2c227370616365566965774964223a6e756c6c2c227374617465223a2246554c46494c4c222c227375636365737355726c223a6e756c6c2c227465726d696e616c223a7b22636f6e66696775726174696f6e56657273696f6e223a7b22636f6e66696775726174696f6e223a7b226964223a3132323736322c226c696e6b656453706163654964223a35343239352c226e616d65223a22446562756720436f6e66696775726174696f6e222c22706c616e6e6564507572676544617465223a6e756c6c2c227374617465223a22414354495645222c2274797065223a7b226465736372697074696f6e223a7b2264652d4445223a2244617320706879736973636865205465726d696e616c2065726c617562742064696520566572617262656974756e6720766f6e205a61686c756e67656e2061756620486172647761726520476572c3a474656e2e222c22656e2d5553223a2254686520706879736963616c207465726d696e616c20616c6c6f777320796f7520746f2070726f63657373207465726d696e616c207061796d656e7473206f6e2061206861726477617265206465766963652e222c2266722d4652223a224c65207465726d696e616c20706879736971756520766f7573207065726d65742064652074726169746572206c657320706169656d656e747320706172207465726d696e616c2073757220756e20646973706f7369746966206d6174c3a97269656c2e222c2269742d4954223a22496c207465726d696e616c652066697369636f207065726d6574746520646920656c61626f72617265206920706167616d656e746920616c207465726d696e616c6520737520756e20646973706f73697469766f2068617264776172652e227d2c226964223a313536383337393539393831392c226e616d65223a7b2264652d4445223a2250687973697363686573205465726d696e616c222c22656e2d5553223a22506879736963616c205465726d696e616c222c2266722d4652223a225465726d696e616c207068797369717565222c2269742d4954223a225465726d696e616c652066697369636f227d7d2c2276657273696f6e223a317d2c22636f6e6e6563746f72436f6e66696775726174696f6e73223a5b3332363039312c3332363039302c3332363038382c3332363038372c3332363039322c3332363038395d2c22637265617465644279223a38393539312c22637265617465644f6e223a22323032342d30342d31345431353a32393a33302e3930385a222c2264656661756c7443757272656e6379223a6e756c6c2c226964223a3136323435352c226c696e6b656453706163654964223a35343239352c226d61696e74656e616e636557696e646f774475726174696f6e223a2250543248222c226d61696e74656e616e636557696e646f775374617274223a2230313a3030222c22706c616e6e6564507572676544617465223a6e756c6c2c227374617465223a22414354495645222c2274696d655a6f6e65223a224575726f70652f5a7572696368222c2276657273696f6e223a322c2276657273696f6e4170706c696564496d6d6564696174656c79223a747275657d2c2264656661756c7443757272656e6379223a22434846222c226465766963654e616d65223a6e756c6c2c2264657669636553657269616c4e756d626572223a2231373030343037343035222c2265787465726e616c4964223a2238366465616239392d646437312d343136372d393337632d343236333438623834336165222c226964223a3134353730332c226964656e746966696572223a223332353830313238222c226c696e6b656453706163654964223a35343239352c226c6f636174696f6e56657273696f6e223a7b2261646472657373223a7b2263697479223a224269656c222c22636f756e747279223a224348222c22646570656e64656e744c6f63616c697479223a22222c22656d61696c41646472657373223a22686162656a32406266682e6368222c2266616d696c794e616d65223a2248c3a46265726c69222c22676976656e4e616d65223a224a6f656c222c226d6f62696c6550686f6e654e756d626572223a222b3431373935363337373631222c226f7267616e697a6174696f6e4e616d65223a224265726e65722046616368686f6368736368756c65222c2270686f6e654e756d626572223a22222c22706f7374616c5374617465223a6e756c6c2c22706f7374636f6465223a2232353032222c22706f7374436f6465223a2232353032222c2273616c75746174696f6e223a2248657272222c22736f7274696e67436f6465223a22222c22737472656574223a225175656c6c6761737365203231227d2c22636f6e7461637441646472657373223a6e756c6c2c22637265617465644279223a38393539312c22637265617465644f6e223a22323032342d30312d31385431343a33363a35392e34335a222c226964223a3130353730302c226c696e6b656453706163654964223a35343239352c226c6f636174696f6e223a7b2265787465726e616c4964223a2239613764313361652d653331362d343632322d393839392d616632373930356365376638222c226964223a39383039322c226c696e6b656453706163654964223a35343239352c226e616d65223a224265726e65722046616368686f6368736368756c65202d204269656c222c22706c616e6e6564507572676544617465223a6e756c6c2c227374617465223a22414354495645222c2276657273696f6e223a317d2c22706c616e6e6564507572676544617465223a6e756c6c2c227374617465223a22414354495645222c2276657273696f6e223a322c2276657273696f6e4170706c696564496d6d6564696174656c79223a747275657d2c226e616d65223a2244656275675f546573745f7465726d696e616c222c22706c616e6e6564507572676544617465223a6e756c6c2c227374617465223a22414354495645222c2274797065223a7b226465736372697074696f6e223a7b2264652d4445223a2244617320706879736973636865205465726d696e616c2065726c617562742064696520566572617262656974756e6720766f6e205a61686c756e67656e2061756620486172647761726520476572c3a474656e2e222c22656e2d5553223a2254686520706879736963616c207465726d696e616c20616c6c6f777320796f7520746f2070726f63657373207465726d696e616c207061796d656e7473206f6e2061206861726477617265206465766963652e222c2266722d4652223a224c65207465726d696e616c20706879736971756520766f7573207065726d65742064652074726169746572206c657320706169656d656e747320706172207465726d696e616c2073757220756e20646973706f7369746966206d6174c3a97269656c2e222c2269742d4954223a22496c207465726d696e616c652066697369636f207065726d6574746520646920656c61626f72617265206920706167616d656e746920616c207465726d696e616c6520737520756e20646973706f73697469766f2068617264776172652e227d2c226964223a313536383337393539393831392c226e616d65223a7b2264652d4445223a2250687973697363686573205465726d696e616c222c22656e2d5553223a22506879736963616c205465726d696e616c222c2266722d4652223a225465726d696e616c207068797369717565222c2269742d4954223a225465726d696e616c652066697369636f227d7d2c2276657273696f6e223a337d2c2274696d655a6f6e65223a6e756c6c2c22746f6b656e223a6e756c6c2c22746f6b656e697a6174696f6e4d6f6465223a6e756c6c2c22746f74616c4170706c69656446656573223a302c22746f74616c536574746c6564416d6f756e74223a302c22757365724167656e74486561646572223a6e756c6c2c22757365724661696c7572654d657373616765223a6e756c6c2c2275736572496e7465726661636554797065223a225445524d494e414c222c2276657273696f6e223a31342c2277696e646f77486569676874223a6e756c6c2c2277696e646f775769647468223a6e756c6c2c227965617273546f4b656570223a327d'); +INSERT INTO c2ec.withdrawal VALUES (100010, '20e6d305-1537-4bf9-a3b2-65756c14dde1', '\xffd6d80e38262b984418d37179c868caee3d95be5c61c357348241e1a03c81bd', NULL, 1716042796, '(5,0,"")', '(0,0,"")', '(0,0,"")', 'aborted', 3, '', NULL, 0, '\x'); +INSERT INTO c2ec.withdrawal VALUES (100011, 'badeb997-ff50-442b-9bf0-ef447a6836e0', '\x9b53b8efe4eab7cef882413f13dc4da32c51d6fde3fada0e369fd9dd8dc40c16', '\x9b53b8efe4eab7cef882413f13dc4da32c51d6fde3fada0e369fd9dd8dc40c16', 1716041931, '(12,0,CHF)', '(0,0,"")', '(0,0,"")', 'aborted', 3, '', NULL, 9, '\x'); +INSERT INTO c2ec.withdrawal VALUES (100012,'018f8bba-3965-796a-b140-cef29a8f915c', '\x83b77f4d5afce708d0ce2926d0750940ce635202b58a671000bde1382d57ae7f', '\x55f6e286d1f83b9c4e107784c21e8cf1e65e3fcd293a0c89459e4185d356b89d', 1716036196, '(10,50,CHF)', '(10,50,CHF)', '(0,10,CHF)', 'confirmed', 1, 'simulation-transaction-id-0', NULL, 1, '\x7468697320697320612073696d756c61746564207472616e73616374696f6e20616e64207468657265666f726520686173206e6f20636f6e74656e742e'); +INSERT INTO c2ec.withdrawal VALUES (100013,'018f8c07-186d-7dc8-834b-ef4c7730d837', '\x5ab4bb269286c6f5d5c0916d051864b4e757389d255e611d2ad8f7e7538dc328', '\xb1339c2d84c9b7f80761d6f099b5c0a9ca747e392234f646bfe48b176bd57cc6', 1716041234, '(10,50,CHF)', '(10,50,CHF)', '(0,10,CHF)', 'confirmed', 1, 'simulation-transaction-id-0', NULL, 1, '\x7468697320697320612073696d756c61746564207472616e73616374696f6e20616e64207468657265666f726520686173206e6f20636f6e74656e742e'); +INSERT INTO c2ec.withdrawal VALUES (100014, '018f954d-b88b-7068-9f29-263bdbaacbc5', '\x45918f0c2b8953b2e65dd817f5f0876ea1d88cb56534312f4b576e021d601246', '\x120ab8f2a0b49f78a161b971ea0b453b4505c9ddbe099ab5462f79ce0fafb6ea', 1716196849, '(10,50,CHF)', '(10,50,CHF)', '(10,0,CHF)', 'confirmed', 1, 'simulation-transaction-id-0', NULL, 1, '\x7468697320697320612073696d756c61746564207472616e73616374696f6e20616e64207468657265666f726520686173206e6f20636f6e74656e742e'); +INSERT INTO c2ec.withdrawal VALUES (100015, '8e6cf8f2-c5f8-41c1-aa52-9f899ca625cf', '\x220bdeb5a0702bddddc88c0b4e6596122a4cbdcb6c106bbf3ccc6fbcdb571863', '\x220bdeb5a0702bddddc88c0b4e6596122a4cbdcb6c106bbf3ccc6fbcdb571863', 1716042584, '(24,0,CHF)', '(0,0,"")', '(0,0,"")', 'aborted', 3, 'RM1H8QM1THDPPRPW5NZFKEK7A4S5XMQ33QVJSZSDDT9XJA797Y5G', NULL, 12, '\x'); +INSERT INTO c2ec.withdrawal VALUES (100016, '538385ab-fb96-4dd4-b90e-4d3b47268cbc', '\xec92fd1b634f779a22fb06dc3414361727f37102ea83dc56ec6a3e6b57ba8dc5', '\xec92fd1b634f779a22fb06dc3414361727f37102ea83dc56ec6a3e6b57ba8dc5', 1716041981, '(12,5,CHF)', '(0,0,"")', '(0,0,"")', 'aborted', 3, '', NULL, 9, '\x'); +INSERT INTO c2ec.withdrawal VALUES (100017, '21541d26-ca93-489f-9c22-b2a6b7181667', '\xc1c3fc11a4cee3cfc1529067c951bab68499929bb53b315275b9e4a91b251802', NULL, 1716042823, '(5,0,CHF)', '(0,0,"")', '(0,0,"")', 'pending', 3, '', NULL, 0, NULL); +INSERT INTO c2ec.withdrawal VALUES (100018, '5e259dc2-5333-4333-a7b5-64e050e13de4', '\xf794293aeac109950836d2b3bf0da89324969b27cc7fa5b4e96ae21956683fff', '\xf794293aeac109950836d2b3bf0da89324969b27cc7fa5b4e96ae21956683fff', 1716041892, '(12,0,"")', '(0,0,"")', '(0,0,"")', 'aborted', 3, '', NULL, 8, '\x'); +INSERT INTO c2ec.withdrawal VALUES (100019, '03b94285-e5cb-4d6c-acbf-3e0748d9a0d8', '\x62f0adc7917a12d1969258cdc147bdc19ef08aab14ccab1513d67b39967bb6b1', NULL, 1716043380, '(12,0,"")', '(0,0,"")', '(0,0,"")', 'pending', 3, '', NULL, 0, NULL); +INSERT INTO c2ec.withdrawal VALUES (100020, '13db398c-9579-4bd2-80f1-8d3bd16cb52c', '\x52fcad31aa15b53d9170b27abb2a3bdfb2bc41f49bed2975a4bf118611934ce5', '\x52fcad31aa15b53d9170b27abb2a3bdfb2bc41f49bed2975a4bf118611934ce5', 1716042271, '(45,0,CHF)', '(0,0,"")', '(0,0,"")', 'aborted', 3, '', NULL, 10, '\x'); +INSERT INTO c2ec.withdrawal VALUES (100021, '73937481-046a-49dc-a54a-3a9abcc4736e', '\x9aa3426610f5b7f9933310071d36384ef3ada5a242e375f09664a30ced6c3d1c', NULL, 1716042639, '(10,0,CHF)', '(0,0,"")', '(0,0,"")', 'pending', 3, '', NULL, 0, NULL); +INSERT INTO c2ec.withdrawal VALUES (100022, '79dc8716-ba60-4eb3-abbf-bd7c7532f912', '\x2ff757c90cf8e48998e4007db1828277923838307de70e6f8ff241e1ce83a276', '\x2ff757c90cf8e48998e4007db1828277923838307de70e6f8ff241e1ce83a276', 1716197262, '(14,0,CHF)', '(0,0,"")', '(0,0,"")', 'aborted', 3, '', NULL, 7, '\x'); +INSERT INTO c2ec.withdrawal VALUES (100023, 'f80ba99a-a0b1-45a8-8c38-0f4111ac1b65', '\xa581f2f2c15e43cc9da00fc11e4a5ae982e6dfac08aded8e5a7c443f905bc658', '\xa581f2f2c15e43cc9da00fc11e4a5ae982e6dfac08aded8e5a7c443f905bc658', 1716197224, '(13,0,CHF)', '(0,0,"")', '(0,0,"")', 'aborted', 3, '', NULL, 7, '\x'); +INSERT INTO c2ec.withdrawal VALUES (100024, '86f820d9-9f0f-4aa9-8d54-17bdcbd00430', '\x03ab595c6bb2fb59bde0ae255bbf9c780740cd051645d843d992784eac665c80', NULL, 1716197350, '(5,0,CHF)', '(0,0,"")', '(0,0,"")', 'pending', 3, '', NULL, 0, NULL); diff --git a/c2ec/db/test_wire_gateway_cleanup.sql b/c2ec/db/test_wire_gateway_cleanup.sql @@ -0,0 +1,26 @@ +DELETE FROM c2ec.withdrawal WHERE withdrawal_row_id IN ( +100001, +100002, +100003, +100004, +100005, +100006, +100007, +100008, +100009, +100010, +100011, +100012, +100013, +100014, +100015, +100016, +100017, +100018, +100019, +100020, +100021, +100022, +100023, +100024 +); +\ No newline at end of file diff --git a/c2ec/taler-wire-gateway-test.sh b/c2ec/taler-wire-gateway-test.sh @@ -14,18 +14,13 @@ taler-exchange-wire-gateway-client -i -b https://bank.example.com taler-exchange-wire-gateway-client -i -b http://taler-c2ec.ti.bfh.ch/taler-wire-gateway/ - - ### TRANSFER taler-exchange-wire-gateway-client taler-exchange-wire-gateway-client -C payto://example/bank/account -a EUR:10.00 -b https://bank.example.com taler-exchange-wire-gateway-client -D payto://example/bank/account -a EUR:10.00 -b https://bank.example.com - ### OUTGOING HISTORY taler-exchange-wire-gateway-client taler-exchange-wire-gateway-client -o -b https://bank.example.com - - -### cleanup test data -\ No newline at end of file +### cleanup test data diff --git a/cli/cli.go b/cli/cli.go @@ -25,6 +25,7 @@ const ACTION_REGISTER_TERMINAL = "rt" const ACTION_DEACTIVATE_TERMINAL = "dt" const ACTION_ACTIVATE_TERMINAL = "at" const ACTION_WITHDRAWAL_INFOMRATION = "w" +const ACTION_WITHDRAWAL_INFOMRATION_BY_PTID = "wp" const ACTION_CONNECT_DB = "db" const ACTION_QUIT = "q" @@ -238,7 +239,7 @@ func activateTerminal() error { return nil } -func withdrawalInformation() error { +func withdrawalInformationByWopid() error { if DB == nil { return errors.New("connect to the database first (cmd: db)") @@ -258,6 +259,30 @@ func withdrawalInformation() error { return err } + return readPrintWithdrawal(rows) +} + +func withdrawalInformationByProviderTransactionId() error { + + if DB == nil { + return errors.New("connect to the database first (cmd: db)") + } + + ptid := read("Provider Transaction ID: ") + rows, err := DB.Query( + context.Background(), + GET_WITHDRAWAL_BY_PROVIDER_TRANSACTION_ID, + ptid, + ) + if err != nil { + return err + } + + return readPrintWithdrawal(rows) +} + +func readPrintWithdrawal(rows pgx.Rows) error { + type TalerAmountCurrency struct { Val int64 `db:"val"` Frac int32 `db:"frac"` @@ -428,7 +453,8 @@ func showHelp() error { fmt.Println("deactivate wallee terminal (", ACTION_DEACTIVATE_TERMINAL, ")") fmt.Println("activate wallee terminal (", ACTION_ACTIVATE_TERMINAL, ")") fmt.Println("setup simulation (", ACTION_SETUP_SIMULATION, ")") - fmt.Println("withdrawal information (", ACTION_WITHDRAWAL_INFOMRATION, ")") + fmt.Println("withdrawal information by wopid (", ACTION_WITHDRAWAL_INFOMRATION, ")") + fmt.Println("witdhrawal information by provider transaction id", ACTION_WITHDRAWAL_INFOMRATION_BY_PTID, ")") fmt.Println("connect database (", ACTION_CONNECT_DB, ")") fmt.Println("show help (", ACTION_HELP, ")") fmt.Println("quit (", ACTION_QUIT, ")") @@ -497,7 +523,9 @@ func dispatchCommand(cmd string) error { case ACTION_ACTIVATE_TERMINAL: err = activateTerminal() case ACTION_WITHDRAWAL_INFOMRATION: - err = withdrawalInformation() + err = withdrawalInformationByWopid() + case ACTION_WITHDRAWAL_INFOMRATION_BY_PTID: + err = withdrawalInformationByProviderTransactionId() case ACTION_SETUP_SIMULATION: err = setupSimulation() default: diff --git a/cli/db.go b/cli/db.go @@ -7,6 +7,7 @@ const ACTIVATE_TERMINAL = "UPDATE c2ec.terminal SET active = true WHERE terminal const GET_PROVIDER_BY_NAME = "SELECT * FROM c2ec.provider WHERE name=$1" const GET_LAST_INSERTED_TERMINAL = "SELECT * FROM c2ec.terminal WHERE terminal_id = (SELECT MAX(terminal_id) FROM c2ec.terminal)" const GET_WITHDRAWAL_BY_WOPID = "SELECT * FROM c2ec.withdrawal WHERE wopid=$1" +const GET_WITHDRAWAL_BY_PROVIDER_TRANSACTION_ID = "SELECT * FROM c2ec.withdrawal WHERE provider_transaction_id=$1" type Provider struct { ProviderId int64 `db:"provider_id"` diff --git a/docs/content/implementation/a-bank-integration-api.tex b/docs/content/implementation/a-bank-integration-api.tex @@ -33,5 +33,6 @@ The \textit{/withdrawal-operation/[WOPID]} endpoint returns the status of withdr This endpoint is used by the Wallet to register the reserve public key generated by the Wallet, which will eventually hold the digital cash at the Exchange. This reserve public key is unique and the API will return a conflict response if a withdrawal with the reserve public key specified in the request already exists. This is also the case if a mapping for the given \textit{WOPID} was already created. \textbf{Aborting a withdrawal (/withdrawal-operation/[WOPID]/abort)} +\label{sec-implementation-bank-integration-api-abort} This endpoint simply allows the abortion of the withdrawal. This will change the status of the withdrawal to the \textit{aborted} state. diff --git a/docs/content/implementation/a-c2ec.tex b/docs/content/implementation/a-c2ec.tex @@ -56,6 +56,12 @@ Following a short list of events and from whom they are triggered and who listen \end{itemize} \end{itemize} +\subsection{Abortion Handling} + +A withdrawal might be aborted through the terminal or the wallet. These cases are implemented through the respective \textit{abort} endpoint in the bank-integration API \autoref{sec-implementation-bank-integration-api-abort} and terminals API \autoref{sec-implementation-terminal-api-abort}. If in doubt whether to abort the withdrawal or not, it should be aborted. In case of abortion and failure cases, the security of the money is weighted higher than the user-experience. If the user must restart the withdrawal in case of a failure in the process, it is less severe than opening possible security holes by somehow processing the withdrawal anyway. On the other hand the system must be as stable as possible to make this error cases very rare. If they occur too often, the customer might not use the technology and therefore would make it worthless. + +The withdrawal can only be aborted, when it is not yet confirmed by the attestation process (described in \autoref{sec-implementation-processes-attestation}). + \newpage \include{content/implementation/a-terminal-api} diff --git a/docs/content/implementation/a-processes.tex b/docs/content/implementation/a-processes.tex @@ -4,6 +4,7 @@ This section describes the different processes running in the background transitioning the state of a withdrawal. These transitions are triggered by the because of requests received by one of the components through the respective API. \subsubsection{Attestation} +\label{sec-implementation-processes-attestation} The attestation of a transaction is crucial, since this is the action which allows the exchange to create a reserve and can proof to the provider and customer, that the transaction was successful and therefore can put the liability for the money on the provider. The attestation process is implemented using a provider client interface and a provider transaction interface. This allows the process to be the same for each individual provider and new providers can be added easily by providing a specific implementation of the interfaces. diff --git a/docs/content/implementation/a-terminal-api.tex b/docs/content/implementation/a-terminal-api.tex @@ -39,6 +39,11 @@ When the terminal setup the withdrawal successful and received the \textit{WOPID Once the terminal authorized the transaction at the providers backend and received the notification, that the transaction was processed at the providers backend, the terminal can trigger the attestation of the transaction by calling this endpoint. This is also the point where the terminal can know the fees of the provider (if any) and send them to the C2EC component. +\textbf{Trigger Attestation (/withdrawals/[WOPID]/abort)} +\label{sec-implementation-terminal-api-abort} + +As long as the withdrawal was not authorized, it can be aborted by the terminal through this API. If the withdrawal was already authorized, the abortion will not work and the refund process might be needed to gain back the authorized money. + \textbf{Taler Integration (/taler-integration/*)} Under the \textit{/taler-integration/} sub-path the Bank-Integration API is reachable. Endpoints under this subpath are used by the Wallet to register parameters of a withdrawal and ask for the status of a withdrawal operation. The endpoints of the Bank-Integration API are described in \autoref{sec-implementation-bank-integration-api} diff --git a/docs/content/implementation/b-terminal.tex b/docs/content/implementation/b-terminal.tex @@ -57,7 +57,7 @@ This screen in \autoref{fig-terminal-screen-register-parameters} displays a QR c \subsubsection{Authorization Screen} -The authorization screen will use Wallee's \textit{Android Till SDK} \cite{wallee-till-sdk} to authorize the amount at the Wallee backend. The response handler of the SDK will delegate the response to the implementation of the terminal, which allows triggering the attestation of the payment by C2EC using the Terminals API. When the authorization process is not started and the transaction therefore is created at the backend system of Wallee, the screen displayed at \autoref{fig-terminal-screen-authorizing} will be displayed. This signals the user, that the payment authorization must still be done and is about to be started. The user can abort the transaction at this point. +The authorization screen will use Wallee's \textit{Android Till SDK} \cite{wallee-till-sdk} to authorize the amount at the Wallee backend. The response handler of the SDK will delegate the response to the implementation of the terminal, which allows triggering the attestation of the payment by C2EC using the Terminals API. When the authorization process is not started and the transaction therefore is created at the backend system of Wallee, the screen \autoref{fig-terminal-screen-authorizing} will be displayed. This signals the user, that the payment authorization must still be done and is about to be started. The user can abort the transaction at this point. \begin{figure}[h] \centering @@ -75,5 +75,22 @@ When the transaction was processed successfully, the summary of the transaction \label{fig-terminal-screen-authorized} \end{figure} +\subsection{Abortion Handling} + +During the flow various steps can fail or lead to the abortion of the withdrawal. Therefore these edge cases must be considered and handled the right way. Generally we can split the abortion handling on the terminal side into two different phases. The implementation of the Wallee POS Terminal therefore follows a strict \textit{abort on failure} strategy. This means that if anything goes wrong the withdrawal is aborted and must be started again. Generally the abortion handling strategy is to abort the withdrawal when in doubt and values security (of the money) over user-experience. + +\subsubsection{Abortion before authorization} + +The first phase are abortions \textit{before} the payment is authorized. In this case the withdrawal operation can be aborted using the \textit{abort} operation described in \autoref{sec-implementation-terminal-api}. Every problem which cannot be recovered or not further processed must therefore lead to the abortion of the withdrawal. + +\subsubsection{Abortion after authorization} + +When the transaction was authorized, the process is a little bit more complex. The customer has two possibilities. The first one is automatically covered with the given implementation, while the second is not guaranteed and needs manual interaction of the customer with the Taler Exchange operator. + +\textbf{Wait for automatic refund due to closing of the reserve} +The Taler Exchange configures a duration for which a reserve is kept open (and therefore can be withdrawn). When the configured duration exceeds the reserve is closed autmatically and the money transferred back to the customer. In the case of Wallee payments, this is realized through a refund request at the provider backend upon receiving a transfer request at the wire-gateway API \autoref{sec-implementation-wire-gateway-api} of the C2EC component. + +\textbf{Manual request to refund money} +Depending on the operator of the Taler Exchange it might be possible to somehow manually trigger a refund and get back the money spent for the withdrawal. \newpage \ No newline at end of file diff --git a/docs/content/implementation/e-security.tex b/docs/content/implementation/e-security.tex @@ -11,11 +11,12 @@ The database is very important as it decides wether to allow a withdrawal or not \subsubsection{Storing credentials} -Even if a database leak occurs, it shall be very hard for the attacker to access the API using the credentials stored in the database. This is why credentials are stored using PBKDF \textit{argon2} \cite{password-competition-argon2}. \textit{Argon2} is the winner of the password hashing competition initiated by the cryptographer Jean-Philippe Aumasson \cite{password-competition-argon2}. It is a widely adopted best practice approach for hashing passwords. Storing the hash of the credentials makes stealing credentials very hard and therefore prevents the abuse of credentials gathered through a database leak. The CLI described in \autoref{sec-implementation-cli} implements operations which will register providers and terminals also hashing the credentials using \textit{argon2}. +Even if a database leak occurs, it shall be very hard for the attacker to access the API using the credentials stored in the database. This is why credentials are stored using the PBKDF \textit{argon2} \cite{password-competition-argon2}. \textit{Argon2} is the winner of the password hashing competition initiated by the cryptographer Jean-Philippe Aumasson \cite{password-competition-argon2}. It is a widely adopted best practice approach for hashing passwords. Storing the hash of the credentials makes stealing credentials very hard and therefore prevents the abuse of credentials gathered through a database leak. The CLI described in \autoref{sec-implementation-cli} implements operations which will register providers and terminals also hashing the credentials using \textit{argon2}. \subsubsection{Access data through correct user} +\label{sec-security-db-users} -The database user executing a database query must have enough rights to execute its duties but not more. Therefore different database users are created for different tasks within the database. +The database user executing a database query must have enough rights to execute its duties but not more. Therefore different database users are created for different tasks within the database. The described setup and installation process in \autoref{sec-deployment} will automatically generate the users and grant them the correct rights, when the respective variables are specified. \begin{table}[H] \centering @@ -37,7 +38,7 @@ The database user executing a database query must have enough rights to execute \subsection{Authenticating at the Wallee ReST API} \label{sec-security-auth-wallee} -The Wallee API specifies four Wallee specific headers which are used to authenticate against the API. It defines its own authentication standard and flow. The flow builds on a MAC (message authentication code) which is built on a version, user identifier, and a timestamp. For the creation of the MAC the HMAC (hash based message authentication code) SHA-512 is leveraged which takes the so called \textit{application-user-key} (which is basically just an access-token, which the user receives when creating a new API user) as key and the above mentioned properties plus information about the requested http method and the exactly requested path (including request parameters) as message \cite{wallee-api-authentication}. The format of the message is specified like: +The Wallee API specifies four Wallee specific headers which are used to authenticate against the API. It defines its own authentication standard and flow. The flow builds on a message authentication code (MAC) which is built on a version, user identifier, and a timestamp. For the creation of the MAC the hash based message authentication code (HMAC) SHA-512 is leveraged which takes the so called \textit{application-user-key} (which is basically just an access-token, which the user receives when creating a new API user) as key and the above mentioned properties plus information about the requested http method and the exactly requested path (including request parameters) as message \cite{wallee-api-authentication}. The format of the message is specified like: \begin{center} \texttt{Version|User-Id|Unix-Timestamp|Http-Method|Path} diff --git a/docs/content/implementation/f-cli.tex b/docs/content/implementation/f-cli.tex @@ -3,7 +3,7 @@ The management of providers and terminals is not part of the thesis but since writing and issueing SQL statements is cumbersome and error-prone a small cli was implemented to abstract managment tasks. The cli tool was also shows the concepts a future implementation of the provider managment can use to integrate with the present features. The cli can be extended with more actions to allow the management of other providers and its terminals. Also the cli allows to setup the simulation terminal and provider which can be used for testing. Before commands can be executed, the user must connect the tool to the database which can be done throught the \textit{db} command. With the aim to not introduce security risks by storing configuration state of the cli, the credentials must be entered after each startup of the cli. This can be surpassed by specifying postgres specific environment variables \texttt{PGHOST}, \texttt{PGPORT}, \texttt{PGUSER} and \texttt{PGPASSWORD} but remember that these environment variables might leak database credentials to others if not cleaned properly or set for the wrong users shell. -The cli was implemented to be usable and as it was out of scope of the thesis, the focus was on the functionality and tasks needed for the thesis. This included features to manage wallee provider and terminals and the simulation. Additionally the tool implements commands to activate and deactivate a terminal, which makes the task much easier than writing and executing SQL by hand. Also it eliminates mistakes by reducing problems to bugs in the implementation of the cli. +The cli was implemented to be usable and as it was out of scope of the thesis, the focus was on the functionality and tasks needed for the thesis and to allow an easy management of the terminals. This included features to manage wallee provider and terminals and the simulation. Additionally the tool implements commands to activate and deactivate a terminal, which makes the task much easier than writing and executing SQL by hand. Also it eliminates mistakes by reducing problems to bugs in the implementation of the cli. \subsection{Adding a Wallee provider} @@ -20,4 +20,3 @@ To deactivate the terminal, the command \textit{dt} must be issued. It will ask \subsection{Setting up the Simulation} The Simulation provider and terminal allow to simulate transactions and interactions of the terminal with the API of C2EC. Therefore the command \textit{sim} will setup the needed provider and terminal including the credentials of the simulation terminal, which must be saved and supplied to the operator through a secure channel. These credentials allow to test the Terminals API using the simulation terminal. The simulation client will not be available in productive environments to reduce the attack surface due to unnecessaty features. -s -\ No newline at end of file diff --git a/docs/content/implementation/f-testing.tex b/docs/content/implementation/f-testing.tex @@ -2,4 +2,6 @@ Since the program leverages concurrency and operates in a distributed way, it is difficult to test besides unit testing. Therefore a simulation client and simulation program was implemented which allows to test the C2EC component while simulating the different involved parties like the terminal, wallet and the providers backend system. This setup allows to test and therefore proof the functionality of the system. -Besides the automated tests, using the above mentioned simulation, manual test were executed and done. +The Simulation can be used for regression testing and therefore can be run before introducing new features in order to check, that existing functionality will not be broken. + +Besides the automated tests, using the above mentioned simulation, unit tests were implemented for parsing, formatting and encoding functions. Additionally nanual test were fulfilled to ensure the system behaves correctly and without problems. To test the wire-gateway API, the \textit{taler-exchange-wire-gateway-client} facility was used supplied by GNU Taler to verify the correct functioning of the API. diff --git a/docs/content/implementation/g-deployment.tex b/docs/content/implementation/g-deployment.tex @@ -0,0 +1,45 @@ +\section{Deployment} +\label{sec-deployment} + +\subsection{Preparation} + +For the deployment the it is recommended to use a Debian Linux machine. To prepare the deployment of C2EC following steps must be done: + +\begin{enumerate} + \item Machine which has bash, go and postgres installed must be prepared. + \item Three \textit{different} passwords (each must be different and be stored in a secure location, like a password manager for example) + \item For the setup the username and password of postgresql superuser must be known. + \item The name for the database must be known and the database must exist at the target database system. + \item The installation location of C2EC must be created + \item The \textit{setup} script in the root directory of cashless2cash must be altered with the values mentioned above. +\end{enumerate} + +For the deployment of the Wallee POS Terminal app, the following steps are necessary to prepare the usage of the cashless withdrawals leveraging Wallee: + +\begin{enumerate} + \item A running deployment of C2EC must be accessible. + \item Wallee must be a registered provider at the C2EC instance. + \item The Terminal must be registered at C2EC. +\end{enumerate} + +\subsection{Setup} + +Once the steps from the preparation were succesfully done, the \textit{setup}-script can now be run. It will initiate the database and setup the users (as described in \autoref{sec-security-db-users}) with the correct permissions. It will further generate the executables for C2EC, the cli and the simulation inside the specified \texttt{C2EC\_HOME}. The setup script contains sensitive credentials and shall be deleted after using it. Maybe it can be stored in a save location like a password manager. Like this it will be still available in the future but will not lie around on the filesystem unencrypted. + +\subsubsection{Setting up Wallee as provider} + +To allow withdrawals using Wallee as provider, the correct access tokens must be created at the Wallee backend. Therefore a new application user must be created and the \textit{application user key} must be saved to a password manager. Then Wallee must be registered at C2EC using the cli (described in \autoref{sec-implementation-cli}) and the \textit{rp} command. There the space-id, user-id of the application user and the \textit{application user key} must be provided. The cli will register the provider using these values. + +When Wallee was registered as provider, one must register a terminal to allow access to the Taler Terminals API of C2EC. Therefore also the cli with its \textit{rt} command can be used. It will generate the terminal user id and the access token. Both these values should be stored in a save location like the password manager + +\subsubsection{Setting up the simulation} + +When the simulation shall be installed the \textit{prod}-flag in the C2EC configuration should be disabled, in order to allow the simulation provider to be registered at startup. This is a security measure, that testing facilities are not reachable in productive use of the system. + +\subsection{Deploy} + +When the provider and the terminal was successfully registered, the configuration located inside the \texttt{C2EC\_HOME} must be adjusted to the correct values. Once this is done, the C2EC process can be started using \texttt{./c2ec [PATH-TO-CONFIGFILE]}. + +\subsection{Migration and releases} + +When a new version of the system shall be installed, the new executable can be built by issueing \texttt{make build}. After migrating the database using \texttt{make migrate} the newly built executable can be started. diff --git a/docs/thesis.pdf b/docs/thesis.pdf Binary files differ. diff --git a/docs/thesis.tex b/docs/thesis.tex @@ -207,6 +207,8 @@ \input{content/implementation/d-wallet} \input{content/implementation/e-security} \input{content/implementation/f-cli} +\input{content/implementation/f-testing} +\input{content/implementation/g-deployment} \chapter{Results} \input{content/results/discussion} diff --git a/simulation/c2ec-simulation b/simulation/c2ec-simulation Binary files differ.