diff --git a/scnserver/TODO.md b/scnserver/TODO.md index 5fde951..d8ae446 100644 --- a/scnserver/TODO.md +++ b/scnserver/TODO.md @@ -56,12 +56,14 @@ * [X] compat simply uses default-keys * [X] CRUD routes for keys * [X] KeyToken.messagecounter - * [ ] update old-data migration to create token-keys + * [x] update old-data migration to create token-keys * [ ] unit tests - We no longer have a route to reshuffle all keys (previously in updateUser), add a /user/:uid/keys/reset ? Would delete all existing keys and create 3 new ones? +- TODO comments + #### PERSONAL - in my script: use `srvname` for sendername diff --git a/scnserver/api/handler/message.go b/scnserver/api/handler/message.go index 9e0a893..65d2e73 100644 --- a/scnserver/api/handler/message.go +++ b/scnserver/api/handler/message.go @@ -242,7 +242,7 @@ func (h MessageHandler) sendMessageInternal(g *gin.Context, ctx *logic.AppContex clientIP := g.ClientIP() - msg, err := h.database.CreateMessage(ctx, *UserID, channel, sendTimestamp, *Title, Content, priority, UserMessageID, clientIP, SenderName) + msg, err := h.database.CreateMessage(ctx, *UserID, channel, sendTimestamp, *Title, Content, priority, UserMessageID, clientIP, SenderName, keytok.KeyTokenID) if err != nil { return nil, langext.Ptr(ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to create message in db", err)) } diff --git a/scnserver/cmd/migrate/main.go b/scnserver/cmd/migrate/main.go index bc32bd9..83064ad 100644 --- a/scnserver/cmd/migrate/main.go +++ b/scnserver/cmd/migrate/main.go @@ -195,21 +195,17 @@ func migrateUser(ctx context.Context, dbnew sq.DB, dbold sq.DB, user OldUser, ap fmt.Printf("New UserID: %s\n", userid) - readKey := scn.RandomAuthKey() - sendKey := scn.RandomAuthKey() - adminKey := user.UserKey + tokKeyID := models.NewKeyTokenID() + tokKeySec := user.UserKey protoken := user.ProToken if protoken != nil { protoken = langext.Ptr("ANDROID|v1|" + *protoken) } - _, err = dbnew.Exec(ctx, "INSERT INTO users (user_id, username, read_key, send_key, admin_key, is_pro, pro_token, timestamp_created) VALUES (:uid, :un, :rk, :sk, :ak, :pro, :tok, :ts)", sq.PP{ + _, err = dbnew.Exec(ctx, "INSERT INTO users (user_id, username, is_pro, pro_token, timestamp_created) VALUES (:uid, :un, :pro, :tok, :ts)", sq.PP{ "uid": userid, "un": nil, - "rk": readKey, - "sk": sendKey, - "ak": adminKey, "pro": langext.Conditional(user.IsPro, 1, 0), "tok": protoken, "ts": user.TimestampCreated.UnixMilli(), @@ -227,6 +223,20 @@ func migrateUser(ctx context.Context, dbnew sq.DB, dbold sq.DB, user OldUser, ap panic(err) } + _, err = dbnew.Exec(ctx, "INSERT INTO keytokens (keytoken_id, name, timestamp_created, owner_user_id, all_channels, channels, token, permissions) VALUES (:tid, :nam, :tsc, :owr, :all, :cha, :tok, :prm)", sq.PP{ + "tid": tokKeyID, + "nam": "AdminKey (migrated)", + "tsc": user.TimestampCreated.UnixMilli(), + "owr": userid, + "all": 1, + "cha": "", + "tok": tokKeySec, + "prm": "A", + }) + if err != nil { + panic(err) + } + var clientid *models.ClientID = nil if user.FcmToken != nil && *user.FcmToken != "BLACKLISTED" { @@ -260,15 +270,14 @@ func migrateUser(ctx context.Context, dbnew sq.DB, dbold sq.DB, user OldUser, ap } mainChannelID := models.NewChannelID() - _, err = dbnew.Exec(ctx, "INSERT INTO channels (channel_id, owner_user_id, display_name, internal_name, description_name, subscribe_key, send_key, timestamp_created) VALUES (:cid, :ouid, :dnam, :inam, :hnam, :subkey, :sendkey, :ts)", sq.PP{ - "cid": mainChannelID, - "ouid": userid, - "dnam": "main", - "inam": "main", - "hnam": nil, - "subkey": scn.RandomAuthKey(), - "sendkey": scn.RandomAuthKey(), - "ts": user.TimestampCreated.UnixMilli(), + _, err = dbnew.Exec(ctx, "INSERT INTO channels (channel_id, owner_user_id, display_name, internal_name, description_name, subscribe_key, timestamp_created) VALUES (:cid, :ouid, :dnam, :inam, :hnam, :subkey, :ts)", sq.PP{ + "cid": mainChannelID, + "ouid": userid, + "dnam": "main", + "inam": "main", + "hnam": nil, + "subkey": scn.RandomAuthKey(), + "ts": user.TimestampCreated.UnixMilli(), }) if err != nil { panic(err) @@ -334,15 +343,14 @@ func migrateUser(ctx context.Context, dbnew sq.DB, dbold sq.DB, user OldUser, ap channelID = models.NewChannelID() channelInternalName = intName - _, err = dbnew.Exec(ctx, "INSERT INTO channels (channel_id, owner_user_id, display_name, internal_name, description_name, subscribe_key, send_key, timestamp_created) VALUES (:cid, :ouid, :dnam, :inam, :hnam, :subkey, :sendkey, :ts)", sq.PP{ - "cid": channelID, - "ouid": userid, - "dnam": dispName, - "inam": intName, - "hnam": nil, - "subkey": scn.RandomAuthKey(), - "sendkey": scn.RandomAuthKey(), - "ts": oldmessage.TimestampReal.UnixMilli(), + _, err = dbnew.Exec(ctx, "INSERT INTO channels (channel_id, owner_user_id, display_name, internal_name, description_name, subscribe_key, timestamp_created) VALUES (:cid, :ouid, :dnam, :inam, :hnam, :subkey, :ts)", sq.PP{ + "cid": channelID, + "ouid": userid, + "dnam": dispName, + "inam": intName, + "hnam": nil, + "subkey": scn.RandomAuthKey(), + "ts": oldmessage.TimestampReal.UnixMilli(), }) if err != nil { panic(err) @@ -419,8 +427,9 @@ func migrateUser(ctx context.Context, dbnew sq.DB, dbold sq.DB, user OldUser, ap "umid": oldmessage.UsrMessageId, "ip": "", "snam": sendername, + "ukid": tokKeyID, } - _, err = dbnew.Exec(ctx, "INSERT INTO messages (message_id, sender_user_id, owner_user_id, channel_internal_name, channel_id, timestamp_real, timestamp_client, title, content, priority, usr_message_id, sender_ip, sender_name) VALUES (:mid, :suid, :ouid, :cnam, :cid, :tsr, :tsc, :tit, :cnt, :prio, :umid, :ip, :snam)", pp) + _, err = dbnew.Exec(ctx, "INSERT INTO messages (message_id, sender_user_id, owner_user_id, channel_internal_name, channel_id, timestamp_real, timestamp_client, title, content, priority, usr_message_id, sender_ip, sender_name, used_key_id) VALUES (:mid, :suid, :ouid, :cnam, :cid, :tsr, :tsc, :tit, :cnt, :prio, :umid, :ip, :snam, :ukid)", pp) if err != nil { jv, _ := json.MarshalIndent(pp, "", " ") fmt.Printf("%s", string(jv)) diff --git a/scnserver/db/impl/primary/messages.go b/scnserver/db/impl/primary/messages.go index cddb8f6..b60c9e3 100644 --- a/scnserver/db/impl/primary/messages.go +++ b/scnserver/db/impl/primary/messages.go @@ -56,7 +56,7 @@ func (db *Database) GetMessage(ctx TxContext, scnMessageID models.MessageID, all return msg, nil } -func (db *Database) CreateMessage(ctx TxContext, senderUserID models.UserID, channel models.Channel, timestampSend *time.Time, title string, content *string, priority int, userMsgId *string, senderIP string, senderName *string) (models.Message, error) { +func (db *Database) CreateMessage(ctx TxContext, senderUserID models.UserID, channel models.Channel, timestampSend *time.Time, title string, content *string, priority int, userMsgId *string, senderIP string, senderName *string, usedKeyID models.KeyTokenID) (models.Message, error) { tx, err := ctx.GetOrCreateTransaction(db) if err != nil { return models.Message{}, err @@ -66,7 +66,7 @@ func (db *Database) CreateMessage(ctx TxContext, senderUserID models.UserID, cha messageid := models.NewMessageID() - _, err = tx.Exec(ctx, "INSERT INTO messages (message_id, sender_user_id, owner_user_id, channel_internal_name, channel_id, timestamp_real, timestamp_client, title, content, priority, usr_message_id, sender_ip, sender_name) VALUES (:mid, :suid, :ouid, :cnam, :cid, :tsr, :tsc, :tit, :cnt, :prio, :umid, :ip, :snam)", sq.PP{ + _, err = tx.Exec(ctx, "INSERT INTO messages (message_id, sender_user_id, owner_user_id, channel_internal_name, channel_id, timestamp_real, timestamp_client, title, content, priority, usr_message_id, sender_ip, sender_name, used_key_id) VALUES (:mid, :suid, :ouid, :cnam, :cid, :tsr, :tsc, :tit, :cnt, :prio, :umid, :ip, :snam, :uk)", sq.PP{ "mid": messageid, "suid": senderUserID, "ouid": channel.OwnerUserID, @@ -80,6 +80,7 @@ func (db *Database) CreateMessage(ctx TxContext, senderUserID models.UserID, cha "umid": userMsgId, "ip": senderIP, "snam": senderName, + "uk": usedKeyID, }) if err != nil { return models.Message{}, err @@ -99,6 +100,7 @@ func (db *Database) CreateMessage(ctx TxContext, senderUserID models.UserID, cha Content: content, Priority: priority, UserMessageID: userMsgId, + UsedKeyID: usedKeyID, }, nil } diff --git a/scnserver/db/impl/primary/schema/schema_3.ddl b/scnserver/db/impl/primary/schema/schema_3.ddl index 38527e1..bbbc394 100644 --- a/scnserver/db/impl/primary/schema/schema_3.ddl +++ b/scnserver/db/impl/primary/schema/schema_3.ddl @@ -125,6 +125,8 @@ CREATE TABLE messages priority INTEGER CHECK(priority IN (0, 1, 2)) NOT NULL, usr_message_id TEXT NULL, + used_key_id TEXT NOT NULL, + deleted INTEGER CHECK(deleted IN (0, 1)) NOT NULL DEFAULT '0', PRIMARY KEY (message_id) @@ -139,6 +141,7 @@ CREATE INDEX "idx_messages_sendername" ON messages (sender_name COL CREATE INDEX "idx_messages_sendername_nc" ON messages (sender_name COLLATE NOCASE); CREATE INDEX "idx_messages_title" ON messages (title COLLATE BINARY); CREATE INDEX "idx_messages_title_nc" ON messages (title COLLATE NOCASE); +CREATE INDEX "idx_messages_usedkey" ON messages (owner_user_id, used_key_id); CREATE INDEX "idx_messages_deleted" ON messages (deleted); diff --git a/scnserver/models/keytoken.go b/scnserver/models/keytoken.go index cc477fa..c7dfe6f 100644 --- a/scnserver/models/keytoken.go +++ b/scnserver/models/keytoken.go @@ -11,7 +11,7 @@ import ( type TokenPerm string //@enum:type const ( - PermAdmin TokenPerm = "A" // Edit userdata (+ includes all othe permissions) + PermAdmin TokenPerm = "A" // Edit userdata (+ includes all other permissions) PermChannelRead TokenPerm = "CR" // Read messages PermChannelSend TokenPerm = "CS" // Send messages PermUserRead TokenPerm = "UR" // Read userdata diff --git a/scnserver/models/message.go b/scnserver/models/message.go index a79c50a..a171209 100644 --- a/scnserver/models/message.go +++ b/scnserver/models/message.go @@ -26,6 +26,7 @@ type Message struct { Content *string Priority int UserMessageID *string + UsedKeyID KeyTokenID Deleted bool } @@ -43,6 +44,7 @@ func (m Message) FullJSON() MessageJSON { Content: m.Content, Priority: m.Priority, UserMessageID: m.UserMessageID, + UsedKeyID: m.UsedKeyID, Trimmed: false, } } @@ -61,6 +63,7 @@ func (m Message) TrimmedJSON() MessageJSON { Content: m.TrimmedContent(), Priority: m.Priority, UserMessageID: m.UserMessageID, + UsedKeyID: m.UsedKeyID, Trimmed: m.NeedsTrim(), } } @@ -94,36 +97,38 @@ func (m Message) ShortContent() string { } type MessageJSON struct { - MessageID MessageID `json:"message_id"` - SenderUserID UserID `json:"sender_user_id"` - OwnerUserID UserID `json:"owner_user_id"` - ChannelInternalName string `json:"channel_internal_name"` - ChannelID ChannelID `json:"channel_id"` - SenderName *string `json:"sender_name"` - SenderIP string `json:"sender_ip"` - Timestamp string `json:"timestamp"` - Title string `json:"title"` - Content *string `json:"content"` - Priority int `json:"priority"` - UserMessageID *string `json:"usr_message_id"` - Trimmed bool `json:"trimmed"` + MessageID MessageID `json:"message_id"` + SenderUserID UserID `json:"sender_user_id"` + OwnerUserID UserID `json:"owner_user_id"` + ChannelInternalName string `json:"channel_internal_name"` + ChannelID ChannelID `json:"channel_id"` + SenderName *string `json:"sender_name"` + SenderIP string `json:"sender_ip"` + Timestamp string `json:"timestamp"` + Title string `json:"title"` + Content *string `json:"content"` + Priority int `json:"priority"` + UserMessageID *string `json:"usr_message_id"` + UsedKeyID KeyTokenID `json:"used_key_id"` + Trimmed bool `json:"trimmed"` } type MessageDB struct { - MessageID MessageID `db:"message_id"` - SenderUserID UserID `db:"sender_user_id"` - OwnerUserID UserID `db:"owner_user_id"` - ChannelInternalName string `db:"channel_internal_name"` - ChannelID ChannelID `db:"channel_id"` - SenderName *string `db:"sender_name"` - SenderIP string `db:"sender_ip"` - TimestampReal int64 `db:"timestamp_real"` - TimestampClient *int64 `db:"timestamp_client"` - Title string `db:"title"` - Content *string `db:"content"` - Priority int `db:"priority"` - UserMessageID *string `db:"usr_message_id"` - Deleted int `db:"deleted"` + MessageID MessageID `db:"message_id"` + SenderUserID UserID `db:"sender_user_id"` + OwnerUserID UserID `db:"owner_user_id"` + ChannelInternalName string `db:"channel_internal_name"` + ChannelID ChannelID `db:"channel_id"` + SenderName *string `db:"sender_name"` + SenderIP string `db:"sender_ip"` + TimestampReal int64 `db:"timestamp_real"` + TimestampClient *int64 `db:"timestamp_client"` + Title string `db:"title"` + Content *string `db:"content"` + Priority int `db:"priority"` + UserMessageID *string `db:"usr_message_id"` + UsedKeyID KeyTokenID `db:"used_key_id"` + Deleted int `db:"deleted"` } func (m MessageDB) Model() Message { @@ -141,6 +146,7 @@ func (m MessageDB) Model() Message { Content: m.Content, Priority: m.Priority, UserMessageID: m.UserMessageID, + UsedKeyID: m.UsedKeyID, Deleted: m.Deleted != 0, } } diff --git a/scnserver/models/messagefilter.go b/scnserver/models/messagefilter.go index a0c0012..d0b92f0 100644 --- a/scnserver/models/messagefilter.go +++ b/scnserver/models/messagefilter.go @@ -40,6 +40,7 @@ type MessageFilter struct { OnlyDeleted bool IncludeDeleted bool CompatAcknowledged *bool + UsedKeyID *[]KeyTokenID } func (f MessageFilter) SQL() (string, string, sq.PP, error) { @@ -220,6 +221,15 @@ func (f MessageFilter) SQL() (string, string, sq.PP, error) { } } + if f.UsedKeyID != nil { + filter := make([]string, 0) + for i, v := range *f.UsedKeyID { + filter = append(filter, fmt.Sprintf("(used_key_id = :usedkeyid_%d)", i)) + params[fmt.Sprintf("usedkeyid_%d", i)] = v + } + sqlClauses = append(sqlClauses, "("+strings.Join(filter, " OR ")+")") + } + if f.SearchString != nil { filter := make([]string, 0) for i, v := range *f.SearchString {