package tokenboard import ( "errors" "git.openprivacy.ca/cwtch.im/tapir/applications" "git.openprivacy.ca/cwtch.im/tapir/networks/tor" "git.openprivacy.ca/cwtch.im/tapir/primitives" "git.openprivacy.ca/cwtch.im/tapir/primitives/auditable" "git.openprivacy.ca/cwtch.im/tapir/primitives/privacypass" "git.openprivacy.ca/openprivacy/connectivity" torProvider "git.openprivacy.ca/openprivacy/connectivity/tor" "git.openprivacy.ca/openprivacy/log" "os" "runtime" "sync" "testing" "time" ) type Handler struct { Store *auditable.Store } func (h Handler) HandleNewMessages(previousLastCommit []byte) { log.Debugf("Handling Messages After %x", previousLastCommit) messages := h.Store.GetMessagesAfter(previousLastCommit) for _, message := range messages { log.Debugf("Message %s", message) } } type FreePaymentHandler struct { tokens []*privacypass.Token TokenService *privacypass.TokenServer ACN connectivity.ACN ServerHostname string } func (fph *FreePaymentHandler) MakePayment() { id, sk := primitives.InitializeEphemeralIdentity() client := new(tor.BaseOnionService) client.Init(fph.ACN, sk, &id) tokenApplication := new(applications.TokenApplication) tokenApplication.TokenService = fph.TokenService powTokenApp := new(applications.ApplicationChain). ChainApplication(new(applications.ProofOfWorkApplication), applications.SuccessfulProofOfWorkCapability). ChainApplication(tokenApplication, applications.HasTokensCapability) client.Connect(fph.ServerHostname, powTokenApp) conn, err := client.WaitForCapabilityOrClose(fph.ServerHostname, applications.HasTokensCapability) if err == nil { powtapp, _ := conn.App().(*applications.TokenApplication) fph.tokens = append(fph.tokens, powtapp.Tokens...) log.Debugf("Transcript: %v", powtapp.Transcript().OutputTranscriptToAudit()) conn.Close() return } log.Debugf("Error making payment: %v", err) } func (fph *FreePaymentHandler) NextToken(data []byte, hostname string) (privacypass.SpentToken, error) { if len(fph.tokens) == 0 { return privacypass.SpentToken{}, errors.New("No more tokens") } token := fph.tokens[0] fph.tokens = fph.tokens[1:] return token.SpendToken(append(data, hostname...)), nil } func TestTokenBoardApp(t *testing.T) { // numRoutinesStart := runtime.NumGoroutine() log.SetLevel(log.LevelDebug) log.Infof("Number of goroutines open at start: %d", runtime.NumGoroutine()) os.MkdirAll("./tor/", 0700) builder := new(torProvider.TorrcBuilder) builder.WithHashedPassword("tapir-integration-test").Build("./tor/torrc") // Connect to Tor acn, err := torProvider.NewTorACNWithAuth("./", "", 9051, torProvider.HashedPasswordAuthenticator{Password: "tapir-integration-test"}) if err != nil { t.Fatalf("could not launch ACN %v", err) } acn.WaitTillBootstrapped() // Generate Server Key sid, sk := primitives.InitializeEphemeralIdentity() tokenService := privacypass.NewTokenServer() serverAuditableStore := new(auditable.Store) serverAuditableStore.Init(sid) clientAuditableStore := new(auditable.Store) // Only initialize with public parameters sidpubk := sid.PublicKey() publicsid := primitives.InitializeIdentity("server", nil, &sidpubk) clientAuditableStore.Init(publicsid) // Init the Server running the Simple App. service := new(tor.BaseOnionService) service.Init(acn, sk, &sid) // Goroutine Management sg := new(sync.WaitGroup) sg.Add(1) go func() { service.Listen(NewTokenBoardServer(tokenService, serverAuditableStore)) sg.Done() }() // Init the Server running the PoW Token App. powTokenService := new(tor.BaseOnionService) spowid, spowk := primitives.InitializeEphemeralIdentity() powTokenService.Init(acn, spowk, &spowid) sg.Add(1) go func() { tokenApplication := new(applications.TokenApplication) tokenApplication.TokenService = tokenService powTokenApp := new(applications.ApplicationChain). ChainApplication(new(applications.ProofOfWorkApplication), applications.SuccessfulProofOfWorkCapability). ChainApplication(tokenApplication, applications.HasTokensCapability) powTokenService.Listen(powTokenApp) sg.Done() }() time.Sleep(time.Second * 60) // wait for server to initialize id, sk := primitives.InitializeEphemeralIdentity() client := new(tor.BaseOnionService) client.Init(acn, sk, &id) client.Connect(sid.Hostname(), NewTokenBoardClient(clientAuditableStore, Handler{Store: clientAuditableStore}, &FreePaymentHandler{ACN: acn, TokenService: tokenService, ServerHostname: spowid.Hostname()})) client.WaitForCapabilityOrClose(sid.Hostname(), applications.AuthCapability) conn, _ := client.GetConnection(sid.Hostname()) tba, _ := conn.App().(*Client) tba.PurchaseTokens() tba.Post([]byte("HELLO 1")) tba.Post([]byte("HELLO 2")) tba.Post([]byte("HELLO 3")) tba.Post([]byte("HELLO 4")) tba.Post([]byte("HELLO 5")) tba.Replay() time.Sleep(time.Second * 10) // We have to wait for the async replay request! tba.Post([]byte("HELLO 6")) tba.Post([]byte("HELLO 7")) tba.Post([]byte("HELLO 8")) tba.Post([]byte("HELLO 9")) tba.Post([]byte("HELLO 10")) tba.Replay() time.Sleep(time.Second * 10) // We have to wait for the async replay request! if tba.Post([]byte("HELLO 11")) { t.Errorf("Post should have failed.") } time.Sleep(time.Second * 10) acn.Close() sg.Wait() }