From 39a0e5c01fb047753dc49ce8f0e09dc9029e484f Mon Sep 17 00:00:00 2001 From: afonso Date: Fri, 19 Apr 2024 11:55:16 +0100 Subject: [PATCH 1/8] [PD1] Fixed stuff. Unmarshal still returns map[string]interface{}, need to fix --- Projs/PD1/internal/client/client.go | 7 +- Projs/PD1/internal/protocol/protocol.go | 166 +++++++++--------- Projs/PD1/internal/server/datastore.go | 19 ++ Projs/PD1/internal/server/server.go | 24 ++- .../internal/utils/cryptoUtils/cryptoUtils.go | 1 - .../internal/utils/networking/connection.go | 6 +- 6 files changed, 127 insertions(+), 96 deletions(-) diff --git a/Projs/PD1/internal/client/client.go b/Projs/PD1/internal/client/client.go index 00aa35c..8ffca2c 100644 --- a/Projs/PD1/internal/client/client.go +++ b/Projs/PD1/internal/client/client.go @@ -5,6 +5,7 @@ import ( "PD1/internal/utils/cryptoUtils" "PD1/internal/utils/networking" "flag" + "fmt" ) func Run() { @@ -34,7 +35,11 @@ func Run() { certRequestPacket := protocol.NewRequestUserCertPacket(uid) cl.Connection.Send(certRequestPacket) - //certPacket := cl.Connection.Receive() + + var certPacket protocol.Packet + cl.Connection.Receive(&certPacket) + uidCert := (certPacket.Body).(protocol.SendUserCertPacket) + fmt.Println(uidCert) // TODO: Encrypt message //submitMessage(cl, uid, cipherContent) diff --git a/Projs/PD1/internal/protocol/protocol.go b/Projs/PD1/internal/protocol/protocol.go index 1e08ad6..6134233 100644 --- a/Projs/PD1/internal/protocol/protocol.go +++ b/Projs/PD1/internal/protocol/protocol.go @@ -1,116 +1,114 @@ package protocol import ( - "time" + "time" ) type PacketType int const ( - ReqUserCertPkt PacketType = iota - ReqAllMsgPkt - ReqMsgPkt - SubmitMsgPkt - SendUserCertPkt - ServerMsgPkt + ReqUserCertPkt PacketType = iota + ReqAllMsgPkt + ReqMsgPkt + SubmitMsgPkt + SendUserCertPkt + ServerMsgPkt +) + +// Define interfaces for packet bodies +type ( + RequestUserCertPacket struct { + UID string `json:"uid"` + } + + RequestAllMsgPacket struct { + FromUID string `json:"from_uid"` + } + + RequestMsgPacket struct { + Num uint16 `json:"num"` + } + + SubmitMessagePacket struct { + ToUID string `json:"to_uid"` + Content []byte `json:"content"` + } + + SendUserCertPacket struct { + UID string `json:"uid"` + Key []byte `json:"key"` + } + + ServerMessagePacket struct { + FromUID string `json:"from_uid"` + ToUID string `json:"to_uid"` + Content []byte `json:"content"` + Timestamp time.Time `json:"timestamp"` + } ) type PacketBody interface{} type Packet struct { - Flag PacketType - Body PacketBody -} - -// Client --> Server: Ask for a user's certificate -type RequestUserCertPacket struct { - UID string + Flag PacketType `json:"flag"` + Body PacketBody `json:"body"` } func NewRequestUserCertPacket(UID string) Packet { - return Packet{ - Flag: ReqUserCertPkt, - Body: RequestUserCertPacket{ - UID: UID, - }, - } -} - -// Client --> Server: Ask for all the client's messages in the queue -type RequestAllMsgPacket struct { - FromUID string + return Packet{ + Flag: ReqUserCertPkt, + Body: RequestUserCertPacket{ + UID: UID, + }, + } } func NewRequestAllMsgPacket(fromUID string) Packet { - return Packet{ - Flag: ReqAllMsgPkt, - Body: RequestAllMsgPacket{ - FromUID: fromUID, - }, - } -} - -// Client --> Server: Ask for a specific message in the queue -type RequestMsgPacket struct { - Num uint16 + return Packet{ + Flag: ReqAllMsgPkt, + Body: RequestAllMsgPacket{ + FromUID: fromUID, + }, + } } func NewRequestMsgPacket(num uint16) Packet { - return Packet{ - Flag: ReqMsgPkt, - Body: RequestMsgPacket{ - Num: num, - }, - } -} - -// Client --> Server: Send message from client to server -type SubmitMessagePacket struct { - ToUID string - Content []byte + return Packet{ + Flag: ReqMsgPkt, + Body: RequestMsgPacket{ + Num: num, + }, + } } func NewSubmitMessagePacket(toUID string, content []byte) Packet { - return Packet{ - Flag: SubmitMsgPkt, - Body: SubmitMessagePacket{ - ToUID: toUID, - Content: content}, - } -} - -// Server --> Client: Send the client the requested public key -type SendUserCertPacket struct { - UID string - Key []byte + return Packet{ + Flag: SubmitMsgPkt, + Body: SubmitMessagePacket{ + ToUID: toUID, + Content: content, + }, + } } func NewSendUserCertPacket(uid string, key []byte) Packet { - return Packet{ - Flag: SendUserCertPkt, - Body: SendUserCertPacket{ - UID: uid, - Key: key, - }, - } -} - -// Server --> Client: Send the client a message -type ServerMessagePacket struct { - FromUID string - ToUID string - Content []byte - Timestamp time.Time + return Packet{ + Flag: SendUserCertPkt, + Body: SendUserCertPacket{ + UID: uid, + Key: key, + }, + } } func NewServerMessagePacket(fromUID, toUID string, content []byte, timestamp time.Time) Packet { - return Packet{ - Flag: ServerMsgPkt, - Body: ServerMessagePacket{ - FromUID: fromUID, - ToUID: toUID, - Content: content, - Timestamp: timestamp, - }, - } + return Packet{ + Flag: ServerMsgPkt, + Body: ServerMessagePacket{ + FromUID: fromUID, + ToUID: toUID, + Content: content, + Timestamp: timestamp, + }, + } } diff --git a/Projs/PD1/internal/server/datastore.go b/Projs/PD1/internal/server/datastore.go index 9513fdc..7120ea9 100644 --- a/Projs/PD1/internal/server/datastore.go +++ b/Projs/PD1/internal/server/datastore.go @@ -154,3 +154,22 @@ func (ds DataStore) GetUserCertificate(uid string) protocol.Packet { } return protocol.NewSendUserCertPacket(uid, userCert) } + +func userExists(db *sql.DB, uid string) bool { + // Prepare the SQL statement for checking if a user exists + query := ` + SELECT COUNT(*) + FROM users + WHERE UID = ? + ` + + var count int + // Execute the SQL query + err := db.QueryRow(query, uid).Scan(&count) + if err != nil { + log.Panicln("Error checking if user exists") + } + + // If count is greater than 0, the user exists + return count > 0 +} diff --git a/Projs/PD1/internal/server/server.go b/Projs/PD1/internal/server/server.go index c2b4c19..c963342 100644 --- a/Projs/PD1/internal/server/server.go +++ b/Projs/PD1/internal/server/server.go @@ -9,17 +9,29 @@ import ( func clientHandler(connection networking.Connection[protocol.Packet], dataStore DataStore) { defer connection.Conn.Close() - _ = dataStore + + //Get certificate sent by user clientCert := connection.GetPeerCertificate() - oidValueMap := cryptoUtils.ExtractAllOIDValues(clientCert) - fmt.Println(oidValueMap) + //Get the OID values + oidMap := cryptoUtils.ExtractAllOIDValues(clientCert) + //Get the UID of this user + UID := oidMap["2.5.4.65"] + if UID=="" { + panic("User certificate does not specify it's PSEUDONYM") + } for { - pac := connection.Receive() + var pac protocol.Packet + connection.Receive(&pac) switch pac.Flag { case protocol.ReqUserCertPkt: - //userCertPacket := dataStore.GetUserCertificate(uid) - //connection.Send(userCertPacket) + fmt.Printf("Type of pac.Body: %T\n", pac.Body) + UserCertPacket, ok := (pac.Body).(protocol.RequestUserCertPacket) + if !ok { + panic("Could not cast packet to it's type") + } + userCertPacket := dataStore.GetUserCertificate(UserCertPacket.UID) + connection.Send(userCertPacket) case protocol.ReqAllMsgPkt: fmt.Println("ReqAllMsg") case protocol.ReqMsgPkt: diff --git a/Projs/PD1/internal/utils/cryptoUtils/cryptoUtils.go b/Projs/PD1/internal/utils/cryptoUtils/cryptoUtils.go index 58a0fbe..3c5dd1c 100644 --- a/Projs/PD1/internal/utils/cryptoUtils/cryptoUtils.go +++ b/Projs/PD1/internal/utils/cryptoUtils/cryptoUtils.go @@ -94,7 +94,6 @@ func (k *KeyStore) GetServerTLSConfig() *tls.Config { caCertPool.AddCert(caCert) } tlsConfig.ClientCAs = caCertPool - //Request one valid or invalid certificate //FIX: SERVER ACCEPTS CONNECTIONS WITH UNMATCHING OR // NO CERTIFICATE, NEEDS TO BE CHANGED SOMEHOW tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert diff --git a/Projs/PD1/internal/utils/networking/connection.go b/Projs/PD1/internal/utils/networking/connection.go index e1bff4d..28a5997 100644 --- a/Projs/PD1/internal/utils/networking/connection.go +++ b/Projs/PD1/internal/utils/networking/connection.go @@ -26,12 +26,10 @@ func (c Connection[T]) Send(obj T) { } } -func (c Connection[T]) Receive() T { - var obj T - if err := c.decoder.Decode(&obj); err != nil { +func (c Connection[T]) Receive(objPtr *T) { + if err := c.decoder.Decode(objPtr); err != nil { panic("Failed decoding data or reading it from connection") } - return obj } func (c Connection[T]) GetPeerCertificate() *x509.Certificate { From 7b3172a850bc079ea00b509554f2b20d5a29e881 Mon Sep 17 00:00:00 2001 From: afonso Date: Fri, 19 Apr 2024 23:59:26 +0100 Subject: [PATCH 2/8] [PD1] Fixed almost everything --- Projs/PD1/go.mod | 8 +- Projs/PD1/go.sum | 2 + Projs/PD1/internal/client/client.go | 131 +++++++-- Projs/PD1/internal/client/datastore.go | 48 +++- Projs/PD1/internal/client/interface.go | 20 +- Projs/PD1/internal/protocol/protocol.go | 263 ++++++++++++------ Projs/PD1/internal/server/datastore.go | 162 +++++++---- Projs/PD1/internal/server/server.go | 44 ++- .../internal/utils/cryptoUtils/cryptoUtils.go | 1 - .../internal/utils/networking/connection.go | 33 ++- Projs/PD1/internal/utils/networking/server.go | 1 - Projs/PD1/server.db | Bin 0 -> 20480 bytes Projs/PD1/tokefile.toml | 13 +- 13 files changed, 534 insertions(+), 192 deletions(-) create mode 100644 Projs/PD1/server.db diff --git a/Projs/PD1/go.mod b/Projs/PD1/go.mod index 29ae242..17a5c07 100644 --- a/Projs/PD1/go.mod +++ b/Projs/PD1/go.mod @@ -3,7 +3,9 @@ module PD1 go 1.22.2 require ( - github.com/mattn/go-sqlite3 v1.14.22 // indirect - golang.org/x/crypto v0.11.0 // indirect - software.sslmate.com/src/go-pkcs12 v0.4.0 // indirect + github.com/mattn/go-sqlite3 v1.14.22 + golang.org/x/crypto v0.11.0 + software.sslmate.com/src/go-pkcs12 v0.4.0 ) + +require golang.org/x/sys v0.10.0 // indirect diff --git a/Projs/PD1/go.sum b/Projs/PD1/go.sum index 90a922e..cb0edca 100644 --- a/Projs/PD1/go.sum +++ b/Projs/PD1/go.sum @@ -2,5 +2,7 @@ github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k= software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= diff --git a/Projs/PD1/internal/client/client.go b/Projs/PD1/internal/client/client.go index 8ffca2c..3f8487e 100644 --- a/Projs/PD1/internal/client/client.go +++ b/Projs/PD1/internal/client/client.go @@ -4,8 +4,10 @@ import ( "PD1/internal/protocol" "PD1/internal/utils/cryptoUtils" "PD1/internal/utils/networking" + "crypto/x509" "flag" "fmt" + "sort" ) func Run() { @@ -16,7 +18,7 @@ func Run() { if flag.NArg() == 0 { panic("No command provided. Use 'help' for instructions.") } - //Get user KeyStore + //Get user KeyStore password := AskUserPassword() clientKeyStore := cryptoUtils.LoadKeyStore(userFile, password) @@ -27,27 +29,79 @@ func Run() { panic("Insufficient arguments for 'send' command. Usage: send ") } uid := flag.Arg(1) - //subject := flag.Arg(2) - //messageContent := readMessageContent() + subject := flag.Arg(2) + messageBody := readMessageBody() + //Turn content to bytes + marshaledSubject := Marshal(subject) + marshaledBody := Marshal(messageBody) cl := networking.NewClient[protocol.Packet](&clientKeyStore) defer cl.Connection.Conn.Close() - certRequestPacket := protocol.NewRequestUserCertPacket(uid) - cl.Connection.Send(certRequestPacket) - - var certPacket protocol.Packet - cl.Connection.Receive(&certPacket) - uidCert := (certPacket.Body).(protocol.SendUserCertPacket) - fmt.Println(uidCert) - - // TODO: Encrypt message - //submitMessage(cl, uid, cipherContent) + uidCert := getUserCert(cl, uid) + if uidCert == nil { + return + } + encryptedSubject := clientKeyStore.EncryptMessageContent(uidCert, marshaledSubject) + encryptedBody := clientKeyStore.EncryptMessageContent(uidCert, marshaledBody) + submitMessage := protocol.NewSubmitMessagePacket(uid, encryptedSubject, encryptedBody) + if !cl.Connection.Send(submitMessage) { + return + } + cl.Connection.Conn.Close() case "askqueue": cl := networking.NewClient[protocol.Packet](&clientKeyStore) defer cl.Connection.Conn.Close() + requestUnreadMsgsQueuePacket := protocol.NewRequestUnreadMsgsQueuePacket() + if !cl.Connection.Send(requestUnreadMsgsQueuePacket) { + return + } + serverMessagePackets, certificates := getManyMessagesInfo(cl) + var clientMessages []ClientMessageInfo + for _, message := range serverMessagePackets { + senderCert, ok := certificates[message.FromUID] + if ok { + decryptedSubjectBytes := clientKeyStore.DecryptMessageContent(senderCert, message.Subject) + subject := Unmarshal(decryptedSubjectBytes) + clientMessage := newClientMessageInfo(message.Num, message.FromUID, subject, message.Timestamp) + clientMessages = append(clientMessages, clientMessage) + } + } + //Sort the messages + sort.Slice(clientMessages, func(i, j int) bool { + return clientMessages[i].Num > clientMessages[j].Num + }) + + showMessagesInfo(clientMessages) + + //case "getall": + // cl := networking.NewClient[protocol.Packet](&clientKeyStore) + // defer cl.Connection.Conn.Close() + + // requestAllMsgPacket := protocol.NewRequestAllMsgPacket() + // if !cl.Connection.Send(requestAllMsgPacket) { + // return + // } + // serverMessagePackets,certificates := getManyMessages(cl) + // var clientMessages []ClientMessage + // for _, message := range serverMessagePackets { + // senderCert, ok := certificates[message.FromUID] + // if ok { + // decryptedContentBytes := clientKeyStore.DecryptMessageContent(senderCert, message.Content) + // content := UnmarshalContent(decryptedContentBytes) + // clientMessage := newClientMessage(message.FromUID, message.ToUID, content, message.Timestamp) + // clientMessages = append(clientMessages, clientMessage) + // } + // } + // //Sort the messages + // sort.Slice(clientMessages, func(i, j int) bool { + // return clientMessages[i].Timestamp.After(clientMessages[j].Timestamp) + // }) + + // showMessages(clientMessages) + case "getmsg": if flag.NArg() < 2 { panic("Insufficient arguments for 'getmsg' command. Usage: getmsg ") @@ -65,7 +119,52 @@ func Run() { } -func submitMessage(cl networking.Client[protocol.Packet], uid string, content []byte) { - pack := protocol.NewSubmitMessagePacket(uid, content) - cl.Connection.Send(pack) +func getUserCert(cl networking.Client[protocol.Packet], uid string) *x509.Certificate { + certRequestPacket := protocol.NewRequestUserCertPacket(uid) + if !cl.Connection.Send(certRequestPacket) { + return nil + } + var certPacket *protocol.Packet + certPacket, active := cl.Connection.Receive() + if !active { + return nil + } + uidCertInBytes := protocol.UnmarshalSendUserCertPacket(certPacket.Body) + uidCert, err := x509.ParseCertificate(uidCertInBytes.Certificate) + if err != nil { + return nil + } + return uidCert +} + +func getManyMessagesInfo(cl networking.Client[protocol.Packet]) ([]protocol.ServerMessageInfoPacket, map[string]*x509.Certificate) { + //Create the slice to hold the incoming messages before decrypting + //Create the map to hold the sender certificates + //Create sync mutexes + serverMessageInfoPackets := []protocol.ServerMessageInfoPacket{} + //Run while message isn't the last one + msg := protocol.ServerMessageInfoPacket{} + for !msg.Last { + sendMsgPacket, active := cl.Connection.Receive() + if !active { + return nil, nil + } + msg = protocol.UnmarshalServerMessageInfoPacket(sendMsgPacket.Body) + //Lock and append + serverMessageInfoPackets = append(serverMessageInfoPackets, msg) + } + + //Create Set of needed certificates + senderSet := map[string]bool{} + for _, messageInfo := range serverMessageInfoPackets { + senderSet[messageInfo.FromUID] = true + } + certificatesMap := map[string]*x509.Certificate{} + //Get senders' certificates + for senderUID := range senderSet { + senderCert := getUserCert(cl, senderUID) + fmt.Println("Got a User cert") + certificatesMap[senderUID] = senderCert + } + return serverMessageInfoPackets, certificatesMap } diff --git a/Projs/PD1/internal/client/datastore.go b/Projs/PD1/internal/client/datastore.go index 2ff30e9..55a38ff 100644 --- a/Projs/PD1/internal/client/datastore.go +++ b/Projs/PD1/internal/client/datastore.go @@ -1,15 +1,47 @@ package client -import "time" +import ( + "encoding/json" + "log" + "time" +) -type Content struct { - Subject []byte - Body []byte -} - -type RecievedMessage struct { +type ClientMessage struct { FromUID string ToUID string - Content Content + Subject string + Body string Timestamp time.Time } + +type ClientMessageInfo struct { + Num int + FromUID string + Timestamp time.Time + Subject string +} + +func newClientMessage(fromUID string, toUID string, subject string, body string, timestamp time.Time) ClientMessage { + return ClientMessage{FromUID: fromUID, ToUID: toUID, Subject: subject, Body: body, Timestamp: timestamp} +} + +func newClientMessageInfo(num int, fromUID string, subject string, timestamp time.Time) ClientMessageInfo { + return ClientMessageInfo{Num:num,FromUID: fromUID,Subject: subject,Timestamp: timestamp} +} + +func Marshal(data any) []byte { + subject, err := json.Marshal(data) + if err != nil { + log.Panicf("Error when marshalling message: %v", err) + } + return subject +} + +func Unmarshal(data []byte) string { + var c string + err := json.Unmarshal(data, &c) + if err != nil { + log.Panicln("Could not unmarshal data") + } + return c +} diff --git a/Projs/PD1/internal/client/interface.go b/Projs/PD1/internal/client/interface.go index 02cee71..8d49bb6 100644 --- a/Projs/PD1/internal/client/interface.go +++ b/Projs/PD1/internal/client/interface.go @@ -6,7 +6,7 @@ import ( "os" ) -func readMessageContent() string { +func readMessageBody() string { fmt.Println("Enter message content (limited to 1000 bytes):") scanner := bufio.NewScanner(os.Stdin) scanner.Scan() @@ -23,11 +23,10 @@ func AskUserPassword() string { } func commandError() { - fmt.Println("MSG SERVICE: command error!") - showHelp() + fmt.Println("MSG SERVICE: command error!") + showHelp() } - func showHelp() { fmt.Println("Comandos da aplicação cliente:") fmt.Println("-user : Especifica o ficheiro com dados do utilizador. Por omissão, será assumido que esse ficheiro é userdata.p12.") @@ -36,3 +35,16 @@ func showHelp() { fmt.Println("getmsg : Solicita ao servidor o envio da mensagem da sua queue com número .") fmt.Println("help: Imprime instruções de uso do programa.") } + +func showMessagesInfo(messages []ClientMessageInfo) { + for _, message := range messages { + fmt.Printf("%v:%v:%v:%v\n", message.Num, message.FromUID, message.Timestamp, message.Subject) + } +} + +func showMessage(message ClientMessage) { + fmt.Printf("From:%v\n", message.FromUID) + fmt.Printf("To:%v\n", message.ToUID) + fmt.Printf("Subject:%v\n", message.Subject) + fmt.Printf("Body:%v\n", message.Body) +} diff --git a/Projs/PD1/internal/protocol/protocol.go b/Projs/PD1/internal/protocol/protocol.go index 6134233..6aeecec 100644 --- a/Projs/PD1/internal/protocol/protocol.go +++ b/Projs/PD1/internal/protocol/protocol.go @@ -1,114 +1,219 @@ package protocol import ( - "time" + "encoding/json" + "fmt" + "time" ) type PacketType int const ( - ReqUserCertPkt PacketType = iota - ReqAllMsgPkt - ReqMsgPkt - SubmitMsgPkt - SendUserCertPkt - ServerMsgPkt + ReqUserCertPkt PacketType = iota + ReqMsgsQueue + ReqMsgPkt + SubmitMsgPkt + SendUserCertPkt + ServerMsgInfoPkt + ServerMsgPkt ) -// Define interfaces for packet bodies type ( - RequestUserCertPacket struct { - UID string `json:"uid"` - } + RequestUserCertPacket struct { + UID string `json:"uid"` + } - RequestAllMsgPacket struct { - FromUID string `json:"from_uid"` - } + RequestMsgsQueuePacket struct { + } - RequestMsgPacket struct { - Num uint16 `json:"num"` - } + RequestMsgPacket struct { + Num int `json:"num"` + } - SubmitMessagePacket struct { - ToUID string `json:"to_uid"` - Content []byte `json:"content"` - } + SubmitMessagePacket struct { + ToUID string `json:"to_uid"` + Subject []byte `json:"subject"` + Body []byte `json:"body"` + } - SendUserCertPacket struct { - UID string `json:"uid"` - Key []byte `json:"key"` - } + SendUserCertPacket struct { + UID string `json:"uid"` + Certificate []byte `json:"certificate"` + } - ServerMessagePacket struct { - FromUID string `json:"from_uid"` - ToUID string `json:"to_uid"` - Content []byte `json:"content"` - Timestamp time.Time `json:"timestamp"` - } + ServerMessageInfoPacket struct { + Num int `json:"num"` + FromUID string `json:"from_uid"` + Subject []byte `json:"subject"` + Timestamp time.Time `json:"timestamp"` + Last bool `json:"last"` + } + ServerMessagePacket struct { + FromUID string `json:"from_uid"` + ToUID string `json:"to_uid"` + Subject []byte `json:"subject"` + Body []byte `json:"body"` + Timestamp time.Time `json:"timestamp"` + } ) type PacketBody interface{} type Packet struct { - Flag PacketType `json:"flag"` - Body PacketBody `json:"body"` + Flag PacketType `json:"flag"` + Body PacketBody `json:"body"` } func NewRequestUserCertPacket(UID string) Packet { - return Packet{ - Flag: ReqUserCertPkt, - Body: RequestUserCertPacket{ - UID: UID, - }, - } + return Packet{ + Flag: ReqUserCertPkt, + Body: RequestUserCertPacket{ + UID: UID, + }, + } } -func NewRequestAllMsgPacket(fromUID string) Packet { - return Packet{ - Flag: ReqAllMsgPkt, - Body: RequestAllMsgPacket{ - FromUID: fromUID, - }, - } +func NewRequestUnreadMsgsQueuePacket() Packet { + return Packet{ + Flag: ReqMsgsQueue, + Body: RequestMsgsQueuePacket{}, + } } -func NewRequestMsgPacket(num uint16) Packet { - return Packet{ - Flag: ReqMsgPkt, - Body: RequestMsgPacket{ - Num: num, - }, - } +func NewRequestMsgPacket(num int) Packet { + return Packet{ + Flag: ReqMsgPkt, + Body: RequestMsgPacket{ + Num: num, + }, + } } -func NewSubmitMessagePacket(toUID string, content []byte) Packet { - return Packet{ - Flag: SubmitMsgPkt, - Body: SubmitMessagePacket{ - ToUID: toUID, - Content: content, - }, - } +func NewSubmitMessagePacket(toUID string, subject []byte, body []byte) Packet { + return Packet{ + Flag: SubmitMsgPkt, + Body: SubmitMessagePacket{ + ToUID: toUID, + Subject: subject, + Body: body, + }, + } } -func NewSendUserCertPacket(uid string, key []byte) Packet { - return Packet{ - Flag: SendUserCertPkt, - Body: SendUserCertPacket{ - UID: uid, - Key: key, - }, - } +func NewSendUserCertPacket(uid string, certificate []byte) Packet { + return Packet{ + Flag: SendUserCertPkt, + Body: SendUserCertPacket{ + UID: uid, + Certificate: certificate, + }, + } +} +func NewServerMessageInfoPacket(num int, fromUID string, subject []byte, timestamp time.Time, last bool) Packet { + return Packet{ + Flag: ServerMsgInfoPkt, + Body: ServerMessageInfoPacket{ + Num: num, + FromUID: fromUID, + Subject: subject, + Timestamp: timestamp, + Last: last, + }, + } } -func NewServerMessagePacket(fromUID, toUID string, content []byte, timestamp time.Time) Packet { - return Packet{ - Flag: ServerMsgPkt, - Body: ServerMessagePacket{ - FromUID: fromUID, - ToUID: toUID, - Content: content, - Timestamp: timestamp, - }, - } +func NewServerMessagePacket(fromUID, toUID string, subject []byte, body []byte, timestamp time.Time, last bool) Packet { + return Packet{ + Flag: ServerMsgPkt, + Body: ServerMessagePacket{ + FromUID: fromUID, + ToUID: toUID, + Subject: subject, + Body: body, + Timestamp: timestamp, + }, + } +} + +func UnmarshalRequestUserCertPacket(data PacketBody) RequestUserCertPacket { + jsonData, err := json.Marshal(data) + if err != nil { + panic(fmt.Errorf("failed to marshal data: %v", err)) + } + var packet RequestUserCertPacket + if err := json.Unmarshal(jsonData, &packet); err != nil { + panic(fmt.Errorf("failed to unmarshal into RequestUserCertPacket: %v", err)) + } + return packet +} + +func UnmarshalRequestMsgsQueuePacket(data PacketBody) RequestMsgsQueuePacket { + jsonData, err := json.Marshal(data) + if err != nil { + panic(fmt.Errorf("failed to marshal data: %v", err)) + } + var packet RequestMsgsQueuePacket + if err := json.Unmarshal(jsonData, &packet); err != nil { + panic(fmt.Errorf("failed to unmarshal into RequestMsgsQueuePacket: %v", err)) + } + return packet +} + +func UnmarshalRequestMsgPacket(data PacketBody) RequestMsgPacket { + jsonData, err := json.Marshal(data) + if err != nil { + panic(fmt.Errorf("failed to marshal data: %v", err)) + } + var packet RequestMsgPacket + if err := json.Unmarshal(jsonData, &packet); err != nil { + panic(fmt.Errorf("failed to unmarshal into RequestMsgPacket: %v", err)) + } + return packet +} + +func UnmarshalSubmitMessagePacket(data PacketBody) SubmitMessagePacket { + jsonData, err := json.Marshal(data) + if err != nil { + panic(fmt.Errorf("failed to marshal data: %v", err)) + } + var packet SubmitMessagePacket + if err := json.Unmarshal(jsonData, &packet); err != nil { + panic(fmt.Errorf("failed to unmarshal into SubmitMessagePacket: %v", err)) + } + return packet +} + +func UnmarshalSendUserCertPacket(data PacketBody) SendUserCertPacket { + jsonData, err := json.Marshal(data) + if err != nil { + panic(fmt.Errorf("failed to marshal data: %v", err)) + } + var packet SendUserCertPacket + if err := json.Unmarshal(jsonData, &packet); err != nil { + panic(fmt.Errorf("failed to unmarshal into SendUserCertPacket: %v", err)) + } + return packet +} +func UnmarshalServerMessageInfoPacket(data PacketBody) ServerMessageInfoPacket { + jsonData, err := json.Marshal(data) + if err != nil { + panic(fmt.Errorf("failed to marshal data: %v", err)) + } + var packet ServerMessageInfoPacket + if err := json.Unmarshal(jsonData, &packet); err != nil { + panic(fmt.Errorf("failed to unmarshal into ServerMessageInfoPacket: %v", err)) + } + return packet +} + +func UnmarshalServerMessagePacket(data PacketBody) ServerMessagePacket { + jsonData, err := json.Marshal(data) + if err != nil { + panic(fmt.Errorf("failed to marshal data: %v", err)) + } + var packet ServerMessagePacket + if err := json.Unmarshal(jsonData, &packet); err != nil { + panic(fmt.Errorf("failed to unmarshal into ServerMessagePacket: %v", err)) + } + return packet } diff --git a/Projs/PD1/internal/server/datastore.go b/Projs/PD1/internal/server/datastore.go index 7120ea9..75e54e9 100644 --- a/Projs/PD1/internal/server/datastore.go +++ b/Projs/PD1/internal/server/datastore.go @@ -2,7 +2,9 @@ package server import ( "PD1/internal/protocol" + "crypto/x509" "database/sql" + "fmt" "log" "time" @@ -18,7 +20,9 @@ func OpenDB() DataStore { if err != nil { log.Fatalln("Error opening db file") } - return DataStore{db: db} + ds := DataStore{db: db} + ds.CreateTables() + return ds } func (ds DataStore) CreateTables() error { @@ -28,6 +32,7 @@ func (ds DataStore) CreateTables() error { userCert BLOB )`) if err != nil { + fmt.Println("Error creating users table", err) return err } @@ -36,23 +41,26 @@ func (ds DataStore) CreateTables() error { fromUID TEXT, toUID TEXT, timestamp TIMESTAMP, - content BLOB, + subject BLOB, + body BLOB, + status INT CHECK (status IN (0,1)), PRIMARY KEY (toUID, fromUID, timestamp), FOREIGN KEY(fromUID) REFERENCES users(UID), FOREIGN KEY(toUID) REFERENCES users(UID) )`) if err != nil { + fmt.Println("Error creating messages table", err) return err } return nil } -func (ds DataStore) GetMessage(toUID string, position int) protocol.ServerMessagePacket { +func (ds DataStore) GetMessage(toUID string, position int) protocol.Packet { var serverMessage protocol.ServerMessagePacket query := ` - SELECT fromUID, toUID, content, timestamp + SELECT fromUID, toUID, subject, body, timestamp FROM messages WHERE toUID = ? AND status = 0 @@ -61,15 +69,16 @@ func (ds DataStore) GetMessage(toUID string, position int) protocol.ServerMessag ` // Execute the query row := ds.db.QueryRow(query, toUID, position) - err := row.Scan(&serverMessage.FromUID, &serverMessage.ToUID, &serverMessage.Content, &serverMessage.Timestamp) + err := row.Scan(&serverMessage.FromUID, &serverMessage.ToUID, &serverMessage.Subject, &serverMessage.Body, &serverMessage.Timestamp) if err != nil { - log.Panicln("Could not map DB query to ServerMessage") + log.Printf("Error getting the message in position %v from UID %v: %v", position, toUID, err) } - return serverMessage + + return protocol.NewServerMessagePacket(serverMessage.FromUID, serverMessage.ToUID, serverMessage.Subject, serverMessage.Body, serverMessage.Timestamp, true) } -func (ds DataStore) MarkMessageInQueueAsRead(toUID string, position int) error { +func (ds DataStore) MarkMessageInQueueAsRead(toUID string, position int) { query := ` UPDATE messages SET status = 1 @@ -81,61 +90,90 @@ func (ds DataStore) MarkMessageInQueueAsRead(toUID string, position int) error { // Execute the SQL statement _, err := ds.db.Exec(query, toUID, position) if err != nil { - return err + log.Printf("Error marking the message in position %v from UID %v as read: %v", position, toUID, err) } - - return nil } -func (ds DataStore) GetAllMessages(toUID string) []protocol.Packet { - var messagePackets []protocol.Packet +func (ds DataStore) GetUnreadMessagesInfoQueue(toUID string) []protocol.Packet { + var messageInfoPackets []protocol.Packet // Query to retrieve all messages from the user's queue query := ` - SELECT fromUID, toUID, content, timestamp - FROM messages - WHERE toUID = ? - AND status = 0 - ORDER BY timestamp + SELECT + fromUID, + toUID, + timestamp, + queue_position, + subject, + status + FROM ( + SELECT + fromUID, + toUID, + timestamp, + ROW_NUMBER() OVER (PARTITION BY toUID ORDER BY timestamp) - 1 AS queue_position, + subject, + status + FROM + messages + WHERE + toUID = ? + ) AS ranked_messages + WHERE + status = 0 + ORDER BY + timestamp; ` // Execute the query rows, err := ds.db.Query(query, toUID) if err != nil { - log.Panicln("Failed to execute query:", err) + log.Printf("Error getting all messages for UID %v: %v", toUID, err) } defer rows.Close() // Iterate through the result set and scan each row into a ServerMessage struct - for rows.Next() { + //First row + if !rows.Next() { + return []protocol.Packet{} + } + for { var fromUID string - var toUID string - var content []byte + var subject []byte var timestamp time.Time - if err := rows.Scan(&fromUID, &toUID, &content, ×tamp); err != nil { - log.Panicln("Failed to scan row:", err) + var queuePosition, status int + if err := rows.Scan(&fromUID, &toUID, ×tamp, &queuePosition, &subject, &status); err != nil { + panic(err) + } + var message protocol.Packet + hasNext := rows.Next() + if !hasNext { + message = protocol.NewServerMessageInfoPacket(queuePosition, fromUID, subject, timestamp, true) + messageInfoPackets = append(messageInfoPackets, message) + break + } else { + message = protocol.NewServerMessageInfoPacket(queuePosition, fromUID, subject, timestamp, false) + messageInfoPackets = append(messageInfoPackets, message) } - message := protocol.NewServerMessagePacket(fromUID, toUID, content, timestamp) - messagePackets = append(messagePackets, message) } if err := rows.Err(); err != nil { - log.Panicln("Error when getting user's messages") + log.Printf("Error when getting messages for UID %v: %v", toUID, err) } - return messagePackets + return messageInfoPackets } -func (ds DataStore) AddMessageToQueue(uid string, message protocol.SubmitMessagePacket) { +func (ds DataStore) AddMessageToQueue(fromUID string, message protocol.SubmitMessagePacket) { query := ` - INSERT INTO messages (fromUID, toUID, content, timestamp, status) - VALUES (?, ?, ?, ?, 0) + INSERT INTO messages (fromUID, toUID, subject, body, timestamp, status) + VALUES (?, ?, ?, ?, ?, 0) ` // Execute the SQL statement currentTime := time.Now() - _, err := ds.db.Exec(query, uid, message.ToUID, message.Content, currentTime) + _, err := ds.db.Exec(query, fromUID, message.ToUID, message.Subject, message.Body, currentTime) if err != nil { - log.Panicln("Error adding message to database") + log.Printf("Error adding message to UID %v: %v", fromUID, err) } } @@ -147,29 +185,53 @@ func (ds DataStore) GetUserCertificate(uid string) protocol.Packet { ` // Execute the SQL query - var userCert []byte - err := ds.db.QueryRow(query, uid).Scan(&userCert) - if err != nil { - log.Panicln("Error getting user certificate from the database") + var userCertBytes []byte + err := ds.db.QueryRow(query, uid).Scan(&userCertBytes) + if err == sql.ErrNoRows { + log.Panicf("No certificate for UID %v found in the database", uid) } - return protocol.NewSendUserCertPacket(uid, userCert) + //userCert,err := x509.ParseCertificate(userCertBytes) + //if err!=nil { + // log.Panicf("Error parsing certificate for UID %v",uid) + //} + return protocol.NewSendUserCertPacket(uid, userCertBytes) } -func userExists(db *sql.DB, uid string) bool { - // Prepare the SQL statement for checking if a user exists - query := ` +func (ds DataStore) userExists(uid string) bool { + // Prepare the SQL statement for checking if a user exists + query := ` SELECT COUNT(*) FROM users WHERE UID = ? ` - var count int - // Execute the SQL query - err := db.QueryRow(query, uid).Scan(&count) - if err != nil { - log.Panicln("Error checking if user exists") - } - - // If count is greater than 0, the user exists - return count > 0 + var count int + // Execute the SQL query + err := ds.db.QueryRow(query, uid).Scan(&count) + if err == sql.ErrNoRows { + log.Printf("User with UID %v does not exist", uid) + return false + } else { + return true + } +} + +func (ds DataStore) storeUserCertIfNotExists(uid string, cert x509.Certificate) { + // Check if the user already exists + if ds.userExists(uid) { + log.Printf("User certificate for UID %s already exists.\n", uid) + return + } + + // Insert the user certificate + insertQuery := ` + INSERT INTO users (UID, userCert) + VALUES (?, ?) + ` + _, err := ds.db.Exec(insertQuery, uid, cert.Raw) + if err != nil { + log.Printf("Error storing user certificate for UID %s: %v\n", uid, err) + return + } + log.Printf("User certificate for UID %s stored successfully.\n", uid) } diff --git a/Projs/PD1/internal/server/server.go b/Projs/PD1/internal/server/server.go index c963342..ba22925 100644 --- a/Projs/PD1/internal/server/server.go +++ b/Projs/PD1/internal/server/server.go @@ -16,28 +16,44 @@ func clientHandler(connection networking.Connection[protocol.Packet], dataStore oidMap := cryptoUtils.ExtractAllOIDValues(clientCert) //Get the UID of this user UID := oidMap["2.5.4.65"] - if UID=="" { + if UID == "" { panic("User certificate does not specify it's PSEUDONYM") } - + dataStore.storeUserCertIfNotExists(UID, *clientCert) +F: for { - var pac protocol.Packet - connection.Receive(&pac) + pac, active := connection.Receive() + if !active { + break F + } switch pac.Flag { case protocol.ReqUserCertPkt: - fmt.Printf("Type of pac.Body: %T\n", pac.Body) - UserCertPacket, ok := (pac.Body).(protocol.RequestUserCertPacket) - if !ok { - panic("Could not cast packet to it's type") + reqUserCert := protocol.UnmarshalRequestUserCertPacket(pac.Body) + userCertPacket := dataStore.GetUserCertificate(reqUserCert.UID) + if active := connection.Send(userCertPacket); !active { + break F + } + case protocol.ReqMsgsQueue: + _ = protocol.UnmarshalRequestMsgsQueuePacket(pac.Body) + messages := dataStore.GetUnreadMessagesInfoQueue(UID) + fmt.Printf("Number of unread messages by user %v is %v\n",UID,len(messages)) + for _, message := range messages { + if !connection.Send(message) { + break + } } - userCertPacket := dataStore.GetUserCertificate(UserCertPacket.UID) - connection.Send(userCertPacket) - case protocol.ReqAllMsgPkt: - fmt.Println("ReqAllMsg") case protocol.ReqMsgPkt: - fmt.Println("ReqMsg") + reqMsg := protocol.UnmarshalRequestMsgPacket(pac.Body) + message := dataStore.GetMessage(UID, reqMsg.Num) + if active := connection.Send(message); !active { + break F + } case protocol.SubmitMsgPkt: - fmt.Println("SubmitMsg") + submitMsg := protocol.UnmarshalSubmitMessagePacket(pac.Body) + if submitMsg.ToUID != UID && dataStore.userExists(submitMsg.ToUID) { + dataStore.AddMessageToQueue(UID, submitMsg) + } + } } diff --git a/Projs/PD1/internal/utils/cryptoUtils/cryptoUtils.go b/Projs/PD1/internal/utils/cryptoUtils/cryptoUtils.go index 3c5dd1c..49bfd06 100644 --- a/Projs/PD1/internal/utils/cryptoUtils/cryptoUtils.go +++ b/Projs/PD1/internal/utils/cryptoUtils/cryptoUtils.go @@ -178,7 +178,6 @@ func (k KeyStore) EncryptMessageContent(receiverCert *x509.Certificate, content } func (k KeyStore) DecryptMessageContent(senderCert *x509.Certificate, cipherContent []byte) []byte { - return nil } diff --git a/Projs/PD1/internal/utils/networking/connection.go b/Projs/PD1/internal/utils/networking/connection.go index 28a5997..1e40f9b 100644 --- a/Projs/PD1/internal/utils/networking/connection.go +++ b/Projs/PD1/internal/utils/networking/connection.go @@ -4,6 +4,8 @@ import ( "crypto/tls" "crypto/x509" "encoding/json" + "io" + "log" ) type Connection[T any] struct { @@ -20,16 +22,33 @@ func NewConnection[T any](netConn *tls.Conn) Connection[T] { } } -func (c Connection[T]) Send(obj T) { - if err := c.encoder.Encode(&obj); err != nil { - panic("Failed encoding data or sending it to connection") - } +func (c Connection[T]) Send(obj T) bool { + if err := c.encoder.Encode(&obj); err!=nil { + if err == io.EOF { + log.Println("Connection closed by peer") + //Return false as connection not active + return false + } else { + log.Panic(err) + } + } + //Return true as connection active + return true } -func (c Connection[T]) Receive(objPtr *T) { - if err := c.decoder.Decode(objPtr); err != nil { - panic("Failed decoding data or reading it from connection") +func (c Connection[T]) Receive() (*T, bool) { + var obj T + if err := c.decoder.Decode(&obj); err != nil { + if err == io.EOF { + log.Println("Connection closed by peer") + //Return false as connection not active + return nil,false + } else { + log.Panic(err) + } } + //Return true as connection active + return &obj, true } func (c Connection[T]) GetPeerCertificate() *x509.Certificate { diff --git a/Projs/PD1/internal/utils/networking/server.go b/Projs/PD1/internal/utils/networking/server.go index 60e9c70..49f5948 100644 --- a/Projs/PD1/internal/utils/networking/server.go +++ b/Projs/PD1/internal/utils/networking/server.go @@ -43,7 +43,6 @@ func (s *Server[T]) ListenLoop() { state := tlsConn.ConnectionState() if len(state.PeerCertificates) == 0 { - fmt.Println(state.PeerCertificates) log.Panicln("Client did not provide a certificate") } conn := NewConnection[T](tlsConn) diff --git a/Projs/PD1/server.db b/Projs/PD1/server.db new file mode 100644 index 0000000000000000000000000000000000000000..649678698dfe3251187c804538aa52326f6c92f8 GIT binary patch literal 20480 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 Date: Sat, 20 Apr 2024 00:55:16 +0100 Subject: [PATCH 3/8] [PD1] Logic all done? --- Projs/PD1/internal/client/client.go | 51 +++++++++++-------------- Projs/PD1/internal/server/datastore.go | 13 ++++--- Projs/PD1/internal/server/server.go | 1 + Projs/PD1/server.db | Bin 20480 -> 32768 bytes 4 files changed, 31 insertions(+), 34 deletions(-) diff --git a/Projs/PD1/internal/client/client.go b/Projs/PD1/internal/client/client.go index 3f8487e..3afbda7 100644 --- a/Projs/PD1/internal/client/client.go +++ b/Projs/PD1/internal/client/client.go @@ -6,8 +6,9 @@ import ( "PD1/internal/utils/networking" "crypto/x509" "flag" - "fmt" + "log" "sort" + "strconv" ) func Run() { @@ -76,40 +77,33 @@ func Run() { showMessagesInfo(clientMessages) - //case "getall": - // cl := networking.NewClient[protocol.Packet](&clientKeyStore) - // defer cl.Connection.Conn.Close() - - // requestAllMsgPacket := protocol.NewRequestAllMsgPacket() - // if !cl.Connection.Send(requestAllMsgPacket) { - // return - // } - // serverMessagePackets,certificates := getManyMessages(cl) - // var clientMessages []ClientMessage - // for _, message := range serverMessagePackets { - // senderCert, ok := certificates[message.FromUID] - // if ok { - // decryptedContentBytes := clientKeyStore.DecryptMessageContent(senderCert, message.Content) - // content := UnmarshalContent(decryptedContentBytes) - // clientMessage := newClientMessage(message.FromUID, message.ToUID, content, message.Timestamp) - // clientMessages = append(clientMessages, clientMessage) - // } - // } - // //Sort the messages - // sort.Slice(clientMessages, func(i, j int) bool { - // return clientMessages[i].Timestamp.After(clientMessages[j].Timestamp) - // }) - - // showMessages(clientMessages) - case "getmsg": if flag.NArg() < 2 { panic("Insufficient arguments for 'getmsg' command. Usage: getmsg ") } - //num := flag.Arg(1) + numString := flag.Arg(1) cl := networking.NewClient[protocol.Packet](&clientKeyStore) defer cl.Connection.Conn.Close() + num,err :=strconv.Atoi(numString) + if err!=nil{ + log.Panicln("NUM argument provided is not a number") + } + packet := protocol.NewRequestMsgPacket(num) + cl.Connection.Send(packet) + receivedMsgPacket,active := cl.Connection.Receive() + if !active{ + return + } + serverMessagePacket := protocol.UnmarshalServerMessagePacket(receivedMsgPacket.Body) + senderCert := getUserCert(cl, serverMessagePacket.FromUID) + decryptedSubjectBytes := clientKeyStore.DecryptMessageContent(senderCert, serverMessagePacket.Subject) + decryptedBodyBytes := clientKeyStore.DecryptMessageContent(senderCert, serverMessagePacket.Body) + subject := Unmarshal(decryptedSubjectBytes) + body := Unmarshal(decryptedBodyBytes) + message := newClientMessage(serverMessagePacket.FromUID, serverMessagePacket.ToUID, subject, body, serverMessagePacket.Timestamp) + showMessage(message) + case "help": showHelp() @@ -163,7 +157,6 @@ func getManyMessagesInfo(cl networking.Client[protocol.Packet]) ([]protocol.Serv //Get senders' certificates for senderUID := range senderSet { senderCert := getUserCert(cl, senderUID) - fmt.Println("Got a User cert") certificatesMap[senderUID] = senderCert } return serverMessageInfoPackets, certificatesMap diff --git a/Projs/PD1/internal/server/datastore.go b/Projs/PD1/internal/server/datastore.go index 75e54e9..9229077 100644 --- a/Projs/PD1/internal/server/datastore.go +++ b/Projs/PD1/internal/server/datastore.go @@ -63,7 +63,6 @@ func (ds DataStore) GetMessage(toUID string, position int) protocol.Packet { SELECT fromUID, toUID, subject, body, timestamp FROM messages WHERE toUID = ? - AND status = 0 ORDER BY timestamp LIMIT 1 OFFSET ? ` @@ -81,10 +80,14 @@ func (ds DataStore) GetMessage(toUID string, position int) protocol.Packet { func (ds DataStore) MarkMessageInQueueAsRead(toUID string, position int) { query := ` UPDATE messages - SET status = 1 - WHERE toUID = ? AND status = 0 - ORDER BY timestamp - LIMIT 1 OFFSET ? + SET status = 1 + WHERE (fromUID,toUID,timestamp) = ( + SELECT fromUID,toUID,timestamp + FROM messages + WHERE toUID = ? + ORDER BY timestamp + LIMIT 1 OFFSET ? + ) ` // Execute the SQL statement diff --git a/Projs/PD1/internal/server/server.go b/Projs/PD1/internal/server/server.go index ba22925..1f2863a 100644 --- a/Projs/PD1/internal/server/server.go +++ b/Projs/PD1/internal/server/server.go @@ -48,6 +48,7 @@ F: if active := connection.Send(message); !active { break F } + dataStore.MarkMessageInQueueAsRead(UID, reqMsg.Num) case protocol.SubmitMsgPkt: submitMsg := protocol.UnmarshalSubmitMessagePacket(pac.Body) if submitMsg.ToUID != UID && dataStore.userExists(submitMsg.ToUID) { diff --git a/Projs/PD1/server.db b/Projs/PD1/server.db index 649678698dfe3251187c804538aa52326f6c92f8..b5ed3b148273dff98bb8afe342732e7866c2a5a9 100644 GIT binary patch delta 4612 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 B3_t(? From f3cf9cfc40d2a42a431b1b2703df08d0f92e3a6a Mon Sep 17 00:00:00 2001 From: afonso Date: Sat, 20 Apr 2024 17:16:52 +0100 Subject: [PATCH 4/8] [PD1] Cleaned up protocol,database and receiving multiple messageInfos --- Projs/PD1/internal/client/client.go | 164 +++++++++-------- Projs/PD1/internal/client/interface.go | 65 ++++++- Projs/PD1/internal/protocol/protocol.go | 227 +++++++++++++++--------- Projs/PD1/internal/server/datastore.go | 92 +++++----- Projs/PD1/internal/server/server.go | 30 ++-- Projs/PD1/server.db | Bin 32768 -> 40960 bytes 6 files changed, 347 insertions(+), 231 deletions(-) diff --git a/Projs/PD1/internal/client/client.go b/Projs/PD1/internal/client/client.go index 3afbda7..3769cb2 100644 --- a/Projs/PD1/internal/client/client.go +++ b/Projs/PD1/internal/client/client.go @@ -30,52 +30,46 @@ func Run() { panic("Insufficient arguments for 'send' command. Usage: send ") } uid := flag.Arg(1) - subject := flag.Arg(2) - messageBody := readMessageBody() + plainSubject := flag.Arg(2) + plainBody := readStdin("Enter message content (limited to 1000 bytes):") //Turn content to bytes - marshaledSubject := Marshal(subject) - marshaledBody := Marshal(messageBody) + plainSubjectBytes := Marshal(plainSubject) + plainBodyBytes := Marshal(plainBody) cl := networking.NewClient[protocol.Packet](&clientKeyStore) defer cl.Connection.Conn.Close() - uidCert := getUserCert(cl, uid) - if uidCert == nil { + receiverCert := getUserCert(cl, uid) + if receiverCert == nil { return } - encryptedSubject := clientKeyStore.EncryptMessageContent(uidCert, marshaledSubject) - encryptedBody := clientKeyStore.EncryptMessageContent(uidCert, marshaledBody) - submitMessage := protocol.NewSubmitMessagePacket(uid, encryptedSubject, encryptedBody) - if !cl.Connection.Send(submitMessage) { + subject := clientKeyStore.EncryptMessageContent(receiverCert, plainSubjectBytes) + body := clientKeyStore.EncryptMessageContent(receiverCert, plainBodyBytes) + sendMsgPacket := protocol.NewSendMsgPacket(uid, subject, body) + if !cl.Connection.Send(sendMsgPacket) { return } cl.Connection.Conn.Close() case "askqueue": - cl := networking.NewClient[protocol.Packet](&clientKeyStore) - defer cl.Connection.Conn.Close() - - requestUnreadMsgsQueuePacket := protocol.NewRequestUnreadMsgsQueuePacket() - if !cl.Connection.Send(requestUnreadMsgsQueuePacket) { - return - } - serverMessagePackets, certificates := getManyMessagesInfo(cl) - var clientMessages []ClientMessageInfo - for _, message := range serverMessagePackets { - senderCert, ok := certificates[message.FromUID] - if ok { - decryptedSubjectBytes := clientKeyStore.DecryptMessageContent(senderCert, message.Subject) - subject := Unmarshal(decryptedSubjectBytes) - clientMessage := newClientMessageInfo(message.Num, message.FromUID, subject, message.Timestamp) - clientMessages = append(clientMessages, clientMessage) + pageInput := flag.Arg(1) + page := 1 + if pageInput != "" { + if val, err := strconv.Atoi(pageInput); err == nil { + page = max(1, val) + } + } + pageSizeInput := flag.Arg(2) + pageSize := 5 + if pageSizeInput != "" { + if val, err := strconv.Atoi(pageSizeInput); err == nil { + pageSize = max(1, val) } } - //Sort the messages - sort.Slice(clientMessages, func(i, j int) bool { - return clientMessages[i].Num > clientMessages[j].Num - }) - showMessagesInfo(clientMessages) + cl := networking.NewClient[protocol.Packet](&clientKeyStore) + defer cl.Connection.Conn.Close() + askQueue(cl,clientKeyStore, page, pageSize) case "getmsg": if flag.NArg() < 2 { @@ -84,26 +78,26 @@ func Run() { numString := flag.Arg(1) cl := networking.NewClient[protocol.Packet](&clientKeyStore) defer cl.Connection.Conn.Close() - num,err :=strconv.Atoi(numString) - if err!=nil{ - log.Panicln("NUM argument provided is not a number") - } - packet := protocol.NewRequestMsgPacket(num) - cl.Connection.Send(packet) + num, err := strconv.Atoi(numString) + if err != nil { + log.Panicln("NUM argument provided is not a number") + } + packet := protocol.NewGetMsgPacket(num) + cl.Connection.Send(packet) + + receivedMsgPacket, active := cl.Connection.Receive() + if !active { + return + } + answerGetMsg := protocol.UnmarshalAnswerGetMsg(receivedMsgPacket.Body) + senderCert := getUserCert(cl, answerGetMsg.FromUID) + decSubjectBytes := clientKeyStore.DecryptMessageContent(senderCert, answerGetMsg.Subject) + decBodyBytes := clientKeyStore.DecryptMessageContent(senderCert, answerGetMsg.Body) + subject := Unmarshal(decSubjectBytes) + body := Unmarshal(decBodyBytes) + message := newClientMessage(answerGetMsg.FromUID, answerGetMsg.ToUID, subject, body, answerGetMsg.Timestamp) + showMessage(message) - receivedMsgPacket,active := cl.Connection.Receive() - if !active{ - return - } - serverMessagePacket := protocol.UnmarshalServerMessagePacket(receivedMsgPacket.Body) - senderCert := getUserCert(cl, serverMessagePacket.FromUID) - decryptedSubjectBytes := clientKeyStore.DecryptMessageContent(senderCert, serverMessagePacket.Subject) - decryptedBodyBytes := clientKeyStore.DecryptMessageContent(senderCert, serverMessagePacket.Body) - subject := Unmarshal(decryptedSubjectBytes) - body := Unmarshal(decryptedBodyBytes) - message := newClientMessage(serverMessagePacket.FromUID, serverMessagePacket.ToUID, subject, body, serverMessagePacket.Timestamp) - showMessage(message) - case "help": showHelp() @@ -114,43 +108,33 @@ func Run() { } func getUserCert(cl networking.Client[protocol.Packet], uid string) *x509.Certificate { - certRequestPacket := protocol.NewRequestUserCertPacket(uid) - if !cl.Connection.Send(certRequestPacket) { + getUserCertPacket := protocol.NewGetUserCertPacket(uid) + if !cl.Connection.Send(getUserCertPacket) { return nil } - var certPacket *protocol.Packet - certPacket, active := cl.Connection.Receive() + var answerGetUserCertPacket *protocol.Packet + answerGetUserCertPacket, active := cl.Connection.Receive() if !active { return nil } - uidCertInBytes := protocol.UnmarshalSendUserCertPacket(certPacket.Body) - uidCert, err := x509.ParseCertificate(uidCertInBytes.Certificate) + answerGetUserCert := protocol.UnmarshalAnswerGetUserCert(answerGetUserCertPacket.Body) + userCert, err := x509.ParseCertificate(answerGetUserCert.Certificate) if err != nil { return nil } - return uidCert + return userCert } -func getManyMessagesInfo(cl networking.Client[protocol.Packet]) ([]protocol.ServerMessageInfoPacket, map[string]*x509.Certificate) { - //Create the slice to hold the incoming messages before decrypting - //Create the map to hold the sender certificates - //Create sync mutexes - serverMessageInfoPackets := []protocol.ServerMessageInfoPacket{} - //Run while message isn't the last one - msg := protocol.ServerMessageInfoPacket{} - for !msg.Last { - sendMsgPacket, active := cl.Connection.Receive() - if !active { - return nil, nil - } - msg = protocol.UnmarshalServerMessageInfoPacket(sendMsgPacket.Body) - //Lock and append - serverMessageInfoPackets = append(serverMessageInfoPackets, msg) +func getManyMessagesInfo(cl networking.Client[protocol.Packet]) (protocol.AnswerGetUnreadMsgsInfo, map[string]*x509.Certificate) { + answerGetUnreadMsgsInfoPacket, active := cl.Connection.Receive() + if !active { + return protocol.NewAnswerGetUnreadMsgsInfo(0, 0, nil), nil } + answerGetUnreadMsgsInfo := protocol.UnmarshalAnswerGetUnreadMsgsInfo(answerGetUnreadMsgsInfoPacket.Body) //Create Set of needed certificates senderSet := map[string]bool{} - for _, messageInfo := range serverMessageInfoPackets { + for _, messageInfo := range answerGetUnreadMsgsInfo.MessagesInfo { senderSet[messageInfo.FromUID] = true } certificatesMap := map[string]*x509.Certificate{} @@ -159,5 +143,37 @@ func getManyMessagesInfo(cl networking.Client[protocol.Packet]) ([]protocol.Serv senderCert := getUserCert(cl, senderUID) certificatesMap[senderUID] = senderCert } - return serverMessageInfoPackets, certificatesMap + return answerGetUnreadMsgsInfo, certificatesMap +} + +func askQueue(cl networking.Client[protocol.Packet],clientKeyStore cryptoUtils.KeyStore, page int, pageSize int) { + requestUnreadMsgsQueuePacket := protocol.NewGetUnreadMsgsInfoPacket(page, pageSize) + if !cl.Connection.Send(requestUnreadMsgsQueuePacket) { + return + } + unreadMsgsInfo, certificates := getManyMessagesInfo(cl) + var clientMessages []ClientMessageInfo + for _, message := range unreadMsgsInfo.MessagesInfo { + senderCert, ok := certificates[message.FromUID] + if ok { + decryptedSubjectBytes := clientKeyStore.DecryptMessageContent(senderCert, message.Subject) + subject := Unmarshal(decryptedSubjectBytes) + clientMessage := newClientMessageInfo(message.Num, message.FromUID, subject, message.Timestamp) + clientMessages = append(clientMessages, clientMessage) + } + } + //Sort the messages + sort.Slice(clientMessages, func(i, j int) bool { + return clientMessages[i].Num > clientMessages[j].Num + }) + + action := showMessagesInfo(unreadMsgsInfo.Page, unreadMsgsInfo.NumPages, clientMessages) + switch action { + case -1: + askQueue(cl, clientKeyStore , max(1,unreadMsgsInfo.Page-1) , pageSize) + case 0: + return + case 1: + askQueue(cl, clientKeyStore , max(1,unreadMsgsInfo.Page+1) , pageSize) + } } diff --git a/Projs/PD1/internal/client/interface.go b/Projs/PD1/internal/client/interface.go index 8d49bb6..82f2d8a 100644 --- a/Projs/PD1/internal/client/interface.go +++ b/Projs/PD1/internal/client/interface.go @@ -4,10 +4,11 @@ import ( "bufio" "fmt" "os" + "strings" ) -func readMessageBody() string { - fmt.Println("Enter message content (limited to 1000 bytes):") +func readStdin(message string) string { + fmt.Println(message) scanner := bufio.NewScanner(os.Stdin) scanner.Scan() // FIX: make sure this doesnt die @@ -36,15 +37,63 @@ func showHelp() { fmt.Println("help: Imprime instruções de uso do programa.") } -func showMessagesInfo(messages []ClientMessageInfo) { +func showMessagesInfo(page int, numPages int, messages []ClientMessageInfo) int { + if messages == nil { + fmt.Println("No unread messages in the queue") + return 0 + } for _, message := range messages { fmt.Printf("%v:%v:%v:%v\n", message.Num, message.FromUID, message.Timestamp, message.Subject) } + fmt.Printf("Page %v/%v\n",page,numPages) + return messagesInfoPageNavigation(page, numPages) } -func showMessage(message ClientMessage) { - fmt.Printf("From:%v\n", message.FromUID) - fmt.Printf("To:%v\n", message.ToUID) - fmt.Printf("Subject:%v\n", message.Subject) - fmt.Printf("Body:%v\n", message.Body) +func messagesInfoPageNavigation(page int, numPages int) int { + var action string + + switch page { + case 1: + if page == numPages { + action = readStdin("Actions: quit") + } else { + action = readStdin("Actions: quit/next") + } + case numPages: + action = readStdin("Actions: prev/quit") + default: + action = readStdin("prev/quit/next") + } + + switch strings.ToLower(action) { + case "prev": + if page == 1 { + fmt.Println("Unavailable action: Already in first page") + messagesInfoPageNavigation(page, numPages) + } else { + return -1 + } + case "quit": + return 0 + case "next": + if page == numPages { + fmt.Println("Unavailable action: Already in last page") + messagesInfoPageNavigation(page, numPages) + } else { + return 1 + } + default: + fmt.Println("Unknown action") + messagesInfoPageNavigation(page, numPages) + } + return 0 } + + +func showMessage(message ClientMessage) { + fmt.Printf("From: %s\n", message.FromUID) + fmt.Printf("To: %s\n", message.ToUID) + fmt.Printf("Subject: %s\n", message.Subject) + fmt.Printf("Body: %s\n", message.Body) +} + diff --git a/Projs/PD1/internal/protocol/protocol.go b/Projs/PD1/internal/protocol/protocol.go index 6aeecec..680c2b5 100644 --- a/Projs/PD1/internal/protocol/protocol.go +++ b/Projs/PD1/internal/protocol/protocol.go @@ -9,46 +9,67 @@ import ( type PacketType int const ( - ReqUserCertPkt PacketType = iota - ReqMsgsQueue - ReqMsgPkt - SubmitMsgPkt - SendUserCertPkt - ServerMsgInfoPkt - ServerMsgPkt + // Client requests user certificate + FlagGetUserCert PacketType = iota + + // Client requests unread message info + FlagGetUnreadMsgsInfo + + // Client requests a message from the queue + FlagGetMsg + + // Client sends a message + FlagSendMsg + + // Server sends user certificate + FlagAnswerGetUserCert + + // Server sends list of unread messages + FlagAnswerGetUnreadMsgsInfo + + // Server sends requested message + FlagAnswerGetMsg ) type ( - RequestUserCertPacket struct { + GetUserCert struct { UID string `json:"uid"` } - RequestMsgsQueuePacket struct { + GetUnreadMsgsInfo struct { + Page int `json:"page"` + PageSize int `json:"pageSize"` } - RequestMsgPacket struct { + GetMsg struct { Num int `json:"num"` } - SubmitMessagePacket struct { + SendMsg struct { ToUID string `json:"to_uid"` Subject []byte `json:"subject"` Body []byte `json:"body"` } - SendUserCertPacket struct { + AnswerGetUserCert struct { UID string `json:"uid"` Certificate []byte `json:"certificate"` } - ServerMessageInfoPacket struct { + AnswerGetUnreadMsgsInfo struct { + Page int `json:"page"` + NumPages int `json:"num_pages"` + MessagesInfo []MsgInfo `json:"messages_info"` + } + + MsgInfo struct { Num int `json:"num"` FromUID string `json:"from_uid"` Subject []byte `json:"subject"` Timestamp time.Time `json:"timestamp"` - Last bool `json:"last"` } - ServerMessagePacket struct { + + AnswerGetMsg struct { FromUID string `json:"from_uid"` ToUID string `json:"to_uid"` Subject []byte `json:"subject"` @@ -64,156 +85,188 @@ type Packet struct { Body PacketBody `json:"body"` } -func NewRequestUserCertPacket(UID string) Packet { +func NewPacket(fl PacketType, body PacketBody) Packet { return Packet{ - Flag: ReqUserCertPkt, - Body: RequestUserCertPacket{ - UID: UID, - }, + Flag: fl, + Body: body, + } + +} + +func NewGetUserCert(UID string) GetUserCert { + return GetUserCert{ + UID: UID, } } -func NewRequestUnreadMsgsQueuePacket() Packet { - return Packet{ - Flag: ReqMsgsQueue, - Body: RequestMsgsQueuePacket{}, +func NewGetUnreadMsgsInfo(page int, pageSize int) GetUnreadMsgsInfo { + return GetUnreadMsgsInfo{ + Page: page, + PageSize: pageSize} +} + +func NewGetMsg(num int) GetMsg { + return GetMsg{ + Num: num, } } -func NewRequestMsgPacket(num int) Packet { - return Packet{ - Flag: ReqMsgPkt, - Body: RequestMsgPacket{ - Num: num, - }, +func NewSendMsg(toUID string, subject []byte, body []byte) SendMsg { + return SendMsg{ + ToUID: toUID, + Subject: subject, + Body: body, } } -func NewSubmitMessagePacket(toUID string, subject []byte, body []byte) Packet { - return Packet{ - Flag: SubmitMsgPkt, - Body: SubmitMessagePacket{ - ToUID: toUID, - Subject: subject, - Body: body, - }, +func NewAnswerGetUserCert(uid string, certificate []byte) AnswerGetUserCert { + return AnswerGetUserCert{ + UID: uid, + Certificate: certificate, } } -func NewSendUserCertPacket(uid string, certificate []byte) Packet { - return Packet{ - Flag: SendUserCertPkt, - Body: SendUserCertPacket{ - UID: uid, - Certificate: certificate, - }, - } +func NewAnswerGetUnreadMsgsInfo(page int, numPages int, messagesInfo []MsgInfo) AnswerGetUnreadMsgsInfo { + return AnswerGetUnreadMsgsInfo{Page:page,NumPages:numPages,MessagesInfo: messagesInfo} } -func NewServerMessageInfoPacket(num int, fromUID string, subject []byte, timestamp time.Time, last bool) Packet { - return Packet{ - Flag: ServerMsgInfoPkt, - Body: ServerMessageInfoPacket{ - Num: num, - FromUID: fromUID, - Subject: subject, - Timestamp: timestamp, - Last: last, - }, +func NewMsgInfo(num int, fromUID string, subject []byte, timestamp time.Time) MsgInfo { + return MsgInfo{ + Num: num, + FromUID: fromUID, + Subject: subject, + Timestamp: timestamp, } } -func NewServerMessagePacket(fromUID, toUID string, subject []byte, body []byte, timestamp time.Time, last bool) Packet { - return Packet{ - Flag: ServerMsgPkt, - Body: ServerMessagePacket{ - FromUID: fromUID, - ToUID: toUID, - Subject: subject, - Body: body, - Timestamp: timestamp, - }, +func NewAnswerGetMsg(fromUID, toUID string, subject []byte, body []byte, timestamp time.Time, last bool) AnswerGetMsg { + return AnswerGetMsg{ + FromUID: fromUID, + ToUID: toUID, + Subject: subject, + Body: body, + Timestamp: timestamp, } } -func UnmarshalRequestUserCertPacket(data PacketBody) RequestUserCertPacket { +func NewGetUserCertPacket(UID string) Packet { + return NewPacket(FlagGetUserCert, NewGetUserCert(UID)) +} + +func NewGetUnreadMsgsInfoPacket(page int, pageSize int) Packet { + return NewPacket(FlagGetUnreadMsgsInfo, NewGetUnreadMsgsInfo(page, pageSize)) +} + +func NewGetMsgPacket(num int) Packet { + return NewPacket(FlagGetMsg, NewGetMsg(num)) +} + +func NewSendMsgPacket(toUID string, subject []byte, body []byte) Packet { + return NewPacket(FlagSendMsg, NewSendMsg(toUID, subject, body)) +} + +func NewAnswerGetUserCertPacket(uid string, certificate []byte) Packet { + return NewPacket(FlagAnswerGetUserCert, NewAnswerGetUserCert(uid, certificate)) +} + +func NewAnswerGetUnreadMsgsInfoPacket(page int, numPages int, messagesInfo []MsgInfo) Packet { + return NewPacket(FlagAnswerGetUnreadMsgsInfo, NewAnswerGetUnreadMsgsInfo(page,numPages,messagesInfo)) +} + +func NewAnswerGetMsgPacket(fromUID, toUID string, subject []byte, body []byte, timestamp time.Time, last bool) Packet { + return NewPacket(FlagAnswerGetMsg, NewAnswerGetMsg(fromUID, toUID, subject, body, timestamp, last)) +} + +func UnmarshalGetUserCert(data PacketBody) GetUserCert { jsonData, err := json.Marshal(data) if err != nil { panic(fmt.Errorf("failed to marshal data: %v", err)) } - var packet RequestUserCertPacket + var packet GetUserCert if err := json.Unmarshal(jsonData, &packet); err != nil { - panic(fmt.Errorf("failed to unmarshal into RequestUserCertPacket: %v", err)) + panic(fmt.Errorf("failed to unmarshal into GetUserCert: %v", err)) } return packet } -func UnmarshalRequestMsgsQueuePacket(data PacketBody) RequestMsgsQueuePacket { +func UnmarshalGetUnreadMsgsInfo(data PacketBody) GetUnreadMsgsInfo { jsonData, err := json.Marshal(data) if err != nil { panic(fmt.Errorf("failed to marshal data: %v", err)) } - var packet RequestMsgsQueuePacket + var packet GetUnreadMsgsInfo if err := json.Unmarshal(jsonData, &packet); err != nil { - panic(fmt.Errorf("failed to unmarshal into RequestMsgsQueuePacket: %v", err)) + panic(fmt.Errorf("failed to unmarshal into GetUnreadMsgsInfo: %v", err)) } return packet } -func UnmarshalRequestMsgPacket(data PacketBody) RequestMsgPacket { +func UnmarshalGetMsg(data PacketBody) GetMsg { jsonData, err := json.Marshal(data) if err != nil { panic(fmt.Errorf("failed to marshal data: %v", err)) } - var packet RequestMsgPacket + var packet GetMsg if err := json.Unmarshal(jsonData, &packet); err != nil { - panic(fmt.Errorf("failed to unmarshal into RequestMsgPacket: %v", err)) + panic(fmt.Errorf("failed to unmarshal into GetMsg: %v", err)) } return packet } -func UnmarshalSubmitMessagePacket(data PacketBody) SubmitMessagePacket { +func UnmarshalSendMsg(data PacketBody) SendMsg { jsonData, err := json.Marshal(data) if err != nil { panic(fmt.Errorf("failed to marshal data: %v", err)) } - var packet SubmitMessagePacket + var packet SendMsg if err := json.Unmarshal(jsonData, &packet); err != nil { - panic(fmt.Errorf("failed to unmarshal into SubmitMessagePacket: %v", err)) + panic(fmt.Errorf("failed to unmarshal into SendMsg: %v", err)) } return packet } -func UnmarshalSendUserCertPacket(data PacketBody) SendUserCertPacket { +func UnmarshalAnswerGetUserCert(data PacketBody) AnswerGetUserCert { jsonData, err := json.Marshal(data) if err != nil { panic(fmt.Errorf("failed to marshal data: %v", err)) } - var packet SendUserCertPacket + var packet AnswerGetUserCert if err := json.Unmarshal(jsonData, &packet); err != nil { - panic(fmt.Errorf("failed to unmarshal into SendUserCertPacket: %v", err)) + panic(fmt.Errorf("failed to unmarshal into AnswerGetUserCert: %v", err)) } return packet } -func UnmarshalServerMessageInfoPacket(data PacketBody) ServerMessageInfoPacket { +func UnmarshalUnreadMsgInfo(data PacketBody) MsgInfo { jsonData, err := json.Marshal(data) if err != nil { panic(fmt.Errorf("failed to marshal data: %v", err)) } - var packet ServerMessageInfoPacket + var packet MsgInfo if err := json.Unmarshal(jsonData, &packet); err != nil { - panic(fmt.Errorf("failed to unmarshal into ServerMessageInfoPacket: %v", err)) + panic(fmt.Errorf("failed to unmarshal into UnreadMsgInfo: %v", err)) } return packet } -func UnmarshalServerMessagePacket(data PacketBody) ServerMessagePacket { +func UnmarshalAnswerGetUnreadMsgsInfo(data PacketBody) AnswerGetUnreadMsgsInfo { jsonData, err := json.Marshal(data) if err != nil { panic(fmt.Errorf("failed to marshal data: %v", err)) } - var packet ServerMessagePacket + var packet AnswerGetUnreadMsgsInfo if err := json.Unmarshal(jsonData, &packet); err != nil { - panic(fmt.Errorf("failed to unmarshal into ServerMessagePacket: %v", err)) + panic(fmt.Errorf("failed to unmarshal into AnswerGetUnreadMsgsInfo: %v", err)) + } + return packet +} + +func UnmarshalAnswerGetMsg(data PacketBody) AnswerGetMsg { + jsonData, err := json.Marshal(data) + if err != nil { + panic(fmt.Errorf("failed to marshal data: %v", err)) + } + var packet AnswerGetMsg + if err := json.Unmarshal(jsonData, &packet); err != nil { + panic(fmt.Errorf("failed to unmarshal into AnswerGetMsg: %v", err)) } return packet } diff --git a/Projs/PD1/internal/server/datastore.go b/Projs/PD1/internal/server/datastore.go index 9229077..c2466c1 100644 --- a/Projs/PD1/internal/server/datastore.go +++ b/Projs/PD1/internal/server/datastore.go @@ -41,6 +41,7 @@ func (ds DataStore) CreateTables() error { fromUID TEXT, toUID TEXT, timestamp TIMESTAMP, + queue_position INT DEFAULT 0, subject BLOB, body BLOB, status INT CHECK (status IN (0,1)), @@ -53,18 +54,36 @@ func (ds DataStore) CreateTables() error { return err } + // Define a trigger to automatically assign numbers for each message of each user starting from 1 + _, err = ds.db.Exec(` + CREATE TRIGGER IF NOT EXISTS assign_queue_position + AFTER INSERT ON messages + FOR EACH ROW + BEGIN + UPDATE messages + SET queue_position = ( + SELECT COUNT(*) + FROM messages + WHERE toUID = NEW.toUID + ) + WHERE toUID = NEW.toUID AND rowid = NEW.rowid; + END; + `) + if err != nil { + fmt.Println("Error creating trigger", err) + return err + } + return nil } func (ds DataStore) GetMessage(toUID string, position int) protocol.Packet { - var serverMessage protocol.ServerMessagePacket + var serverMessage protocol.AnswerGetMsg query := ` SELECT fromUID, toUID, subject, body, timestamp FROM messages - WHERE toUID = ? - ORDER BY timestamp - LIMIT 1 OFFSET ? + WHERE toUID = ? AND queue_position = ? ` // Execute the query row := ds.db.QueryRow(query, toUID, position) @@ -73,7 +92,7 @@ func (ds DataStore) GetMessage(toUID string, position int) protocol.Packet { log.Printf("Error getting the message in position %v from UID %v: %v", position, toUID, err) } - return protocol.NewServerMessagePacket(serverMessage.FromUID, serverMessage.ToUID, serverMessage.Subject, serverMessage.Body, serverMessage.Timestamp, true) + return protocol.NewAnswerGetMsgPacket(serverMessage.FromUID, serverMessage.ToUID, serverMessage.Subject, serverMessage.Body, serverMessage.Timestamp, true) } @@ -84,9 +103,7 @@ func (ds DataStore) MarkMessageInQueueAsRead(toUID string, position int) { WHERE (fromUID,toUID,timestamp) = ( SELECT fromUID,toUID,timestamp FROM messages - WHERE toUID = ? - ORDER BY timestamp - LIMIT 1 OFFSET ? + WHERE toUID = ? AND queue_position = ? ) ` @@ -97,8 +114,14 @@ func (ds DataStore) MarkMessageInQueueAsRead(toUID string, position int) { } } -func (ds DataStore) GetUnreadMessagesInfoQueue(toUID string) []protocol.Packet { - var messageInfoPackets []protocol.Packet +func (ds DataStore) GetUnreadMsgsInfo(toUID string, page int, pageSize int) protocol.Packet { + + // Retrieve the total count of unread messages + var totalCount int + err := ds.db.QueryRow("SELECT COUNT(*) FROM messages WHERE toUID = ? AND status = 0", toUID).Scan(&totalCount) + if err != nil { + log.Printf("Error getting total count of unread messages for UID %v: %v", toUID, err) + } // Query to retrieve all messages from the user's queue query := ` @@ -109,38 +132,23 @@ func (ds DataStore) GetUnreadMessagesInfoQueue(toUID string) []protocol.Packet { queue_position, subject, status - FROM ( - SELECT - fromUID, - toUID, - timestamp, - ROW_NUMBER() OVER (PARTITION BY toUID ORDER BY timestamp) - 1 AS queue_position, - subject, - status - FROM - messages - WHERE - toUID = ? - ) AS ranked_messages + FROM messages WHERE - status = 0 + toUID = ? AND status = 0 ORDER BY - timestamp; + queue_position DESC + LIMIT ? OFFSET ?; ` // Execute the query - rows, err := ds.db.Query(query, toUID) + rows, err := ds.db.Query(query, toUID, pageSize, (page-1)*pageSize) if err != nil { log.Printf("Error getting all messages for UID %v: %v", toUID, err) } defer rows.Close() - // Iterate through the result set and scan each row into a ServerMessage struct - //First row - if !rows.Next() { - return []protocol.Packet{} - } - for { + messageInfoPackets := []protocol.MsgInfo{} + for rows.Next() { var fromUID string var subject []byte var timestamp time.Time @@ -148,25 +156,19 @@ func (ds DataStore) GetUnreadMessagesInfoQueue(toUID string) []protocol.Packet { if err := rows.Scan(&fromUID, &toUID, ×tamp, &queuePosition, &subject, &status); err != nil { panic(err) } - var message protocol.Packet - hasNext := rows.Next() - if !hasNext { - message = protocol.NewServerMessageInfoPacket(queuePosition, fromUID, subject, timestamp, true) - messageInfoPackets = append(messageInfoPackets, message) - break - } else { - message = protocol.NewServerMessageInfoPacket(queuePosition, fromUID, subject, timestamp, false) - messageInfoPackets = append(messageInfoPackets, message) - } + answerGetUnreadMsgsInfo := protocol.NewMsgInfo(queuePosition, fromUID, subject, timestamp) + messageInfoPackets = append(messageInfoPackets, answerGetUnreadMsgsInfo) } if err := rows.Err(); err != nil { log.Printf("Error when getting messages for UID %v: %v", toUID, err) } - return messageInfoPackets + numberOfPages := (totalCount + pageSize - 1) / pageSize + currentPage := min(numberOfPages, page) + return protocol.NewAnswerGetUnreadMsgsInfoPacket(currentPage, numberOfPages, messageInfoPackets) } -func (ds DataStore) AddMessageToQueue(fromUID string, message protocol.SubmitMessagePacket) { +func (ds DataStore) AddMessageToQueue(fromUID string, message protocol.SendMsg) { query := ` INSERT INTO messages (fromUID, toUID, subject, body, timestamp, status) VALUES (?, ?, ?, ?, ?, 0) @@ -197,7 +199,7 @@ func (ds DataStore) GetUserCertificate(uid string) protocol.Packet { //if err!=nil { // log.Panicf("Error parsing certificate for UID %v",uid) //} - return protocol.NewSendUserCertPacket(uid, userCertBytes) + return protocol.NewAnswerGetUserCertPacket(uid, userCertBytes) } func (ds DataStore) userExists(uid string) bool { diff --git a/Projs/PD1/internal/server/server.go b/Projs/PD1/internal/server/server.go index 1f2863a..e4d6474 100644 --- a/Projs/PD1/internal/server/server.go +++ b/Projs/PD1/internal/server/server.go @@ -4,7 +4,6 @@ import ( "PD1/internal/protocol" "PD1/internal/utils/cryptoUtils" "PD1/internal/utils/networking" - "fmt" ) func clientHandler(connection networking.Connection[protocol.Packet], dataStore DataStore) { @@ -24,33 +23,30 @@ F: for { pac, active := connection.Receive() if !active { - break F + break } switch pac.Flag { - case protocol.ReqUserCertPkt: - reqUserCert := protocol.UnmarshalRequestUserCertPacket(pac.Body) + case protocol.FlagGetUserCert: + reqUserCert := protocol.UnmarshalGetUserCert(pac.Body) userCertPacket := dataStore.GetUserCertificate(reqUserCert.UID) if active := connection.Send(userCertPacket); !active { break F } - case protocol.ReqMsgsQueue: - _ = protocol.UnmarshalRequestMsgsQueuePacket(pac.Body) - messages := dataStore.GetUnreadMessagesInfoQueue(UID) - fmt.Printf("Number of unread messages by user %v is %v\n",UID,len(messages)) - for _, message := range messages { - if !connection.Send(message) { - break - } + case protocol.FlagGetUnreadMsgsInfo: + getUnreadMsgsInfo := protocol.UnmarshalGetUnreadMsgsInfo(pac.Body) + messages := dataStore.GetUnreadMsgsInfo(UID,getUnreadMsgsInfo.Page,getUnreadMsgsInfo.PageSize) + if !connection.Send(messages) { + break F } - case protocol.ReqMsgPkt: - reqMsg := protocol.UnmarshalRequestMsgPacket(pac.Body) + case protocol.FlagGetMsg: + reqMsg := protocol.UnmarshalGetMsg(pac.Body) message := dataStore.GetMessage(UID, reqMsg.Num) if active := connection.Send(message); !active { break F } - dataStore.MarkMessageInQueueAsRead(UID, reqMsg.Num) - case protocol.SubmitMsgPkt: - submitMsg := protocol.UnmarshalSubmitMessagePacket(pac.Body) + dataStore.MarkMessageInQueueAsRead(UID, reqMsg.Num) + case protocol.FlagSendMsg: + submitMsg := protocol.UnmarshalSendMsg(pac.Body) if submitMsg.ToUID != UID && dataStore.userExists(submitMsg.ToUID) { dataStore.AddMessageToQueue(UID, submitMsg) } diff --git a/Projs/PD1/server.db b/Projs/PD1/server.db index b5ed3b148273dff98bb8afe342732e7866c2a5a9..3784ec98eb700789457acedb5eadc3cf839188db 100644 GIT binary patch delta 14032 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 z zl5vNtN4`DYvg+yIZxJzpzG}?8o1#!Ss?)yz{2V|)yTBDEHSwgbEaq}t-1%}q51i0w zA9e4&?OKzRQCeID7XZj_UE{beY<%hCUF7HuaP=%)v_Aavu+`%N{hxEX`h6vU1rX#E z62kYhVoaCiSB#pkBG<3%bDjgS;|+N6$RCL?zHfCzI~zSoHNTU05S>hAm>&p<1dWMJ zt-%4Za;ctKgjNjXg2U#*%Mc4kpd5E=!gcWVv#tW$(T9FVA|`GZ?&gQ=5-x*S0~=>! zkci5Q;E3}05qP0sq&X3k9usSqJJN6YQ`I+gK_=_Zmrab68d}&OU7z`tbYhTSEB45| zw7-q)%g`u(&xFac3a|wa$uwLfdqSK*4F>_zs~okI&rOd$T)*wUXIt8@0l{o*7MV8> z#HC5Du@mCSI)U^Y%1z{}wP%Jy#yg?xI{?MEXpcNa#}Cmo!bi61e9eq9qq;Y<4I52j^rar9lKI>A1;=&3;KHCMf}c54)df} z;QGE>C_J^6;z~e(`jQ~(b?2J)z|xGboj8EQ?lH4H8Ak8nN~h=%${C&Q56%XaNGP{N zFq(~8y7S{z=9BEpTw<%Lk!73WcB()^C4I(wp}tC!rtWJ0v<)zD1HX=HL08X0pOOf= ztb46|iv5ore^B)m;+{ddh3qJ1Nl}8nd4YOU(lQqPY9EM$ROub@gz9v`LJ&5-w5!%Z z<<`F>zM?GqU~Oud2C-0EClC#k;!Q&6n!XRK>0QH2`I4&TN%$Rt3)DfVJNOy&cyOLY zO=M@SuV>=f8+X(G2q?OiGiEOKO+sh+qD8aGXu3tzJc*q`5aIMDMJ-?UMa>?3DvC$H zG!IM_k-kLp48Aezu$=-fmWKarS#Ar?(ySEk7~k<$ZQ563t9FIdn&(;2gHS#8t~%Pd zyxb^dm{y_GHnkX{PwEFf>ZfX?0?qZ(uXL_pBqnR<-eAX0;s98D?=@ByuCHO+$bGhB z!O|C%jw|Wky9|Ot2||oW?3` zX$EVaD>Z@DLH@DGD9wOTK2VM-rLF}(`r3Hz4_P>uzUWmu9xOku#o!_v~u3B0ik>G!}~Fp184 z^G2F6fg2MvWRBMKIjiQlNukiyvVH8eS@@j!#11^+-f>@3o!wS+GOq`7F~=@AX=b`~ z$aodueH`g?L82M^h8@L^%SO*k$MI|UW|MqaPuBUq>k#{)yPGgZ*>~_{(fr=yhqx&t zl#X2j)!%?->OQ#D7-k65xTP&4nq6G>(ysj2$%n@fhd8(7oc?<0M4B5Ryi#qU$+GIS z1Av*Fca3b}`a-z94*6zsf8SZ~Hoi&|^5Uof_ZXqq;24KexqSb?S|gf<6L|d->zfj% z;&fkK)8SyHL4yVL*04oe6Jm#_Lx$CrV~dI8T)er7a_bX2A$_mj zMRjw({b+tf!70H4cEJo%gv?4*VCw7-iG9#II!1}uu3mOHnuK3`d_rQE;=aro33q{X zn(@&y9JlKIz@t~KxCET3Y&gjef@}IcoScJp@&BT3kjTU!$P372$lk~b$iz*k#7M}= zK1x`?UoeH0mz9-~m4lgsllwn)2_!w_UrOc=cKHKe{*An_^0II4W!Xy2Ev7Y~wVO}86UJZc`e}vcHON#);zn2yP zzy4lY1l;|-vt@xPZAVekE+Mb~=rgB-?s+sMK(T4%$_M_sGvNR5Wx z(7^wUg#ICU{%ao#3?xYHXQe{QtU&u#I-w*i(msM?gvj@^cegUgv#Fh+aW(ptMV`-g zrTbu>N=2si>9SopRm>8x@QWc%ladqPEj;MyH#0v<%;pAIqc8x7tFw={fE>f|PxGm# z+#GC$EqL+y!&LQe9T~j2yiezs+*@+%Mho; zSuSjv%K2bsP%F2OyV%C4WGjY_$S3jp2O3hA4$Z&IpeooFKoT z#t#@E4jHs9^A>B)mW=D1oh15ozBa#eO;WZREVYxS2nYZZuAvuhtT^lrH%_12&@MVu zilKh?Y6}O3`EG<1=s!tI+kFimvFSDbYGMFYh{FAO8cMw2#|LM^JZRqCBfe8PupBJm z%#&62E8qDvO&#=>P!P%W5ZHw|)ueZgnJ{+4#end4ccd*ZHf;_aCFPfRJ&uzoF3CbG z^sd@Q?y?6C_tS|&yZXON_~KN>Gr`J*zaK>R+=;=zas7y!4B13UNqhepo*v8I0Hg81 zoJ%lI%_I7SJuNV~_<+V%r5Z*aw_7A_mhKoQ8&l$2O>OQR;}RM_ztaWu3<2n#YCw*D zdURVmLDSy!wflUtGg+iV{csBmOjA;8)tF<37$`DumT*)fW*^gBK(m$A ztjtzoee#{?&gc1smh#4rX`P`Gxz0d^@eEDo>D=GXn$tq3M5xX3vq(U6E{D8EKGfH= zdsH^lsF_;0EVpLV(H}fs17!xHA=WU7xZqhK5gJP)lEem>(nAgB1sH9K_paFJ$dBA8 zxIwbY9*SL|C)t=7rrO0`10CsfxUE>F{doi0Pj`?sdrKrlth)dMQn%*c(_`dX2uuDd7? z7Zn&7@ofUBJd)FL=@&WKMzrWhWw>xM3gJn4g1#itm!hmV&jk{G}t*>5~4{E9Hhi+FzbFN7R}=351GM9FmI$;+hoHVgbBp{^$~S*t(KVvqob2khL|qcr47t2Sorv<2OC1%QJE&!1Y?J1{7r5rPn9?CU zMy=>~311OGkv1-Bjpk_nZ^ZOpw1SuwS9TzPl_qANEW9& z6|K>ujMcRCSuX)Df_c^o0^-xhj{=c;Iz_S!NP~%Z3+=$yZ#6H_9qegNkowcEz#3Tk zQ6u+D2~9fILRuT!%$l*D+}wKg)jE%PEDD;mQEA*u6p-5+6$b>3W#2xotqDkJ5BG13V_y`aD=T*9MrKx$*2^`7G?Q3f}7LU$yy zlz(Fr>2B~-$J;Zz)(d4=0>(FcU{mXp8v8dQ5Pyxu;72EtcbzHcGO#WUE1gZe>Rajc^sf4T0j@ck*rl}@`dnr zP}H>)!4a?m-D&*0k}-ao0->4snyxGWN>K5)h6AP7%lF*hzyhDGRBv zd#IQx@8{r{p}#(wxSR#awHkCbJ}8}=@)ZMRmMZxZBJ*~?$N-`B=lSjw=E5; z4l(~Co!8@N*@(atg#s;*IS+jG5f6*r!%OGTu18?Q7wuu8?V z5AZb94P1Kcd&#E**hW~hy=`mW=xp?HR5K51frKB z(0VU^tK`}dp=d(@-qoO8zbjh%r}9#e>X`q&?R{2W4tCrufDBG;s5e=3e&mgVDKaLuxPR=*9OgC(+oz&Q3D@EgZ{*CI-IiyAbgIEtaRb>v+J;F| zLt;r1+A+OoyBlt2F`ylPd|AF}qJI_j1jjaBzP2&HRaWg#b*^9DQ*IJ0 zD+=}9!$C3-%l(qWe>Z4gAsm0JIvl#i7-J;fc0fO|(a`J9S2q8nIQe(f0|sJXX||Mr zbo2fM)`-RAH~(2eK*ZgLTOs5dvZCiCafZz7w(B@bai$(Mx)hS4s>h3!<7VFVnfXH#nYm?z zi!aNe;|H&h_7t>8@Q2iQmuz{&&IVr>8J<%>zsasCu^WmRGWjKYbSZtipHA4NC|C%0 zt&s0tpI%V(c=C)q9hL`b$IoG_#HTf#3VjfC(3nfZDK#;6nBITmy} z*Mo?Aj_aWvOxnbMo_^lOhZD$j^nON16rnO;8l$`4vP`5dx;<~IRtqrt#z6gU$je&= znW@C5TkF2%Qx8Q(lEDMFdjYO_0joC8nF&MQJO`G^sX(!a>iGt^!J$v$Fd9NnDk%}I z_NXTxz=7s`%i^7R#OT*v^#Z3aD@+Q7BnqxppV=cAXrqj)TGzI6)Nn2C{rU;ZkgKQl zEZEG%$?%&ednugq`Eb1_=@=8*syFW;Z(7UZmoO$fjNR|!JEHHrY58Jf>hW0RQ9XKx zgfp2o?$37L3Nj=BZY;cYKlK-q+L6K`4h~+TbcJ{o?KIO@gKi}ol4kscq&kWII(aLH zhCF+$1M3nY&zJ6>%fd%4boeYV2f<7ej~$&sRpiJWlue`aP$+h|)9F*DmL1V_PTrxD z{GYsU);Pt4L^Q({gy?)8ce{2-FC0%xnvV3CZ1&k;_n^7~Ax)7L#=azf19NsovQEzV zcN>b3BOe_(M|x7;d){Rclq>C%d;AcDEXz4LWwXyWns7L}p;E7NF*e(04|uz=rt|lD zXG^6Sz3&=i9I=T?&pR)L&0R!Fg(GAxg43fk*uk@ z<)sx{7ZVxK+C)b)q7Is-OpUkE6=eSuXUF}Ch}ZuHR*FtN4Rgh-(dn2z**IjrbP5$} z_^E=KJ`>6Mv5(24j&ApgCR5ZaGi*Cu$HzlA#@8Gvm zQAm$DBxBup0`F*0^uPh=PeqngOIBTG6P5k>c>Opa$DYb@f6c6>yj*c;u%8n2y56xQ zefxYL5@Xx$arig?yr75Bkl3DrWdoUNW0k!%#ipJQ+mWif4#7nuv(~&=j8OgH^scF% zEQg1oBE#}ZWugFig9&MwG^4CHv#VBX?bjK}&~+OpFc5Qt=BP$_UFS!($!ly_a^v<$ zOFcC}YR_;?TE1}~w;fF`ii8`RjOk7;*e8|A8W}ooqFDpQSCfc_V5R2CPr$E0X_>PP z#|>dsm{}TjPEgavrrgw6InEcP-?2_!#UrgNbpEBnk}hMeF<*YgQ{f^1M!M^c;1j)z z3hli5R3DegWHwdrCJRUmYCP^oq<@vK+zjjbA2SuG@~sMsF3~>hk9TlaZXMz z$mo9jmJ^Fx8jGbjK-*L<_7bedWY9z}!pq83uMYj>#K1p^3}}eURKl_|()<1nPCSey zwl_gRzH(LhHDgpxO;4m{b1fgo7Mq)2Yv0FITv<}|>{(bcSNE;pmn3m!tGstHulNnn z5P4~Fbj{V1!!gHO_Qq2{UZxMS`lEUk@nDVCDRNb4<4dF~H<@+1tme9@N5@HGKz%qH zmW)m^dk-(QpF7P*-JUrD3IC8Li&63PxL$6=^VZ~(Z-y9q8sn)*ozDqG?)xY7;sD)< zG>0-LLC80EQ~%Guw|A^F7DtPwG=u1Yt_Yq)*Do$fK2q#0u^dC)1Blrm=blaKs&d+K zuKGkR7qzzja?McqaYIo)KpqRvFZD>ZK$NwZid$#N-#-h#MwZTI9*z;3c?8Pp;Rce8 z5o~@Bws}qFq{@nz@d$|Noa+6a>%v4Um_xcuD`T4uh9rT~HM;6a&TSWnPNni25PwU% zZN$}Zn;V%v_qU}tx1^A`mJQpfHeJbw%bY;~va8aW24qt=sY-4&-+ScT?GJ4v2q z%I;#57Dq0bud~L>l2r4zk!@3gcFgk_o&s-vQAjOXKG z?UO3(%K~PrbEC*`oy^$rE8xUEt+U5?MNi$)gqSA$lF1a6B8LcpPA) zw{j*5^EK$%TpK#S!w;R!Yn>*BRu050pb`f!M51EXTs(D3sCfl3xje%FG%(Ow4_?}M z7G5JslE=b4F*)P7ZKD_s1+*f&pYGW1*D#MUFzr(_I6_Sr@Rb*-8Mz`+Mn-C32hD=n zQX~r>bFU%MpnWRpMII3PStO}ZBVtv$(dWm}geio5TWI{lz8>bp%qcQ6c@-xaKN4(a z#a9$6m4l%1#D}D^~sTb0#}I=}-ac2|#B1Y$~ZXuG%%d-#kcl92tBT zIWwEqYo2os+qsHn#3;kQeQ^?~z`9qLXL{V;*N8~!!Z;#mu9(rq4W5LJ_0uI4KJZ!S zUr!KRy?By0)98pqbq4ehJTNlzyLnEtV=bx9%LS=s5NG-63z0|I&DlNiSz$F*n@kiv zu~WZ<(r2RP*>Elz|3jQW{*U71-#4wmK&W>qO>ufgokHHMs8@CH;z@2qEt%A|hO>Y9 znr4o6Vl-f9F{A$`k6a6Oa%`<=K#%@v9TYJ1svxrUS(h|0D*Uk1bv+k^8&5zq4)BZV zyhe;j;-W|=Wt!_16Zeehj?0*IDv*8bIh{<&KfFM?td=~_LVW41U|F)A@T&C9;nq-n zUFZcrp^djbv2!{pXQJ3>bFD8<&Ls3X#jqklq?f~bT5w@GM1p%vX5LUdpt$=wd!S0u z2Gc&P3BRu!dlL;d8zf3k*BQhA11S3J$iv;uo^N)WScD78m27Q}~67T2=nnhW%L-vRS@D;cL8Ufj(naWDzbo=VXxr_WftG~{*- z(#RK`K3|jK86G8n&U^DB$4S1_K_3p-v^U9{a#pjk-P7_YeA73W5%z1?=fi zry{jYU%z^am8KIue^PKJqAUN_ZO_MvjXptIb?QE%9tDBb4Gcttnuz4YR-z(mqT~3< zgIE1{)NqfE18Z?$GeI}cquBoH**>lB6hk4#Gi`e_v}>8} zBNDiD3ypoxXH8jmo|_6gf4xXWCD*chP;w!_k|ev1=&3ft8?}w3HqWhK9YULbmXTM% zW0tf{ED$2p3z*sVh$^Za;fvFK@WO_=4O$6&N;F^1$m$t;?vuQv-_$DAG$v8s5uGDw zz#z8EWA3bz6Jc!~l_f6=IXAz$4O|fA?6BpAjEA5Ia7vB&gj4*r<1uZ}CO;uqW#H=z z$uj|4B@IX0eIFPI0g)#|TvncV`H*1w`C5*70VG*N0C439&hso4P-NHD1M`2Q@1P;WeUQKGfKmKBZwNe!W;XqeA?E8*zhf{>jF3YyN7C zFH+HU-%;~ZwXhW>wVms<(_Ikm$DHqAia8qW%pu5)Go#$ohM;y$sY-X&4m<=NPh`>0 z<=htwTObCTkWgS?7iC0D-+eZ`y*RpX7^tNsY5uv6M`zCE9!&d$eh{v?D=AN9dxT!2RH7#jR)2}elQ5#C3CMYE!` zo&n}SL_g%%UR>k2eazqGGc}|%Ja|FB_~Ng-7GR6zyGpX&%jHD&Z*NrfCpZ$Lk7|VM z3$uo+ABRMnLk(KaCr|7$-u1$?Uef-9$qY7QOQ|NQgf7$YmYBFR6>6_l)Rj(qCcKnE ztQ(`Ko3&PuUg7Q1W1!$~o0&J<2zklG*U{9b$xAl$LGC-Rpu!*Xt_P-316EFfe}3nn z;sCVs5#1bLhF;DsB(llbHE6*77#UI+dp-=chA>W>M*5>E4wj#6b2*yW!UEuGPX*SL zULwA?znGVHowAKw)NI%d^`_YS8}rVDquV-;)dFwRY(G25N%br}w}uGFqespXAZPE( zL|%>|XE;e^`rpSY-WuE#vw0-W0vQG8WdKGoFI1Ua@_;Aa!x#KHjE|jg0k%gMFelU- zAY@1Hm_Ct2bob2e{dAL)j81_R{AraR4gHU*okHsFg{ zd-Jx1=4AK`V;uN=*zoiF;b9J!q@oISE^!O;q5Xjl1GcyOA3)(@sI{T{h^2ljt0(^b zIjXIA>|BDZp0`u6kPs!k>zp*1`3|moNg=mC^k4>Rm{QQewwj3BH`2lBQy?q5^&wA$+TJcu3c4zBopLyhn6!r0tAoruDhP@G z1v5i(i$F>~Jij=>7}uMI#fp3DAv-Iq!^KH(mXM?82mTgXNjpM;O8NLG^(K*AYIGI3 z-}=;&A^Ecm#0Z&zZWu$wbc~u{K=n6Yqu-9t)rFYshYCTqU?nFBPNBGub%0?D#vC+) z0RwpXu1`-Bif3$-4myJ$`;zQ0T_{h#Dk@j;q0hELLPOm|KE8>t_=Ae1^!IYBLJ`yo zMnT&j{p+(XRZQ|`ki3I)(PM_gX|UKFl|8i?kUvDgOCF_DU9@bT-(8KlG{5U#>6naC wQ_?YGgJRya8x}C$LC@RILtqD-wNf2e|GX$Mf?)?m7P(vS|B=M)j%ND50E=bHDF6Tf delta 9074 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 q Date: Sat, 20 Apr 2024 17:34:45 +0100 Subject: [PATCH 5/8] [PD1] Added server's TODOS --- Projs/PD1/internal/server/server.go | 5 +++++ Projs/PD1/server.db | Bin 40960 -> 45056 bytes 2 files changed, 5 insertions(+) diff --git a/Projs/PD1/internal/server/server.go b/Projs/PD1/internal/server/server.go index e4d6474..1f8def5 100644 --- a/Projs/PD1/internal/server/server.go +++ b/Projs/PD1/internal/server/server.go @@ -6,6 +6,11 @@ import ( "PD1/internal/utils/networking" ) +//TODO: CREATE SERVER SIDE CHECKS FOR EVERYTHING +//TODO: LOGGING SYSTEM +//TODO: TELL THE USER THAT THE MESSAGE HAS BEEN RECEIVED BY THE SERVER +//TODO: ERROR PACKET TO SEND BACK TO USER + func clientHandler(connection networking.Connection[protocol.Packet], dataStore DataStore) { defer connection.Conn.Close() diff --git a/Projs/PD1/server.db b/Projs/PD1/server.db index 3784ec98eb700789457acedb5eadc3cf839188db..e4212f7faea935ea26f6e1f6f5e3d0a7016810de 100644 GIT binary patch delta 2292 zcmVvT%6^0S1$LM;?DNGdeOfE;lkVGch?UFflqXFa`nunZf4W z^mCAk4p=$FY34KsSOBL8W!>nB0SJlNO=t*w1K<}cf+ltBH4Ipgemf2+mDQ_G9v|gC zueO2OEk>N6r^q?yItV^{mh&m;fcNQ-EjcBSzQphcyX4J|`%Trzrd5EoFWIpTOiq7> z43>0w9y2yu+ubFcC&aNx9r)&vqEavypXa_B!dw>_sa7?D<``PI+mN zkbZbHnN^sajl`~}a!qf;_W^pC3`)Y}m#p{%NGF5J1^{rvnVN)xlq-3m7(rBv4>a+| z8P2cEsyotOw7?+p?1PB0UG~l zgfmBU8BCcK7vpob-(qSLlmj%n<=bINd~@r5TY5IVZe@AmD}cb= zct41aDwP4vH?`G)&utN9R>2+UmZqdw{g@r$pWJ}4J7SinSHR`<@=5?hIgLqX`fdf- z_#f%#+&GRI6GyKgp^zWS=_fRLOcG2zBpq$iBhHXsd@Nvza&f$zvBHXclR>3g;zW~N z>e4Mj*w8G+a*JFsxCF1`T#tWc?v&@2-`Mkolva7@wmjSkVx4DlXx)-lnbj|7<&915 z-;^#}UG6iP?((~@S}d(r%87s`^W3?e!^(I22%a<+o|kZ600$eVxy-+NWo&&}rzkO1 zciE$^Sv^=&1hl5?_>UiLGo~7BBQ-JV;z3x@eY;e)ID!tst@9r*G9-VI5>>hpB0`AD zO6YIm%-=_8VAgn1U67_ktvoCl;zH>1ID#-=0BMLxa;gW*ETz_o*i>YKRl9o#}6XCGJnwE-q< z$_gSfPVZ`cT(aOk1?d%1AeY9A^2Nngu1C#c#L7TXWT}VgIU9emNd#d|u3&1!Q<(j0 zj9^A7K9a(bu+Svb$tt4if-`Aw4zor<-E6Z*h?xSU3aAQ(-cdCA$5RQnAnoP$abT+b z7E{1P2juh_qNQC8%sC`_`Rikk`~cIm%q@0FtG6nYPU(5vRN#b`j_qBgR~YA6xL<}G zm+J&rp7X$#>lc57gM@VIK9Z1WOisRX+;E4$Vi-~91?}`j1d?D*E1v+>B$k15;eh6b zwG6k273eQAgis~J8jre>?SO>*_(YG~b+Ie@n!dQu0syB4P@Pz-V%)(ZbPoNeJji5E zP0>8ruseTMGTdV+r*F9BrA_HIC#Hy_92OL<=)f_coF#u0-|{*52bGqHtUZ^*D%F9# zG#uJC#yzZ$d~{g-<8pf%{clMvMUsRVLiLSuFDodx=9tE~KBy%O4Wtx-sLFE?cL58<%L z)W!&Cl-_?8--6v2QM#HcgLp*%yD#zq#4LL%?)MEN(M=>yohNiXPnS|YU$E_3GQqLiTdA{CdSb(*U;jeUdQco zofTu-tJyG%)?NeI0YHT}^{hLjP&Fx}&7mufomXvnp|tFi{}L~JVd^zcCPlL&yb;sWiR}5y)qeVQ^e&YwMEB6yvB+w;y@8n1P4!y2i4@ zW;YP~O-U=c#BxOjMA4FPm`Yv7uPR}a2~8``>5Y(^{G4f^L{BvL0y+gCCks5u!M>Ok zph5#s+oP=IOyFv0DVQ#1luYiin%;kYlKyEh(9egb9kiE9fi~T78xBG4BWbkmm1Lfr z81f)8CPByet8QVm%T{0>IML)q?@*N1OFdXQ$T0&V!JY0-EFF^v443J6=P}S`pU#o? zJ*4|FgZH$JT9CSwWKZm~*&~}SC$CltAqdkrL`uNr^OR6^d=&ODfkp#& zahBuflXQ7zPlLd;NRtl&q-1>~7TlIFU@Tic%&`j~h_ZTXX>Ab)_Y~=uGVN}f5QS`E zWDp8m#aDxbZ_ZfW{fEczk(FEdK*47K4yoor(yC)RQt_?nH`LoU3SBJ9>X)Q9#$7}o OL^A+Eic}y2UbRI)FHjT! delta 83 zcmZp8z|?SnX@WGX1_J{F*F*(-MvaXLOY{X;_}>5p7`XU<^MB+2$p2 Date: Mon, 22 Apr 2024 14:46:10 +0100 Subject: [PATCH 6/8] Started Report --- Projs/PD1/README.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/Projs/PD1/README.md b/Projs/PD1/README.md index cfeaf02..8c66f37 100644 --- a/Projs/PD1/README.md +++ b/Projs/PD1/README.md @@ -1,6 +1,26 @@ -# Report +# Relatório do Projeto de Desenvolvimento 1 + +## Introdução + +O nosso principal objetivo com este projeto foi consolidar os conceitos lecionados assim como simular interações com um cliente/entidade que nos "encomendou" o serviço, procurando satisfazer as necessidades e requisitos. O projeto consiste num sistema Cliente/Servidor, em que a aplicação cliente seria executada por cada utilizador que queria aceder ao serviço de mensagens, e o servidor seria responsável por responder aos pedidos dos utilizadores e armezenar de forma segura a informação. Para tal, o sistema deveria permitir a troca de mensagens entre os utilizadores, garantindo a autenticidade das mensagens. +Algumas notas sobre o projeto: +- Optamos por escolher **Golang** como linguagem visando uma implementação mais eficiente, robusta e segura ao nível de concorrência. +- Implementamos algumas funcionalidades extra, como o armazenamento dos dados no servidor numa base de dados **sqlite3** +Nas secções seguintes iremos detalhar cada componente do sistema, bem como as funcionalidades implementadas. ## Key Store generation + +## Server + +### Data Store + + + +## Client + + + + [Commands used to generate the key stores](./certs/README.md) From 0889899b4907cf018a1a152704acdb4342de8bfd Mon Sep 17 00:00:00 2001 From: LucasVerdelho Date: Mon, 22 Apr 2024 15:08:11 +0100 Subject: [PATCH 7/8] [PD1] - Report - Arquitetura --- Projs/PD1/README.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/Projs/PD1/README.md b/Projs/PD1/README.md index 8c66f37..0254b99 100644 --- a/Projs/PD1/README.md +++ b/Projs/PD1/README.md @@ -8,8 +8,30 @@ Algumas notas sobre o projeto: - Implementamos algumas funcionalidades extra, como o armazenamento dos dados no servidor numa base de dados **sqlite3** Nas secções seguintes iremos detalhar cada componente do sistema, bem como as funcionalidades implementadas. +## Arquitetura do Sistema + +Neste projeto, a arquitetura do sistema é composta por 2 componentes principais: +- **Cliente**: é a aplicação que cada utilizador executa para interagir com o servidor. O cliente é responsável por enviar mensagens para o servidor e receber mensagens de outros utilizadores (pelo servidor). +- **Servidor**: é a aplicação que recebe os pedidos dos clientes, processa-os e responde de acordo. O servidor é responsável por armazenar as mensagens dos utilizadores e garantir a autenticidade das mensagens. + +### Crypto +É importante destacar que, para garantir a segurança e integridade das mensagens, implementamos um protocolo de comunicação seguro. Este protocolo utiliza tanto criptografia simétrica quanto assimétrica. As mensagens são cifradas com a chave pública do destinatário para garantir a confidencialidade, enquanto são assinadas com a chave privada do emissor para autenticidade. Dessa forma, asseguramos que as mensagens sejam protegidas contra acessos não autorizados e que sua origem possa ser verificada. + +### Networking +O canal de comunicação estabelecido entre o cliente e o servidor nesta implementação garante uma troca de dados segura e criptografada utilizando o protocolo TLS (Transport Layer Security). Ambos, cliente e servidor, empregam configurações TLS para cifrar os dados durante a transmissão, assegurando confidencialidade e integridade. Durante o handshake TLS, o servidor valida o certificado do cliente para verificar sua autenticidade, prevenindo acessos não autorizados. Este mecanismo robusto de segurança protege o canal de comunicação contra escutas, adulterações e ataques do tipo "man in the middle", garantindo uma troca de informações segura e confiável entre o cliente e o servidor. + +### Protocolo de Comunicação + + + +## Diagramas + + + + +## Protocolo de comunicação + -## Key Store generation ## Server From 417f9851f35ed896a6b9ddd2094f888839738a7a Mon Sep 17 00:00:00 2001 From: LucasVerdelho Date: Mon, 22 Apr 2024 15:18:25 +0100 Subject: [PATCH 8/8] [PD1] - Report - Protocol --- Projs/PD1/README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Projs/PD1/README.md b/Projs/PD1/README.md index 0254b99..a123365 100644 --- a/Projs/PD1/README.md +++ b/Projs/PD1/README.md @@ -22,18 +22,21 @@ O canal de comunicação estabelecido entre o cliente e o servidor nesta impleme ### Protocolo de Comunicação +O package **protocol.go** define um conjunto de estruturas e funções que representam os diferentes tipos de pacotes que podem ser transmitidos entre o cliente e o servidor. Cada tipo de pacote é representado por uma constante PacketType, que indica a natureza da informação contida no pacote através de uma **flag**. +As estruturas de dados definidas, como `GetUserCert`, `GetUnreadMsgsInfo`, `GetMsg`, `SendMsg`, `AnswerGetUserCert`, `AnswerGetUnreadMsgsInfo` e `AnswerGetMsg`, descrevem os formatos específicos de cada tipo de pacote a ser enviado e recebido. Cada estrutura contém os campos necessários para armazenar e representar os dados associados a cada tipo de pacote. + +Além disso, foram implementadas funções auxiliares para criar instâncias de cada tipo de pacote, como `NewGetUserCert`, `NewGetUnreadMsgsInfo`, `NewGetMsg`, `NewSendMsg`, `NewAnswerGetUserCert`, `NewAnswerGetUnreadMsgsInfo` e `NewAnswerGetMsg`. Estas funções facilitam a criação de pacotes com os dados necessários de forma estruturada. + +Para facilitar a serialização e desserialização dos pacotes em formato JSON, foram implementadas funções `Unmarshal` específicas para cada tipo de pacote. Estas funções convertem os dados do pacote entre o formato JSON e as estruturas de dados correspondentes, permitindo a comunicação eficiente entre o cliente e o servidor. + +Este package serve como uma camada de abstração que facilita a comunicação entre os componentes cliente e servidor, garantindo que os dados sejam transmitidos de forma estruturada e padronizada, facilitando o desenvolvimento, manutenção e expansão do sistema de comunicação. ## Diagramas -## Protocolo de comunicação - - - - ## Server ### Data Store