diff --git a/test/users/Dockerfile b/test/users/Dockerfile new file mode 100644 index 0000000..45a7a5a --- /dev/null +++ b/test/users/Dockerfile @@ -0,0 +1,3 @@ +FROM alpine:3.2 +ADD users /users +ENTRYPOINT [ "/users" ] diff --git a/test/users/Makefile b/test/users/Makefile new file mode 100644 index 0000000..ddbb866 --- /dev/null +++ b/test/users/Makefile @@ -0,0 +1,22 @@ + +GOPATH:=$(shell go env GOPATH) +.PHONY: init +init: + go get -u github.com/golang/protobuf/proto + go get -u github.com/golang/protobuf/protoc-gen-go + go get github.com/micro/micro/v3/cmd/protoc-gen-micro +.PHONY: proto +proto: + protoc --proto_path=. --micro_out=. --go_out=:. proto/users.proto + +.PHONY: build +build: + go build -o users *.go + +.PHONY: test +test: + go test -v ./... -cover + +.PHONY: docker +docker: + docker build . -t users:latest diff --git a/test/users/README.md b/test/users/README.md new file mode 100644 index 0000000..e687e5b --- /dev/null +++ b/test/users/README.md @@ -0,0 +1,73 @@ +# Users Service + +A user service for storing accounts and simple auth. + +## Getting started + +``` +micro run github.com/micro/services/users +``` + +## Usage + +User server implements the following RPC Methods + +Users +- Create +- Read +- Update +- Delete +- Search +- UpdatePassword +- Login +- Logout +- ReadSession + + +### Create + +```shell +micro call users Users.Create '{"id": "ff3c06de-9e43-41c7-9bab-578f6b4ad32b", "username": "asim", "email": "asim@example.com", "password": "password1"}' +``` + +### Read + +```shell +micro call users Users.Read '{"id": "ff3c06de-9e43-41c7-9bab-578f6b4ad32b"}' +``` + +### Update + +```shell +micro call users Users.Update '{"id": "ff3c06de-9e43-41c7-9bab-578f6b4ad32b", "username": "asim", "email": "asim+update@example.com"}' +``` + +### Update Password + +```shell +micro call users Users.UpdatePassword '{"userId": "ff3c06de-9e43-41c7-9bab-578f6b4ad32b", "oldPassword": "password1", "newPassword": "newpassword1", "confirmPassword": "newpassword1" }' +``` + +### Delete + +```shell +micro call users Users.Delete '{"id": "ff3c06de-9e43-41c7-9bab-578f6b4ad32b"}' +``` + +### Login + +```shell +micro call users Users.Login '{"username": "asim", "password": "password1"}' +``` + +### Read Session + +```shell +micro call users Users.ReadSession '{"sessionId": "sr7UEBmIMg5hYOgiljnhrd4XLsnalNewBV9KzpZ9aD8w37b3jRmEujGtKGcGlXPg1yYoSHR3RLy66ugglw0tofTNGm57NrNYUHsFxfwuGC6pvCn8BecB7aEF6UxTyVFq"}' +``` + +### Logout + +```shell +micro call users Users.Logout '{"sessionId": "sr7UEBmIMg5hYOgiljnhrd4XLsnalNewBV9KzpZ9aD8w37b3jRmEujGtKGcGlXPg1yYoSHR3RLy66ugglw0tofTNGm57NrNYUHsFxfwuGC6pvCn8BecB7aEF6UxTyVFq"}' +``` diff --git a/users/domain/domain.go b/test/users/domain/domain.go similarity index 98% rename from users/domain/domain.go rename to test/users/domain/domain.go index 115f527..471f49f 100644 --- a/users/domain/domain.go +++ b/test/users/domain/domain.go @@ -6,7 +6,7 @@ import ( "github.com/micro/dev/model" "github.com/micro/micro/v3/service/store" - user "github.com/micro/services/users/proto" + user "github.com/micro/services/test/users/proto" ) type pw struct { diff --git a/test/users/generate.go b/test/users/generate.go new file mode 100644 index 0000000..7d9db91 --- /dev/null +++ b/test/users/generate.go @@ -0,0 +1,3 @@ +package main + +//go:generate make proto diff --git a/test/users/handler/handler.go b/test/users/handler/handler.go new file mode 100644 index 0000000..8536485 --- /dev/null +++ b/test/users/handler/handler.go @@ -0,0 +1,174 @@ +package handler + +import ( + "crypto/rand" + "encoding/base64" + "strings" + "time" + + "github.com/micro/micro/v3/service/errors" + "github.com/micro/services/test/users/domain" + pb "github.com/micro/services/test/users/proto" + "golang.org/x/crypto/bcrypt" + "golang.org/x/net/context" +) + +const ( + x = "cruft123" +) + +var ( + alphanum = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" +) + +func random(i int) string { + bytes := make([]byte, i) + for { + rand.Read(bytes) + for i, b := range bytes { + bytes[i] = alphanum[b%byte(len(alphanum))] + } + return string(bytes) + } + return "ughwhy?!!!" +} + +type Users struct { + domain *domain.Domain +} + +func NewUsers() *Users { + return &Users{ + domain: domain.New(), + } +} + +func (s *Users) Create(ctx context.Context, req *pb.CreateRequest, rsp *pb.CreateResponse) error { + if len(req.Password) < 8 { + return errors.InternalServerError("users.Create.Check", "Password is less than 8 characters") + } + salt := random(16) + h, err := bcrypt.GenerateFromPassword([]byte(x+salt+req.Password), 10) + if err != nil { + return errors.InternalServerError("users.Create", err.Error()) + } + pp := base64.StdEncoding.EncodeToString(h) + + return s.domain.Create(&pb.User{ + Id: req.Id, + Username: strings.ToLower(req.Username), + Email: strings.ToLower(req.Email), + }, salt, pp) +} + +func (s *Users) Read(ctx context.Context, req *pb.ReadRequest, rsp *pb.ReadResponse) error { + user, err := s.domain.Read(req.Id) + if err != nil { + return err + } + rsp.User = user + return nil +} + +func (s *Users) Update(ctx context.Context, req *pb.UpdateRequest, rsp *pb.UpdateResponse) error { + return s.domain.Update(&pb.User{ + Id: req.Id, + Username: strings.ToLower(req.Username), + Email: strings.ToLower(req.Email), + }) +} + +func (s *Users) Delete(ctx context.Context, req *pb.DeleteRequest, rsp *pb.DeleteResponse) error { + return s.domain.Delete(req.Id) +} + +func (s *Users) Search(ctx context.Context, req *pb.SearchRequest, rsp *pb.SearchResponse) error { + users, err := s.domain.Search(req.Username, req.Email, req.Limit, req.Offset) + if err != nil { + return err + } + rsp.Users = users + return nil +} + +func (s *Users) UpdatePassword(ctx context.Context, req *pb.UpdatePasswordRequest, rsp *pb.UpdatePasswordResponse) error { + usr, err := s.domain.Read(req.UserId) + if err != nil { + return errors.InternalServerError("users.updatepassword", err.Error()) + } + if req.NewPassword != req.ConfirmPassword { + return errors.InternalServerError("users.updatepassword", "Passwords don't math") + } + + salt, hashed, err := s.domain.SaltAndPassword(usr.Username, usr.Email) + if err != nil { + return errors.InternalServerError("users.updatepassword", err.Error()) + } + + hh, err := base64.StdEncoding.DecodeString(hashed) + if err != nil { + return errors.InternalServerError("users.updatepassword", err.Error()) + } + + if err := bcrypt.CompareHashAndPassword(hh, []byte(x+salt+req.OldPassword)); err != nil { + return errors.Unauthorized("users.updatepassword", err.Error()) + } + + salt = random(16) + h, err := bcrypt.GenerateFromPassword([]byte(x+salt+req.NewPassword), 10) + if err != nil { + return errors.InternalServerError("users.updatepassword", err.Error()) + } + pp := base64.StdEncoding.EncodeToString(h) + + if err := s.domain.UpdatePassword(req.UserId, salt, pp); err != nil { + return errors.InternalServerError("users.updatepassword", err.Error()) + } + return nil +} + +func (s *Users) Login(ctx context.Context, req *pb.LoginRequest, rsp *pb.LoginResponse) error { + username := strings.ToLower(req.Username) + email := strings.ToLower(req.Email) + + salt, hashed, err := s.domain.SaltAndPassword(username, email) + if err != nil { + return err + } + + hh, err := base64.StdEncoding.DecodeString(hashed) + if err != nil { + return errors.InternalServerError("users.Login", err.Error()) + } + + if err := bcrypt.CompareHashAndPassword(hh, []byte(x+salt+req.Password)); err != nil { + return errors.Unauthorized("users.login", err.Error()) + } + // save session + sess := &pb.Session{ + Id: random(128), + Username: username, + Email: email, + Created: time.Now().Unix(), + Expires: time.Now().Add(time.Hour * 24 * 7).Unix(), + } + + if err := s.domain.CreateSession(sess); err != nil { + return errors.InternalServerError("users.Login", err.Error()) + } + rsp.Session = sess + return nil +} + +func (s *Users) Logout(ctx context.Context, req *pb.LogoutRequest, rsp *pb.LogoutResponse) error { + return s.domain.DeleteSession(req.SessionId) +} + +func (s *Users) ReadSession(ctx context.Context, req *pb.ReadSessionRequest, rsp *pb.ReadSessionResponse) error { + sess, err := s.domain.ReadSession(req.SessionId) + if err != nil { + return err + } + rsp.Session = sess + return nil +} diff --git a/test/users/main.go b/test/users/main.go new file mode 100644 index 0000000..20ee73e --- /dev/null +++ b/test/users/main.go @@ -0,0 +1,22 @@ +package main + +import ( + "github.com/micro/micro/v3/service" + "github.com/micro/micro/v3/service/logger" + "github.com/micro/services/test/users/handler" + proto "github.com/micro/services/test/users/proto" +) + +func main() { + service := service.New( + service.Name("users"), + ) + + service.Init() + + proto.RegisterUsersHandler(service.Server(), handler.NewUsers()) + + if err := service.Run(); err != nil { + logger.Fatal(err) + } +} diff --git a/test/users/micro.mu b/test/users/micro.mu new file mode 100644 index 0000000..3f68786 --- /dev/null +++ b/test/users/micro.mu @@ -0,0 +1 @@ +service users diff --git a/test/users/proto/users.pb.go b/test/users/proto/users.pb.go new file mode 100644 index 0000000..e709ffa --- /dev/null +++ b/test/users/proto/users.pb.go @@ -0,0 +1,998 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: proto/users.proto + +package users + +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +type User struct { + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"` + Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` + Created int64 `protobuf:"varint,4,opt,name=created,proto3" json:"created,omitempty"` + Updated int64 `protobuf:"varint,5,opt,name=updated,proto3" json:"updated,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *User) Reset() { *m = User{} } +func (m *User) String() string { return proto.CompactTextString(m) } +func (*User) ProtoMessage() {} +func (*User) Descriptor() ([]byte, []int) { + return fileDescriptor_b1c161a4c7514913, []int{0} +} + +func (m *User) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_User.Unmarshal(m, b) +} +func (m *User) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_User.Marshal(b, m, deterministic) +} +func (m *User) XXX_Merge(src proto.Message) { + xxx_messageInfo_User.Merge(m, src) +} +func (m *User) XXX_Size() int { + return xxx_messageInfo_User.Size(m) +} +func (m *User) XXX_DiscardUnknown() { + xxx_messageInfo_User.DiscardUnknown(m) +} + +var xxx_messageInfo_User proto.InternalMessageInfo + +func (m *User) GetId() string { + if m != nil { + return m.Id + } + return "" +} + +func (m *User) GetUsername() string { + if m != nil { + return m.Username + } + return "" +} + +func (m *User) GetEmail() string { + if m != nil { + return m.Email + } + return "" +} + +func (m *User) GetCreated() int64 { + if m != nil { + return m.Created + } + return 0 +} + +func (m *User) GetUpdated() int64 { + if m != nil { + return m.Updated + } + return 0 +} + +type Session struct { + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"` + Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` + Created int64 `protobuf:"varint,4,opt,name=created,proto3" json:"created,omitempty"` + Expires int64 `protobuf:"varint,5,opt,name=expires,proto3" json:"expires,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Session) Reset() { *m = Session{} } +func (m *Session) String() string { return proto.CompactTextString(m) } +func (*Session) ProtoMessage() {} +func (*Session) Descriptor() ([]byte, []int) { + return fileDescriptor_b1c161a4c7514913, []int{1} +} + +func (m *Session) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Session.Unmarshal(m, b) +} +func (m *Session) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Session.Marshal(b, m, deterministic) +} +func (m *Session) XXX_Merge(src proto.Message) { + xxx_messageInfo_Session.Merge(m, src) +} +func (m *Session) XXX_Size() int { + return xxx_messageInfo_Session.Size(m) +} +func (m *Session) XXX_DiscardUnknown() { + xxx_messageInfo_Session.DiscardUnknown(m) +} + +var xxx_messageInfo_Session proto.InternalMessageInfo + +func (m *Session) GetId() string { + if m != nil { + return m.Id + } + return "" +} + +func (m *Session) GetUsername() string { + if m != nil { + return m.Username + } + return "" +} + +func (m *Session) GetEmail() string { + if m != nil { + return m.Email + } + return "" +} + +func (m *Session) GetCreated() int64 { + if m != nil { + return m.Created + } + return 0 +} + +func (m *Session) GetExpires() int64 { + if m != nil { + return m.Expires + } + return 0 +} + +type CreateRequest struct { + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"` + Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` + Password string `protobuf:"bytes,4,opt,name=password,proto3" json:"password,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateRequest) Reset() { *m = CreateRequest{} } +func (m *CreateRequest) String() string { return proto.CompactTextString(m) } +func (*CreateRequest) ProtoMessage() {} +func (*CreateRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_b1c161a4c7514913, []int{2} +} + +func (m *CreateRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CreateRequest.Unmarshal(m, b) +} +func (m *CreateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CreateRequest.Marshal(b, m, deterministic) +} +func (m *CreateRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateRequest.Merge(m, src) +} +func (m *CreateRequest) XXX_Size() int { + return xxx_messageInfo_CreateRequest.Size(m) +} +func (m *CreateRequest) XXX_DiscardUnknown() { + xxx_messageInfo_CreateRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateRequest proto.InternalMessageInfo + +func (m *CreateRequest) GetId() string { + if m != nil { + return m.Id + } + return "" +} + +func (m *CreateRequest) GetUsername() string { + if m != nil { + return m.Username + } + return "" +} + +func (m *CreateRequest) GetEmail() string { + if m != nil { + return m.Email + } + return "" +} + +func (m *CreateRequest) GetPassword() string { + if m != nil { + return m.Password + } + return "" +} + +type CreateResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateResponse) Reset() { *m = CreateResponse{} } +func (m *CreateResponse) String() string { return proto.CompactTextString(m) } +func (*CreateResponse) ProtoMessage() {} +func (*CreateResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_b1c161a4c7514913, []int{3} +} + +func (m *CreateResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CreateResponse.Unmarshal(m, b) +} +func (m *CreateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CreateResponse.Marshal(b, m, deterministic) +} +func (m *CreateResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateResponse.Merge(m, src) +} +func (m *CreateResponse) XXX_Size() int { + return xxx_messageInfo_CreateResponse.Size(m) +} +func (m *CreateResponse) XXX_DiscardUnknown() { + xxx_messageInfo_CreateResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateResponse proto.InternalMessageInfo + +type DeleteRequest struct { + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteRequest) Reset() { *m = DeleteRequest{} } +func (m *DeleteRequest) String() string { return proto.CompactTextString(m) } +func (*DeleteRequest) ProtoMessage() {} +func (*DeleteRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_b1c161a4c7514913, []int{4} +} + +func (m *DeleteRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteRequest.Unmarshal(m, b) +} +func (m *DeleteRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteRequest.Marshal(b, m, deterministic) +} +func (m *DeleteRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteRequest.Merge(m, src) +} +func (m *DeleteRequest) XXX_Size() int { + return xxx_messageInfo_DeleteRequest.Size(m) +} +func (m *DeleteRequest) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteRequest proto.InternalMessageInfo + +func (m *DeleteRequest) GetId() string { + if m != nil { + return m.Id + } + return "" +} + +type DeleteResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteResponse) Reset() { *m = DeleteResponse{} } +func (m *DeleteResponse) String() string { return proto.CompactTextString(m) } +func (*DeleteResponse) ProtoMessage() {} +func (*DeleteResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_b1c161a4c7514913, []int{5} +} + +func (m *DeleteResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteResponse.Unmarshal(m, b) +} +func (m *DeleteResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteResponse.Marshal(b, m, deterministic) +} +func (m *DeleteResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteResponse.Merge(m, src) +} +func (m *DeleteResponse) XXX_Size() int { + return xxx_messageInfo_DeleteResponse.Size(m) +} +func (m *DeleteResponse) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteResponse proto.InternalMessageInfo + +type ReadRequest struct { + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ReadRequest) Reset() { *m = ReadRequest{} } +func (m *ReadRequest) String() string { return proto.CompactTextString(m) } +func (*ReadRequest) ProtoMessage() {} +func (*ReadRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_b1c161a4c7514913, []int{6} +} + +func (m *ReadRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ReadRequest.Unmarshal(m, b) +} +func (m *ReadRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ReadRequest.Marshal(b, m, deterministic) +} +func (m *ReadRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ReadRequest.Merge(m, src) +} +func (m *ReadRequest) XXX_Size() int { + return xxx_messageInfo_ReadRequest.Size(m) +} +func (m *ReadRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ReadRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_ReadRequest proto.InternalMessageInfo + +func (m *ReadRequest) GetId() string { + if m != nil { + return m.Id + } + return "" +} + +type ReadResponse struct { + User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ReadResponse) Reset() { *m = ReadResponse{} } +func (m *ReadResponse) String() string { return proto.CompactTextString(m) } +func (*ReadResponse) ProtoMessage() {} +func (*ReadResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_b1c161a4c7514913, []int{7} +} + +func (m *ReadResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ReadResponse.Unmarshal(m, b) +} +func (m *ReadResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ReadResponse.Marshal(b, m, deterministic) +} +func (m *ReadResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ReadResponse.Merge(m, src) +} +func (m *ReadResponse) XXX_Size() int { + return xxx_messageInfo_ReadResponse.Size(m) +} +func (m *ReadResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ReadResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_ReadResponse proto.InternalMessageInfo + +func (m *ReadResponse) GetUser() *User { + if m != nil { + return m.User + } + return nil +} + +type UpdateRequest struct { + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"` + Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateRequest) Reset() { *m = UpdateRequest{} } +func (m *UpdateRequest) String() string { return proto.CompactTextString(m) } +func (*UpdateRequest) ProtoMessage() {} +func (*UpdateRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_b1c161a4c7514913, []int{8} +} + +func (m *UpdateRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UpdateRequest.Unmarshal(m, b) +} +func (m *UpdateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UpdateRequest.Marshal(b, m, deterministic) +} +func (m *UpdateRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateRequest.Merge(m, src) +} +func (m *UpdateRequest) XXX_Size() int { + return xxx_messageInfo_UpdateRequest.Size(m) +} +func (m *UpdateRequest) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_UpdateRequest proto.InternalMessageInfo + +func (m *UpdateRequest) GetId() string { + if m != nil { + return m.Id + } + return "" +} + +func (m *UpdateRequest) GetUsername() string { + if m != nil { + return m.Username + } + return "" +} + +func (m *UpdateRequest) GetEmail() string { + if m != nil { + return m.Email + } + return "" +} + +type UpdateResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateResponse) Reset() { *m = UpdateResponse{} } +func (m *UpdateResponse) String() string { return proto.CompactTextString(m) } +func (*UpdateResponse) ProtoMessage() {} +func (*UpdateResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_b1c161a4c7514913, []int{9} +} + +func (m *UpdateResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UpdateResponse.Unmarshal(m, b) +} +func (m *UpdateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UpdateResponse.Marshal(b, m, deterministic) +} +func (m *UpdateResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateResponse.Merge(m, src) +} +func (m *UpdateResponse) XXX_Size() int { + return xxx_messageInfo_UpdateResponse.Size(m) +} +func (m *UpdateResponse) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_UpdateResponse proto.InternalMessageInfo + +type UpdatePasswordRequest struct { + UserId string `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"` + OldPassword string `protobuf:"bytes,2,opt,name=oldPassword,proto3" json:"oldPassword,omitempty"` + NewPassword string `protobuf:"bytes,3,opt,name=newPassword,proto3" json:"newPassword,omitempty"` + ConfirmPassword string `protobuf:"bytes,4,opt,name=confirm_password,json=confirmPassword,proto3" json:"confirm_password,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdatePasswordRequest) Reset() { *m = UpdatePasswordRequest{} } +func (m *UpdatePasswordRequest) String() string { return proto.CompactTextString(m) } +func (*UpdatePasswordRequest) ProtoMessage() {} +func (*UpdatePasswordRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_b1c161a4c7514913, []int{10} +} + +func (m *UpdatePasswordRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UpdatePasswordRequest.Unmarshal(m, b) +} +func (m *UpdatePasswordRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UpdatePasswordRequest.Marshal(b, m, deterministic) +} +func (m *UpdatePasswordRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdatePasswordRequest.Merge(m, src) +} +func (m *UpdatePasswordRequest) XXX_Size() int { + return xxx_messageInfo_UpdatePasswordRequest.Size(m) +} +func (m *UpdatePasswordRequest) XXX_DiscardUnknown() { + xxx_messageInfo_UpdatePasswordRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_UpdatePasswordRequest proto.InternalMessageInfo + +func (m *UpdatePasswordRequest) GetUserId() string { + if m != nil { + return m.UserId + } + return "" +} + +func (m *UpdatePasswordRequest) GetOldPassword() string { + if m != nil { + return m.OldPassword + } + return "" +} + +func (m *UpdatePasswordRequest) GetNewPassword() string { + if m != nil { + return m.NewPassword + } + return "" +} + +func (m *UpdatePasswordRequest) GetConfirmPassword() string { + if m != nil { + return m.ConfirmPassword + } + return "" +} + +type UpdatePasswordResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdatePasswordResponse) Reset() { *m = UpdatePasswordResponse{} } +func (m *UpdatePasswordResponse) String() string { return proto.CompactTextString(m) } +func (*UpdatePasswordResponse) ProtoMessage() {} +func (*UpdatePasswordResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_b1c161a4c7514913, []int{11} +} + +func (m *UpdatePasswordResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UpdatePasswordResponse.Unmarshal(m, b) +} +func (m *UpdatePasswordResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UpdatePasswordResponse.Marshal(b, m, deterministic) +} +func (m *UpdatePasswordResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdatePasswordResponse.Merge(m, src) +} +func (m *UpdatePasswordResponse) XXX_Size() int { + return xxx_messageInfo_UpdatePasswordResponse.Size(m) +} +func (m *UpdatePasswordResponse) XXX_DiscardUnknown() { + xxx_messageInfo_UpdatePasswordResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_UpdatePasswordResponse proto.InternalMessageInfo + +type SearchRequest struct { + Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` + Email string `protobuf:"bytes,2,opt,name=email,proto3" json:"email,omitempty"` + Limit int64 `protobuf:"varint,3,opt,name=limit,proto3" json:"limit,omitempty"` + Offset int64 `protobuf:"varint,4,opt,name=offset,proto3" json:"offset,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SearchRequest) Reset() { *m = SearchRequest{} } +func (m *SearchRequest) String() string { return proto.CompactTextString(m) } +func (*SearchRequest) ProtoMessage() {} +func (*SearchRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_b1c161a4c7514913, []int{12} +} + +func (m *SearchRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SearchRequest.Unmarshal(m, b) +} +func (m *SearchRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SearchRequest.Marshal(b, m, deterministic) +} +func (m *SearchRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_SearchRequest.Merge(m, src) +} +func (m *SearchRequest) XXX_Size() int { + return xxx_messageInfo_SearchRequest.Size(m) +} +func (m *SearchRequest) XXX_DiscardUnknown() { + xxx_messageInfo_SearchRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_SearchRequest proto.InternalMessageInfo + +func (m *SearchRequest) GetUsername() string { + if m != nil { + return m.Username + } + return "" +} + +func (m *SearchRequest) GetEmail() string { + if m != nil { + return m.Email + } + return "" +} + +func (m *SearchRequest) GetLimit() int64 { + if m != nil { + return m.Limit + } + return 0 +} + +func (m *SearchRequest) GetOffset() int64 { + if m != nil { + return m.Offset + } + return 0 +} + +type SearchResponse struct { + Users []*User `protobuf:"bytes,1,rep,name=users,proto3" json:"users,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SearchResponse) Reset() { *m = SearchResponse{} } +func (m *SearchResponse) String() string { return proto.CompactTextString(m) } +func (*SearchResponse) ProtoMessage() {} +func (*SearchResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_b1c161a4c7514913, []int{13} +} + +func (m *SearchResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SearchResponse.Unmarshal(m, b) +} +func (m *SearchResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SearchResponse.Marshal(b, m, deterministic) +} +func (m *SearchResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_SearchResponse.Merge(m, src) +} +func (m *SearchResponse) XXX_Size() int { + return xxx_messageInfo_SearchResponse.Size(m) +} +func (m *SearchResponse) XXX_DiscardUnknown() { + xxx_messageInfo_SearchResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_SearchResponse proto.InternalMessageInfo + +func (m *SearchResponse) GetUsers() []*User { + if m != nil { + return m.Users + } + return nil +} + +type ReadSessionRequest struct { + SessionId string `protobuf:"bytes,1,opt,name=sessionId,proto3" json:"sessionId,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ReadSessionRequest) Reset() { *m = ReadSessionRequest{} } +func (m *ReadSessionRequest) String() string { return proto.CompactTextString(m) } +func (*ReadSessionRequest) ProtoMessage() {} +func (*ReadSessionRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_b1c161a4c7514913, []int{14} +} + +func (m *ReadSessionRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ReadSessionRequest.Unmarshal(m, b) +} +func (m *ReadSessionRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ReadSessionRequest.Marshal(b, m, deterministic) +} +func (m *ReadSessionRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ReadSessionRequest.Merge(m, src) +} +func (m *ReadSessionRequest) XXX_Size() int { + return xxx_messageInfo_ReadSessionRequest.Size(m) +} +func (m *ReadSessionRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ReadSessionRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_ReadSessionRequest proto.InternalMessageInfo + +func (m *ReadSessionRequest) GetSessionId() string { + if m != nil { + return m.SessionId + } + return "" +} + +type ReadSessionResponse struct { + Session *Session `protobuf:"bytes,1,opt,name=session,proto3" json:"session,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ReadSessionResponse) Reset() { *m = ReadSessionResponse{} } +func (m *ReadSessionResponse) String() string { return proto.CompactTextString(m) } +func (*ReadSessionResponse) ProtoMessage() {} +func (*ReadSessionResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_b1c161a4c7514913, []int{15} +} + +func (m *ReadSessionResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ReadSessionResponse.Unmarshal(m, b) +} +func (m *ReadSessionResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ReadSessionResponse.Marshal(b, m, deterministic) +} +func (m *ReadSessionResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ReadSessionResponse.Merge(m, src) +} +func (m *ReadSessionResponse) XXX_Size() int { + return xxx_messageInfo_ReadSessionResponse.Size(m) +} +func (m *ReadSessionResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ReadSessionResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_ReadSessionResponse proto.InternalMessageInfo + +func (m *ReadSessionResponse) GetSession() *Session { + if m != nil { + return m.Session + } + return nil +} + +type LoginRequest struct { + Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` + Email string `protobuf:"bytes,2,opt,name=email,proto3" json:"email,omitempty"` + Password string `protobuf:"bytes,3,opt,name=password,proto3" json:"password,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *LoginRequest) Reset() { *m = LoginRequest{} } +func (m *LoginRequest) String() string { return proto.CompactTextString(m) } +func (*LoginRequest) ProtoMessage() {} +func (*LoginRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_b1c161a4c7514913, []int{16} +} + +func (m *LoginRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_LoginRequest.Unmarshal(m, b) +} +func (m *LoginRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_LoginRequest.Marshal(b, m, deterministic) +} +func (m *LoginRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_LoginRequest.Merge(m, src) +} +func (m *LoginRequest) XXX_Size() int { + return xxx_messageInfo_LoginRequest.Size(m) +} +func (m *LoginRequest) XXX_DiscardUnknown() { + xxx_messageInfo_LoginRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_LoginRequest proto.InternalMessageInfo + +func (m *LoginRequest) GetUsername() string { + if m != nil { + return m.Username + } + return "" +} + +func (m *LoginRequest) GetEmail() string { + if m != nil { + return m.Email + } + return "" +} + +func (m *LoginRequest) GetPassword() string { + if m != nil { + return m.Password + } + return "" +} + +type LoginResponse struct { + Session *Session `protobuf:"bytes,1,opt,name=session,proto3" json:"session,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *LoginResponse) Reset() { *m = LoginResponse{} } +func (m *LoginResponse) String() string { return proto.CompactTextString(m) } +func (*LoginResponse) ProtoMessage() {} +func (*LoginResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_b1c161a4c7514913, []int{17} +} + +func (m *LoginResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_LoginResponse.Unmarshal(m, b) +} +func (m *LoginResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_LoginResponse.Marshal(b, m, deterministic) +} +func (m *LoginResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_LoginResponse.Merge(m, src) +} +func (m *LoginResponse) XXX_Size() int { + return xxx_messageInfo_LoginResponse.Size(m) +} +func (m *LoginResponse) XXX_DiscardUnknown() { + xxx_messageInfo_LoginResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_LoginResponse proto.InternalMessageInfo + +func (m *LoginResponse) GetSession() *Session { + if m != nil { + return m.Session + } + return nil +} + +type LogoutRequest struct { + SessionId string `protobuf:"bytes,1,opt,name=sessionId,proto3" json:"sessionId,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *LogoutRequest) Reset() { *m = LogoutRequest{} } +func (m *LogoutRequest) String() string { return proto.CompactTextString(m) } +func (*LogoutRequest) ProtoMessage() {} +func (*LogoutRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_b1c161a4c7514913, []int{18} +} + +func (m *LogoutRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_LogoutRequest.Unmarshal(m, b) +} +func (m *LogoutRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_LogoutRequest.Marshal(b, m, deterministic) +} +func (m *LogoutRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_LogoutRequest.Merge(m, src) +} +func (m *LogoutRequest) XXX_Size() int { + return xxx_messageInfo_LogoutRequest.Size(m) +} +func (m *LogoutRequest) XXX_DiscardUnknown() { + xxx_messageInfo_LogoutRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_LogoutRequest proto.InternalMessageInfo + +func (m *LogoutRequest) GetSessionId() string { + if m != nil { + return m.SessionId + } + return "" +} + +type LogoutResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *LogoutResponse) Reset() { *m = LogoutResponse{} } +func (m *LogoutResponse) String() string { return proto.CompactTextString(m) } +func (*LogoutResponse) ProtoMessage() {} +func (*LogoutResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_b1c161a4c7514913, []int{19} +} + +func (m *LogoutResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_LogoutResponse.Unmarshal(m, b) +} +func (m *LogoutResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_LogoutResponse.Marshal(b, m, deterministic) +} +func (m *LogoutResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_LogoutResponse.Merge(m, src) +} +func (m *LogoutResponse) XXX_Size() int { + return xxx_messageInfo_LogoutResponse.Size(m) +} +func (m *LogoutResponse) XXX_DiscardUnknown() { + xxx_messageInfo_LogoutResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_LogoutResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*User)(nil), "User") + proto.RegisterType((*Session)(nil), "Session") + proto.RegisterType((*CreateRequest)(nil), "CreateRequest") + proto.RegisterType((*CreateResponse)(nil), "CreateResponse") + proto.RegisterType((*DeleteRequest)(nil), "DeleteRequest") + proto.RegisterType((*DeleteResponse)(nil), "DeleteResponse") + proto.RegisterType((*ReadRequest)(nil), "ReadRequest") + proto.RegisterType((*ReadResponse)(nil), "ReadResponse") + proto.RegisterType((*UpdateRequest)(nil), "UpdateRequest") + proto.RegisterType((*UpdateResponse)(nil), "UpdateResponse") + proto.RegisterType((*UpdatePasswordRequest)(nil), "UpdatePasswordRequest") + proto.RegisterType((*UpdatePasswordResponse)(nil), "UpdatePasswordResponse") + proto.RegisterType((*SearchRequest)(nil), "SearchRequest") + proto.RegisterType((*SearchResponse)(nil), "SearchResponse") + proto.RegisterType((*ReadSessionRequest)(nil), "ReadSessionRequest") + proto.RegisterType((*ReadSessionResponse)(nil), "ReadSessionResponse") + proto.RegisterType((*LoginRequest)(nil), "LoginRequest") + proto.RegisterType((*LoginResponse)(nil), "LoginResponse") + proto.RegisterType((*LogoutRequest)(nil), "LogoutRequest") + proto.RegisterType((*LogoutResponse)(nil), "LogoutResponse") +} + +func init() { + proto.RegisterFile("proto/users.proto", fileDescriptor_b1c161a4c7514913) +} + +var fileDescriptor_b1c161a4c7514913 = []byte{ + // 600 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x55, 0xcf, 0x6e, 0xd3, 0x4e, + 0x10, 0x4e, 0xe2, 0x38, 0x69, 0x27, 0x71, 0xda, 0xdf, 0xb6, 0xbf, 0x60, 0x0c, 0x88, 0x6a, 0x25, + 0xa4, 0x56, 0xa8, 0x8b, 0x94, 0x9e, 0xe0, 0x5a, 0x2e, 0x48, 0x1c, 0xc0, 0x55, 0x6f, 0x48, 0xc8, + 0x24, 0x1b, 0xb0, 0x14, 0x7b, 0x8d, 0xd7, 0x51, 0x39, 0x20, 0xf1, 0x26, 0x3c, 0x08, 0x4f, 0xc7, + 0xec, 0xbf, 0xc4, 0x36, 0x8d, 0x04, 0xa8, 0xdc, 0x3c, 0x33, 0xdf, 0xec, 0x7c, 0x3b, 0x33, 0xdf, + 0x1a, 0xfe, 0x2b, 0x4a, 0x51, 0x89, 0x67, 0x6b, 0xc9, 0x4b, 0xc9, 0xf4, 0x37, 0xfd, 0x0a, 0xfd, + 0x6b, 0x34, 0xc9, 0x04, 0x7a, 0xe9, 0x22, 0xec, 0x9e, 0x74, 0x4f, 0xf7, 0x63, 0xfc, 0x22, 0x11, + 0xec, 0x29, 0x58, 0x9e, 0x64, 0x3c, 0xec, 0x69, 0xef, 0xc6, 0x26, 0xc7, 0xe0, 0xf3, 0x2c, 0x49, + 0x57, 0xa1, 0xa7, 0x03, 0xc6, 0x20, 0x21, 0x0c, 0xe7, 0x25, 0x4f, 0x2a, 0xbe, 0x08, 0xfb, 0xe8, + 0xf7, 0x62, 0x67, 0xaa, 0xc8, 0xba, 0x58, 0xe8, 0x88, 0x6f, 0x22, 0xd6, 0xa4, 0xdf, 0x60, 0x78, + 0xc5, 0xa5, 0x4c, 0x45, 0xfe, 0xaf, 0x09, 0xf0, 0x2f, 0x45, 0x5a, 0x72, 0xe9, 0x08, 0x58, 0x93, + 0x66, 0x10, 0x5c, 0x6a, 0x50, 0xcc, 0x3f, 0xaf, 0xb9, 0xac, 0xee, 0x80, 0x06, 0x66, 0x14, 0x89, + 0x94, 0x37, 0xa2, 0x34, 0x3c, 0x30, 0xc3, 0xd9, 0xf4, 0x10, 0x26, 0xae, 0x9c, 0x2c, 0x44, 0x2e, + 0x39, 0x7d, 0x0c, 0xc1, 0x4b, 0xbe, 0xe2, 0x3b, 0x09, 0xa8, 0x14, 0x07, 0xb0, 0x29, 0x8f, 0x60, + 0x14, 0xf3, 0x64, 0xb1, 0x2b, 0xe1, 0x0c, 0xc6, 0x26, 0x6c, 0xe0, 0xe4, 0x3e, 0xf4, 0x15, 0x63, + 0x8d, 0x18, 0xcd, 0x7c, 0xa6, 0xc6, 0x1d, 0x6b, 0x17, 0x7d, 0x0b, 0xc1, 0xb5, 0x9e, 0xc4, 0x9d, + 0xdd, 0x5e, 0xd1, 0x75, 0x47, 0x5a, 0xba, 0xdf, 0xbb, 0xf0, 0xbf, 0x71, 0xbd, 0xb1, 0x6d, 0x70, + 0xd5, 0xa6, 0x30, 0x50, 0xa7, 0xbd, 0x72, 0x15, 0xad, 0x45, 0x4e, 0x60, 0x24, 0x56, 0x0b, 0x87, + 0xb6, 0x85, 0xeb, 0x2e, 0x85, 0xc8, 0xf9, 0xcd, 0x06, 0x61, 0x18, 0xd4, 0x5d, 0xe4, 0x0c, 0x0e, + 0xe7, 0x22, 0x5f, 0xa6, 0x65, 0xf6, 0xbe, 0x35, 0x8d, 0x03, 0xeb, 0x77, 0x50, 0x1a, 0xc2, 0xb4, + 0xcd, 0xcf, 0x52, 0x17, 0x10, 0x5c, 0xf1, 0xa4, 0x9c, 0x7f, 0x72, 0x8c, 0xeb, 0xfd, 0xe8, 0xee, + 0xea, 0x47, 0xaf, 0xbe, 0x0d, 0xe8, 0x5d, 0xa5, 0x59, 0x5a, 0x69, 0x8e, 0x5e, 0x6c, 0x0c, 0x75, + 0x73, 0xb1, 0x5c, 0x4a, 0x5e, 0xd9, 0x4d, 0xb5, 0x16, 0x3d, 0x87, 0x89, 0x2b, 0x68, 0xa7, 0xf7, + 0x00, 0x7c, 0x2d, 0x57, 0x2c, 0xe7, 0x6d, 0xc7, 0x67, 0x7c, 0x74, 0x06, 0x44, 0x8d, 0xda, 0x4a, + 0xc8, 0x91, 0x7c, 0x08, 0xfb, 0xd2, 0x78, 0x36, 0x9d, 0xdd, 0x3a, 0xe8, 0x73, 0x38, 0x6a, 0xe4, + 0xd8, 0x3a, 0x14, 0x86, 0x16, 0x63, 0x17, 0x65, 0x8f, 0x39, 0x88, 0x0b, 0xd0, 0x77, 0x30, 0x7e, + 0x2d, 0x3e, 0xa6, 0xf9, 0xdf, 0x77, 0xa3, 0xae, 0x0d, 0xaf, 0xa5, 0x8d, 0x0b, 0x08, 0xec, 0xe9, + 0x7f, 0x40, 0xe9, 0x5c, 0x27, 0x89, 0x75, 0xf5, 0x7b, 0x97, 0xc7, 0xed, 0x74, 0x70, 0x53, 0x64, + 0xf6, 0xc3, 0x03, 0x5f, 0xb5, 0x54, 0x92, 0xa7, 0x30, 0x30, 0xda, 0x24, 0x13, 0xd6, 0x78, 0x13, + 0xa2, 0x03, 0xd6, 0x12, 0x6d, 0x87, 0x3c, 0x81, 0xbe, 0xea, 0x22, 0x19, 0xb3, 0x9a, 0x14, 0xa3, + 0x80, 0xd5, 0x95, 0x87, 0x30, 0x3c, 0xd3, 0xac, 0x16, 0x9e, 0xd9, 0x50, 0x1a, 0x9e, 0xd9, 0x92, + 0x89, 0x06, 0x1b, 0xa5, 0x23, 0xb8, 0xf1, 0x26, 0x20, 0xb8, 0xf5, 0x04, 0x68, 0xb0, 0xd9, 0x14, + 0x04, 0x37, 0x76, 0x14, 0xc1, 0xcd, 0x15, 0x42, 0xf0, 0xa5, 0x13, 0xe5, 0x46, 0x1e, 0x53, 0x76, + 0xab, 0x24, 0xa3, 0x7b, 0x6c, 0x87, 0x14, 0x3a, 0xe4, 0x14, 0x7c, 0x3d, 0x1f, 0x12, 0xb0, 0xfa, + 0x16, 0x44, 0x13, 0xd6, 0x18, 0x9b, 0xe1, 0x66, 0xba, 0x4c, 0x74, 0x6c, 0x3b, 0x1d, 0xe4, 0xd6, + 0x6c, 0x3f, 0x82, 0x5f, 0x98, 0xd7, 0xcc, 0xfd, 0x06, 0x8e, 0xd8, 0xaf, 0x1b, 0x1d, 0x1d, 0xb3, + 0x5b, 0x56, 0x96, 0x76, 0x3e, 0x0c, 0xf4, 0x3f, 0xec, 0xe2, 0x67, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xc7, 0x99, 0xc1, 0x0c, 0xd8, 0x06, 0x00, 0x00, +} diff --git a/test/users/proto/users.pb.micro.go b/test/users/proto/users.pb.micro.go new file mode 100644 index 0000000..0e48876 --- /dev/null +++ b/test/users/proto/users.pb.micro.go @@ -0,0 +1,229 @@ +// Code generated by protoc-gen-micro. DO NOT EDIT. +// source: proto/users.proto + +package users + +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + math "math" +) + +import ( + context "context" + api "github.com/micro/micro/v3/service/api" + client "github.com/micro/micro/v3/service/client" + server "github.com/micro/micro/v3/service/server" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +// Reference imports to suppress errors if they are not otherwise used. +var _ api.Endpoint +var _ context.Context +var _ client.Option +var _ server.Option + +// Api Endpoints for Users service + +func NewUsersEndpoints() []*api.Endpoint { + return []*api.Endpoint{} +} + +// Client API for Users service + +type UsersService interface { + Create(ctx context.Context, in *CreateRequest, opts ...client.CallOption) (*CreateResponse, error) + Read(ctx context.Context, in *ReadRequest, opts ...client.CallOption) (*ReadResponse, error) + Update(ctx context.Context, in *UpdateRequest, opts ...client.CallOption) (*UpdateResponse, error) + Delete(ctx context.Context, in *DeleteRequest, opts ...client.CallOption) (*DeleteResponse, error) + Search(ctx context.Context, in *SearchRequest, opts ...client.CallOption) (*SearchResponse, error) + UpdatePassword(ctx context.Context, in *UpdatePasswordRequest, opts ...client.CallOption) (*UpdatePasswordResponse, error) + Login(ctx context.Context, in *LoginRequest, opts ...client.CallOption) (*LoginResponse, error) + Logout(ctx context.Context, in *LogoutRequest, opts ...client.CallOption) (*LogoutResponse, error) + ReadSession(ctx context.Context, in *ReadSessionRequest, opts ...client.CallOption) (*ReadSessionResponse, error) +} + +type usersService struct { + c client.Client + name string +} + +func NewUsersService(name string, c client.Client) UsersService { + return &usersService{ + c: c, + name: name, + } +} + +func (c *usersService) Create(ctx context.Context, in *CreateRequest, opts ...client.CallOption) (*CreateResponse, error) { + req := c.c.NewRequest(c.name, "Users.Create", in) + out := new(CreateResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *usersService) Read(ctx context.Context, in *ReadRequest, opts ...client.CallOption) (*ReadResponse, error) { + req := c.c.NewRequest(c.name, "Users.Read", in) + out := new(ReadResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *usersService) Update(ctx context.Context, in *UpdateRequest, opts ...client.CallOption) (*UpdateResponse, error) { + req := c.c.NewRequest(c.name, "Users.Update", in) + out := new(UpdateResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *usersService) Delete(ctx context.Context, in *DeleteRequest, opts ...client.CallOption) (*DeleteResponse, error) { + req := c.c.NewRequest(c.name, "Users.Delete", in) + out := new(DeleteResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *usersService) Search(ctx context.Context, in *SearchRequest, opts ...client.CallOption) (*SearchResponse, error) { + req := c.c.NewRequest(c.name, "Users.Search", in) + out := new(SearchResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *usersService) UpdatePassword(ctx context.Context, in *UpdatePasswordRequest, opts ...client.CallOption) (*UpdatePasswordResponse, error) { + req := c.c.NewRequest(c.name, "Users.UpdatePassword", in) + out := new(UpdatePasswordResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *usersService) Login(ctx context.Context, in *LoginRequest, opts ...client.CallOption) (*LoginResponse, error) { + req := c.c.NewRequest(c.name, "Users.Login", in) + out := new(LoginResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *usersService) Logout(ctx context.Context, in *LogoutRequest, opts ...client.CallOption) (*LogoutResponse, error) { + req := c.c.NewRequest(c.name, "Users.Logout", in) + out := new(LogoutResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *usersService) ReadSession(ctx context.Context, in *ReadSessionRequest, opts ...client.CallOption) (*ReadSessionResponse, error) { + req := c.c.NewRequest(c.name, "Users.ReadSession", in) + out := new(ReadSessionResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for Users service + +type UsersHandler interface { + Create(context.Context, *CreateRequest, *CreateResponse) error + Read(context.Context, *ReadRequest, *ReadResponse) error + Update(context.Context, *UpdateRequest, *UpdateResponse) error + Delete(context.Context, *DeleteRequest, *DeleteResponse) error + Search(context.Context, *SearchRequest, *SearchResponse) error + UpdatePassword(context.Context, *UpdatePasswordRequest, *UpdatePasswordResponse) error + Login(context.Context, *LoginRequest, *LoginResponse) error + Logout(context.Context, *LogoutRequest, *LogoutResponse) error + ReadSession(context.Context, *ReadSessionRequest, *ReadSessionResponse) error +} + +func RegisterUsersHandler(s server.Server, hdlr UsersHandler, opts ...server.HandlerOption) error { + type users interface { + Create(ctx context.Context, in *CreateRequest, out *CreateResponse) error + Read(ctx context.Context, in *ReadRequest, out *ReadResponse) error + Update(ctx context.Context, in *UpdateRequest, out *UpdateResponse) error + Delete(ctx context.Context, in *DeleteRequest, out *DeleteResponse) error + Search(ctx context.Context, in *SearchRequest, out *SearchResponse) error + UpdatePassword(ctx context.Context, in *UpdatePasswordRequest, out *UpdatePasswordResponse) error + Login(ctx context.Context, in *LoginRequest, out *LoginResponse) error + Logout(ctx context.Context, in *LogoutRequest, out *LogoutResponse) error + ReadSession(ctx context.Context, in *ReadSessionRequest, out *ReadSessionResponse) error + } + type Users struct { + users + } + h := &usersHandler{hdlr} + return s.Handle(s.NewHandler(&Users{h}, opts...)) +} + +type usersHandler struct { + UsersHandler +} + +func (h *usersHandler) Create(ctx context.Context, in *CreateRequest, out *CreateResponse) error { + return h.UsersHandler.Create(ctx, in, out) +} + +func (h *usersHandler) Read(ctx context.Context, in *ReadRequest, out *ReadResponse) error { + return h.UsersHandler.Read(ctx, in, out) +} + +func (h *usersHandler) Update(ctx context.Context, in *UpdateRequest, out *UpdateResponse) error { + return h.UsersHandler.Update(ctx, in, out) +} + +func (h *usersHandler) Delete(ctx context.Context, in *DeleteRequest, out *DeleteResponse) error { + return h.UsersHandler.Delete(ctx, in, out) +} + +func (h *usersHandler) Search(ctx context.Context, in *SearchRequest, out *SearchResponse) error { + return h.UsersHandler.Search(ctx, in, out) +} + +func (h *usersHandler) UpdatePassword(ctx context.Context, in *UpdatePasswordRequest, out *UpdatePasswordResponse) error { + return h.UsersHandler.UpdatePassword(ctx, in, out) +} + +func (h *usersHandler) Login(ctx context.Context, in *LoginRequest, out *LoginResponse) error { + return h.UsersHandler.Login(ctx, in, out) +} + +func (h *usersHandler) Logout(ctx context.Context, in *LogoutRequest, out *LogoutResponse) error { + return h.UsersHandler.Logout(ctx, in, out) +} + +func (h *usersHandler) ReadSession(ctx context.Context, in *ReadSessionRequest, out *ReadSessionResponse) error { + return h.UsersHandler.ReadSession(ctx, in, out) +} diff --git a/test/users/proto/users.proto b/test/users/proto/users.proto new file mode 100644 index 0000000..8d9d0ce --- /dev/null +++ b/test/users/proto/users.proto @@ -0,0 +1,110 @@ +syntax = "proto3"; + +service Users { + rpc Create(CreateRequest) returns (CreateResponse) {} + rpc Read(ReadRequest) returns (ReadResponse) {} + rpc Update(UpdateRequest) returns (UpdateResponse) {} + rpc Delete(DeleteRequest) returns (DeleteResponse) {} + rpc Search(SearchRequest) returns (SearchResponse) {} + rpc UpdatePassword(UpdatePasswordRequest) returns (UpdatePasswordResponse) {} + rpc Login(LoginRequest) returns (LoginResponse) {} + rpc Logout(LogoutRequest) returns (LogoutResponse) {} + rpc ReadSession(ReadSessionRequest) returns(ReadSessionResponse) {} +} + +message User { + string id = 1; // uuid + string username = 2; // alphanumeric user or org + string email = 3; + int64 created = 4; // unix + int64 updated = 5; // unix +} + +message Session { + string id = 1; + string username = 2; + string email = 3; + int64 created = 4; // unix + int64 expires = 5; // unix +} + +message CreateRequest { + string id = 1; // uuid + string username = 2; // alphanumeric user or org + string email = 3; + string password = 4; +} + +message CreateResponse { +} + +message DeleteRequest { + string id = 1; +} + +message DeleteResponse { +} + +message ReadRequest { + string id = 1; +} + +message ReadResponse { + User user = 1; +} + +message UpdateRequest { + string id = 1; // uuid + string username = 2; // alphanumeric user or org + string email = 3; +} + +message UpdateResponse { +} + +message UpdatePasswordRequest { + string userId = 1; + string oldPassword = 2; + string newPassword = 3; + string confirm_password = 4; +} + +message UpdatePasswordResponse { +} + +message SearchRequest { + string username = 1; + string email = 2; + int64 limit = 3; + int64 offset = 4; +} + +message SearchResponse { + repeated User users = 1; +} + +message ReadSessionRequest { + string sessionId = 1; +} + +message ReadSessionResponse { + Session session = 1; +} + +message LoginRequest { + string username = 1; + string email = 2; + string password = 3; +} + +message LoginResponse { + Session session = 1; +} + +message LogoutRequest { + string sessionId = 1; +} + +message LogoutResponse { +} + diff --git a/users/.gitignore b/users/.gitignore new file mode 100644 index 0000000..ae22583 --- /dev/null +++ b/users/.gitignore @@ -0,0 +1 @@ +users diff --git a/users/Dockerfile b/users/Dockerfile index 45a7a5a..5a4c6b4 100644 --- a/users/Dockerfile +++ b/users/Dockerfile @@ -1,3 +1,3 @@ -FROM alpine:3.2 +FROM alpine ADD users /users ENTRYPOINT [ "/users" ] diff --git a/users/Makefile b/users/Makefile index 8702253..ddbb866 100644 --- a/users/Makefile +++ b/users/Makefile @@ -7,13 +7,8 @@ init: go get github.com/micro/micro/v3/cmd/protoc-gen-micro .PHONY: proto proto: - protoc --openapi_out=. --proto_path=. --micro_out=. --go_out=:. proto/users.proto - -.PHONY: docs -docs: - protoc --openapi_out=. --proto_path=. --micro_out=. --go_out=:. proto/users.proto - @redoc-cli bundle api-users.json - + protoc --proto_path=. --micro_out=. --go_out=:. proto/users.proto + .PHONY: build build: go build -o users *.go diff --git a/users/README.md b/users/README.md index b3f91cc..3690034 100644 --- a/users/README.md +++ b/users/README.md @@ -1,76 +1,23 @@ -A user service for storing accounts and simple auth. - # Users Service -The users service provides user management and authentication so you can easily add them to your own apps -without having to build the entire thing from scratch. +This is the Users service -## Getting started +Generated with ``` -micro run github.com/micro/services/users +micro new users ``` ## Usage -User server implements the following RPC Methods +Generate the proto code -Users -- Create -- Read -- Update -- Delete -- Search -- UpdatePassword -- Login -- Logout -- ReadSession - - -### Create - -```shell -micro call users Users.Create '{"id": "ff3c06de-9e43-41c7-9bab-578f6b4ad32b", "username": "asim", "email": "asim@example.com", "password": "password1"}' +``` +make proto ``` -### Read +Run the service -```shell -micro call users Users.Read '{"id": "ff3c06de-9e43-41c7-9bab-578f6b4ad32b"}' -``` - -### Update - -```shell -micro call users Users.Update '{"id": "ff3c06de-9e43-41c7-9bab-578f6b4ad32b", "username": "asim", "email": "asim+update@example.com"}' -``` - -### Update Password - -```shell -micro call users Users.UpdatePassword '{"userId": "ff3c06de-9e43-41c7-9bab-578f6b4ad32b", "oldPassword": "password1", "newPassword": "newpassword1", "confirmPassword": "newpassword1" }' -``` - -### Delete - -```shell -micro call users Users.Delete '{"id": "ff3c06de-9e43-41c7-9bab-578f6b4ad32b"}' -``` - -### Login - -```shell -micro call users Users.Login '{"username": "asim", "password": "password1"}' -``` - -### Read Session - -```shell -micro call users Users.ReadSession '{"sessionId": "sr7UEBmIMg5hYOgiljnhrd4XLsnalNewBV9KzpZ9aD8w37b3jRmEujGtKGcGlXPg1yYoSHR3RLy66ugglw0tofTNGm57NrNYUHsFxfwuGC6pvCn8BecB7aEF6UxTyVFq"}' -``` - -### Logout - -```shell -micro call users Users.Logout '{"sessionId": "sr7UEBmIMg5hYOgiljnhrd4XLsnalNewBV9KzpZ9aD8w37b3jRmEujGtKGcGlXPg1yYoSHR3RLy66ugglw0tofTNGm57NrNYUHsFxfwuGC6pvCn8BecB7aEF6UxTyVFq"}' ``` +micro run . +``` \ No newline at end of file diff --git a/users/generate.go b/users/generate.go index 7d9db91..96f431a 100644 --- a/users/generate.go +++ b/users/generate.go @@ -1,3 +1,2 @@ package main - //go:generate make proto diff --git a/users/handler/handler.go b/users/handler/handler.go index 10b7992..9ad6726 100644 --- a/users/handler/handler.go +++ b/users/handler/handler.go @@ -1,174 +1,369 @@ package handler import ( - "crypto/rand" - "encoding/base64" + "context" + "regexp" "strings" "time" + "github.com/google/uuid" "github.com/micro/micro/v3/service/errors" - "github.com/micro/services/users/domain" + "github.com/micro/micro/v3/service/logger" pb "github.com/micro/services/users/proto" "golang.org/x/crypto/bcrypt" - "golang.org/x/net/context" -) - -const ( - x = "cruft123" + "gorm.io/gorm" ) var ( - alphanum = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + ErrMissingFirstName = errors.BadRequest("MISSING_FIRST_NAME", "Missing first name") + ErrMissingLastName = errors.BadRequest("MISSING_LAST_NAME", "Missing last name") + ErrMissingEmail = errors.BadRequest("MISSING_EMAIL", "Missing email") + ErrDuplicateEmail = errors.BadRequest("DUPLICATE_EMAIL", "A user with this email address already exists") + ErrInvalidEmail = errors.BadRequest("INVALID_EMAIL", "The email provided is invalid") + ErrInvalidPassword = errors.BadRequest("INVALID_PASSWORD", "Password must be at least 8 characters long") + ErrMissingIDs = errors.BadRequest("MISSING_IDS", "One or more ids are required") + ErrMissingID = errors.BadRequest("MISSING_ID", "Missing ID") + ErrMissingToken = errors.BadRequest("MISSING_TOKEN", "Missing token") + ErrIncorrectPassword = errors.BadRequest("INCORRECT_PASSWORD", "Incorrect password") + ErrTokenExpired = errors.BadRequest("TOKEN_EXPIRED", "Token has expired") + ErrInvalidToken = errors.BadRequest("INVALID_TOKEN", "Token is invalid") + ErrNotFound = errors.NotFound("NOT_FOUND", "User not found") + + emailRegex = regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$") + tokenTTL = time.Hour * 7 * 24 ) -func random(i int) string { - bytes := make([]byte, i) - for { - rand.Read(bytes) - for i, b := range bytes { - bytes[i] = alphanum[b%byte(len(alphanum))] - } - return string(bytes) +type User struct { + ID string + FirstName string + LastName string + Email string `gorm:"uniqueIndex"` + Password string + CreatedAt time.Time + Tokens []Token +} + +func (u *User) Serialize() *pb.User { + return &pb.User{ + Id: u.ID, + FirstName: u.FirstName, + LastName: u.LastName, + Email: u.Email, } - return "ughwhy?!!!" +} + +type Token struct { + Key string `gorm:"primaryKey"` + CreatedAt time.Time + ExpiresAt time.Time + UserID string + User User } type Users struct { - domain *domain.Domain + DB *gorm.DB + Time func() time.Time } -func NewUsers() *Users { - return &Users{ - domain: domain.New(), +// Create a user +func (u *Users) Create(ctx context.Context, req *pb.CreateRequest, rsp *pb.CreateResponse) error { + // validate the request + if len(req.FirstName) == 0 { + return ErrMissingFirstName + } + if len(req.LastName) == 0 { + return ErrMissingLastName + } + if len(req.Email) == 0 { + return ErrMissingEmail + } + if !isEmailValid(req.Email) { + return ErrInvalidEmail } -} - -func (s *Users) Create(ctx context.Context, req *pb.CreateRequest, rsp *pb.CreateResponse) error { if len(req.Password) < 8 { - return errors.InternalServerError("users.Create.Check", "Password is less than 8 characters") + return ErrInvalidPassword } - salt := random(16) - h, err := bcrypt.GenerateFromPassword([]byte(x+salt+req.Password), 10) + + // hash and salt the password using bcrypt + phash, err := hashAndSalt(req.Password) if err != nil { - return errors.InternalServerError("users.Create", err.Error()) + logger.Errorf("Error hasing and salting password: %v", err) + return errors.InternalServerError("HASHING_ERROR", "Error hashing password") } - pp := base64.StdEncoding.EncodeToString(h) - return s.domain.Create(&pb.User{ - Id: req.Id, - Username: strings.ToLower(req.Username), - Email: strings.ToLower(req.Email), - }, salt, pp) -} + return u.DB.Transaction(func(tx *gorm.DB) error { + // write the user to the database + user := &User{ + ID: uuid.New().String(), + FirstName: req.FirstName, + LastName: req.LastName, + Email: req.Email, + Password: phash, + } + err = u.DB.Create(user).Error + if err != nil && strings.Contains(err.Error(), "idx_users_email") { + return ErrDuplicateEmail + } else if err != nil { + logger.Errorf("Error writing to the database: %v", err) + return errors.InternalServerError("DATABASE_ERROR", "Error connecting to the database") + } -func (s *Users) Read(ctx context.Context, req *pb.ReadRequest, rsp *pb.ReadResponse) error { - user, err := s.domain.Read(req.Id) - if err != nil { - return err - } - rsp.User = user - return nil -} + // generate a token for the user + token := Token{ + UserID: user.ID, + Key: uuid.New().String(), + ExpiresAt: u.Time().Add(time.Hour * 24 * 7), + } + if err := tx.Create(&token).Error; err != nil { + logger.Errorf("Error writing to the database: %v", err) + return errors.InternalServerError("DATABASE_ERROR", "Error connecting to the database") + } -func (s *Users) Update(ctx context.Context, req *pb.UpdateRequest, rsp *pb.UpdateResponse) error { - return s.domain.Update(&pb.User{ - Id: req.Id, - Username: strings.ToLower(req.Username), - Email: strings.ToLower(req.Email), + // serialize the response + rsp.User = user.Serialize() + rsp.Token = token.Key + return nil }) } -func (s *Users) Delete(ctx context.Context, req *pb.DeleteRequest, rsp *pb.DeleteResponse) error { - return s.domain.Delete(req.Id) -} - -func (s *Users) Search(ctx context.Context, req *pb.SearchRequest, rsp *pb.SearchResponse) error { - users, err := s.domain.Search(req.Username, req.Email, req.Limit, req.Offset) - if err != nil { - return err - } - rsp.Users = users - return nil -} - -func (s *Users) UpdatePassword(ctx context.Context, req *pb.UpdatePasswordRequest, rsp *pb.UpdatePasswordResponse) error { - usr, err := s.domain.Read(req.UserId) - if err != nil { - return errors.InternalServerError("users.updatepassword", err.Error()) - } - if req.NewPassword != req.ConfirmPassword { - return errors.InternalServerError("users.updatepassword", "Passwords don't math") +// Read users using ID +func (u *Users) Read(ctx context.Context, req *pb.ReadRequest, rsp *pb.ReadResponse) error { + // validate the request + if len(req.Ids) == 0 { + return ErrMissingIDs } - salt, hashed, err := s.domain.SaltAndPassword(usr.Username, usr.Email) - if err != nil { - return errors.InternalServerError("users.updatepassword", err.Error()) + // query the database + var users []User + if err := u.DB.Model(&User{}).Where("id IN (?)", req.Ids).Find(&users).Error; err != nil { + logger.Errorf("Error reading from the database: %v", err) + return errors.InternalServerError("DATABASE_ERROR", "Error connecting to the database") } - hh, err := base64.StdEncoding.DecodeString(hashed) - if err != nil { - return errors.InternalServerError("users.updatepassword", err.Error()) - } - - if err := bcrypt.CompareHashAndPassword(hh, []byte(x+salt+req.OldPassword)); err != nil { - return errors.Unauthorized("users.updatepassword", err.Error()) - } - - salt = random(16) - h, err := bcrypt.GenerateFromPassword([]byte(x+salt+req.NewPassword), 10) - if err != nil { - return errors.InternalServerError("users.updatepassword", err.Error()) - } - pp := base64.StdEncoding.EncodeToString(h) - - if err := s.domain.UpdatePassword(req.UserId, salt, pp); err != nil { - return errors.InternalServerError("users.updatepassword", err.Error()) + // serialize the response + rsp.Users = make(map[string]*pb.User, len(users)) + for _, u := range users { + rsp.Users[u.ID] = u.Serialize() } return nil } -func (s *Users) Login(ctx context.Context, req *pb.LoginRequest, rsp *pb.LoginResponse) error { - username := strings.ToLower(req.Username) - email := strings.ToLower(req.Email) - - salt, hashed, err := s.domain.SaltAndPassword(username, email) - if err != nil { - return err +// Update a user +func (u *Users) Update(ctx context.Context, req *pb.UpdateRequest, rsp *pb.UpdateResponse) error { + // validate the request + if len(req.Id) == 0 { + return ErrMissingID + } + if req.FirstName != nil && len(req.FirstName.Value) == 0 { + return ErrMissingFirstName + } + if req.LastName != nil && len(req.LastName.Value) == 0 { + return ErrMissingLastName + } + if req.Email != nil && len(req.Email.Value) == 0 { + return ErrMissingEmail + } + if req.Email != nil && !isEmailValid(req.Email.Value) { + return ErrInvalidEmail } - hh, err := base64.StdEncoding.DecodeString(hashed) - if err != nil { - return errors.InternalServerError("users.Login", err.Error()) + // lookup the user + var user User + if err := u.DB.Where(&User{ID: req.Id}).First(&user).Error; err == gorm.ErrRecordNotFound { + return ErrNotFound + } else if err != nil { + logger.Errorf("Error reading from the database: %v", err) + return errors.InternalServerError("DATABASE_ERROR", "Error connecting to the database") } - if err := bcrypt.CompareHashAndPassword(hh, []byte(x+salt+req.Password)); err != nil { - return errors.Unauthorized("users.login", err.Error()) + // assign the updated values + if req.FirstName != nil { + user.FirstName = req.FirstName.Value } - // save session - sess := &pb.Session{ - Id: random(128), - Username: username, - Email: email, - Created: time.Now().Unix(), - Expires: time.Now().Add(time.Hour * 24 * 7).Unix(), + if req.LastName != nil { + user.LastName = req.LastName.Value + } + if req.Email != nil { + user.Email = req.Email.Value } - if err := s.domain.CreateSession(sess); err != nil { - return errors.InternalServerError("users.Login", err.Error()) + // write the user to the database + err := u.DB.Save(user).Error + if err != nil && strings.Contains(err.Error(), "idx_users_email") { + return ErrDuplicateEmail + } else if err != nil { + logger.Errorf("Error writing to the database: %v", err) + return errors.InternalServerError("DATABASE_ERROR", "Error connecting to the database") } - rsp.Session = sess + + // serialize the user + rsp.User = user.Serialize() return nil } -func (s *Users) Logout(ctx context.Context, req *pb.LogoutRequest, rsp *pb.LogoutResponse) error { - return s.domain.DeleteSession(req.SessionId) +// Delete a user +func (u *Users) Delete(ctx context.Context, req *pb.DeleteRequest, rsp *pb.DeleteResponse) error { + // validate the request + if len(req.Id) == 0 { + return ErrMissingID + } + + // delete the users tokens + return u.DB.Transaction(func(tx *gorm.DB) error { + if err := tx.Delete(&Token{}, &Token{UserID: req.Id}).Error; err != nil { + logger.Errorf("Error writing to the database: %v", err) + return errors.InternalServerError("DATABASE_ERROR", "Error connecting to the database") + } + + // delete from the database + if err := tx.Delete(&User{}, &User{ID: req.Id}).Error; err != nil { + logger.Errorf("Error writing to the database: %v", err) + return errors.InternalServerError("DATABASE_ERROR", "Error connecting to the database") + } + + return nil + }) } -func (s *Users) ReadSession(ctx context.Context, req *pb.ReadSessionRequest, rsp *pb.ReadSessionResponse) error { - sess, err := s.domain.ReadSession(req.SessionId) - if err != nil { - return err +// List all users +func (u *Users) List(ctx context.Context, req *pb.ListRequest, rsp *pb.ListResponse) error { + // query the database + var users []User + if err := u.DB.Model(&User{}).Find(&users).Error; err != nil { + logger.Errorf("Error reading from the database: %v", err) + return errors.InternalServerError("DATABASE_ERROR", "Error connecting to the database") + } + + // serialize the response + rsp.Users = make([]*pb.User, len(users)) + for i, u := range users { + rsp.Users[i] = u.Serialize() } - rsp.Session = sess return nil } + +// Login using email and password returns the users profile and a token +func (u *Users) Login(ctx context.Context, req *pb.LoginRequest, rsp *pb.LoginResponse) error { + // validate the request + if len(req.Email) == 0 { + return ErrMissingEmail + } + if len(req.Password) == 0 { + return ErrInvalidPassword + } + + return u.DB.Transaction(func(tx *gorm.DB) error { + // lookup the user + var user User + if err := tx.Where(&User{Email: req.Email}).First(&user).Error; err == gorm.ErrRecordNotFound { + return ErrNotFound + } else if err != nil { + logger.Errorf("Error reading from the database: %v", err) + return errors.InternalServerError("DATABASE_ERROR", "Error connecting to the database") + } + + // compare the passwords + if !passwordsMatch(user.Password, req.Password) { + return ErrIncorrectPassword + } + + // generate a token for the user + token := Token{ + UserID: user.ID, + Key: uuid.New().String(), + ExpiresAt: u.Time().Add(tokenTTL), + } + if err := tx.Create(&token).Error; err != nil { + logger.Errorf("Error writing to the database: %v", err) + return errors.InternalServerError("DATABASE_ERROR", "Error connecting to the database") + } + + // serialize the response + rsp.Token = token.Key + rsp.User = user.Serialize() + return nil + }) +} + +// Logout expires all tokens for the user +func (u *Users) Logout(ctx context.Context, req *pb.LogoutRequest, rsp *pb.LogoutResponse) error { + // validate the request + if len(req.Id) == 0 { + return ErrMissingID + } + + return u.DB.Transaction(func(tx *gorm.DB) error { + // lookup the user + var user User + if err := tx.Where(&User{ID: req.Id}).Preload("Tokens").First(&user).Error; err == gorm.ErrRecordNotFound { + return ErrNotFound + } else if err != nil { + logger.Errorf("Error reading from the database: %v", err) + return errors.InternalServerError("DATABASE_ERROR", "Error connecting to the database") + } + + // delete the tokens + if err := tx.Delete(user.Tokens).Error; err != nil { + logger.Errorf("Error deleting from the database: %v", err) + return errors.InternalServerError("DATABASE_ERROR", "Error connecting to the database") + } + + return nil + }) +} + +// Validate a token, each time a token is validated it extends its lifetime for another week +func (u *Users) Validate(ctx context.Context, req *pb.ValidateRequest, rsp *pb.ValidateResponse) error { + // validate the request + if len(req.Token) == 0 { + return ErrMissingToken + } + + return u.DB.Transaction(func(tx *gorm.DB) error { + // lookup the token + var token Token + if err := tx.Where(&Token{Key: req.Token}).Preload("User").First(&token).Error; err == gorm.ErrRecordNotFound { + return ErrInvalidToken + } else if err != nil { + logger.Errorf("Error reading from the database: %v", err) + return errors.InternalServerError("DATABASE_ERROR", "Error connecting to the database") + } + + // ensure the token is valid + if u.Time().After(token.ExpiresAt) { + return ErrTokenExpired + } + + // extend the token for another lifetime + token.ExpiresAt = u.Time().Add(tokenTTL) + if err := tx.Save(&token).Error; err != nil { + logger.Errorf("Error writing to the database: %v", err) + return errors.InternalServerError("DATABASE_ERROR", "Error connecting to the database") + } + + // serialize the response + rsp.User = token.User.Serialize() + return nil + }) +} + +// isEmailValid checks if the email provided passes the required structure and length. +func isEmailValid(e string) bool { + if len(e) < 3 && len(e) > 254 { + return false + } + return emailRegex.MatchString(e) +} + +func hashAndSalt(pwd string) (string, error) { + hash, err := bcrypt.GenerateFromPassword([]byte(pwd), bcrypt.DefaultCost) + if err != nil { + return "", err + } + return string(hash), nil +} + +func passwordsMatch(hashed string, plain string) bool { + err := bcrypt.CompareHashAndPassword([]byte(hashed), []byte(plain)) + return err == nil +} diff --git a/users/handler/handler_test.go b/users/handler/handler_test.go new file mode 100644 index 0000000..3241287 --- /dev/null +++ b/users/handler/handler_test.go @@ -0,0 +1,668 @@ +package handler_test + +import ( + "context" + "testing" + "time" + + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "google.golang.org/protobuf/types/known/wrapperspb" + + "github.com/micro/services/users/handler" + pb "github.com/micro/services/users/proto" + "gorm.io/driver/postgres" + "gorm.io/gorm" +) + +func testHandler(t *testing.T) *handler.Users { + // connect to the database + db, err := gorm.Open(postgres.Open("postgresql://postgres@localhost:5432/users?sslmode=disable"), &gorm.Config{}) + if err != nil { + t.Fatalf("Error connecting to database: %v", err) + } + + // migrate the database + if err := db.AutoMigrate(&handler.User{}, &handler.Token{}); err != nil { + t.Fatalf("Error migrating database: %v", err) + } + + // clean any data from a previous run + if err := db.Exec("TRUNCATE TABLE users, tokens CASCADE").Error; err != nil { + t.Fatalf("Error cleaning database: %v", err) + } + + return &handler.Users{DB: db, Time: time.Now} +} + +func TestCreate(t *testing.T) { + tt := []struct { + Name string + FirstName string + LastName string + Email string + Password string + Error error + }{ + { + Name: "MissingFirstName", + LastName: "Doe", + Email: "john@doe.com", + Password: "password", + Error: handler.ErrMissingFirstName, + }, + { + Name: "MissingLastName", + FirstName: "John", + Email: "john@doe.com", + Password: "password", + Error: handler.ErrMissingLastName, + }, + { + Name: "MissingEmail", + FirstName: "John", + LastName: "Doe", + Password: "password", + Error: handler.ErrMissingEmail, + }, + { + Name: "InvalidEmail", + FirstName: "John", + LastName: "Doe", + Password: "password", + Email: "foo.foo.foo", + Error: handler.ErrInvalidEmail, + }, + { + Name: "InvalidPassword", + FirstName: "John", + LastName: "Doe", + Email: "john@doe.com", + Password: "pwd", + Error: handler.ErrInvalidPassword, + }, + } + + // test the validations + h := testHandler(t) + for _, tc := range tt { + t.Run(tc.Name, func(t *testing.T) { + err := h.Create(context.TODO(), &pb.CreateRequest{ + FirstName: tc.FirstName, + LastName: tc.LastName, + Email: tc.Email, + Password: tc.Password, + }, &pb.CreateResponse{}) + assert.Equal(t, tc.Error, err) + }) + } + + t.Run("Valid", func(t *testing.T) { + var rsp pb.CreateResponse + req := pb.CreateRequest{ + FirstName: "John", + LastName: "Doe", + Email: "john@doe.com", + Password: "passwordabc", + } + err := h.Create(context.TODO(), &req, &rsp) + + assert.NoError(t, err) + u := rsp.User + if u == nil { + t.Fatalf("No user returned") + } + assert.NotEmpty(t, u.Id) + assert.Equal(t, req.FirstName, u.FirstName) + assert.Equal(t, req.LastName, u.LastName) + assert.Equal(t, req.Email, u.Email) + assert.NotEmpty(t, rsp.Token) + }) + + t.Run("DuplicateEmail", func(t *testing.T) { + var rsp pb.CreateResponse + req := pb.CreateRequest{ + FirstName: "John", + LastName: "Doe", + Email: "john@doe.com", + Password: "passwordabc", + } + err := h.Create(context.TODO(), &req, &rsp) + assert.Equal(t, handler.ErrDuplicateEmail, err) + assert.Nil(t, rsp.User) + }) + + t.Run("DifferentEmail", func(t *testing.T) { + var rsp pb.CreateResponse + req := pb.CreateRequest{ + FirstName: "John", + LastName: "Doe", + Email: "johndoe@gmail.com", + Password: "passwordabc", + } + err := h.Create(context.TODO(), &req, &rsp) + + assert.NoError(t, err) + u := rsp.User + if u == nil { + t.Fatalf("No user returned") + } + assert.NotEmpty(t, u.Id) + assert.Equal(t, req.FirstName, u.FirstName) + assert.Equal(t, req.LastName, u.LastName) + assert.Equal(t, req.Email, u.Email) + }) +} + +func TestRead(t *testing.T) { + h := testHandler(t) + + t.Run("MissingIDs", func(t *testing.T) { + var rsp pb.ReadResponse + err := h.Read(context.TODO(), &pb.ReadRequest{}, &rsp) + assert.Equal(t, handler.ErrMissingIDs, err) + assert.Nil(t, rsp.Users) + }) + + t.Run("NotFound", func(t *testing.T) { + var rsp pb.ReadResponse + err := h.Read(context.TODO(), &pb.ReadRequest{Ids: []string{"foo"}}, &rsp) + assert.Nil(t, err) + if rsp.Users == nil { + t.Fatal("Expected the users object to not be nil") + } + assert.Nil(t, rsp.Users["foo"]) + }) + + // create some mock data + var rsp1 pb.CreateResponse + req1 := pb.CreateRequest{ + FirstName: "John", + LastName: "Doe", + Email: "john@doe.com", + Password: "passwordabc", + } + err := h.Create(context.TODO(), &req1, &rsp1) + assert.NoError(t, err) + if rsp1.User == nil { + t.Fatal("No user returned") + return + } + + var rsp2 pb.CreateResponse + req2 := pb.CreateRequest{ + FirstName: "Apple", + LastName: "Tree", + Email: "apple@tree.com", + Password: "passwordabc", + } + err = h.Create(context.TODO(), &req2, &rsp2) + assert.NoError(t, err) + if rsp2.User == nil { + t.Fatal("No user returned") + return + } + + // test the read + var rsp pb.ReadResponse + err = h.Read(context.TODO(), &pb.ReadRequest{ + Ids: []string{rsp1.User.Id, rsp2.User.Id}, + }, &rsp) + assert.NoError(t, err) + + if rsp.Users == nil { + t.Fatal("Users not returned") + return + } + assert.NotNil(t, rsp.Users[rsp1.User.Id]) + assert.NotNil(t, rsp.Users[rsp2.User.Id]) + + // check the users match + if u := rsp.Users[rsp1.User.Id]; u != nil { + assert.Equal(t, rsp1.User.Id, u.Id) + assert.Equal(t, rsp1.User.FirstName, u.FirstName) + assert.Equal(t, rsp1.User.LastName, u.LastName) + assert.Equal(t, rsp1.User.Email, u.Email) + } + if u := rsp.Users[rsp2.User.Id]; u != nil { + assert.Equal(t, rsp2.User.Id, u.Id) + assert.Equal(t, rsp2.User.FirstName, u.FirstName) + assert.Equal(t, rsp2.User.LastName, u.LastName) + assert.Equal(t, rsp2.User.Email, u.Email) + } +} + +func TestUpdate(t *testing.T) { + h := testHandler(t) + + t.Run("MissingID", func(t *testing.T) { + var rsp pb.UpdateResponse + err := h.Update(context.TODO(), &pb.UpdateRequest{}, &rsp) + assert.Equal(t, handler.ErrMissingID, err) + assert.Nil(t, rsp.User) + }) + + t.Run("NotFound", func(t *testing.T) { + var rsp pb.UpdateResponse + err := h.Update(context.TODO(), &pb.UpdateRequest{Id: "foo"}, &rsp) + assert.Equal(t, handler.ErrNotFound, err) + assert.Nil(t, rsp.User) + }) + + // create some mock data + var cRsp1 pb.CreateResponse + cReq1 := pb.CreateRequest{ + FirstName: "John", + LastName: "Doe", + Email: "john@doe.com", + Password: "passwordabc", + } + err := h.Create(context.TODO(), &cReq1, &cRsp1) + assert.NoError(t, err) + if cRsp1.User == nil { + t.Fatal("No user returned") + return + } + + var cRsp2 pb.CreateResponse + cReq2 := pb.CreateRequest{ + FirstName: "John", + LastName: "Doe", + Email: "johndoe@gmail.com", + Password: "passwordabc", + } + err = h.Create(context.TODO(), &cReq2, &cRsp2) + assert.NoError(t, err) + if cRsp2.User == nil { + t.Fatal("No user returned") + return + } + + t.Run("BlankFirstName", func(t *testing.T) { + var rsp pb.UpdateResponse + err := h.Update(context.TODO(), &pb.UpdateRequest{ + Id: cRsp1.User.Id, FirstName: &wrapperspb.StringValue{}, + }, &rsp) + assert.Equal(t, handler.ErrMissingFirstName, err) + assert.Nil(t, rsp.User) + }) + + t.Run("BlankLastName", func(t *testing.T) { + var rsp pb.UpdateResponse + err := h.Update(context.TODO(), &pb.UpdateRequest{ + Id: cRsp1.User.Id, LastName: &wrapperspb.StringValue{}, + }, &rsp) + assert.Equal(t, handler.ErrMissingLastName, err) + assert.Nil(t, rsp.User) + }) + + t.Run("BlankLastName", func(t *testing.T) { + var rsp pb.UpdateResponse + err := h.Update(context.TODO(), &pb.UpdateRequest{ + Id: cRsp1.User.Id, LastName: &wrapperspb.StringValue{}, + }, &rsp) + assert.Equal(t, handler.ErrMissingLastName, err) + assert.Nil(t, rsp.User) + }) + + t.Run("BlankEmail", func(t *testing.T) { + var rsp pb.UpdateResponse + err := h.Update(context.TODO(), &pb.UpdateRequest{ + Id: cRsp1.User.Id, Email: &wrapperspb.StringValue{}, + }, &rsp) + assert.Equal(t, handler.ErrMissingEmail, err) + assert.Nil(t, rsp.User) + }) + + t.Run("InvalidEmail", func(t *testing.T) { + var rsp pb.UpdateResponse + err := h.Update(context.TODO(), &pb.UpdateRequest{ + Id: cRsp1.User.Id, Email: &wrapperspb.StringValue{Value: "foo.bar"}, + }, &rsp) + assert.Equal(t, handler.ErrInvalidEmail, err) + assert.Nil(t, rsp.User) + }) + + t.Run("EmailAlreadyExists", func(t *testing.T) { + var rsp pb.UpdateResponse + err := h.Update(context.TODO(), &pb.UpdateRequest{ + Id: cRsp1.User.Id, Email: &wrapperspb.StringValue{Value: cRsp2.User.Email}, + }, &rsp) + assert.Equal(t, handler.ErrDuplicateEmail, err) + assert.Nil(t, rsp.User) + }) + + t.Run("Valid", func(t *testing.T) { + uReq := pb.UpdateRequest{ + Id: cRsp1.User.Id, + Email: &wrapperspb.StringValue{Value: "foobar@gmail.com"}, + FirstName: &wrapperspb.StringValue{Value: "Foo"}, + LastName: &wrapperspb.StringValue{Value: "Bar"}, + } + var uRsp pb.UpdateResponse + err := h.Update(context.TODO(), &uReq, &uRsp) + assert.NoError(t, err) + if uRsp.User == nil { + t.Error("No user returned") + return + } + assert.Equal(t, cRsp1.User.Id, uRsp.User.Id) + assert.Equal(t, uReq.Email.Value, uRsp.User.Email) + assert.Equal(t, uReq.FirstName.Value, uRsp.User.FirstName) + assert.Equal(t, uReq.LastName.Value, uRsp.User.LastName) + }) +} + +func TestDelete(t *testing.T) { + h := testHandler(t) + + t.Run("MissingID", func(t *testing.T) { + err := h.Delete(context.TODO(), &pb.DeleteRequest{}, &pb.DeleteResponse{}) + assert.Equal(t, handler.ErrMissingID, err) + }) + + // create some mock data + var cRsp pb.CreateResponse + cReq := pb.CreateRequest{ + FirstName: "John", + LastName: "Doe", + Email: "john@doe.com", + Password: "passwordabc", + } + err := h.Create(context.TODO(), &cReq, &cRsp) + assert.NoError(t, err) + if cRsp.User == nil { + t.Fatal("No user returned") + return + } + + t.Run("Valid", func(t *testing.T) { + err := h.Delete(context.TODO(), &pb.DeleteRequest{ + Id: cRsp.User.Id, + }, &pb.DeleteResponse{}) + assert.NoError(t, err) + + // check it was actually deleted + var rsp pb.ReadResponse + err = h.Read(context.TODO(), &pb.ReadRequest{ + Ids: []string{cRsp.User.Id}, + }, &rsp) + assert.NoError(t, err) + assert.Nil(t, rsp.Users[cRsp.User.Id]) + }) + + t.Run("Retry", func(t *testing.T) { + err := h.Delete(context.TODO(), &pb.DeleteRequest{ + Id: cRsp.User.Id, + }, &pb.DeleteResponse{}) + assert.NoError(t, err) + }) +} + +func TestList(t *testing.T) { + h := testHandler(t) + + // create some mock data + var cRsp1 pb.CreateResponse + cReq1 := pb.CreateRequest{ + FirstName: "John", + LastName: "Doe", + Email: "john@doe.com", + Password: "passwordabc", + } + err := h.Create(context.TODO(), &cReq1, &cRsp1) + assert.NoError(t, err) + if cRsp1.User == nil { + t.Fatal("No user returned") + return + } + + var cRsp2 pb.CreateResponse + cReq2 := pb.CreateRequest{ + FirstName: "John", + LastName: "Doe", + Email: "johndoe@gmail.com", + Password: "passwordabc", + } + err = h.Create(context.TODO(), &cReq2, &cRsp2) + assert.NoError(t, err) + if cRsp2.User == nil { + t.Fatal("No user returned") + return + } + + var rsp pb.ListResponse + err = h.List(context.TODO(), &pb.ListRequest{}, &rsp) + assert.NoError(t, err) + if rsp.Users == nil { + t.Error("No users returned") + return + } + + var u1Found, u2Found bool + for _, u := range rsp.Users { + switch u.Id { + case cRsp1.User.Id: + assertUsersMatch(t, cRsp1.User, u) + u1Found = true + case cRsp2.User.Id: + assertUsersMatch(t, cRsp2.User, u) + u2Found = true + default: + t.Fatal("Unexpected user returned") + return + } + } + assert.True(t, u1Found) + assert.True(t, u2Found) +} + +func TestLogin(t *testing.T) { + h := testHandler(t) + + // create some mock data + var cRsp pb.CreateResponse + cReq := pb.CreateRequest{ + FirstName: "John", + LastName: "Doe", + Email: "john@doe.com", + Password: "passwordabc", + } + err := h.Create(context.TODO(), &cReq, &cRsp) + assert.NoError(t, err) + if cRsp.User == nil { + t.Fatal("No user returned") + return + } + + tt := []struct { + Name string + Email string + Password string + Error error + User *pb.User + }{ + { + Name: "MissingEmail", + Password: "passwordabc", + Error: handler.ErrMissingEmail, + }, + { + Name: "MissingPassword", + Email: "john@doe.com", + Error: handler.ErrInvalidPassword, + }, + { + Name: "UserNotFound", + Email: "foo@bar.com", + Password: "passwordabc", + Error: handler.ErrNotFound, + }, + { + Name: "IncorrectPassword", + Email: "john@doe.com", + Password: "passwordabcdef", + Error: handler.ErrIncorrectPassword, + }, + { + Name: "Valid", + Email: "john@doe.com", + Password: "passwordabc", + User: cRsp.User, + }, + } + + for _, tc := range tt { + t.Run(tc.Name, func(t *testing.T) { + var rsp pb.LoginResponse + err := h.Login(context.TODO(), &pb.LoginRequest{ + Email: tc.Email, Password: tc.Password, + }, &rsp) + assert.Equal(t, tc.Error, err) + + if tc.User != nil { + assertUsersMatch(t, tc.User, rsp.User) + assert.NotEmpty(t, rsp.Token) + } else { + assert.Nil(t, tc.User) + } + }) + } +} + +func TestLogout(t *testing.T) { + h := testHandler(t) + + t.Run("MissingUserID", func(t *testing.T) { + err := h.Logout(context.TODO(), &pb.LogoutRequest{}, &pb.LogoutResponse{}) + assert.Equal(t, handler.ErrMissingID, err) + }) + + t.Run("UserNotFound", func(t *testing.T) { + err := h.Logout(context.TODO(), &pb.LogoutRequest{Id: uuid.New().String()}, &pb.LogoutResponse{}) + assert.Equal(t, handler.ErrNotFound, err) + }) + + t.Run("Valid", func(t *testing.T) { + // create some mock data + var cRsp pb.CreateResponse + cReq := pb.CreateRequest{ + FirstName: "John", + LastName: "Doe", + Email: "john@doe.com", + Password: "passwordabc", + } + err := h.Create(context.TODO(), &cReq, &cRsp) + assert.NoError(t, err) + if cRsp.User == nil { + t.Fatal("No user returned") + return + } + + err = h.Logout(context.TODO(), &pb.LogoutRequest{Id: cRsp.User.Id}, &pb.LogoutResponse{}) + assert.NoError(t, err) + + err = h.Validate(context.TODO(), &pb.ValidateRequest{Token: cRsp.Token}, &pb.ValidateResponse{}) + assert.Error(t, err) + }) +} + +func TestValidate(t *testing.T) { + h := testHandler(t) + + // create some mock data + var cRsp1 pb.CreateResponse + cReq1 := pb.CreateRequest{ + FirstName: "John", + LastName: "Doe", + Email: "john@doe.com", + Password: "passwordabc", + } + err := h.Create(context.TODO(), &cReq1, &cRsp1) + assert.NoError(t, err) + if cRsp1.User == nil { + t.Fatal("No user returned") + return + } + + var cRsp2 pb.CreateResponse + cReq2 := pb.CreateRequest{ + FirstName: "Barry", + LastName: "Doe", + Email: "barry@doe.com", + Password: "passwordabc", + } + err = h.Create(context.TODO(), &cReq2, &cRsp2) + assert.NoError(t, err) + if cRsp2.User == nil { + t.Fatal("No user returned") + return + } + + tt := []struct { + Name string + Token string + Time func() time.Time + Error error + User *pb.User + }{ + { + Name: "MissingToken", + Error: handler.ErrMissingToken, + }, + { + Name: "InvalidToken", + Error: handler.ErrInvalidToken, + Token: uuid.New().String(), + }, + { + Name: "ExpiredToken", + Error: handler.ErrTokenExpired, + Token: cRsp1.Token, + Time: func() time.Time { return time.Now().Add(time.Hour * 24 * 8) }, + }, + { + Name: "ValidToken", + User: cRsp2.User, + Token: cRsp2.Token, + Time: func() time.Time { return time.Now().Add(time.Hour * 24 * 3) }, + }, + { + Name: "RefreshedToken", + User: cRsp2.User, + Token: cRsp2.Token, + Time: func() time.Time { return time.Now().Add(time.Hour * 24 * 8) }, + }, + } + + for _, tc := range tt { + t.Run(tc.Name, func(t *testing.T) { + if tc.Time == nil { + h.Time = time.Now + } else { + h.Time = tc.Time + } + + var rsp pb.ValidateResponse + err := h.Validate(context.TODO(), &pb.ValidateRequest{Token: tc.Token}, &rsp) + assert.Equal(t, tc.Error, err) + + if tc.User != nil { + assertUsersMatch(t, tc.User, rsp.User) + } else { + assert.Nil(t, tc.User) + } + }) + } +} + +func assertUsersMatch(t *testing.T, exp, act *pb.User) { + if act == nil { + t.Error("No user returned") + return + } + assert.Equal(t, exp.Id, act.Id) + assert.Equal(t, exp.FirstName, act.FirstName) + assert.Equal(t, exp.LastName, act.LastName) + assert.Equal(t, exp.Email, act.Email) +} diff --git a/users/main.go b/users/main.go index c81b663..94c43b0 100644 --- a/users/main.go +++ b/users/main.go @@ -1,22 +1,43 @@ package main import ( - "github.com/micro/micro/v3/service" - "github.com/micro/micro/v3/service/logger" + "time" + "github.com/micro/services/users/handler" - proto "github.com/micro/services/users/proto" + pb "github.com/micro/services/users/proto" + + "github.com/micro/micro/v3/service" + "github.com/micro/micro/v3/service/config" + "github.com/micro/micro/v3/service/logger" + "gorm.io/driver/postgres" + "gorm.io/gorm" ) +var dbAddress = "postgresql://postgres@localhost:5432/users?sslmode=disable" + func main() { - service := service.New( + // Create service + srv := service.New( service.Name("users"), + service.Version("latest"), ) - service.Init() + // Connect to the database + cfg, err := config.Get("users.database") + if err != nil { + logger.Fatalf("Error loading config: %v", err) + } + addr := cfg.String(dbAddress) + db, err := gorm.Open(postgres.Open(addr), &gorm.Config{}) + if err != nil { + logger.Fatalf("Error connecting to database: %v", err) + } - proto.RegisterUsersHandler(service.Server(), handler.NewUsers()) + // Register handler + pb.RegisterUsersHandler(srv.Server(), &handler.Users{DB: db, Time: time.Now}) - if err := service.Run(); err != nil { + // Run service + if err := srv.Run(); err != nil { logger.Fatal(err) } } diff --git a/users/proto/users.pb.go b/users/proto/users.pb.go index 61a5d4e..c878dc4 100644 --- a/users/proto/users.pb.go +++ b/users/proto/users.pb.go @@ -1,13 +1,14 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 -// protoc v3.6.1 +// protoc-gen-go v1.23.0 +// protoc v3.13.0 // source: proto/users.proto package users import ( proto "github.com/golang/protobuf/proto" + wrappers "github.com/golang/protobuf/ptypes/wrappers" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -30,11 +31,10 @@ type User struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // uuid - Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"` // alphanumeric user or org - Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` - Created int64 `protobuf:"varint,4,opt,name=created,proto3" json:"created,omitempty"` // unix - Updated int64 `protobuf:"varint,5,opt,name=updated,proto3" json:"updated,omitempty"` // unix + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + FirstName string `protobuf:"bytes,2,opt,name=first_name,json=firstName,proto3" json:"first_name,omitempty"` + LastName string `protobuf:"bytes,3,opt,name=last_name,json=lastName,proto3" json:"last_name,omitempty"` + Email string `protobuf:"bytes,4,opt,name=email,proto3" json:"email,omitempty"` } func (x *User) Reset() { @@ -76,9 +76,16 @@ func (x *User) GetId() string { return "" } -func (x *User) GetUsername() string { +func (x *User) GetFirstName() string { if x != nil { - return x.Username + return x.FirstName + } + return "" +} + +func (x *User) GetLastName() string { + if x != nil { + return x.LastName } return "" } @@ -90,114 +97,21 @@ func (x *User) GetEmail() string { return "" } -func (x *User) GetCreated() int64 { - if x != nil { - return x.Created - } - return 0 -} - -func (x *User) GetUpdated() int64 { - if x != nil { - return x.Updated - } - return 0 -} - -type Session struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"` - Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` - Created int64 `protobuf:"varint,4,opt,name=created,proto3" json:"created,omitempty"` // unix - Expires int64 `protobuf:"varint,5,opt,name=expires,proto3" json:"expires,omitempty"` // unix -} - -func (x *Session) Reset() { - *x = Session{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_users_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Session) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Session) ProtoMessage() {} - -func (x *Session) ProtoReflect() protoreflect.Message { - mi := &file_proto_users_proto_msgTypes[1] - 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 Session.ProtoReflect.Descriptor instead. -func (*Session) Descriptor() ([]byte, []int) { - return file_proto_users_proto_rawDescGZIP(), []int{1} -} - -func (x *Session) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *Session) GetUsername() string { - if x != nil { - return x.Username - } - return "" -} - -func (x *Session) GetEmail() string { - if x != nil { - return x.Email - } - return "" -} - -func (x *Session) GetCreated() int64 { - if x != nil { - return x.Created - } - return 0 -} - -func (x *Session) GetExpires() int64 { - if x != nil { - return x.Expires - } - return 0 -} - type CreateRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // uuid - Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"` // alphanumeric user or org - Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` - Password string `protobuf:"bytes,4,opt,name=password,proto3" json:"password,omitempty"` + FirstName string `protobuf:"bytes,1,opt,name=first_name,json=firstName,proto3" json:"first_name,omitempty"` + LastName string `protobuf:"bytes,2,opt,name=last_name,json=lastName,proto3" json:"last_name,omitempty"` + Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` + Password string `protobuf:"bytes,4,opt,name=password,proto3" json:"password,omitempty"` } func (x *CreateRequest) Reset() { *x = CreateRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_users_proto_msgTypes[2] + mi := &file_proto_users_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -210,7 +124,7 @@ func (x *CreateRequest) String() string { func (*CreateRequest) ProtoMessage() {} func (x *CreateRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_users_proto_msgTypes[2] + mi := &file_proto_users_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -223,19 +137,19 @@ func (x *CreateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateRequest.ProtoReflect.Descriptor instead. func (*CreateRequest) Descriptor() ([]byte, []int) { - return file_proto_users_proto_rawDescGZIP(), []int{2} + return file_proto_users_proto_rawDescGZIP(), []int{1} } -func (x *CreateRequest) GetId() string { +func (x *CreateRequest) GetFirstName() string { if x != nil { - return x.Id + return x.FirstName } return "" } -func (x *CreateRequest) GetUsername() string { +func (x *CreateRequest) GetLastName() string { if x != nil { - return x.Username + return x.LastName } return "" } @@ -258,12 +172,15 @@ type CreateResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + + User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` + Token string `protobuf:"bytes,2,opt,name=token,proto3" json:"token,omitempty"` } func (x *CreateResponse) Reset() { *x = CreateResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_users_proto_msgTypes[3] + mi := &file_proto_users_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -276,7 +193,7 @@ func (x *CreateResponse) String() string { func (*CreateResponse) ProtoMessage() {} func (x *CreateResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_users_proto_msgTypes[3] + mi := &file_proto_users_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -289,9 +206,235 @@ func (x *CreateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateResponse.ProtoReflect.Descriptor instead. func (*CreateResponse) Descriptor() ([]byte, []int) { + return file_proto_users_proto_rawDescGZIP(), []int{2} +} + +func (x *CreateResponse) GetUser() *User { + if x != nil { + return x.User + } + return nil +} + +func (x *CreateResponse) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + +type ReadRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ids []string `protobuf:"bytes,1,rep,name=ids,proto3" json:"ids,omitempty"` +} + +func (x *ReadRequest) Reset() { + *x = ReadRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_users_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReadRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReadRequest) ProtoMessage() {} + +func (x *ReadRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_users_proto_msgTypes[3] + 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 ReadRequest.ProtoReflect.Descriptor instead. +func (*ReadRequest) Descriptor() ([]byte, []int) { return file_proto_users_proto_rawDescGZIP(), []int{3} } +func (x *ReadRequest) GetIds() []string { + if x != nil { + return x.Ids + } + return nil +} + +type ReadResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Users map[string]*User `protobuf:"bytes,1,rep,name=users,proto3" json:"users,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *ReadResponse) Reset() { + *x = ReadResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_users_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReadResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReadResponse) ProtoMessage() {} + +func (x *ReadResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_users_proto_msgTypes[4] + 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 ReadResponse.ProtoReflect.Descriptor instead. +func (*ReadResponse) Descriptor() ([]byte, []int) { + return file_proto_users_proto_rawDescGZIP(), []int{4} +} + +func (x *ReadResponse) GetUsers() map[string]*User { + if x != nil { + return x.Users + } + return nil +} + +type UpdateRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + FirstName *wrappers.StringValue `protobuf:"bytes,2,opt,name=first_name,json=firstName,proto3" json:"first_name,omitempty"` + LastName *wrappers.StringValue `protobuf:"bytes,3,opt,name=last_name,json=lastName,proto3" json:"last_name,omitempty"` + Email *wrappers.StringValue `protobuf:"bytes,4,opt,name=email,proto3" json:"email,omitempty"` +} + +func (x *UpdateRequest) Reset() { + *x = UpdateRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_users_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateRequest) ProtoMessage() {} + +func (x *UpdateRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_users_proto_msgTypes[5] + 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 UpdateRequest.ProtoReflect.Descriptor instead. +func (*UpdateRequest) Descriptor() ([]byte, []int) { + return file_proto_users_proto_rawDescGZIP(), []int{5} +} + +func (x *UpdateRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *UpdateRequest) GetFirstName() *wrappers.StringValue { + if x != nil { + return x.FirstName + } + return nil +} + +func (x *UpdateRequest) GetLastName() *wrappers.StringValue { + if x != nil { + return x.LastName + } + return nil +} + +func (x *UpdateRequest) GetEmail() *wrappers.StringValue { + if x != nil { + return x.Email + } + return nil +} + +type UpdateResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` +} + +func (x *UpdateResponse) Reset() { + *x = UpdateResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_users_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateResponse) ProtoMessage() {} + +func (x *UpdateResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_users_proto_msgTypes[6] + 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 UpdateResponse.ProtoReflect.Descriptor instead. +func (*UpdateResponse) Descriptor() ([]byte, []int) { + return file_proto_users_proto_rawDescGZIP(), []int{6} +} + +func (x *UpdateResponse) GetUser() *User { + if x != nil { + return x.User + } + return nil +} + type DeleteRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -303,7 +446,7 @@ type DeleteRequest struct { func (x *DeleteRequest) Reset() { *x = DeleteRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_users_proto_msgTypes[4] + mi := &file_proto_users_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -316,7 +459,7 @@ func (x *DeleteRequest) String() string { func (*DeleteRequest) ProtoMessage() {} func (x *DeleteRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_users_proto_msgTypes[4] + mi := &file_proto_users_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -329,7 +472,7 @@ func (x *DeleteRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteRequest.ProtoReflect.Descriptor instead. func (*DeleteRequest) Descriptor() ([]byte, []int) { - return file_proto_users_proto_rawDescGZIP(), []int{4} + return file_proto_users_proto_rawDescGZIP(), []int{7} } func (x *DeleteRequest) GetId() string { @@ -348,7 +491,7 @@ type DeleteResponse struct { func (x *DeleteResponse) Reset() { *x = DeleteResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_users_proto_msgTypes[5] + mi := &file_proto_users_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -361,7 +504,7 @@ func (x *DeleteResponse) String() string { func (*DeleteResponse) ProtoMessage() {} func (x *DeleteResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_users_proto_msgTypes[5] + mi := &file_proto_users_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -374,174 +517,17 @@ func (x *DeleteResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteResponse.ProtoReflect.Descriptor instead. func (*DeleteResponse) Descriptor() ([]byte, []int) { - return file_proto_users_proto_rawDescGZIP(), []int{5} -} - -type ReadRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` -} - -func (x *ReadRequest) Reset() { - *x = ReadRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_users_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ReadRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ReadRequest) ProtoMessage() {} - -func (x *ReadRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_users_proto_msgTypes[6] - 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 ReadRequest.ProtoReflect.Descriptor instead. -func (*ReadRequest) Descriptor() ([]byte, []int) { - return file_proto_users_proto_rawDescGZIP(), []int{6} -} - -func (x *ReadRequest) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -type ReadResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` -} - -func (x *ReadResponse) Reset() { - *x = ReadResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_users_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ReadResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ReadResponse) ProtoMessage() {} - -func (x *ReadResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_users_proto_msgTypes[7] - 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 ReadResponse.ProtoReflect.Descriptor instead. -func (*ReadResponse) Descriptor() ([]byte, []int) { - return file_proto_users_proto_rawDescGZIP(), []int{7} -} - -func (x *ReadResponse) GetUser() *User { - if x != nil { - return x.User - } - return nil -} - -type UpdateRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // uuid - Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"` // alphanumeric user or org - Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` -} - -func (x *UpdateRequest) Reset() { - *x = UpdateRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_users_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *UpdateRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UpdateRequest) ProtoMessage() {} - -func (x *UpdateRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_users_proto_msgTypes[8] - 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 UpdateRequest.ProtoReflect.Descriptor instead. -func (*UpdateRequest) Descriptor() ([]byte, []int) { return file_proto_users_proto_rawDescGZIP(), []int{8} } -func (x *UpdateRequest) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *UpdateRequest) GetUsername() string { - if x != nil { - return x.Username - } - return "" -} - -func (x *UpdateRequest) GetEmail() string { - if x != nil { - return x.Email - } - return "" -} - -type UpdateResponse struct { +type ListRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields } -func (x *UpdateResponse) Reset() { - *x = UpdateResponse{} +func (x *ListRequest) Reset() { + *x = ListRequest{} if protoimpl.UnsafeEnabled { mi := &file_proto_users_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -549,13 +535,13 @@ func (x *UpdateResponse) Reset() { } } -func (x *UpdateResponse) String() string { +func (x *ListRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*UpdateResponse) ProtoMessage() {} +func (*ListRequest) ProtoMessage() {} -func (x *UpdateResponse) ProtoReflect() protoreflect.Message { +func (x *ListRequest) ProtoReflect() protoreflect.Message { mi := &file_proto_users_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -567,24 +553,21 @@ func (x *UpdateResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use UpdateResponse.ProtoReflect.Descriptor instead. -func (*UpdateResponse) Descriptor() ([]byte, []int) { +// Deprecated: Use ListRequest.ProtoReflect.Descriptor instead. +func (*ListRequest) Descriptor() ([]byte, []int) { return file_proto_users_proto_rawDescGZIP(), []int{9} } -type UpdatePasswordRequest struct { +type ListResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - UserId string `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"` - OldPassword string `protobuf:"bytes,2,opt,name=oldPassword,proto3" json:"oldPassword,omitempty"` - NewPassword string `protobuf:"bytes,3,opt,name=newPassword,proto3" json:"newPassword,omitempty"` - ConfirmPassword string `protobuf:"bytes,4,opt,name=confirm_password,json=confirmPassword,proto3" json:"confirm_password,omitempty"` + Users []*User `protobuf:"bytes,1,rep,name=users,proto3" json:"users,omitempty"` } -func (x *UpdatePasswordRequest) Reset() { - *x = UpdatePasswordRequest{} +func (x *ListResponse) Reset() { + *x = ListResponse{} if protoimpl.UnsafeEnabled { mi := &file_proto_users_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -592,13 +575,13 @@ func (x *UpdatePasswordRequest) Reset() { } } -func (x *UpdatePasswordRequest) String() string { +func (x *ListResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*UpdatePasswordRequest) ProtoMessage() {} +func (*ListResponse) ProtoMessage() {} -func (x *UpdatePasswordRequest) ProtoReflect() protoreflect.Message { +func (x *ListResponse) ProtoReflect() protoreflect.Message { mi := &file_proto_users_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -610,303 +593,31 @@ func (x *UpdatePasswordRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use UpdatePasswordRequest.ProtoReflect.Descriptor instead. -func (*UpdatePasswordRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use ListResponse.ProtoReflect.Descriptor instead. +func (*ListResponse) Descriptor() ([]byte, []int) { return file_proto_users_proto_rawDescGZIP(), []int{10} } -func (x *UpdatePasswordRequest) GetUserId() string { - if x != nil { - return x.UserId - } - return "" -} - -func (x *UpdatePasswordRequest) GetOldPassword() string { - if x != nil { - return x.OldPassword - } - return "" -} - -func (x *UpdatePasswordRequest) GetNewPassword() string { - if x != nil { - return x.NewPassword - } - return "" -} - -func (x *UpdatePasswordRequest) GetConfirmPassword() string { - if x != nil { - return x.ConfirmPassword - } - return "" -} - -type UpdatePasswordResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *UpdatePasswordResponse) Reset() { - *x = UpdatePasswordResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_users_proto_msgTypes[11] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *UpdatePasswordResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UpdatePasswordResponse) ProtoMessage() {} - -func (x *UpdatePasswordResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_users_proto_msgTypes[11] - 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 UpdatePasswordResponse.ProtoReflect.Descriptor instead. -func (*UpdatePasswordResponse) Descriptor() ([]byte, []int) { - return file_proto_users_proto_rawDescGZIP(), []int{11} -} - -type SearchRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` - Email string `protobuf:"bytes,2,opt,name=email,proto3" json:"email,omitempty"` - Limit int64 `protobuf:"varint,3,opt,name=limit,proto3" json:"limit,omitempty"` - Offset int64 `protobuf:"varint,4,opt,name=offset,proto3" json:"offset,omitempty"` -} - -func (x *SearchRequest) Reset() { - *x = SearchRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_users_proto_msgTypes[12] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *SearchRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SearchRequest) ProtoMessage() {} - -func (x *SearchRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_users_proto_msgTypes[12] - 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 SearchRequest.ProtoReflect.Descriptor instead. -func (*SearchRequest) Descriptor() ([]byte, []int) { - return file_proto_users_proto_rawDescGZIP(), []int{12} -} - -func (x *SearchRequest) GetUsername() string { - if x != nil { - return x.Username - } - return "" -} - -func (x *SearchRequest) GetEmail() string { - if x != nil { - return x.Email - } - return "" -} - -func (x *SearchRequest) GetLimit() int64 { - if x != nil { - return x.Limit - } - return 0 -} - -func (x *SearchRequest) GetOffset() int64 { - if x != nil { - return x.Offset - } - return 0 -} - -type SearchResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Users []*User `protobuf:"bytes,1,rep,name=users,proto3" json:"users,omitempty"` -} - -func (x *SearchResponse) Reset() { - *x = SearchResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_users_proto_msgTypes[13] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *SearchResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SearchResponse) ProtoMessage() {} - -func (x *SearchResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_users_proto_msgTypes[13] - 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 SearchResponse.ProtoReflect.Descriptor instead. -func (*SearchResponse) Descriptor() ([]byte, []int) { - return file_proto_users_proto_rawDescGZIP(), []int{13} -} - -func (x *SearchResponse) GetUsers() []*User { +func (x *ListResponse) GetUsers() []*User { if x != nil { return x.Users } return nil } -type ReadSessionRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - SessionId string `protobuf:"bytes,1,opt,name=sessionId,proto3" json:"sessionId,omitempty"` -} - -func (x *ReadSessionRequest) Reset() { - *x = ReadSessionRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_users_proto_msgTypes[14] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ReadSessionRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ReadSessionRequest) ProtoMessage() {} - -func (x *ReadSessionRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_users_proto_msgTypes[14] - 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 ReadSessionRequest.ProtoReflect.Descriptor instead. -func (*ReadSessionRequest) Descriptor() ([]byte, []int) { - return file_proto_users_proto_rawDescGZIP(), []int{14} -} - -func (x *ReadSessionRequest) GetSessionId() string { - if x != nil { - return x.SessionId - } - return "" -} - -type ReadSessionResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Session *Session `protobuf:"bytes,1,opt,name=session,proto3" json:"session,omitempty"` -} - -func (x *ReadSessionResponse) Reset() { - *x = ReadSessionResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_users_proto_msgTypes[15] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ReadSessionResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ReadSessionResponse) ProtoMessage() {} - -func (x *ReadSessionResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_users_proto_msgTypes[15] - 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 ReadSessionResponse.ProtoReflect.Descriptor instead. -func (*ReadSessionResponse) Descriptor() ([]byte, []int) { - return file_proto_users_proto_rawDescGZIP(), []int{15} -} - -func (x *ReadSessionResponse) GetSession() *Session { - if x != nil { - return x.Session - } - return nil -} - type LoginRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` - Email string `protobuf:"bytes,2,opt,name=email,proto3" json:"email,omitempty"` - Password string `protobuf:"bytes,3,opt,name=password,proto3" json:"password,omitempty"` + Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"` + Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` } func (x *LoginRequest) Reset() { *x = LoginRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_users_proto_msgTypes[16] + mi := &file_proto_users_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -919,7 +630,7 @@ func (x *LoginRequest) String() string { func (*LoginRequest) ProtoMessage() {} func (x *LoginRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_users_proto_msgTypes[16] + mi := &file_proto_users_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -932,14 +643,7 @@ func (x *LoginRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use LoginRequest.ProtoReflect.Descriptor instead. func (*LoginRequest) Descriptor() ([]byte, []int) { - return file_proto_users_proto_rawDescGZIP(), []int{16} -} - -func (x *LoginRequest) GetUsername() string { - if x != nil { - return x.Username - } - return "" + return file_proto_users_proto_rawDescGZIP(), []int{11} } func (x *LoginRequest) GetEmail() string { @@ -961,13 +665,14 @@ type LoginResponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Session *Session `protobuf:"bytes,1,opt,name=session,proto3" json:"session,omitempty"` + User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` + Token string `protobuf:"bytes,2,opt,name=token,proto3" json:"token,omitempty"` } func (x *LoginResponse) Reset() { *x = LoginResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_users_proto_msgTypes[17] + mi := &file_proto_users_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -980,7 +685,7 @@ func (x *LoginResponse) String() string { func (*LoginResponse) ProtoMessage() {} func (x *LoginResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_users_proto_msgTypes[17] + mi := &file_proto_users_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -993,28 +698,35 @@ func (x *LoginResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use LoginResponse.ProtoReflect.Descriptor instead. func (*LoginResponse) Descriptor() ([]byte, []int) { - return file_proto_users_proto_rawDescGZIP(), []int{17} + return file_proto_users_proto_rawDescGZIP(), []int{12} } -func (x *LoginResponse) GetSession() *Session { +func (x *LoginResponse) GetUser() *User { if x != nil { - return x.Session + return x.User } return nil } +func (x *LoginResponse) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + type LogoutRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - SessionId string `protobuf:"bytes,1,opt,name=sessionId,proto3" json:"sessionId,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` } func (x *LogoutRequest) Reset() { *x = LogoutRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_users_proto_msgTypes[18] + mi := &file_proto_users_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1027,7 +739,7 @@ func (x *LogoutRequest) String() string { func (*LogoutRequest) ProtoMessage() {} func (x *LogoutRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_users_proto_msgTypes[18] + mi := &file_proto_users_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1040,12 +752,12 @@ func (x *LogoutRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use LogoutRequest.ProtoReflect.Descriptor instead. func (*LogoutRequest) Descriptor() ([]byte, []int) { - return file_proto_users_proto_rawDescGZIP(), []int{18} + return file_proto_users_proto_rawDescGZIP(), []int{13} } -func (x *LogoutRequest) GetSessionId() string { +func (x *LogoutRequest) GetId() string { if x != nil { - return x.SessionId + return x.Id } return "" } @@ -1059,7 +771,7 @@ type LogoutResponse struct { func (x *LogoutResponse) Reset() { *x = LogoutResponse{} if protoimpl.UnsafeEnabled { - mi := &file_proto_users_proto_msgTypes[19] + mi := &file_proto_users_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1072,7 +784,7 @@ func (x *LogoutResponse) String() string { func (*LogoutResponse) ProtoMessage() {} func (x *LogoutResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_users_proto_msgTypes[19] + mi := &file_proto_users_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1085,132 +797,211 @@ func (x *LogoutResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use LogoutResponse.ProtoReflect.Descriptor instead. func (*LogoutResponse) Descriptor() ([]byte, []int) { - return file_proto_users_proto_rawDescGZIP(), []int{19} + return file_proto_users_proto_rawDescGZIP(), []int{14} +} + +type ValidateRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` +} + +func (x *ValidateRequest) Reset() { + *x = ValidateRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_users_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ValidateRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidateRequest) ProtoMessage() {} + +func (x *ValidateRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_users_proto_msgTypes[15] + 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 ValidateRequest.ProtoReflect.Descriptor instead. +func (*ValidateRequest) Descriptor() ([]byte, []int) { + return file_proto_users_proto_rawDescGZIP(), []int{15} +} + +func (x *ValidateRequest) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + +type ValidateResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` +} + +func (x *ValidateResponse) Reset() { + *x = ValidateResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_users_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ValidateResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidateResponse) ProtoMessage() {} + +func (x *ValidateResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_users_proto_msgTypes[16] + 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 ValidateResponse.ProtoReflect.Descriptor instead. +func (*ValidateResponse) Descriptor() ([]byte, []int) { + return file_proto_users_proto_rawDescGZIP(), []int{16} +} + +func (x *ValidateResponse) GetUser() *User { + if x != nil { + return x.User + } + return nil } var File_proto_users_proto protoreflect.FileDescriptor var file_proto_users_proto_rawDesc = []byte{ 0x0a, 0x11, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x22, 0x7c, 0x0a, 0x04, 0x55, 0x73, + 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, + 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x68, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, - 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, - 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, - 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x18, - 0x0a, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x22, 0x7f, 0x0a, 0x07, 0x53, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, - 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, - 0x18, 0x0a, 0x07, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x07, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x22, 0x6d, 0x0a, 0x0d, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, - 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, - 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1a, 0x0a, 0x08, - 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x10, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x0a, 0x0d, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x10, 0x0a, 0x0e, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x0a, - 0x0b, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x2f, 0x0a, 0x0c, - 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x04, - 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x75, 0x73, 0x65, - 0x72, 0x73, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x51, 0x0a, - 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, - 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1a, - 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, - 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, - 0x22, 0x10, 0x0a, 0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x9e, 0x01, 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, - 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, - 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, - 0x65, 0x72, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x6f, 0x6c, 0x64, 0x50, 0x61, 0x73, 0x73, 0x77, - 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x6c, 0x64, 0x50, 0x61, - 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x6e, 0x65, 0x77, 0x50, 0x61, 0x73, - 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x65, 0x77, - 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x72, 0x6d, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x50, 0x61, 0x73, 0x73, 0x77, - 0x6f, 0x72, 0x64, 0x22, 0x18, 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, - 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x6f, 0x0a, - 0x0d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, - 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, - 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, - 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x22, 0x33, - 0x0a, 0x0e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x21, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x0b, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x05, 0x75, 0x73, - 0x65, 0x72, 0x73, 0x22, 0x32, 0x0a, 0x12, 0x52, 0x65, 0x61, 0x64, 0x53, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x3f, 0x0a, 0x13, 0x52, 0x65, 0x61, 0x64, 0x53, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, - 0x0a, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x0e, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, - 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x5c, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x69, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, - 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, - 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, - 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x39, 0x0a, 0x0d, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x73, - 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x22, 0x2d, 0x0a, 0x0d, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, - 0x22, 0x10, 0x0a, 0x0e, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x32, 0xa6, 0x04, 0x0a, 0x05, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x37, 0x0a, 0x06, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x14, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x75, - 0x73, 0x65, 0x72, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x04, 0x52, 0x65, 0x61, 0x64, 0x12, 0x12, 0x2e, - 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x13, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x37, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x12, 0x14, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x73, - 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x12, 0x37, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x14, 0x2e, 0x75, 0x73, - 0x65, 0x72, 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x15, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x37, 0x0a, 0x06, 0x53, 0x65, - 0x61, 0x72, 0x63, 0x68, 0x12, 0x14, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x53, 0x65, 0x61, - 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x75, 0x73, 0x65, - 0x72, 0x73, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, - 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x1c, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x73, 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, 0x34, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x13, 0x2e, - 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x37, 0x0a, 0x06, 0x4c, 0x6f, - 0x67, 0x6f, 0x75, 0x74, 0x12, 0x14, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x4c, 0x6f, 0x67, - 0x6f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x75, 0x73, 0x65, - 0x72, 0x73, 0x2e, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x00, 0x12, 0x46, 0x0a, 0x0b, 0x52, 0x65, 0x61, 0x64, 0x53, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x19, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x53, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, - 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x0d, 0x5a, 0x0b, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x3b, 0x75, 0x73, 0x65, 0x72, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x69, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x66, 0x69, 0x72, 0x73, 0x74, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x61, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, + 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, + 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x7d, 0x0a, 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x66, 0x69, 0x72, 0x73, 0x74, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x61, 0x73, 0x74, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, + 0x6f, 0x72, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, + 0x6f, 0x72, 0x64, 0x22, 0x47, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x55, 0x73, 0x65, 0x72, + 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x1f, 0x0a, 0x0b, + 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x69, + 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x8b, 0x01, + 0x0a, 0x0c, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, + 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, + 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x75, + 0x73, 0x65, 0x72, 0x73, 0x1a, 0x45, 0x0a, 0x0a, 0x55, 0x73, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x21, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x55, 0x73, 0x65, 0x72, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xcb, 0x01, 0x0a, 0x0d, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, + 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x3b, 0x0a, + 0x0a, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, + 0x09, 0x66, 0x69, 0x72, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x39, 0x0a, 0x09, 0x6c, 0x61, + 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x6c, 0x61, 0x73, + 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x32, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x31, 0x0a, 0x0e, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x04, 0x75, + 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x75, 0x73, 0x65, 0x72, + 0x73, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x1f, 0x0a, 0x0d, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, + 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x10, 0x0a, + 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x0d, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x31, + 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, + 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, + 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, + 0x73, 0x22, 0x40, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 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, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, + 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, + 0x6f, 0x72, 0x64, 0x22, 0x46, 0x0a, 0x0d, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, + 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x1f, 0x0a, 0x0d, 0x4c, + 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x10, 0x0a, 0x0e, + 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x27, + 0x0a, 0x0f, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x33, 0x0a, 0x10, 0x56, 0x61, 0x6c, 0x69, 0x64, + 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x04, 0x75, + 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x75, 0x73, 0x65, 0x72, + 0x73, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x32, 0xc6, 0x03, 0x0a, + 0x05, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x37, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x12, 0x14, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, + 0x31, 0x0a, 0x04, 0x52, 0x65, 0x61, 0x64, 0x12, 0x12, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, + 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x75, 0x73, + 0x65, 0x72, 0x73, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x12, 0x37, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x14, 0x2e, 0x75, + 0x73, 0x65, 0x72, 0x73, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x37, 0x0a, 0x06, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x14, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x75, 0x73, + 0x65, 0x72, 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x12, 0x2e, 0x75, + 0x73, 0x65, 0x72, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x13, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x34, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, + 0x12, 0x13, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x4c, 0x6f, + 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x37, 0x0a, + 0x06, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x12, 0x14, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, + 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, + 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3d, 0x0a, 0x08, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, + 0x74, 0x65, 0x12, 0x16, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, + 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x75, 0x73, 0x65, + 0x72, 0x73, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x0d, 0x5a, 0x0b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3b, 0x75, + 0x73, 0x65, 0x72, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1225,57 +1016,60 @@ func file_proto_users_proto_rawDescGZIP() []byte { return file_proto_users_proto_rawDescData } -var file_proto_users_proto_msgTypes = make([]protoimpl.MessageInfo, 20) +var file_proto_users_proto_msgTypes = make([]protoimpl.MessageInfo, 18) var file_proto_users_proto_goTypes = []interface{}{ - (*User)(nil), // 0: users.User - (*Session)(nil), // 1: users.Session - (*CreateRequest)(nil), // 2: users.CreateRequest - (*CreateResponse)(nil), // 3: users.CreateResponse - (*DeleteRequest)(nil), // 4: users.DeleteRequest - (*DeleteResponse)(nil), // 5: users.DeleteResponse - (*ReadRequest)(nil), // 6: users.ReadRequest - (*ReadResponse)(nil), // 7: users.ReadResponse - (*UpdateRequest)(nil), // 8: users.UpdateRequest - (*UpdateResponse)(nil), // 9: users.UpdateResponse - (*UpdatePasswordRequest)(nil), // 10: users.UpdatePasswordRequest - (*UpdatePasswordResponse)(nil), // 11: users.UpdatePasswordResponse - (*SearchRequest)(nil), // 12: users.SearchRequest - (*SearchResponse)(nil), // 13: users.SearchResponse - (*ReadSessionRequest)(nil), // 14: users.ReadSessionRequest - (*ReadSessionResponse)(nil), // 15: users.ReadSessionResponse - (*LoginRequest)(nil), // 16: users.LoginRequest - (*LoginResponse)(nil), // 17: users.LoginResponse - (*LogoutRequest)(nil), // 18: users.LogoutRequest - (*LogoutResponse)(nil), // 19: users.LogoutResponse + (*User)(nil), // 0: users.User + (*CreateRequest)(nil), // 1: users.CreateRequest + (*CreateResponse)(nil), // 2: users.CreateResponse + (*ReadRequest)(nil), // 3: users.ReadRequest + (*ReadResponse)(nil), // 4: users.ReadResponse + (*UpdateRequest)(nil), // 5: users.UpdateRequest + (*UpdateResponse)(nil), // 6: users.UpdateResponse + (*DeleteRequest)(nil), // 7: users.DeleteRequest + (*DeleteResponse)(nil), // 8: users.DeleteResponse + (*ListRequest)(nil), // 9: users.ListRequest + (*ListResponse)(nil), // 10: users.ListResponse + (*LoginRequest)(nil), // 11: users.LoginRequest + (*LoginResponse)(nil), // 12: users.LoginResponse + (*LogoutRequest)(nil), // 13: users.LogoutRequest + (*LogoutResponse)(nil), // 14: users.LogoutResponse + (*ValidateRequest)(nil), // 15: users.ValidateRequest + (*ValidateResponse)(nil), // 16: users.ValidateResponse + nil, // 17: users.ReadResponse.UsersEntry + (*wrappers.StringValue)(nil), // 18: google.protobuf.StringValue } var file_proto_users_proto_depIdxs = []int32{ - 0, // 0: users.ReadResponse.user:type_name -> users.User - 0, // 1: users.SearchResponse.users:type_name -> users.User - 1, // 2: users.ReadSessionResponse.session:type_name -> users.Session - 1, // 3: users.LoginResponse.session:type_name -> users.Session - 2, // 4: users.Users.Create:input_type -> users.CreateRequest - 6, // 5: users.Users.Read:input_type -> users.ReadRequest - 8, // 6: users.Users.Update:input_type -> users.UpdateRequest - 4, // 7: users.Users.Delete:input_type -> users.DeleteRequest - 12, // 8: users.Users.Search:input_type -> users.SearchRequest - 10, // 9: users.Users.UpdatePassword:input_type -> users.UpdatePasswordRequest - 16, // 10: users.Users.Login:input_type -> users.LoginRequest - 18, // 11: users.Users.Logout:input_type -> users.LogoutRequest - 14, // 12: users.Users.ReadSession:input_type -> users.ReadSessionRequest - 3, // 13: users.Users.Create:output_type -> users.CreateResponse - 7, // 14: users.Users.Read:output_type -> users.ReadResponse - 9, // 15: users.Users.Update:output_type -> users.UpdateResponse - 5, // 16: users.Users.Delete:output_type -> users.DeleteResponse - 13, // 17: users.Users.Search:output_type -> users.SearchResponse - 11, // 18: users.Users.UpdatePassword:output_type -> users.UpdatePasswordResponse - 17, // 19: users.Users.Login:output_type -> users.LoginResponse - 19, // 20: users.Users.Logout:output_type -> users.LogoutResponse - 15, // 21: users.Users.ReadSession:output_type -> users.ReadSessionResponse - 13, // [13:22] is the sub-list for method output_type - 4, // [4:13] is the sub-list for method input_type - 4, // [4:4] is the sub-list for extension type_name - 4, // [4:4] is the sub-list for extension extendee - 0, // [0:4] is the sub-list for field type_name + 0, // 0: users.CreateResponse.user:type_name -> users.User + 17, // 1: users.ReadResponse.users:type_name -> users.ReadResponse.UsersEntry + 18, // 2: users.UpdateRequest.first_name:type_name -> google.protobuf.StringValue + 18, // 3: users.UpdateRequest.last_name:type_name -> google.protobuf.StringValue + 18, // 4: users.UpdateRequest.email:type_name -> google.protobuf.StringValue + 0, // 5: users.UpdateResponse.user:type_name -> users.User + 0, // 6: users.ListResponse.users:type_name -> users.User + 0, // 7: users.LoginResponse.user:type_name -> users.User + 0, // 8: users.ValidateResponse.user:type_name -> users.User + 0, // 9: users.ReadResponse.UsersEntry.value:type_name -> users.User + 1, // 10: users.Users.Create:input_type -> users.CreateRequest + 3, // 11: users.Users.Read:input_type -> users.ReadRequest + 5, // 12: users.Users.Update:input_type -> users.UpdateRequest + 7, // 13: users.Users.Delete:input_type -> users.DeleteRequest + 9, // 14: users.Users.List:input_type -> users.ListRequest + 11, // 15: users.Users.Login:input_type -> users.LoginRequest + 13, // 16: users.Users.Logout:input_type -> users.LogoutRequest + 15, // 17: users.Users.Validate:input_type -> users.ValidateRequest + 2, // 18: users.Users.Create:output_type -> users.CreateResponse + 4, // 19: users.Users.Read:output_type -> users.ReadResponse + 6, // 20: users.Users.Update:output_type -> users.UpdateResponse + 8, // 21: users.Users.Delete:output_type -> users.DeleteResponse + 10, // 22: users.Users.List:output_type -> users.ListResponse + 12, // 23: users.Users.Login:output_type -> users.LoginResponse + 14, // 24: users.Users.Logout:output_type -> users.LogoutResponse + 16, // 25: users.Users.Validate:output_type -> users.ValidateResponse + 18, // [18:26] is the sub-list for method output_type + 10, // [10:18] is the sub-list for method input_type + 10, // [10:10] is the sub-list for extension type_name + 10, // [10:10] is the sub-list for extension extendee + 0, // [0:10] is the sub-list for field type_name } func init() { file_proto_users_proto_init() } @@ -1297,18 +1091,6 @@ func file_proto_users_proto_init() { } } file_proto_users_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Session); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_users_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CreateRequest); i { case 0: return &v.state @@ -1320,7 +1102,7 @@ func file_proto_users_proto_init() { return nil } } - file_proto_users_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_proto_users_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CreateResponse); i { case 0: return &v.state @@ -1332,31 +1114,7 @@ func file_proto_users_proto_init() { return nil } } - file_proto_users_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeleteRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_users_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeleteResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_users_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_proto_users_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ReadRequest); i { case 0: return &v.state @@ -1368,7 +1126,7 @@ func file_proto_users_proto_init() { return nil } } - file_proto_users_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_proto_users_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ReadResponse); i { case 0: return &v.state @@ -1380,7 +1138,7 @@ func file_proto_users_proto_init() { return nil } } - file_proto_users_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_proto_users_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*UpdateRequest); i { case 0: return &v.state @@ -1392,7 +1150,7 @@ func file_proto_users_proto_init() { return nil } } - file_proto_users_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_proto_users_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*UpdateResponse); i { case 0: return &v.state @@ -1404,8 +1162,44 @@ func file_proto_users_proto_init() { return nil } } + file_proto_users_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_users_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_users_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } file_proto_users_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdatePasswordRequest); i { + switch v := v.(*ListResponse); i { case 0: return &v.state case 1: @@ -1417,66 +1211,6 @@ func file_proto_users_proto_init() { } } file_proto_users_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdatePasswordResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_users_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SearchRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_users_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SearchResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_users_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReadSessionRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_users_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReadSessionResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_users_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*LoginRequest); i { case 0: return &v.state @@ -1488,7 +1222,7 @@ func file_proto_users_proto_init() { return nil } } - file_proto_users_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + file_proto_users_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*LoginResponse); i { case 0: return &v.state @@ -1500,7 +1234,7 @@ func file_proto_users_proto_init() { return nil } } - file_proto_users_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + file_proto_users_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*LogoutRequest); i { case 0: return &v.state @@ -1512,7 +1246,7 @@ func file_proto_users_proto_init() { return nil } } - file_proto_users_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + file_proto_users_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*LogoutResponse); i { case 0: return &v.state @@ -1524,6 +1258,30 @@ func file_proto_users_proto_init() { return nil } } + file_proto_users_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ValidateRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_users_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ValidateResponse); 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{ @@ -1531,7 +1289,7 @@ func file_proto_users_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_proto_users_proto_rawDesc, NumEnums: 0, - NumMessages: 20, + NumMessages: 18, NumExtensions: 0, NumServices: 1, }, diff --git a/users/proto/users.pb.micro.go b/users/proto/users.pb.micro.go index 0e48876..2aa58a3 100644 --- a/users/proto/users.pb.micro.go +++ b/users/proto/users.pb.micro.go @@ -6,6 +6,7 @@ package users import ( fmt "fmt" proto "github.com/golang/protobuf/proto" + _ "github.com/golang/protobuf/ptypes/wrappers" math "math" ) @@ -46,11 +47,13 @@ type UsersService interface { Read(ctx context.Context, in *ReadRequest, opts ...client.CallOption) (*ReadResponse, error) Update(ctx context.Context, in *UpdateRequest, opts ...client.CallOption) (*UpdateResponse, error) Delete(ctx context.Context, in *DeleteRequest, opts ...client.CallOption) (*DeleteResponse, error) - Search(ctx context.Context, in *SearchRequest, opts ...client.CallOption) (*SearchResponse, error) - UpdatePassword(ctx context.Context, in *UpdatePasswordRequest, opts ...client.CallOption) (*UpdatePasswordResponse, error) + List(ctx context.Context, in *ListRequest, opts ...client.CallOption) (*ListResponse, error) + // Login using email and password returns the users profile and a token Login(ctx context.Context, in *LoginRequest, opts ...client.CallOption) (*LoginResponse, error) + // Logout expires all tokens for the user Logout(ctx context.Context, in *LogoutRequest, opts ...client.CallOption) (*LogoutResponse, error) - ReadSession(ctx context.Context, in *ReadSessionRequest, opts ...client.CallOption) (*ReadSessionResponse, error) + // Validate a token, each time a token is validated it extends its lifetime for another week + Validate(ctx context.Context, in *ValidateRequest, opts ...client.CallOption) (*ValidateResponse, error) } type usersService struct { @@ -105,19 +108,9 @@ func (c *usersService) Delete(ctx context.Context, in *DeleteRequest, opts ...cl return out, nil } -func (c *usersService) Search(ctx context.Context, in *SearchRequest, opts ...client.CallOption) (*SearchResponse, error) { - req := c.c.NewRequest(c.name, "Users.Search", in) - out := new(SearchResponse) - err := c.c.Call(ctx, req, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *usersService) UpdatePassword(ctx context.Context, in *UpdatePasswordRequest, opts ...client.CallOption) (*UpdatePasswordResponse, error) { - req := c.c.NewRequest(c.name, "Users.UpdatePassword", in) - out := new(UpdatePasswordResponse) +func (c *usersService) List(ctx context.Context, in *ListRequest, opts ...client.CallOption) (*ListResponse, error) { + req := c.c.NewRequest(c.name, "Users.List", in) + out := new(ListResponse) err := c.c.Call(ctx, req, out, opts...) if err != nil { return nil, err @@ -145,9 +138,9 @@ func (c *usersService) Logout(ctx context.Context, in *LogoutRequest, opts ...cl return out, nil } -func (c *usersService) ReadSession(ctx context.Context, in *ReadSessionRequest, opts ...client.CallOption) (*ReadSessionResponse, error) { - req := c.c.NewRequest(c.name, "Users.ReadSession", in) - out := new(ReadSessionResponse) +func (c *usersService) Validate(ctx context.Context, in *ValidateRequest, opts ...client.CallOption) (*ValidateResponse, error) { + req := c.c.NewRequest(c.name, "Users.Validate", in) + out := new(ValidateResponse) err := c.c.Call(ctx, req, out, opts...) if err != nil { return nil, err @@ -162,11 +155,13 @@ type UsersHandler interface { Read(context.Context, *ReadRequest, *ReadResponse) error Update(context.Context, *UpdateRequest, *UpdateResponse) error Delete(context.Context, *DeleteRequest, *DeleteResponse) error - Search(context.Context, *SearchRequest, *SearchResponse) error - UpdatePassword(context.Context, *UpdatePasswordRequest, *UpdatePasswordResponse) error + List(context.Context, *ListRequest, *ListResponse) error + // Login using email and password returns the users profile and a token Login(context.Context, *LoginRequest, *LoginResponse) error + // Logout expires all tokens for the user Logout(context.Context, *LogoutRequest, *LogoutResponse) error - ReadSession(context.Context, *ReadSessionRequest, *ReadSessionResponse) error + // Validate a token, each time a token is validated it extends its lifetime for another week + Validate(context.Context, *ValidateRequest, *ValidateResponse) error } func RegisterUsersHandler(s server.Server, hdlr UsersHandler, opts ...server.HandlerOption) error { @@ -175,11 +170,10 @@ func RegisterUsersHandler(s server.Server, hdlr UsersHandler, opts ...server.Han Read(ctx context.Context, in *ReadRequest, out *ReadResponse) error Update(ctx context.Context, in *UpdateRequest, out *UpdateResponse) error Delete(ctx context.Context, in *DeleteRequest, out *DeleteResponse) error - Search(ctx context.Context, in *SearchRequest, out *SearchResponse) error - UpdatePassword(ctx context.Context, in *UpdatePasswordRequest, out *UpdatePasswordResponse) error + List(ctx context.Context, in *ListRequest, out *ListResponse) error Login(ctx context.Context, in *LoginRequest, out *LoginResponse) error Logout(ctx context.Context, in *LogoutRequest, out *LogoutResponse) error - ReadSession(ctx context.Context, in *ReadSessionRequest, out *ReadSessionResponse) error + Validate(ctx context.Context, in *ValidateRequest, out *ValidateResponse) error } type Users struct { users @@ -208,12 +202,8 @@ func (h *usersHandler) Delete(ctx context.Context, in *DeleteRequest, out *Delet return h.UsersHandler.Delete(ctx, in, out) } -func (h *usersHandler) Search(ctx context.Context, in *SearchRequest, out *SearchResponse) error { - return h.UsersHandler.Search(ctx, in, out) -} - -func (h *usersHandler) UpdatePassword(ctx context.Context, in *UpdatePasswordRequest, out *UpdatePasswordResponse) error { - return h.UsersHandler.UpdatePassword(ctx, in, out) +func (h *usersHandler) List(ctx context.Context, in *ListRequest, out *ListResponse) error { + return h.UsersHandler.List(ctx, in, out) } func (h *usersHandler) Login(ctx context.Context, in *LoginRequest, out *LoginResponse) error { @@ -224,6 +214,6 @@ func (h *usersHandler) Logout(ctx context.Context, in *LogoutRequest, out *Logou return h.UsersHandler.Logout(ctx, in, out) } -func (h *usersHandler) ReadSession(ctx context.Context, in *ReadSessionRequest, out *ReadSessionResponse) error { - return h.UsersHandler.ReadSession(ctx, in, out) +func (h *usersHandler) Validate(ctx context.Context, in *ValidateRequest, out *ValidateResponse) error { + return h.UsersHandler.Validate(ctx, in, out) } diff --git a/users/proto/users.proto b/users/proto/users.proto index fa54fc0..c96a2ef 100644 --- a/users/proto/users.proto +++ b/users/proto/users.proto @@ -2,112 +2,93 @@ syntax = "proto3"; package users; option go_package = "proto;users"; +import "google/protobuf/wrappers.proto"; service Users { rpc Create(CreateRequest) returns (CreateResponse) {} rpc Read(ReadRequest) returns (ReadResponse) {} rpc Update(UpdateRequest) returns (UpdateResponse) {} rpc Delete(DeleteRequest) returns (DeleteResponse) {} - rpc Search(SearchRequest) returns (SearchResponse) {} - rpc UpdatePassword(UpdatePasswordRequest) returns (UpdatePasswordResponse) {} + rpc List(ListRequest) returns (ListResponse) {} + + // Login using email and password returns the users profile and a token rpc Login(LoginRequest) returns (LoginResponse) {} + // Logout expires all tokens for the user rpc Logout(LogoutRequest) returns (LogoutResponse) {} - rpc ReadSession(ReadSessionRequest) returns(ReadSessionResponse) {} + // Validate a token, each time a token is validated it extends its lifetime for another week + rpc Validate(ValidateRequest) returns (ValidateResponse) {} } message User { - string id = 1; // uuid - string username = 2; // alphanumeric user or org - string email = 3; - int64 created = 4; // unix - int64 updated = 5; // unix -} - -message Session { - string id = 1; - string username = 2; - string email = 3; - int64 created = 4; // unix - int64 expires = 5; // unix + string id = 1; + string first_name = 2; + string last_name = 3; + string email = 4; } message CreateRequest { - string id = 1; // uuid - string username = 2; // alphanumeric user or org + string first_name = 1; + string last_name = 2; string email = 3; - string password = 4; + string password = 4; } message CreateResponse { + User user = 1; + string token = 2; +} + +message ReadRequest { + repeated string ids = 1; +} + +message ReadResponse { + map users = 1; +} + +message UpdateRequest { + string id = 1; + google.protobuf.StringValue first_name = 2; + google.protobuf.StringValue last_name = 3; + google.protobuf.StringValue email = 4; +} + +message UpdateResponse { + User user = 1; } message DeleteRequest { string id = 1; } -message DeleteResponse { -} +message DeleteResponse {} -message ReadRequest { - string id = 1; -} +message ListRequest {} -message ReadResponse { - User user = 1; -} - -message UpdateRequest { - string id = 1; // uuid - string username = 2; // alphanumeric user or org - string email = 3; -} - -message UpdateResponse { -} - -message UpdatePasswordRequest { - string userId = 1; - string oldPassword = 2; - string newPassword = 3; - string confirm_password = 4; -} - -message UpdatePasswordResponse { -} - -message SearchRequest { - string username = 1; - string email = 2; - int64 limit = 3; - int64 offset = 4; -} - -message SearchResponse { +message ListResponse { repeated User users = 1; } -message ReadSessionRequest { - string sessionId = 1; -} - -message ReadSessionResponse { - Session session = 1; -} - message LoginRequest { - string username = 1; - string email = 2; - string password = 3; + string email = 1; + string password = 2; } message LoginResponse { - Session session = 1; + User user = 1; + string token = 2; } message LogoutRequest { - string sessionId = 1; + string id = 1; } -message LogoutResponse { +message LogoutResponse {} + +message ValidateRequest { + string token = 1; } +message ValidateResponse { + User user = 1; +} \ No newline at end of file