mirror of
https://github.com/aljazceru/signal-cli-rest-api.git
synced 2025-12-19 23:54:22 +01:00
Store base64 files locally before sending.
This commit is contained in:
@@ -1,23 +1,33 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gabriel-vasile/mimetype"
|
||||||
|
uuid "github.com/gofrs/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AttachmentEntry struct {
|
type AttachmentEntry struct {
|
||||||
MimeInfo string
|
MimeInfo string
|
||||||
FileName string
|
FileName string
|
||||||
Base64 string
|
DirName string
|
||||||
FilePath string
|
Base64 string
|
||||||
|
FilePath string
|
||||||
|
attachmentTmpDir string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAttachmentEntry(attachmentData string) *AttachmentEntry {
|
func NewAttachmentEntry(attachmentData string, attachmentTmpDir string) *AttachmentEntry {
|
||||||
attachmentEntry := AttachmentEntry{
|
attachmentEntry := AttachmentEntry{
|
||||||
MimeInfo: "",
|
MimeInfo: "",
|
||||||
FileName: "",
|
FileName: "",
|
||||||
Base64: "",
|
DirName: "",
|
||||||
FilePath: "",
|
Base64: "",
|
||||||
|
FilePath: "",
|
||||||
|
attachmentTmpDir: attachmentTmpDir,
|
||||||
}
|
}
|
||||||
|
|
||||||
attachmentEntry.extractMetaData(attachmentData)
|
attachmentEntry.extractMetaData(attachmentData)
|
||||||
@@ -52,6 +62,70 @@ func (attachmentEntry *AttachmentEntry) extractMetaData(attachmentData string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (attachmentEntry *AttachmentEntry) storeBase64AsTemporaryFile() error {
|
||||||
|
if strings.Compare(attachmentEntry.Base64, "") == 0 {
|
||||||
|
return errors.New("The base64 data does not exist.")
|
||||||
|
}
|
||||||
|
|
||||||
|
dec, err := base64.StdEncoding.DecodeString(attachmentEntry.Base64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// if no custom filename
|
||||||
|
if strings.Compare(attachmentEntry.FileName, "") == 0 {
|
||||||
|
mimeType := mimetype.Detect(dec)
|
||||||
|
|
||||||
|
fileNameUuid, err := uuid.NewV4()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
attachmentEntry.FileName = fileNameUuid.String() + mimeType.Extension()
|
||||||
|
}
|
||||||
|
|
||||||
|
dirNameUuid, err := uuid.NewV4()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
attachmentEntry.DirName = dirNameUuid.String()
|
||||||
|
dirPath := attachmentEntry.attachmentTmpDir + attachmentEntry.DirName
|
||||||
|
if err := os.Mkdir(dirPath, os.ModePerm); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
attachmentEntry.FilePath = dirPath + string(os.PathSeparator) + attachmentEntry.FileName
|
||||||
|
|
||||||
|
f, err := os.Create(attachmentEntry.FilePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
if _, err := f.Write(dec); err != nil {
|
||||||
|
attachmentEntry.cleanUp()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := f.Sync(); err != nil {
|
||||||
|
attachmentEntry.cleanUp()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f.Close()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (attachmentEntry *AttachmentEntry) cleanUp() {
|
||||||
|
if strings.Compare(attachmentEntry.FilePath, "") != 0 {
|
||||||
|
os.Remove(attachmentEntry.FilePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Compare(attachmentEntry.DirName, "") != 0 {
|
||||||
|
dirPath := attachmentEntry.attachmentTmpDir + attachmentEntry.DirName
|
||||||
|
os.Remove(dirPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (attachmentEntry *AttachmentEntry) setFieldValueByName(fieldName string, fieldValue string) {
|
func (attachmentEntry *AttachmentEntry) setFieldValueByName(fieldName string, fieldValue string) {
|
||||||
reflectPointer := reflect.ValueOf(attachmentEntry)
|
reflectPointer := reflect.ValueOf(attachmentEntry)
|
||||||
reflectStructure := reflectPointer.Elem()
|
reflectStructure := reflectPointer.Elem()
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"flag"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
@@ -11,42 +13,45 @@ func Test_Attachment_ExtractMetadata_ShouldPrepareDataFor_toDataForSignal(t *tes
|
|||||||
inputData string
|
inputData string
|
||||||
resultIsWithMetaData bool
|
resultIsWithMetaData bool
|
||||||
base64Expected string
|
base64Expected string
|
||||||
|
base64Valid bool
|
||||||
fileNameExpected string
|
fileNameExpected string
|
||||||
mimeInfoExpected string
|
mimeInfoExpected string
|
||||||
toDataForSignal string
|
toDataForSignal string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"BC base64 - compatibility", "MTIzNDU=", false, "MTIzNDU=", "", "", "MTIzNDU=",
|
"BC base64 - compatibility", "MTIzNDU=", false, "MTIzNDU=", true, "", "", "MTIzNDU=",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"+base64 -data -filename", "base64,MTIzNDU=", false, "base64,MTIzNDU=", "", "", "base64,MTIzNDU=",
|
"+base64 -data -filename", "base64,MTIzNDU=", false, "base64,MTIzNDU=", false, "", "", "base64,MTIzNDU=",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"+base64 +data -filename", "data:someData;base64,MTIzNDU=", true, "MTIzNDU=", "", "someData", "data:someData;base64,MTIzNDU=",
|
"+base64 +data -filename", "data:someData;base64,MTIzNDU=", true, "MTIzNDU=", true, "", "someData", "data:someData;base64,MTIzNDU=",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"+base64 -data +filename", "filename=file.name;base64,MTIzNDU=", false, "filename=file.name;base64,MTIzNDU=", "", "", "filename=file.name;base64,MTIzNDU=",
|
"+base64 -data +filename", "filename=file.name;base64,MTIzNDU=", false, "filename=file.name;base64,MTIzNDU=", false, "", "", "filename=file.name;base64,MTIzNDU=",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"+base64 +data +filename", "data:someData;filename=file.name;base64,MTIzNDU=", true, "MTIzNDU=", "file.name", "someData", "data:someData;filename=file.name;base64,MTIzNDU=",
|
"+base64 +data +filename", "data:someData;filename=file.name;base64,MTIzNDU=", true, "MTIzNDU=", true, "file.name", "someData", "data:someData;filename=file.name;base64,MTIzNDU=",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"-base64 -data -filename", "INVALIDMTIzNDU=", false, "INVALIDMTIzNDU=", "", "", "INVALIDMTIzNDU=",
|
"-base64 -data -filename", "INVALIDMTIzNDU=", false, "INVALIDMTIzNDU=", false, "", "", "INVALIDMTIzNDU=",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"-base64 +data -filename", "data:someData;INVALIDMTIzNDU=", false, "data:someData;INVALIDMTIzNDU=", "", "", "data:someData;INVALIDMTIzNDU=",
|
"-base64 +data -filename", "data:someData;INVALIDMTIzNDU=", false, "data:someData;INVALIDMTIzNDU=", false, "", "", "data:someData;INVALIDMTIzNDU=",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"-base64 -data +filename", "filename=file.name;INVALIDMTIzNDU=", false, "filename=file.name;INVALIDMTIzNDU=", "", "", "filename=file.name;INVALIDMTIzNDU=",
|
"-base64 -data +filename", "filename=file.name;INVALIDMTIzNDU=", false, "filename=file.name;INVALIDMTIzNDU=", false, "", "", "filename=file.name;INVALIDMTIzNDU=",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"-base64 +data +filename", "data:someData;filename=file.name;INVALIDMTIzNDU=", false, "data:someData;filename=file.name;INVALIDMTIzNDU=", "", "", "data:someData;filename=file.name;INVALIDMTIzNDU=",
|
"-base64 +data +filename", "data:someData;filename=file.name;INVALIDMTIzNDU=", false, "data:someData;filename=file.name;INVALIDMTIzNDU=", false, "", "", "data:someData;filename=file.name;INVALIDMTIzNDU=",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
attachmentTmp := flag.String("attachment-tmp-dir", string(os.PathSeparator)+"tmp"+string(os.PathSeparator), "Attachment tmp directory")
|
||||||
|
|
||||||
for _, tt := range testCases {
|
for _, tt := range testCases {
|
||||||
t.Run(tt.nameTest, func(t *testing.T) {
|
t.Run(tt.nameTest, func(t *testing.T) {
|
||||||
attachmentEntry := NewAttachmentEntry(tt.inputData)
|
attachmentEntry := NewAttachmentEntry(tt.inputData, *attachmentTmp)
|
||||||
|
|
||||||
if attachmentEntry.isWithMetaData() != tt.resultIsWithMetaData {
|
if attachmentEntry.isWithMetaData() != tt.resultIsWithMetaData {
|
||||||
t.Errorf("isWithMetaData() got \"%v\", want \"%v\"", attachmentEntry.isWithMetaData(), tt.resultIsWithMetaData)
|
t.Errorf("isWithMetaData() got \"%v\", want \"%v\"", attachmentEntry.isWithMetaData(), tt.resultIsWithMetaData)
|
||||||
@@ -67,6 +72,36 @@ func Test_Attachment_ExtractMetadata_ShouldPrepareDataFor_toDataForSignal(t *tes
|
|||||||
if strings.Compare(attachmentEntry.toDataForSignal(), tt.toDataForSignal) != 0 {
|
if strings.Compare(attachmentEntry.toDataForSignal(), tt.toDataForSignal) != 0 {
|
||||||
t.Errorf("toDataForSignal() got \"%v\", want \"%v\"", attachmentEntry.toDataForSignal(), tt.toDataForSignal)
|
t.Errorf("toDataForSignal() got \"%v\", want \"%v\"", attachmentEntry.toDataForSignal(), tt.toDataForSignal)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err := attachmentEntry.storeBase64AsTemporaryFile()
|
||||||
|
if err != nil && tt.base64Valid {
|
||||||
|
t.Error("storeBase64AsTemporaryFile error: %w", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := os.Stat(attachmentEntry.FilePath)
|
||||||
|
if os.IsNotExist(err) && tt.base64Valid {
|
||||||
|
t.Error("file not exists after storeBase64AsTemporaryFile: %w", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (info == nil || info.IsDir()) && tt.base64Valid {
|
||||||
|
t.Error("is not a file by path after storeBase64AsTemporaryFile")
|
||||||
|
t.Error(attachmentEntry)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
attachmentEntry.cleanUp()
|
||||||
|
|
||||||
|
info, err = os.Stat(attachmentEntry.FilePath)
|
||||||
|
if info != nil && !os.IsNotExist(err) && tt.base64Valid {
|
||||||
|
t.Error("no info or file exists after cleanUp")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
info, err = os.Stat(*attachmentTmp + attachmentEntry.DirName)
|
||||||
|
if info != nil && !os.IsNotExist(err) && tt.base64Valid {
|
||||||
|
t.Error("dir exists after cleanUp")
|
||||||
|
return
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
securejoin "github.com/cyphar/filepath-securejoin"
|
securejoin "github.com/cyphar/filepath-securejoin"
|
||||||
"github.com/gabriel-vasile/mimetype"
|
|
||||||
"github.com/h2non/filetype"
|
"github.com/h2non/filetype"
|
||||||
|
|
||||||
uuid "github.com/gofrs/uuid"
|
uuid "github.com/gofrs/uuid"
|
||||||
@@ -136,11 +135,7 @@ func cleanupTmpFiles(paths []string) {
|
|||||||
|
|
||||||
func cleanupAttachmentEntries(attachmentEntries []AttachmentEntry) {
|
func cleanupAttachmentEntries(attachmentEntries []AttachmentEntry) {
|
||||||
for _, attachmentEntry := range attachmentEntries {
|
for _, attachmentEntry := range attachmentEntries {
|
||||||
if len(attachmentEntry.FilePath) == 0 {
|
attachmentEntry.cleanUp()
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
os.Remove(attachmentEntry.FilePath)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,43 +306,15 @@ func (s *SignalClient) send(number string, message string,
|
|||||||
|
|
||||||
attachmentEntries := []AttachmentEntry{}
|
attachmentEntries := []AttachmentEntry{}
|
||||||
for _, base64Attachment := range base64Attachments {
|
for _, base64Attachment := range base64Attachments {
|
||||||
attachmentEntry := NewAttachmentEntry(base64Attachment)
|
attachmentEntry := NewAttachmentEntry(base64Attachment, s.attachmentTmpDir)
|
||||||
|
|
||||||
u, err := uuid.NewV4()
|
err := attachmentEntry.storeBase64AsTemporaryFile()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
cleanupAttachmentEntries(attachmentEntries)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
dec, err := base64.StdEncoding.DecodeString(attachmentEntry.Base64)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
mimeType := mimetype.Detect(dec)
|
|
||||||
|
|
||||||
if attachmentEntry.isWithMetaData() {
|
|
||||||
attachmentEntries = append(attachmentEntries, *attachmentEntry)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
attachmentEntry.FilePath = s.attachmentTmpDir + u.String() + mimeType.Extension()
|
|
||||||
attachmentEntries = append(attachmentEntries, *attachmentEntry)
|
attachmentEntries = append(attachmentEntries, *attachmentEntry)
|
||||||
|
|
||||||
f, err := os.Create(attachmentEntry.FilePath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
if _, err := f.Write(dec); err != nil {
|
|
||||||
cleanupAttachmentEntries(attachmentEntries)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := f.Sync(); err != nil {
|
|
||||||
cleanupAttachmentEntries(attachmentEntries)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
f.Close()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.signalCliMode == JsonRpc {
|
if s.signalCliMode == JsonRpc {
|
||||||
|
|||||||
Reference in New Issue
Block a user