Browse Source

Add deposit only token support

master
Teran McKinney 2 years ago
parent
commit
67667c15f4
  1. 15
      cmd/settlers/main.go
  2. 95
      cmd/settlersd/cmd_test.go
  3. 2
      cmd/settlersd/database.go
  4. 56
      cmd/settlersd/deposit.go
  5. 46
      cmd/settlersd/deposit_only_token_enabled.go
  6. 9
      cmd/settlersd/enable.go
  7. 7
      cmd/settlersd/enable_test.go
  8. 14
      cmd/settlersd/web.go
  9. 10
      request_types.go
  10. 70
      settlers.go
  11. 9
      settlers_test.go
  12. 2
      test.sh

15
cmd/settlers/main.go

@ -14,6 +14,9 @@ func usage() {
fmt.Fprintln(os.Stderr, "Command: balance <endpoint> <customer token> <business token>")
fmt.Fprintln(os.Stderr, "Command: add <endpoint> <customer token> <business token> <amount>")
fmt.Fprintln(os.Stderr, "Command: subtract <endpoint> <customer token> <business token> <amount>")
fmt.Fprintln(os.Stderr, "Command: deposittoken <customer token>")
fmt.Fprintln(os.Stderr, "Command: depositonlytokenenabled <endpoint> <deposit token> <business token>")
fmt.Fprintln(os.Stderr, "Command: deposit <endpoint> <deposit token> <business token> <amount>")
os.Exit(2)
}
@ -46,6 +49,18 @@ func main() {
amount, err = settlers.Balance(os.Args[1+1], os.Args[1+2], os.Args[1+3])
fatalError(err)
fmt.Println(amount)
case "deposittoken":
exactlyArguments(2 + 1)
fmt.Println(settlers.DepositToken(os.Args[1+1]))
case "depositonlytokenenabled":
exactlyArguments(2 + 3)
err = settlers.DepositOnlyTokenEnabled(os.Args[1+1], os.Args[1+2], os.Args[1+3])
fatalError(err)
case "deposit":
exactlyArguments(2 + 4)
amount, err = strconv.ParseUint(os.Args[1+4], 10, 64)
fatalError(err)
fatalError(settlers.Deposit(os.Args[1+1], os.Args[1+2], os.Args[1+3], amount))
case "add":
exactlyArguments(2 + 4)
amount, err = strconv.ParseUint(os.Args[1+4], 10, 64)

95
cmd/settlersd/cmd_test.go

@ -22,29 +22,29 @@ func TestSettlers(t *testing.T) {
_, userErr, err := balance(testToken, db)
if err != nil {
t.Error(err.Error())
}
if userErr != settlers.ErrorAccountNotEnabled {
} else if userErr != settlers.ErrorAccountNotEnabled {
t.Error("Account should not be enabled.")
} else {
log.Print("Non-enabled account balance shows not enabled.")
}
err, userErr = enable(testToken, testAdminToken, db, testConfiguration)
depositToken := settlers.DepositToken(testToken)
err, userErr = enable(testToken, depositToken, testAdminToken, db, testConfiguration)
if err != nil {
t.Error(err.Error())
}
if userErr != nil {
} else if userErr != nil {
t.Error(userErr.Error())
} else {
log.Print("Enable worked.")
}
amount, userErr, err := balance(testToken, db)
if err != nil {
t.Error(err.Error())
}
if userErr != nil {
} else if userErr != nil {
t.Error(userErr.Error())
}
if amount != startingBalance {
} else if amount != startingBalance {
t.Errorf("Balance is not %d, it's %d.", startingBalance, amount)
} else {
log.Print("Balance is 0.")
@ -53,8 +53,7 @@ func TestSettlers(t *testing.T) {
userErr, err = add(testToken, 100, db)
if err != nil {
t.Error(err.Error())
}
if userErr != nil {
} else if userErr != nil {
t.Error(userErr.Error())
} else {
log.Print("Able to add 100 to token.")
@ -63,8 +62,7 @@ func TestSettlers(t *testing.T) {
userErr, err = subtract(testToken, 40, db)
if err != nil {
t.Error(err.Error())
}
if userErr != nil {
} else if userErr != nil {
t.Error(userErr.Error())
} else {
log.Print("Able to subtract 40 from token.")
@ -73,19 +71,78 @@ func TestSettlers(t *testing.T) {
amount, userErr, err = balance(testToken, db)
if err != nil {
t.Error(err.Error())
}
if userErr != nil {
} else if userErr != nil {
t.Error(userErr.Error())
}
if amount != 60 {
} else if amount != 60 {
t.Errorf("Balance is not %d, it's %d.", 60, amount)
} else {
log.Print("Balance after subtract is correct.")
}
userErr, err = subtract(testToken, 61, db)
if err != nil {
t.Error(err.Error())
}
if userErr != settlers.ErrorInsufficientBalance {
} else if userErr != settlers.ErrorInsufficientBalance {
t.Error("Should have errored insufficient balance.")
} else {
log.Print("Got insufficient balance when we were supposed to.")
}
userErr, err = depositOnlyTokenEnabled(depositToken, db)
if err != nil {
t.Error(err.Error())
} else if userErr != nil {
t.Error(userErr.Error())
} else {
log.Print("depositTokenEnabled works.")
}
userErr, err = deposit(depositToken, 100, db)
if err != nil {
t.Error(err.Error())
} else if userErr != nil {
t.Error(userErr.Error())
} else {
log.Print("deposit works.")
}
amount, userErr, err = balance(testToken, db)
if err != nil {
t.Error(err.Error())
} else if userErr != nil {
t.Error(userErr.Error())
} else if amount != 160 {
t.Errorf("Balance is not %d, it's %d.", 160, amount)
} else {
log.Print("Balance is correct after deposit.")
}
// Make sure depositToken is restricted properly.
_, userErr, err = balance(depositToken, db)
if err != nil {
t.Error(err.Error())
} else if userErr != settlers.ErrorAccountNotEnabled {
t.Error(userErr.Error())
} else {
log.Print("Deposit token can't check balance.")
}
userErr, err = add(depositToken, 10, db)
if err != nil {
t.Error(err.Error())
} else if userErr != settlers.ErrorAccountNotEnabled {
t.Error(userErr.Error())
} else {
log.Print("Deposit token can't do regular add.")
}
userErr, err = subtract(depositToken, 10, db)
if err != nil {
t.Error(err.Error())
} else if userErr != settlers.ErrorAccountNotEnabled {
t.Error(userErr.Error())
} else {
log.Print("Deposit token can't do subtract.")
}
}

2
cmd/settlersd/database.go

@ -5,7 +5,7 @@ import "github.com/bvinc/go-sqlite-lite/sqlite3"
const inMemoryDatabase = ":memory:"
func dbPrep(connection *sqlite3.Conn) error {
return connection.Exec(`CREATE TABLE balances (combined_token TEXT NOT NULL UNIQUE, balance INTEGER CHECK (balance >= 0))`)
return connection.Exec(`CREATE TABLE balances (combined_token TEXT NOT NULL UNIQUE, combined_deposit_only_token TEXT UNIQUE, balance INTEGER CHECK (balance >= 0))`)
}
func dbConnect(conf Configuration) (connection *sqlite3.Conn, err error) {

56
cmd/settlersd/deposit.go

@ -0,0 +1,56 @@
package main
import (
"encoding/json"
"net/http"
"github.com/bvinc/go-sqlite-lite/sqlite3"
"github.com/sporestack/settlers"
)
func deposit(depositOnlyToken string, amount uint64, db *sqlite3.Conn) (userErr, err error) {
// Add to a regular depositOnlyToken with its deposit only depositOnlyToken.
if userErr = settlers.ValidateToken(depositOnlyToken); userErr != nil {
return
}
// Check if account is enabled.
userErr, err = depositOnlyTokenEnabled(depositOnlyToken, db)
if userErr != nil || err != nil {
return
}
// sqlite3 only supports signed integers
var signedAmount int64
signedAmount = int64(amount)
err = db.Exec("UPDATE balances SET balance = balance + ? WHERE combined_deposit_only_token = ?", signedAmount, depositOnlyToken)
if err != nil {
return
}
return
}
func httpDeposit(w http.ResponseWriter, r *http.Request, db *sqlite3.Conn) {
defer r.Body.Close()
var request settlers.DepositRequest
decoder := json.NewDecoder(r.Body)
decoder.DisallowUnknownFields()
userErr := decoder.Decode(&request)
if userErr != nil {
httpHandle400(w, userErr)
return
}
userErr, err := deposit(request.CombinedDepositOnlyToken, request.Amount, db)
if userErr != nil {
httpHandle400(w, userErr)
return
}
if err != nil {
httpHandle500(w, err)
return
}
return
}

46
cmd/settlersd/deposit_only_token_enabled.go

@ -0,0 +1,46 @@
package main
import (
"net/http"
"strings"
"github.com/bvinc/go-sqlite-lite/sqlite3"
"github.com/sporestack/settlers"
)
func depositOnlyTokenEnabled(depositOnlyToken string, db *sqlite3.Conn) (userErr, err error) {
if userErr = settlers.ValidateToken(depositOnlyToken); userErr != nil {
return
}
statement, err := db.Prepare("SELECT balance FROM balances WHERE combined_deposit_only_token = ?", depositOnlyToken)
if err != nil {
return
}
defer statement.Close()
hasRow, err := statement.Step()
if err != nil {
return
}
if !hasRow {
userErr = settlers.ErrorAccountNotEnabled
return
}
return
}
func httpDepositOnlyTokenEnabled(w http.ResponseWriter, r *http.Request, db *sqlite3.Conn) {
defer r.Body.Close()
pathParts := strings.Split(r.URL.Path, "/")
token := pathParts[len(pathParts)-1]
userErr, err := depositOnlyTokenEnabled(token, db)
if err != nil {
httpHandle500(w, err)
return
}
if userErr != nil {
httpHandle400(w, userErr)
return
}
return
}

9
cmd/settlersd/enable.go

@ -10,12 +10,15 @@ import (
const startingBalance = 0
func enable(token, adminToken string, db *sqlite3.Conn, conf Configuration) (userErr, err error) {
func enable(token, depositOnlyToken, adminToken string, db *sqlite3.Conn, conf Configuration) (userErr, err error) {
// We should consider doing balance first to know if it's a DB error
// or a user error.
if userErr = settlers.ValidateToken(token); userErr != nil {
return
}
if userErr = settlers.ValidateToken(depositOnlyToken); userErr != nil {
return
}
if userErr = settlers.ValidateToken(adminToken); userErr != nil {
return
}
@ -26,7 +29,7 @@ func enable(token, adminToken string, db *sqlite3.Conn, conf Configuration) (use
// userErr because of constraint issues but debatable.
// If the user tries to add two tokens, it should fail and not be considered our failure.
userErr = db.Exec("INSERT INTO balances (combined_token, balance) VALUES (?, ?)", token, startingBalance)
userErr = db.Exec("INSERT INTO balances (combined_token, combined_deposit_only_token, balance) VALUES (?, ?, ?)", token, depositOnlyToken, startingBalance)
return
}
@ -43,7 +46,7 @@ func httpEnable(w http.ResponseWriter, r *http.Request, db *sqlite3.Conn, conf C
return
}
userErr, err := enable(request.CombinedToken, request.AdminToken, db, conf)
userErr, err := enable(request.CombinedToken, request.CombinedDepositOnlyToken, request.AdminToken, db, conf)
if userErr != nil {
httpHandle400(w, userErr)
return

7
cmd/settlersd/enable_test.go

@ -14,11 +14,12 @@ func TestEnable(t *testing.T) {
}
defer db.Close()
userErr, err := enable(testToken, testToken, db, testConfiguration)
depositToken := settlers.DepositToken(testToken)
userErr, err := enable(testToken, testToken, depositToken, db, testConfiguration)
if err != nil {
t.Error(err.Error())
}
if userErr != settlers.ErrorIncorrectAdminToken {
} else if userErr != settlers.ErrorIncorrectAdminToken {
t.Error("Did not give incorrect admin token error for invalid token.")
} else {
log.Print("We secure enable properly.")

14
cmd/settlersd/web.go

@ -54,6 +54,20 @@ func web(conf Configuration) (err error) {
return
})
http.HandleFunc("/depositOnlyTokenEnabled/", func(w http.ResponseWriter, r *http.Request) {
s.Increment("depositOnlyTokenEnabled.hit")
defer s.NewTiming().Send("depositOnlyTokenEnabled")
httpDepositOnlyTokenEnabled(w, r, db)
return
})
http.HandleFunc("/deposit", func(w http.ResponseWriter, r *http.Request) {
s.Increment("deposit.hit")
defer s.NewTiming().Send("deposit")
httpDeposit(w, r, db)
return
})
http.HandleFunc("/SettlersAlive", func(w http.ResponseWriter, r *http.Request) {
s.Increment("SettlersAlive.hit")
defer s.NewTiming().Send("SettlersAlive")

10
request_types.go

@ -15,6 +15,12 @@ type SubtractRequest struct {
}
type EnableRequest struct {
CombinedToken string `json:"combined_token"`
AdminToken string `json:"admin_token"`
CombinedToken string `json:"combined_token"`
CombinedDepositOnlyToken string `json:"combined_deposit_only_token"`
AdminToken string `json:"admin_token"`
}
type DepositRequest struct {
CombinedDepositOnlyToken string `json:"combined_deposit_only_token"`
Amount uint64 `json:"amount"`
}

70
settlers.go

@ -34,7 +34,11 @@ func CombineToken(customerToken, businessToken string) string {
return Hash(customerToken + " for " + businessToken)
}
func Enable(endpouint64, adminToken, customerToken, businessToken string) (err error) {
func DepositToken(customerToken string) string {
return Hash(customerToken + " deposit")
}
func Enable(endpoint, adminToken, customerToken, businessToken string) (err error) {
if err = ValidateToken(adminToken); err != nil {
return
}
@ -46,11 +50,15 @@ func Enable(endpouint64, adminToken, customerToken, businessToken string) (err e
}
combinedToken := CombineToken(customerToken, businessToken)
requestJson, err := json.Marshal(EnableRequest{AdminToken: adminToken, CombinedToken: combinedToken})
depositOnlyToken := DepositToken(customerToken)
combinedDepositOnlyToken := CombineToken(depositOnlyToken, businessToken)
requestJson, err := json.Marshal(EnableRequest{AdminToken: adminToken, CombinedToken: combinedToken, CombinedDepositOnlyToken: combinedDepositOnlyToken})
if err != nil {
return
}
ourURL := endpouint64 + "/enable"
ourURL := endpoint + "/enable"
ourHTTP, err := clearnetOrOnionHTTP(ourURL)
if err != nil {
return
@ -59,7 +67,7 @@ func Enable(endpouint64, adminToken, customerToken, businessToken string) (err e
return
}
func Balance(endpouint64, customerToken, businessToken string) (amount uint64, err error) {
func Balance(endpoint, customerToken, businessToken string) (amount uint64, err error) {
if err = ValidateToken(customerToken); err != nil {
return
}
@ -68,7 +76,7 @@ func Balance(endpouint64, customerToken, businessToken string) (amount uint64, e
}
combinedToken := CombineToken(customerToken, businessToken)
ourURL := endpouint64 + "/balance/" + combinedToken
ourURL := endpoint + "/balance/" + combinedToken
ourHTTP, err := clearnetOrOnionHTTP(ourURL)
if err != nil {
return
@ -91,7 +99,51 @@ func Balance(endpouint64, customerToken, businessToken string) (amount uint64, e
return
}
func Add(endpouint64, customerToken, businessToken string, amount uint64) (err error) {
func DepositOnlyTokenEnabled(endpoint, depositToken, businessToken string) (err error) {
if err = ValidateToken(depositToken); err != nil {
return
}
if err = ValidateToken(businessToken); err != nil {
return
}
combinedToken := CombineToken(depositToken, businessToken)
ourURL := endpoint + "/depositOnlyTokenEnabled/" + combinedToken
ourHTTP, err := clearnetOrOnionHTTP(ourURL)
if err != nil {
return
}
_, err = handleResponse(ourHTTP.Get(ourURL))
if err != nil {
return
}
return
}
func Deposit(endpoint, depositToken, businessToken string, amount uint64) (err error) {
if err = ValidateToken(depositToken); err != nil {
return
}
if err = ValidateToken(businessToken); err != nil {
return
}
combinedToken := CombineToken(depositToken, businessToken)
requestJson, err := json.Marshal(DepositRequest{CombinedDepositOnlyToken: combinedToken, Amount: amount})
if err != nil {
return
}
ourURL := endpoint + "/deposit"
ourHTTP, err := clearnetOrOnionHTTP(ourURL)
if err != nil {
return
}
_, err = handleResponse(ourHTTP.Post(ourURL, "application/json", bytes.NewReader(requestJson)))
return
}
func Add(endpoint, customerToken, businessToken string, amount uint64) (err error) {
if err = ValidateToken(customerToken); err != nil {
return
}
@ -104,7 +156,7 @@ func Add(endpouint64, customerToken, businessToken string, amount uint64) (err e
if err != nil {
return
}
ourURL := endpouint64 + "/add"
ourURL := endpoint + "/add"
ourHTTP, err := clearnetOrOnionHTTP(ourURL)
if err != nil {
return
@ -113,7 +165,7 @@ func Add(endpouint64, customerToken, businessToken string, amount uint64) (err e
return
}
func Subtract(endpouint64, customerToken, businessToken string, amount uint64) (err error) {
func Subtract(endpoint, customerToken, businessToken string, amount uint64) (err error) {
if err = ValidateToken(customerToken); err != nil {
return
}
@ -126,7 +178,7 @@ func Subtract(endpouint64, customerToken, businessToken string, amount uint64) (
if err != nil {
return
}
ourURL := endpouint64 + "/subtract"
ourURL := endpoint + "/subtract"
ourHTTP, err := clearnetOrOnionHTTP(ourURL)
if err != nil {
return

9
settlers_test.go

@ -7,6 +7,7 @@ import (
// Testing constants
const validToken = "ee2ec014a1194908209736c6e89c843fe61e94f8763afef7bb12999c5da02b55"
const validTokensDepositToken = "49291c159d8d5e641402e6088213049988f607a9c7778e0624610f7c85652330"
// Non hex token
const invalidNonHexToken = "ze2ec014a1194908209736c6e89c843fe61e94f8763afef7bb12999c5da02b55"
@ -41,3 +42,11 @@ func TestValidateToken(t *testing.T) {
log.Print("Non-hex token invalid: ", err.Error())
}
}
func TestDepositToken(t *testing.T) {
if DepositToken(validToken) == validTokensDepositToken {
log.Print("Deposit Token generation is correct.")
} else {
t.Error("Deposit Token generation is broken.")
}
}

2
test.sh

@ -61,6 +61,8 @@ curl -s --show-error --fail "http://localhost:2828/balance/01ba4719c80b6fe911b09
./settlers subtract http://localhost:2828 01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b 53c234e5e8472b6ac51c1ae1cab3fe06fad053beb8ebfd8977b010655bfdd3c3 40 || fail "Cannot subtract"
./settlers balance http://localhost:2828 01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b 53c234e5e8472b6ac51c1ae1cab3fe06fad053beb8ebfd8977b010655bfdd3c3 || fail "Cannot get balance"
./settlers subtract http://localhost:2828 01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b 53c234e5e8472b6ac51c1ae1cab3fe06fad053beb8ebfd8977b010655bfdd3c3 61 && fail "Can subtract too much."
./settlers depositonlytokenenabled http://localhost:2828 "$(./settlers deposittoken 01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b)" 53c234e5e8472b6ac51c1ae1cab3fe06fad053beb8ebfd8977b010655bfdd3c3 || fail "deposit only token not enabled"
./settlers deposit http://localhost:2828 "$(./settlers deposittoken 01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b)" 53c234e5e8472b6ac51c1ae1cab3fe06fad053beb8ebfd8977b010655bfdd3c3 100 || fail "Cannot deposit"
cleanup

Loading…
Cancel
Save