fix: handle opaque attachment references
This commit is contained in:
@@ -43,6 +43,7 @@ func runDBVerify(ctx context.Context, coordinatorPath, output, tenantCode, dsnEn
|
|||||||
var coordinator struct {
|
var coordinator struct {
|
||||||
Start StartInfo `json:"start"`
|
Start StartInfo `json:"start"`
|
||||||
Ledgers map[string][]AcceptedMessage `json:"ledgers"`
|
Ledgers map[string][]AcceptedMessage `json:"ledgers"`
|
||||||
|
Observed map[string][]AcceptedMessage `json:"observed"`
|
||||||
}
|
}
|
||||||
if err = json.Unmarshal(raw, &coordinator); err != nil {
|
if err = json.Unmarshal(raw, &coordinator); err != nil {
|
||||||
return fmt.Errorf("decode coordinator: %w", err)
|
return fmt.Errorf("decode coordinator: %w", err)
|
||||||
@@ -77,19 +78,13 @@ func runDBVerify(ctx context.Context, coordinatorPath, output, tenantCode, dsnEn
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := make(map[string]AcceptedMessage)
|
expected := expectedDBMessages(coordinator.Start.RunID, coordinator.Ledgers, coordinator.Observed)
|
||||||
months := make(map[string]struct{})
|
months := make(map[string]struct{})
|
||||||
for _, ledger := range coordinator.Ledgers {
|
for _, message := range expected {
|
||||||
for _, message := range ledger {
|
|
||||||
if message.RunID != coordinator.Start.RunID {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
expected[message.ClientMid] = message
|
|
||||||
if message.Kind == "group" {
|
if message.Kind == "group" {
|
||||||
months[message.SentAt.UTC().Format("200601")] = struct{}{}
|
months[message.SentAt.UTC().Format("200601")] = struct{}{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
tables := []string{fmt.Sprintf("im_%03d_messages", tenantID)}
|
tables := []string{fmt.Sprintf("im_%03d_messages", tenantID)}
|
||||||
for month := range months {
|
for month := range months {
|
||||||
tables = append(tables, fmt.Sprintf("im_%03d_group_messages_%s", tenantID, month))
|
tables = append(tables, fmt.Sprintf("im_%03d_group_messages_%s", tenantID, month))
|
||||||
@@ -167,3 +162,20 @@ func runDBVerify(ctx context.Context, coordinatorPath, output, tenantCode, dsnEn
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func expectedDBMessages(runID string, ledgers, observed map[string][]AcceptedMessage) map[string]AcceptedMessage {
|
||||||
|
all := make([]AcceptedMessage, 0)
|
||||||
|
for _, messages := range observed {
|
||||||
|
all = append(all, messages...)
|
||||||
|
}
|
||||||
|
for _, messages := range ledgers {
|
||||||
|
all = append(all, messages...)
|
||||||
|
}
|
||||||
|
expected := make(map[string]AcceptedMessage, len(all))
|
||||||
|
for _, message := range mergeMessageLedgers(nil, all) {
|
||||||
|
if message.RunID == runID && message.ClientMid != "" {
|
||||||
|
expected[message.ClientMid] = message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return expected
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestExpectedDBMessagesIncludesObservedWithoutAck(t *testing.T) {
|
||||||
|
ledgers := map[string][]AcceptedMessage{
|
||||||
|
"a": {{RunID: "run-1", ClientMid: "acked", Topic: "grp-one", Seq: 1}},
|
||||||
|
}
|
||||||
|
observed := map[string][]AcceptedMessage{
|
||||||
|
"a": {
|
||||||
|
{RunID: "run-1", ClientMid: "unacked", Topic: "grp-one", Seq: 2},
|
||||||
|
{RunID: "other", ClientMid: "foreign", Topic: "grp-one", Seq: 3},
|
||||||
|
},
|
||||||
|
"b": {{RunID: "run-1", ClientMid: "unacked", Topic: "grp-one", Seq: 2}},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := expectedDBMessages("run-1", ledgers, observed)
|
||||||
|
if len(expected) != 2 {
|
||||||
|
t.Fatalf("expected messages=%d want=2: %+v", len(expected), expected)
|
||||||
|
}
|
||||||
|
if expected["acked"].Seq != 1 || expected["unacked"].Seq != 2 {
|
||||||
|
t.Fatalf("unexpected merged messages: %+v", expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package store
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/tinode/chat/server/store/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFileLinkUserIDAllowsOpaqueTopicReferences(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
topic string
|
||||||
|
isUser bool
|
||||||
|
wantUID types.Uid
|
||||||
|
}{
|
||||||
|
{name: "cultivate reference", topic: "cvpbzxw1aio4ni8x0"},
|
||||||
|
{name: "short opaque reference", topic: "x"},
|
||||||
|
{name: "empty reference", topic: ""},
|
||||||
|
{name: "user reference", topic: types.Uid(42).UserId(), isUser: true, wantUID: types.Uid(42)},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
gotUID, gotIsUser := fileLinkUserID(test.topic)
|
||||||
|
if gotIsUser != test.isUser || gotUID != test.wantUID {
|
||||||
|
t.Fatalf("fileLinkUserID(%q) = (%v, %v), want (%v, %v)", test.topic, gotUID, gotIsUser, test.wantUID, test.isUser)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
-2
@@ -4684,8 +4684,8 @@ func (fileMapper) LinkAttachments(tenantID types.TenantID, topic string, msgId t
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
userId := types.ZeroUid
|
userId := types.ZeroUid
|
||||||
if topic != "" && types.GetTopicCat(topic) == types.TopicCatMe {
|
if parsedUserID, ok := fileLinkUserID(topic); ok {
|
||||||
userId = types.ParseUserId(topic)
|
userId = parsedUserID
|
||||||
topic = ""
|
topic = ""
|
||||||
}
|
}
|
||||||
return tenantAdp.TenantFileLinkAttachments(tenantID, topic, userId, msgId, fids)
|
return tenantAdp.TenantFileLinkAttachments(tenantID, topic, userId, msgId, fids)
|
||||||
@@ -4693,6 +4693,14 @@ func (fileMapper) LinkAttachments(tenantID types.TenantID, topic string, msgId t
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// File link topics may also be opaque retention keys, such as cultivate's cvp prefix.
|
||||||
|
func fileLinkUserID(topic string) (types.Uid, bool) {
|
||||||
|
if !strings.HasPrefix(topic, "usr") {
|
||||||
|
return types.ZeroUid, false
|
||||||
|
}
|
||||||
|
return types.ParseUserId(topic), true
|
||||||
|
}
|
||||||
|
|
||||||
func (fileMapper) UserHasAccess(tenantID types.TenantID, fid string, uid types.Uid) (bool, error) {
|
func (fileMapper) UserHasAccess(tenantID types.TenantID, fid string, uid types.Uid) (bool, error) {
|
||||||
if fid == "" || uid.IsZero() {
|
if fid == "" || uid.IsZero() {
|
||||||
return false, types.ErrMalformed
|
return false, types.ErrMalformed
|
||||||
|
|||||||
Reference in New Issue
Block a user