| 73 | } |
| 74 | |
| 75 | func (n *nativeAttachmentStore) DownloadURL(agentEmail, messageID string, index int, ttl time.Duration) (string, time.Time, error) { |
| 76 | // Fail closed if wired with no secret — an empty HMAC key makes every token |
| 77 | // trivially forgeable. Production config already rejects empty/short secrets, |
| 78 | // but defend here too so a future miswiring can't silently open the route. |
| 79 | if len(n.secret) == 0 { |
| 80 | return "", time.Time{}, fmt.Errorf("attachment store: empty signing secret") |
| 81 | } |
| 82 | exp := time.Now().Add(ttl) |
| 83 | tok := n.sign(messageID, index, exp.Unix()) |
| 84 | u := fmt.Sprintf("%s/v1/agents/%s/messages/%s/attachments/%d/download?token=%s", |
| 85 | n.publicURL, |
| 86 | url.PathEscape(agentEmail), |
| 87 | url.PathEscape(messageID), |
| 88 | index, |
| 89 | url.QueryEscape(tok), |
| 90 | ) |
| 91 | return u, exp, nil |
| 92 | } |
| 93 | |
| 94 | func (n *nativeAttachmentStore) VerifyDownload(token, messageID string, index int) bool { |
| 95 | if len(n.secret) == 0 { |