main_test.go (12622B)
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 "database/sql" 24 "fmt" 25 "io" 26 "log" 27 "net/http" 28 "net/http/httptest" 29 "os" 30 "strings" 31 "testing" 32 33 "github.com/schanzen/taler-go/pkg/merchant" 34 talerutil "github.com/schanzen/taler-go/pkg/util" 35 "gopkg.in/ini.v1" 36 _ "taler.net/taldir/cmd/taldir-server" 37 "taler.net/taldir/internal/util" 38 taldir "taler.net/taldir/pkg/taldir" 39 ) 40 41 var t taldir.Taldir 42 43 // Note: This duration will be rounded down to 20 Months (= 51840000000000) 44 var validRegisterRequest = []byte(` 45 { 46 "alias": "abc@test", 47 "target_uri": "myinbox@xyz", 48 "duration": 53135000000000 49 } 50 `) 51 52 var validRegisterRequestUnmodified = []byte(` 53 { 54 "alias": "abc@test", 55 "target_uri": "myinbox@xyz", 56 "duration": 0 57 } 58 `) 59 60 var newOrderMockResponse = ` 61 { 62 "order_id": "testOrder1234", 63 "taler_pay_uri": "payto://ladida" 64 } 65 ` 66 67 var newOrderStatusUnpaidMockResponse = ` 68 { 69 "order_status": "unpaid", 70 "taler_pay_uri": "payto://somedude" 71 } 72 ` 73 74 const merchantConfigResponse = `{ 75 "currency": "KUDOS", 76 "currencies": { 77 "KUDOS": { 78 "name": "Kudos (Taler Demonstrator)", 79 "currency": "KUDOS", 80 "num_fractional_input_digits": 2, 81 "num_fractional_normal_digits": 2, 82 "num_fractional_trailing_zero_digits": 2, 83 "alt_unit_names": { 84 "0": "ク" 85 } 86 } 87 }, 88 "exchanges": [ 89 { 90 "master_pub": "F80MFRG8HVH6R9CQ47KRFQSJP3T6DBJ4K1D9B703RJY3Z39TBMJ0", 91 "currency": "KUDOS", 92 "base_url": "https://exchange.demo.taler.net/" 93 } 94 ], 95 "implementation": "urn:net:taler:specs:taler-merchant:c-reference", 96 "name": "taler-merchant", 97 "version": "18:0:15" 98 }` 99 100 func TestMain(m *testing.M) { 101 cfg, err := ini.LooseLoad("testdata/taldir-test.conf") 102 if err != nil { 103 log.Fatalf("Failed to read config: %v", err) 104 } 105 psqlconn := cfg.Section("taldir-pq").Key("connection_string").MustString("postgres:///taler-directory") 106 segments := strings.Split(strings.Split(psqlconn, "?")[0], "/") 107 dbName := segments[len(segments)-1] 108 109 db, err := sql.Open("postgres", psqlconn) 110 if err != nil { 111 log.Panic(err) 112 } 113 defer db.Close() 114 err = talerutil.DBInit(db, "../..", dbName, "taler-directory") 115 if err != nil { 116 log.Fatalf("Failed to apply versioning or patches: %v", err) 117 } 118 merchServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 119 if r.URL.Path == "/config" { 120 w.WriteHeader(http.StatusOK) 121 w.Write([]byte(merchantConfigResponse)) 122 return 123 } 124 if !strings.HasPrefix(r.URL.Path, "/private/orders") { 125 log.Printf("Expected to request '/private/orders', got: %s\n", r.URL.Path) 126 return 127 } 128 if r.Method == http.MethodPost { 129 jsonResp := fmt.Sprintf("{\"order_id\":\"%s\"}", "uniqueOrderId") 130 w.WriteHeader(http.StatusOK) 131 w.Write([]byte(jsonResp)) 132 } else { 133 if r.Header.Get("PaidIndicator") == "yes" { 134 jsonResp := "{\"order_status\":\"paid\"}" 135 w.WriteHeader(http.StatusOK) 136 w.Write([]byte(jsonResp)) 137 } else { 138 jsonResp := "{\"order_status\":\"unpaid\", \"taler_pay_uri\": \"somepaytouri\"}" 139 w.WriteHeader(http.StatusOK) 140 w.Write([]byte(jsonResp)) 141 } 142 } 143 })) 144 defer merchServer.Close() 145 merch := merchant.NewMerchant(merchServer.URL, "supersecret") 146 t.Initialize(taldir.TaldirConfig{ 147 Ini: cfg, 148 Version: "testing", 149 Datahome: "./testdata", 150 Db: db, 151 Merchant: merch, 152 Loglevel: taldir.LogDebug, 153 }) 154 log.Printf("have %d validators", len(t.Validators)) 155 log.Print(t.Validators) 156 code := m.Run() 157 t.ClearDatabase() 158 os.Exit(code) 159 } 160 161 func getHAlias(alias string) string { 162 ha := taldir.HashAlias("test", alias) 163 return util.Base32CrockfordEncode(ha) 164 } 165 166 func TestNoEntry(s *testing.T) { 167 t.ClearDatabase() 168 169 hAlias := getHAlias("jdoe@example.com") 170 req, _ := http.NewRequest("GET", "/"+hAlias, nil) 171 response := executeRequest(req) 172 173 if http.StatusNotFound != response.Code { 174 s.Errorf("Expected response code %d. Got %d\n", http.StatusNotFound, response.Code) 175 } 176 } 177 178 func executeRequest(req *http.Request) *httptest.ResponseRecorder { 179 rr := httptest.NewRecorder() 180 t.Router.ServeHTTP(rr, req) 181 return rr 182 } 183 184 func TestRegisterRequest(s *testing.T) { 185 t.ClearDatabase() 186 187 req, _ := http.NewRequest("POST", "/register/test", bytes.NewBuffer(validRegisterRequest)) 188 response := executeRequest(req) 189 190 if http.StatusAccepted != response.Code { 191 s.Errorf("Expected response code %d. Got %d, with %s\n", http.StatusAccepted, response.Code, response.Body) 192 } 193 file, err := os.Open("validation_code") 194 if err != nil { 195 s.Errorf("No validation code file found!\n") 196 } 197 code, err := io.ReadAll(file) 198 if err != nil { 199 s.Errorf("Error reading validation code file contents!\n") 200 } 201 hAlias := getHAlias("abc@test") 202 trimCode := strings.Trim(string(code), " \r\n") 203 solution := util.GenerateSolution("myinbox@xyz", trimCode) 204 solutionJSON := "{\"solution\": \"" + solution + "\"}" 205 req, _ = http.NewRequest("POST", "/"+hAlias, bytes.NewBuffer([]byte(solutionJSON))) 206 response = executeRequest(req) 207 if http.StatusNoContent != response.Code { 208 s.Errorf("Expected response code %d. Got %d\n", http.StatusNoContent, response.Code) 209 } 210 } 211 212 func TestRegisterQRPageRequest(s *testing.T) { 213 t.ClearDatabase() 214 215 req, _ := http.NewRequest("POST", "/register/test", bytes.NewBuffer(validRegisterRequest)) 216 response := executeRequest(req) 217 218 if http.StatusAccepted != response.Code { 219 s.Errorf("Expected response code %d. Got %d\n", http.StatusAccepted, response.Code) 220 } 221 req, _ = http.NewRequest("GET", "/register/NonSenseAddr/NonSenseCode", nil) 222 response = executeRequest(req) 223 if http.StatusNotFound != response.Code { 224 s.Errorf("Expected response code %d. Got %d\n", http.StatusNotFound, response.Code) 225 } 226 227 file, err := os.Open("validation_code") 228 if err != nil { 229 s.Errorf("No validation code file found!\n") 230 } 231 code, err := io.ReadAll(file) 232 if err != nil { 233 s.Errorf("Error reading validation code file contents!\n") 234 } 235 hAlias := getHAlias("abc@test") 236 trimCode := strings.Trim(string(code), " \r\n") 237 req, _ = http.NewRequest("GET", "/register/"+hAlias+"/"+trimCode+"?alias="+"abc@test", nil) 238 response = executeRequest(req) 239 if http.StatusOK != response.Code { 240 s.Errorf("Expected response code %d. Got %d\n", http.StatusOK, response.Code) 241 } 242 } 243 244 func TestReRegisterRequest(s *testing.T) { 245 t.ClearDatabase() 246 247 req, _ := http.NewRequest("POST", "/register/test", bytes.NewBuffer(validRegisterRequest)) 248 response := executeRequest(req) 249 250 if http.StatusAccepted != response.Code { 251 s.Errorf("Expected response code %d. Got %d\n", http.StatusAccepted, response.Code) 252 } 253 file, err := os.Open("validation_code") 254 if err != nil { 255 s.Errorf("No validation code file found!\n") 256 } 257 code, err := io.ReadAll(file) 258 if err != nil { 259 s.Errorf("Error reading validation code file contents!\n") 260 } 261 hAlias := getHAlias("abc@test") 262 trimCode := strings.Trim(string(code), " \r\n") 263 solution := util.GenerateSolution("myinbox@xyz", trimCode) 264 solutionJSON := "{\"solution\": \"" + solution + "\"}" 265 req, _ = http.NewRequest("POST", "/"+hAlias, bytes.NewBuffer([]byte(solutionJSON))) 266 response = executeRequest(req) 267 if http.StatusNoContent != response.Code { 268 s.Errorf("Expected response code %d. Got %d\n", http.StatusNoContent, response.Code) 269 } 270 req, _ = http.NewRequest("POST", "/register/test", bytes.NewBuffer(validRegisterRequestUnmodified)) 271 response = executeRequest(req) 272 273 if http.StatusOK != response.Code { 274 s.Errorf("Expected response code %d. Got %d\n", http.StatusOK, response.Code) 275 } 276 277 } 278 279 func TestReRegisterRequestTooMany(s *testing.T) { 280 t.ClearDatabase() 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.StatusAccepted != response.Code { 292 s.Errorf("Expected response code %d. Got %d\n", http.StatusAccepted, response.Code) 293 } 294 req, _ = http.NewRequest("POST", "/register/test", bytes.NewBuffer(validRegisterRequest)) 295 response = executeRequest(req) 296 297 if http.StatusAccepted != response.Code { 298 s.Errorf("Expected response code %d. Got %d\n", http.StatusAccepted, response.Code) 299 } 300 req, _ = http.NewRequest("POST", "/register/test", bytes.NewBuffer(validRegisterRequest)) 301 response = executeRequest(req) 302 303 if http.StatusTooManyRequests != response.Code { 304 s.Errorf("Expected response code %d. Got %d\n", http.StatusTooManyRequests, response.Code) 305 } 306 307 } 308 309 func TestSolutionRequestTooMany(s *testing.T) { 310 t.ClearDatabase() 311 312 req, _ := http.NewRequest("POST", "/register/test", bytes.NewBuffer(validRegisterRequest)) 313 response := executeRequest(req) 314 315 if http.StatusAccepted != response.Code { 316 s.Errorf("Expected response code %d. Got %d\n", http.StatusAccepted, response.Code) 317 } 318 hAlias := getHAlias("abc@test") 319 solution := util.GenerateSolution("myinbox@xyz", "wrongSolution") 320 solutionJSON := "{\"solution\": \"" + solution + "\"}" 321 req, _ = http.NewRequest("POST", "/"+hAlias, bytes.NewBuffer([]byte(solutionJSON))) 322 response = executeRequest(req) 323 if http.StatusForbidden != response.Code { 324 s.Errorf("Expected response code %d. Got %d\n", http.StatusForbidden, response.Code) 325 } 326 req, _ = http.NewRequest("POST", "/"+hAlias, bytes.NewBuffer([]byte(solutionJSON))) 327 response = executeRequest(req) 328 if http.StatusForbidden != response.Code { 329 s.Errorf("Expected response code %d. Got %d\n", http.StatusForbidden, response.Code) 330 } 331 req, _ = http.NewRequest("POST", "/"+hAlias, bytes.NewBuffer([]byte(solutionJSON))) 332 response = executeRequest(req) 333 if http.StatusForbidden != response.Code { 334 s.Errorf("Expected response code %d. Got %d\n", http.StatusForbidden, response.Code) 335 } 336 req, _ = http.NewRequest("POST", "/"+hAlias, bytes.NewBuffer([]byte(solutionJSON))) 337 response = executeRequest(req) 338 if http.StatusTooManyRequests != response.Code { 339 s.Errorf("Expected response code %d. Got %d\n", http.StatusTooManyRequests, response.Code) 340 } 341 342 } 343 344 func TestRegisterRequestWrongTargetUri(s *testing.T) { 345 t.ClearDatabase() 346 347 req, _ := http.NewRequest("POST", "/register/test", bytes.NewBuffer(validRegisterRequest)) 348 response := executeRequest(req) 349 350 if http.StatusAccepted != response.Code { 351 s.Errorf("Expected response code %d. Got %d\n", http.StatusAccepted, response.Code) 352 } 353 file, err := os.Open("validation_code") 354 if err != nil { 355 s.Errorf("No validation code file found!\n") 356 } 357 code, err := io.ReadAll(file) 358 if err != nil { 359 s.Errorf("Error reading validation code file contents!\n") 360 } 361 hAlias := getHAlias("abc@test") 362 trimCode := strings.Trim(string(code), " \r\n") 363 solution := util.GenerateSolution("myinox@xyz", trimCode) 364 solutionJSON := "{\"solution\": \"" + solution + "\"}" 365 req, _ = http.NewRequest("POST", "/"+hAlias, bytes.NewBuffer([]byte(solutionJSON))) 366 response = executeRequest(req) 367 if http.StatusForbidden != response.Code { 368 s.Errorf("Expected response code %d. Got %d\n", http.StatusForbidden, response.Code) 369 } 370 } 371 372 func TestUnsupportedAliasType(s *testing.T) { 373 t.ClearDatabase() 374 375 req, _ := http.NewRequest("POST", "/register/email", bytes.NewBuffer(validRegisterRequest)) 376 response := executeRequest(req) 377 378 if http.StatusNotFound != response.Code { 379 s.Errorf("Expected response code %d. Got %d\n", http.StatusNotFound, response.Code) 380 } 381 } 382 383 func TestPaymentRequiredMethod(s *testing.T) { 384 t.ClearDatabase() 385 t.MonthlyFee = "KUDOS:5" 386 req, _ := http.NewRequest("POST", "/register/test-cost", bytes.NewBuffer(validRegisterRequest)) 387 388 response := executeRequest(req) 389 t.MonthlyFee = "KUDOS:0" 390 if http.StatusPaymentRequired != response.Code { 391 s.Errorf("Expected response code %d. Got %d\n", http.StatusPaymentRequired, response.Code) 392 } 393 }