176 lines
4.6 KiB
Go
176 lines
4.6 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
|
|
"bank-emulator/internal/bank"
|
|
"bank-emulator/internal/storage"
|
|
)
|
|
|
|
var b *bank.Bank
|
|
|
|
func main() {
|
|
store := storage.New("bank_data.json")
|
|
b = bank.New(store)
|
|
|
|
http.HandleFunc("/validate", handleValidate)
|
|
http.HandleFunc("/bind", handleBind)
|
|
http.HandleFunc("/confirm-3ds", handleConfirm3DS)
|
|
http.HandleFunc("/charge", handleCharge)
|
|
http.HandleFunc("/complete-charge", handleCompleteCharge)
|
|
http.HandleFunc("/direct-charge", handleDirectCharge)
|
|
|
|
fmt.Println("Bank emulator running on :9090")
|
|
log.Fatal(http.ListenAndServe(":9090", nil))
|
|
}
|
|
|
|
type validateReq struct {
|
|
CardNumber string `json:"card_number"`
|
|
}
|
|
|
|
type bindReq struct {
|
|
CardNumber string `json:"card_number"`
|
|
CVV string `json:"cvv"`
|
|
Expiry string `json:"expiry"`
|
|
HolderName string `json:"holder_name"`
|
|
}
|
|
|
|
type confirm3dsReq struct {
|
|
SessionID string `json:"session_id"`
|
|
Code string `json:"code"`
|
|
}
|
|
|
|
type chargeReq struct {
|
|
CardNumber string `json:"card_number"`
|
|
Amount float64 `json:"amount"`
|
|
}
|
|
|
|
type completeChargeReq struct {
|
|
SessionID string `json:"session_id"`
|
|
Amount float64 `json:"amount"`
|
|
}
|
|
|
|
type directChargeReq struct {
|
|
CardNumber string `json:"card_number"`
|
|
Amount float64 `json:"amount"`
|
|
}
|
|
|
|
type resp struct {
|
|
OK bool `json:"ok"`
|
|
Error string `json:"error,omitempty"`
|
|
SessionID string `json:"session_id,omitempty"`
|
|
}
|
|
|
|
func writeJSON(w http.ResponseWriter, status int, v any) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(status)
|
|
json.NewEncoder(w).Encode(v)
|
|
}
|
|
|
|
func handleValidate(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
writeJSON(w, 405, resp{OK: false, Error: "method not allowed"})
|
|
return
|
|
}
|
|
var req validateReq
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
writeJSON(w, 400, resp{OK: false, Error: "invalid request body"})
|
|
return
|
|
}
|
|
if err := b.ValidateCard(req.CardNumber); err != nil {
|
|
writeJSON(w, 400, resp{OK: false, Error: err.Error()})
|
|
return
|
|
}
|
|
writeJSON(w, 200, resp{OK: true})
|
|
}
|
|
|
|
func handleBind(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
writeJSON(w, 405, resp{OK: false, Error: "method not allowed"})
|
|
return
|
|
}
|
|
var req bindReq
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
writeJSON(w, 400, resp{OK: false, Error: "invalid request body"})
|
|
return
|
|
}
|
|
session, err := b.InitiateBind(req.CardNumber, req.CVV, req.Expiry)
|
|
if err != nil {
|
|
writeJSON(w, 400, resp{OK: false, Error: err.Error()})
|
|
return
|
|
}
|
|
writeJSON(w, 200, resp{OK: true, SessionID: session.SessionID})
|
|
}
|
|
|
|
func handleConfirm3DS(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
writeJSON(w, 405, resp{OK: false, Error: "method not allowed"})
|
|
return
|
|
}
|
|
var req confirm3dsReq
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
writeJSON(w, 400, resp{OK: false, Error: "invalid request body"})
|
|
return
|
|
}
|
|
if err := b.Confirm3DS(req.SessionID, req.Code); err != nil {
|
|
writeJSON(w, 400, resp{OK: false, Error: err.Error()})
|
|
return
|
|
}
|
|
writeJSON(w, 200, resp{OK: true})
|
|
}
|
|
|
|
func handleCharge(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
writeJSON(w, 405, resp{OK: false, Error: "method not allowed"})
|
|
return
|
|
}
|
|
var req chargeReq
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
writeJSON(w, 400, resp{OK: false, Error: "invalid request body"})
|
|
return
|
|
}
|
|
session, err := b.Charge(req.CardNumber, req.Amount)
|
|
if err != nil {
|
|
writeJSON(w, 400, resp{OK: false, Error: err.Error()})
|
|
return
|
|
}
|
|
writeJSON(w, 200, resp{OK: true, SessionID: session.SessionID})
|
|
}
|
|
|
|
func handleCompleteCharge(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
writeJSON(w, 405, resp{OK: false, Error: "method not allowed"})
|
|
return
|
|
}
|
|
var req completeChargeReq
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
writeJSON(w, 400, resp{OK: false, Error: "invalid request body"})
|
|
return
|
|
}
|
|
if err := b.CompleteCharge(req.SessionID, req.Amount); err != nil {
|
|
writeJSON(w, 400, resp{OK: false, Error: err.Error()})
|
|
return
|
|
}
|
|
writeJSON(w, 200, resp{OK: true})
|
|
}
|
|
|
|
func handleDirectCharge(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
writeJSON(w, 405, resp{OK: false, Error: "method not allowed"})
|
|
return
|
|
}
|
|
var req directChargeReq
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
writeJSON(w, 400, resp{OK: false, Error: "invalid request body"})
|
|
return
|
|
}
|
|
if err := b.DirectCharge(req.CardNumber, req.Amount); err != nil {
|
|
writeJSON(w, 400, resp{OK: false, Error: err.Error()})
|
|
return
|
|
}
|
|
writeJSON(w, 200, resp{OK: true})
|
|
}
|