Skip to content
This repository has been archived by the owner on Jun 20, 2024. It is now read-only.

Commit

Permalink
Disallow start and end coordinates for encrypted files
Browse files Browse the repository at this point in the history
  • Loading branch information
MalinAhlberg committed Feb 7, 2024
1 parent 381c010 commit d5f1348
Showing 1 changed file with 66 additions and 79 deletions.
145 changes: 66 additions & 79 deletions api/sda/sda.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ func Download(c *gin.Context) {
c.String(http.StatusUnauthorized, "unauthorised")

return

}

// Get file header
Expand All @@ -166,6 +167,43 @@ func Download(c *gin.Context) {
return
}

// Get query params
qStart := c.DefaultQuery("startCoordinate", "0")
qEnd := c.DefaultQuery("endCoordinate", "0")

// Parse and verify coordinates are valid
start, err := strconv.ParseInt(qStart, 10, 0)

if err != nil {
log.Errorf("failed to convert start coordinate %d to integer, %s", start, err)
c.String(http.StatusBadRequest, "startCoordinate must be an integer")

return
}
end, err := strconv.ParseInt(qEnd, 10, 0)
if err != nil {
log.Errorf("failed to convert end coordinate %d to integer, %s", end, err)

c.String(http.StatusBadRequest, "endCoordinate must be an integer")

return
}
if end < start {
log.Errorf("endCoordinate=%d must be greater than startCoordinate=%d", end, start)

c.String(http.StatusBadRequest, "endCoordinate must be greater than startCoordinate")

return
}

if start == 0 && end == 0 {
c.Header("Content-Length", fmt.Sprint(fileDetails.DecryptedSize))
} else {
// Calculate how much we should read (if given)
togo := end - start
c.Header("Content-Length", fmt.Sprint(togo))
}

// Get archive file handle
file, err := Backend.NewFileReader(fileDetails.ArchivePath)
if err != nil {
Expand Down Expand Up @@ -195,65 +233,41 @@ func Download(c *gin.Context) {
return
}

// Stitch file and prepare it for streaming
var fileStream *streaming.Crypt4GHReader
// Prepare the file for streaming, encrypted or decrypted
var encryptedFileReader io.Reader
var fileStream io.Reader
hr := bytes.NewReader(fileDetails.Header)
encryptedFileReader = io.MultiReader(hr, file)

switch c.Param("type") {
case "encrypted":
log.Print("Return encrypted file")
fileStream, err = stitchEncryptedFile(fileDetails.Header, file)
if err != nil {
log.Errorf("could not prepare file for streaming, %s", err)
c.String(http.StatusInternalServerError, "file stream error")
if start > 0 || end > 0 {
// unset content-length
c.Header("Content-Length", "-1")
log.Errorf("Start and end coordinates for encrypted files not implemented! %v", start)
c.String(http.StatusInternalServerError, "an error occurred")

return
}
c.Header("Content-Length", "")
fileStream = encryptedFileReader

default:
// Stitch file and prepare it for streaming
fileStream, err = stitchFile(fileDetails.Header, file)
c4ghfileStream, err := streaming.NewCrypt4GHReader(encryptedFileReader, *config.Config.App.Crypt4GHKey, nil)
defer c4ghfileStream.Close()
if err != nil {
log.Errorf("could not prepare file for streaming, %s", err)
c.String(http.StatusInternalServerError, "file stream error")

return
}
}

// Get query params
qStart := c.DefaultQuery("startCoordinate", "0")
qEnd := c.DefaultQuery("endCoordinate", "0")

// Parse and verify coordinates are valid
start, err := strconv.ParseInt(qStart, 10, 0)

if err != nil {
log.Errorf("failed to convert start coordinate %d to integer, %s", start, err)
c.String(http.StatusBadRequest, "startCoordinate must be an integer")

return
}
end, err := strconv.ParseInt(qEnd, 10, 0)
if err != nil {
log.Errorf("failed to convert end coordinate %d to integer, %s", end, err)

c.String(http.StatusBadRequest, "endCoordinate must be an integer")

return
}
if end < start {
log.Errorf("endCoordinate=%d must be greater than startCoordinate=%d", end, start)

c.String(http.StatusBadRequest, "endCoordinate must be greater than startCoordinate")

return
}
err = truncateStream(c4ghfileStream, c.Writer, start)
fileStream = c4ghfileStream
if err != nil {
log.Errorf("error occurred while finding sending start: %v", err)
c.String(http.StatusInternalServerError, "an error occurred")

if start == 0 && end == 0 {
c.Header("Content-Length", fmt.Sprint(fileDetails.DecryptedSize))
} else {
// Calculate how much we should read (if given)
togo := end - start
c.Header("Content-Length", fmt.Sprint(togo))
return
}
}

err = sendStream(fileStream, c.Writer, start, end)
Expand All @@ -265,46 +279,19 @@ func Download(c *gin.Context) {
}
}

// stitchFile stitches the header and file body together for Crypt4GHReader
// and returns a streamable Reader
var stitchFile = func(header []byte, file io.ReadCloser) (*streaming.Crypt4GHReader, error) {
log.Debugf("stitching header to file %s for streaming", file)
// Stitch header and file body together
hr := bytes.NewReader(header)
mr := io.MultiReader(hr, file)

c4ghr, err := streaming.NewCrypt4GHReader(mr, *config.Config.App.Crypt4GHKey, nil)
//defer c4ghr.Close()
return c4ghr, err
}

// stitchEncryptedFile stitches the header and file body together for Crypt4GHReader
// and returns a streamable Reader
var stitchEncryptedFile = func(header []byte, file io.ReadCloser) (*streaming.Crypt4GHReader, error) {
log.Debugf("stitching header to file %s for streaming", file)
// Stitch header and file body together
hr := bytes.NewReader(header)

encryptedFile := io.MultiReader(hr, io.MultiReader(hr, file))

log.Print("Encrypted file:", encryptedFile)

log.Debugf("file stream for %s constructed", file)
c4ghr, err := streaming.NewCrypt4GHReader(encryptedFile, *config.Config.App.Crypt4GHKey, nil)

return c4ghr, err
}

// sendStream
// used from: https://github.com/neicnordic/crypt4gh/blob/master/examples/reader/main.go#L48C1-L113C1
var sendStream = func(reader *streaming.Crypt4GHReader, writer http.ResponseWriter, start, end int64) error {
var truncateStream = func(reader *streaming.Crypt4GHReader, writer http.ResponseWriter, start int64) error {

if start != 0 {
// We don't want to read from start, skip ahead to where we should be
if _, err := reader.Seek(start, 0); err != nil {
return err
}
}
return nil

Check failure on line 290 in api/sda/sda.go

View workflow job for this annotation

GitHub Actions / Check code (1.20)

return with no blank line before (nlreturn)
}

// used from: https://github.com/neicnordic/crypt4gh/blob/master/examples/reader/main.go#L48C1-L113C1
var sendStream = func(reader io.Reader, writer http.ResponseWriter, start, end int64) error {

// Calculate how much we should read (if given)
togo := end - start
Expand Down

0 comments on commit d5f1348

Please sign in to comment.