diff --git a/doc/api.oa3 b/doc/api.oa3 index be72727a..a6807fb1 100644 --- a/doc/api.oa3 +++ b/doc/api.oa3 @@ -4507,7 +4507,18 @@ components: value: type: string format: json string of Connect, Disconnect, Authenticate, or Profile - + + ContactStatus: + type: object + required: + - status + properties: + token: + type: string + status: + type: string + enum: [ pending, confirmed, requested, connecting, connected ] + DataMessage: type: object required: diff --git a/net/server/internal/api_addCard.go b/net/server/internal/api_addCard.go index 454eec97..b24f5714 100644 --- a/net/server/internal/api_addCard.go +++ b/net/server/internal/api_addCard.go @@ -35,42 +35,40 @@ func AddCard(w http.ResponseWriter, r *http.Request) { ErrResponse(w, http.StatusInternalServerError, err) return } + + // populate new record + card.CardId = uuid.New().String() + card.AccountID = account.ID + card.Guid = guid + card.Username = identity.Handle + card.Name = identity.Name + card.Description = identity.Description + card.Location = identity.Location + card.Image = identity.Image + card.Version = identity.Version + card.Node = identity.Node + card.ProfileRevision = identity.Revision + card.Status = APP_CARDCONFIRMED + } else { - // update record if revision changed - if identity.Revision > card.ProfileRevision { - card.Username = identity.Handle - card.Name = identity.Name - card.Description = identity.Description - card.Location = identity.Location - card.Image = identity.Image - card.Version = identity.Version - card.Node = identity.Node - card.ProfileRevision = identity.Revision - if err := store.DB.Save(&card).Error; err != nil { - ErrResponse(w, http.StatusInternalServerError, err) - return - } + if identity.Revision <= card.ProfileRevision { + WriteResponse(w, getCardModel(&card)) + return } - WriteResponse(w, getCardModel(&card)) - return + + // update record if revision changed + card.Username = identity.Handle + card.Name = identity.Name + card.Description = identity.Description + card.Location = identity.Location + card.Image = identity.Image + card.Version = identity.Version + card.Node = identity.Node + card.ProfileRevision = identity.Revision } - // save new record - card.CardId = uuid.New().String() - card.AccountID = account.ID - card.Guid = guid - card.Username = identity.Handle - card.Name = identity.Name - card.Description = identity.Description - card.Location = identity.Location - card.Image = identity.Image - card.Version = identity.Version - card.Node = identity.Node - card.ProfileRevision = identity.Revision - card.Status = APP_CARDCONFIRMED - - // save and update contact revision + // save contact card err = store.DB.Transaction(func(tx *gorm.DB) error { if res := store.DB.Save(&card).Error; res != nil { return res diff --git a/net/server/internal/api_contact.go b/net/server/internal/api_contact.go index 9c9d1e5d..5a8e8517 100644 --- a/net/server/internal/api_contact.go +++ b/net/server/internal/api_contact.go @@ -83,11 +83,6 @@ func SetContentRevision(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) } -func SetOpenMessage(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json; charset=UTF-8") - w.WriteHeader(http.StatusOK) -} - func SetProfileRevision(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=UTF-8") w.WriteHeader(http.StatusOK) diff --git a/net/server/internal/api_setOpenMessage.go b/net/server/internal/api_setOpenMessage.go new file mode 100644 index 00000000..c42e5326 --- /dev/null +++ b/net/server/internal/api_setOpenMessage.go @@ -0,0 +1,120 @@ +package databag + +import ( + "time" + "errors" + "net/http" + "gorm.io/gorm" + "github.com/google/uuid" + "databag/internal/store" +) + +func SetOpenMessage(w http.ResponseWriter, r *http.Request) { + + var message DataMessage + if err := ParseRequest(r, w, &message); err != nil { + ErrResponse(w, http.StatusBadRequest, err) + return + } + + var connect Connect + guid, messageType, ts, err := ReadDataMessage(&message, &connect) + if messageType != APP_MSGCONNECT || err != nil { + ErrResponse(w, http.StatusBadRequest, err) + return + } + if ts + APP_CONNECTEXPIRE < time.Now().Unix() { + ErrResponse(w, http.StatusBadRequest, errors.New("message has expired")) + return + } + + // load referenced account + var account store.Account + if err := store.DB.Where("guid = ?", connect.Contact).First(&account).Error; err != nil { + if !errors.Is(err, gorm.ErrRecordNotFound) { + ErrResponse(w, http.StatusInternalServerError, err) + } else { + ErrResponse(w, http.StatusNotFound, err) + } + return + } + + // see if card exists + var card store.Card + if err := store.DB.Where("account_id = ? AND guid = ?", account.ID, guid).First(&card).Error; err != nil { + if !errors.Is(err, gorm.ErrRecordNotFound) { + ErrResponse(w, http.StatusInternalServerError, err) + return + } + + // populate new record + card.CardId = uuid.New().String() + card.AccountID = account.ID + card.Guid = guid + card.Username = connect.Handle + card.Name = connect.Name + card.Description = connect.Description + card.Location = connect.Location + card.Image = connect.Image + card.Version = connect.Version + card.Node = connect.Node + card.ProfileRevision = connect.ProfileRevision + card.RemoteContent = connect.ContentRevision + card.RemoteProfile = connect.ProfileRevision + card.Status = APP_CARDPENDING + card.DataRevision = 1 + card.OutToken = connect.Token + + } else { + + // update profile if revision changed + if connect.ProfileRevision > card.ProfileRevision { + card.Username = connect.Handle + card.Name = connect.Name + card.Description = connect.Description + card.Location = connect.Location + card.Image = connect.Image + card.Version = connect.Version + card.Node = connect.Node + card.ProfileRevision = connect.ProfileRevision + } + if connect.ContentRevision > card.RemoteContent { + card.RemoteContent = connect.ContentRevision + } + if connect.ProfileRevision > card.RemoteProfile { + card.RemoteProfile = connect.ProfileRevision + } + if card.Status == APP_CARDCONFIRMED { + card.Status = APP_CARDREQUESTED + } + if card.Status == APP_CARDCONNECTING { + card.Status = APP_CARDCONNECTED + } + card.DataRevision += 1 + card.OutToken = connect.Token + + } + + // save contact card + err = store.DB.Transaction(func(tx *gorm.DB) error { + if res := store.DB.Save(&card).Error; res != nil { + return res + } + if res := store.DB.Model(&account).Update("card_revision", account.CardRevision + 1).Error; res != nil { + return res + } + return nil + }) + if err != nil { + ErrResponse(w, http.StatusInternalServerError, err) + return + } + + status := &ContactStatus{ + Token: card.InToken, + Status: card.Status, + } + SetStatus(&account) + WriteResponse(w, &status) +} + diff --git a/net/server/internal/appValues.go b/net/server/internal/appValues.go index f5fe6cad..a698fc10 100644 --- a/net/server/internal/appValues.go +++ b/net/server/internal/appValues.go @@ -4,6 +4,7 @@ const APP_BODYLIMIT = 1048576 const APP_VERSION = "0.0.1" const APP_ATTACHEXPIRE = 300 const APP_CREATEEXPIRE = 86400 +const APP_CONNECTEXPIRE = 30 const APP_KEYSIZE = 4096 const APP_RSA4096 = "RSA4096" const APP_RSA2048 = "RSA2048" diff --git a/net/server/internal/models.go b/net/server/internal/models.go index d3e04330..d7e81d74 100644 --- a/net/server/internal/models.go +++ b/net/server/internal/models.go @@ -278,6 +278,11 @@ type Tunnel struct { Data string `json:"data,omitempty"` } +type ContactStatus struct { + Token string `json:"token,omitempty"` + Status string `json:"status"` +} + type DataMessage struct { Message string `json:"message"` KeyType string `json:"keyType"` diff --git a/net/server/internal/ucConnectContact_test.go b/net/server/internal/ucConnectContact_test.go index cceb521c..f4e8c9ff 100644 --- a/net/server/internal/ucConnectContact_test.go +++ b/net/server/internal/ucConnectContact_test.go @@ -59,8 +59,6 @@ func TestConnectContact(t *testing.T) { assert.NotEqual(t, cardRevision, revision.Card) cardRevision = revision.Card -PrintMsg(revision) - // get open message to A r, w, _ = NewRequest("GET", "/contact/cards/{cardId}/openMessage", nil) vars = map[string]string{ "cardId": card.CardId } @@ -69,7 +67,13 @@ PrintMsg(revision) GetOpenMessage(w, r) assert.NoError(t, ReadResponse(w, &msg)) -PrintMsg(msg) + // set open message in A + r, w, _ = NewRequest("PUT", "/contact/openMessage", msg) + SetOpenMessage(w, r) + var contactStatus ContactStatus + assert.NoError(t, ReadResponse(w, &contactStatus)) + +PrintMsg(contactStatus) // A request B