Conversation
Reviewer's GuideImplements enhanced media sending by flagging MP4s sourced from GIF URLs for GIF-like video playback, extending sticker sending to support video-to-animated-WebP conversion with optional background removal via a transparentColor parameter, and updating API docs accordingly. Sequence diagram for sending animated video sticker with transparent backgroundsequenceDiagram
actor Client
participant API as HTTP_API
participant Service as sendService
participant Conv as convertToWebP
participant VidConv as convertVideoToWebP
participant FF as ffmpeg
participant WA as WhatsApp_Server
Client->>API: POST /send/sticker {number, sticker URL, transparentColor}
API->>Service: SendSticker(StickerStruct)
alt Sticker is URL
Service->>Conv: convertToWebP(stickerURL, transparentColor)
Conv->>API: http.Get(stickerURL)
API-->>Conv: Response body bytes
Conv->>Conv: Detect MIME type
alt MIME is video/mp4
Conv->>VidConv: convertVideoToWebP(data, transparentColor)
VidConv->>FF: run ffmpeg with colorkey and base filters
FF-->>VidConv: animated WebP file
VidConv-->>Conv: webpData []byte
else MIME is image (jpeg/png/jpg)
Conv->>Conv: Decode image and encode to WebP
end
Conv-->>Service: webpData []byte
end
Service->>WA: Send sticker message with WebP media
WA-->>Service: Message ID
Service-->>API: MessageSendStruct
API-->>Client: 200 OK with message info
Class diagram for enhanced media sending and sticker conversionclassDiagram
class sendService {
+sendMediaFileWithRetry(data MediaStruct, fileData []byte, instance instance_model.Instance) MessageSendStruct
+sendMediaUrlWithRetry(data MediaStruct, instance instance_model.Instance) MessageSendStruct
+SendSticker(data StickerStruct, instance instance_model.Instance) MessageSendStruct
}
class StickerStruct {
+string Number
+string Sticker
+string Id
+int32 Delay
+[]string MentionedJID
+bool MentionAll
+*bool FormatJid
+string TransparentColor
+QuotedStruct Quoted
}
class MediaStruct {
+string Filename
+string Url
+string Caption
}
class waE2EVideoMessage {
+string Caption
+string URL
+string DirectPath
+string Mimetype
+[]byte FileSHA256
+uint64 FileLength
+[]byte FileEncSHA256
+bool GifPlayback
}
class convertToWebP {
+convertToWebP(imageDataURL string, transparentColor string) []byte
}
class convertVideoToWebP {
+convertVideoToWebP(inputData []byte, transparentColor string) []byte
}
sendService --> StickerStruct : uses
sendService --> MediaStruct : uses
sendService --> waE2EVideoMessage : builds
sendService --> convertToWebP : calls
convertToWebP --> convertVideoToWebP : calls
class ffmpegProcess {
+string inputPath
+string outputPath
+string filters
}
convertVideoToWebP --> ffmpegProcess : spawns
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 1 security issue, 3 other issues, and left some high level feedback:
Security issues:
- Discovered a potential authorization token provided in a curl command header, which could compromise the curl accessed resource. (link)
General comments:
- The
isGifdetection forGifPlaybackcurrently relies only on.gifsuffix inFilename/Url; consider basing this on the actual content type (e.g., via existing upload metadata or MIME sniffing) to avoid misclassification when URLs or filenames do not reflect the true media type. - In
convertVideoToWebP/convertToWebP, thetransparentColorparameter is passed directly into thecolorkeyfilter after only stripping#; adding validation (length, hex chars, optional alpha) and normalizing to the exact format FFmpeg expects would make behavior more predictable and avoid subtle filter failures. - The
http.GetinconvertToWebPis a bare call with no timeout or context; using a sharedhttp.Clientwith sensible timeouts (or a context-aware request) would make remote sticker/video conversion more robust against slow or hanging endpoints.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The `isGif` detection for `GifPlayback` currently relies only on `.gif` suffix in `Filename`/`Url`; consider basing this on the actual content type (e.g., via existing upload metadata or MIME sniffing) to avoid misclassification when URLs or filenames do not reflect the true media type.
- In `convertVideoToWebP`/`convertToWebP`, the `transparentColor` parameter is passed directly into the `colorkey` filter after only stripping `#`; adding validation (length, hex chars, optional alpha) and normalizing to the exact format FFmpeg expects would make behavior more predictable and avoid subtle filter failures.
- The `http.Get` in `convertToWebP` is a bare call with no timeout or context; using a shared `http.Client` with sensible timeouts (or a context-aware request) would make remote sticker/video conversion more robust against slow or hanging endpoints.
## Individual Comments
### Comment 1
<location path="pkg/sendMessage/service/send_service.go" line_range="1425-1434" />
<code_context>
+func convertVideoToWebP(inputData []byte, transparentColor string) ([]byte, error) {
</code_context>
<issue_to_address>
**issue (bug_risk):** Validate `transparentColor` before using it in the `colorkey` filter to avoid ffmpeg failures.
Currently any `transparentColor` is interpolated directly into `colorkey=0x%s:0.1:0.0`. If the value isn’t a valid hex color (length or characters), ffmpeg will likely fail at runtime. Please validate the cleaned hex (e.g., only `[0-9a-fA-F]`, length 6/8) and either normalize or return a clear error instead of relying on ffmpeg’s failure message.
</issue_to_address>
### Comment 2
<location path="pkg/sendMessage/service/send_service.go" line_range="1493-1499" />
<code_context>
+
+ if mime.Is("image/webp") {
+ return data, nil
+ } else if mime.Is("video/mp4") {
+ return convertVideoToWebP(data, transparentColor)
+ } else if mime.Is("image/jpeg") || mime.Is("image/png") || mime.Is("image/jpg") {
</code_context>
<issue_to_address>
**suggestion:** Consider handling additional common formats (e.g. GIF) or documenting the new "unsupported format" behavior.
This change narrows supported formats to WebP, MP4, and a few image types, and now returns "unsupported format" for everything else. For sticker URLs served as `image/gif`, this is a behavior change from "try to decode whatever `image.Decode` supports" to an explicit failure. If GIF stickers are expected, consider adding GIF support (e.g., via ffmpeg or `image/gif`) or clearly documenting that GIF and similar formats are not supported so callers can handle that case.
```suggestion
mime := mimetype.Detect(data)
// Supported sticker formats:
// - image/webp: returned as-is
// - video/mp4: converted to WebP
// - image/jpeg, image/jpg, image/png, image/gif: decoded and re-encoded as WebP
// Any other MIME type will result in an "unsupported format" error so callers can handle it explicitly.
if mime.Is("image/webp") {
return data, nil
} else if mime.Is("video/mp4") {
return convertVideoToWebP(data, transparentColor)
} else if mime.Is("image/jpeg") || mime.Is("image/png") || mime.Is("image/jpg") || mime.Is("image/gif") {
```
</issue_to_address>
### Comment 3
<location path="pkg/sendMessage/service/send_service.go" line_range="937-939" />
<code_context>
}
mediaType = "ImageMessage"
case "video":
+ isGif := strings.HasSuffix(strings.ToLower(data.Filename), ".gif") || strings.HasSuffix(strings.ToLower(data.Url), ".gif")
if isNewsletter {
media = &waE2E.Message{VideoMessage: &waE2E.VideoMessage{
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Deriving `GifPlayback` from filename/URL extension may be fragile; consider using a more reliable signal.
`isGif` is derived only from `.gif` suffixes on `data.Filename`/`data.Url`, which can fail when filenames are absent, URLs contain query strings, or the extension doesn’t match the actual content type. Since you already have `mimeType` (or can use upload metadata), prefer inferring `GifPlayback` from a trusted MIME/content-type source rather than the path suffix.
```suggestion
case "video":
lowerMimeType := strings.ToLower(mimeType)
isGif := strings.HasPrefix(lowerMimeType, "image/gif") || strings.HasPrefix(lowerMimeType, "video/gif")
if isNewsletter {
```
</issue_to_address>
### Comment 4
<location path="docs/wiki/guias-api/api-messages.md" line_range="380-382" />
<code_context>
SUA-CHAVE-API
</code_context>
<issue_to_address>
**security (curl-auth-header):** Discovered a potential authorization token provided in a curl command header, which could compromise the curl accessed resource.
*Source: gitleaks*
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| func convertVideoToWebP(inputData []byte, transparentColor string) ([]byte, error) { | ||
| tmpInput, err := os.CreateTemp("", "sticker-input-*.mp4") | ||
| if err != nil { | ||
| return nil, fmt.Errorf("failed to create temp file: %v", err) | ||
| } | ||
| defer os.Remove(tmpInput.Name()) | ||
|
|
||
| if _, err := tmpInput.Write(inputData); err != nil { | ||
| tmpInput.Close() | ||
| return nil, fmt.Errorf("failed to write to temp file: %v", err) |
There was a problem hiding this comment.
issue (bug_risk): Validate transparentColor before using it in the colorkey filter to avoid ffmpeg failures.
Currently any transparentColor is interpolated directly into colorkey=0x%s:0.1:0.0. If the value isn’t a valid hex color (length or characters), ffmpeg will likely fail at runtime. Please validate the cleaned hex (e.g., only [0-9a-fA-F], length 6/8) and either normalize or return a clear error instead of relying on ffmpeg’s failure message.
| mime := mimetype.Detect(data) | ||
|
|
||
| if mime.Is("image/webp") { | ||
| return data, nil | ||
| } else if mime.Is("video/mp4") { | ||
| return convertVideoToWebP(data, transparentColor) | ||
| } else if mime.Is("image/jpeg") || mime.Is("image/png") || mime.Is("image/jpg") { |
There was a problem hiding this comment.
suggestion: Consider handling additional common formats (e.g. GIF) or documenting the new "unsupported format" behavior.
This change narrows supported formats to WebP, MP4, and a few image types, and now returns "unsupported format" for everything else. For sticker URLs served as image/gif, this is a behavior change from "try to decode whatever image.Decode supports" to an explicit failure. If GIF stickers are expected, consider adding GIF support (e.g., via ffmpeg or image/gif) or clearly documenting that GIF and similar formats are not supported so callers can handle that case.
| mime := mimetype.Detect(data) | |
| if mime.Is("image/webp") { | |
| return data, nil | |
| } else if mime.Is("video/mp4") { | |
| return convertVideoToWebP(data, transparentColor) | |
| } else if mime.Is("image/jpeg") || mime.Is("image/png") || mime.Is("image/jpg") { | |
| mime := mimetype.Detect(data) | |
| // Supported sticker formats: | |
| // - image/webp: returned as-is | |
| // - video/mp4: converted to WebP | |
| // - image/jpeg, image/jpg, image/png, image/gif: decoded and re-encoded as WebP | |
| // Any other MIME type will result in an "unsupported format" error so callers can handle it explicitly. | |
| if mime.Is("image/webp") { | |
| return data, nil | |
| } else if mime.Is("video/mp4") { | |
| return convertVideoToWebP(data, transparentColor) | |
| } else if mime.Is("image/jpeg") || mime.Is("image/png") || mime.Is("image/jpg") || mime.Is("image/gif") { |
| case "video": | ||
| isGif := strings.HasSuffix(strings.ToLower(data.Filename), ".gif") || strings.HasSuffix(strings.ToLower(data.Url), ".gif") | ||
| if isNewsletter { |
There was a problem hiding this comment.
suggestion (bug_risk): Deriving GifPlayback from filename/URL extension may be fragile; consider using a more reliable signal.
isGif is derived only from .gif suffixes on data.Filename/data.Url, which can fail when filenames are absent, URLs contain query strings, or the extension doesn’t match the actual content type. Since you already have mimeType (or can use upload metadata), prefer inferring GifPlayback from a trusted MIME/content-type source rather than the path suffix.
| case "video": | |
| isGif := strings.HasSuffix(strings.ToLower(data.Filename), ".gif") || strings.HasSuffix(strings.ToLower(data.Url), ".gif") | |
| if isNewsletter { | |
| case "video": | |
| lowerMimeType := strings.ToLower(mimeType) | |
| isGif := strings.HasPrefix(lowerMimeType, "image/gif") || strings.HasPrefix(lowerMimeType, "video/gif") | |
| if isNewsletter { |
| curl -X POST http://localhost:4000/send/sticker \ | ||
| -H "Content-Type: application/json" \ | ||
| -H "apikey: SUA-CHAVE-API" \ |
There was a problem hiding this comment.
security (curl-auth-header): Discovered a potential authorization token provided in a curl command header, which could compromise the curl accessed resource.
Source: gitleaks
Introduces several enhancements to media handling:
transparentColorparameter to the sticker endpoint, allowing background removal via FFmpeg colorkey filter.These changes have been in effect in my codebase since december (early acess) - throughly tested.
Type of Change
Testing
Checklist
Summary by Sourcery
Enhance media sending to support GIF-like video playback and richer sticker generation options.
New Features:
Documentation: