Implemented and integrated ChallengeTaker

This commit is contained in:
Samuel Hawksby-Robinson 2023-03-20 15:31:39 +00:00
parent 4ec064ec9c
commit 4019689df1
3 changed files with 46 additions and 33 deletions

View File

@ -36,6 +36,7 @@ func makeCookieStore() (*sessions.CookieStore, error) {
return sessions.NewCookieStore(auth, enc), nil
}
// ChallengeGiver is responsible for generating challenges and checking challenge responses
type ChallengeGiver struct {
cookieStore *sessions.CookieStore
encryptor *PayloadEncryptor
@ -50,15 +51,15 @@ func NewChallengeGiver(e *PayloadEncryptor, logger *zap.Logger) (*ChallengeGiver
return &ChallengeGiver{
cookieStore: cs,
encryptor: e,
encryptor: e.Renew(),
logger: logger,
}, nil
}
func (cg *ChallengeGiver) handleChallengeResponse(w http.ResponseWriter, r *http.Request) *ChallengeError {
func (cg *ChallengeGiver) checkChallengeResponse(w http.ResponseWriter, r *http.Request) *ChallengeError {
s, err := cg.cookieStore.Get(r, sessionChallenge)
if err != nil {
cg.logger.Error("handleChallengeResponse: cg.cookieStore.Get(r, sessionChallenge)", zap.Error(err), zap.String("sessionChallenge", sessionChallenge))
cg.logger.Error("checkChallengeResponse: cg.cookieStore.Get(r, sessionChallenge)", zap.Error(err), zap.String("sessionChallenge", sessionChallenge))
return &ChallengeError{"error", http.StatusInternalServerError}
}
@ -75,7 +76,7 @@ func (cg *ChallengeGiver) handleChallengeResponse(w http.ResponseWriter, r *http
c, err := cg.encryptor.decryptPlain(base58.Decode(pc))
if err != nil {
cg.logger.Error("handleChallengeResponse: cg.encryptor.decryptPlain(base58.Decode(pc))", zap.Error(err), zap.String("pc", pc))
cg.logger.Error("checkChallengeResponse: cg.encryptor.decryptPlain(base58.Decode(pc))", zap.Error(err), zap.String("pc", pc))
return &ChallengeError{"error", http.StatusInternalServerError}
}
@ -91,7 +92,7 @@ func (cg *ChallengeGiver) handleChallengeResponse(w http.ResponseWriter, r *http
s.Values[sessionBlocked] = true
err = s.Save(r, w)
if err != nil {
cg.logger.Error("handleChallengeResponse: err = s.Save(r, w)", zap.Error(err))
cg.logger.Error("checkChallengeResponse: err = s.Save(r, w)", zap.Error(err))
return &ChallengeError{"error", http.StatusInternalServerError}
}
@ -126,6 +127,30 @@ func (cg *ChallengeGiver) getChallenge(w http.ResponseWriter, r *http.Request) (
return challenge, nil
}
// ChallengeTaker is responsible for storing and performing server challenges
type ChallengeTaker struct {
encryptor *PayloadEncryptor
encryptor *PayloadEncryptor
serverChallenge []byte
}
func NewChallengeTaker(e *PayloadEncryptor) *ChallengeTaker {
return &ChallengeTaker{
encryptor: e.Renew(),
}
}
func (ct *ChallengeTaker) SetChallenge(challenge []byte) {
ct.serverChallenge = challenge
}
func (ct *ChallengeTaker) DoChallenge(req *http.Request) error {
if ct.serverChallenge != nil {
ec, err := ct.encryptor.encryptPlain(ct.serverChallenge)
if err != nil {
return err
}
req.Header.Set(sessionChallenge, base58.Encode(ec))
}
return nil
}

View File

@ -13,8 +13,6 @@ import (
"net/http/cookiejar"
"net/url"
"github.com/btcsuite/btcutil/base58"
"github.com/status-im/status-go/api"
"github.com/status-im/status-go/logutils"
"github.com/status-im/status-go/signal"
@ -32,10 +30,9 @@ import (
// BaseClient is responsible for lower level pairing.Client functionality common to dependent Client types
type BaseClient struct {
*http.Client
serverCert *x509.Certificate
encryptor *PayloadEncryptor
baseAddress *url.URL
serverChallenge []byte
serverCert *x509.Certificate
baseAddress *url.URL
challengeTaker *ChallengeTaker
}
// NewBaseClient returns a fully qualified BaseClient from the given ConnectionParams
@ -79,10 +76,10 @@ func NewBaseClient(c *ConnectionParams) (*BaseClient, error) {
}
return &BaseClient{
Client: &http.Client{Transport: tr, Jar: cj},
serverCert: serverCert,
encryptor: NewPayloadEncryptor(c.aesKey),
baseAddress: u,
Client: &http.Client{Transport: tr, Jar: cj},
serverCert: serverCert,
challengeTaker: NewChallengeTaker(NewPayloadEncryptor(c.aesKey)),
baseAddress: u,
}, nil
}
@ -98,20 +95,11 @@ func (c *BaseClient) getChallenge() error {
return fmt.Errorf("[client] status not ok when getting challenge, received '%s'", resp.Status)
}
c.serverChallenge, err = ioutil.ReadAll(resp.Body)
return err
}
// doChallenge checks if there is a serverChallenge and encrypts the challenge using the shared AES key
func (c *BaseClient) doChallenge(req *http.Request) error {
if c.serverChallenge != nil {
ec, err := c.encryptor.encryptPlain(c.serverChallenge)
if err != nil {
return err
}
req.Header.Set(sessionChallenge, base58.Encode(ec))
challenge, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
c.challengeTaker.SetChallenge(challenge)
return nil
}
@ -322,7 +310,7 @@ func (c *ReceiverClient) receiveAccountData() error {
return err
}
err = c.doChallenge(req)
err = c.challengeTaker.DoChallenge(req)
if err != nil {
signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionPairingAccount})
return err
@ -363,7 +351,7 @@ func (c *ReceiverClient) receiveSyncDeviceData() error {
return err
}
err = c.doChallenge(req)
err = c.challengeTaker.DoChallenge(req)
if err != nil {
signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionSyncDevice})
return err
@ -410,7 +398,7 @@ func (c *ReceiverClient) sendInstallationData() error {
}
req.Header.Set("Content-Type", "application/octet-stream")
err = c.doChallenge(req)
err = c.challengeTaker.DoChallenge(req)
if err != nil {
signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionPairingInstallation})
return err

View File

@ -187,7 +187,7 @@ func handleSendInstallation(hs HandlerServer, pmr PayloadMounterReceiver) http.H
func middlewareChallenge(cg *ChallengeGiver, next http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ce := cg.handleChallengeResponse(w, r)
ce := cg.checkChallengeResponse(w, r)
if ce != nil {
http.Error(w, ce.Text, ce.HttpCode)
return