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