package interceptor
import (
"bytes"
"encoding/hex"
"encoding/json"
"html/template"
"log"
"os"
"strconv"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ses"
)
const (
charset = "UTF-8"
)
func addresses(a string) (addr []*string) {
json.Unmarshal([]byte(a), &addr)
return
}
func sendEmail(to, cc, from, content, subject string) error {
sess, err := session.NewSession(&aws.Config{})
if err != nil {
log.Printf("Error in session.NewSession: %v", err)
return err
}
svc := ses.New(sess)
input := &ses.SendEmailInput{
Destination: &ses.Destination{
CcAddresses: addresses(cc),
ToAddresses: addresses(to),
},
Message: &ses.Message{
Body: &ses.Body{
Html: &ses.Content{
Charset: aws.String(charset),
Data: aws.String(content),
},
},
Subject: &ses.Content{
Charset: aws.String(charset),
Data: aws.String(subject),
},
},
Source: aws.String(from),
}
// Attempt to send the email.
result, err := svc.SendEmail(input)
if err != nil {
if aerr, ok := err.(awserr.Error); ok {
switch aerr.Code() {
case ses.ErrCodeMessageRejected:
log.Println(ses.ErrCodeMessageRejected, aerr.Error())
case ses.ErrCodeMailFromDomainNotVerifiedException:
log.Println(ses.ErrCodeMailFromDomainNotVerifiedException, aerr.Error())
case ses.ErrCodeConfigurationSetDoesNotExistException:
log.Println(ses.ErrCodeConfigurationSetDoesNotExistException, aerr.Error())
default:
log.Println(aerr.Error())
}
} else {
// Print the error, cast err to awserr.Error to get the Code and
// Message from an error.
log.Println(err.Error())
}
return err
}
log.Printf("Email sent with result:\n%v", result)
return nil
}
func sendChannelMismatchNotification(nodeID string, notFakeChannels, closedChannels map[string]uint64) error {
var html bytes.Buffer
tpl := `
NodeID: {{ .NodeID }}
{{ if .NotFakeChannels }}Channels not fake anynmore
| Channel Point | Height Hint |
{{ range $key, $value := .NotFakeChannels }}| {{ $key }} | {{ $value }} |
{{ end }}
{{ end }}
{{ if .ClosedChannels }}Closed Channels
| Channel Point | Height Hint |
{{ range $key, $value := .ClosedChannels }}| {{ $key }} | {{ $value }} |
{{ end }}
{{ end }}
`
t, err := template.New("ChannelMismatchEmail").Parse(tpl)
if err != nil {
return err
}
if err := t.Execute(&html, struct {
NodeID string
NotFakeChannels map[string]uint64
ClosedChannels map[string]uint64
}{nodeID, notFakeChannels, closedChannels}); err != nil {
return err
}
err = sendEmail(
os.Getenv("CHANNELMISMATCH_NOTIFICATION_TO"),
os.Getenv("CHANNELMISMATCH_NOTIFICATION_CC"),
os.Getenv("CHANNELMISMATCH_NOTIFICATION_FROM"),
html.String(),
"Channel(s) Mismatch",
)
if err != nil {
log.Printf("Error sending open channel email: %v", err)
return err
}
return nil
}
func sendOpenChannelEmailNotification(
paymentHash []byte, incomingAmountMsat int64,
destination []byte, capacity int64,
channelPoint string,
tag *string,
) error {
var html bytes.Buffer
tpl := `
| Payment Hash: | {{ .PaymentHash }} |
| Incoming Amount (msat): | {{ .IncomingAmountMsat }} |
| Destination Node: | {{ .Destination }} |
| Channel capacity (sat): | {{ .Capacity }} |
| Channel point: | {{ .ChannelPoint }} |
| Tag: | {{ .Tag }} |
`
t, err := template.New("OpenChannelEmail").Parse(tpl)
if err != nil {
return err
}
tagStr := ""
if tag != nil {
tagStr = *tag
}
if err := t.Execute(&html, map[string]string{
"PaymentHash": hex.EncodeToString(paymentHash),
"IncomingAmountMsat": strconv.FormatUint(uint64(incomingAmountMsat), 10),
"Destination": hex.EncodeToString(destination),
"Capacity": strconv.FormatUint(uint64(capacity), 10),
"ChannelPoint": channelPoint,
"Tag": tagStr,
}); err != nil {
return err
}
err = sendEmail(
os.Getenv("OPENCHANNEL_NOTIFICATION_TO"),
os.Getenv("OPENCHANNEL_NOTIFICATION_CC"),
os.Getenv("OPENCHANNEL_NOTIFICATION_FROM"),
html.String(),
"Open Channel - Interceptor",
)
if err != nil {
log.Printf("Error sending open channel email: %v", err)
return err
}
return nil
}