From 5bb338f91c74379e26eb146bbdffe0ed8127e13c Mon Sep 17 00:00:00 2001 From: Marc Ole Bulling Date: Fri, 15 Jul 2022 02:29:49 +0200 Subject: [PATCH] Breaking: Make API output less verbose #63, fixed hotlink not working with "duplicate" API call, added option to change filename with duplicate API call --- internal/models/FileList.go | 57 ++++++++++++++++--- internal/models/FileList_test.go | 2 +- internal/storage/FileServing.go | 9 ++- internal/storage/FileServing_test.go | 34 ++++++++--- internal/webserver/Webserver.go | 8 ++- internal/webserver/api/Api.go | 28 ++++++--- internal/webserver/api/Api_test.go | 22 +++---- .../web/static/apidocumentation/openapi.json | 57 +++++++++++++------ internal/webserver/web/static/js/admin.js | 4 +- .../webserver/web/templates/html_admin.tmpl | 6 +- openapi.json | 57 +++++++++++++------ 11 files changed, 204 insertions(+), 80 deletions(-) diff --git a/internal/models/FileList.go b/internal/models/FileList.go index ce7102d..fbc172a 100644 --- a/internal/models/FileList.go +++ b/internal/models/FileList.go @@ -3,6 +3,7 @@ package models import ( "encoding/json" "fmt" + "github.com/jinzhu/copier" ) // File is a struct used for saving information about an uploaded file @@ -25,6 +26,26 @@ type File struct { RequiresClientSideDecryption bool `json:"RequiresClientSideDecryption"` } +// FileApiOutput will be displayed for public outputs from the ID, hiding sensitive information +type FileApiOutput struct { + Id string `json:"Id"` + Name string `json:"Name"` + Size string `json:"Size"` + SHA256 string `json:"SHA256"` + HotlinkId string `json:"HotlinkId"` + ContentType string `json:"ContentType"` + ExpireAt int64 `json:"ExpireAt"` + ExpireAtString string `json:"ExpireAtString"` + DownloadsRemaining int `json:"DownloadsRemaining"` + DownloadCount int `json:"DownloadCount"` + UnlimitedDownloads bool `json:"UnlimitedDownloads"` + UnlimitedTime bool `json:"UnlimitedTime"` + RequiresClientSideDecryption bool `json:"RequiresClientSideDecryption"` + IsEncrypted bool `json:"IsEncrypted"` + IsPasswordProtected bool `json:"IsPasswordProtected"` + IsSavedOnLocalStorage bool `json:"IsSavedOnLocalStorage"` +} + // EncryptionInfo holds information about the encryption used on the file type EncryptionInfo struct { IsEncrypted bool `json:"IsEncrypted"` @@ -32,31 +53,51 @@ type EncryptionInfo struct { Nonce []byte `json:"Nonce"` } +func (f *File) ToFileApiOutput() (FileApiOutput, error) { + var result FileApiOutput + err := copier.Copy(&result, &f) + if err != nil { + return FileApiOutput{}, err + } + result.IsPasswordProtected = f.PasswordHash != "" + result.IsEncrypted = f.Encryption.IsEncrypted + result.IsSavedOnLocalStorage = f.AwsBucket == "" + return result, nil +} + // ToJsonResult converts the file info to a json String used for returning a result for an upload func (f *File) ToJsonResult(serverUrl string) string { + info, err := f.ToFileApiOutput() + if err != nil { + return errorAsJson(err) + } result := Result{ Result: "OK", Url: serverUrl + "d?id=", HotlinkUrl: serverUrl + "hotlink/", GenericHotlinkUrl: serverUrl + "downloadFile?id=", - FileInfo: f, + FileInfo: info, } bytes, err := json.Marshal(result) if err != nil { - fmt.Println(err) - return "{\"Result\":\"error\",\"ErrorMessage\":\"" + err.Error() + "\"}" + return errorAsJson(err) } return string(bytes) } +func errorAsJson(err error) string { + fmt.Println(err) + return "{\"Result\":\"error\",\"ErrorMessage\":\"" + err.Error() + "\"}" +} + // Result is the struct used for the result after an upload // swagger:model UploadResult type Result struct { - Result string `json:"Result"` - FileInfo *File `json:"FileInfo"` - Url string `json:"Url"` - HotlinkUrl string `json:"HotlinkUrl"` - GenericHotlinkUrl string `json:"GenericHotlinkUrl"` + Result string `json:"Result"` + FileInfo FileApiOutput `json:"FileInfo"` + Url string `json:"Url"` + HotlinkUrl string `json:"HotlinkUrl"` + GenericHotlinkUrl string `json:"GenericHotlinkUrl"` } // DownloadStatus contains current downloads, so they do not get removed during cleanup diff --git a/internal/models/FileList_test.go b/internal/models/FileList_test.go index 7c808ed..872e7b5 100644 --- a/internal/models/FileList_test.go +++ b/internal/models/FileList_test.go @@ -27,5 +27,5 @@ func TestToJsonResult(t *testing.T) { UnlimitedDownloads: true, UnlimitedTime: true, } - test.IsEqualString(t, file.ToJsonResult("serverurl/"), `{"Result":"OK","FileInfo":{"Id":"testId","Name":"testName","Size":"10 B","SHA256":"sha256","ExpireAt":50,"ExpireAtString":"future","DownloadsRemaining":1,"DownloadCount":3,"PasswordHash":"pwhash","HotlinkId":"hotlinkid","ContentType":"text/html","AwsBucket":"test","Encryption":{"IsEncrypted":true,"DecryptionKey":"AQ==","Nonce":"Ag=="},"UnlimitedDownloads":true,"UnlimitedTime":true,"RequiresClientSideDecryption":false},"Url":"serverurl/d?id=","HotlinkUrl":"serverurl/hotlink/","GenericHotlinkUrl":"serverurl/downloadFile?id="}`) + test.IsEqualString(t, file.ToJsonResult("serverurl/"), `{"Result":"OK","FileInfo":{"Id":"testId","Name":"testName","Size":"10 B","SHA256":"sha256","HotlinkId":"hotlinkid","ContentType":"text/html","ExpireAt":50,"ExpireAtString":"future","DownloadsRemaining":1,"DownloadCount":3,"UnlimitedDownloads":true,"UnlimitedTime":true,"RequiresClientSideDecryption":false,"IsEncrypted":true,"IsPasswordProtected":true,"IsSavedOnLocalStorage":false},"Url":"serverurl/d?id=","HotlinkUrl":"serverurl/hotlink/","GenericHotlinkUrl":"serverurl/downloadFile?id="}`) } diff --git a/internal/storage/FileServing.go b/internal/storage/FileServing.go index ef20d4b..6754f51 100644 --- a/internal/storage/FileServing.go +++ b/internal/storage/FileServing.go @@ -148,10 +148,11 @@ const ( ParamExpiry int = 1 << iota ParamDownloads ParamPassword + ParamName ) // DuplicateFile creates a copy of an existing file with new parameters -func DuplicateFile(file models.File, parametersToChange int, fileParameters models.UploadRequest) (models.File, error) { +func DuplicateFile(file models.File, parametersToChange int, newFileName string, fileParameters models.UploadRequest) (models.File, error) { var newFile models.File err := copier.Copy(&newFile, &file) if err != nil { @@ -161,6 +162,7 @@ func DuplicateFile(file models.File, parametersToChange int, fileParameters mode changeExpiry := parametersToChange&ParamExpiry != 0 changeDownloads := parametersToChange&ParamDownloads != 0 changePassword := parametersToChange&ParamPassword != 0 + changeName := parametersToChange&ParamName != 0 if changeExpiry { newFile.ExpireAt = fileParameters.ExpiryTimestamp @@ -174,8 +176,13 @@ func DuplicateFile(file models.File, parametersToChange int, fileParameters mode if changePassword { newFile.PasswordHash = configuration.HashPassword(fileParameters.Password, true) } + if changeName { + newFile.Name = newFileName + } + newFile.Id = createNewId() newFile.DownloadCount = 0 + addHotlink(&file) database.SaveMetaData(newFile) return newFile, nil diff --git a/internal/storage/FileServing_test.go b/internal/storage/FileServing_test.go index 902d823..2abd013 100644 --- a/internal/storage/FileServing_test.go +++ b/internal/storage/FileServing_test.go @@ -333,7 +333,7 @@ func TestDuplicateFile(t *testing.T) { retrievedFile.DownloadCount = 5 database.SaveMetaData(retrievedFile) - newFile, err := DuplicateFile(retrievedFile, 0, models.UploadRequest{}) + newFile, err := DuplicateFile(retrievedFile, 0, "123", models.UploadRequest{}) test.IsNil(t, err) test.IsEqualInt(t, newFile.DownloadCount, 0) test.IsEqualInt(t, newFile.DownloadsRemaining, 1) @@ -341,6 +341,7 @@ func TestDuplicateFile(t *testing.T) { test.IsEqualString(t, newFile.PasswordHash, "") test.IsEqualBool(t, newFile.UnlimitedDownloads, false) test.IsEqualBool(t, newFile.UnlimitedTime, false) + test.IsEqualString(t, newFile.Name, "test.dat") uploadRequest := models.UploadRequest{ AllowedDownloads: 5, @@ -351,7 +352,7 @@ func TestDuplicateFile(t *testing.T) { UnlimitedTime: true, } - newFile, err = DuplicateFile(retrievedFile, 0, uploadRequest) + newFile, err = DuplicateFile(retrievedFile, 0, "123", uploadRequest) test.IsNil(t, err) test.IsEqualInt(t, newFile.DownloadCount, 0) test.IsEqualInt(t, newFile.DownloadsRemaining, 1) @@ -359,8 +360,19 @@ func TestDuplicateFile(t *testing.T) { test.IsEqualString(t, newFile.PasswordHash, "") test.IsEqualBool(t, newFile.UnlimitedDownloads, false) test.IsEqualBool(t, newFile.UnlimitedTime, false) + test.IsEqualString(t, newFile.Name, "test.dat") - newFile, err = DuplicateFile(retrievedFile, ParamExpiry, uploadRequest) + newFile, err = DuplicateFile(retrievedFile, ParamName, "123", uploadRequest) + test.IsNil(t, err) + test.IsEqualInt(t, newFile.DownloadCount, 0) + test.IsEqualInt(t, newFile.DownloadsRemaining, 1) + test.IsEqualInt64(t, newFile.ExpireAt, 2147483600) + test.IsEqualString(t, newFile.PasswordHash, "") + test.IsEqualBool(t, newFile.UnlimitedDownloads, false) + test.IsEqualBool(t, newFile.UnlimitedTime, false) + test.IsEqualString(t, newFile.Name, "123") + + newFile, err = DuplicateFile(retrievedFile, ParamExpiry, "123", uploadRequest) test.IsNil(t, err) test.IsEqualInt(t, newFile.DownloadCount, 0) test.IsEqualInt(t, newFile.DownloadsRemaining, 1) @@ -368,8 +380,9 @@ func TestDuplicateFile(t *testing.T) { test.IsEqualString(t, newFile.PasswordHash, "") test.IsEqualBool(t, newFile.UnlimitedDownloads, false) test.IsEqualBool(t, newFile.UnlimitedTime, true) + test.IsEqualString(t, newFile.Name, "test.dat") - newFile, err = DuplicateFile(retrievedFile, ParamDownloads, uploadRequest) + newFile, err = DuplicateFile(retrievedFile, ParamDownloads, "123", uploadRequest) test.IsNil(t, err) test.IsEqualInt(t, newFile.DownloadCount, 0) test.IsEqualInt(t, newFile.DownloadsRemaining, 5) @@ -377,8 +390,9 @@ func TestDuplicateFile(t *testing.T) { test.IsEqualString(t, newFile.PasswordHash, "") test.IsEqualBool(t, newFile.UnlimitedDownloads, true) test.IsEqualBool(t, newFile.UnlimitedTime, false) + test.IsEqualString(t, newFile.Name, "test.dat") - newFile, err = DuplicateFile(retrievedFile, ParamPassword, uploadRequest) + newFile, err = DuplicateFile(retrievedFile, ParamPassword, "123", uploadRequest) test.IsNil(t, err) test.IsEqualInt(t, newFile.DownloadCount, 0) test.IsEqualInt(t, newFile.DownloadsRemaining, 1) @@ -386,9 +400,10 @@ func TestDuplicateFile(t *testing.T) { test.IsNotEqualString(t, newFile.PasswordHash, "") test.IsEqualBool(t, newFile.UnlimitedDownloads, false) test.IsEqualBool(t, newFile.UnlimitedTime, false) + test.IsEqualString(t, newFile.Name, "test.dat") retrievedFile.PasswordHash = "ahash" - newFile, err = DuplicateFile(retrievedFile, 0, uploadRequest) + newFile, err = DuplicateFile(retrievedFile, 0, "123", uploadRequest) test.IsNil(t, err) test.IsEqualInt(t, newFile.DownloadCount, 0) test.IsEqualInt(t, newFile.DownloadsRemaining, 1) @@ -396,9 +411,10 @@ func TestDuplicateFile(t *testing.T) { test.IsEqualString(t, newFile.PasswordHash, "ahash") test.IsEqualBool(t, newFile.UnlimitedDownloads, false) test.IsEqualBool(t, newFile.UnlimitedTime, false) + test.IsEqualString(t, newFile.Name, "test.dat") uploadRequest.Password = "" - newFile, err = DuplicateFile(retrievedFile, ParamPassword, uploadRequest) + newFile, err = DuplicateFile(retrievedFile, ParamPassword, "123", uploadRequest) test.IsNil(t, err) test.IsEqualInt(t, newFile.DownloadCount, 0) test.IsEqualInt(t, newFile.DownloadsRemaining, 1) @@ -406,9 +422,10 @@ func TestDuplicateFile(t *testing.T) { test.IsEqualString(t, newFile.PasswordHash, "") test.IsEqualBool(t, newFile.UnlimitedDownloads, false) test.IsEqualBool(t, newFile.UnlimitedTime, false) + test.IsEqualString(t, newFile.Name, "test.dat") uploadRequest.Password = "123" - newFile, err = DuplicateFile(retrievedFile, ParamExpiry|ParamPassword|ParamDownloads, uploadRequest) + newFile, err = DuplicateFile(retrievedFile, ParamExpiry|ParamPassword|ParamDownloads|ParamName, "123", uploadRequest) test.IsNil(t, err) test.IsEqualInt(t, newFile.DownloadCount, 0) test.IsEqualInt(t, newFile.DownloadsRemaining, 5) @@ -416,6 +433,7 @@ func TestDuplicateFile(t *testing.T) { test.IsNotEqualString(t, newFile.PasswordHash, "") test.IsEqualBool(t, newFile.UnlimitedDownloads, true) test.IsEqualBool(t, newFile.UnlimitedTime, true) + test.IsEqualString(t, newFile.Name, "123") } diff --git a/internal/webserver/Webserver.go b/internal/webserver/Webserver.go index 14cb748..f588b9a 100644 --- a/internal/webserver/Webserver.go +++ b/internal/webserver/Webserver.go @@ -376,7 +376,7 @@ type DownloadView struct { // UploadView contains parameters for the admin menu template type UploadView struct { - Items []models.File + Items []models.FileApiOutput ApiKeys []models.ApiKey Url string HotlinkUrl string @@ -397,11 +397,13 @@ type UploadView struct { // Converts the globalConfig variable to an UploadView struct to pass the infos to // the admin template func (u *UploadView) convertGlobalConfig(isMainView bool) *UploadView { - var result []models.File + var result []models.FileApiOutput var resultApi []models.ApiKey if isMainView { for _, element := range database.GetAllMetadata() { - result = append(result, element) + fileInfo, err := element.ToFileApiOutput() + helper.Check(err) + result = append(result, fileInfo) } sort.Slice(result[:], func(i, j int) bool { if result[i].ExpireAt == result[j].ExpireAt { diff --git a/internal/webserver/api/Api.go b/internal/webserver/api/Api.go index c771d0a..bce4fb3 100644 --- a/internal/webserver/api/Api.go +++ b/internal/webserver/api/Api.go @@ -88,11 +88,13 @@ func deleteFile(w http.ResponseWriter, request apiRequest) { } func list(w http.ResponseWriter) { - var validFiles []models.File + var validFiles []models.FileApiOutput timeNow := time.Now().Unix() for _, element := range database.GetAllMetadata() { if !storage.IsExpiredFile(element, timeNow) { - validFiles = append(validFiles, element) + file, err := element.ToFileApiOutput() + helper.Check(err) + validFiles = append(validFiles, file) } } result, err := json.Marshal(validFiles) @@ -120,35 +122,38 @@ func duplicateFile(w http.ResponseWriter, request apiRequest) { sendError(w, http.StatusBadRequest, "Invalid id provided.") return } - uploadRequest, paramsToChange, err := apiRequestToUploadRequest(request.request) + uploadRequest, paramsToChange, filename, err := apiRequestToUploadRequest(request.request) if err != nil { sendError(w, http.StatusBadRequest, err.Error()) return } - newFile, err := storage.DuplicateFile(file, paramsToChange, uploadRequest) + newFile, err := storage.DuplicateFile(file, paramsToChange, filename, uploadRequest) if err != nil { sendError(w, http.StatusBadRequest, err.Error()) return } - result, err := json.Marshal(newFile) + publicOutput, err := newFile.ToFileApiOutput() + helper.Check(err) + result, err := json.Marshal(publicOutput) helper.Check(err) _, _ = w.Write(result) } -func apiRequestToUploadRequest(request *http.Request) (models.UploadRequest, int, error) { +func apiRequestToUploadRequest(request *http.Request) (models.UploadRequest, int, string, error) { paramsToChange := 0 allowedDownloads := 0 daysExpiry := 0 unlimitedTime := false unlimitedDownloads := false password := "" + fileName := "" var err error if request.Form.Get("allowedDownloads") != "" { paramsToChange = paramsToChange | storage.ParamDownloads allowedDownloads, err = strconv.Atoi(request.Form.Get("allowedDownloads")) if err != nil { - return models.UploadRequest{}, 0, err + return models.UploadRequest{}, 0, "", err } if allowedDownloads == 0 { unlimitedDownloads = true @@ -159,7 +164,7 @@ func apiRequestToUploadRequest(request *http.Request) (models.UploadRequest, int paramsToChange = paramsToChange | storage.ParamExpiry daysExpiry, err = strconv.Atoi(request.Form.Get("expiryDays")) if err != nil { - return models.UploadRequest{}, 0, err + return models.UploadRequest{}, 0, "", err } if daysExpiry == 0 { unlimitedTime = true @@ -171,6 +176,11 @@ func apiRequestToUploadRequest(request *http.Request) (models.UploadRequest, int password = request.Form.Get("password") } + if request.Form.Get("filename") != "" { + paramsToChange = paramsToChange | storage.ParamName + fileName = request.Form.Get("filename") + } + return models.UploadRequest{ AllowedDownloads: allowedDownloads, Expiry: daysExpiry, @@ -178,7 +188,7 @@ func apiRequestToUploadRequest(request *http.Request) (models.UploadRequest, int UnlimitedDownload: unlimitedDownloads, Password: password, ExpiryTimestamp: time.Now().Add(time.Duration(daysExpiry) * time.Hour * 24).Unix(), - }, paramsToChange, nil + }, paramsToChange, fileName, nil } func isAuthorisedForApi(w http.ResponseWriter, request apiRequest) bool { diff --git a/internal/webserver/api/Api_test.go b/internal/webserver/api/Api_test.go index 3f9f14e..09b3fb6 100644 --- a/internal/webserver/api/Api_test.go +++ b/internal/webserver/api/Api_test.go @@ -192,7 +192,7 @@ func TestUploadAndDuplication(t *testing.T) { test.IsEqualString(t, result.Result, "OK") test.IsEqualString(t, result.FileInfo.Size, "3 B") test.IsEqualInt(t, result.FileInfo.DownloadsRemaining, 200) - test.IsNotEqualString(t, result.FileInfo.PasswordHash, "") + test.IsEqualBool(t, result.FileInfo.IsPasswordProtected, true) test.IsEqualString(t, result.Url, "http://127.0.0.1:53843/d?id=") newFileId := result.FileInfo.Id @@ -238,7 +238,7 @@ func TestUploadAndDuplication(t *testing.T) { {Name: "Content-type", Value: "application/x-www-form-urlencoded"}}, strings.NewReader(data.Encode())) Process(w, r, maxMemory) - resultDuplication := models.File{} + resultDuplication := models.FileApiOutput{} response, err = io.ReadAll(w.Result().Body) test.IsNil(t, err) err = json.Unmarshal(response, &resultDuplication) @@ -247,7 +247,7 @@ func TestUploadAndDuplication(t *testing.T) { test.IsEqualBool(t, resultDuplication.UnlimitedTime, false) test.IsEqualBool(t, resultDuplication.UnlimitedDownloads, false) test.IsEqualInt(t, resultDuplication.DownloadCount, 0) - test.IsEqualString(t, resultDuplication.PasswordHash, "") + test.IsEqualBool(t, resultDuplication.IsPasswordProtected, false) data = url.Values{} data.Set("id", newFileId) @@ -259,7 +259,7 @@ func TestUploadAndDuplication(t *testing.T) { {Name: "Content-type", Value: "application/x-www-form-urlencoded"}}, strings.NewReader(data.Encode())) Process(w, r, maxMemory) - resultDuplication = models.File{} + resultDuplication = models.FileApiOutput{} response, err = io.ReadAll(w.Result().Body) test.IsNil(t, err) err = json.Unmarshal(response, &resultDuplication) @@ -277,7 +277,7 @@ func TestUploadAndDuplication(t *testing.T) { {Name: "Content-type", Value: "application/x-www-form-urlencoded"}}, strings.NewReader(data.Encode())) Process(w, r, maxMemory) - resultDuplication = models.File{} + resultDuplication = models.FileApiOutput{} response, err = io.ReadAll(w.Result().Body) test.IsNil(t, err) err = json.Unmarshal(response, &resultDuplication) @@ -318,7 +318,7 @@ func TestUploadAndDuplication(t *testing.T) { {Name: "Content-type", Value: "application/x-www-form-urlencoded"}}, strings.NewReader(data.Encode())) Process(w, r, maxMemory) - resultDuplication = models.File{} + resultDuplication = models.FileApiOutput{} response, err = io.ReadAll(w.Result().Body) test.IsNil(t, err) err = json.Unmarshal(response, &resultDuplication) @@ -335,7 +335,7 @@ func TestUploadAndDuplication(t *testing.T) { {Name: "Content-type", Value: "application/x-www-form-urlencoded"}}, strings.NewReader(data.Encode())) Process(w, r, maxMemory) - resultDuplication = models.File{} + resultDuplication = models.FileApiOutput{} response, err = io.ReadAll(w.Result().Body) test.IsNil(t, err) err = json.Unmarshal(response, &resultDuplication) @@ -352,12 +352,12 @@ func TestUploadAndDuplication(t *testing.T) { {Name: "Content-type", Value: "application/x-www-form-urlencoded"}}, strings.NewReader(data.Encode())) Process(w, r, maxMemory) - resultDuplication = models.File{} + resultDuplication = models.FileApiOutput{} response, err = io.ReadAll(w.Result().Body) test.IsNil(t, err) err = json.Unmarshal(response, &resultDuplication) test.IsNil(t, err) - test.IsNotEqualString(t, resultDuplication.PasswordHash, "") + test.IsEqualBool(t, resultDuplication.IsPasswordProtected, true) data = url.Values{} data.Set("id", newFileId) @@ -368,12 +368,12 @@ func TestUploadAndDuplication(t *testing.T) { {Name: "Content-type", Value: "application/x-www-form-urlencoded"}}, strings.NewReader(data.Encode())) Process(w, r, maxMemory) - resultDuplication = models.File{} + resultDuplication = models.FileApiOutput{} response, err = io.ReadAll(w.Result().Body) test.IsNil(t, err) err = json.Unmarshal(response, &resultDuplication) test.IsNil(t, err) - test.IsEqualString(t, resultDuplication.PasswordHash, "") + test.IsEqualBool(t, resultDuplication.IsPasswordProtected, false) } func TestList(t *testing.T) { diff --git a/internal/webserver/web/static/apidocumentation/openapi.json b/internal/webserver/web/static/apidocumentation/openapi.json index b5fd2d0..4316736 100644 --- a/internal/webserver/web/static/apidocumentation/openapi.json +++ b/internal/webserver/web/static/apidocumentation/openapi.json @@ -217,12 +217,23 @@ "File": { "type": "object", "properties": { - "ContentType": { + "Id": { "type": "string" }, - "DownloadsRemaining": { - "type": "integer", - "format": "int64" + "Name": { + "type": "string" + }, + "Size": { + "type": "string" + }, + "SHA256": { + "type": "string" + }, + "HotlinkId": { + "type": "string" + }, + "ContentType": { + "type": "string" }, "ExpireAt": { "type": "integer", @@ -231,23 +242,31 @@ "ExpireAtString": { "type": "string" }, - "HotlinkId": { - "type": "string" + "DownloadsRemaining": { + "type": "integer", + "format": "int64" }, - "Id": { - "type": "string" + "DownloadCount": { + "type": "integer", + "format": "int64" }, - "Name": { - "type": "string" + "UnlimitedDownloads": { + "type": "boolean" }, - "PasswordHash": { - "type": "string" + "UnlimitedTime": { + "type": "boolean" }, - "SHA256": { - "type": "string" + "RequiresClientSideDecryption": { + "type": "boolean" }, - "Size": { - "type": "string" + "IsEncrypted": { + "type": "boolean" + }, + "IsPasswordProtected": { + "type": "boolean" + }, + "IsSavedOnLocalStorage": { + "type": "boolean" } }, "description": "File is a struct used for saving information about an uploaded file", @@ -316,11 +335,15 @@ }, "password": { "type": "string", - "description": "Password for this file to be set. No password will be used if empty-" + "description": "Password for this file to be set. No password will be used if empty." }, "originalPassword": { "type": "boolean", "description": "Set to true to use original password. Field \"password\" will be ignored if set." + }, + "filename": { + "type": "string", + "description": "Sets a new filename. Filename will be unchanged if empty." } } } diff --git a/internal/webserver/web/static/js/admin.js b/internal/webserver/web/static/js/admin.js index 39535e3..cbc416b 100644 --- a/internal/webserver/web/static/js/admin.js +++ b/internal/webserver/web/static/js/admin.js @@ -91,7 +91,7 @@ function addRow(jsonText) { let cellButtons = row.insertCell(6); let lockIcon = ""; - if (item.PasswordHash !== "") { + if (item.IsPasswordProtected === true) { lockIcon = " 🔒"; } cellFilename.innerText = item.Name; @@ -113,7 +113,7 @@ function addRow(jsonText) { if (item.HotlinkId !== "") { buttons = buttons + ' '; } else { - if (item.RequiresClientSideDecryption === false && item.PasswordHash === "") { + if (item.RequiresClientSideDecryption === false && item.IsPasswordProtected === false) { buttons = buttons + ' '; } else { buttons = buttons + ' '; diff --git a/internal/webserver/web/templates/html_admin.tmpl b/internal/webserver/web/templates/html_admin.tmpl index 6dc3eec..208b5fe 100644 --- a/internal/webserver/web/templates/html_admin.tmpl +++ b/internal/webserver/web/templates/html_admin.tmpl @@ -71,12 +71,12 @@ {{ .ExpireAtString }} {{ end }} {{ .DownloadCount }} - {{ $.Url }}{{ .Id }}{{ if ne .PasswordHash "" }} 🔒{{ end }} + {{ $.Url }}{{ .Id }}{{ if .IsPasswordProtected }} 🔒{{ end }} {{ if ne .HotlinkId "" }} {{ else }} - {{ if and (not .RequiresClientSideDecryption) (eq .PasswordHash "") }} + {{ if and (not .IsPasswordProtected) (not .RequiresClientSideDecryption) }} {{ else }} @@ -95,7 +95,7 @@ - +