main_test.go (12199B)
1 // This file is part of taldir, the Taler Directory implementation. 2 // Copyright (C) 2022 Martin Schanzenbach 3 // 4 // Taldir is free software: you can redistribute it and/or modify it 5 // under the terms of the GNU Affero General Public License as published 6 // by the Free Software Foundation, either version 3 of the License, 7 // or (at your option) any later version. 8 // 9 // Taldir is distributed in the hope that it will be useful, but 10 // WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 // Affero General Public License for more details. 13 // 14 // You should have received a copy of the GNU Affero General Public License 15 // along with this program. If not, see <http://www.gnu.org/licenses/>. 16 // 17 // SPDX-License-Identifier: AGPL3.0-or-later 18 19 package main_test 20 21 import ( 22 "bytes" 23 "fmt" 24 "io" 25 "log" 26 "net/http" 27 "net/http/httptest" 28 "os" 29 "strings" 30 "testing" 31 32 "github.com/schanzen/taler-go/pkg/merchant" 33 "gopkg.in/ini.v1" 34 "gorm.io/driver/sqlite" 35 _ "taler.net/taldir/cmd/taldir-server" 36 "taler.net/taldir/internal/util" 37 taldir "taler.net/taldir/pkg/taldir" 38 ) 39 40 var t taldir.Taldir 41 42 // Note: This duration will be rounded down to 20 Months (= 51840000000000) 43 var validRegisterRequest = []byte(` 44 { 45 "alias": "abc@test", 46 "target_uri": "myinbox@xyz", 47 "duration": 53135000000000 48 } 49 `) 50 51 var validRegisterRequestUnmodified = []byte(` 52 { 53 "alias": "abc@test", 54 "target_uri": "myinbox@xyz", 55 "duration": 0 56 } 57 `) 58 59 var newOrderMockResponse = ` 60 { 61 "order_id": "testOrder1234", 62 "taler_pay_uri": "payto://ladida" 63 } 64 ` 65 66 var newOrderStatusUnpaidMockResponse = ` 67 { 68 "order_status": "unpaid", 69 "taler_pay_uri": "payto://somedude" 70 } 71 ` 72 73 const merchantConfigResponse = `{ 74 "currency": "KUDOS", 75 "currencies": { 76 "KUDOS": { 77 "name": "Kudos (Taler Demonstrator)", 78 "currency": "KUDOS", 79 "num_fractional_input_digits": 2, 80 "num_fractional_normal_digits": 2, 81 "num_fractional_trailing_zero_digits": 2, 82 "alt_unit_names": { 83 "0": "ク" 84 } 85 } 86 }, 87 "exchanges": [ 88 { 89 "master_pub": "F80MFRG8HVH6R9CQ47KRFQSJP3T6DBJ4K1D9B703RJY3Z39TBMJ0", 90 "currency": "KUDOS", 91 "base_url": "https://exchange.demo.taler.net/" 92 } 93 ], 94 "implementation": "urn:net:taler:specs:taler-merchant:c-reference", 95 "name": "taler-merchant", 96 "version": "18:0:15" 97 }` 98 99 func TestMain(m *testing.M) { 100 cfg, err := ini.LooseLoad("testdata/taldir-test.conf") 101 if err != nil { 102 log.Fatalf("Failed to read config: %v", err) 103 os.Exit(1) 104 } 105 db := sqlite.Open("file::memory:?cache=shared") 106 merchServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 107 if r.URL.Path == "/config" { 108 w.WriteHeader(http.StatusOK) 109 w.Write([]byte(merchantConfigResponse)) 110 return 111 } 112 if !strings.HasPrefix(r.URL.Path, "/private/orders") { 113 log.Printf("Expected to request '/private/orders', got: %s\n", r.URL.Path) 114 return 115 } 116 if r.Method == http.MethodPost { 117 jsonResp := fmt.Sprintf("{\"order_id\":\"%s\"}", "uniqueOrderId") 118 w.WriteHeader(http.StatusOK) 119 w.Write([]byte(jsonResp)) 120 } else { 121 if r.Header.Get("PaidIndicator") == "yes" { 122 jsonResp := "{\"order_status\":\"paid\"}" 123 w.WriteHeader(http.StatusOK) 124 w.Write([]byte(jsonResp)) 125 } else { 126 jsonResp := "{\"order_status\":\"unpaid\", \"taler_pay_uri\": \"somepaytouri\"}" 127 w.WriteHeader(http.StatusOK) 128 w.Write([]byte(jsonResp)) 129 } 130 } 131 })) 132 defer merchServer.Close() 133 merch := merchant.NewMerchant(merchServer.URL, "supersecret") 134 t.Initialize(taldir.TaldirConfig{ 135 Ini: cfg, 136 Version: "testing", 137 Datahome: "./testdata", 138 Db: db, 139 Merchant: merch, 140 Loglevel: taldir.LogDebug, 141 }) 142 log.Printf("have %d validators", len(t.Validators)) 143 log.Print(t.Validators) 144 code := m.Run() 145 t.ClearDatabase() 146 os.Exit(code) 147 } 148 149 func getHAlias(alias string) string { 150 ha := t.HashAlias("test", alias) 151 return util.Base32CrockfordEncode(ha) 152 } 153 154 func TestNoEntry(s *testing.T) { 155 t.ClearDatabase() 156 157 h_alias := getHAlias("jdoe@example.com") 158 req, _ := http.NewRequest("GET", "/"+h_alias, nil) 159 response := executeRequest(req) 160 161 if http.StatusNotFound != response.Code { 162 s.Errorf("Expected response code %d. Got %d\n", http.StatusNotFound, response.Code) 163 } 164 } 165 166 func executeRequest(req *http.Request) *httptest.ResponseRecorder { 167 rr := httptest.NewRecorder() 168 t.Router.ServeHTTP(rr, req) 169 return rr 170 } 171 172 func TestRegisterRequest(s *testing.T) { 173 t.ClearDatabase() 174 175 req, _ := http.NewRequest("POST", "/register/test", bytes.NewBuffer(validRegisterRequest)) 176 response := executeRequest(req) 177 178 if http.StatusAccepted != response.Code { 179 s.Errorf("Expected response code %d. Got %d, with %s\n", http.StatusAccepted, response.Code, response.Body) 180 } 181 file, err := os.Open("validation_code") 182 if err != nil { 183 s.Errorf("No validation code file found!\n") 184 } 185 code, err := io.ReadAll(file) 186 if err != nil { 187 s.Errorf("Error reading validation code file contents!\n") 188 } 189 h_alias := getHAlias("abc@test") 190 trimCode := strings.Trim(string(code), " \r\n") 191 solution := util.GenerateSolution("myinbox@xyz", trimCode) 192 solutionJSON := "{\"solution\": \"" + solution + "\"}" 193 req, _ = http.NewRequest("POST", "/"+h_alias, bytes.NewBuffer([]byte(solutionJSON))) 194 response = executeRequest(req) 195 if http.StatusNoContent != response.Code { 196 s.Errorf("Expected response code %d. Got %d\n", http.StatusNoContent, response.Code) 197 } 198 } 199 200 func TestRegisterQRPageRequest(s *testing.T) { 201 t.ClearDatabase() 202 203 req, _ := http.NewRequest("POST", "/register/test", bytes.NewBuffer(validRegisterRequest)) 204 response := executeRequest(req) 205 206 if http.StatusAccepted != response.Code { 207 s.Errorf("Expected response code %d. Got %d\n", http.StatusAccepted, response.Code) 208 } 209 req, _ = http.NewRequest("GET", "/register/NonSenseAddr/NonSenseCode", nil) 210 response = executeRequest(req) 211 if http.StatusNotFound != response.Code { 212 s.Errorf("Expected response code %d. Got %d\n", http.StatusNotFound, response.Code) 213 } 214 215 file, err := os.Open("validation_code") 216 if err != nil { 217 s.Errorf("No validation code file found!\n") 218 } 219 code, err := io.ReadAll(file) 220 if err != nil { 221 s.Errorf("Error reading validation code file contents!\n") 222 } 223 h_alias := getHAlias("abc@test") 224 trimCode := strings.Trim(string(code), " \r\n") 225 req, _ = http.NewRequest("GET", "/register/"+h_alias+"/"+trimCode+"?alias="+"abc@test", nil) 226 response = executeRequest(req) 227 if http.StatusOK != response.Code { 228 s.Errorf("Expected response code %d. Got %d\n", http.StatusOK, response.Code) 229 } 230 } 231 232 func TestReRegisterRequest(s *testing.T) { 233 t.ClearDatabase() 234 235 req, _ := http.NewRequest("POST", "/register/test", bytes.NewBuffer(validRegisterRequest)) 236 response := executeRequest(req) 237 238 if http.StatusAccepted != response.Code { 239 s.Errorf("Expected response code %d. Got %d\n", http.StatusAccepted, response.Code) 240 } 241 file, err := os.Open("validation_code") 242 if err != nil { 243 s.Errorf("No validation code file found!\n") 244 } 245 code, err := io.ReadAll(file) 246 if err != nil { 247 s.Errorf("Error reading validation code file contents!\n") 248 } 249 h_alias := getHAlias("abc@test") 250 trimCode := strings.Trim(string(code), " \r\n") 251 solution := util.GenerateSolution("myinbox@xyz", trimCode) 252 solutionJSON := "{\"solution\": \"" + solution + "\"}" 253 req, _ = http.NewRequest("POST", "/"+h_alias, bytes.NewBuffer([]byte(solutionJSON))) 254 response = executeRequest(req) 255 if http.StatusNoContent != response.Code { 256 s.Errorf("Expected response code %d. Got %d\n", http.StatusNoContent, response.Code) 257 } 258 req, _ = http.NewRequest("POST", "/register/test", bytes.NewBuffer(validRegisterRequestUnmodified)) 259 response = executeRequest(req) 260 261 if http.StatusOK != response.Code { 262 s.Errorf("Expected response code %d. Got %d\n", http.StatusOK, response.Code) 263 } 264 265 } 266 267 func TestReRegisterRequestTooMany(s *testing.T) { 268 t.ClearDatabase() 269 270 req, _ := http.NewRequest("POST", "/register/test", bytes.NewBuffer(validRegisterRequest)) 271 response := executeRequest(req) 272 273 if http.StatusAccepted != response.Code { 274 s.Errorf("Expected response code %d. Got %d\n", http.StatusAccepted, response.Code) 275 } 276 req, _ = http.NewRequest("POST", "/register/test", bytes.NewBuffer(validRegisterRequest)) 277 response = executeRequest(req) 278 279 if http.StatusAccepted != response.Code { 280 s.Errorf("Expected response code %d. Got %d\n", http.StatusAccepted, response.Code) 281 } 282 req, _ = http.NewRequest("POST", "/register/test", bytes.NewBuffer(validRegisterRequest)) 283 response = executeRequest(req) 284 285 if http.StatusAccepted != response.Code { 286 s.Errorf("Expected response code %d. Got %d\n", http.StatusAccepted, response.Code) 287 } 288 req, _ = http.NewRequest("POST", "/register/test", bytes.NewBuffer(validRegisterRequest)) 289 response = executeRequest(req) 290 291 if http.StatusTooManyRequests != response.Code { 292 s.Errorf("Expected response code %d. Got %d\n", http.StatusTooManyRequests, response.Code) 293 } 294 295 } 296 297 func TestSolutionRequestTooMany(s *testing.T) { 298 t.ClearDatabase() 299 300 req, _ := http.NewRequest("POST", "/register/test", bytes.NewBuffer(validRegisterRequest)) 301 response := executeRequest(req) 302 303 if http.StatusAccepted != response.Code { 304 s.Errorf("Expected response code %d. Got %d\n", http.StatusAccepted, response.Code) 305 } 306 h_alias := getHAlias("abc@test") 307 solution := util.GenerateSolution("myinbox@xyz", "wrongSolution") 308 solutionJSON := "{\"solution\": \"" + solution + "\"}" 309 req, _ = http.NewRequest("POST", "/"+h_alias, bytes.NewBuffer([]byte(solutionJSON))) 310 response = executeRequest(req) 311 if http.StatusForbidden != response.Code { 312 s.Errorf("Expected response code %d. Got %d\n", http.StatusForbidden, response.Code) 313 } 314 req, _ = http.NewRequest("POST", "/"+h_alias, bytes.NewBuffer([]byte(solutionJSON))) 315 response = executeRequest(req) 316 if http.StatusForbidden != response.Code { 317 s.Errorf("Expected response code %d. Got %d\n", http.StatusForbidden, response.Code) 318 } 319 req, _ = http.NewRequest("POST", "/"+h_alias, bytes.NewBuffer([]byte(solutionJSON))) 320 response = executeRequest(req) 321 if http.StatusForbidden != response.Code { 322 s.Errorf("Expected response code %d. Got %d\n", http.StatusForbidden, response.Code) 323 } 324 req, _ = http.NewRequest("POST", "/"+h_alias, bytes.NewBuffer([]byte(solutionJSON))) 325 response = executeRequest(req) 326 if http.StatusTooManyRequests != response.Code { 327 s.Errorf("Expected response code %d. Got %d\n", http.StatusTooManyRequests, response.Code) 328 } 329 330 } 331 332 func TestRegisterRequestWrongTargetUri(s *testing.T) { 333 t.ClearDatabase() 334 335 req, _ := http.NewRequest("POST", "/register/test", bytes.NewBuffer(validRegisterRequest)) 336 response := executeRequest(req) 337 338 if http.StatusAccepted != response.Code { 339 s.Errorf("Expected response code %d. Got %d\n", http.StatusAccepted, response.Code) 340 } 341 file, err := os.Open("validation_code") 342 if err != nil { 343 s.Errorf("No validation code file found!\n") 344 } 345 code, err := io.ReadAll(file) 346 if err != nil { 347 s.Errorf("Error reading validation code file contents!\n") 348 } 349 h_alias := getHAlias("abc@test") 350 trimCode := strings.Trim(string(code), " \r\n") 351 solution := util.GenerateSolution("myinox@xyz", trimCode) 352 solutionJSON := "{\"solution\": \"" + solution + "\"}" 353 req, _ = http.NewRequest("POST", "/"+h_alias, bytes.NewBuffer([]byte(solutionJSON))) 354 response = executeRequest(req) 355 if http.StatusForbidden != response.Code { 356 s.Errorf("Expected response code %d. Got %d\n", http.StatusForbidden, response.Code) 357 } 358 } 359 360 func TestUnsupportedAliasType(s *testing.T) { 361 t.ClearDatabase() 362 363 req, _ := http.NewRequest("POST", "/register/email", bytes.NewBuffer(validRegisterRequest)) 364 response := executeRequest(req) 365 366 if http.StatusNotFound != response.Code { 367 s.Errorf("Expected response code %d. Got %d\n", http.StatusNotFound, response.Code) 368 } 369 } 370 371 func TestPaymentRequiredMethod(s *testing.T) { 372 t.ClearDatabase() 373 t.MonthlyFee = "KUDOS:5" 374 req, _ := http.NewRequest("POST", "/register/test-cost", bytes.NewBuffer(validRegisterRequest)) 375 376 response := executeRequest(req) 377 t.MonthlyFee = "KUDOS:0" 378 if http.StatusPaymentRequired != response.Code { 379 s.Errorf("Expected response code %d. Got %d\n", http.StatusPaymentRequired, response.Code) 380 } 381 }