Skip to content

Commit

Permalink
Merge pull request #68 from bitcoin-sv/feat-679-contacts
Browse files Browse the repository at this point in the history
feat(SPV-679) finalize contacts
  • Loading branch information
chris-4chain committed May 8, 2024
2 parents dc359a7 + 61fdcff commit ba61334
Show file tree
Hide file tree
Showing 20 changed files with 521 additions and 49 deletions.
7 changes: 7 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ const (
EnvHttpServerCookieSecure = "http.server.cookie.secure"
// EnvHttpServerCorsAllowedDomains http server cors origin allowed domains.
EnvHttpServerCorsAllowedDomains = "http.server.cors.allowedDomains"
// EnvHttpServerSessionSecret gin session store secret to encrypt session data in database.
EnvHttpServerSessionSecret = "http.server.session.secret" // nolint: gosec
)

// Define basic spv-wallet config keys.
Expand Down Expand Up @@ -76,6 +78,11 @@ const (
EnvEndpointsExchangeRate = "endpoints.exchangeRate"
)

const (
EnvContactsPasscodePeriod = "contacts.passcode.period"
EnvContactsPasscodeDigits = "contacts.passcode.digits"
)

// Config returns strongly typed config values.
type Config struct {
Db *Db
Expand Down
7 changes: 7 additions & 0 deletions config/viper.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ func NewViperConfig(appname string) *Config {
setLoggingDefaults()
setEndpointsDefaults()
setWebsocketDefaults()
setContactsDefaults()
return &Config{}
}

Expand Down Expand Up @@ -49,6 +50,7 @@ func setHttpServerDefaults() {
viper.SetDefault(EnvHttpServerCookieDomain, "localhost")
viper.SetDefault(EnvHttpServerCookieSecure, false)
viper.SetDefault(EnvHttpServerCorsAllowedDomains, []string{})
viper.SetDefault(EnvHttpServerSessionSecret, "secret")
}

// setSpvWalletDefaults sets default values for spv-wallet connection.
Expand Down Expand Up @@ -82,3 +84,8 @@ func setWebsocketDefaults() {
viper.SetDefault(EnvWebsocketHistoryMax, 300)
viper.SetDefault(EnvWebsocketHistoryTtl, 10)
}

func setContactsDefaults() {
viper.SetDefault(EnvContactsPasscodePeriod, uint(3600)) //1h
viper.SetDefault(EnvContactsPasscodeDigits, uint(2))
}
88 changes: 88 additions & 0 deletions domain/contacts/contacts_service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package contacts

import (
"context"

"github.com/bitcoin-sv/spv-wallet-go-client/transports"
"github.com/bitcoin-sv/spv-wallet-web-backend/config"
"github.com/bitcoin-sv/spv-wallet-web-backend/domain/users"
"github.com/bitcoin-sv/spv-wallet/models"
"github.com/rs/zerolog"
"github.com/spf13/viper"
)

type ContactsService struct {
adminWalletClient users.AdminWalletClient
walletClientFactory users.WalletClientFactory
log *zerolog.Logger
}

func NewContactsService(adminWalletClient users.AdminWalletClient, walletClientFactory users.WalletClientFactory, log *zerolog.Logger) *ContactsService {
transactionServiceLogger := log.With().Str("service", "contacts-service").Logger()
return &ContactsService{
adminWalletClient: adminWalletClient,
walletClientFactory: walletClientFactory,
log: &transactionServiceLogger,
}
}

func (s *ContactsService) UpsertContact(ctx context.Context, accessKey, paymail, fullName string, metadata *models.Metadata) (*models.Contact, error) {
userWalletClient, err := s.walletClientFactory.CreateWithAccessKey(accessKey)
if err != nil {
return nil, err
}

return userWalletClient.UpsertContact(ctx, paymail, fullName, metadata)
}

func (s *ContactsService) AcceptContact(ctx context.Context, accessKey, paymail string) error {
userWalletClient, err := s.walletClientFactory.CreateWithAccessKey(accessKey)
if err != nil {
return err
}

return userWalletClient.AcceptContact(ctx, paymail)
}

func (s *ContactsService) RejectContact(ctx context.Context, accessKey, paymail string) error {
userWalletClient, err := s.walletClientFactory.CreateWithAccessKey(accessKey)
if err != nil {
return err
}

return userWalletClient.RejectContact(ctx, paymail)
}

func (s *ContactsService) ConfirmContact(ctx context.Context, xPriv string, contact *models.Contact, passcode, requesterPaymail string) error {
userWalletClient, err := s.walletClientFactory.CreateWithXpriv(xPriv)
if err != nil {
return err
}

return userWalletClient.ConfirmContact(ctx, contact, passcode, requesterPaymail, getConfPeriod(), getConfDigits())
}

func (s *ContactsService) GetContacts(ctx context.Context, accessKey string, conditions map[string]interface{}, metadata *models.Metadata, queryParams *transports.QueryParams) ([]*models.Contact, error) {
userWalletClient, err := s.walletClientFactory.CreateWithAccessKey(accessKey)
if err != nil {
return nil, err
}

return userWalletClient.GetContacts(ctx, conditions, metadata, queryParams)
}

func (s *ContactsService) GenerateTotpForContact(ctx context.Context, xPriv string, contact *models.Contact) (string, error) {
userWalletClient, err := s.walletClientFactory.CreateWithXpriv(xPriv) //xPriv instead of accessKey because it is necessary to calculate the shared secret
if err != nil {
return "", err
}

return userWalletClient.GenerateTotpForContact(contact, getConfPeriod(), getConfDigits())
}

func getConfPeriod() uint {
return viper.GetUint(config.EnvContactsPasscodePeriod)
}
func getConfDigits() uint {
return viper.GetUint(config.EnvContactsPasscodeDigits)
}
3 changes: 3 additions & 0 deletions domain/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package domain
import (
db_users "github.com/bitcoin-sv/spv-wallet-web-backend/data/users"
"github.com/bitcoin-sv/spv-wallet-web-backend/domain/config"
"github.com/bitcoin-sv/spv-wallet-web-backend/domain/contacts"
"github.com/bitcoin-sv/spv-wallet-web-backend/domain/transactions"
"github.com/bitcoin-sv/spv-wallet-web-backend/domain/users"
"github.com/bitcoin-sv/spv-wallet-web-backend/transports/spvwallet"
Expand All @@ -14,6 +15,7 @@ import (
type Services struct {
UsersService *users.UserService
TransactionsService *transactions.TransactionService
ContactsService *contacts.ContactsService
WalletClientFactory users.WalletClientFactory
ConfigService *config.ConfigService
}
Expand All @@ -32,6 +34,7 @@ func NewServices(usersRepo *db_users.UsersRepository, log *zerolog.Logger) (*Ser
return &Services{
UsersService: uService,
TransactionsService: transactions.NewTransactionService(adminWalletClient, walletClientFactory, log),
ContactsService: contacts.NewContactsService(adminWalletClient, walletClientFactory, log),
WalletClientFactory: walletClientFactory,
ConfigService: config.NewConfigService(adminWalletClient, log),
}, nil
Expand Down
2 changes: 1 addition & 1 deletion domain/transactions/transactions_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type TransactionService struct {

// NewTransactionService creates new transaction service.
func NewTransactionService(adminWalletClient users.AdminWalletClient, walletClientFactory users.WalletClientFactory, log *zerolog.Logger) *TransactionService {
transactionServiceLogger := log.With().Str("service", "user-service").Logger()
transactionServiceLogger := log.With().Str("service", "transaction-service").Logger()
return &TransactionService{
adminWalletClient: adminWalletClient,
walletClientFactory: walletClientFactory,
Expand Down
8 changes: 8 additions & 0 deletions domain/users/interfaces.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package users

import (
"context"
"time"

"github.com/bitcoin-sv/spv-wallet-go-client/transports"
Expand Down Expand Up @@ -69,6 +70,13 @@ type (
GetTransactionsCount() (int64, error)
CreateAndFinalizeTransaction(recipients []*transports.Recipients, metadata *models.Metadata) (DraftTransaction, error)
RecordTransaction(hex, draftTxId string, metadata *models.Metadata) (*models.Transaction, error)
// Contacts methods
UpsertContact(ctx context.Context, paymail, fullName string, metadata *models.Metadata) (*models.Contact, transports.ResponseError)
AcceptContact(ctx context.Context, paymail string) transports.ResponseError
RejectContact(ctx context.Context, paymail string) transports.ResponseError
ConfirmContact(ctx context.Context, contact *models.Contact, passcode, requesterPaymail string, period, digits uint) transports.ResponseError
GetContacts(ctx context.Context, conditions map[string]interface{}, metadata *models.Metadata, queryParams *transports.QueryParams) ([]*models.Contact, transports.ResponseError)
GenerateTotpForContact(contact *models.Contact, period, digits uint) (string, error)
}

// AdminWalletClient defines methods which are available for an admin with admin key.
Expand Down
3 changes: 2 additions & 1 deletion domain/users/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
type User struct {
Id int `json:"id"`
Email string `json:"email"`
Xpriv string `json:"-"`
Xpriv string `json:"-"` //xPriv encrypted with user password
Paymail string `json:"paymail"`
CreatedAt time.Time `json:"created_at"`
}
Expand All @@ -24,6 +24,7 @@ type AuthenticatedUser struct {
User *User
AccessKey AccessKey
Balance Balance
Xpriv string `json:"-"` //xPriv should not be exposed to the client
}

// AccessKey is a struct that contains access key data.
Expand Down
1 change: 1 addition & 0 deletions domain/users/users_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ func (s *UserService) SignInUser(email, password string) (*AuthenticatedUser, er
Key: accessKey.GetAccessKey(),
},
Balance: *balance,
Xpriv: decryptedXpriv,
}

return signInUser, nil
Expand Down
6 changes: 4 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ go 1.21.5

require (
github.com/avast/retry-go/v4 v4.5.1
github.com/bitcoin-sv/spv-wallet-go-client v0.9.0
github.com/bitcoin-sv/spv-wallet/models v0.24.0
github.com/bitcoin-sv/spv-wallet-go-client v1.0.0-beta.2
github.com/bitcoin-sv/spv-wallet/models v1.0.0-beta.2
github.com/brianvoe/gofakeit/v6 v6.28.0
github.com/centrifugal/centrifuge v0.31.0
github.com/gin-contrib/sessions v0.0.5
Expand All @@ -28,6 +28,7 @@ require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/bitcoinschema/go-bitcoin/v2 v2.0.5 // indirect
github.com/bitcoinsv/bsvd v0.0.0-20190609155523-4c29707f7173 // indirect
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
github.com/bytedance/sonic v1.11.2 // indirect
github.com/centrifugal/protocol v0.12.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
Expand Down Expand Up @@ -61,6 +62,7 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/pquerna/otp v1.4.0 // indirect
github.com/prometheus/client_golang v1.19.0 // indirect
github.com/prometheus/client_model v0.6.0 // indirect
github.com/prometheus/common v0.50.0 // indirect
Expand Down
12 changes: 8 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@ github.com/avast/retry-go/v4 v4.5.1 h1:AxIx0HGi4VZ3I02jr78j5lZ3M6x1E0Ivxa6b0pUUh
github.com/avast/retry-go/v4 v4.5.1/go.mod h1:/sipNsvNB3RRuT5iNcb6h73nw3IBmXJ/H3XrCQYSOpc=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bitcoin-sv/spv-wallet-go-client v0.9.0 h1:ncSEaFsCcTYWN4toD5BvVQ8rTdIeNpYCH1DCZZO3VqE=
github.com/bitcoin-sv/spv-wallet-go-client v0.9.0/go.mod h1:thz4lwT/Sx1ag5o0IWhMcQoGobt26wemKRgx5uL/7V8=
github.com/bitcoin-sv/spv-wallet/models v0.24.0 h1:cIfi2noDfRWaFt0VMOECwF8H9OsJFdP0T03XK4BULe0=
github.com/bitcoin-sv/spv-wallet/models v0.24.0/go.mod h1:P8vXF1mPg1Zh3xSvB9yqwuPJfOR8Tt/SAG2FYztwENI=
github.com/bitcoin-sv/spv-wallet-go-client v1.0.0-beta.2 h1:SV/3ZGR3+DgNipOKgdDAY0aUYXQOu6xdaGjix6loGE8=
github.com/bitcoin-sv/spv-wallet-go-client v1.0.0-beta.2/go.mod h1:aC6hqUEXbMDyjTubrDWrrzGA6bydLr6JNEzfVwUeCyM=
github.com/bitcoin-sv/spv-wallet/models v1.0.0-beta.2 h1:kDCCnBgyGXPbP9rnrbYIGyasFXAobdGj7Sxya42XOZM=
github.com/bitcoin-sv/spv-wallet/models v1.0.0-beta.2/go.mod h1:i3txysriHpprqYd3u97wEQsC4/jn+KHcyFOmuFYMw8M=
github.com/bitcoinschema/go-bitcoin/v2 v2.0.5 h1:Sgh5Eb746Zck/46rFDrZZEXZWyO53fMuWYhNoZa1tck=
github.com/bitcoinschema/go-bitcoin/v2 v2.0.5/go.mod h1:JjO1ivfZv6vhK0uAXzyH08AAHlzNMAfnyK1Fiv9r4ZA=
github.com/bitcoinsv/bsvd v0.0.0-20190609155523-4c29707f7173 h1:2yTIV9u7H0BhRDGXH5xrAwAz7XibWJtX2dNezMeNsUo=
github.com/bitcoinsv/bsvd v0.0.0-20190609155523-4c29707f7173/go.mod h1:BZ1UcC9+tmcDEcdVXgpt13hMczwJxWzpAn68wNs7zRA=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/brianvoe/gofakeit/v6 v6.28.0 h1:Xib46XXuQfmlLS2EXRuJpqcw8St6qSZz75OUo0tgAW4=
github.com/brianvoe/gofakeit/v6 v6.28.0/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
Expand Down Expand Up @@ -167,6 +169,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg=
github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos=
Expand Down
Loading

0 comments on commit ba61334

Please sign in to comment.