Add an API to reset the password
This commit is contained in:
parent
aa13131b0d
commit
8cba6e01e0
@ -4,17 +4,24 @@ import (
|
||||
"context"
|
||||
|
||||
"git.badhouseplants.net/softplayer/softplayer-backend/internal/controllers"
|
||||
"git.badhouseplants.net/softplayer/softplayer-backend/internal/helpers/email"
|
||||
"git.badhouseplants.net/softplayer/softplayer-go-proto/pkg/accounts"
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
)
|
||||
|
||||
func NewAccountRPCImpl(contoller ctrl.Manager, hashCost int16) *AccountsServer {
|
||||
func NewAccountRPCImpl(contoller ctrl.Manager, hashCost int16, email *email.EmailConf, devMode bool) *AccountsServer {
|
||||
return &AccountsServer{
|
||||
Controller: contoller,
|
||||
Params: &controllers.AccountParams{
|
||||
HashCost: hashCost,
|
||||
},
|
||||
emailConfig: *email,
|
||||
devMode: devMode,
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,6 +29,9 @@ type AccountsServer struct {
|
||||
accounts.UnimplementedAccountsServer
|
||||
Controller ctrl.Manager
|
||||
Params *controllers.AccountParams
|
||||
emailConfig email.EmailConf
|
||||
// When dev mode is enabled, email won't be sent, instead the code will be returned in metadata
|
||||
devMode bool
|
||||
}
|
||||
|
||||
func (a *AccountsServer) SignUp(ctx context.Context, in *accounts.AccountWithPassword) (*accounts.AccountFullWithToken, error) {
|
||||
@ -64,6 +74,24 @@ func (a *AccountsServer) SignIn(ctx context.Context, in *accounts.AccountWithPas
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (a *AccountsServer) ResetPassword(ctx context.Context, in *accounts.AccountData) (*empty.Empty, error) {
|
||||
data := populateData(in.GetName(), "", in.GetEmail())
|
||||
acc := populateAccount(data, a.Controller)
|
||||
code, err := acc.ResetPassword(ctx, a.emailConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if a.devMode {
|
||||
header := metadata.Pairs("code", code)
|
||||
if err := grpc.SendHeader(ctx, header); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
func populateData(username, password, email string) *controllers.AccountData {
|
||||
return &controllers.AccountData{
|
||||
Username: username,
|
||||
|
@ -2,15 +2,22 @@ package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.badhouseplants.net/softplayer/softplayer-backend/internal/consts"
|
||||
"git.badhouseplants.net/softplayer/softplayer-backend/internal/helpers/email"
|
||||
"git.badhouseplants.net/softplayer/softplayer-backend/internal/helpers/hash"
|
||||
"git.badhouseplants.net/softplayer/softplayer-backend/internal/helpers/kube"
|
||||
"github.com/google/uuid"
|
||||
"github.com/sirupsen/logrus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
@ -21,6 +28,7 @@ type Account struct {
|
||||
Params AccountParams
|
||||
Data *AccountData
|
||||
Token string
|
||||
DevMode bool
|
||||
}
|
||||
|
||||
type AccountParams struct {
|
||||
@ -207,6 +215,68 @@ func (acc *Account) Login(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (acc *Account) ResetPassword(ctx context.Context, emailConfig email.EmailConf) (string, error) {
|
||||
clientset, err := kubernetes.NewForConfig(acc.Controller.GetConfig())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
userdata, err := clientset.CoreV1().Secrets("softplayer-accounts").Get(ctx, acc.Data.Username, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if string(userdata.Data["email"]) != acc.Data.Email {
|
||||
return "", errors.New("user or email not found")
|
||||
}
|
||||
|
||||
acc.Data.UUID = string(userdata.Data["uuid"])
|
||||
|
||||
conf := &rest.Config{
|
||||
Host: "https://kubernetes.default.svc.cluster.local:443",
|
||||
BearerToken: acc.Token,
|
||||
TLSClientConfig: rest.TLSClientConfig{
|
||||
Insecure: true,
|
||||
},
|
||||
}
|
||||
|
||||
clientset, err = kubernetes.NewForConfig(conf)
|
||||
if err != nil {
|
||||
logrus.Error(err, "Couldn't create a new clientset")
|
||||
return "", consts.ErrSystemError
|
||||
}
|
||||
|
||||
secretName := "password-reset-code"
|
||||
number := encodeToString(6)
|
||||
secret := corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: secretName,
|
||||
},
|
||||
StringData: map[string]string{
|
||||
"code": number,
|
||||
},
|
||||
}
|
||||
sec, err := clientset.CoreV1().Secrets(acc.Data.UUID).Create(ctx, &secret, metav1.CreateOptions{})
|
||||
if !k8serrors.IsAlreadyExists(err) {
|
||||
return "", err
|
||||
} else if k8serrors.IsAlreadyExists(err) {
|
||||
timestamp := sec.CreationTimestamp.Time
|
||||
now := time.Now()
|
||||
if timestamp.Add(time.Minute).Before(now) {
|
||||
return "", errors.New("You can send an email once per minute, please wait")
|
||||
}
|
||||
}
|
||||
|
||||
if !acc.DevMode {
|
||||
emailContent := "Subject: Softplayer verification code\r\n" + "\r\n" + fmt.Sprintf("Your verification code is %s", number)
|
||||
email := string(userdata.Data["email"])
|
||||
if err := emailConfig.SendEmail(email, emailContent); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
return number, nil
|
||||
}
|
||||
|
||||
func (acc *Account) getToken(ctx context.Context, saSec *corev1.Secret) (string, error) {
|
||||
client := acc.Controller.GetClient()
|
||||
if err := client.Get(ctx, types.NamespacedName{
|
||||
|
2
main.go
2
main.go
@ -98,7 +98,7 @@ func server(params Serve) error {
|
||||
}
|
||||
|
||||
environments.RegisterEnvironmentsServer(grpcServer, v1.NewapiGrpcImpl(controller, log))
|
||||
accounts.RegisterAccountsServer(grpcServer, v1.NewAccountRPCImpl(controller, params.HashCost))
|
||||
accounts.RegisterAccountsServer(grpcServer, v1.NewAccountRPCImpl(controller, params.HashCost, &emailConfig, params.DevMode))
|
||||
email_proto.RegisterEmailValidationServer(grpcServer, v1.InitEmailServer(controller, &emailConfig, params.DevMode))
|
||||
applications_proto.RegisterApplicationsServer(grpcServer, v1.NewApplicationsGrpcImpl(controller, log))
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user