[PD1] Added SQLlite queries and minor protocol changes

This commit is contained in:
Afonso Franco 2024-04-18 01:18:51 +01:00
parent 1e12bcde6c
commit 23584e2901
Signed by: afonso
SSH key fingerprint: SHA256:aiLbdlPwXKJS5wMnghdtod0SPy8imZjlVvCyUX9DJNk
6 changed files with 213 additions and 46 deletions

View file

@ -3,6 +3,7 @@ module PD1
go 1.22.2 go 1.22.2
require ( require (
github.com/mattn/go-sqlite3 v1.14.22 // indirect
golang.org/x/crypto v0.11.0 // indirect golang.org/x/crypto v0.11.0 // indirect
software.sslmate.com/src/go-pkcs12 v0.4.0 // indirect software.sslmate.com/src/go-pkcs12 v0.4.0 // indirect
) )

View file

@ -1,3 +1,5 @@
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
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 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k= software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k=

View file

@ -30,7 +30,7 @@ func Run() {
defer cl.Connection.Conn.Close() defer cl.Connection.Conn.Close()
// TODO: getuserinfo client cert // TODO: getuserinfo client cert
// TODO: ask server for the recieving client's cert // TODO: ask server for the recieving client's cert
certRequestPacket := protocol.NewRequestPubKey() certRequestPacket := protocol.NewRequestUserCertPacket(uid)
cl.Connection.Send(certRequestPacket) cl.Connection.Send(certRequestPacket)
certPacket := cl.Connection.Receive() certPacket := cl.Connection.Receive()
// TODO: cipherContent := cryptoUtils.encryptMessageContent() // TODO: cipherContent := cryptoUtils.encryptMessageContent()

View file

@ -7,12 +7,12 @@ import (
type PacketType int type PacketType int
const ( const (
ReqPK PacketType = iota ReqUserCertPkt PacketType = iota
ReqAllMsg ReqAllMsgPkt
ReqMsg ReqMsgPkt
SubmitMsg SubmitMsgPkt
SendPK SendUserCertPkt
Msg ServerMsgPkt
) )
type PacketBody interface{} type PacketBody interface{}
@ -22,91 +22,91 @@ type Packet struct {
Body PacketBody Body PacketBody
} }
// Client --> Server: Ask for a user's public key // Client --> Server: Ask for a user's certificate
type RequestPubKey struct { type RequestUserCertPacket struct {
FromUID string UID string
KeyUID string
} }
func NewRequestPubKey(fromUID, keyUID string) Packet { func NewRequestUserCertPacket(UID string) Packet {
return Packet{ return Packet{
Flag: ReqPK, Flag: ReqUserCertPkt,
Body: RequestPubKey{ Body: RequestUserCertPacket{
FromUID: fromUID, UID: UID,
KeyUID: keyUID,
}, },
} }
} }
// Client --> Server: Ask for all the client's messages in the queue // Client --> Server: Ask for all the client's messages in the queue
type RequestAllMsg struct { type RequestAllMsgPacket struct {
FromUID string FromUID string
} }
func NewRequestAllMsg(fromUID string) Packet { func NewRequestAllMsgPacket(fromUID string) Packet {
return Packet{ return Packet{
Flag: ReqAllMsg, Flag: ReqAllMsgPkt,
Body: RequestAllMsg{ Body: RequestAllMsgPacket{
FromUID: fromUID, FromUID: fromUID,
}, },
} }
} }
// Client --> Server: Ask for a specific message in the queue // Client --> Server: Ask for a specific message in the queue
type RequestMsg struct { type RequestMsgPacket struct {
Num uint16 Num uint16
} }
func NewRequestMsg(num uint16) Packet { func NewRequestMsgPacket(num uint16) Packet {
return Packet{ return Packet{
Flag: ReqMsg, Flag: ReqMsgPkt,
Body: RequestMsg{ Body: RequestMsgPacket{
Num: num, Num: num,
}, },
} }
} }
// Client --> Server: Send message from client to server // Client --> Server: Send message from client to server
type SubmitMessage struct { type SubmitMessagePacket struct {
ToUID string ToUID string
Content []byte Content []byte
} }
func NewSubmitMessage(toUID string, content []byte) Packet { func NewSubmitMessagePacket(toUID string, content []byte) Packet {
return Packet{ return Packet{
Flag: SubmitMsg, Flag: SubmitMsgPkt,
Body: SubmitMessage{ Body: SubmitMessagePacket{
ToUID: toUID, ToUID: toUID,
Content: content}, Content: content},
} }
} }
// Server --> Client: Send the client the requested public key // Server --> Client: Send the client the requested public key
type SendPubKey struct { type SendUserCertPacket struct {
UID string
Key []byte Key []byte
} }
func NewSendPubKey(key []byte) Packet { func NewSendUserCertPacket(uid string, key []byte) Packet {
return Packet{ return Packet{
Flag: SendPK, Flag: SendUserCertPkt,
Body: SendPubKey{ Body: SendUserCertPacket{
UID: uid,
Key: key, Key: key,
}, },
} }
} }
// Server --> Client: Send the client a message // Server --> Client: Send the client a message
type ServerMessage struct { type ServerMessagePacket struct {
FromUID string FromUID string
ToUID string ToUID string
Content []byte Content []byte
Timestamp time.Time Timestamp time.Time
} }
func NewMessage(fromUID, toUID string, content []byte, timestamp time.Time) Packet { func NewMessagePacket(fromUID, toUID string, content []byte, timestamp time.Time) Packet {
return Packet{ return Packet{
Flag: Msg, Flag: Msg,
Body: ServerMessage{ Body: ServerMessagePacket{
FromUID: fromUID, FromUID: fromUID,
ToUID: toUID, ToUID: toUID,
Content: content, Content: content,

View file

@ -1 +1,156 @@
package server package server
import (
"PD1/internal/protocol"
"database/sql"
"log"
"time"
_ "github.com/mattn/go-sqlite3"
)
type DataStore struct {
db *sql.DB
}
func OpenDB() DataStore {
db, err := sql.Open("sqlite3", "server.db")
if err != nil {
log.Fatalln("Error opening db file")
}
return DataStore{db: db}
}
func (ds DataStore) CreateTables() error {
// Create users table
_, err := ds.db.Exec(`CREATE TABLE IF NOT EXISTS users (
UID TEXT PRIMARY KEY,
userCert BLOB
)`)
if err != nil {
return err
}
// Create messages table
_, err = ds.db.Exec(`CREATE TABLE IF NOT EXISTS messages (
fromUID TEXT,
toUID TEXT,
timestamp TIMESTAMP,
content BLOB,
PRIMARY KEY (toUID, fromUID, timestamp),
FOREIGN KEY(fromUID) REFERENCES users(UID),
FOREIGN KEY(toUID) REFERENCES users(UID)
)`)
if err != nil {
return err
}
return nil
}
func (ds DataStore) GetMessage(toUID string, position int) protocol.ServerMessagePacket {
var serverMessage protocol.ServerMessagePacket
query := `
SELECT fromUID, toUID, content, timestamp
FROM messages
WHERE toUID = ?
AND status = 0
ORDER BY timestamp
LIMIT 1 OFFSET ?
`
// Execute the query
row := ds.db.QueryRow(query, toUID, position)
err := row.Scan(&serverMessage.FromUID, &serverMessage.ToUID, &serverMessage.Content, &serverMessage.Timestamp)
if err != nil {
log.Panicln("Could not map DB query to ServerMessage")
}
return serverMessage
}
func (ds DataStore) MarkMessageInQueueAsRead(toUID string, position int) error {
query := `
UPDATE messages
SET status = 1
WHERE toUID = ? AND status = 0
ORDER BY timestamp
LIMIT 1 OFFSET ?
`
// Execute the SQL statement
_, err := ds.db.Exec(query, toUID, position)
if err != nil {
return err
}
return nil
}
func (ds DataStore) GetAllMessages(toUID string) []protocol.Packet {
var messagePackets []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
`
// Execute the query
rows, err := ds.db.Query(query, toUID)
if err != nil {
log.Panicln("Failed to execute query:", err)
}
defer rows.Close()
// Iterate through the result set and scan each row into a ServerMessage struct
for rows.Next() {
var fromUID string
var toUID string
var content []byte
var timestamp time.Time
if err := rows.Scan(&fromUID, &toUID, &content, &timestamp); err != nil {
log.Panicln("Failed to scan row:", err)
}
message := protocol.NewMessagePacket(fromUID, toUID, content, timestamp)
messagePackets = append(messagePackets, message)
}
if err := rows.Err(); err != nil {
log.Panicln("Error when getting user's messages")
}
return messagePackets
}
func (ds DataStore) AddMessageToQueue(uid string, message protocol.SubmitMessagePacket) {
query := `
INSERT INTO messages (fromUID, toUID, content, timestamp, status)
VALUES (?, ?, ?, ?, 0)
`
// Execute the SQL statement
currentTime := time.Now()
_, err := ds.db.Exec(query, uid, message.ToUID, message.Content, currentTime)
if err != nil {
log.Panicln("Error adding message to database")
}
}
func (ds DataStore) GetUserCertificate(uid string) protocol.Packet {
query := `
SELECT userCert
FROM users
WHERE UID = ?
`
// 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")
}
return protocol.NewSendUserCertPacket(uid, userCert)
}

View file

@ -6,19 +6,23 @@ import (
"fmt" "fmt"
) )
func clientHandler(connection networking.Connection[protocol.Packet]) { func clientHandler(connection networking.Connection[protocol.Packet], dataStore DataStore) {
defer connection.Conn.Close() defer connection.Conn.Close()
// FIX: GET THE UID FROM THE USER CERTIFICATE FROM THE TLS SESSION
uid := "0"
for { for {
pac := connection.Receive() pac := connection.Receive()
switch pac.Flag { switch pac.Flag {
case protocol.ReqPK: case protocol.ReqUserCertPkt:
fmt.Println("ReqPK") userCertPacket := dataStore.GetUserCertificate(uid)
case protocol.ReqAllMsg: connection.Send(userCertPacket)
case protocol.ReqAllMsgPkt:
fmt.Println("ReqAllMsg") fmt.Println("ReqAllMsg")
case protocol.ReqMsg: case protocol.ReqMsgPkt:
fmt.Println("ReqMsg") fmt.Println("ReqMsg")
case protocol.SubmitMsg: case protocol.SubmitMsgPkt:
fmt.Println("SubmitMsg") fmt.Println("SubmitMsg")
} }
} }
@ -26,6 +30,11 @@ func clientHandler(connection networking.Connection[protocol.Packet]) {
} }
func Run(port int) { func Run(port int) {
//Open connection to DB
dataStore := OpenDB()
defer dataStore.db.Close()
//Create server listener
server := networking.NewServer[protocol.Packet](port) server := networking.NewServer[protocol.Packet](port)
go server.ListenLoop() go server.ListenLoop()
@ -33,6 +42,6 @@ func Run(port int) {
//Receive Connection via channel //Receive Connection via channel
conn := <-server.C conn := <-server.C
//Launch client handler via clientHandler //Launch client handler via clientHandler
go clientHandler(conn) go clientHandler(conn, dataStore)
} }
} }