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.Error("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'}