Add an API to reset the password
This commit is contained in:
parent
aa13131b0d
commit
8cba6e01e0
@ -4,17 +4,24 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.badhouseplants.net/softplayer/softplayer-backend/internal/controllers"
|
"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"
|
"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"
|
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{
|
return &AccountsServer{
|
||||||
Controller: contoller,
|
Controller: contoller,
|
||||||
Params: &controllers.AccountParams{
|
Params: &controllers.AccountParams{
|
||||||
HashCost: hashCost,
|
HashCost: hashCost,
|
||||||
},
|
},
|
||||||
|
emailConfig: *email,
|
||||||
|
devMode: devMode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,6 +29,9 @@ type AccountsServer struct {
|
|||||||
accounts.UnimplementedAccountsServer
|
accounts.UnimplementedAccountsServer
|
||||||
Controller ctrl.Manager
|
Controller ctrl.Manager
|
||||||
Params *controllers.AccountParams
|
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) {
|
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
|
}, 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 {
|
func populateData(username, password, email string) *controllers.AccountData {
|
||||||
return &controllers.AccountData{
|
return &controllers.AccountData{
|
||||||
Username: username,
|
Username: username,
|
||||||
|
@ -2,15 +2,22 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"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/hash"
|
||||||
"git.badhouseplants.net/softplayer/softplayer-backend/internal/helpers/kube"
|
"git.badhouseplants.net/softplayer/softplayer-backend/internal/helpers/kube"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
rbacv1 "k8s.io/api/rbac/v1"
|
rbacv1 "k8s.io/api/rbac/v1"
|
||||||
|
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/client-go/kubernetes"
|
||||||
|
"k8s.io/client-go/rest"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
@ -21,6 +28,7 @@ type Account struct {
|
|||||||
Params AccountParams
|
Params AccountParams
|
||||||
Data *AccountData
|
Data *AccountData
|
||||||
Token string
|
Token string
|
||||||
|
DevMode bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type AccountParams struct {
|
type AccountParams struct {
|
||||||
@ -207,6 +215,68 @@ func (acc *Account) Login(ctx context.Context) error {
|
|||||||
return nil
|
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) {
|
func (acc *Account) getToken(ctx context.Context, saSec *corev1.Secret) (string, error) {
|
||||||
client := acc.Controller.GetClient()
|
client := acc.Controller.GetClient()
|
||||||
if err := client.Get(ctx, types.NamespacedName{
|
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))
|
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))
|
email_proto.RegisterEmailValidationServer(grpcServer, v1.InitEmailServer(controller, &emailConfig, params.DevMode))
|
||||||
applications_proto.RegisterApplicationsServer(grpcServer, v1.NewApplicationsGrpcImpl(controller, log))
|
applications_proto.RegisterApplicationsServer(grpcServer, v1.NewApplicationsGrpcImpl(controller, log))
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user