Add support for direct downloads of server files
This commit is contained in:
parent
cc54b99b55
commit
3edcd5f9c3
|
@ -15,6 +15,7 @@ func Configure() *gin.Engine {
|
||||||
|
|
||||||
// These routes use signed URLs to validate access to the resource being requested.
|
// These routes use signed URLs to validate access to the resource being requested.
|
||||||
router.GET("/download/backup", getDownloadBackup)
|
router.GET("/download/backup", getDownloadBackup)
|
||||||
|
router.GET("/download/file", getDownloadFile)
|
||||||
|
|
||||||
// This route is special it sits above all of the other requests because we are
|
// This route is special it sits above all of the other requests because we are
|
||||||
// using a JWT to authorize access to it, therefore it needs to be publicly
|
// using a JWT to authorize access to it, therefore it needs to be publicly
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Handle a download request for a server backup.
|
||||||
func getDownloadBackup(c *gin.Context) {
|
func getDownloadBackup(c *gin.Context) {
|
||||||
token := tokens.BackupPayload{}
|
token := tokens.BackupPayload{}
|
||||||
if err := tokens.ParseToken([]byte(c.Query("token")), &token); err != nil {
|
if err := tokens.ParseToken([]byte(c.Query("token")), &token); err != nil {
|
||||||
|
@ -43,3 +44,46 @@ func getDownloadBackup(c *gin.Context) {
|
||||||
|
|
||||||
bufio.NewReader(f).WriteTo(c.Writer)
|
bufio.NewReader(f).WriteTo(c.Writer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handles downloading a specific file for a server.
|
||||||
|
func getDownloadFile(c *gin.Context) {
|
||||||
|
token := tokens.FilePayload{}
|
||||||
|
if err := tokens.ParseToken([]byte(c.Query("token")), &token); err != nil {
|
||||||
|
TrackedError(err).AbortWithServerError(c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s := GetServer(token.ServerUuid)
|
||||||
|
if s == nil || !token.IsUniqueRequest() {
|
||||||
|
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{
|
||||||
|
"error": "The requested resource was not found on this server.",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p, _ := s.Filesystem.SafePath(token.FilePath)
|
||||||
|
st, err := os.Stat(p)
|
||||||
|
// If there is an error or we're somehow trying to download a directory, just
|
||||||
|
// respond with the appropriate error.
|
||||||
|
if err != nil {
|
||||||
|
TrackedServerError(err, s).AbortWithServerError(c)
|
||||||
|
return
|
||||||
|
} else if st.IsDir() {
|
||||||
|
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{
|
||||||
|
"error": "The requested resource was not found on this server.",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Open(p)
|
||||||
|
if err != nil {
|
||||||
|
TrackedServerError(err, s).AbortWithServerError(c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Header("Content-Length", strconv.Itoa(int(st.Size())))
|
||||||
|
c.Header("Content-Disposition", "attachment; filename="+st.Name())
|
||||||
|
c.Header("Content-Type", "application/octet-stream")
|
||||||
|
|
||||||
|
bufio.NewReader(f).WriteTo(c.Writer)
|
||||||
|
}
|
25
router/tokens/file.go
Normal file
25
router/tokens/file.go
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
package tokens
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gbrlsnchs/jwt/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FilePayload struct {
|
||||||
|
jwt.Payload
|
||||||
|
FilePath string `json:"file_path"`
|
||||||
|
ServerUuid string `json:"server_uuid"`
|
||||||
|
UniqueId string `json:"unique_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the JWT payload.
|
||||||
|
func (p *FilePayload) GetPayload() *jwt.Payload {
|
||||||
|
return &p.Payload
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determines if this JWT is valid for the given request cycle. If the
|
||||||
|
// unique ID passed in the token has already been seen before this will
|
||||||
|
// return false. This allows us to use this JWT as a one-time token that
|
||||||
|
// validates all of the request.
|
||||||
|
func (p *FilePayload) IsUniqueRequest() bool {
|
||||||
|
return getTokenStore().IsValidToken(p.UniqueId)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user