128 lines
2.9 KiB
Go
128 lines
2.9 KiB
Go
package controllers
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
|
|
"git.badhouseplants.net/softplayer/softplayer-backend/internal/helpers/email"
|
|
"git.badhouseplants.net/softplayer/softplayer-backend/internal/helpers/kube"
|
|
ctrl "sigs.k8s.io/controller-runtime"
|
|
|
|
corev1 "k8s.io/api/core/v1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/types"
|
|
)
|
|
|
|
type EmailSvc struct {
|
|
Controller ctrl.Manager
|
|
Data EmailData
|
|
EmailConfig email.EmailConf
|
|
DevMode bool
|
|
}
|
|
|
|
type EmailData struct {
|
|
UserID string
|
|
Code string
|
|
}
|
|
|
|
func (svc *EmailSvc) SendVerification(ctx context.Context) error {
|
|
client := svc.Controller.GetClient()
|
|
userns := &corev1.Namespace{}
|
|
if err := client.Get(ctx, types.NamespacedName{
|
|
Name: svc.Data.UserID,
|
|
}, userns); err != nil {
|
|
return err
|
|
}
|
|
|
|
userName, ok := userns.Labels["username"]
|
|
if !ok {
|
|
return errors.New("user not found")
|
|
}
|
|
accountData := &corev1.Secret{}
|
|
if err := client.Get(ctx, types.NamespacedName{
|
|
Namespace: "softplayer-accounts",
|
|
Name: userName,
|
|
}, accountData); err != nil {
|
|
return err
|
|
}
|
|
|
|
if val, ok := userns.Labels["email-verified"]; ok && val == "true" {
|
|
return errors.New("email is already verified")
|
|
}
|
|
|
|
number := encodeToString(6)
|
|
svc.Data.Code = number
|
|
if !svc.DevMode {
|
|
emailContent := "Subject: Softplayer verification code\r\n" + "\r\n" + fmt.Sprintf("Your verification code is %s", number)
|
|
email := string(accountData.Data["email"])
|
|
if err := svc.EmailConfig.SendEmail(email, emailContent); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
emailCode := corev1.ConfigMap{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "email-verification-code",
|
|
Namespace: svc.Data.UserID,
|
|
},
|
|
Data: map[string]string{
|
|
"code": number,
|
|
},
|
|
}
|
|
|
|
if err := kube.Create(ctx, client, &emailCode, true); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (svc *EmailSvc) ConfirmVerification(ctx context.Context) error {
|
|
client := svc.Controller.GetClient()
|
|
emailCode := &corev1.ConfigMap{}
|
|
if err := client.Get(ctx, types.NamespacedName{
|
|
Namespace: svc.Data.UserID,
|
|
Name: "email-verification-code",
|
|
}, emailCode); err != nil {
|
|
return err
|
|
}
|
|
|
|
if svc.Data.Code != emailCode.Data["code"] {
|
|
log.Println(svc.Data.Code)
|
|
log.Println(emailCode.Data["code"])
|
|
return errors.New("wrong verification code")
|
|
}
|
|
if err := client.Delete(ctx, emailCode); err != nil {
|
|
return err
|
|
}
|
|
|
|
userns := &corev1.Namespace{}
|
|
if err := client.Get(ctx, types.NamespacedName{
|
|
Name: svc.Data.UserID,
|
|
}, userns); err != nil {
|
|
return err
|
|
}
|
|
|
|
userns.Labels["email-verified"] = "true"
|
|
if err := client.Update(ctx, userns); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func encodeToString(max int) string {
|
|
b := make([]byte, max)
|
|
n, err := io.ReadAtLeast(rand.Reader, b, max)
|
|
if n != max {
|
|
panic(err)
|
|
}
|
|
for i := 0; i < len(b); i++ {
|
|
b[i] = table[int(b[i])%len(table)]
|
|
}
|
|
return string(b)
|
|
}
|
|
|
|
var table = [...]byte{'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'}
|