diff --git a/internal/attachments/mime.go b/internal/attachments/mime.go index 90f7539..ed42dd1 100644 --- a/internal/attachments/mime.go +++ b/internal/attachments/mime.go @@ -119,26 +119,8 @@ func IsImageType(mimeType string) bool { return imageTypes[mimeType] } -// IsAllowedType returns true if the MIME type is allowed for upload. -// Allowed: image/*, application/pdf, text/*. +// IsAllowedType returns true for all MIME types. Any file type is allowed; +// only size is restricted (50 MB max). func IsAllowedType(mimeType string) bool { - // Normalize: strip parameters like "; charset=utf-8". - base := mimeType - if idx := strings.Index(mimeType, ";"); idx >= 0 { - base = strings.TrimSpace(mimeType[:idx]) - } - if strings.HasPrefix(base, "image/") { - return true - } - if base == "application/pdf" { - return true - } - if strings.HasPrefix(base, "text/") { - return true - } - // Also allow JSON and XML which may be detected as application/* - if base == "application/json" || base == "application/xml" { - return true - } - return false + return true } diff --git a/internal/attachments/mime_test.go b/internal/attachments/mime_test.go index 142e674..25c2b06 100644 --- a/internal/attachments/mime_test.go +++ b/internal/attachments/mime_test.go @@ -167,10 +167,10 @@ func TestIsAllowedType(t *testing.T) { {"text/csv", true}, {"text/plain; charset=utf-8", true}, {"application/json", true}, - {"application/octet-stream", false}, - {"application/zip", false}, - {"application/x-executable", false}, - {"video/mp4", false}, + {"application/octet-stream", true}, + {"application/zip", true}, + {"application/x-executable", true}, + {"video/mp4", true}, } for _, tt := range tests { diff --git a/internal/attachments/service.go b/internal/attachments/service.go index 1d64773..6866f86 100644 --- a/internal/attachments/service.go +++ b/internal/attachments/service.go @@ -60,11 +60,6 @@ func (s *Service) Upload(ctx context.Context, req UploadRequest) (*UploadResult, mimeType = DetectMIMEType(sniffBuf, req.Filename) } - // Validate file type against allowlist. - if !IsAllowedType(mimeType) { - return nil, ErrUnsupportedType - } - // Assign default filename if missing. filename := req.Filename if filename == "" { diff --git a/internal/attachments/service_test.go b/internal/attachments/service_test.go index b5dd1df..2dcb1b6 100644 --- a/internal/attachments/service_test.go +++ b/internal/attachments/service_test.go @@ -236,18 +236,18 @@ func TestService_Upload_FileTypeValidation(t *testing.T) { wantErr: nil, }, { - name: "invalid type zip rejected", + name: "zip upload allowed", content: []byte("not real zip content"), filename: "archive.zip", mimeType: "application/zip", - wantErr: ErrUnsupportedType, + wantErr: nil, }, { - name: "invalid type executable rejected", + name: "executable upload allowed", content: []byte{0x7f, 0x45, 0x4c, 0x46}, filename: "program.exe", mimeType: "application/x-executable", - wantErr: ErrUnsupportedType, + wantErr: nil, }, } diff --git a/internal/mcp/bridge.go b/internal/mcp/bridge.go index 2683aa7..7ccd095 100644 --- a/internal/mcp/bridge.go +++ b/internal/mcp/bridge.go @@ -216,6 +216,8 @@ func (b *ServiceBridge) callReadInbox(ctx context.Context, args map[string]any) return nil, err } + b.msgService.EnrichMessages(ctx, page.Messages) + return map[string]any{ "messages": page.Messages, "count": len(page.Messages), @@ -233,6 +235,8 @@ func (b *ServiceBridge) callClaimMessages(ctx context.Context, args map[string]a return nil, err } + b.msgService.EnrichMessages(ctx, messages) + return map[string]any{ "messages": messages, "count": len(messages), @@ -287,6 +291,15 @@ func (b *ServiceBridge) callSearchMessages(ctx context.Context, args map[string] return nil, err } + // Enrich messages with attachments + searchMsgs := make([]*messaging.Message, 0, len(resp.Results)) + for _, r := range resp.Results { + if r.Message != nil { + searchMsgs = append(searchMsgs, r.Message) + } + } + b.msgService.EnrichMessages(ctx, searchMsgs) + resultMsgs := make([]map[string]any, len(resp.Results)) for i, r := range resp.Results { entry := map[string]any{ @@ -326,6 +339,8 @@ func (b *ServiceBridge) callSearchMessages(ctx context.Context, args map[string] return nil, err } + b.msgService.EnrichMessages(ctx, page.Messages) + return map[string]any{ "messages": page.Messages, "count": len(page.Messages), @@ -553,15 +568,18 @@ func (b *ServiceBridge) callGetChannelMessages(ctx context.Context, args map[str return nil, err } + b.msgService.EnrichMessages(ctx, page.Messages) + result := make([]map[string]any, len(page.Messages)) for i, msg := range page.Messages { result[i] = map[string]any{ - "id": msg.ID, - "from": msg.FromAgent, - "body": msg.Body, - "priority": msg.Priority, - "status": msg.Status, - "created_at": msg.CreatedAt, + "id": msg.ID, + "from": msg.FromAgent, + "body": msg.Body, + "priority": msg.Priority, + "status": msg.Status, + "created_at": msg.CreatedAt, + "attachments": msg.Attachments, } if len(msg.Metadata) > 0 { result[i]["metadata"] = msg.Metadata @@ -1119,23 +1137,30 @@ func (b *ServiceBridge) callListByState(ctx context.Context, args map[string]any if maxBodyLen <= 0 { maxBodyLen = 500 } - var messages []map[string]any + var msgSlice []*messaging.Message for _, id := range pageIDs { msg, err := b.msgService.GetMessageByID(ctx, id) if err != nil { continue } + msgSlice = append(msgSlice, msg) + } + b.msgService.EnrichMessages(ctx, msgSlice) + + var messages []map[string]any + for _, msg := range msgSlice { body := msg.Body if len(body) > maxBodyLen { body = body[:maxBodyLen] + "..." } messages = append(messages, map[string]any{ - "id": msg.ID, - "from_agent": msg.FromAgent, - "body": body, - "priority": msg.Priority, - "created_at": msg.CreatedAt, - "reply_to": msg.ReplyTo, + "id": msg.ID, + "from_agent": msg.FromAgent, + "body": body, + "priority": msg.Priority, + "created_at": msg.CreatedAt, + "reply_to": msg.ReplyTo, + "attachments": msg.Attachments, }) } resp["messages"] = messages diff --git a/internal/web/dist/index.html b/internal/web/dist/index.html index 789bdd7..2d8b7fe 100644 --- a/internal/web/dist/index.html +++ b/internal/web/dist/index.html @@ -11,30 +11,30 @@ - - + + - - - - - - + + + + + +
@@ -248,6 +285,13 @@ {/if}
+ {#if msg.attachments?.length > 0} +
+ {#each msg.attachments as att (att.hash)} + + {/each} +
+ {/if} {#if msg.workflow_state} {/if} @@ -286,11 +330,34 @@ {#if sendError}
{sendError}
{/if} + {#if uploadError} +
{uploadError}
+ {/if} {#if ownAgents.length === 0}
Register an agent to send messages
{:else} + + + {#if uploadedAttachments.length > 0} +
+ {#each uploadedAttachments as att (att.hash)} + + + {att.original_filename} + ({formatFileSize(att.size)}) + + + {/each} +
+ {/if} + {#if uploading} +
+ + Uploading... +
+ {/if}
+