-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmercury.go
135 lines (112 loc) · 3.86 KB
/
mercury.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package messagix
import (
"bytes"
"encoding/json"
"fmt"
"mime/multipart"
"net/textproto"
"reflect"
"github.com/0xzer/messagix/methods"
"github.com/0xzer/messagix/types"
"github.com/google/go-querystring/query"
)
type MediaType string
const (
IMAGE_JPEG MediaType = "image/jpeg"
VIDEO_MP4 MediaType = "video/mp4"
)
type MercuryUploadMedia struct {
Filename string
MediaType MediaType
MediaData []byte
}
func (c *Client) SendMercuryUploadRequest(medias []*MercuryUploadMedia) ([]*types.MercuryUploadResponse, error) {
responses := make([]*types.MercuryUploadResponse, 0)
for _, media := range medias {
urlQueries := c.NewHttpQuery()
queryValues, err := query.Values(urlQueries)
if err != nil {
return nil, fmt.Errorf("failed to convert HttpQuery into query.Values for mercury upload: %e", err)
}
payloadQuery := queryValues.Encode()
url := c.getEndpoint("media_upload") + payloadQuery
payload, contentType, err := c.NewMercuryMediaPayload(media)
if err != nil {
return nil, err
}
h := c.buildHeaders(true)
h.Add("content-type", contentType)
h.Add("origin", c.getEndpoint("base_url"))
h.Add("referer", c.getEndpoint("messages"))
h.Add("sec-fetch-dest", "empty")
h.Add("sec-fetch-mode", "cors")
h.Add("sec-fetch-site", "same-origin") // header is required
_, respBody, err := c.MakeRequest(url, "POST", h, payload, types.NONE)
if err != nil {
return nil, fmt.Errorf("failed to send MercuryUploadRequest: %e", err)
}
resp, err := c.parseMercuryResponse(respBody)
if err != nil {
return nil, fmt.Errorf("failed to parse mercury response: %e", err)
}
responses = append(responses, resp)
}
return responses, nil
}
func (c *Client) parseMercuryResponse(respBody []byte) (*types.MercuryUploadResponse, error) {
if len(respBody) < 9 {
return nil, fmt.Errorf("mercury upload response body was less than 9 in size")
}
jsonData := respBody[9:]
var mercuryResponse *types.MercuryUploadResponse
if err := json.Unmarshal(jsonData, &mercuryResponse); err != nil {
return nil, err
}
err := c.parseMetadata(mercuryResponse)
if err != nil {
return nil, err
}
return mercuryResponse, nil
}
func (c *Client) parseMetadata(response *types.MercuryUploadResponse) error {
var err error
switch metadata := response.Payload.Metadata.(type) {
case []interface{}:
var realMetadata types.ImageMetadata
err = methods.InterfaceToStructJSON(metadata[0], &realMetadata)
response.Payload.Metadata = &realMetadata
case map[string]interface{}:
var realMetadata types.VideoMetadata
err = methods.InterfaceToStructJSON(metadata["0"], &realMetadata)
response.Payload.Metadata = &realMetadata
default:
return fmt.Errorf("got invalid metadata type, cannot proceed with type assertion: %v", reflect.TypeOf(metadata))
}
return err
}
// returns payloadBytes, multipart content-type header
func (c *Client) NewMercuryMediaPayload(media *MercuryUploadMedia) ([]byte, string, error) {
var mercuryPayload bytes.Buffer
writer := multipart.NewWriter(&mercuryPayload)
err := writer.SetBoundary("----WebKitFormBoundary" + methods.RandStr(16))
if err != nil {
return nil, "", fmt.Errorf("messagix-mercury: Failed to set boundary (%e)", err)
}
partHeader := textproto.MIMEHeader{
"Content-Disposition": []string{`form-data; name="farr"; filename="` + media.Filename + `"`},
"Content-Type": []string{string(media.MediaType)},
}
mediaPart, err := writer.CreatePart(partHeader)
if err != nil {
return nil, "", fmt.Errorf("messagix-mercury: Failed to create multipart writer (%e)", err)
}
_, err = mediaPart.Write(media.MediaData)
if err != nil {
return nil, "", fmt.Errorf("messagix-mercury: Failed to write data to multipart section (%e)", err)
}
err = writer.Close()
if err != nil {
return nil, "", fmt.Errorf("messagix-mercury: Failed to close multipart writer (%e)", err)
}
return mercuryPayload.Bytes(), writer.FormDataContentType(), nil
}