Integrated ChallengeGiver into SenderServer

This commit is contained in:
Samuel Hawksby-Robinson 2023-03-16 14:15:07 +00:00
parent cc8552a782
commit 4ec064ec9c
4 changed files with 34 additions and 110 deletions

View File

@ -58,7 +58,7 @@ func NewChallengeGiver(e *PayloadEncryptor, logger *zap.Logger) (*ChallengeGiver
func (cg *ChallengeGiver) handleChallengeResponse(w http.ResponseWriter, r *http.Request) *ChallengeError { func (cg *ChallengeGiver) handleChallengeResponse(w http.ResponseWriter, r *http.Request) *ChallengeError {
s, err := cg.cookieStore.Get(r, sessionChallenge) s, err := cg.cookieStore.Get(r, sessionChallenge)
if err != nil { if err != nil {
cg.logger.Error("hs.GetCookieStore().Get(r, sessionChallenge)", zap.Error(err)) cg.logger.Error("handleChallengeResponse: cg.cookieStore.Get(r, sessionChallenge)", zap.Error(err), zap.String("sessionChallenge", sessionChallenge))
return &ChallengeError{"error", http.StatusInternalServerError} return &ChallengeError{"error", http.StatusInternalServerError}
} }
@ -75,7 +75,7 @@ func (cg *ChallengeGiver) handleChallengeResponse(w http.ResponseWriter, r *http
c, err := cg.encryptor.decryptPlain(base58.Decode(pc)) c, err := cg.encryptor.decryptPlain(base58.Decode(pc))
if err != nil { if err != nil {
cg.logger.Error("c, err := hs.DecryptPlain(rc, hs.ek)", zap.Error(err)) cg.logger.Error("handleChallengeResponse: cg.encryptor.decryptPlain(base58.Decode(pc))", zap.Error(err), zap.String("pc", pc))
return &ChallengeError{"error", http.StatusInternalServerError} return &ChallengeError{"error", http.StatusInternalServerError}
} }
@ -91,7 +91,8 @@ func (cg *ChallengeGiver) handleChallengeResponse(w http.ResponseWriter, r *http
s.Values[sessionBlocked] = true s.Values[sessionBlocked] = true
err = s.Save(r, w) err = s.Save(r, w)
if err != nil { if err != nil {
cg.logger.Error("err = s.Save(r, w)", zap.Error(err)) cg.logger.Error("handleChallengeResponse: err = s.Save(r, w)", zap.Error(err))
return &ChallengeError{"error", http.StatusInternalServerError}
} }
return &ChallengeError{"forbidden", http.StatusForbidden} return &ChallengeError{"forbidden", http.StatusForbidden}
@ -99,11 +100,11 @@ func (cg *ChallengeGiver) handleChallengeResponse(w http.ResponseWriter, r *http
return nil return nil
} }
func (cg *ChallengeGiver) challenge(w http.ResponseWriter, r *http.Request) *ChallengeError { func (cg *ChallengeGiver) getChallenge(w http.ResponseWriter, r *http.Request) ([]byte, *ChallengeError) {
s, err := cg.cookieStore.Get(r, sessionChallenge) s, err := cg.cookieStore.Get(r, sessionChallenge)
if err != nil { if err != nil {
cg.logger.Error("hs.GetCookieStore().Get(r, sessionChallenge)", zap.Error(err)) cg.logger.Error("getChallenge: hs.cookieStore.Get(r, sessionChallenge)", zap.Error(err))
return &ChallengeError{"error", http.StatusInternalServerError} return nil, &ChallengeError{"error", http.StatusInternalServerError}
} }
challenge, ok := s.Values[sessionChallenge].([]byte) challenge, ok := s.Values[sessionChallenge].([]byte)
@ -111,32 +112,18 @@ func (cg *ChallengeGiver) challenge(w http.ResponseWriter, r *http.Request) *Cha
challenge = make([]byte, 64) challenge = make([]byte, 64)
_, err = rand.Read(challenge) _, err = rand.Read(challenge)
if err != nil { if err != nil {
cg.logger.Error("_, err = rand.Read(challenge)", zap.Error(err)) cg.logger.Error("getChallenge: _, err = rand.Read(challenge)", zap.Error(err))
return &ChallengeError{"error", http.StatusInternalServerError} return nil, &ChallengeError{"error", http.StatusInternalServerError}
} }
s.Values[sessionChallenge] = challenge s.Values[sessionChallenge] = challenge
err = s.Save(r, w) err = s.Save(r, w)
if err != nil { if err != nil {
cg.logger.Error("err = s.Save(r, w)", zap.Error(err)) cg.logger.Error("getChallenge: err = s.Save(r, w)", zap.Error(err))
return &ChallengeError{"error", http.StatusInternalServerError} return nil, &ChallengeError{"error", http.StatusInternalServerError}
} }
} }
return challenge, nil
w.Header().Set("Content-Type", "application/octet-stream")
_, err = w.Write(challenge)
if err != nil {
cg.logger.Error("_, err = w.Write(challenge)", zap.Error(err))
}
return nil
}
func (s *BaseServer) GetCookieStore() *sessions.CookieStore {
return s.cookieStore
}
func (s *BaseServer) DecryptPlain(data []byte) ([]byte, error) {
return s.encryptor.decryptPlain(data)
} }
type ChallengeTaker struct { type ChallengeTaker struct {

View File

@ -1,12 +1,9 @@
package pairing package pairing
import ( import (
"bytes"
"crypto/rand"
"io" "io"
"net/http" "net/http"
"github.com/btcsuite/btcutil/base58"
"go.uber.org/zap" "go.uber.org/zap"
"github.com/status-im/status-go/signal" "github.com/status-im/status-go/signal"
@ -188,53 +185,11 @@ func handleSendInstallation(hs HandlerServer, pmr PayloadMounterReceiver) http.H
// Challenge middleware and handling // Challenge middleware and handling
func middlewareChallenge(hs HandlerServer, next http.Handler) http.HandlerFunc { func middlewareChallenge(cg *ChallengeGiver, next http.Handler) http.HandlerFunc {
logger := hs.GetLogger()
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
s, err := hs.GetCookieStore().Get(r, sessionChallenge) ce := cg.handleChallengeResponse(w, r)
if err != nil { if ce != nil {
logger.Error("middlewareChallenge: hs.GetCookieStore().Get(r, sessionChallenge)", zap.Error(err), zap.String("sessionChallenge", sessionChallenge)) http.Error(w, ce.Text, ce.HttpCode)
http.Error(w, "error", http.StatusInternalServerError)
return
}
blocked, ok := s.Values[sessionBlocked].(bool)
if ok && blocked {
http.Error(w, "forbidden", http.StatusForbidden)
return
}
// If the request header doesn't include a challenge don't punish the client, just throw a 403
pc := r.Header.Get(sessionChallenge)
if pc == "" {
http.Error(w, "forbidden", http.StatusForbidden)
return
}
c, err := hs.DecryptPlain(base58.Decode(pc))
if err != nil {
logger.Error("middlewareChallenge: c, err := hs.DecryptPlain(base58.Decode(pc))", zap.Error(err), zap.String("pc", pc))
http.Error(w, "error", http.StatusInternalServerError)
return
}
// If the challenge is not in the session store don't punish the client, just throw a 403
challenge, ok := s.Values[sessionChallenge].([]byte)
if !ok {
http.Error(w, "forbidden", http.StatusForbidden)
return
}
// Only if we have both a challenge in the session store and in the request header
// do we entertain blocking the client. Because then we know someone is trying to be sneaky.
if !bytes.Equal(c, challenge) {
s.Values[sessionBlocked] = true
err = s.Save(r, w)
if err != nil {
logger.Error("middlewareChallenge: err = s.Save(r, w)", zap.Error(err))
}
http.Error(w, "forbidden", http.StatusForbidden)
return return
} }
@ -242,40 +197,18 @@ func middlewareChallenge(hs HandlerServer, next http.Handler) http.HandlerFunc {
} }
} }
func handlePairingChallenge(hs HandlerServer) http.HandlerFunc { func handlePairingChallenge(cg *ChallengeGiver) http.HandlerFunc {
logger := hs.GetLogger()
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
s, err := hs.GetCookieStore().Get(r, sessionChallenge) challenge, ce := cg.getChallenge(w, r)
if err != nil { if ce != nil {
logger.Error("handlePairingChallenge: hs.GetCookieStore().Get(r, sessionChallenge)", zap.Error(err)) http.Error(w, ce.Text, ce.HttpCode)
http.Error(w, "error", http.StatusInternalServerError)
return return
} }
var challenge []byte
challenge, ok := s.Values[sessionChallenge].([]byte)
if !ok {
challenge = make([]byte, 64)
_, err = rand.Read(challenge)
if err != nil {
logger.Error("handlePairingChallenge: _, err = rand.Read(challenge)", zap.Error(err))
http.Error(w, "error", http.StatusInternalServerError)
return
}
s.Values[sessionChallenge] = challenge
err = s.Save(r, w)
if err != nil {
logger.Error("handlePairingChallenge: err = s.Save(r, w)", zap.Error(err))
http.Error(w, "error", http.StatusInternalServerError)
return
}
}
w.Header().Set("Content-Type", "application/octet-stream") w.Header().Set("Content-Type", "application/octet-stream")
_, err = w.Write(challenge) _, err := w.Write(challenge)
if err != nil { if err != nil {
logger.Error("handlePairingChallenge: _, err = w.Write(challenge)", zap.Error(err)) cg.logger.Error("handlePairingChallenge: _, err = w.Write(challenge)", zap.Error(err))
return return
} }
} }

View File

@ -1,7 +1,6 @@
package pairing package pairing
import ( import (
"github.com/gorilla/sessions"
"go.uber.org/zap" "go.uber.org/zap"
) )
@ -28,8 +27,6 @@ type PayloadLocker interface {
type HandlerServer interface { type HandlerServer interface {
GetLogger() *zap.Logger GetLogger() *zap.Logger
GetCookieStore() *sessions.CookieStore
DecryptPlain([]byte) ([]byte, error)
} }
type ProtobufMarshaler interface { type ProtobufMarshaler interface {

View File

@ -122,6 +122,8 @@ type SenderServer struct {
accountMounter PayloadMounter accountMounter PayloadMounter
rawMessageMounter *RawMessagePayloadMounter rawMessageMounter *RawMessagePayloadMounter
installationMounter *InstallationPayloadMounterReceiver installationMounter *InstallationPayloadMounterReceiver
challengeGiver *ChallengeGiver
} }
// NewSenderServer returns a *SenderServer init from the given *SenderServerConfig // NewSenderServer returns a *SenderServer init from the given *SenderServerConfig
@ -139,24 +141,30 @@ func NewSenderServer(backend *api.GethStatusBackend, config *SenderServerConfig)
return nil, err return nil, err
} }
cg, err := NewChallengeGiver(e, logger)
if err != nil {
return nil, err
}
return &SenderServer{ return &SenderServer{
BaseServer: bs, BaseServer: bs,
accountMounter: am, accountMounter: am,
rawMessageMounter: rmm, rawMessageMounter: rmm,
installationMounter: imr, installationMounter: imr,
challengeGiver: cg,
}, nil }, nil
} }
func (s *SenderServer) startSendingData() error { func (s *SenderServer) startSendingData() error {
s.SetHandlers(server.HandlerPatternMap{ s.SetHandlers(server.HandlerPatternMap{
pairingChallenge: handlePairingChallenge(s), pairingChallenge: handlePairingChallenge(s.challengeGiver),
pairingSendAccount: middlewareChallenge(s, handleSendAccount(s, s.accountMounter)), pairingSendAccount: middlewareChallenge(s.challengeGiver, handleSendAccount(s, s.accountMounter)),
pairingSendSyncDevice: middlewareChallenge(s, handlePairingSyncDeviceSend(s, s.rawMessageMounter)), pairingSendSyncDevice: middlewareChallenge(s.challengeGiver, handlePairingSyncDeviceSend(s, s.rawMessageMounter)),
// TODO implement refactor of installation data exchange to follow the send/receive pattern of // TODO implement refactor of installation data exchange to follow the send/receive pattern of
// the other handlers. // the other handlers.
// https://github.com/status-im/status-go/issues/3304 // https://github.com/status-im/status-go/issues/3304
// receive installation data from receiver // receive installation data from receiver
pairingReceiveInstallation: middlewareChallenge(s, handleReceiveInstallation(s, s.installationMounter)), pairingReceiveInstallation: middlewareChallenge(s.challengeGiver, handleReceiveInstallation(s, s.installationMounter)),
}) })
return s.Start() return s.Start()
} }
@ -240,7 +248,6 @@ func NewReceiverServer(backend *api.GethStatusBackend, config *ReceiverServerCon
func (s *ReceiverServer) startReceivingData() error { func (s *ReceiverServer) startReceivingData() error {
s.SetHandlers(server.HandlerPatternMap{ s.SetHandlers(server.HandlerPatternMap{
pairingChallenge: handlePairingChallenge(s),
pairingReceiveAccount: handleReceiveAccount(s, s.accountReceiver), pairingReceiveAccount: handleReceiveAccount(s, s.accountReceiver),
pairingReceiveSyncDevice: handleParingSyncDeviceReceive(s, s.rawMessageReceiver), pairingReceiveSyncDevice: handleParingSyncDeviceReceive(s, s.rawMessageReceiver),
// TODO implement refactor of installation data exchange to follow the send/receive pattern of // TODO implement refactor of installation data exchange to follow the send/receive pattern of