From c5788a18ea98d9bdeba54702e8329711e47e7cae Mon Sep 17 00:00:00 2001 From: Ilaria Corda Date: Sat, 28 Oct 2023 19:35:54 +0200 Subject: [PATCH] feat: add changes --- README.md | 3 ++- go.mod | 1 + go.sum | 4 ++-- pkg/message.go | 41 ++++++++++++++++++--------------- proto/message.pb.go | 55 +++++++++++++++++++++++++------------------- proto/message.proto | 4 +++- test/message_test.go | 46 ++++++++++++++++++------------------ 7 files changed, 84 insertions(+), 70 deletions(-) diff --git a/README.md b/README.md index 6a2fe13..005d45c 100644 --- a/README.md +++ b/README.md @@ -98,4 +98,5 @@ The task was time-boxed and this currently version was reached in approximately ### Subsequent PRs - Added structured logging with [zerolog](https://github.com/rs/zerolog) whose basic setup for Console logging is defined in `logger.go` and called in `main.go` -- ADD linter to Github actions and include Makefile with targets \ No newline at end of file +- ADD linter to Github actions and include Makefile with targets +- Move to proto definitions as opposed to JSON \ No newline at end of file diff --git a/go.mod b/go.mod index 70e7566..881bf59 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module secure-messaging-system go 1.21 require ( + github.com/google/go-cmp v0.6.0 github.com/icrowley/fake v0.0.0-20221112152111-d7b7e2276db2 github.com/rs/zerolog v1.31.0 github.com/stretchr/testify v1.7.5 diff --git a/go.sum b/go.sum index 1623b6a..7728436 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,9 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/icrowley/fake v0.0.0-20221112152111-d7b7e2276db2 h1:qU3v73XG4QAqCPHA4HOpfC1EfUvtLIDvQK4mNQ0LvgI= github.com/icrowley/fake v0.0.0-20221112152111-d7b7e2276db2/go.mod h1:dQ6TM/OGAe+cMws81eTe4Btv1dKxfPZ2CX+YaAFAPN4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -30,7 +31,6 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= diff --git a/pkg/message.go b/pkg/message.go index 38666f7..4a7af3f 100644 --- a/pkg/message.go +++ b/pkg/message.go @@ -4,6 +4,7 @@ import ( "encoding/json" "errors" "github.com/rs/zerolog/log" + "google.golang.org/protobuf/types/known/timestamppb" pb "secure-messaging-system/proto" "time" "unicode/utf8" @@ -23,7 +24,7 @@ func NewMessageBuilder() *MessageBuilder { // WithSenderID sets the SenderID of the message. func (b *MessageBuilder) WithSenderID(senderID string) *MessageBuilder { if senderID == "" { - log.Warn().Msg("Provided empty SenderID") + log.Warn().Msg("Provided empty SenderId") return b } b.message.SenderId = senderID @@ -33,15 +34,15 @@ func (b *MessageBuilder) WithSenderID(senderID string) *MessageBuilder { // WithReceiverID sets the ReceiverID of the message. func (b *MessageBuilder) WithReceiverID(receiverID string) *MessageBuilder { if receiverID == "" { - log.Warn().Msg("Provided empty ReceiverID") + log.Warn().Msg("Provided empty ReceiverId") return b } b.message.ReceiverId = receiverID return b } -func (b *MessageBuilder) WithTimestamp(timestamp time.Time) *MessageBuilder { - b.message.Timestamp = timestamp.Unix() +func (b *MessageBuilder) WithTimestamp(timeStamp time.Time) *MessageBuilder { + b.message.Timestamp = timestamppb.New(timeStamp) return b } @@ -57,19 +58,21 @@ func (b *MessageBuilder) WithEncryptedText(encryptedText string) *MessageBuilder // Build finalizes the building process and returns the constructed Message. func (b *MessageBuilder) Build() (*pb.Message, error) { - if b.message.SenderId == "" || b.message.ReceiverId == "" || b.message.EncryptedText == "" { + if b.message.SenderId == "" || + b.message.ReceiverId == "" || + b.message.EncryptedText == "" || + b.message.Timestamp == nil { return nil, errors.New("message is incomplete") } - if b.message.Timestamp == 0 { - b.message.Timestamp = time.Now().Unix() - } - return b.message, nil } -func NewMessage(senderID, receiverID, encryptedText string) *pb.Message { - if senderID == "" || receiverID == "" || encryptedText == "" { +func NewMessage(senderID, receiverID, encryptedText string, timestamp *time.Time) *pb.Message { + if senderID == "" || + receiverID == "" || + encryptedText == "" || + timestamp == nil { log.Error().Msg("Cannot create a new message with empty fields") return nil } @@ -77,7 +80,7 @@ func NewMessage(senderID, receiverID, encryptedText string) *pb.Message { return &pb.Message{ SenderId: senderID, ReceiverId: receiverID, - Timestamp: time.Now().Unix(), + Timestamp: timestamppb.New(*timestamp), EncryptedText: encryptedText, } } @@ -97,12 +100,12 @@ func ToJSON(msg *pb.Message) ([]byte, error) { return jsonData, nil } -// MessageFromJSON converts a JSON representation to a message. -func MessageFromJSON(data []byte) (*pb.Message, error) { - msg := &pb.Message{} - err := json.Unmarshal(data, msg) - if err != nil { - return nil, err +func FromJSON(data []byte) (*pb.Message, error) { + var msg pb.Message + + if err := json.Unmarshal(data, &msg); err != nil { + return nil, errors.New("failed to unmarshal JSON into Message struct: " + err.Error()) } - return msg, nil + + return &msg, nil } diff --git a/proto/message.pb.go b/proto/message.pb.go index 23981d3..3cf6486 100644 --- a/proto/message.pb.go +++ b/proto/message.pb.go @@ -9,6 +9,7 @@ package pkg import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" ) @@ -25,10 +26,10 @@ type Message struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - SenderId string `protobuf:"bytes,1,opt,name=sender_id,json=senderId,proto3" json:"sender_id,omitempty"` - ReceiverId string `protobuf:"bytes,2,opt,name=receiver_id,json=receiverId,proto3" json:"receiver_id,omitempty"` - Timestamp int64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` - EncryptedText string `protobuf:"bytes,4,opt,name=encrypted_text,json=encryptedText,proto3" json:"encrypted_text,omitempty"` + SenderId string `protobuf:"bytes,1,opt,name=sender_id,json=senderId,proto3" json:"sender_id,omitempty"` + ReceiverId string `protobuf:"bytes,2,opt,name=receiver_id,json=receiverId,proto3" json:"receiver_id,omitempty"` + Timestamp *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + EncryptedText string `protobuf:"bytes,4,opt,name=encrypted_text,json=encryptedText,proto3" json:"encrypted_text,omitempty"` } func (x *Message) Reset() { @@ -77,11 +78,11 @@ func (x *Message) GetReceiverId() string { return "" } -func (x *Message) GetTimestamp() int64 { +func (x *Message) GetTimestamp() *timestamppb.Timestamp { if x != nil { return x.Timestamp } - return 0 + return nil } func (x *Message) GetEncryptedText() string { @@ -95,18 +96,22 @@ var File_message_proto protoreflect.FileDescriptor var file_message_proto_rawDesc = []byte{ 0x0a, 0x0d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, - 0x03, 0x70, 0x6b, 0x67, 0x22, 0x8c, 0x01, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1f, 0x0a, - 0x0b, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1c, - 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x25, 0x0a, 0x0e, - 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x54, - 0x65, 0x78, 0x74, 0x42, 0x1d, 0x5a, 0x1b, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x2d, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x69, 0x6e, 0x67, 0x2d, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2f, 0x70, - 0x6b, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x03, 0x70, 0x6b, 0x67, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa8, 0x01, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1f, + 0x0a, 0x0b, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x49, 0x64, 0x12, + 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x65, 0x6e, 0x63, + 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0d, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x54, 0x65, 0x78, 0x74, + 0x42, 0x1d, 0x5a, 0x1b, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x2d, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x69, 0x6e, 0x67, 0x2d, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2f, 0x70, 0x6b, 0x67, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -123,14 +128,16 @@ func file_message_proto_rawDescGZIP() []byte { var file_message_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_message_proto_goTypes = []interface{}{ - (*Message)(nil), // 0: pkg.Message + (*Message)(nil), // 0: pkg.Message + (*timestamppb.Timestamp)(nil), // 1: google.protobuf.Timestamp } var file_message_proto_depIdxs = []int32{ - 0, // [0:0] is the sub-list for method output_type - 0, // [0:0] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name + 1, // 0: pkg.Message.timestamp:type_name -> google.protobuf.Timestamp + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name } func init() { file_message_proto_init() } diff --git a/proto/message.proto b/proto/message.proto index 8f3e507..2271597 100644 --- a/proto/message.proto +++ b/proto/message.proto @@ -2,11 +2,13 @@ syntax = "proto3"; package pkg; +import "google/protobuf/timestamp.proto"; + option go_package = "secure-messaging-system/pkg"; message Message { string sender_id = 1; string receiver_id = 2; - int64 timestamp = 3; + google.protobuf.Timestamp timestamp = 3; string encrypted_text = 4; } \ No newline at end of file diff --git a/test/message_test.go b/test/message_test.go index f3b2512..71a9c31 100644 --- a/test/message_test.go +++ b/test/message_test.go @@ -1,11 +1,15 @@ package test import ( + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/icrowley/fake" "github.com/stretchr/testify/assert" + "google.golang.org/protobuf/types/known/timestamppb" "secure-messaging-system/pkg" pb "secure-messaging-system/proto" "testing" + "time" ) const ( @@ -19,8 +23,9 @@ func Test_NewMessage(t *testing.T) { senderID := fake.CharactersN(10) receiverID := fake.CharactersN(10) encryptedText := fake.Sentence() + timestamp := time.Now() - message := pkg.NewMessage(senderID, receiverID, encryptedText) + message := pkg.NewMessage(senderID, receiverID, encryptedText, ×tamp) assert.Equal(t, senderID, message.SenderId, senderIDMismatchErr) assert.Equal(t, receiverID, message.ReceiverId, receiverIDMismatchErr) @@ -35,21 +40,22 @@ func TestMessageBuilder(t *testing.T) { senderID := fake.CharactersN(10) receiverID := fake.CharactersN(10) encryptedText := fake.Sentence() + timestamp := time.Now() message, err := pkg.NewMessageBuilder(). WithSenderID(senderID). WithReceiverID(receiverID). WithEncryptedText(encryptedText). + WithTimestamp(timestamp). Build() assert.NoError(t, err, "Error building the message") - assert.Equal(t, senderID, message.SenderId, senderIDMismatchErr) - assert.Equal(t, receiverID, message.ReceiverId, receiverIDMismatchErr) - assert.Equal(t, encryptedText, message.EncryptedText, encryptedTextMismatchErr) + assert.Equal(t, senderID, message.SenderId, "Mismatched Sender ID") + assert.Equal(t, receiverID, message.ReceiverId, "Mismatched Receiver ID") + assert.Equal(t, encryptedText, message.EncryptedText, "Mismatched Encrypted Text") - // Make sure that the timestamp was set - assert.NotEqual(t, int64(0), message.Timestamp, "Timestamp was not set") + assert.Equal(t, timestamppb.New(timestamp), message.Timestamp, "Timestamp mismatch") }) } @@ -66,7 +72,7 @@ func TestMessageConversion(t *testing.T) { message: &pb.Message{ SenderId: fake.CharactersN(10), ReceiverId: fake.CharactersN(10), - Timestamp: int64(0), + Timestamp: timestamppb.New(time.Now()), EncryptedText: fake.Paragraph(), }, wantErr: false, @@ -76,7 +82,7 @@ func TestMessageConversion(t *testing.T) { message: &pb.Message{ SenderId: fake.CharactersN(10), ReceiverId: fake.CharactersN(10), - Timestamp: int64(0), + Timestamp: timestamppb.New(time.Now()), EncryptedText: string([]byte{0x80, 0x81, 0x82, 0x83}), }, wantErr: true, @@ -90,7 +96,7 @@ func TestMessageConversion(t *testing.T) { name: "incomplete Message", message: &pb.Message{ SenderId: fake.CharactersN(10), - Timestamp: int64(0), + Timestamp: timestamppb.New(time.Now()), }, wantErr: false, }, @@ -111,26 +117,20 @@ func TestMessageConversion(t *testing.T) { return } - msgFromJSON, err := pkg.MessageFromJSON(jsonData) + msgFromJSON, err := pkg.FromJSON(jsonData) if (err != nil) != tt.wantErr { t.Errorf("MessageFromJSON() error = %v, wantErr %v", err, tt.wantErr) return } - if !tt.wantErr { - assert.True(t, messagesAreEquivalent(tt.message, msgFromJSON)) + diff := cmp.Diff( + tt.message, + msgFromJSON, + cmpopts.IgnoreUnexported(pb.Message{}, timestamppb.Timestamp{}), + ) + if diff != "" { + t.Errorf("Mismatch (-Original +FromJSON):\n%s", diff) } }) } } - -// Helper function - -// messagesAreEquivalent compares two pb.Message objects and determines if they are equivalent. -func messagesAreEquivalent(msg1, msg2 *pb.Message) bool { - // Compare individual fields of the messages. - return msg1.SenderId == msg2.SenderId && - msg1.ReceiverId == msg2.ReceiverId && - msg1.EncryptedText == msg2.EncryptedText && - msg1.Timestamp == msg2.Timestamp -}