diff --git a/Backend/Api/Auth/ChangeMessageExpiry.go b/Backend/Api/Auth/ChangeUserMessageExpiry.go similarity index 88% rename from Backend/Api/Auth/ChangeMessageExpiry.go rename to Backend/Api/Auth/ChangeUserMessageExpiry.go index aa2fd5e..4805519 100644 --- a/Backend/Api/Auth/ChangeMessageExpiry.go +++ b/Backend/Api/Auth/ChangeUserMessageExpiry.go @@ -13,8 +13,8 @@ type rawChangeMessageExpiry struct { MessageExpiry string `json:"message_expiry"` } -// ChangeMessageExpiry handles changing default message expiry for user -func ChangeMessageExpiry(w http.ResponseWriter, r *http.Request) { +// ChangeUserMessageExpiry handles changing default message expiry for user +func ChangeUserMessageExpiry(w http.ResponseWriter, r *http.Request) { var ( user Models.User changeMessageExpiry rawChangeMessageExpiry diff --git a/Backend/Api/Auth/ChangeMessageExpiry_test.go b/Backend/Api/Auth/ChangeUserMessageExpiry_test.go similarity index 97% rename from Backend/Api/Auth/ChangeMessageExpiry_test.go rename to Backend/Api/Auth/ChangeUserMessageExpiry_test.go index 2c48c75..ca13511 100644 --- a/Backend/Api/Auth/ChangeMessageExpiry_test.go +++ b/Backend/Api/Auth/ChangeUserMessageExpiry_test.go @@ -10,7 +10,7 @@ import ( "git.tovijaeschke.xyz/tovi/Capsule/Backend/Tests" ) -func Test_ChangeMessageExpiry(t *testing.T) { +func Test_ChangeUserMessageExpiry(t *testing.T) { client, ts, err := Tests.InitTestEnv() defer ts.Close() if err != nil { diff --git a/Backend/Api/Friends/AcceptFriendRequest_test.go b/Backend/Api/Friends/AcceptFriendRequest_test.go new file mode 100644 index 0000000..ff5c642 --- /dev/null +++ b/Backend/Api/Friends/AcceptFriendRequest_test.go @@ -0,0 +1,137 @@ +package Friends_test + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + "net/http" + "testing" + + "git.tovijaeschke.xyz/tovi/Capsule/Backend/Database" + "git.tovijaeschke.xyz/tovi/Capsule/Backend/Database/Seeder" + "git.tovijaeschke.xyz/tovi/Capsule/Backend/Models" + "git.tovijaeschke.xyz/tovi/Capsule/Backend/Tests" +) + +func Test_AcceptFriendRequest(t *testing.T) { + client, ts, err := Tests.InitTestEnv() + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + return + } + + u, err := Database.GetUserByUsername("test") + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + return + } + + u2, err := Tests.InitTestCreateUser("test2") + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + return + } + + key, err := Seeder.GenerateAesKey() + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + return + } + + decodedPublicKey := Seeder.GetPubKey() + + encPublicKey, err := key.AesEncrypt([]byte(Seeder.PublicKey)) + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + return + } + + friendReq := Models.FriendRequest{ + UserID: u.ID, + FriendID: base64.StdEncoding.EncodeToString( + Seeder.EncryptWithPublicKey( + []byte(u2.ID.String()), + decodedPublicKey, + ), + ), + FriendUsername: base64.StdEncoding.EncodeToString( + Seeder.EncryptWithPublicKey( + []byte(u2.Username), + decodedPublicKey, + ), + ), + FriendPublicAsymmetricKey: base64.StdEncoding.EncodeToString( + encPublicKey, + ), + SymmetricKey: base64.StdEncoding.EncodeToString( + Seeder.EncryptWithPublicKey(key.Key, decodedPublicKey), + ), + } + + err = Database.CreateFriendRequest(&friendReq) + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + return + } + + friendReqResponse := Models.FriendRequest{ + UserID: u2.ID, + FriendID: base64.StdEncoding.EncodeToString( + Seeder.EncryptWithPublicKey( + []byte(u.ID.String()), + decodedPublicKey, + ), + ), + FriendUsername: base64.StdEncoding.EncodeToString( + Seeder.EncryptWithPublicKey( + []byte(u.Username), + decodedPublicKey, + ), + ), + FriendPublicAsymmetricKey: base64.StdEncoding.EncodeToString( + encPublicKey, + ), + SymmetricKey: base64.StdEncoding.EncodeToString( + Seeder.EncryptWithPublicKey(key.Key, decodedPublicKey), + ), + } + + jsonStr, _ := json.Marshal(friendReqResponse) + req, _ := http.NewRequest( + "POST", + fmt.Sprintf( + "%s/api/v1/auth/friend_request/%s", + ts.URL, + friendReq.ID, + ), + bytes.NewBuffer(jsonStr), + ) + req.Header.Set("Content-Type", "application/json") + + resp, err := client.Do(req) + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + return + } + + if resp.StatusCode != http.StatusNoContent { + t.Errorf("Expected %d, recieved %d", http.StatusNoContent, resp.StatusCode) + return + } + + var reqs []Models.FriendRequest + + err = Database.DB.Find(&reqs).Error + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + return + } + + for _, r := range reqs { + if r.AcceptedAt.Valid != true { + t.Errorf("Expected true, recieved false") + return + } + } +} diff --git a/Backend/Api/Friends/CreateFriendRequest_test.go b/Backend/Api/Friends/CreateFriendRequest_test.go new file mode 100644 index 0000000..49b152e --- /dev/null +++ b/Backend/Api/Friends/CreateFriendRequest_test.go @@ -0,0 +1,204 @@ +package Friends_test + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "net/http" + "testing" + + "git.tovijaeschke.xyz/tovi/Capsule/Backend/Database" + "git.tovijaeschke.xyz/tovi/Capsule/Backend/Database/Seeder" + "git.tovijaeschke.xyz/tovi/Capsule/Backend/Models" + "git.tovijaeschke.xyz/tovi/Capsule/Backend/Tests" +) + +func Test_CreateFriendRequest(t *testing.T) { + client, ts, err := Tests.InitTestEnv() + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + return + } + + u, err := Database.GetUserByUsername("test") + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + return + } + + u2, err := Tests.InitTestCreateUser("test2") + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + return + } + + key, err := Seeder.GenerateAesKey() + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + return + } + + decodedPublicKey := Seeder.GetPubKey() + + encPublicKey, err := key.AesEncrypt([]byte(Seeder.PublicKey)) + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + return + } + + friendReq := Models.FriendRequest{ + UserID: u.ID, + FriendID: base64.StdEncoding.EncodeToString( + Seeder.EncryptWithPublicKey( + []byte(u2.ID.String()), + decodedPublicKey, + ), + ), + FriendUsername: base64.StdEncoding.EncodeToString( + Seeder.EncryptWithPublicKey( + []byte(u2.Username), + decodedPublicKey, + ), + ), + FriendPublicAsymmetricKey: base64.StdEncoding.EncodeToString( + encPublicKey, + ), + SymmetricKey: base64.StdEncoding.EncodeToString( + Seeder.EncryptWithPublicKey(key.Key, decodedPublicKey), + ), + } + + jsonStr, _ := json.Marshal(friendReq) + req, _ := http.NewRequest("POST", ts.URL+"/api/v1/auth/friend_request", bytes.NewBuffer(jsonStr)) + req.Header.Set("Content-Type", "application/json") + + resp, err := client.Do(req) + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + return + } + + if resp.StatusCode != http.StatusOK { + t.Errorf("Expected %d, recieved %d", http.StatusOK, resp.StatusCode) + return + } + + var r Models.FriendRequest + + err = Database.DB.First(&r).Error + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + return + } + + if r.AcceptedAt.Valid == true { + t.Errorf("Expected false, recieved true") + return + } +} + +func Test_CreateFriendRequestQrCode(t *testing.T) { + client, ts, err := Tests.InitTestEnv() + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + return + } + + u, err := Database.GetUserByUsername("test") + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + return + } + + u2, err := Tests.InitTestCreateUser("test2") + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + return + } + + key, err := Seeder.GenerateAesKey() + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + return + } + + decodedPublicKey := Seeder.GetPubKey() + + encPublicKey, err := key.AesEncrypt([]byte(Seeder.PublicKey)) + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + return + } + + friendReq := Models.FriendRequest{ + UserID: u.ID, + FriendID: base64.StdEncoding.EncodeToString( + Seeder.EncryptWithPublicKey( + []byte(u2.ID.String()), + decodedPublicKey, + ), + ), + FriendUsername: base64.StdEncoding.EncodeToString( + Seeder.EncryptWithPublicKey( + []byte(u2.Username), + decodedPublicKey, + ), + ), + FriendPublicAsymmetricKey: base64.StdEncoding.EncodeToString( + encPublicKey, + ), + SymmetricKey: base64.StdEncoding.EncodeToString( + Seeder.EncryptWithPublicKey(key.Key, decodedPublicKey), + ), + } + + friendReq2 := Models.FriendRequest{ + UserID: u2.ID, + FriendID: base64.StdEncoding.EncodeToString( + Seeder.EncryptWithPublicKey( + []byte(u.ID.String()), + decodedPublicKey, + ), + ), + FriendUsername: base64.StdEncoding.EncodeToString( + Seeder.EncryptWithPublicKey( + []byte(u.Username), + decodedPublicKey, + ), + ), + FriendPublicAsymmetricKey: base64.StdEncoding.EncodeToString( + encPublicKey, + ), + SymmetricKey: base64.StdEncoding.EncodeToString( + Seeder.EncryptWithPublicKey(key.Key, decodedPublicKey), + ), + } + + jsonStr, _ := json.Marshal([]Models.FriendRequest{friendReq, friendReq2}) + req, _ := http.NewRequest("POST", ts.URL+"/api/v1/auth/friend_request/qr_code", bytes.NewBuffer(jsonStr)) + req.Header.Set("Content-Type", "application/json") + + resp, err := client.Do(req) + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + return + } + + if resp.StatusCode != http.StatusOK { + t.Errorf("Expected %d, recieved %d", http.StatusOK, resp.StatusCode) + return + } + + var r Models.FriendRequest + + err = Database.DB.First(&r).Error + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + return + } + + if r.AcceptedAt.Valid == false { + t.Errorf("Expected true, recieved false") + return + } +} diff --git a/Backend/Api/Friends/FriendRequest.go b/Backend/Api/Friends/FriendRequest.go deleted file mode 100644 index c704800..0000000 --- a/Backend/Api/Friends/FriendRequest.go +++ /dev/null @@ -1,60 +0,0 @@ -package Friends - -import ( - "encoding/json" - "io/ioutil" - "net/http" - - "git.tovijaeschke.xyz/tovi/Capsule/Backend/Database" - "git.tovijaeschke.xyz/tovi/Capsule/Backend/Models" - "git.tovijaeschke.xyz/tovi/Capsule/Backend/Util" -) - -func FriendRequest(w http.ResponseWriter, r *http.Request) { - var ( - user Models.User - requestBody []byte - requestJson map[string]interface{} - friendID string - friendRequest Models.FriendRequest - ok bool - err error - ) - - user, err = Util.GetUserById(w, r) - if err != nil { - http.Error(w, "Not Found", http.StatusNotFound) - return - } - - requestBody, err = ioutil.ReadAll(r.Body) - if err != nil { - http.Error(w, "Not Found", http.StatusNotFound) - return - } - - json.Unmarshal(requestBody, &requestJson) - if requestJson["id"] == nil { - http.Error(w, "Invalid Data", http.StatusBadRequest) - return - } - - friendID, ok = requestJson["id"].(string) - if !ok { - http.Error(w, "Error", http.StatusInternalServerError) - return - } - - friendRequest = Models.FriendRequest{ - UserID: user.ID, - FriendID: friendID, - } - - err = Database.CreateFriendRequest(&friendRequest) - if requestJson["id"] == nil { - http.Error(w, "Error", http.StatusInternalServerError) - return - } - - w.WriteHeader(http.StatusNoContent) -} diff --git a/Backend/Api/Friends/Friends_test.go b/Backend/Api/Friends/Friends_test.go index d18de12..ee177b8 100644 --- a/Backend/Api/Friends/Friends_test.go +++ b/Backend/Api/Friends/Friends_test.go @@ -28,17 +28,17 @@ func Test_FriendRequestList(t *testing.T) { return } + key, err := Seeder.GenerateAesKey() + if err != nil { + t.Errorf("Expected nil, recieved %s", err.Error()) + return + } + for i := 0; i < 30; i++ { u2, err := Tests.InitTestCreateUser(fmt.Sprintf("test%d", i)) decodedPublicKey := Seeder.GetPubKey() - key, err := Seeder.GenerateAesKey() - if err != nil { - t.Errorf("Expected nil, recieved %s", err.Error()) - return - } - encPublicKey, err := key.AesEncrypt([]byte(Seeder.PublicKey)) if err != nil { t.Errorf("Expected nil, recieved %s", err.Error()) diff --git a/Backend/Api/Messages/ChangeConversationMessageExpiry.go b/Backend/Api/Messages/ChangeConversationMessageExpiry.go new file mode 100644 index 0000000..b589590 --- /dev/null +++ b/Backend/Api/Messages/ChangeConversationMessageExpiry.go @@ -0,0 +1,74 @@ +package Messages + +import ( + "encoding/json" + "io/ioutil" + "net/http" + + "git.tovijaeschke.xyz/tovi/Capsule/Backend/Database" + "git.tovijaeschke.xyz/tovi/Capsule/Backend/Models" + "github.com/gorilla/mux" +) + +type rawChangeMessageExpiry struct { + MessageExpiry string `json:"message_expiry"` +} + +// ChangeUserMessageExpiry handles changing default message expiry for user +func ChangeConversationMessageExpiry(w http.ResponseWriter, r *http.Request) { + var ( + // user Models.User + changeMessageExpiry rawChangeMessageExpiry + conversationDetail Models.ConversationDetail + requestBody []byte + urlVars map[string]string + detailID string + ok bool + err error + ) + + urlVars = mux.Vars(r) + detailID, ok = urlVars["detailID"] + if !ok { + http.Error(w, "Not Found", http.StatusNotFound) + return + } + + conversationDetail, err = Database.GetConversationDetailByID(detailID) + if err != nil { + http.Error(w, "Not Found", http.StatusNotFound) + return + } + + // Ignore error here, as middleware should handle auth + // TODO: Check if user in conversation + // user, _ = Auth.CheckCookieCurrentUser(w, r) + + requestBody, err = ioutil.ReadAll(r.Body) + if err != nil { + http.Error(w, "Error", http.StatusInternalServerError) + return + } + + err = json.Unmarshal(requestBody, &changeMessageExpiry) + if err != nil { + http.Error(w, "Error", http.StatusInternalServerError) + return + } + + err = conversationDetail.MessageExpiryDefault.Scan(changeMessageExpiry.MessageExpiry) + if err != nil { + http.Error(w, "Error", http.StatusUnprocessableEntity) + return + } + + err = Database.UpdateConversationDetail( + &conversationDetail, + ) + if err != nil { + http.Error(w, "Error", http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusNoContent) +} diff --git a/Backend/Api/Messages/Conversations.go b/Backend/Api/Messages/Conversations.go index 1639111..03da54e 100644 --- a/Backend/Api/Messages/Conversations.go +++ b/Backend/Api/Messages/Conversations.go @@ -1,6 +1,7 @@ package Messages import ( + "database/sql/driver" "encoding/json" "net/http" "net/url" @@ -58,6 +59,7 @@ func ConversationDetailsList(w http.ResponseWriter, r *http.Request) { detail Models.ConversationDetail query url.Values conversationIds []string + messageExpiryRaw driver.Value returnJSON []byte i int ok bool @@ -82,6 +84,9 @@ func ConversationDetailsList(w http.ResponseWriter, r *http.Request) { } for i, detail = range conversationDetails { + messageExpiryRaw, _ = detail.MessageExpiryDefault.Value() + conversationDetails[i].MessageExpiry, _ = messageExpiryRaw.(string) + if detail.AttachmentID == nil { continue } diff --git a/Backend/Api/Messages/CreateMessage.go b/Backend/Api/Messages/CreateMessage.go index 04cb15e..faf6dad 100644 --- a/Backend/Api/Messages/CreateMessage.go +++ b/Backend/Api/Messages/CreateMessage.go @@ -44,14 +44,12 @@ func CreateMessage(w http.ResponseWriter, r *http.Request) { for i, message = range messageData.Messages { t, err = time.Parse("2006-01-02T15:04:05Z", message.ExpiryRaw) - if err != nil { - http.Error(w, "Error", http.StatusInternalServerError) - return - } - err = messageData.Messages[i].Expiry.Scan(t) - if err != nil { - http.Error(w, "Error", http.StatusInternalServerError) - return + if err == nil { + err = messageData.Messages[i].Expiry.Scan(t) + if err != nil { + http.Error(w, "Error", http.StatusInternalServerError) + return + } } } diff --git a/Backend/Api/Routes.go b/Backend/Api/Routes.go index 73d98f4..5fd7ab6 100644 --- a/Backend/Api/Routes.go +++ b/Backend/Api/Routes.go @@ -63,7 +63,7 @@ func InitAPIEndpoints(router *mux.Router) { authAPI.HandleFunc("/check", Auth.Check).Methods("GET") authAPI.HandleFunc("/change_password", Auth.ChangePassword).Methods("POST") - authAPI.HandleFunc("/message_expiry", Auth.ChangeMessageExpiry).Methods("POST") + authAPI.HandleFunc("/message_expiry", Auth.ChangeUserMessageExpiry).Methods("POST") authAPI.HandleFunc("/image", Auth.AddProfileImage).Methods("POST") authAPI.HandleFunc("/users", Users.SearchUsers).Methods("GET") @@ -79,6 +79,7 @@ func InitAPIEndpoints(router *mux.Router) { authAPI.HandleFunc("/conversations", Messages.CreateConversation).Methods("POST") authAPI.HandleFunc("/conversations", Messages.UpdateConversation).Methods("PUT") authAPI.HandleFunc("/conversations/{detailID}/image", Messages.AddConversationImage).Methods("POST") + authAPI.HandleFunc("/conversations/{detailID}/message_expiry", Messages.ChangeConversationMessageExpiry).Methods("POST") authAPI.HandleFunc("/message", Messages.CreateMessage).Methods("POST") authAPI.HandleFunc("/messages/{associationKey}", Messages.Messages).Methods("GET") diff --git a/Backend/Database/ConversationDetails.go b/Backend/Database/ConversationDetails.go index 811fa62..7de9fe5 100644 --- a/Backend/Database/ConversationDetails.go +++ b/Backend/Database/ConversationDetails.go @@ -10,51 +10,51 @@ import ( // GetConversationDetailByID gets by id func GetConversationDetailByID(id string) (Models.ConversationDetail, error) { var ( - messageThread Models.ConversationDetail - err error + conversationDetail Models.ConversationDetail + err error ) err = DB.Preload(clause.Associations). Where("id = ?", id). - First(&messageThread). + First(&conversationDetail). Error - return messageThread, err + return conversationDetail, err } // GetConversationDetailsByIds gets by multiple ids func GetConversationDetailsByIds(id []string) ([]Models.ConversationDetail, error) { var ( - messageThread []Models.ConversationDetail - err error + conversationDetail []Models.ConversationDetail + err error ) err = DB.Preload(clause.Associations). Where("id IN ?", id). - Find(&messageThread). + Find(&conversationDetail). Error - return messageThread, err + return conversationDetail, err } // CreateConversationDetail creates a ConversationDetail record -func CreateConversationDetail(messageThread *Models.ConversationDetail) error { +func CreateConversationDetail(conversationDetail *Models.ConversationDetail) error { return DB.Session(&gorm.Session{FullSaveAssociations: true}). - Create(messageThread). + Create(conversationDetail). Error } // UpdateConversationDetail updates a ConversationDetail record -func UpdateConversationDetail(messageThread *Models.ConversationDetail) error { +func UpdateConversationDetail(conversationDetail *Models.ConversationDetail) error { return DB.Session(&gorm.Session{FullSaveAssociations: true}). - Where("id = ?", messageThread.ID). - Updates(messageThread). + Where("id = ?", conversationDetail.ID). + Updates(conversationDetail). Error } // DeleteConversationDetail deletes a ConversationDetail record -func DeleteConversationDetail(messageThread *Models.ConversationDetail) error { +func DeleteConversationDetail(conversationDetail *Models.ConversationDetail) error { return DB.Session(&gorm.Session{FullSaveAssociations: true}). - Delete(messageThread). + Delete(conversationDetail). Error } diff --git a/Backend/Database/Seeder/FriendSeeder.go b/Backend/Database/Seeder/FriendSeeder.go index 43cdd0f..cc5edee 100644 --- a/Backend/Database/Seeder/FriendSeeder.go +++ b/Backend/Database/Seeder/FriendSeeder.go @@ -90,10 +90,10 @@ func SeedFriends() { err error ) - err = copyProfileImage() - if err != nil { - panic(err) - } + // err = copyProfileImage() + // if err != nil { + // panic(err) + // } primaryUser, err = Database.GetUserByUsername("testUser") if err != nil { diff --git a/Backend/Dockerfile b/Backend/Dockerfile index 9fea42e..71c43c5 100644 --- a/Backend/Dockerfile +++ b/Backend/Dockerfile @@ -6,11 +6,9 @@ COPY ./ /go/src/git.tovijaeschke.xyz/Capsule/Backend WORKDIR /go/src/git.tovijaeschke.xyz/Capsule/Backend -# For "go test" -RUN apk add gcc libc-dev +# For "go test" and development +RUN apk add gcc libc-dev inotify-tools RUN go mod download -RUN go build -o /go/bin/capsule-server main.go - -CMD [ "/go/bin/capsule-server" ] +CMD [ "sh", "./dev.sh" ] diff --git a/Backend/Dockerfile.prod b/Backend/Dockerfile.prod new file mode 100644 index 0000000..9fea42e --- /dev/null +++ b/Backend/Dockerfile.prod @@ -0,0 +1,16 @@ +FROM golang:1.19-alpine + +RUN mkdir -p /go/src/git.tovijaeschke.xyz/Capsule/Backend + +COPY ./ /go/src/git.tovijaeschke.xyz/Capsule/Backend + +WORKDIR /go/src/git.tovijaeschke.xyz/Capsule/Backend + +# For "go test" +RUN apk add gcc libc-dev + +RUN go mod download + +RUN go build -o /go/bin/capsule-server main.go + +CMD [ "/go/bin/capsule-server" ] diff --git a/Backend/Models/Conversations.go b/Backend/Models/Conversations.go index 6df37ec..bc6ff3a 100644 --- a/Backend/Models/Conversations.go +++ b/Backend/Models/Conversations.go @@ -9,11 +9,13 @@ import ( // ConversationDetail stores the name for the conversation type ConversationDetail struct { Base - Name string `gorm:"not null" json:"name"` // Stored encrypted - Users []ConversationDetailUser ` json:"users"` - TwoUser string `gorm:"not null" json:"two_user"` - AttachmentID *uuid.UUID ` json:"attachment_id"` - Attachment Attachment ` json:"attachment"` + Name string `gorm:"not null" json:"name"` // Stored encrypted + Users []ConversationDetailUser ` json:"users"` + TwoUser string `gorm:"not null" json:"two_user"` + AttachmentID *uuid.UUID ` json:"attachment_id"` + Attachment Attachment ` json:"attachment"` + MessageExpiryDefault MessageExpiry `gorm:"default:no_expiry" json:"-" sql:"type:ENUM('fifteen_min', 'thirty_min', 'one_hour', 'three_hour', 'six_hour', 'twelve_hour', 'one_day', 'three_day', 'no_expiry')"` // Stored encrypted + MessageExpiry string `gorm:"-" json:"message_expiry"` // Stored encrypted } // ConversationDetailUser all users associated with a customer diff --git a/Backend/Models/MessageExpiry.go b/Backend/Models/MessageExpiry.go new file mode 100644 index 0000000..4d25ccc --- /dev/null +++ b/Backend/Models/MessageExpiry.go @@ -0,0 +1,70 @@ +package Models + +import ( + "database/sql/driver" + "errors" +) + +// MessageExpiry holds values for how long messages should expire by default +type MessageExpiry []uint8 + +const ( + // MessageExpiryFifteenMin expires after 15 minutes + MessageExpiryFifteenMin = "fifteen_min" + // MessageExpiryThirtyMin expires after 30 minutes + MessageExpiryThirtyMin = "thirty_min" + // MessageExpiryOneHour expires after one hour + MessageExpiryOneHour = "one_hour" + // MessageExpiryThreeHour expires after three hours + MessageExpiryThreeHour = "three_hour" + // MessageExpirySixHour expires after six hours + MessageExpirySixHour = "six_hour" + // MessageExpiryTwelveHour expires after twelve hours + MessageExpiryTwelveHour = "twelve_hour" + // MessageExpiryOneDay expires after one day + MessageExpiryOneDay = "one_day" + // MessageExpiryThreeDay expires after three days + MessageExpiryThreeDay = "three_day" + // MessageExpiryNoExpiry never expires + MessageExpiryNoExpiry = "no_expiry" +) + +// MessageExpiryValues list of all expiry values for validation +var MessageExpiryValues = []string{ + MessageExpiryFifteenMin, + MessageExpiryThirtyMin, + MessageExpiryOneHour, + MessageExpiryThreeHour, + MessageExpirySixHour, + MessageExpiryTwelveHour, + MessageExpiryOneDay, + MessageExpiryThreeDay, + MessageExpiryNoExpiry, +} + +// Scan new value into MessageExpiry +func (e *MessageExpiry) Scan(value interface{}) error { + var ( + strValue = value.(string) + m string + ) + + for _, m = range MessageExpiryValues { + if strValue != m { + continue + } + *e = MessageExpiry(strValue) + return nil + } + + return errors.New("Invalid MessageExpiry value") +} + +// Value gets value out of MessageExpiry column +func (e MessageExpiry) Value() (driver.Value, error) { + return string(e), nil +} + +func (e MessageExpiry) String() string { + return string(e) +} diff --git a/Backend/Models/Users.go b/Backend/Models/Users.go index 736289e..fa587d4 100644 --- a/Backend/Models/Users.go +++ b/Backend/Models/Users.go @@ -1,84 +1,20 @@ package Models import ( - "database/sql/driver" - "errors" - "github.com/gofrs/uuid" "gorm.io/gorm" ) -// BeforeUpdate prevents updating the email if it has not changed +// BeforeUpdate prevents updating the username or email if it has not changed // This stops a unique constraint error func (u *User) BeforeUpdate(tx *gorm.DB) (err error) { if !tx.Statement.Changed("Username") { tx.Statement.Omit("Username") } - return nil -} - -// MessageExpiry holds values for how long messages should expire by default -type MessageExpiry []uint8 - -const ( - // MessageExpiryFifteenMin expires after 15 minutes - MessageExpiryFifteenMin = "fifteen_min" - // MessageExpiryThirtyMin expires after 30 minutes - MessageExpiryThirtyMin = "thirty_min" - // MessageExpiryOneHour expires after one hour - MessageExpiryOneHour = "one_hour" - // MessageExpiryThreeHour expires after three hours - MessageExpiryThreeHour = "three_hour" - // MessageExpirySixHour expires after six hours - MessageExpirySixHour = "six_hour" - // MessageExpiryTwelveHour expires after twelve hours - MessageExpiryTwelveHour = "twelve_hour" - // MessageExpiryOneDay expires after one day - MessageExpiryOneDay = "one_day" - // MessageExpiryThreeDay expires after three days - MessageExpiryThreeDay = "three_day" - // MessageExpiryNoExpiry never expires - MessageExpiryNoExpiry = "no_expiry" -) - -// MessageExpiryValues list of all expiry values for validation -var MessageExpiryValues = []string{ - MessageExpiryFifteenMin, - MessageExpiryThirtyMin, - MessageExpiryOneHour, - MessageExpiryThreeHour, - MessageExpirySixHour, - MessageExpiryTwelveHour, - MessageExpiryOneDay, - MessageExpiryThreeDay, - MessageExpiryNoExpiry, -} - -// Scan new value into MessageExpiry -func (e *MessageExpiry) Scan(value interface{}) error { - var ( - strValue = value.(string) - m string - ) - - for _, m = range MessageExpiryValues { - if strValue != m { - continue - } - *e = MessageExpiry(strValue) - return nil + if !tx.Statement.Changed("Email") { + tx.Statement.Omit("Email") } - - return errors.New("Invalid MessageExpiry value") -} - -// Value gets value out of MessageExpiry column -func (e MessageExpiry) Value() (driver.Value, error) { - return string(e), nil -} - -func (e MessageExpiry) String() string { - return string(e) + return nil } // User holds user data @@ -87,19 +23,11 @@ type User struct { Username string `gorm:"not null;unique" json:"username"` Password string `gorm:"not null" json:"password"` ConfirmPassword string `gorm:"-" json:"confirm_password"` + Email string ` json:"email"` AsymmetricPrivateKey string `gorm:"not null" json:"asymmetric_private_key"` // Stored encrypted AsymmetricPublicKey string `gorm:"not null" json:"asymmetric_public_key"` SymmetricKey string `gorm:"not null" json:"symmetric_key"` // Stored encrypted AttachmentID *uuid.UUID ` json:"attachment_id"` Attachment Attachment ` json:"attachment"` - MessageExpiryDefault MessageExpiry `gorm:"default:no_expiry" json:"-" sql:"type:ENUM( - 'fifteen_min', - 'thirty_min', - 'one_hour', - 'three_hour', - 'six_hour', - 'twelve_hour', - 'one_day', - 'three_day' - )"` // Stored encrypted + MessageExpiryDefault MessageExpiry `gorm:"default:no_expiry" json:"-" sql:"type:ENUM('fifteen_min', 'thirty_min', 'one_hour', 'three_hour', 'six_hour', 'twelve_hour', 'one_day', 'three_day', 'no_expiry')"` // Stored encrypted } diff --git a/Backend/dev.sh b/Backend/dev.sh new file mode 100644 index 0000000..8b41296 --- /dev/null +++ b/Backend/dev.sh @@ -0,0 +1,8 @@ +#!/bin/sh +while true; do + go build main.go + ./main & + PID=$! + inotifywait -r -e modify . + kill $PID +done diff --git a/Backend/main b/Backend/main new file mode 100755 index 0000000000000000000000000000000000000000..8bb2fa56e17b9b4ad0e2ed4017b2337ca23778dd GIT binary patch literal 13716931 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