-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathfile.go
More file actions
144 lines (122 loc) · 4.1 KB
/
Copy pathfile.go
File metadata and controls
144 lines (122 loc) · 4.1 KB
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
136
137
138
139
140
141
142
143
144
package handlers
import (
"context"
"encoding/json"
"fmt"
"strings"
"maunium.net/go/mautrix/bridgev2"
"maunium.net/go/mautrix/event"
"github.com/highesttt/matrix-line-messenger/pkg/line"
)
// ConvertFile converts a LINE file message to a Matrix file message.
func (h *Handler) ConvertFile(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, data line.Message, decryptedBody string, relatesTo *event.RelatesTo) (*bridgev2.ConvertedMessage, error) {
if oversized := h.oversizedMediaNoticeFromMetadata(data.ContentMetadata, relatesTo); oversized != nil {
return oversized, nil
}
client := h.NewClient()
oid := data.ContentMetadata["OID"]
isPlainMedia := oid == ""
if oid == "" && decryptedBody != "" && strings.Contains(decryptedBody, "fileName") {
h.Log.Debug().Msg("File message with encrypted payload, OID in metadata")
}
// For plain media, the file is stored at r/talk/m/{messageID}
if isPlainMedia {
oid = data.ID
}
if oid == "" {
return nil, nil
}
sid := "emf"
if isPlainMedia {
sid = "m"
}
downloadOptions := lineOBSDownloadOptions(data.ContentMetadata, isPlainMedia)
talkMetaMessageID := obsTalkMetaMessageID(data.ID, isPlainMedia)
fileData, err := client.DownloadOBSWithSIDOptions(ctx, oid, talkMetaMessageID, sid, downloadOptions)
if newClient, ok := h.tryRecoverClient(ctx, client, err); ok {
client = newClient
fileData, err = client.DownloadOBSWithSIDOptions(ctx, oid, talkMetaMessageID, sid, downloadOptions)
}
h.handleFinalAuthError(ctx, client, err)
if err != nil {
h.Log.Warn().
Err(err).
Str("oid", oid).
Bool("plain_media", isPlainMedia).
Msg("Failed to download file from OBS")
return mediaDownloadFailure("File", err, relatesTo)
}
// Try to decrypt using keyMaterial from encrypted payload
var fileName string
if decryptedBody != "" && strings.Contains(decryptedBody, "keyMaterial") {
var decryptInfo struct {
KeyMaterial string `json:"keyMaterial"`
FileName string `json:"fileName"`
}
if err := json.Unmarshal([]byte(decryptedBody), &decryptInfo); err != nil {
h.Log.Error().Err(err).Msg("Failed to parse file payload JSON")
return nil, fmt.Errorf("failed to parse file payload: %w", err)
}
if decryptInfo.KeyMaterial != "" {
keyPreview := decryptInfo.KeyMaterial
if len(keyPreview) > 20 {
keyPreview = keyPreview[:20] + "..."
}
h.Log.Debug().
Str("key_material_preview", keyPreview).
Msg("Decrypting file using keyMaterial from payload")
decryptedFile, err := h.DecryptMedia(fileData, decryptInfo.KeyMaterial)
if err != nil {
h.Log.Error().Err(err).Msg("Failed to decrypt file data")
return nil, fmt.Errorf("failed to decrypt file data: %w", err)
}
fileData = decryptedFile
h.Log.Info().Int("decrypted_size", len(fileData)).Msg("Successfully decrypted file")
}
if decryptInfo.FileName != "" {
fileName = decryptInfo.FileName
}
}
if oversized := h.oversizedMediaNotice(int64(len(fileData)), "downloaded", relatesTo); oversized != nil {
return oversized, nil
}
if fileName == "" {
fileName = data.ContentMetadata["FILE_NAME"]
}
if fileName == "" {
fileName = "file.bin"
}
// Detect MIME type from file extension
mimeType := "application/octet-stream"
if strings.HasSuffix(strings.ToLower(fileName), ".pdf") {
mimeType = "application/pdf"
}
mxc, file, err := intent.UploadMedia(ctx, portal.MXID, fileData, fileName, mimeType)
if err != nil {
h.Log.Error().Err(err).Int("size_bytes", len(fileData)).Msg("Failed to upload file to Matrix")
return nil, fmt.Errorf("failed to upload file to matrix: %w", err)
}
h.Log.Info().
Str("mxc", mxc.ParseOrIgnore().String()).
Str("file_name", fileName).
Int("size", len(fileData)).
Msg("Successfully uploaded file to Matrix")
return &bridgev2.ConvertedMessage{
Parts: []*bridgev2.ConvertedMessagePart{
{
Type: event.EventMessage,
Content: &event.MessageEventContent{
MsgType: event.MsgFile,
Body: fileName,
URL: mxc,
File: file,
Info: &event.FileInfo{
MimeType: mimeType,
Size: len(fileData),
},
RelatesTo: relatesTo,
},
},
},
}, nil
}