mirror of
https://github.com/Forceu/Gokapi.git
synced 2026-05-24 08:48:50 -05:00
Use in-memory for presigned URLs instead of database, added tests
This commit is contained in:
@@ -18,7 +18,6 @@ var db dbabstraction.Database
|
||||
// Connect establishes a connection to the database and creates the table structure, if necessary
|
||||
func Connect(config models.DbConnection) {
|
||||
var err error
|
||||
dbcache.Init()
|
||||
db, err = dbabstraction.GetNew(config)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -354,20 +353,3 @@ func SaveFileRequest(request models.FileRequest) {
|
||||
func DeleteFileRequest(request models.FileRequest) {
|
||||
db.DeleteFileRequest(request)
|
||||
}
|
||||
|
||||
// Presigned URLs
|
||||
|
||||
// GetPresignedUrl returns the presigned url with the given ID or false if not a valid ID
|
||||
func GetPresignedUrl(id string) (models.Presign, bool) {
|
||||
return db.GetPresignedUrl(id)
|
||||
}
|
||||
|
||||
// DeletePresignedUrl deletes the presigned url with the given ID
|
||||
func DeletePresignedUrl(id string) {
|
||||
db.DeletePresignedUrl(id)
|
||||
}
|
||||
|
||||
// SavePresignedUrl saves the presigned url
|
||||
func SavePresignedUrl(presign models.Presign) {
|
||||
db.SavePresignedUrl(presign)
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ func TestUsers(t *testing.T) {
|
||||
}, 2)
|
||||
test.IsEqual(t, allUsersSqlite, allUsersRedis)
|
||||
runAllTypesNoOutput(t, func() {
|
||||
dbcache.Init()
|
||||
dbcache.ResetAll()
|
||||
UpdateUserLastOnline(1)
|
||||
})
|
||||
runAllTypesCompareTwoOutputs(t, func() (any, any) {
|
||||
|
||||
@@ -108,13 +108,6 @@ type Database interface {
|
||||
SaveFileRequest(request models.FileRequest)
|
||||
// DeleteFileRequest deletes a file request with the given ID
|
||||
DeleteFileRequest(request models.FileRequest)
|
||||
|
||||
// GetPresignedUrl returns the presigned url with the given ID or false if not a valid ID
|
||||
GetPresignedUrl(id string) (models.Presign, bool)
|
||||
// DeletePresignedUrl deletes the presigned url with the given ID
|
||||
DeletePresignedUrl(id string)
|
||||
// SavePresignedUrl saves the presigned url
|
||||
SavePresignedUrl(presign models.Presign)
|
||||
}
|
||||
|
||||
// GetNew connects to the given database and initialises it
|
||||
|
||||
@@ -5,14 +5,9 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var lastOnlineTimeUpdate map[int]int64
|
||||
var lastOnlineTimeUpdate = make(map[int]int64)
|
||||
var lastOnlineTimeMutex sync.Mutex
|
||||
|
||||
// Init starts the DB Cache
|
||||
func Init() {
|
||||
lastOnlineTimeUpdate = make(map[int]int64)
|
||||
}
|
||||
|
||||
// LastOnlineRequiresSave returns true if the last update time of the user is older than 60 seconds.
|
||||
func LastOnlineRequiresSave(userId int) bool {
|
||||
lastOnlineTimeMutex.Lock()
|
||||
@@ -24,3 +19,10 @@ func LastOnlineRequiresSave(userId int) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ResetAll is only used for testing purposes
|
||||
func ResetAll() {
|
||||
lastOnlineTimeMutex.Lock()
|
||||
lastOnlineTimeUpdate = make(map[int]int64)
|
||||
lastOnlineTimeMutex.Unlock()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package dbcache
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"testing/synctest"
|
||||
"time"
|
||||
|
||||
"github.com/forceu/gokapi/internal/test"
|
||||
)
|
||||
|
||||
func TestLastOnlineRequiresSave(t *testing.T) {
|
||||
synctest.Test(t, func(t *testing.T) {
|
||||
test.IsEqualBool(t, LastOnlineRequiresSave(100), true)
|
||||
test.IsEqualBool(t, LastOnlineRequiresSave(100), false)
|
||||
time.Sleep(61 * time.Second)
|
||||
test.IsEqualBool(t, LastOnlineRequiresSave(100), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestResetAll(t *testing.T) {
|
||||
LastOnlineRequiresSave(100)
|
||||
test.IsEqualInt(t, len(lastOnlineTimeUpdate), 1)
|
||||
ResetAll()
|
||||
test.IsEqualInt(t, len(lastOnlineTimeUpdate), 0)
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package redis
|
||||
|
||||
import (
|
||||
"github.com/forceu/gokapi/internal/helper"
|
||||
"github.com/forceu/gokapi/internal/models"
|
||||
redigo "github.com/gomodule/redigo/redis"
|
||||
)
|
||||
|
||||
const (
|
||||
prefixPresign = "ps:"
|
||||
)
|
||||
|
||||
// GetPresignedUrl returns the presigned url with the given ID or false if not a valid ID
|
||||
func (p DatabaseProvider) GetPresignedUrl(id string) (models.Presign, bool) {
|
||||
hashmapEntry, ok := p.getHashMap(prefixPresign + id)
|
||||
if !ok {
|
||||
return models.Presign{}, false
|
||||
}
|
||||
var result models.Presign
|
||||
err := redigo.ScanStruct(hashmapEntry, &result)
|
||||
helper.Check(err)
|
||||
return result, true
|
||||
}
|
||||
|
||||
// SavePresignedUrl saves the presigned url
|
||||
func (p DatabaseProvider) SavePresignedUrl(presign models.Presign) {
|
||||
p.setHashMap(p.buildArgs(prefixPresign + presign.Id).AddFlat(presign))
|
||||
p.setExpiryAt(prefixPresign+presign.Id, presign.Expiry)
|
||||
}
|
||||
|
||||
// DeletePresignedUrl deletes the presigned url with the given ID
|
||||
func (p DatabaseProvider) DeletePresignedUrl(id string) {
|
||||
p.deleteKey(prefixPresign + id)
|
||||
}
|
||||
@@ -62,14 +62,7 @@ func (p DatabaseProvider) Upgrade(currentDbVersion int) {
|
||||
"apiKey" TEXT NOT NULL UNIQUE,
|
||||
"note" TEXT NOT NULL,
|
||||
PRIMARY KEY("id")
|
||||
);
|
||||
CREATE TABLE "Presign" (
|
||||
"id" TEXT NOT NULL UNIQUE,
|
||||
"fileIds" TEXT NOT NULL,
|
||||
"expiry" INTEGER NOT NULL,
|
||||
"filename" TEXT NOT NULL,
|
||||
PRIMARY KEY("id")
|
||||
);`)
|
||||
);`)
|
||||
helper.Check(err)
|
||||
grantUploadPerm := environment.New().PermRequestGrantedByDefault
|
||||
for _, user := range p.GetAllUsers() {
|
||||
@@ -154,7 +147,6 @@ func (p DatabaseProvider) Close() {
|
||||
func (p DatabaseProvider) RunGarbageCollection() {
|
||||
p.cleanExpiredSessions()
|
||||
p.cleanApiKeys()
|
||||
p.cleanPresignedUrls()
|
||||
}
|
||||
|
||||
func (p DatabaseProvider) createNewDatabase() error {
|
||||
@@ -231,15 +223,7 @@ func (p DatabaseProvider) createNewDatabase() error {
|
||||
"apiKey" TEXT NOT NULL UNIQUE,
|
||||
"note" TEXT NOT NULL,
|
||||
PRIMARY KEY("id")
|
||||
);
|
||||
CREATE TABLE "Presign" (
|
||||
"id" TEXT NOT NULL UNIQUE,
|
||||
"fileIds" TEXT NOT NULL,
|
||||
"expiry" INTEGER NOT NULL,
|
||||
"filename" TEXT NOT NULL,
|
||||
PRIMARY KEY("id")
|
||||
);
|
||||
`
|
||||
);`
|
||||
err := p.rawSqlite(sqlStmt)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
package sqlite
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/forceu/gokapi/internal/helper"
|
||||
"github.com/forceu/gokapi/internal/models"
|
||||
)
|
||||
|
||||
type schemaPresign struct {
|
||||
Id string
|
||||
FileId string
|
||||
Expiry int64
|
||||
Filename string
|
||||
}
|
||||
|
||||
// GetPresignedUrl returns the presigned url with the given ID or false if not a valid ID
|
||||
func (p DatabaseProvider) GetPresignedUrl(id string) (models.Presign, bool) {
|
||||
var rowResult schemaPresign
|
||||
row := p.sqliteDb.QueryRow("SELECT * FROM Presign WHERE id = ?", id)
|
||||
err := row.Scan(&rowResult.Id, &rowResult.FileId, &rowResult.Expiry, &rowResult.Filename)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return models.Presign{}, false
|
||||
}
|
||||
helper.Check(err)
|
||||
return models.Presign{}, false
|
||||
}
|
||||
result := models.Presign{
|
||||
Id: rowResult.Id,
|
||||
FileIds: strings.Split(rowResult.FileId, ","),
|
||||
Expiry: rowResult.Expiry,
|
||||
Filename: rowResult.Filename,
|
||||
}
|
||||
return result, true
|
||||
}
|
||||
|
||||
// SavePresignedUrl saves the presigned url
|
||||
func (p DatabaseProvider) SavePresignedUrl(presign models.Presign) {
|
||||
_, err := p.sqliteDb.Exec("INSERT OR REPLACE INTO Presign (id, fileIds, expiry, filename) VALUES (?, ?, ?, ?)",
|
||||
presign.Id, strings.Join(presign.FileIds, ","), presign.Expiry, presign.Filename)
|
||||
helper.Check(err)
|
||||
}
|
||||
|
||||
// DeletePresignedUrl deletes the presigned url with the given ID
|
||||
func (p DatabaseProvider) DeletePresignedUrl(id string) {
|
||||
_, err := p.sqliteDb.Exec("DELETE FROM Presign WHERE id = ?", id)
|
||||
helper.Check(err)
|
||||
}
|
||||
|
||||
func (p DatabaseProvider) cleanPresignedUrls() {
|
||||
_, err := p.sqliteDb.Exec("DELETE FROM Presign WHERE expiry < ?", currentTime().Unix())
|
||||
helper.Check(err)
|
||||
}
|
||||
@@ -13,25 +13,18 @@ func TestApiKey_GetRedactedId(t *testing.T) {
|
||||
|
||||
func TestSetPermission(t *testing.T) {
|
||||
key := &ApiKey{}
|
||||
test.IsEqualBool(t, key.HasPermission(ApiPermView), false)
|
||||
key.GrantPermission(ApiPermView)
|
||||
if !key.HasPermission(ApiPermView) {
|
||||
t.Errorf("expected permission %d to be set", ApiPermView)
|
||||
}
|
||||
if key.HasPermission(ApiPermEdit) {
|
||||
t.Errorf("expected permission %d to be not set", ApiPermEdit)
|
||||
}
|
||||
test.IsEqualBool(t, key.HasPermission(ApiPermView), true)
|
||||
test.IsEqualBool(t, key.HasPermission(ApiPermEdit), false)
|
||||
}
|
||||
|
||||
func TestRemovePermission(t *testing.T) {
|
||||
key := &ApiKey{}
|
||||
key.GrantPermission(ApiPermView)
|
||||
if !key.HasPermission(ApiPermView) {
|
||||
t.Errorf("expected permission %d to be set", ApiPermView)
|
||||
}
|
||||
test.IsEqualBool(t, key.HasPermission(ApiPermView), true)
|
||||
key.RemovePermission(ApiPermView)
|
||||
if key.HasPermission(ApiPermView) {
|
||||
t.Errorf("expected permission %d to be removed", ApiPermView)
|
||||
}
|
||||
test.IsEqualBool(t, key.HasPermission(ApiPermView), false)
|
||||
}
|
||||
|
||||
func TestHasPermission(t *testing.T) {
|
||||
@@ -53,9 +46,7 @@ func TestHasPermission(t *testing.T) {
|
||||
|
||||
func TestHasPermissionView(t *testing.T) {
|
||||
key := &ApiKey{}
|
||||
if key.HasPermissionView() {
|
||||
t.Errorf("expected view permission to be not set")
|
||||
}
|
||||
test.IsEqualBool(t, key.HasPermissionManageFileRequests(), false)
|
||||
key.GrantPermission(ApiPermView)
|
||||
if !key.HasPermissionView() {
|
||||
t.Errorf("expected view permission to be set")
|
||||
@@ -64,6 +55,7 @@ func TestHasPermissionView(t *testing.T) {
|
||||
|
||||
func TestHasPermissionUpload(t *testing.T) {
|
||||
key := &ApiKey{}
|
||||
test.IsEqualBool(t, key.HasPermissionManageFileRequests(), false)
|
||||
key.GrantPermission(ApiPermUpload)
|
||||
if !key.HasPermissionUpload() {
|
||||
t.Errorf("expected upload permission to be set")
|
||||
@@ -72,6 +64,7 @@ func TestHasPermissionUpload(t *testing.T) {
|
||||
|
||||
func TestHasPermissionDelete(t *testing.T) {
|
||||
key := &ApiKey{}
|
||||
test.IsEqualBool(t, key.HasPermissionManageFileRequests(), false)
|
||||
key.GrantPermission(ApiPermDelete)
|
||||
if !key.HasPermissionDelete() {
|
||||
t.Errorf("expected delete permission to be set")
|
||||
@@ -80,6 +73,7 @@ func TestHasPermissionDelete(t *testing.T) {
|
||||
|
||||
func TestHasPermissionApiMod(t *testing.T) {
|
||||
key := &ApiKey{}
|
||||
test.IsEqualBool(t, key.HasPermissionManageFileRequests(), false)
|
||||
key.GrantPermission(ApiPermApiMod)
|
||||
if !key.HasPermissionApiMod() {
|
||||
t.Errorf("expected ApiMod permission to be set")
|
||||
@@ -88,6 +82,7 @@ func TestHasPermissionApiMod(t *testing.T) {
|
||||
|
||||
func TestHasPermissionEdit(t *testing.T) {
|
||||
key := &ApiKey{}
|
||||
test.IsEqualBool(t, key.HasPermissionManageFileRequests(), false)
|
||||
key.GrantPermission(ApiPermEdit)
|
||||
if !key.HasPermissionEdit() {
|
||||
t.Errorf("expected edit permission to be set")
|
||||
@@ -96,6 +91,7 @@ func TestHasPermissionEdit(t *testing.T) {
|
||||
|
||||
func TestHasPermissionReplace(t *testing.T) {
|
||||
key := &ApiKey{}
|
||||
test.IsEqualBool(t, key.HasPermissionManageFileRequests(), false)
|
||||
key.GrantPermission(ApiPermReplace)
|
||||
if !key.HasPermissionReplace() {
|
||||
t.Errorf("expected edit permission to be set")
|
||||
@@ -103,6 +99,7 @@ func TestHasPermissionReplace(t *testing.T) {
|
||||
}
|
||||
func TestHasPermissionManageUsers(t *testing.T) {
|
||||
key := &ApiKey{}
|
||||
test.IsEqualBool(t, key.HasPermissionManageFileRequests(), false)
|
||||
key.GrantPermission(ApiPermManageUsers)
|
||||
if !key.HasPermissionManageUsers() {
|
||||
t.Errorf("expected edit permission to be set")
|
||||
@@ -110,12 +107,26 @@ func TestHasPermissionManageUsers(t *testing.T) {
|
||||
}
|
||||
func TestHasPermissionManageLogs(t *testing.T) {
|
||||
key := &ApiKey{}
|
||||
test.IsEqualBool(t, key.HasPermissionManageFileRequests(), false)
|
||||
key.GrantPermission(ApiPermManageLogs)
|
||||
if !key.HasPermissionManageLogs() {
|
||||
t.Errorf("expected edit permission to be set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHasPermissionManageFileRequests(t *testing.T) {
|
||||
key := &ApiKey{}
|
||||
test.IsEqualBool(t, key.HasPermissionManageFileRequests(), false)
|
||||
key.GrantPermission(ApiPermManageFileRequests)
|
||||
test.IsEqualBool(t, key.HasPermissionManageFileRequests(), true)
|
||||
}
|
||||
func TestHasPPermissionDownload(t *testing.T) {
|
||||
key := &ApiKey{}
|
||||
test.IsEqualBool(t, key.HasPermissionDownload(), false)
|
||||
key.GrantPermission(ApiPermDownload)
|
||||
test.IsEqualBool(t, key.HasPermissionDownload(), true)
|
||||
}
|
||||
|
||||
func TestApiPermAllNoApiMod(t *testing.T) {
|
||||
key := &ApiKey{}
|
||||
key.GrantPermission(ApiPermDefault)
|
||||
@@ -141,6 +152,8 @@ func checkOnlyPermissionSet(t *testing.T, key *ApiKey, perm ApiPermission) {
|
||||
{ApiPermReplace, "ApiPermReplace"},
|
||||
{ApiPermManageUsers, "ApiPermManageUsers"},
|
||||
{ApiPermManageLogs, "ApiPermManageLogs"},
|
||||
{ApiPermManageFileRequests, "ApiPermManageFileRequests"},
|
||||
{ApiPermDownload, "ApiPermDownload"},
|
||||
}
|
||||
|
||||
for _, p := range allPermissions {
|
||||
@@ -172,6 +185,8 @@ func TestSetIndividualPermissions(t *testing.T) {
|
||||
{ApiPermReplace, "ApiPermReplace"},
|
||||
{ApiPermManageUsers, "ApiPermManageUsers"},
|
||||
{ApiPermManageLogs, "ApiPermManageLogs"},
|
||||
{ApiPermManageFileRequests, "ApiPermManageFileRequests"},
|
||||
{ApiPermDownload, "ApiPermDownload"},
|
||||
}
|
||||
|
||||
for _, p := range permissions {
|
||||
@@ -201,6 +216,8 @@ func TestSetCombinedPermissions(t *testing.T) {
|
||||
ApiPermReplace,
|
||||
ApiPermManageUsers,
|
||||
ApiPermManageLogs,
|
||||
ApiPermManageFileRequests,
|
||||
ApiPermDownload,
|
||||
}
|
||||
|
||||
// Test setting permissions in combination
|
||||
@@ -213,6 +230,13 @@ func TestSetCombinedPermissions(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestApiKey_IsUploadRequestKey(t *testing.T) {
|
||||
key := &ApiKey{Permissions: ApiPermManageFileRequests, UploadRequestId: "test"}
|
||||
test.IsEqualBool(t, key.IsUploadRequestKey(), true)
|
||||
key.UploadRequestId = ""
|
||||
test.IsEqualBool(t, key.IsUploadRequestKey(), false)
|
||||
}
|
||||
|
||||
func TestApiPermissionFromString(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -260,6 +284,16 @@ func TestApiPermissionFromString(t *testing.T) {
|
||||
input: "PERM_MANAGE_LOGS",
|
||||
wantPerm: ApiPermManageLogs,
|
||||
},
|
||||
{
|
||||
name: "PERM_MANAGE_FILE_REQUESTS",
|
||||
input: "PERM_MANAGE_FILE_REQUESTS",
|
||||
wantPerm: ApiPermManageFileRequests,
|
||||
},
|
||||
{
|
||||
name: "PERM_DOWNLOAD",
|
||||
input: "PERM_DOWNLOAD",
|
||||
wantPerm: ApiPermDownload,
|
||||
},
|
||||
{
|
||||
name: "invalid permission",
|
||||
input: "PERM_UNKNOWN",
|
||||
|
||||
@@ -2,7 +2,6 @@ package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
)
|
||||
|
||||
// Configuration is a struct that contains the global configuration
|
||||
@@ -26,7 +25,7 @@ type Configuration struct {
|
||||
IncludeFilename bool `json:"IncludeFilename"`
|
||||
}
|
||||
|
||||
// Encryption hold information about the encryption used on this file
|
||||
// Encryption holds information about the encryption used on this file
|
||||
type Encryption struct {
|
||||
Level int
|
||||
Cipher []byte
|
||||
@@ -35,20 +34,22 @@ type Encryption struct {
|
||||
ChecksumSalt string
|
||||
}
|
||||
|
||||
// ToJson returns an idented JSon representation
|
||||
// ToJson returns an indented Json representation
|
||||
func (c Configuration) ToJson() []byte {
|
||||
result, err := json.MarshalIndent(c, "", " ")
|
||||
if err != nil {
|
||||
log.Fatal("Error encoding configuration:", err)
|
||||
}
|
||||
checkError(err)
|
||||
return result
|
||||
}
|
||||
|
||||
// ToString returns the object as an unidented Json string used for test units
|
||||
// ToString returns the object as an unindented JSON string used for test units
|
||||
func (c Configuration) ToString() string {
|
||||
result, err := json.Marshal(c)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
checkError(err)
|
||||
return string(result)
|
||||
}
|
||||
|
||||
func checkError(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -43,7 +44,12 @@ func TestConfiguration_ToJson(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestConfiguration_ToString(t *testing.T) {
|
||||
test.IsEqualString(t, testConfig.ToString(), exptectedUnidentedOutput)
|
||||
test.IsEqualString(t, testConfig.ToString(), expectedUnindentedOutput)
|
||||
}
|
||||
|
||||
const exptectedUnidentedOutput = `{"Authentication":{"Method":0,"SaltAdmin":"saltadmin","SaltFiles":"saltfiles","Username":"admin","HeaderKey":"","OauthProvider":"","OAuthClientId":"","OAuthClientSecret":"","OauthGroupScope":"","OAuthRecheckInterval":0,"OAuthGroups":null,"OnlyRegisteredUsers":false},"Port":":12345","ServerUrl":"https://testserver.com/","RedirectUrl":"https://test.com","PublicName":"public-name","DataDir":"test","DatabaseUrl":"sqlite://./test/gokapitest.sqlite","ConfigVersion":14,"MaxFileSizeMB":20,"MaxMemory":50,"ChunkSize":0,"MaxParallelUploads":0,"Encryption":{"Level":1,"Cipher":"AA==","Salt":"encsalt","Checksum":"encsum","ChecksumSalt":"encsumsalt"},"UseSsl":true,"PicturesAlwaysLocal":true,"SaveIp":false,"IncludeFilename":false}`
|
||||
func TestCheck(t *testing.T) {
|
||||
defer test.ExpectPanic(t)
|
||||
checkError(errors.New("test"))
|
||||
}
|
||||
|
||||
const expectedUnindentedOutput = `{"Authentication":{"Method":0,"SaltAdmin":"saltadmin","SaltFiles":"saltfiles","Username":"admin","HeaderKey":"","OauthProvider":"","OAuthClientId":"","OAuthClientSecret":"","OauthGroupScope":"","OAuthRecheckInterval":0,"OAuthGroups":null,"OnlyRegisteredUsers":false},"Port":":12345","ServerUrl":"https://testserver.com/","RedirectUrl":"https://test.com","PublicName":"public-name","DataDir":"test","DatabaseUrl":"sqlite://./test/gokapitest.sqlite","ConfigVersion":14,"MaxFileSizeMB":20,"MaxMemory":50,"ChunkSize":0,"MaxParallelUploads":0,"Encryption":{"Level":1,"Cipher":"AA==","Salt":"encsalt","Checksum":"encsum","ChecksumSalt":"encsumsalt"},"UseSsl":true,"PicturesAlwaysLocal":true,"SaveIp":false,"IncludeFilename":false}`
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/forceu/gokapi/internal/test"
|
||||
)
|
||||
|
||||
func TestFileRequest_PopulateAndHelpers(t *testing.T) {
|
||||
now := time.Now().Unix()
|
||||
|
||||
files := map[string]File{
|
||||
"file1": {
|
||||
Id: "file1",
|
||||
UploadRequestId: "req1",
|
||||
SizeBytes: 1000,
|
||||
UploadDate: now - 100,
|
||||
},
|
||||
"file2": {
|
||||
Id: "file2",
|
||||
UploadRequestId: "req1",
|
||||
SizeBytes: 2000,
|
||||
UploadDate: now,
|
||||
},
|
||||
"file3": {
|
||||
Id: "file3",
|
||||
UploadRequestId: "other",
|
||||
SizeBytes: 9999,
|
||||
UploadDate: now,
|
||||
},
|
||||
}
|
||||
|
||||
fr := &FileRequest{
|
||||
Id: "req1",
|
||||
MaxFiles: 5,
|
||||
MaxSize: 10,
|
||||
}
|
||||
|
||||
fr.Populate(files, 8)
|
||||
test.IsEqualInt(t, fr.UploadedFiles, 2)
|
||||
test.IsEqualInt(t, fr.MaxFiles, 5)
|
||||
test.IsEqualInt(t, fr.CombinedMaxSize, 8)
|
||||
test.IsEqualInt(t, fr.FilesRemaining(), 3)
|
||||
|
||||
test.IsEqualInt64(t, fr.TotalFileSize, int64(3000))
|
||||
test.IsEqualInt64(t, fr.LastUpload, now)
|
||||
test.IsEqualInt(t, len(fr.FileIdList), 2)
|
||||
|
||||
test.IsNotEqualString(t, fr.GetReadableDateLastUpdate(), "None")
|
||||
test.IsNotEqualString(t, fr.GetFilesAsString(), "")
|
||||
|
||||
fr = &FileRequest{
|
||||
Id: "req2",
|
||||
UploadedFiles: 5,
|
||||
MaxFiles: 2,
|
||||
TotalFileSize: 102400,
|
||||
}
|
||||
test.IsEqualInt(t, fr.FilesRemaining(), 0)
|
||||
test.IsEqualString(t, fr.GetReadableDateLastUpdate(), "None")
|
||||
test.IsEqualString(t, fr.GetReadableTotalSize(), "100.0 kB")
|
||||
|
||||
}
|
||||
|
||||
func TestFileRequest_UnlimitedFlags(t *testing.T) {
|
||||
fr := &FileRequest{
|
||||
MaxFiles: 0,
|
||||
MaxSize: 0,
|
||||
Expiry: 0,
|
||||
}
|
||||
|
||||
test.IsEqualBool(t, fr.IsUnlimitedFiles(), true)
|
||||
test.IsEqualBool(t, fr.IsUnlimitedSize(), true)
|
||||
test.IsEqualBool(t, fr.IsUnlimitedTime(), true)
|
||||
test.IsEqualBool(t, !fr.HasRestrictions(), true)
|
||||
}
|
||||
|
||||
func TestFileRequest_IsExpired(t *testing.T) {
|
||||
fr := &FileRequest{
|
||||
Expiry: time.Now().Unix() - 10,
|
||||
}
|
||||
|
||||
test.IsEqualBool(t, fr.IsExpired(), true)
|
||||
}
|
||||
@@ -16,7 +16,8 @@ func TestUserPermAll(t *testing.T) {
|
||||
!user.HasPermission(UserPermReplaceOtherUploads) ||
|
||||
!user.HasPermission(UserPermManageLogs) ||
|
||||
!user.HasPermission(UserPermManageApiKeys) ||
|
||||
!user.HasPermission(UserPermManageUsers) {
|
||||
!user.HasPermission(UserPermManageUsers) ||
|
||||
!user.HasPermission(UserPermGuestUploads) {
|
||||
t.Errorf("expected all permissions to be set")
|
||||
}
|
||||
}
|
||||
@@ -35,6 +36,7 @@ func checkOnlyUserPermissionSet(t *testing.T, user *User, perm UserPermission) {
|
||||
{UserPermManageLogs, "UserPermManageLogs"},
|
||||
{UserPermManageApiKeys, "UserPermManageApiKeys"},
|
||||
{UserPermManageUsers, "UserPermManageUsers"},
|
||||
{UserPermGuestUploads, "UserPermGuestUploads"},
|
||||
}
|
||||
|
||||
for _, p := range allPermissions {
|
||||
@@ -66,6 +68,7 @@ func TestSetIndividualUserPermissions(t *testing.T) {
|
||||
{UserPermManageLogs, "UserPermManageLogs"},
|
||||
{UserPermManageApiKeys, "UserPermManageApiKeys"},
|
||||
{UserPermManageUsers, "UserPermManageUsers"},
|
||||
{UserPermGuestUploads, "UserPermGuestUploads"},
|
||||
}
|
||||
|
||||
for _, p := range permissions {
|
||||
@@ -95,6 +98,7 @@ func TestSetCombinedUserPermissions(t *testing.T) {
|
||||
UserPermManageLogs,
|
||||
UserPermManageApiKeys,
|
||||
UserPermManageUsers,
|
||||
UserPermGuestUploads,
|
||||
}
|
||||
|
||||
// Test setting permissions in combination
|
||||
@@ -133,6 +137,19 @@ func TestUser_IsSuperAdmin(t *testing.T) {
|
||||
test.IsEqualBool(t, user.IsSuperAdmin(), false)
|
||||
}
|
||||
|
||||
func TestUser_IsAdmin(t *testing.T) {
|
||||
user := &User{
|
||||
UserLevel: UserLevelSuperAdmin,
|
||||
}
|
||||
test.IsEqualBool(t, user.IsAdmin(), true)
|
||||
user.UserLevel = UserLevelAdmin
|
||||
test.IsEqualBool(t, user.IsAdmin(), true)
|
||||
user.UserLevel = UserLevelUser
|
||||
test.IsEqualBool(t, user.IsAdmin(), false)
|
||||
user.UserLevel = 4
|
||||
test.IsEqualBool(t, user.IsAdmin(), false)
|
||||
}
|
||||
|
||||
func TestUser_IsSameUser(t *testing.T) {
|
||||
user := &User{
|
||||
Id: 5,
|
||||
@@ -239,6 +256,13 @@ func TestUser_HasPermissionManageUsers(t *testing.T) {
|
||||
test.IsEqualBool(t, user.HasPermissionManageUsers(), true)
|
||||
}
|
||||
|
||||
func TestUser_HasPermissionManageGuestUploads(t *testing.T) {
|
||||
user := &User{}
|
||||
test.IsEqualBool(t, user.HasPermissionCreateFileRequests(), false)
|
||||
user.GrantPermission(UserPermGuestUploads)
|
||||
test.IsEqualBool(t, user.HasPermissionCreateFileRequests(), true)
|
||||
}
|
||||
|
||||
func TestUser_ToJson(t *testing.T) {
|
||||
user := &User{
|
||||
Id: 4,
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package presign
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/forceu/gokapi/internal/models"
|
||||
)
|
||||
|
||||
var presignedUrls = make(map[string]models.Presign)
|
||||
var mutex sync.RWMutex
|
||||
var cleanupStarted = false
|
||||
|
||||
// Save saves the presigned url
|
||||
func Save(presign models.Presign) {
|
||||
mutex.Lock()
|
||||
presignedUrls[presign.Id] = presign
|
||||
mutex.Unlock()
|
||||
go cleanUp(true)
|
||||
}
|
||||
|
||||
// Get returns the presigned url with the given ID or false if not a valid ID
|
||||
func Get(id string) (models.Presign, bool) {
|
||||
mutex.RLock()
|
||||
defer mutex.RUnlock()
|
||||
result, ok := presignedUrls[id]
|
||||
if !ok {
|
||||
return models.Presign{}, false
|
||||
}
|
||||
if result.Expiry < time.Now().Unix() {
|
||||
return models.Presign{}, false
|
||||
}
|
||||
return result, true
|
||||
}
|
||||
|
||||
// Delete deletes the presigned url with the given ID
|
||||
func Delete(id string) {
|
||||
mutex.Lock()
|
||||
delete(presignedUrls, id)
|
||||
mutex.Unlock()
|
||||
}
|
||||
|
||||
func cleanUp(periodic bool) {
|
||||
if cleanupStarted {
|
||||
return
|
||||
}
|
||||
cleanupStarted = true
|
||||
mutex.Lock()
|
||||
for k, v := range presignedUrls {
|
||||
if v.Expiry < time.Now().Unix() {
|
||||
delete(presignedUrls, k)
|
||||
}
|
||||
}
|
||||
mutex.Unlock()
|
||||
if periodic {
|
||||
select {
|
||||
case <-time.After(20 * time.Minute):
|
||||
go cleanUp(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ import (
|
||||
"github.com/forceu/gokapi/internal/models"
|
||||
"github.com/forceu/gokapi/internal/storage"
|
||||
"github.com/forceu/gokapi/internal/storage/filerequest"
|
||||
"github.com/forceu/gokapi/internal/storage/presign"
|
||||
"github.com/forceu/gokapi/internal/webserver/api"
|
||||
"github.com/forceu/gokapi/internal/webserver/authentication"
|
||||
"github.com/forceu/gokapi/internal/webserver/authentication/oauth"
|
||||
@@ -986,13 +987,13 @@ func downloadPresigned(w http.ResponseWriter, r *http.Request) {
|
||||
responseError(w, storage.ErrorInvalidPresign)
|
||||
return
|
||||
}
|
||||
presign, ok := database.GetPresignedUrl(presignKey[0])
|
||||
if !ok || presign.Expiry < time.Now().Unix() {
|
||||
presignedUrl, ok := presign.Get(presignKey[0])
|
||||
if !ok {
|
||||
responseError(w, storage.ErrorInvalidPresign)
|
||||
return
|
||||
}
|
||||
files := make([]models.File, 0)
|
||||
for _, file := range presign.FileIds {
|
||||
for _, file := range presignedUrl.FileIds {
|
||||
storedFile, ok := storage.GetFile(file)
|
||||
if !ok {
|
||||
responseError(w, storage.ErrorFileNotFound)
|
||||
@@ -1000,13 +1001,13 @@ func downloadPresigned(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
files = append(files, storedFile)
|
||||
}
|
||||
database.DeletePresignedUrl(presign.Id)
|
||||
presign.Delete(presignedUrl.Id)
|
||||
|
||||
if len(files) == 1 {
|
||||
storage.ServeFile(files[0], w, r, true, false, true)
|
||||
return
|
||||
}
|
||||
storage.ServeFilesAsZip(files, presign.Filename, w, r)
|
||||
storage.ServeFilesAsZip(files, presignedUrl.Filename, w, r)
|
||||
}
|
||||
|
||||
func serveFile(id string, isRootUrl bool, w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"github.com/forceu/gokapi/internal/storage/chunking/chunkreservation"
|
||||
"github.com/forceu/gokapi/internal/storage/filerequest"
|
||||
"github.com/forceu/gokapi/internal/storage/filerequest/ratelimiter"
|
||||
"github.com/forceu/gokapi/internal/storage/presign"
|
||||
"github.com/forceu/gokapi/internal/webserver/api/errorcodes"
|
||||
"github.com/forceu/gokapi/internal/webserver/authentication/users"
|
||||
"github.com/forceu/gokapi/internal/webserver/fileupload"
|
||||
@@ -642,7 +643,7 @@ func createAndOutputPresignedUrl(ids []string, w http.ResponseWriter, filename s
|
||||
Expiry: time.Now().Add(time.Second * 30).Unix(),
|
||||
Filename: filename,
|
||||
}
|
||||
database.SavePresignedUrl(presignUrl)
|
||||
presign.Save(presignUrl)
|
||||
response := struct {
|
||||
Result string `json:"Result"`
|
||||
DownloadUrl string `json:"downloadUrl"`
|
||||
|
||||
Reference in New Issue
Block a user