From 6b880ec7ae6e09c61ff37ed500fa25bf31117427 Mon Sep 17 00:00:00 2001 From: Brian Ginsburg <7957636+bgins@users.noreply.github.com> Date: Thu, 19 Dec 2024 16:15:06 -0800 Subject: [PATCH] feat: Add download files signature check (#472) * refactor: Rename GetAddressFromHeaders to CheckSignature * docs: Update error messages and comments * feat: Add headers to GET requests * feat: Add auth to download files route --- pkg/http/utils.go | 14 +++++----- pkg/solver/server.go | 61 +++++++++++++++++++++++++++++--------------- 2 files changed, 48 insertions(+), 27 deletions(-) diff --git a/pkg/http/utils.go b/pkg/http/utils.go index eef795dc..17aa2e73 100644 --- a/pkg/http/utils.go +++ b/pkg/http/utils.go @@ -109,12 +109,12 @@ func AddHeaders( return nil } -// this will use the client headers to ensure that a message was signed -// by the holder of a private key for a specific address -// there is a "X-Lilypad-User" header that will contain the address -// there is a "X-Lilypad-Signature" header that will contain the signature -// we use the signature to verify that the message was signed by the private key -func GetAddressFromHeaders(req *http.Request) (string, error) { +// Use the client headers to ensure that a message was signed +// by the holder of a private key for a specific address. +// The "X-Lilypad-User" header contains the address. +// The "X-Lilypad-Signature" header contains the signature. +// We use the signature to verify that the message was signed by the private key. +func CheckSignature(req *http.Request) (string, error) { userHeader := req.Header.Get(X_LILYPAD_USER_HEADER) if userHeader == "" { return "", HTTPError{ @@ -319,6 +319,8 @@ func GetRequestBuffer( if err != nil { return nil, err } + privateKey, err := web3.ParsePrivateKey(options.PrivateKey) + AddHeaders(req, privateKey, web3.GetAddress(privateKey).String()) resp, err := client.Do(req) if err != nil { diff --git a/pkg/solver/server.go b/pkg/solver/server.go index 29bd5d30..e40cc50e 100644 --- a/pkg/solver/server.go +++ b/pkg/solver/server.go @@ -4,6 +4,7 @@ import ( "archive/tar" "context" "encoding/json" + "errors" "fmt" "io" corehttp "net/http" @@ -277,12 +278,12 @@ func (solverServer *solverServer) getResult(res corehttp.ResponseWriter, req *co * */ func (solverServer *solverServer) addJobOffer(jobOffer data.JobOffer, res corehttp.ResponseWriter, req *corehttp.Request) (*data.JobOfferContainer, error) { - signerAddress, err := http.GetAddressFromHeaders(req) + signerAddress, err := http.CheckSignature(req) if err != nil { - log.Error().Err(err).Msgf("have error parsing user address") + log.Error().Err(err).Msgf("error checking signature") return nil, err } - // only the job creator can post a job offer + // Only the job creator can post their job offer if signerAddress != jobOffer.JobCreator { return nil, fmt.Errorf("job creator address does not match signer address") } @@ -298,12 +299,12 @@ func (solverServer *solverServer) addResourceOffer(resourceOffer data.ResourceOf versionHeader, _ := http.GetVersionFromHeaders(req) log.Debug().Msgf("resource provider adding offer with version header %s", versionHeader) - signerAddress, err := http.GetAddressFromHeaders(req) + signerAddress, err := http.CheckSignature(req) if err != nil { - log.Error().Err(err).Msgf("have error parsing user address") + log.Error().Err(err).Msgf("error checking signature") return nil, err } - // only the job creator can post a job offer + // Only the resource provider can post their resource offer if signerAddress != resourceOffer.ResourceProvider { return nil, fmt.Errorf("resource provider address does not match signer address") } @@ -326,12 +327,12 @@ func (solverServer *solverServer) addResult(results data.Result, res corehttp.Re if deal == nil { return nil, fmt.Errorf("deal not found") } - signerAddress, err := http.GetAddressFromHeaders(req) + signerAddress, err := http.CheckSignature(req) if err != nil { - log.Error().Err(err).Msgf("have error parsing user address") + log.Error().Err(err).Msgf("error checking signature") return nil, err } - // only the resource provider can add a result + // Only the resource provider in a deal can add a result if signerAddress != deal.ResourceProvider { return nil, fmt.Errorf("resource provider address does not match signer address") } @@ -367,12 +368,12 @@ func (solverServer *solverServer) updateTransactionsResourceProvider(payload dat log.Error().Err(err).Msgf("deal not found") return nil, fmt.Errorf("deal not found") } - signerAddress, err := http.GetAddressFromHeaders(req) + signerAddress, err := http.CheckSignature(req) if err != nil { - log.Error().Err(err).Msgf("have error parsing user address") + log.Error().Err(err).Msgf("error checking signature") return nil, err } - // only the job creator can post a job offer + // Only the resource provider in a deal can update its transactions if signerAddress != deal.ResourceProvider { return nil, fmt.Errorf("resource provider address does not match signer address") } @@ -391,12 +392,12 @@ func (solverServer *solverServer) updateTransactionsJobCreator(payload data.Deal log.Error().Err(err).Msgf("deal not found") return nil, fmt.Errorf("deal not found") } - signerAddress, err := http.GetAddressFromHeaders(req) + signerAddress, err := http.CheckSignature(req) if err != nil { - log.Error().Err(err).Msgf("have error parsing user address") + log.Error().Err(err).Msgf("error checking signature") return nil, err } - // only the job creator can post a job offer + // Only the job creator in a deal can update its transactions if signerAddress != deal.JobCreator { return nil, fmt.Errorf("job creator address does not match signer address") } @@ -415,12 +416,12 @@ func (solverServer *solverServer) updateTransactionsMediator(payload data.DealTr log.Error().Err(err).Msgf("deal not found") return nil, fmt.Errorf("deal not found") } - signerAddress, err := http.GetAddressFromHeaders(req) + signerAddress, err := http.CheckSignature(req) if err != nil { - log.Error().Err(err).Msgf("have error parsing user address") + log.Error().Err(err).Msgf("error checking signature") return nil, err } - // only the job creator can post a job offer + // Only the mediator in a deal can update its transactions if signerAddress != deal.Mediator { return nil, fmt.Errorf("job creator address does not match mediator address") } @@ -458,6 +459,24 @@ func (solverServer *solverServer) downloadFiles(res corehttp.ResponseWriter, req StatusCode: corehttp.StatusNotFound, } } + + signerAddress, err := http.CheckSignature(req) + if err != nil { + log.Error().Err(err).Msgf("error checking signature") + return &http.HTTPError{ + Message: errors.New("not authorized").Error(), + StatusCode: corehttp.StatusUnauthorized, + } + } + // Only the job creator in a deal can download job outputs + if signerAddress != deal.JobCreator { + log.Error().Err(err).Msgf("job creator address does not match signer address") + return &http.HTTPError{ + Message: errors.New("not authorized").Error(), + StatusCode: corehttp.StatusUnauthorized, + } + } + filesPath := GetDealsFilePath(id) // check if the filesPath directory exists if _, err := os.Stat(filesPath); os.IsNotExist(err) { @@ -500,12 +519,12 @@ func (solverServer *solverServer) uploadFiles(res corehttp.ResponseWriter, req * log.Error().Msgf("deal not found") return err } - signerAddress, err := http.GetAddressFromHeaders(req) + signerAddress, err := http.CheckSignature(req) if err != nil { - log.Error().Err(err).Msgf("have error parsing user address") + log.Error().Err(err).Msgf("error checking signature") return err } - // only the resource provider can add a result + // Only the resource provider in a deal can upload job outputs if signerAddress != deal.ResourceProvider { return fmt.Errorf("resource provider address does not match signer address") }