github.com/status-im/status-go@v1.1.0/server/pairing/handlers.go (about)

     1  package pairing
     2  
     3  import (
     4  	"io"
     5  	"net/http"
     6  
     7  	"go.uber.org/zap"
     8  
     9  	"github.com/status-im/status-go/signal"
    10  )
    11  
    12  const (
    13  	// Handler routes for pairing
    14  	pairingBase                = "/pairing"
    15  	pairingChallenge           = pairingBase + "/challenge"
    16  	pairingSendAccount         = pairingBase + "/sendAccount"
    17  	pairingReceiveAccount      = pairingBase + "/receiveAccount"
    18  	pairingSendSyncDevice      = pairingBase + "/sendSyncDevice"
    19  	pairingReceiveSyncDevice   = pairingBase + "/receiveSyncDevice"
    20  	pairingSendInstallation    = pairingBase + "/sendInstallation"
    21  	pairingReceiveInstallation = pairingBase + "/receiveInstallation"
    22  )
    23  
    24  // Account handling
    25  
    26  func handleReceiveAccount(logger *zap.Logger, pr PayloadReceiver) http.HandlerFunc {
    27  	return func(w http.ResponseWriter, r *http.Request) {
    28  		signal.SendLocalPairingEvent(Event{Type: EventConnectionSuccess, Action: ActionPairingAccount})
    29  		payload, err := io.ReadAll(r.Body)
    30  		if err != nil {
    31  			signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionPairingAccount})
    32  			logger.Error("handleReceiveAccount io.ReadAll(r.Body)", zap.Error(err))
    33  			http.Error(w, "error", http.StatusInternalServerError)
    34  			return
    35  		}
    36  		signal.SendLocalPairingEvent(Event{Type: EventTransferSuccess, Action: ActionPairingAccount})
    37  
    38  		err = pr.Receive(payload)
    39  		if err != nil {
    40  			signal.SendLocalPairingEvent(Event{Type: EventProcessError, Error: err.Error(), Action: ActionPairingAccount})
    41  			logger.Error("handleReceiveAccount pr.Receive(payload)", zap.Error(err), zap.Binary("payload", payload))
    42  			http.Error(w, "error", http.StatusInternalServerError)
    43  			return
    44  		}
    45  		signal.SendLocalPairingEvent(Event{Type: EventProcessSuccess, Action: ActionPairingAccount})
    46  	}
    47  }
    48  
    49  func handleSendAccount(logger *zap.Logger, pm PayloadMounter, beforeSending func()) http.HandlerFunc {
    50  	return func(w http.ResponseWriter, r *http.Request) {
    51  		signal.SendLocalPairingEvent(Event{Type: EventConnectionSuccess, Action: ActionPairingAccount})
    52  		w.Header().Set("Content-Type", "application/octet-stream")
    53  		err := pm.Mount()
    54  		if err != nil {
    55  			signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionPairingAccount})
    56  			logger.Error("handleSendAccount pm.Mount()", zap.Error(err))
    57  			http.Error(w, "error", http.StatusInternalServerError)
    58  			return
    59  		}
    60  
    61  		beforeSending()
    62  		_, err = w.Write(pm.ToSend())
    63  		if err != nil {
    64  			signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionPairingAccount})
    65  			logger.Error("handleSendAccount w.Write(pm.ToSend())", zap.Error(err))
    66  			http.Error(w, "error", http.StatusInternalServerError)
    67  			return
    68  		}
    69  		signal.SendLocalPairingEvent(Event{Type: EventTransferSuccess, Action: ActionPairingAccount})
    70  
    71  		pm.LockPayload()
    72  	}
    73  }
    74  
    75  // Device sync handling
    76  
    77  func handleParingSyncDeviceReceive(logger *zap.Logger, pr PayloadReceiver) http.HandlerFunc {
    78  	return func(w http.ResponseWriter, r *http.Request) {
    79  		signal.SendLocalPairingEvent(Event{Type: EventConnectionSuccess, Action: ActionSyncDevice})
    80  		payload, err := io.ReadAll(r.Body)
    81  		if err != nil {
    82  			signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionSyncDevice})
    83  			logger.Error("handleParingSyncDeviceReceive io.ReadAll(r.Body)", zap.Error(err))
    84  			http.Error(w, "error", http.StatusInternalServerError)
    85  			return
    86  		}
    87  		signal.SendLocalPairingEvent(Event{Type: EventTransferSuccess, Action: ActionSyncDevice})
    88  
    89  		err = pr.Receive(payload)
    90  		if err != nil {
    91  			signal.SendLocalPairingEvent(Event{Type: EventProcessError, Error: err.Error(), Action: ActionSyncDevice})
    92  			logger.Error("handleParingSyncDeviceReceive pr.Receive(payload)", zap.Error(err), zap.Binary("payload", payload))
    93  			http.Error(w, "error", http.StatusInternalServerError)
    94  			return
    95  		}
    96  		signal.SendLocalPairingEvent(Event{Type: EventProcessSuccess, Action: ActionSyncDevice})
    97  	}
    98  }
    99  
   100  func handlePairingSyncDeviceSend(logger *zap.Logger, pm PayloadMounter, beforeSending func()) http.HandlerFunc {
   101  	return func(w http.ResponseWriter, r *http.Request) {
   102  		signal.SendLocalPairingEvent(Event{Type: EventConnectionSuccess, Action: ActionSyncDevice})
   103  		w.Header().Set("Content-Type", "application/octet-stream")
   104  
   105  		err := pm.Mount()
   106  		if err != nil {
   107  			// maybe better to use a new event type here instead of EventTransferError?
   108  			signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionSyncDevice})
   109  			logger.Error("handlePairingSyncDeviceSend pm.Mount()", zap.Error(err))
   110  			http.Error(w, "error", http.StatusInternalServerError)
   111  			return
   112  		}
   113  
   114  		beforeSending()
   115  		_, err = w.Write(pm.ToSend())
   116  		if err != nil {
   117  			signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionSyncDevice})
   118  			logger.Error("handlePairingSyncDeviceSend w.Write(pm.ToSend())", zap.Error(err))
   119  			http.Error(w, "error", http.StatusInternalServerError)
   120  			return
   121  		}
   122  		signal.SendLocalPairingEvent(Event{Type: EventTransferSuccess, Action: ActionSyncDevice})
   123  
   124  		pm.LockPayload()
   125  	}
   126  }
   127  
   128  // Installation data handling
   129  
   130  func handleReceiveInstallation(logger *zap.Logger, pmr PayloadMounterReceiver) http.HandlerFunc {
   131  	return func(w http.ResponseWriter, r *http.Request) {
   132  		signal.SendLocalPairingEvent(Event{Type: EventConnectionSuccess, Action: ActionPairingInstallation})
   133  		payload, err := io.ReadAll(r.Body)
   134  		if err != nil {
   135  			signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionPairingInstallation})
   136  			logger.Error("handleReceiveInstallation io.ReadAll(r.Body)", zap.Error(err))
   137  			http.Error(w, "error", http.StatusInternalServerError)
   138  			return
   139  		}
   140  		signal.SendLocalPairingEvent(Event{Type: EventTransferSuccess, Action: ActionPairingInstallation})
   141  
   142  		err = pmr.Receive(payload)
   143  		if err != nil {
   144  			signal.SendLocalPairingEvent(Event{Type: EventProcessError, Error: err.Error(), Action: ActionPairingInstallation})
   145  			logger.Error("handleReceiveInstallation pmr.Receive(payload)", zap.Error(err), zap.Binary("payload", payload))
   146  			http.Error(w, "error", http.StatusInternalServerError)
   147  			return
   148  		}
   149  		signal.SendLocalPairingEvent(Event{Type: EventProcessSuccess, Action: ActionPairingInstallation})
   150  	}
   151  }
   152  
   153  func handleSendInstallation(logger *zap.Logger, pmr PayloadMounterReceiver, beforeSending func()) http.HandlerFunc {
   154  	return func(w http.ResponseWriter, r *http.Request) {
   155  		signal.SendLocalPairingEvent(Event{Type: EventConnectionSuccess, Action: ActionPairingInstallation})
   156  		w.Header().Set("Content-Type", "application/octet-stream")
   157  		err := pmr.Mount()
   158  		if err != nil {
   159  			signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionPairingInstallation})
   160  			logger.Error("handleSendInstallation pmr.Mount()", zap.Error(err))
   161  			http.Error(w, "error", http.StatusInternalServerError)
   162  			return
   163  		}
   164  
   165  		beforeSending()
   166  		_, err = w.Write(pmr.ToSend())
   167  		if err != nil {
   168  			signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionPairingInstallation})
   169  			logger.Error("handleSendInstallation w.Write(pmr.ToSend())", zap.Error(err))
   170  			http.Error(w, "error", http.StatusInternalServerError)
   171  			return
   172  		}
   173  		signal.SendLocalPairingEvent(Event{Type: EventTransferSuccess, Action: ActionPairingInstallation})
   174  
   175  		pmr.LockPayload()
   176  	}
   177  }
   178  
   179  // Challenge middleware and handling
   180  
   181  func middlewareChallenge(cg *ChallengeGiver, next http.Handler) http.HandlerFunc {
   182  	return func(w http.ResponseWriter, r *http.Request) {
   183  		err := cg.checkChallengeResponse(w, r)
   184  		if err != nil {
   185  			if cErr, ok := err.(*ChallengeError); ok {
   186  				http.Error(w, cErr.Text, cErr.HTTPCode)
   187  				return
   188  			}
   189  			cg.logger.Error("failed to checkChallengeResponse in middlewareChallenge", zap.Error(err))
   190  			http.Error(w, "error", http.StatusInternalServerError)
   191  			return
   192  		}
   193  
   194  		next.ServeHTTP(w, r)
   195  	}
   196  }
   197  
   198  func handlePairingChallenge(cg *ChallengeGiver) http.HandlerFunc {
   199  	return func(w http.ResponseWriter, r *http.Request) {
   200  		challenge, err := cg.getChallenge(w, r)
   201  		if err != nil {
   202  			if cErr, ok := err.(*ChallengeError); ok {
   203  				http.Error(w, cErr.Text, cErr.HTTPCode)
   204  				return
   205  			}
   206  			cg.logger.Error("failed to getChallenge in handlePairingChallenge", zap.Error(err))
   207  			http.Error(w, "error", http.StatusInternalServerError)
   208  			return
   209  		}
   210  
   211  		w.Header().Set("Content-Type", "application/octet-stream")
   212  		_, err = w.Write(challenge)
   213  		if err != nil {
   214  			cg.logger.Error("failed to Write(challenge) in handlePairingChallenge", zap.Error(err))
   215  			http.Error(w, "error", http.StatusInternalServerError)
   216  			return
   217  		}
   218  	}
   219  }