// Handle processes a container to pair with a new client without going through the pairing process. func (c *PairingController) Handle(cont util.Container) (util.Container, error) { method := pairMethodType(cont.GetByte(TagPairingMethod)) username := cont.GetString(TagUsername) publicKey := cont.GetBytes(TagPublicKey) log.Println("[VERB] -> Method:", method) log.Println("[VERB] -> Username:"******"[VERB] -> LTPK:", publicKey) entity := db.NewEntity(username, publicKey, nil) switch method { case PairingMethodDelete: log.Printf("[INFO] Remove LTPK for client '%s'\n", username) c.database.DeleteEntity(entity) case PairingMethodAdd: err := c.database.SaveEntity(entity) if err != nil { log.Println("[ERRO]", err) return nil, err } default: return nil, fmt.Errorf("Invalid pairing method type %v", method) } out := util.NewTLV8Container() out.SetByte(TagSequence, 0x2) return out, nil }
// Handle processes a container to verify if a client is paired correctly. func (verify *VerifyServerController) Handle(in util.Container) (util.Container, error) { var out util.Container var err error method := PairMethodType(in.GetByte(TagPairingMethod)) // It is valid that method is not sent // If method is sent then it must be 0x00 if method != PairingMethodDefault { return nil, errInvalidPairMethod(method) } seq := VerifyStepType(in.GetByte(TagSequence)) switch seq { case VerifyStepStartRequest: if verify.step != VerifyStepWaiting { verify.reset() return nil, errInvalidInternalVerifyStep(verify.step) } out, err = verify.handlePairVerifyStart(in) case VerifyStepFinishRequest: if verify.step != VerifyStepStartResponse { verify.reset() return nil, errInvalidInternalVerifyStep(verify.step) } out, err = verify.handlePairVerifyFinish(in) default: return nil, errInvalidVerifyStep(seq) } return out, err }
func (endpoint *Pairing) ServeHTTP(response http.ResponseWriter, request *http.Request) { log.Printf("[VERB] %v POST /pairings", request.RemoteAddr) response.Header().Set("Content-Type", netio.HTTPContentTypePairingTLV8) var err error var in util.Container var out util.Container if in, err = util.NewTLV8ContainerFromReader(request.Body); err == nil { out, err = endpoint.controller.Handle(in) } if err != nil { log.Println(err) response.WriteHeader(http.StatusInternalServerError) } else { io.Copy(response, out.BytesBuffer()) // Send events based on pairing method type b := in.GetByte(pair.TagPairingMethod) switch pair.PairMethodType(b) { case pair.PairingMethodDelete: // pairing removed endpoint.emitter.Emit(event.DeviceUnpaired{}) case pair.PairingMethodAdd: // pairing added endpoint.emitter.Emit(event.DevicePaired{}) } } }
// Server -> Client // - only error ocde (optional) func (verify *VerifyClientController) handlePairVerifyStepFinishResponse(in util.Container) (util.Container, error) { code := errCode(in.GetByte(TagErrCode)) if code != ErrCodeNo { fmt.Printf("Unexpected error %v\n", code) } return nil, nil }
func (endpoint *PairVerify) ServeHTTP(response http.ResponseWriter, request *http.Request) { log.Printf("[VERB] %v POST /pair-verify", request.RemoteAddr) response.Header().Set("Content-Type", netio.HTTPContentTypePairingTLV8) key := endpoint.context.GetConnectionKey(request) session := endpoint.context.Get(key).(netio.Session) ctlr := session.PairVerifyHandler() if ctlr == nil { log.Println("[VERB] Create new pair verify controller") ctlr = pair.NewVerifyServerController(endpoint.database, endpoint.context) session.SetPairVerifyHandler(ctlr) } var err error var in util.Container var out util.Container var secSession crypto.Cryptographer if in, err = util.NewTLV8ContainerFromReader(request.Body); err == nil { out, err = ctlr.Handle(in) } if err != nil { log.Println(err) response.WriteHeader(http.StatusInternalServerError) } else { io.Copy(response, out.BytesBuffer()) // When key verification is done, switch to a secure session // based on the negotiated shared session key b := out.GetByte(pair.TagSequence) switch pair.VerifyStepType(b) { case pair.VerifyStepFinishResponse: if secSession, err = crypto.NewSecureSessionFromSharedKey(ctlr.SharedKey()); err == nil { log.Println("[VERB] Setup secure session") session.SetCryptographer(secSession) } else { log.Println("[ERRO] Could not setup secure session.", err) } } } }
// Handle processes a container to pair (exchange keys) with an accessory. func (setup *SetupClientController) Handle(in util.Container) (util.Container, error) { method := pairMethodType(in.GetByte(TagPairingMethod)) // It is valid that method is not sent // If method is sent then it must be 0x00 if method != PairingMethodDefault { return nil, errInvalidPairMethod(method) } code := errCode(in.GetByte(TagErrCode)) if code != ErrCodeNo { log.Println("[ERRO]", code) return nil, code.Error() } seq := pairStepType(in.GetByte(TagSequence)) var out util.Container var err error switch seq { case PairStepStartResponse: out, err = setup.handlePairStepStartResponse(in) case PairStepVerifyResponse: out, err = setup.handlePairStepVerifyResponse(in) case PairStepKeyExchangeResponse: out, err = setup.handleKeyExchange(in) default: return nil, errInvalidPairStep(seq) } return out, err }
// Handle processes a container to pair (exchange keys) with a client. func (setup *SetupServerController) Handle(in util.Container) (out util.Container, err error) { method := PairMethodType(in.GetByte(TagPairingMethod)) // It is valid that pair method is not sent // If method set then it must be 0x00 if method != PairingMethodDefault { return nil, errInvalidPairMethod(method) } seq := PairStepType(in.GetByte(TagSequence)) switch seq { case PairStepStartRequest: if setup.step != PairStepWaiting { setup.reset() return nil, errInvalidInternalPairStep(setup.step) } out, err = setup.handlePairStart(in) case PairStepVerifyRequest: if setup.step != PairStepStartResponse { setup.reset() return nil, errInvalidInternalPairStep(setup.step) } out, err = setup.handlePairVerify(in) case PairStepKeyExchangeRequest: if setup.step != PairStepVerifyResponse { setup.reset() return nil, errInvalidInternalPairStep(setup.step) } out, err = setup.handleKeyExchange(in) default: return nil, errInvalidPairStep(seq) } return out, err }
func (endpoint *PairSetup) ServeHTTP(response http.ResponseWriter, request *http.Request) { log.Debug.Printf("%v POST /pair-setup", request.RemoteAddr) response.Header().Set("Content-Type", hap.HTTPContentTypePairingTLV8) var err error var in util.Container var out util.Container key := endpoint.context.GetConnectionKey(request) session := endpoint.context.Get(key).(hap.Session) ctrl := session.PairSetupHandler() if ctrl == nil { log.Debug.Println("Create new pair setup controller") if ctrl, err = pair.NewSetupServerController(endpoint.device, endpoint.database); err != nil { log.Info.Panic(err) } session.SetPairSetupHandler(ctrl) } if in, err = util.NewTLV8ContainerFromReader(request.Body); err == nil { out, err = ctrl.Handle(in) } if err != nil { log.Info.Println(err) response.WriteHeader(http.StatusInternalServerError) } else { io.Copy(response, out.BytesBuffer()) // Send event when key exchange is done b := out.GetByte(pair.TagSequence) switch pair.PairStepType(b) { case pair.PairStepKeyExchangeResponse: endpoint.emitter.Emit(event.DevicePaired{}) } } }
// Handle processes a container to verify if an accessory is paired correctly. func (verify *VerifyClientController) Handle(in util.Container) (util.Container, error) { var out util.Container var err error method := pairMethodType(in.GetByte(TagPairingMethod)) // It is valid that method is not sent // If method is sent then it must be 0x00 if method != PairingMethodDefault { return nil, errInvalidPairMethod(method) } seq := VerifyStepType(in.GetByte(TagSequence)) switch seq { case VerifyStepStartResponse: out, err = verify.handlePairStepVerifyResponse(in) case VerifyStepFinishResponse: out, err = verify.handlePairVerifyStepFinishResponse(in) default: return nil, errInvalidVerifyStep(seq) } return out, err }