refactor: use external email package
This commit is contained in:
parent
da1228082a
commit
bc29b63114
3
Makefile
3
Makefile
|
@ -55,4 +55,5 @@ clean:
|
||||||
rm -rf $(BIN_DIR)
|
rm -rf $(BIN_DIR)
|
||||||
|
|
||||||
.PHONY: rebuild
|
.PHONY: rebuild
|
||||||
rebuild: clean build_linux_amd64 build_linux_arm64 build_windows_amd64 build_windows_386 build_mac_amd64 build_mac_arm64
|
#rebuild: clean build_linux_amd64 build_linux_arm64 build_windows_amd64 build_windows_386 build_mac_amd64 build_mac_arm64
|
||||||
|
rebuild: clean build_linux_amd64 build_windows_amd64 build_windows_386 build_mac_amd64
|
||||||
|
|
|
@ -15,9 +15,9 @@ import (
|
||||||
"gitea.urkob.com/urko/btc-pay-checker/internal/platform/mongodb/order"
|
"gitea.urkob.com/urko/btc-pay-checker/internal/platform/mongodb/order"
|
||||||
"gitea.urkob.com/urko/btc-pay-checker/internal/services"
|
"gitea.urkob.com/urko/btc-pay-checker/internal/services"
|
||||||
"gitea.urkob.com/urko/btc-pay-checker/internal/services/btc"
|
"gitea.urkob.com/urko/btc-pay-checker/internal/services/btc"
|
||||||
"gitea.urkob.com/urko/btc-pay-checker/internal/services/mail"
|
|
||||||
"gitea.urkob.com/urko/btc-pay-checker/internal/services/price"
|
"gitea.urkob.com/urko/btc-pay-checker/internal/services/price"
|
||||||
"gitea.urkob.com/urko/btc-pay-checker/kit/cfg"
|
"gitea.urkob.com/urko/btc-pay-checker/kit/cfg"
|
||||||
|
"gitea.urkob.com/urko/emailsender/pkg/email"
|
||||||
"go.mongodb.org/mongo-driver/mongo"
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
"go.mongodb.org/mongo-driver/mongo/options"
|
"go.mongodb.org/mongo-driver/mongo/options"
|
||||||
)
|
)
|
||||||
|
@ -61,17 +61,14 @@ func main() {
|
||||||
|
|
||||||
priceSrv := price.NewPriceConversor(config.ConversorApi, config.ConversorApi)
|
priceSrv := price.NewPriceConversor(config.ConversorApi, config.ConversorApi)
|
||||||
btcSrv := btc.NewBitcoinService(config.RpcHost, config.RpcAuth, config.RpcZmq, config.WalletAddress).WithTestnet()
|
btcSrv := btc.NewBitcoinService(config.RpcHost, config.RpcAuth, config.RpcZmq, config.WalletAddress).WithTestnet()
|
||||||
mailSrv := mail.NewMailService(
|
emailSrv := email.NewSecure(email.MailServiceConfig{
|
||||||
mail.MailServiceConfig{
|
Auth: smtp.PlainAuth("", config.MailUser, config.MailPassword, config.MailHost),
|
||||||
Auth: smtp.PlainAuth("", config.MailUser, config.MailPassword, config.MailHost),
|
Host: config.MailHost,
|
||||||
Host: config.MailHost,
|
Port: config.MailPort,
|
||||||
Port: config.MailPort,
|
From: config.MailFrom,
|
||||||
From: config.MailFrom,
|
})
|
||||||
TemplatesDir: config.MailTemplatesDir,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
restServer := api.NewRestServer(config, orderSrv, btcSrv, priceSrv, mailSrv)
|
restServer := api.NewRestServer(config, orderSrv, btcSrv, priceSrv, emailSrv)
|
||||||
go func() {
|
go func() {
|
||||||
if err = restServer.Start(ctx, config.ApiPort, config.Views); err != nil {
|
if err = restServer.Start(ctx, config.ApiPort, config.Views); err != nil {
|
||||||
panic(fmt.Errorf("restServer.Start: %w", err))
|
panic(fmt.Errorf("restServer.Start: %w", err))
|
||||||
|
|
5
go.mod
5
go.mod
|
@ -1,8 +1,9 @@
|
||||||
module gitea.urkob.com/urko/btc-pay-checker
|
module gitea.urkob.com/urko/btc-pay-checker
|
||||||
|
|
||||||
go 1.20
|
go 1.21.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
gitea.urkob.com/urko/emailsender v0.0.0-20231226090954-aca310503955
|
||||||
gitea.urkob.com/urko/go-root-dir v0.0.0-20230311113851-2f6d4355888a
|
gitea.urkob.com/urko/go-root-dir v0.0.0-20230311113851-2f6d4355888a
|
||||||
github.com/docker/go-units v0.5.0
|
github.com/docker/go-units v0.5.0
|
||||||
github.com/gofiber/fiber/v2 v2.48.0
|
github.com/gofiber/fiber/v2 v2.48.0
|
||||||
|
@ -12,7 +13,6 @@ require (
|
||||||
github.com/pebbe/zmq4 v1.2.10
|
github.com/pebbe/zmq4 v1.2.10
|
||||||
github.com/stretchr/testify v1.8.4
|
github.com/stretchr/testify v1.8.4
|
||||||
go.mongodb.org/mongo-driver v1.12.0
|
go.mongodb.org/mongo-driver v1.12.0
|
||||||
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
@ -22,6 +22,7 @@ require (
|
||||||
github.com/gofiber/template v1.8.2 // indirect
|
github.com/gofiber/template v1.8.2 // indirect
|
||||||
github.com/gofiber/utils v1.1.0 // indirect
|
github.com/gofiber/utils v1.1.0 // indirect
|
||||||
github.com/golang/snappy v0.0.1 // indirect
|
github.com/golang/snappy v0.0.1 // indirect
|
||||||
|
github.com/google/go-cmp v0.5.8 // indirect
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
github.com/google/uuid v1.3.0 // indirect
|
||||||
github.com/klauspost/compress v1.16.5 // indirect
|
github.com/klauspost/compress v1.16.5 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
|
|
6
go.sum
6
go.sum
|
@ -1,3 +1,5 @@
|
||||||
|
gitea.urkob.com/urko/emailsender v0.0.0-20231226090954-aca310503955 h1:wQE6MlojyWmOlEp3j88BMGIM0A/ZWqByTFZzXbsbtuQ=
|
||||||
|
gitea.urkob.com/urko/emailsender v0.0.0-20231226090954-aca310503955/go.mod h1:V0m9luBiPICIA72Yr7GJKIOS0GZ+UK0aajtl3Eugqqw=
|
||||||
gitea.urkob.com/urko/go-root-dir v0.0.0-20230311113851-2f6d4355888a h1:s73cd3bRR6v0LGiBei841iIolbBJN2tbkUwN54X9vVg=
|
gitea.urkob.com/urko/go-root-dir v0.0.0-20230311113851-2f6d4355888a h1:s73cd3bRR6v0LGiBei841iIolbBJN2tbkUwN54X9vVg=
|
||||||
gitea.urkob.com/urko/go-root-dir v0.0.0-20230311113851-2f6d4355888a/go.mod h1:mU9nRHl70tBhJFbgKotpoXMV+s0wx+1uJ988p4oEpSo=
|
gitea.urkob.com/urko/go-root-dir v0.0.0-20230311113851-2f6d4355888a/go.mod h1:mU9nRHl70tBhJFbgKotpoXMV+s0wx+1uJ988p4oEpSo=
|
||||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||||
|
@ -20,6 +22,7 @@ github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||||
|
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
|
@ -72,8 +75,6 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
|
||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
||||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||||
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw=
|
|
||||||
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
|
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
@ -117,5 +118,6 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"gitea.urkob.com/urko/btc-pay-checker/internal/services/mail"
|
"gitea.urkob.com/urko/btc-pay-checker/internal/services/mail"
|
||||||
"gitea.urkob.com/urko/btc-pay-checker/internal/services/price"
|
"gitea.urkob.com/urko/btc-pay-checker/internal/services/price"
|
||||||
"gitea.urkob.com/urko/btc-pay-checker/kit/cfg"
|
"gitea.urkob.com/urko/btc-pay-checker/kit/cfg"
|
||||||
|
"gitea.urkob.com/urko/emailsender/pkg/email"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -30,7 +31,7 @@ type RestServer struct {
|
||||||
config *cfg.Config
|
config *cfg.Config
|
||||||
btcService *btc.BitcoinService
|
btcService *btc.BitcoinService
|
||||||
orderSrv *services.Order
|
orderSrv *services.Order
|
||||||
mailSrv *mail.MailService
|
emailSrv *mail.MailService
|
||||||
priceSrv *price.PriceConversor
|
priceSrv *price.PriceConversor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,14 +40,14 @@ func NewRestServer(
|
||||||
orderSrv *services.Order,
|
orderSrv *services.Order,
|
||||||
btcService *btc.BitcoinService,
|
btcService *btc.BitcoinService,
|
||||||
priceSrv *price.PriceConversor,
|
priceSrv *price.PriceConversor,
|
||||||
mailSrv *mail.MailService,
|
emailSrv *email.EmailService,
|
||||||
) *RestServer {
|
) *RestServer {
|
||||||
return &RestServer{
|
return &RestServer{
|
||||||
config: config,
|
config: config,
|
||||||
orderSrv: orderSrv,
|
orderSrv: orderSrv,
|
||||||
btcService: btcService,
|
btcService: btcService,
|
||||||
priceSrv: priceSrv,
|
priceSrv: priceSrv,
|
||||||
mailSrv: mailSrv,
|
emailSrv: mail.NewMailService(emailSrv),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +119,7 @@ func (s *RestServer) onNotification(ctx context.Context, notifChan chan domain.N
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send email to client and provider
|
// Send email to client and provider
|
||||||
if err := s.mailSrv.SendProviderConfirm(mail.SendOK{
|
if err := s.emailSrv.SendProviderConfirm(mail.SendOK{
|
||||||
Tx: order.Tx,
|
Tx: order.Tx,
|
||||||
Block: order.Block,
|
Block: order.Block,
|
||||||
Amount: order.Amount,
|
Amount: order.Amount,
|
||||||
|
|
|
@ -15,6 +15,6 @@ type Order struct {
|
||||||
Tx string `bson:"tx" json:"tx"`
|
Tx string `bson:"tx" json:"tx"`
|
||||||
Block string `bson:"block" json:"block"`
|
Block string `bson:"block" json:"block"`
|
||||||
PaidAt time.Time `bson:"paid_at" json:"paid_at"`
|
PaidAt time.Time `bson:"paid_at" json:"paid_at"`
|
||||||
CreatedAt time.Time `bson:"created_at" json:"created_at"`
|
CreatedAt time.Time `bson:"created_at" json:"-"`
|
||||||
ExpiresAt time.Time `bson:"expires_at" json:"expires_at"`
|
ExpiresAt time.Time `bson:"expires_at" json:"-"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,218 +1,81 @@
|
||||||
package mail
|
package mail
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
|
||||||
"crypto/x509"
|
|
||||||
"fmt"
|
|
||||||
"net/smtp"
|
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/exp/slices"
|
"gitea.urkob.com/urko/btc-pay-checker/internal/services/mail/templates"
|
||||||
|
"gitea.urkob.com/urko/emailsender/pkg/email"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
mime = "MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n\n"
|
mime = "MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n\n"
|
||||||
okSubject = "Proof-of-Evidence record successful"
|
okSubject = "BTC Pay Checker successful"
|
||||||
failSubject = "Proof-of-Evidence record failed"
|
failSubject = "BTC Pay Checker failed"
|
||||||
templateError = "errror.html"
|
|
||||||
templateClientConfirm = "client_confirm.html"
|
|
||||||
templateProviderConfirm = "provider_confirm.html"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type MailService struct {
|
type MailService struct {
|
||||||
auth smtp.Auth
|
emailSrv *email.EmailService
|
||||||
host string
|
}
|
||||||
port string
|
|
||||||
from string
|
func NewMailService(emailSrv *email.EmailService) *MailService {
|
||||||
templatesDir string
|
return &MailService{
|
||||||
tlsconfig *tls.Config
|
emailSrv: emailSrv,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type SendOK struct {
|
type SendOK struct {
|
||||||
Amount float64
|
Amount float64
|
||||||
ExplorerUrl string
|
ExplorerUrl string
|
||||||
Tx string
|
Tx string
|
||||||
CustomerID string
|
CustomerID string
|
||||||
OrderID string
|
OrderID string
|
||||||
Block string
|
Block string
|
||||||
Timestamp time.Time
|
Timestamp time.Time
|
||||||
To string
|
To string
|
||||||
|
SupportEmail string
|
||||||
}
|
}
|
||||||
|
|
||||||
type MailServiceConfig struct {
|
|
||||||
Auth smtp.Auth
|
|
||||||
Host string
|
|
||||||
Port string
|
|
||||||
From string // Sender email address
|
|
||||||
TemplatesDir string // Should end with slash '/'
|
|
||||||
}
|
|
||||||
|
|
||||||
var validCommonNames = []string{"ISRG Root X1", "R3", "DST Root CA X3"}
|
|
||||||
|
|
||||||
func NewMailService(config MailServiceConfig) *MailService {
|
|
||||||
return &MailService{
|
|
||||||
auth: config.Auth,
|
|
||||||
host: config.Host,
|
|
||||||
port: config.Port,
|
|
||||||
from: config.From,
|
|
||||||
templatesDir: config.TemplatesDir,
|
|
||||||
tlsconfig: &tls.Config{
|
|
||||||
InsecureSkipVerify: true,
|
|
||||||
ServerName: config.Host,
|
|
||||||
VerifyConnection: func(cs tls.ConnectionState) error {
|
|
||||||
|
|
||||||
// // Check the server's common name
|
|
||||||
// for _, cert := range cs.PeerCertificates {
|
|
||||||
// log.Println("cert.DNSNames", cert.DNSNames)
|
|
||||||
// if err := cert.VerifyHostname(config.Host); err != nil {
|
|
||||||
// return fmt.Errorf("invalid common name: %w", err)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Check the certificate chain
|
|
||||||
opts := x509.VerifyOptions{
|
|
||||||
Intermediates: x509.NewCertPool(),
|
|
||||||
}
|
|
||||||
for _, cert := range cs.PeerCertificates[1:] {
|
|
||||||
opts.Intermediates.AddCert(cert)
|
|
||||||
}
|
|
||||||
_, err := cs.PeerCertificates[0].Verify(opts)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("invalid certificate chain: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterate over the certificates again to perform custom checks
|
|
||||||
for _, cert := range cs.PeerCertificates {
|
|
||||||
// Add your own custom checks here...
|
|
||||||
if time.Now().After(cert.NotAfter) {
|
|
||||||
return fmt.Errorf("certificate has expired")
|
|
||||||
}
|
|
||||||
if time.Now().Add(30 * 24 * time.Hour).After(cert.NotAfter) {
|
|
||||||
return fmt.Errorf("certificate will expire within 30 days")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !slices.Contains(validCommonNames, cert.Issuer.CommonName) {
|
|
||||||
return fmt.Errorf("certificate is not issued by a trusted CA")
|
|
||||||
}
|
|
||||||
// log.Println("cert.ExtKeyUsage", cert.ExtKeyUsage)
|
|
||||||
// if cert.KeyUsage&x509.KeyUsageDigitalSignature == 0 || len(cert.ExtKeyUsage) == 0 || !slices.Contains(cert.ExtKeyUsage, x509.ExtKeyUsageServerAuth) {
|
|
||||||
// log.Printf("%+v", cert)
|
|
||||||
// return fmt.Errorf("certificate cannot be used for server authentication")
|
|
||||||
// }
|
|
||||||
if cert.PublicKeyAlgorithm != x509.RSA {
|
|
||||||
return fmt.Errorf("unsupported public key algorithm")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func (m *MailService) SendProviderConfirm(data SendOK) error {
|
func (m *MailService) SendProviderConfirm(data SendOK) error {
|
||||||
bts, err := os.ReadFile(m.templatesDir + templateProviderConfirm)
|
template := strings.Replace(templates.ProviderConfirm, "{{explorer_url}}", data.ExplorerUrl, -1)
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("os.ReadFile: %s", err)
|
|
||||||
}
|
|
||||||
template := strings.Replace(string(bts), "{{explorer_url}}", data.ExplorerUrl, -1)
|
|
||||||
template = strings.Replace(template, "{{customer_id}}", data.CustomerID, -1)
|
template = strings.Replace(template, "{{customer_id}}", data.CustomerID, -1)
|
||||||
template = strings.Replace(template, "{{order_id}}", data.OrderID, -1)
|
template = strings.Replace(template, "{{order_id}}", data.OrderID, -1)
|
||||||
template = strings.Replace(template, "{{tx}}", data.Tx, -1)
|
template = strings.Replace(template, "{{tx}}", data.Tx, -1)
|
||||||
template = strings.Replace(template, "{{block}}", data.Block, -1)
|
template = strings.Replace(template, "{{block}}", data.Block, -1)
|
||||||
template = strings.Replace(template, "{{timestamp}}", data.Timestamp.Format(time.RFC3339), -1)
|
template = strings.Replace(template, "{{timestamp}}", data.Timestamp.Format(time.RFC3339), -1)
|
||||||
msg := []byte(m.messageWithHeaders(okSubject, data.To, template))
|
|
||||||
return m.send(data.To, msg)
|
return m.emailSrv.SendEmail(email.EmailMessage{
|
||||||
|
To: data.To,
|
||||||
|
Subject: okSubject,
|
||||||
|
Body: template,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MailService) SendClientConfirm(data SendOK) error {
|
func (m *MailService) SendClientConfirm(data SendOK) error {
|
||||||
bts, err := os.ReadFile(m.templatesDir + templateClientConfirm)
|
template := strings.Replace(templates.ClientConfirm, "{{explorer_url}}", data.ExplorerUrl, -1)
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("os.ReadFile: %s", err)
|
|
||||||
}
|
|
||||||
template := strings.Replace(string(bts), "{{explorer_url}}", data.ExplorerUrl, -1)
|
|
||||||
template = strings.Replace(template, "{{customer_id}}", data.CustomerID, -1)
|
template = strings.Replace(template, "{{customer_id}}", data.CustomerID, -1)
|
||||||
template = strings.Replace(template, "{{order_id}}", data.OrderID, -1)
|
template = strings.Replace(template, "{{order_id}}", data.OrderID, -1)
|
||||||
template = strings.Replace(template, "{{tx}}", data.Tx, -1)
|
template = strings.Replace(template, "{{tx}}", data.Tx, -1)
|
||||||
template = strings.Replace(template, "{{block}}", data.Block, -1)
|
template = strings.Replace(template, "{{block}}", data.Block, -1)
|
||||||
template = strings.Replace(template, "{{timestamp}}", data.Timestamp.Format(time.RFC3339), -1)
|
template = strings.Replace(template, "{{timestamp}}", data.Timestamp.Format(time.RFC3339), -1)
|
||||||
msg := []byte(m.messageWithHeaders(okSubject, data.To, template))
|
|
||||||
return m.send(data.To, msg)
|
return m.emailSrv.SendEmail(email.EmailMessage{
|
||||||
|
To: data.To,
|
||||||
|
Subject: okSubject,
|
||||||
|
Body: template,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MailService) SendFail(data SendOK) error {
|
func (m *MailService) SendFail(data SendOK) error {
|
||||||
//templateError
|
template := strings.Replace(templates.Error, "{{explorer_url}}", data.ExplorerUrl, -1)
|
||||||
bts, err := os.ReadFile(m.templatesDir + templateError)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("os.ReadFile: %s", err)
|
|
||||||
}
|
|
||||||
template := strings.Replace(string(bts), "{{explorer_url}}", data.ExplorerUrl, -1)
|
|
||||||
template = strings.Replace(template, "{{tx_id}}", data.Tx, -1)
|
template = strings.Replace(template, "{{tx_id}}", data.Tx, -1)
|
||||||
template = strings.Replace(template, "{{block_hash}}", data.Block, -1)
|
template = strings.Replace(template, "{{block_hash}}", data.Block, -1)
|
||||||
template = strings.Replace(template, "{{support_email}}", m.from, -1)
|
template = strings.Replace(template, "{{support_email}}", data.SupportEmail, -1)
|
||||||
// TODO: Alert client too
|
// TODO: Alert client too
|
||||||
msg := []byte(m.messageWithHeaders(okSubject, data.To, template))
|
|
||||||
return m.send(data.To, msg)
|
return m.emailSrv.SendEmail(email.EmailMessage{
|
||||||
}
|
To: data.To,
|
||||||
|
Subject: failSubject,
|
||||||
func (m *MailService) send(to string, msg []byte) error {
|
Body: template,
|
||||||
c, err := smtp.Dial(m.host + ":" + m.port)
|
})
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("DIAL: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = c.StartTLS(m.tlsconfig); err != nil {
|
|
||||||
return fmt.Errorf("c.StartTLS: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Auth
|
|
||||||
if err = c.Auth(m.auth); err != nil {
|
|
||||||
return fmt.Errorf("c.Auth: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// To && From
|
|
||||||
if err = c.Mail(m.from); err != nil {
|
|
||||||
return fmt.Errorf("c.Mail: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = c.Rcpt(to); err != nil {
|
|
||||||
return fmt.Errorf("c.Rcpt: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Data
|
|
||||||
w, err := c.Data()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("c.Data: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = w.Write(msg)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("w.Write: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = w.Close(); err != nil {
|
|
||||||
return fmt.Errorf("w.Close: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = c.Quit(); err != nil {
|
|
||||||
return fmt.Errorf("w.Quit: %s", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MailService) messageWithHeaders(subject, to, body string) string {
|
|
||||||
headers := make(map[string]string)
|
|
||||||
headers["From"] = m.from
|
|
||||||
headers["To"] = to
|
|
||||||
headers["Subject"] = subject
|
|
||||||
headers["MIME-Version"] = "1.0"
|
|
||||||
|
|
||||||
message := ""
|
|
||||||
for k, v := range headers {
|
|
||||||
message += fmt.Sprintf("%s: %s\r\n", k, v)
|
|
||||||
}
|
|
||||||
message += "Content-Type: text/html; charset=utf-8\r\n" + body
|
|
||||||
|
|
||||||
return message
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
package mail
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/smtp"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"gitea.urkob.com/urko/btc-pay-checker/kit"
|
|
||||||
"gitea.urkob.com/urko/btc-pay-checker/kit/cfg"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
mailSrv *MailService
|
|
||||||
config *cfg.Config
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
config = cfg.NewConfig(kit.RootDir() + "/.test.env")
|
|
||||||
mailSrv = NewMailService(
|
|
||||||
MailServiceConfig{
|
|
||||||
Auth: smtp.PlainAuth("", config.MailUser, config.MailPassword, config.MailHost),
|
|
||||||
Host: config.MailHost,
|
|
||||||
Port: config.MailPort,
|
|
||||||
From: config.MailFrom,
|
|
||||||
TemplatesDir: config.MailTemplatesDir,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_mailService_SendOK(t *testing.T) {
|
|
||||||
dto := SendOK{
|
|
||||||
Amount: 12.0,
|
|
||||||
ExplorerUrl: "test",
|
|
||||||
Tx: "test-hash",
|
|
||||||
CustomerID: "client",
|
|
||||||
OrderID: "order",
|
|
||||||
Block: "block",
|
|
||||||
Timestamp: time.Now(),
|
|
||||||
To: config.MailTo,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := mailSrv.SendClientConfirm(dto)
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_mailService_SendConfirm(t *testing.T) {
|
|
||||||
dto := SendOK{
|
|
||||||
Amount: 12.0,
|
|
||||||
ExplorerUrl: "test",
|
|
||||||
Tx: "test-hash",
|
|
||||||
CustomerID: "client",
|
|
||||||
OrderID: "order",
|
|
||||||
Block: "block",
|
|
||||||
Timestamp: time.Now(),
|
|
||||||
To: config.MailTo,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := mailSrv.SendProviderConfirm(dto)
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
|
@ -1,4 +1,6 @@
|
||||||
<!DOCTYPE html>
|
package templates
|
||||||
|
|
||||||
|
var ClientConfirm = `<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<style>
|
<style>
|
||||||
|
@ -48,4 +50,4 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>`
|
|
@ -0,0 +1,3 @@
|
||||||
|
package templates
|
||||||
|
|
||||||
|
var Error = ``
|
|
@ -1 +0,0 @@
|
||||||
TODO:
|
|
|
@ -1,4 +1,6 @@
|
||||||
<!DOCTYPE html>
|
package templates
|
||||||
|
|
||||||
|
var ProviderConfirm = `<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<style>
|
<style>
|
||||||
|
@ -50,4 +52,4 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>`
|
Loading…
Reference in New Issue