upload: add media delete method

This commit is contained in:
Tulir Asokan
2026-03-27 20:16:59 +02:00
parent 7e66fe5e5a
commit 02ec817e7c
2 changed files with 57 additions and 0 deletions
+4
View File
@@ -682,6 +682,10 @@ func (cli *Client) handleHistorySyncNotificationLoop() {
cli.Log.Errorf("Failed to download history sync: %v", err)
} else {
cli.dispatchEvent(&events.HistorySync{Data: blob})
err = cli.DeleteMedia(ctx, MediaHistory, notif.GetDirectPath(), notif.GetFileEncSHA256(), notif.GetEncHandle())
if err != nil {
cli.Log.Warnf("Failed to delete history sync media from server: %v", err)
}
}
case <-time.After(1 * time.Minute):
return
+53
View File
@@ -18,6 +18,7 @@ import (
"net/http"
"net/url"
"os"
"strings"
"go.mau.fi/util/random"
@@ -249,3 +250,55 @@ func (cli *Client) rawUpload(ctx context.Context, dataToUpload io.Reader, upload
}
return err
}
// DeleteMedia deletes the media at the given direct path from WhatsApp servers.
//
// This is only used for things like history syncs, which should be deleted after processing.
func (cli *Client) DeleteMedia(ctx context.Context, appInfo MediaType, directPath string, encFileHash []byte, encHandle string) error {
mediaConn, err := cli.refreshMediaConn(ctx, false)
if err != nil {
return fmt.Errorf("failed to refresh media connections: %w", err)
}
queryStart := strings.IndexByte(directPath, '?')
if queryStart > 0 {
directPath = directPath[:queryStart]
}
token := base64.URLEncoding.EncodeToString(encFileHash)
query := url.Values{
"token": []string{token},
"d_md": []string{base64.RawURLEncoding.EncodeToString([]byte(directPath))},
"auth": []string{mediaConn.Auth},
}
if encHandle != "" {
query.Set("e_handle", encHandle)
}
deleteURL := url.URL{
Scheme: "https",
Host: mediaConn.Hosts[0].Hostname,
Path: fmt.Sprintf("/mms/%s/%s", mediaTypeToMMSType[appInfo], token),
RawQuery: query.Encode(),
}
req, err := http.NewRequestWithContext(ctx, http.MethodDelete, deleteURL.String(), nil)
if err != nil {
return fmt.Errorf("failed to prepare request: %w", err)
}
req.Header.Set("Origin", socket.Origin)
req.Header.Set("Referer", socket.Origin+"/")
// TODO non-on-demand backfills may require this? it's in the initial bootstrap payload and may need to be persisted
//req.Header.Set("Companion_User_Secret", companionMetaNonce)
httpResp, err := cli.mediaHTTP.Do(req)
if err != nil {
err = fmt.Errorf("failed to execute request: %w", err)
} else if httpResp.StatusCode < 200 || httpResp.StatusCode >= 300 {
err = fmt.Errorf("media delete failed with status code %d", httpResp.StatusCode)
}
if httpResp != nil {
_ = httpResp.Body.Close()
}
return err
}