refactor(tus): add auth requirement on TUS and add support for tracking and storing the uploader throughout the upload lifecycle
This commit is contained in:
parent
0bc862e35d
commit
ceb729f11d
25
main.go
25
main.go
|
@ -1,18 +1,22 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"embed"
|
"embed"
|
||||||
"git.lumeweb.com/LumeWeb/portal/config"
|
"git.lumeweb.com/LumeWeb/portal/config"
|
||||||
"git.lumeweb.com/LumeWeb/portal/controller"
|
"git.lumeweb.com/LumeWeb/portal/controller"
|
||||||
"git.lumeweb.com/LumeWeb/portal/db"
|
"git.lumeweb.com/LumeWeb/portal/db"
|
||||||
_ "git.lumeweb.com/LumeWeb/portal/docs"
|
_ "git.lumeweb.com/LumeWeb/portal/docs"
|
||||||
"git.lumeweb.com/LumeWeb/portal/logger"
|
"git.lumeweb.com/LumeWeb/portal/logger"
|
||||||
|
"git.lumeweb.com/LumeWeb/portal/middleware"
|
||||||
"git.lumeweb.com/LumeWeb/portal/service/auth"
|
"git.lumeweb.com/LumeWeb/portal/service/auth"
|
||||||
"git.lumeweb.com/LumeWeb/portal/service/files"
|
"git.lumeweb.com/LumeWeb/portal/service/files"
|
||||||
|
"git.lumeweb.com/LumeWeb/portal/shared"
|
||||||
"git.lumeweb.com/LumeWeb/portal/tus"
|
"git.lumeweb.com/LumeWeb/portal/tus"
|
||||||
"github.com/iris-contrib/swagger"
|
"github.com/iris-contrib/swagger"
|
||||||
"github.com/iris-contrib/swagger/swaggerFiles"
|
"github.com/iris-contrib/swagger/swaggerFiles"
|
||||||
"github.com/kataras/iris/v12"
|
"github.com/kataras/iris/v12"
|
||||||
|
irisContext "github.com/kataras/iris/v12/context"
|
||||||
"github.com/kataras/iris/v12/middleware/cors"
|
"github.com/kataras/iris/v12/middleware/cors"
|
||||||
"github.com/kataras/iris/v12/mvc"
|
"github.com/kataras/iris/v12/mvc"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
@ -60,6 +64,8 @@ func main() {
|
||||||
api := app.Party("/api")
|
api := app.Party("/api")
|
||||||
v1 := api.Party("/v1")
|
v1 := api.Party("/v1")
|
||||||
|
|
||||||
|
tusHandler := tus.Init()
|
||||||
|
|
||||||
// Register the AccountController with the MVC framework and attach it to the "/api/account" path
|
// Register the AccountController with the MVC framework and attach it to the "/api/account" path
|
||||||
mvc.Configure(v1.Party("/account"), func(app *mvc.Application) {
|
mvc.Configure(v1.Party("/account"), func(app *mvc.Application) {
|
||||||
app.Handle(new(controller.AccountController))
|
app.Handle(new(controller.AccountController))
|
||||||
|
@ -70,15 +76,22 @@ func main() {
|
||||||
})
|
})
|
||||||
|
|
||||||
mvc.Configure(v1.Party("/files"), func(app *mvc.Application) {
|
mvc.Configure(v1.Party("/files"), func(app *mvc.Application) {
|
||||||
|
tusRoute := app.Router.Party(tus.TUS_API_PATH)
|
||||||
|
tusRoute.Use(middleware.VerifyJwt)
|
||||||
|
|
||||||
|
fromStd := func(handler http.Handler) func(ctx *irisContext.Context) {
|
||||||
|
return func(ctx *irisContext.Context) {
|
||||||
|
newCtx := context.WithValue(ctx.Request().Context(), shared.TusRequestContextKey, ctx)
|
||||||
|
handler.ServeHTTP(ctx.ResponseWriter(), ctx.Request().WithContext(newCtx))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tusRoute.Any("/{fileparam:path}", fromStd(http.StripPrefix(v1.GetRelPath()+tus.TUS_API_PATH+"/", tusHandler)))
|
||||||
|
tusRoute.Post("/", fromStd(http.StripPrefix(tusRoute.GetRelPath()+tus.TUS_API_PATH, tusHandler)))
|
||||||
|
|
||||||
app.Handle(new(controller.FilesController))
|
app.Handle(new(controller.FilesController))
|
||||||
app.Router.Use()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
tusHandler := tus.Init()
|
|
||||||
|
|
||||||
v1.Any(tus.TUS_API_PATH+"/{fileparam:path}", iris.FromStd(http.StripPrefix(v1.GetRelPath()+tus.TUS_API_PATH+"/", tusHandler)))
|
|
||||||
v1.Post(tus.TUS_API_PATH, iris.FromStd(http.StripPrefix(v1.GetRelPath()+tus.TUS_API_PATH, tusHandler)))
|
|
||||||
|
|
||||||
swaggerConfig := swagger.Config{
|
swaggerConfig := swagger.Config{
|
||||||
// The url pointing to API definition.
|
// The url pointing to API definition.
|
||||||
URL: "http://localhost:8080/swagger/doc.json",
|
URL: "http://localhost:8080/swagger/doc.json",
|
||||||
|
|
10
model/tus.go
10
model/tus.go
|
@ -6,8 +6,10 @@ import (
|
||||||
|
|
||||||
type Tus struct {
|
type Tus struct {
|
||||||
gorm.Model
|
gorm.Model
|
||||||
ID uint64 `gorm:"primaryKey"`
|
ID uint64 `gorm:"primaryKey"`
|
||||||
UploadID string
|
UploadID string
|
||||||
Hash string
|
Hash string
|
||||||
Info string
|
Info string
|
||||||
|
AccountID uint
|
||||||
|
Account Account
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,12 @@ var tusStore *interface{}
|
||||||
var tusComposer *interface{}
|
var tusComposer *interface{}
|
||||||
var tusWorker TusFunc
|
var tusWorker TusFunc
|
||||||
|
|
||||||
|
type tusRequestContextKey int
|
||||||
|
|
||||||
|
const (
|
||||||
|
TusRequestContextKey tusRequestContextKey = iota
|
||||||
|
)
|
||||||
|
|
||||||
func SetTusQueue(q interface{}) {
|
func SetTusQueue(q interface{}) {
|
||||||
tusQueue = &q
|
tusQueue = &q
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"io"
|
"io"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
const TUS_API_PATH = "/files/tus"
|
const TUS_API_PATH = "/files/tus"
|
||||||
|
@ -167,7 +168,9 @@ func tusWorker(upload *tusd.Upload) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
newUpload, err := files.Upload(file.(io.ReadSeeker), info.Size, hashBytes)
|
uploader, _ := strconv.Atoi(info.Storage["uploader"])
|
||||||
|
|
||||||
|
newUpload, err := files.Upload(file.(io.ReadSeeker), info.Size, hashBytes, uint(uploader))
|
||||||
tErr := terminateUpload(*upload)
|
tErr := terminateUpload(*upload)
|
||||||
|
|
||||||
if tErr != nil {
|
if tErr != nil {
|
||||||
|
|
|
@ -9,13 +9,17 @@ import (
|
||||||
"git.lumeweb.com/LumeWeb/portal/db"
|
"git.lumeweb.com/LumeWeb/portal/db"
|
||||||
"git.lumeweb.com/LumeWeb/portal/logger"
|
"git.lumeweb.com/LumeWeb/portal/logger"
|
||||||
"git.lumeweb.com/LumeWeb/portal/model"
|
"git.lumeweb.com/LumeWeb/portal/model"
|
||||||
|
"git.lumeweb.com/LumeWeb/portal/service/auth"
|
||||||
"git.lumeweb.com/LumeWeb/portal/shared"
|
"git.lumeweb.com/LumeWeb/portal/shared"
|
||||||
"github.com/golang-queue/queue"
|
"github.com/golang-queue/queue"
|
||||||
|
clone "github.com/huandu/go-clone/generic"
|
||||||
|
"github.com/kataras/iris/v12"
|
||||||
"github.com/tus/tusd/pkg/handler"
|
"github.com/tus/tusd/pkg/handler"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
var defaultFilePerm = os.FileMode(0664)
|
var defaultFilePerm = os.FileMode(0664)
|
||||||
|
@ -61,10 +65,13 @@ func (store DbFileStore) NewUpload(ctx context.Context, info handler.FileInfo) (
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
irisContext := ctx.Value(shared.TusRequestContextKey).(iris.Context)
|
||||||
|
|
||||||
upload := &fileUpload{
|
upload := &fileUpload{
|
||||||
info: info,
|
info: info,
|
||||||
binPath: binPath,
|
binPath: binPath,
|
||||||
hash: info.MetaData["hash"],
|
hash: info.MetaData["hash"],
|
||||||
|
uploader: auth.GetCurrentUserId(irisContext),
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeInfo creates the file by itself if necessary
|
// writeInfo creates the file by itself if necessary
|
||||||
|
@ -138,11 +145,15 @@ type fileUpload struct {
|
||||||
// info stores the current information about the upload
|
// info stores the current information about the upload
|
||||||
info handler.FileInfo
|
info handler.FileInfo
|
||||||
// binPath is the path to the binary file (which has no extension)
|
// binPath is the path to the binary file (which has no extension)
|
||||||
binPath string
|
binPath string
|
||||||
hash string
|
hash string
|
||||||
|
uploader uint
|
||||||
}
|
}
|
||||||
|
|
||||||
func (upload *fileUpload) GetInfo(ctx context.Context) (handler.FileInfo, error) {
|
func (upload *fileUpload) GetInfo(ctx context.Context) (handler.FileInfo, error) {
|
||||||
|
info := clone.Clone(upload.info)
|
||||||
|
info.Storage["uploader"] = strconv.Itoa(int(upload.uploader))
|
||||||
|
|
||||||
return upload.info, nil
|
return upload.info, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,7 +251,7 @@ func (upload *fileUpload) writeInfo() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
tusRecord = &model.Tus{UploadID: upload.info.ID, Hash: upload.hash, Info: string(data)}
|
tusRecord = &model.Tus{UploadID: upload.info.ID, Hash: upload.hash, Info: string(data), AccountID: upload.uploader}
|
||||||
|
|
||||||
if ret := db.Get().Create(&tusRecord); ret.Error != nil {
|
if ret := db.Get().Create(&tusRecord); ret.Error != nil {
|
||||||
logger.Get().Error("failed to create tus entry", zap.Error(ret.Error))
|
logger.Get().Error("failed to create tus entry", zap.Error(ret.Error))
|
||||||
|
|
Loading…
Reference in New Issue