diff --git a/user/domain/domain.go b/user/domain/domain.go index 3c301ee..78b7584 100644 --- a/user/domain/domain.go +++ b/user/domain/domain.go @@ -31,6 +31,12 @@ type verificationToken struct { UserID string `json:"userId"` } +type passwordResetCode struct { + ID string `json:"id"` + Expires time.Time `json:"expires"` + UserID string `json:"userId"` +} + type Domain struct { db db.DbService sengridKey string @@ -59,7 +65,80 @@ func (domain *Domain) SendEmail(fromName, toAddress, toUsername, subject, textCo } from := mail.NewEmail(fromName, "support@m3o.com") to := mail.NewEmail(toUsername, toAddress) - textContent = strings.Replace(textContent, "$micro_verification_link", "https://angry-cori-854281.netlify.app?token="+token+"&redirectUrl="+url.QueryEscape(redirctUrl)+"&failureRedirectUrl="+url.QueryEscape(failureRedirectUrl), -1) + textContent = strings.Replace(textContent, "$micro_verification_link", "https://user.m3o.com?token="+token+"&redirectUrl="+url.QueryEscape(redirctUrl)+"&failureRedirectUrl="+url.QueryEscape(failureRedirectUrl), -1) + message := mail.NewSingleEmail(from, subject, to, textContent, "") + client := sendgrid.NewSendClient(domain.sengridKey) + response, err := client.Send(message) + logger.Info(response) + + return err +} + +func (domain *Domain) CreatePasswordResetCode(ctx context.Context, userID string) (*passwordResetCode, error) { + pwcode := passwordResetCode{ + ID: uuid.New().String(), + Expires: time.Now().Add(24 * time.Hour), + UserID: userID, + } + + s := &_struct.Struct{} + jso, _ := json.Marshal(pwcode) + err := s.UnmarshalJSON(jso) + if err != nil { + return nil, err + } + _, err = domain.db.Create(ctx, &db.CreateRequest{ + Table: "password-reset-codes", + Record: s, + }) + return &pwcode, err +} + +func (domain *Domain) DeletePasswordRestCode(ctx context.Context, id string) error { + _, err := domain.db.Delete(ctx, &db.DeleteRequest{ + Table: "password-reset-codes", + Id: id, + }) + return err +} + +// ReadToken returns the user id +func (domain *Domain) ReadPasswordResetCode(ctx context.Context, id string) (*passwordResetCode, error) { + if id == "" { + return nil, errors.New("password reset code id is empty") + } + token := &passwordResetCode{} + + rsp, err := domain.db.Read(ctx, &db.ReadRequest{ + Table: "password-reset-codes", + Query: fmt.Sprintf("id == '%v'", id), + }) + if err != nil { + return nil, err + } + if len(rsp.Records) == 0 { + return nil, errors.New("password reset code not found") + } + m, _ := rsp.Records[0].MarshalJSON() + json.Unmarshal(m, token) + + if token.Expires.Before(time.Now()) { + return nil, errors.New("password reset code expired") + } + return token, nil +} + +func (domain *Domain) SendPasswordResetEmail(ctx context.Context, userId, fromName, toAddress, toUsername, subject, textContent string) error { + if domain.sengridKey == "" { + return fmt.Errorf("empty email api key") + } + from := mail.NewEmail(fromName, "support@m3o.com") + to := mail.NewEmail(toUsername, toAddress) + code, err := domain.CreatePasswordResetCode(ctx, userId) + if err != nil { + return err + } + textContent = strings.Replace(textContent, "$code", code.ID, -1) message := mail.NewSingleEmail(from, subject, to, textContent, "") client := sendgrid.NewSendClient(domain.sengridKey) response, err := client.Send(message) diff --git a/user/examples.json b/user/examples.json index f0ffe42..62ed360 100644 --- a/user/examples.json +++ b/user/examples.json @@ -101,6 +101,19 @@ "response": {} } ], + "sendPasswordResetEmail": [ + { + "title": "Send password reset email", + "run_check": true, + "request": { + "email": "joe@example.com", + "subject": "Password reset", + "textContent": "Hi there,\n click here to reset your password: myapp.com/reset/code?=$code", + "fromName": "Awesome Dot Com" + }, + "response": {} + } + ], "verifyEmail": [ { "title": "Verify email", diff --git a/user/handler/handler.go b/user/handler/handler.go index e288226..c3b0154 100644 --- a/user/handler/handler.go +++ b/user/handler/handler.go @@ -245,3 +245,32 @@ func (s *User) SendVerificationEmail(ctx context.Context, req *pb.SendVerificati return s.domain.SendEmail(req.FromName, req.Email, users[0].Username, req.Subject, req.TextContent, token, req.RedirectUrl, req.FailureRedirectUrl) } + +func (s *User) SendPasswordResetEmail(ctx context.Context, req *pb.SendPasswordResetEmailRequest, rsp *pb.SendPasswordResetEmailResponse) error { + users, err := s.domain.Search(ctx, "", req.Email) + if err != nil { + return err + } + + return s.domain.SendPasswordResetEmail(ctx, users[0].Id, req.FromName, req.Email, users[0].Username, req.Subject, req.TextContent) +} + +func (s *User) ResetPassword(ctx context.Context, req *pb.ResetPasswordRequest, rsp *pb.ResetPasswordResponse) error { + code, err := s.domain.ReadPasswordResetCode(ctx, req.Code) + if err != nil { + return err + } + // no error means it exists and not expired + salt := random(16) + h, err := bcrypt.GenerateFromPassword([]byte(x+salt+req.NewPassword), 10) + if err != nil { + return errors.InternalServerError("user.ResetPassword", err.Error()) + } + pp := base64.StdEncoding.EncodeToString(h) + + if err := s.domain.UpdatePassword(ctx, code.UserID, salt, pp); err != nil { + return errors.InternalServerError("user.resetpassword", err.Error()) + } + s.domain.DeletePasswordRestCode(ctx, req.Code) + return nil +} diff --git a/user/proto/user.pb.go b/user/proto/user.pb.go index 35f7879..d85f097 100644 --- a/user/proto/user.pb.go +++ b/user/proto/user.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.26.0 -// protoc v3.15.6 +// protoc v3.6.1 // source: proto/user.proto package user @@ -34,8 +34,10 @@ type Account struct { // unix timestamp Created int64 `protobuf:"varint,4,opt,name=created,proto3" json:"created,omitempty"` // unix timestamp - Updated int64 `protobuf:"varint,5,opt,name=updated,proto3" json:"updated,omitempty"` - Verified bool `protobuf:"varint,6,opt,name=verified,proto3" json:"verified,omitempty"` + Updated int64 `protobuf:"varint,5,opt,name=updated,proto3" json:"updated,omitempty"` + // if the account is verified + Verified bool `protobuf:"varint,6,opt,name=verified,proto3" json:"verified,omitempty"` + // date of verification VerificationDate int64 `protobuf:"varint,7,opt,name=verificationDate,proto3" json:"verificationDate,omitempty"` // Store any custom data you want about your users in this fields. Profile map[string]string `protobuf:"bytes,8,rep,name=profile,proto3" json:"profile,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` @@ -210,7 +212,7 @@ type CreateRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // optional acccount id + // optional account id Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // the username Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"` @@ -433,7 +435,7 @@ type ReadRequest struct { Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // the account username Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"` - // the account password + // the account email Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` } @@ -1150,10 +1152,6 @@ func (*VerifyEmailResponse) Descriptor() ([]byte, []int) { return file_proto_user_proto_rawDescGZIP(), []int{19} } -// Send a verification email -// to the user being signed up. Email from will be 'support@m3o.com', -// but you can provide the title and contents. -// Use $micro_verification_link template variable in the content. type SendVerificationEmailRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1161,15 +1159,12 @@ type SendVerificationEmailRequest struct { Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"` Subject string `protobuf:"bytes,2,opt,name=subject,proto3" json:"subject,omitempty"` - // Example: 'Hi there, welcome onboard! Use the link below to verify your email: $micro_verification_link' - // The variable will be replaced with an actual url that will look similar to this: - // 'https://user.m3o.com/user/verify?token=a-verification-token&rediretUrl=your-redir-url' + // Text content of the email. Don't forget to include the string '$micro_verification_link' which will be replaced by the real verification link // HTML emails are not available currently. TextContent string `protobuf:"bytes,3,opt,name=textContent,proto3" json:"textContent,omitempty"` RedirectUrl string `protobuf:"bytes,4,opt,name=redirectUrl,proto3" json:"redirectUrl,omitempty"` FailureRedirectUrl string `protobuf:"bytes,5,opt,name=failureRedirectUrl,proto3" json:"failureRedirectUrl,omitempty"` - // While the from email address can't be changed, - // the from name (ie. sender name) can. + // Display name of the sender for the email. Note: the email address will still be 'support@m3o.com' FromName string `protobuf:"bytes,6,opt,name=fromName,proto3" json:"fromName,omitempty"` } @@ -1285,6 +1280,225 @@ func (*SendVerificationEmailResponse) Descriptor() ([]byte, []int) { return file_proto_user_proto_rawDescGZIP(), []int{21} } +// Send an email with a verification code to reset password. +// Call "ResetPassword" endpoint once user provides the code. +type SendPasswordResetEmailRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"` + Subject string `protobuf:"bytes,2,opt,name=subject,proto3" json:"subject,omitempty"` + // Text content of the email. Don't forget to include the string '$code' which will be replaced by the real verification link + // HTML emails are not available currently. + TextContent string `protobuf:"bytes,3,opt,name=textContent,proto3" json:"textContent,omitempty"` + // Display name of the sender for the email. Note: the email address will still be 'support@m3o.com' + FromName string `protobuf:"bytes,4,opt,name=fromName,proto3" json:"fromName,omitempty"` +} + +func (x *SendPasswordResetEmailRequest) Reset() { + *x = SendPasswordResetEmailRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_user_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SendPasswordResetEmailRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SendPasswordResetEmailRequest) ProtoMessage() {} + +func (x *SendPasswordResetEmailRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_user_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SendPasswordResetEmailRequest.ProtoReflect.Descriptor instead. +func (*SendPasswordResetEmailRequest) Descriptor() ([]byte, []int) { + return file_proto_user_proto_rawDescGZIP(), []int{22} +} + +func (x *SendPasswordResetEmailRequest) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *SendPasswordResetEmailRequest) GetSubject() string { + if x != nil { + return x.Subject + } + return "" +} + +func (x *SendPasswordResetEmailRequest) GetTextContent() string { + if x != nil { + return x.TextContent + } + return "" +} + +func (x *SendPasswordResetEmailRequest) GetFromName() string { + if x != nil { + return x.FromName + } + return "" +} + +type SendPasswordResetEmailResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *SendPasswordResetEmailResponse) Reset() { + *x = SendPasswordResetEmailResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_user_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SendPasswordResetEmailResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SendPasswordResetEmailResponse) ProtoMessage() {} + +func (x *SendPasswordResetEmailResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_user_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SendPasswordResetEmailResponse.ProtoReflect.Descriptor instead. +func (*SendPasswordResetEmailResponse) Descriptor() ([]byte, []int) { + return file_proto_user_proto_rawDescGZIP(), []int{23} +} + +// Reset password with the code sent by the "SendPasswordResetEmail" endoint. +type ResetPasswordRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The code from the verification email + Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"` + // the new password + NewPassword string `protobuf:"bytes,2,opt,name=newPassword,proto3" json:"newPassword,omitempty"` + // confirm new password + ConfirmPassword string `protobuf:"bytes,3,opt,name=confirmPassword,proto3" json:"confirmPassword,omitempty"` +} + +func (x *ResetPasswordRequest) Reset() { + *x = ResetPasswordRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_user_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ResetPasswordRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResetPasswordRequest) ProtoMessage() {} + +func (x *ResetPasswordRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_user_proto_msgTypes[24] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResetPasswordRequest.ProtoReflect.Descriptor instead. +func (*ResetPasswordRequest) Descriptor() ([]byte, []int) { + return file_proto_user_proto_rawDescGZIP(), []int{24} +} + +func (x *ResetPasswordRequest) GetCode() string { + if x != nil { + return x.Code + } + return "" +} + +func (x *ResetPasswordRequest) GetNewPassword() string { + if x != nil { + return x.NewPassword + } + return "" +} + +func (x *ResetPasswordRequest) GetConfirmPassword() string { + if x != nil { + return x.ConfirmPassword + } + return "" +} + +type ResetPasswordResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ResetPasswordResponse) Reset() { + *x = ResetPasswordResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_user_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ResetPasswordResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResetPasswordResponse) ProtoMessage() {} + +func (x *ResetPasswordResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_user_proto_msgTypes[25] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResetPasswordResponse.ProtoReflect.Descriptor instead. +func (*ResetPasswordResponse) Descriptor() ([]byte, []int) { + return file_proto_user_proto_rawDescGZIP(), []int{25} +} + var File_proto_user_proto protoreflect.FileDescriptor var file_proto_user_proto_rawDesc = []byte{ @@ -1412,49 +1626,80 @@ var file_proto_user_proto_rawDesc = []byte{ 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x72, 0x6f, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x1f, 0x0a, 0x1d, 0x53, 0x65, 0x6e, 0x64, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x86, 0x05, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, - 0x35, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x13, 0x2e, 0x75, 0x73, 0x65, 0x72, - 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, - 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x2f, 0x0a, 0x04, 0x52, 0x65, 0x61, 0x64, 0x12, 0x11, - 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x12, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x35, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x12, 0x13, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x35, - 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x13, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, - 0x75, 0x73, 0x65, 0x72, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, - 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x1b, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x00, 0x12, 0x32, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x12, 0x2e, - 0x75, 0x73, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x13, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x35, 0x0a, 0x06, 0x4c, 0x6f, 0x67, 0x6f, - 0x75, 0x74, 0x12, 0x13, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x4c, - 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, - 0x44, 0x0a, 0x0b, 0x52, 0x65, 0x61, 0x64, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, - 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, - 0x52, 0x65, 0x61, 0x64, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x44, 0x0a, 0x0b, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x45, - 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x18, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x56, 0x65, 0x72, 0x69, - 0x66, 0x79, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, - 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x45, 0x6d, 0x61, 0x69, - 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x62, 0x0a, 0x15, 0x53, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x8d, 0x01, 0x0a, 0x1d, 0x53, 0x65, 0x6e, 0x64, 0x50, + 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x65, 0x74, 0x45, 0x6d, 0x61, 0x69, + 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, + 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x18, + 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x74, 0x65, 0x78, 0x74, + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x74, + 0x65, 0x78, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x72, + 0x6f, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x72, + 0x6f, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x20, 0x0a, 0x1e, 0x53, 0x65, 0x6e, 0x64, 0x50, 0x61, + 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x65, 0x74, 0x45, 0x6d, 0x61, 0x69, 0x6c, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x76, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x65, + 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x63, 0x6f, 0x64, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6e, 0x65, 0x77, 0x50, 0x61, 0x73, 0x73, 0x77, + 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x65, 0x77, 0x50, 0x61, + 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, + 0x6d, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, + 0x22, 0x17, 0x0a, 0x15, 0x52, 0x65, 0x73, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, + 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xb9, 0x06, 0x0a, 0x04, 0x55, 0x73, + 0x65, 0x72, 0x12, 0x35, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x13, 0x2e, 0x75, + 0x73, 0x65, 0x72, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x14, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x2f, 0x0a, 0x04, 0x52, 0x65, 0x61, + 0x64, 0x12, 0x11, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x61, 0x64, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x35, 0x0a, 0x06, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x12, 0x13, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x75, 0x73, 0x65, 0x72, + 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x12, 0x35, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x13, 0x2e, 0x75, 0x73, + 0x65, 0x72, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x14, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x0e, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x1b, 0x2e, 0x75, 0x73, 0x65, + 0x72, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x32, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, + 0x12, 0x12, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x69, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x35, 0x0a, 0x06, 0x4c, + 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x12, 0x13, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, + 0x6f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x75, 0x73, 0x65, + 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x12, 0x44, 0x0a, 0x0b, 0x52, 0x65, 0x61, 0x64, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x18, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x75, 0x73, + 0x65, 0x72, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x44, 0x0a, 0x0b, 0x56, 0x65, 0x72, 0x69, + 0x66, 0x79, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x18, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x56, + 0x65, 0x72, 0x69, 0x66, 0x79, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x19, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x45, + 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x62, + 0x0a, 0x15, 0x53, 0x65, 0x6e, 0x64, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x22, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, - 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x22, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x6e, 0x64, - 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6d, 0x61, 0x69, - 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, - 0x53, 0x65, 0x6e, 0x64, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, - 0x0e, 0x5a, 0x0c, 0x2e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3b, 0x75, 0x73, 0x65, 0x72, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x75, 0x73, + 0x65, 0x72, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x12, 0x65, 0x0a, 0x16, 0x53, 0x65, 0x6e, 0x64, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, + 0x72, 0x64, 0x52, 0x65, 0x73, 0x65, 0x74, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x23, 0x2e, 0x75, + 0x73, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, + 0x52, 0x65, 0x73, 0x65, 0x74, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x24, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x50, 0x61, 0x73, + 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x65, 0x74, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0d, 0x52, 0x65, 0x73, + 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x1a, 0x2e, 0x75, 0x73, 0x65, + 0x72, 0x2e, 0x52, 0x65, 0x73, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x52, 0x65, + 0x73, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x0e, 0x5a, 0x0c, 0x2e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x3b, 0x75, 0x73, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1469,40 +1714,44 @@ func file_proto_user_proto_rawDescGZIP() []byte { return file_proto_user_proto_rawDescData } -var file_proto_user_proto_msgTypes = make([]protoimpl.MessageInfo, 25) +var file_proto_user_proto_msgTypes = make([]protoimpl.MessageInfo, 29) var file_proto_user_proto_goTypes = []interface{}{ - (*Account)(nil), // 0: user.Account - (*Session)(nil), // 1: user.Session - (*CreateRequest)(nil), // 2: user.CreateRequest - (*CreateResponse)(nil), // 3: user.CreateResponse - (*DeleteRequest)(nil), // 4: user.DeleteRequest - (*DeleteResponse)(nil), // 5: user.DeleteResponse - (*ReadRequest)(nil), // 6: user.ReadRequest - (*ReadResponse)(nil), // 7: user.ReadResponse - (*UpdateRequest)(nil), // 8: user.UpdateRequest - (*UpdateResponse)(nil), // 9: user.UpdateResponse - (*UpdatePasswordRequest)(nil), // 10: user.UpdatePasswordRequest - (*UpdatePasswordResponse)(nil), // 11: user.UpdatePasswordResponse - (*ReadSessionRequest)(nil), // 12: user.ReadSessionRequest - (*ReadSessionResponse)(nil), // 13: user.ReadSessionResponse - (*LoginRequest)(nil), // 14: user.LoginRequest - (*LoginResponse)(nil), // 15: user.LoginResponse - (*LogoutRequest)(nil), // 16: user.LogoutRequest - (*LogoutResponse)(nil), // 17: user.LogoutResponse - (*VerifyEmailRequest)(nil), // 18: user.VerifyEmailRequest - (*VerifyEmailResponse)(nil), // 19: user.VerifyEmailResponse - (*SendVerificationEmailRequest)(nil), // 20: user.SendVerificationEmailRequest - (*SendVerificationEmailResponse)(nil), // 21: user.SendVerificationEmailResponse - nil, // 22: user.Account.ProfileEntry - nil, // 23: user.CreateRequest.ProfileEntry - nil, // 24: user.UpdateRequest.ProfileEntry + (*Account)(nil), // 0: user.Account + (*Session)(nil), // 1: user.Session + (*CreateRequest)(nil), // 2: user.CreateRequest + (*CreateResponse)(nil), // 3: user.CreateResponse + (*DeleteRequest)(nil), // 4: user.DeleteRequest + (*DeleteResponse)(nil), // 5: user.DeleteResponse + (*ReadRequest)(nil), // 6: user.ReadRequest + (*ReadResponse)(nil), // 7: user.ReadResponse + (*UpdateRequest)(nil), // 8: user.UpdateRequest + (*UpdateResponse)(nil), // 9: user.UpdateResponse + (*UpdatePasswordRequest)(nil), // 10: user.UpdatePasswordRequest + (*UpdatePasswordResponse)(nil), // 11: user.UpdatePasswordResponse + (*ReadSessionRequest)(nil), // 12: user.ReadSessionRequest + (*ReadSessionResponse)(nil), // 13: user.ReadSessionResponse + (*LoginRequest)(nil), // 14: user.LoginRequest + (*LoginResponse)(nil), // 15: user.LoginResponse + (*LogoutRequest)(nil), // 16: user.LogoutRequest + (*LogoutResponse)(nil), // 17: user.LogoutResponse + (*VerifyEmailRequest)(nil), // 18: user.VerifyEmailRequest + (*VerifyEmailResponse)(nil), // 19: user.VerifyEmailResponse + (*SendVerificationEmailRequest)(nil), // 20: user.SendVerificationEmailRequest + (*SendVerificationEmailResponse)(nil), // 21: user.SendVerificationEmailResponse + (*SendPasswordResetEmailRequest)(nil), // 22: user.SendPasswordResetEmailRequest + (*SendPasswordResetEmailResponse)(nil), // 23: user.SendPasswordResetEmailResponse + (*ResetPasswordRequest)(nil), // 24: user.ResetPasswordRequest + (*ResetPasswordResponse)(nil), // 25: user.ResetPasswordResponse + nil, // 26: user.Account.ProfileEntry + nil, // 27: user.CreateRequest.ProfileEntry + nil, // 28: user.UpdateRequest.ProfileEntry } var file_proto_user_proto_depIdxs = []int32{ - 22, // 0: user.Account.profile:type_name -> user.Account.ProfileEntry - 23, // 1: user.CreateRequest.profile:type_name -> user.CreateRequest.ProfileEntry + 26, // 0: user.Account.profile:type_name -> user.Account.ProfileEntry + 27, // 1: user.CreateRequest.profile:type_name -> user.CreateRequest.ProfileEntry 0, // 2: user.CreateResponse.account:type_name -> user.Account 0, // 3: user.ReadResponse.account:type_name -> user.Account - 24, // 4: user.UpdateRequest.profile:type_name -> user.UpdateRequest.ProfileEntry + 28, // 4: user.UpdateRequest.profile:type_name -> user.UpdateRequest.ProfileEntry 1, // 5: user.ReadSessionResponse.session:type_name -> user.Session 1, // 6: user.LoginResponse.session:type_name -> user.Session 2, // 7: user.User.Create:input_type -> user.CreateRequest @@ -1515,18 +1764,22 @@ var file_proto_user_proto_depIdxs = []int32{ 12, // 14: user.User.ReadSession:input_type -> user.ReadSessionRequest 18, // 15: user.User.VerifyEmail:input_type -> user.VerifyEmailRequest 20, // 16: user.User.SendVerificationEmail:input_type -> user.SendVerificationEmailRequest - 3, // 17: user.User.Create:output_type -> user.CreateResponse - 7, // 18: user.User.Read:output_type -> user.ReadResponse - 9, // 19: user.User.Update:output_type -> user.UpdateResponse - 5, // 20: user.User.Delete:output_type -> user.DeleteResponse - 11, // 21: user.User.UpdatePassword:output_type -> user.UpdatePasswordResponse - 15, // 22: user.User.Login:output_type -> user.LoginResponse - 17, // 23: user.User.Logout:output_type -> user.LogoutResponse - 13, // 24: user.User.ReadSession:output_type -> user.ReadSessionResponse - 19, // 25: user.User.VerifyEmail:output_type -> user.VerifyEmailResponse - 21, // 26: user.User.SendVerificationEmail:output_type -> user.SendVerificationEmailResponse - 17, // [17:27] is the sub-list for method output_type - 7, // [7:17] is the sub-list for method input_type + 22, // 17: user.User.SendPasswordResetEmail:input_type -> user.SendPasswordResetEmailRequest + 24, // 18: user.User.ResetPassword:input_type -> user.ResetPasswordRequest + 3, // 19: user.User.Create:output_type -> user.CreateResponse + 7, // 20: user.User.Read:output_type -> user.ReadResponse + 9, // 21: user.User.Update:output_type -> user.UpdateResponse + 5, // 22: user.User.Delete:output_type -> user.DeleteResponse + 11, // 23: user.User.UpdatePassword:output_type -> user.UpdatePasswordResponse + 15, // 24: user.User.Login:output_type -> user.LoginResponse + 17, // 25: user.User.Logout:output_type -> user.LogoutResponse + 13, // 26: user.User.ReadSession:output_type -> user.ReadSessionResponse + 19, // 27: user.User.VerifyEmail:output_type -> user.VerifyEmailResponse + 21, // 28: user.User.SendVerificationEmail:output_type -> user.SendVerificationEmailResponse + 23, // 29: user.User.SendPasswordResetEmail:output_type -> user.SendPasswordResetEmailResponse + 25, // 30: user.User.ResetPassword:output_type -> user.ResetPasswordResponse + 19, // [19:31] is the sub-list for method output_type + 7, // [7:19] is the sub-list for method input_type 7, // [7:7] is the sub-list for extension type_name 7, // [7:7] is the sub-list for extension extendee 0, // [0:7] is the sub-list for field type_name @@ -1802,6 +2055,54 @@ func file_proto_user_proto_init() { return nil } } + file_proto_user_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SendPasswordResetEmailRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_user_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SendPasswordResetEmailResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_user_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ResetPasswordRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_user_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ResetPasswordResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -1809,7 +2110,7 @@ func file_proto_user_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_proto_user_proto_rawDesc, NumEnums: 0, - NumMessages: 25, + NumMessages: 29, NumExtensions: 0, NumServices: 1, }, diff --git a/user/proto/user.pb.micro.go b/user/proto/user.pb.micro.go index 35303cb..c375448 100644 --- a/user/proto/user.pb.micro.go +++ b/user/proto/user.pb.micro.go @@ -52,6 +52,8 @@ type UserService interface { ReadSession(ctx context.Context, in *ReadSessionRequest, opts ...client.CallOption) (*ReadSessionResponse, error) VerifyEmail(ctx context.Context, in *VerifyEmailRequest, opts ...client.CallOption) (*VerifyEmailResponse, error) SendVerificationEmail(ctx context.Context, in *SendVerificationEmailRequest, opts ...client.CallOption) (*SendVerificationEmailResponse, error) + SendPasswordResetEmail(ctx context.Context, in *SendPasswordResetEmailRequest, opts ...client.CallOption) (*SendPasswordResetEmailResponse, error) + ResetPassword(ctx context.Context, in *ResetPasswordRequest, opts ...client.CallOption) (*ResetPasswordResponse, error) } type userService struct { @@ -166,6 +168,26 @@ func (c *userService) SendVerificationEmail(ctx context.Context, in *SendVerific return out, nil } +func (c *userService) SendPasswordResetEmail(ctx context.Context, in *SendPasswordResetEmailRequest, opts ...client.CallOption) (*SendPasswordResetEmailResponse, error) { + req := c.c.NewRequest(c.name, "User.SendPasswordResetEmail", in) + out := new(SendPasswordResetEmailResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userService) ResetPassword(ctx context.Context, in *ResetPasswordRequest, opts ...client.CallOption) (*ResetPasswordResponse, error) { + req := c.c.NewRequest(c.name, "User.ResetPassword", in) + out := new(ResetPasswordResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // Server API for User service type UserHandler interface { @@ -179,6 +201,8 @@ type UserHandler interface { ReadSession(context.Context, *ReadSessionRequest, *ReadSessionResponse) error VerifyEmail(context.Context, *VerifyEmailRequest, *VerifyEmailResponse) error SendVerificationEmail(context.Context, *SendVerificationEmailRequest, *SendVerificationEmailResponse) error + SendPasswordResetEmail(context.Context, *SendPasswordResetEmailRequest, *SendPasswordResetEmailResponse) error + ResetPassword(context.Context, *ResetPasswordRequest, *ResetPasswordResponse) error } func RegisterUserHandler(s server.Server, hdlr UserHandler, opts ...server.HandlerOption) error { @@ -193,6 +217,8 @@ func RegisterUserHandler(s server.Server, hdlr UserHandler, opts ...server.Handl ReadSession(ctx context.Context, in *ReadSessionRequest, out *ReadSessionResponse) error VerifyEmail(ctx context.Context, in *VerifyEmailRequest, out *VerifyEmailResponse) error SendVerificationEmail(ctx context.Context, in *SendVerificationEmailRequest, out *SendVerificationEmailResponse) error + SendPasswordResetEmail(ctx context.Context, in *SendPasswordResetEmailRequest, out *SendPasswordResetEmailResponse) error + ResetPassword(ctx context.Context, in *ResetPasswordRequest, out *ResetPasswordResponse) error } type User struct { user @@ -244,3 +270,11 @@ func (h *userHandler) VerifyEmail(ctx context.Context, in *VerifyEmailRequest, o func (h *userHandler) SendVerificationEmail(ctx context.Context, in *SendVerificationEmailRequest, out *SendVerificationEmailResponse) error { return h.UserHandler.SendVerificationEmail(ctx, in, out) } + +func (h *userHandler) SendPasswordResetEmail(ctx context.Context, in *SendPasswordResetEmailRequest, out *SendPasswordResetEmailResponse) error { + return h.UserHandler.SendPasswordResetEmail(ctx, in, out) +} + +func (h *userHandler) ResetPassword(ctx context.Context, in *ResetPasswordRequest, out *ResetPasswordResponse) error { + return h.UserHandler.ResetPassword(ctx, in, out) +} diff --git a/user/proto/user.proto b/user/proto/user.proto index 0aa7b04..e1cb85f 100644 --- a/user/proto/user.proto +++ b/user/proto/user.proto @@ -15,6 +15,8 @@ service User { rpc ReadSession(ReadSessionRequest) returns(ReadSessionResponse) {} rpc VerifyEmail(VerifyEmailRequest) returns(VerifyEmailResponse) {} rpc SendVerificationEmail(SendVerificationEmailRequest) returns (SendVerificationEmailResponse) {} + rpc SendPasswordResetEmail(SendPasswordResetEmailRequest) returns (SendPasswordResetEmailResponse) {} + rpc ResetPassword(ResetPasswordRequest) returns (ResetPasswordResponse) {} } message Account { @@ -185,3 +187,32 @@ message SendVerificationEmailRequest{ } message SendVerificationEmailResponse{} + +// Send an email with a verification code to reset password. +// Call "ResetPassword" endpoint once user provides the code. +message SendPasswordResetEmailRequest { + string email = 1; + string subject = 2; + // Text content of the email. Don't forget to include the string '$code' which will be replaced by the real verification link + // HTML emails are not available currently. + string textContent = 3; + // Display name of the sender for the email. Note: the email address will still be 'support@m3o.com' + string fromName = 4; +} + +message SendPasswordResetEmailResponse { +} + +// Reset password with the code sent by the "SendPasswordResetEmail" endoint. +message ResetPasswordRequest { + // The code from the verification email + string code = 1; + // the new password + string newPassword = 2; + // confirm new password + string confirmPassword = 3; +} + +message ResetPasswordResponse { + +} \ No newline at end of file