taldir

Directory service to resolve wallet mailboxes by messenger addresses
Log | Files | Refs | Submodules | README | LICENSE

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 }