Beispiel #1
0
func (handler *Characteristics) ServeHTTP(response http.ResponseWriter, request *http.Request) {
	var res io.Reader
	var err error

	handler.mutex.Lock()
	switch request.Method {
	case netio.MethodGET:
		log.Printf("[VERB] %v GET /characteristics", request.RemoteAddr)
		request.ParseForm()
		res, err = handler.controller.HandleGetCharacteristics(request.Form)
	case netio.MethodPUT:
		log.Printf("[VERB] %v PUT /characteristics", request.RemoteAddr)
		session := handler.context.GetSessionForRequest(request)
		conn := session.Connection()
		err = handler.controller.HandleUpdateCharacteristics(request.Body, conn)
	default:
		log.Println("[WARN] Cannot handle HTTP method", request.Method)
	}
	handler.mutex.Unlock()

	if err != nil {
		log.Println("[ERRO]", err)
		response.WriteHeader(http.StatusInternalServerError)
	} else {
		if res != nil {
			response.Header().Set("Content-Type", netio.HTTPContentTypeHAPJson)
			wr := netio.NewChunkedWriter(response, 2048)
			b, _ := ioutil.ReadAll(res)
			wr.Write(b)
		} else {
			response.WriteHeader(http.StatusNoContent)
		}
	}
}
Beispiel #2
0
func (handler *PairSetup) ServeHTTP(response http.ResponseWriter, request *http.Request) {
	log.Printf("[VERB] %v POST /pair-setup", request.RemoteAddr)
	response.Header().Set("Content-Type", netio.HTTPContentTypePairingTLV8)

	key := handler.context.GetConnectionKey(request)
	session := handler.context.Get(key).(netio.Session)
	controller := session.PairSetupHandler()
	if controller == nil {
		log.Println("[VERB] Create new pair setup controller")
		var err error
		controller, err = pair.NewSetupServerController(handler.device, handler.database)
		if err != nil {
			log.Println(err)
		}

		session.SetPairSetupHandler(controller)
	}

	res, err := pair.HandleReaderForHandler(request.Body, controller)

	if err != nil {
		log.Println("[ERRO]", err)
		response.WriteHeader(http.StatusInternalServerError)
	} else {
		io.Copy(response, res)
	}
}
Beispiel #3
0
func (handler *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 := handler.context.GetConnectionKey(request)
	session := handler.context.Get(key).(netio.Session)
	controller := session.PairVerifyHandler()
	if controller == nil {
		log.Println("[VERB] Create new pair verify controller")
		controller = pair.NewVerifyServerController(handler.database, handler.context)
		session.SetPairVerifyHandler(controller)
	}

	res, err := pair.HandleReaderForHandler(request.Body, controller)

	if err != nil {
		log.Println(err)
		response.WriteHeader(http.StatusInternalServerError)
	} else {
		io.Copy(response, res)
		// Setup secure session
		if controller.KeyVerified() == true {
			// Verification is done
			// Switch to secure session
			secureSession, err := crypto.NewSecureSessionFromSharedKey(controller.SharedKey())
			if err != nil {
				log.Println("[ERRO] Could not setup secure session.", err)
			} else {
				log.Println("[VERB] Setup secure session")
			}
			session.SetCryptographer(secureSession)
		}
	}
}
Beispiel #4
0
// 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
}
Beispiel #5
0
func (t *Thermostat) RunLoop() {
	go t.boiler.RunLoop()

	for {
		select {
		case <-time.After(interval):
			temp = t.thermometer.Temperature()

			if temp >= t.targetTemp+maxOver {
				if t.boiler.GetCurrentCommand() == true {
					log.Println("[INFO] Over temperature, turning boiler off")
					t.boiler.SetCurrentCommand(false)
					t.isOn = false
				}
			} else if temp <= t.targetTemp-minUnder {
				if t.boiler.GetCurrentCommand() == false {
					log.Println("[INFO] Under temperature, turning boiler on")
					t.boiler.SetCurrentCommand(true)
					t.isOn = true
				}
			}
		case <-t.done:
			break
		}
	}

	t.boiler.Stop()
}
Beispiel #6
0
func main() {
	log.Println("[ERRO] Just an error")
	log.Printf("[ERRO] Just an error %d", 1)
	log.Println("[WARN] Just a warning")
	log.Printf("[WARN] Just a warning %d", 1)
	log.Println("[INFO] Just an info")
	log.Printf("[INFO] Just an info %d", 1)
	log.Println("[VERB] Just an info")
	log.Printf("[VERB] Just an info %d", 1)

	log.Error = false
	log.Warn = false
	log.Info = false
	log.Verbose = false

	log.Println("MUST be displayed")
	log.Println("[ERRO] MUST NOT be displayed")
	log.Printf("[ERRO] MUST NOT be displayed %d", 1)
	log.Println("[WARN] MUST NOT be displayed")
	log.Printf("[WARN] MUST NOT be displayed %d", 1)
	log.Println("[INFO] MUST NOT be displayed")
	log.Printf("[INFO] MUST NOT be displayed %d", 1)
	log.Println("[VERB] MUST NOT be displayed")
	log.Printf("[VERB] MUST NOT be displayed %d", 1)
}
Beispiel #7
0
func main() {
	flag.Float64Var(&temp, "temp", 20.0, "Target temperature")
	flag.StringVar(&tempPath, "tempPath", "", "Target temperature path")
	flag.StringVar(&device, "device", "", "Thermometer device")
	flag.BoolVar(&verbose, "verbose", false, "Verbose logging")
	flag.Parse()

	log.Verbose = verbose

	if device == "" {
		log.Fatal("No device specified")
	}

	if tempPath != "" {
		_, err := os.Stat(tempPath)
		if err != nil {
			log.Fatal(err)
		}

		log.Println("[INFO] Starting thermostat with temperature from path:", tempPath)
	} else {
		log.Println("[INFO] Starting thermostat with target temperature:", temp)
	}

	log.Println("[VERB] Using thermometer at", device)

	boiler := NewBoiler()
	thermometer := NewThermometer(device)
	go thermometer.RunLoop()

	thermostat := NewThermostat(boiler, thermometer, temp)
	go thermostat.RunLoop()

	if tempPath != "" {
		tempPoller := NewTempPoller(thermostat, tempPath)
		temp = tempPoller.PollTemp()
		go tempPoller.RunLoop()
	}

	api := NewAPI(thermostat)
	go api.RunLoop()

	homekitService := NewHomeKitService(thermostat)
	go homekitService.RunLoop()

	// Handle SIGINT and SIGTERM.
	ch := make(chan os.Signal)
	signal.Notify(ch, os.Interrupt, os.Kill, syscall.SIGINT, syscall.SIGTERM)
	signal := <-ch
	log.Println("[INFO] Received signal", signal, "terminating")

	homekitService.Stop()
	thermostat.Stop()
}
// Client -> Server
// - Auth start
//
// Server -> Client
// - B: server public key
// - s: salt
func (setup *SetupServerController) handlePairStart(in util.Container) (util.Container, error) {
	out := util.NewTLV8Container()
	setup.step = PairStepStartResponse

	out.SetByte(TagSequence, setup.step.Byte())
	out.SetBytes(TagPublicKey, setup.session.PublicKey)
	out.SetBytes(TagSalt, setup.session.Salt)

	log.Println("[VERB] <-     B:", hex.EncodeToString(out.GetBytes(TagPublicKey)))
	log.Println("[VERB] <-     s:", hex.EncodeToString(out.GetBytes(TagSalt)))

	return out, nil
}
// 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
}
Beispiel #10
0
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{})

		}
	}
}
Beispiel #11
0
func HandleInputValueWithName(v uvr.Value, name string) (s *hkuvr1611.Sensor) {
	var found bool
	if s, found = sensors[name]; found == false {
		s = hkuvr1611.NewSensorForInputValue(v, InfoForAccessoryName(name))
		if s != nil {
			log.Println("[INFO]", reflect.TypeOf(s.Model), "with name", name)
			sensors[name] = s
		}
	} else {
		err := hkuvr1611.UpdateAccessoryWithInputValue(s.Model, v)
		if err != nil {
			log.Println("[ERRO]", err)
		}
	}
	return s
}
// HandleUpdateCharacteristics handles an update characteristic request. The bytes must represent
// a data.Characteristics json.
func (ctr *CharacteristicController) HandleUpdateCharacteristics(r io.Reader, conn net.Conn) error {
	b, err := ioutil.ReadAll(r)
	if err != nil {
		return err
	}

	var chars data.Characteristics
	err = json.Unmarshal(b, &chars)
	if err != nil {
		return err
	}

	log.Println("[VERB]", string(b))

	for _, c := range chars.Characteristics {
		characteristic := ctr.GetCharacteristic(c.AccessoryID, c.ID)
		if characteristic == nil {
			log.Printf("[ERRO] Could not find characteristic with aid %d and iid %d\n", c.AccessoryID, c.ID)
			continue
		}

		if c.Value != nil {
			characteristic.SetValueFromConnection(c.Value, conn)
		}

		if events, ok := c.Events.(bool); ok == true {
			characteristic.SetEventsEnabled(events)
		}
	}

	return err
}
Beispiel #13
0
func NewDevice(device common.Device) {
	if light, ok := device.(common.Light); ok {
		hkLight := GetHKLight(light)

		hkLight.sub, _ = light.NewSubscription()
		for {
			event := <-hkLight.sub.Events()
			switch event.(type) {
			case common.EventUpdateLabel:
				log.Printf("[INFO] Updated Label for %s to %s", hkLight.accessory.Name(), event.(common.EventUpdateLabel).Label)
				// TODO Add support for label changes to HomeControl
				log.Printf("[INFO] Unsupported by HomeControl")
			case common.EventUpdatePower:
				log.Printf("[INFO] Updated Power for %s", hkLight.accessory.Name())
				hkLight.light.SetOn(event.(common.EventUpdatePower).Power)
			case common.EventUpdateColor:
				log.Printf("[INFO] Updated Color for %s", hkLight.accessory.Name())

				hue, saturation, brightness := ConvertLIFXColor(event.(common.EventUpdateColor).Color)

				hkLight.light.SetHue(hue)
				hkLight.light.SetSaturation(saturation)
				hkLight.light.SetBrightness(int(brightness))

			default:
				log.Printf("[INFO] Unknown Device Event: %T", event)
			}
		}
	} else {
		log.Println("[INFO] Unsupported Device")
	}
}
Beispiel #14
0
func (tp *TempPoller) updateTemp() {
	temp := tp.PollTemp()
	if temp != tp.lastTemp {
		log.Println("[INFO] Setting thermostat target temperature to", temp)
		tp.thermostat.targetTemp = temp
		tp.lastTemp = temp
	}
}
Beispiel #15
0
func HandleOutletWithName(o uvr1611.Outlet, name string) (s *hkuvr1611.Sensor) {
	var found bool
	if s, found = sensors[name]; found == false {
		s = hkuvr1611.NewSensorForOutlet(o, InfoForAccessoryName(name))
		if s != nil {
			log.Println("[INFO]", reflect.TypeOf(s.Model), "with name", name)
			sensors[name] = s
		}
	} else {
		err := hkuvr1611.UpdateAccessoryWithOutlet(s.Model, o)
		if err != nil {
			log.Println("[ERRO]", err)
		}
	}

	return s
}
Beispiel #16
0
// Close closes the connection and deletes the related session from the context.
func (con *HAPConnection) Close() error {
	log.Println("[INFO] Close connection and remove session")

	// Remove session from the context
	con.context.DeleteSessionForConnection(con.connection)

	return con.connection.Close()
}
Beispiel #17
0
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)
			}
		}
	}
}
Beispiel #18
0
func NewHomeKitService(thermostat *Thermostat) *HomeKitService {
	thermostatInfo := model.Info{
		Name: "Thermostat",
	}

	hkThermostat := accessory.NewThermostat(thermostatInfo, temp, 17, 25, 0.5)
	hkThermostat.SetTargetMode(model.HeatCoolModeHeat)
	hkThermostat.OnTargetTempChange(func(temp float64) {
		log.Println("[INFO] HomeKit requested thermostat to change to", temp)
		thermostat.targetTemp = temp
	})

	hkThermostat.OnTargetModeChange(func(mode model.HeatCoolModeType) {
		log.Println("[INFO] HomeKit requested thermostat to change to", mode)

		switch mode {
		case model.HeatCoolModeHeat:
			log.Println("[INFO] HomeKit setting thermostat to default on temp of", defaultOnTemp)
			thermostat.targetTemp = defaultOnTemp
		case model.HeatCoolModeOff:
			log.Println("[INFO] HomeKit setting thermostat to default off temp of", defaultOffTemp)
			thermostat.targetTemp = defaultOffTemp
		case model.HeatCoolModeAuto, model.HeatCoolModeCool:
			hkThermostat.SetTargetMode(model.HeatCoolModeHeat)
		}

	})

	transport, err := hap.NewIPTransport("24282428", hkThermostat.Accessory)
	if err != nil {
		log.Fatal(err)
	}

	t := HomeKitService{
		thermostat:   thermostat,
		done:         make(chan bool),
		hkThermostat: hkThermostat,
		transport:    transport,
	}

	return &t
}
Beispiel #19
0
func ExpireDevice(device common.Device) {
	if light, ok := device.(common.Light); ok {
		hkLight, _ := lights[light.ID()]
		light.CloseSubscription(hkLight.sub)
		hkLight.transport.Stop()

		delete(lights, light.ID())
	} else {
		log.Println("[INFO] Unsupported Device")
	}
}
// Server -> Client
// - only sequence number
// - error code (optional)
func (verify *VerifyServerController) handlePairVerifyFinish(in util.Container) (util.Container, error) {
	verify.step = VerifyStepFinishResponse

	data := in.GetBytes(TagEncryptedData)
	message := data[:(len(data) - 16)]
	var mac [16]byte
	copy(mac[:], data[len(message):]) // 16 byte (MAC)
	log.Println("[VERB] ->     Message:", hex.EncodeToString(message))
	log.Println("[VERB] ->     MAC:", hex.EncodeToString(mac[:]))

	decryptedBytes, err := chacha20poly1305.DecryptAndVerify(verify.session.EncryptionKey[:], []byte("PV-Msg03"), message, mac, nil)

	out := util.NewTLV8Container()
	out.SetByte(TagSequence, verify.step.Byte())

	if err != nil {
		verify.reset()
		log.Println("[ERRO]", err)
		out.SetByte(TagErrCode, ErrCodeAuthenticationFailed.Byte()) // return error 2
	} else {
		in, err := util.NewTLV8ContainerFromReader(bytes.NewBuffer(decryptedBytes))
		if err != nil {
			return nil, err
		}

		username := in.GetString(TagUsername)
		signature := in.GetBytes(TagSignature)
		log.Println("[VERB]     client:", username)
		log.Println("[VERB]  signature:", hex.EncodeToString(signature))

		entity := verify.database.EntityWithName(username)
		if entity == nil {
			return nil, fmt.Errorf("Client %s is unknown", username)
		}

		if len(entity.PublicKey()) == 0 {
			return nil, fmt.Errorf("No LTPK available for client %s", username)
		}

		var material []byte
		material = append(material, verify.session.OtherPublicKey[:]...)
		material = append(material, []byte(username)...)
		material = append(material, verify.session.PublicKey[:]...)

		if crypto.ValidateED25519Signature(entity.PublicKey(), material, signature) == false {
			log.Println("[WARN] signature is invalid")
			verify.reset()
			out.SetByte(TagErrCode, ErrCodeUnknownPeer.Byte()) // return error 4
		} else {
			log.Println("[VERB] signature is valid")
		}
	}

	return out, nil
}
Beispiel #21
0
func (endpoint *PairSetup) ServeHTTP(response http.ResponseWriter, request *http.Request) {
	log.Printf("[VERB] %v POST /pair-setup", request.RemoteAddr)
	response.Header().Set("Content-Type", netio.HTTPContentTypePairingTLV8)

	var err error
	var in util.Container
	var out util.Container

	key := endpoint.context.GetConnectionKey(request)
	session := endpoint.context.Get(key).(netio.Session)
	ctrl := session.PairSetupHandler()
	if ctrl == nil {
		log.Println("[VERB] Create new pair setup controller")

		if ctrl, err = pair.NewSetupServerController(endpoint.device, endpoint.database); err != nil {
			log.Println(err)
		}

		session.SetPairSetupHandler(ctrl)
	}

	if in, err = util.NewTLV8ContainerFromReader(request.Body); err == nil {
		out, err = ctrl.Handle(in)
	}

	if err != nil {
		log.Println("[ERRO]", 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{})
		}
	}
}
Beispiel #22
0
func (handler *Pairing) ServeHTTP(response http.ResponseWriter, request *http.Request) {
	log.Printf("[VERB] %v POST /pairings", request.RemoteAddr)
	response.Header().Set("Content-Type", netio.HTTPContentTypePairingTLV8)

	res, err := pair.HandleReaderForHandler(request.Body, handler.controller)

	if err != nil {
		log.Println(err)
		response.WriteHeader(http.StatusInternalServerError)
	} else {
		io.Copy(response, res)
	}
}
Beispiel #23
0
// HandleReaderForHandler wraps h.Handle() call and logs sequence numbers and errors to the console.
func HandleReaderForHandler(r io.Reader, h netio.ContainerHandler) (rOut io.Reader, err error) {
	in, err := util.NewTLV8ContainerFromReader(r)
	if err != nil {
		return nil, err
	}

	log.Println("[VERB] ->     Seq:", in.GetByte(TagSequence))

	out, err := h.Handle(in)

	if err != nil {
		log.Println("[ERRO]", err)
	} else {
		if out != nil {
			log.Println("[VERB] <-     Seq:", out.GetByte(TagSequence))
			rOut = out.BytesBuffer()
		}
	}
	log.Println("[VERB] --------------------------")

	return rOut, err
}
Beispiel #24
0
func (handler *Accessories) ServeHTTP(response http.ResponseWriter, request *http.Request) {
	log.Printf("[VERB] %v GET /accessories", request.RemoteAddr)
	response.Header().Set("Content-Type", netio.HTTPContentTypeHAPJson)

	handler.mutex.Lock()
	res, err := handler.controller.HandleGetAccessories(request.Body)
	handler.mutex.Unlock()

	if err != nil {
		log.Println("[ERRO]", err)
		response.WriteHeader(http.StatusInternalServerError)
	} else {
		// Write the data in chunks of 2048 bytes
		// http.ResponseWriter should do this already, but crashes because of an unkown reason
		wr := netio.NewChunkedWriter(response, 2048)
		b, _ := ioutil.ReadAll(res)
		log.Println("[VERB]", string(b))
		_, err := wr.Write(b)
		if err != nil {
			log.Println("[ERRO]", err)
		}
	}
}
Beispiel #25
0
// EncryptedWrite encrypts and writes bytes to the connection.
// The method returns the number of written bytes and an error when writing failed.
func (con *HAPConnection) EncryptedWrite(b []byte) (int, error) {
	var buffer bytes.Buffer
	buffer.Write(b)
	encrypted, err := con.getEncrypter().Encrypt(&buffer)

	if err != nil {
		log.Println("[ERRO] Encryption failed:", err)
		err = con.connection.Close()
		return 0, err
	}

	encryptedBytes, err := ioutil.ReadAll(encrypted)
	n, err := con.connection.Write(encryptedBytes)

	return n, err
}
Beispiel #26
0
// Publish announces the service for the machine's ip address on a random port using mDNS.
func (s *MDNSService) Publish() error {
	ip, err := GetFirstLocalIPAddress()
	if err != nil {
		return err
	}
	log.Println("[INFO] Accessory IP is", ip)

	// Host should end with '.'
	hostname, _ := os.Hostname()
	host := fmt.Sprintf("%s.", strings.Trim(hostname, "."))
	text := s.txtRecords()
	server, err := bonjour.RegisterProxy(s.name, "_hap._tcp.", "", s.port, host, ip.String(), text, nil)
	if err != nil {
		log.Fatal(err)
	}

	s.server = server
	return err
}
// HandleGetCharacteristics handles a get characteristic request.
func (ctr *CharacteristicController) HandleGetCharacteristics(form url.Values) (io.Reader, error) {
	var b bytes.Buffer
	aid, cid, err := ParseAccessoryAndCharacterID(form.Get("id"))
	containerChar := ctr.GetCharacteristic(aid, cid)
	if containerChar == nil {
		log.Printf("[WARN] No characteristic found with aid %d and iid %d\n", aid, cid)
		return &b, nil
	}

	chars := data.NewCharacteristics()
	char := data.Characteristic{AccessoryID: aid, ID: cid, Value: containerChar.GetValue(), Events: containerChar.EventsEnabled()}
	chars.AddCharacteristic(char)

	result, err := json.Marshal(chars)
	if err != nil {
		log.Println("[ERRO]", err)
	}

	b.Write(result)
	return &b, err
}
Beispiel #28
0
// DecryptedRead reads and decrypts bytes from the connection.
// The method returns the number of read bytes and an error when reading failed.
func (con *HAPConnection) DecryptedRead(b []byte) (int, error) {
	if con.readBuffer == nil {
		buffered := bufio.NewReader(con.connection)
		decrypted, err := con.getDecrypter().Decrypt(buffered)
		if err != nil {
			log.Println("[ERRO] Decryption failed:", err)
			err = con.connection.Close()
			return 0, err
		}

		con.readBuffer = decrypted
	}

	n, err := con.readBuffer.Read(b)

	if n < len(b) || err == io.EOF {
		con.readBuffer = nil
	}

	return n, err
}
// Server -> Client
// - B: server public key
// - signature: from server session public key, server name, client session public key
func (verify *VerifyServerController) handlePairVerifyStart(in util.Container) (util.Container, error) {
	verify.step = VerifyStepStartResponse

	clientPublicKey := in.GetBytes(TagPublicKey)
	log.Println("[VERB] ->     A:", hex.EncodeToString(clientPublicKey))
	if len(clientPublicKey) != 32 {
		return nil, errInvalidClientKeyLength
	}

	var otherPublicKey [32]byte
	copy(otherPublicKey[:], clientPublicKey)

	verify.session.GenerateSharedKeyWithOtherPublicKey(otherPublicKey)
	verify.session.SetupEncryptionKey([]byte("Pair-Verify-Encrypt-Salt"), []byte("Pair-Verify-Encrypt-Info"))

	device := verify.context.GetSecuredDevice()
	var material []byte
	material = append(material, verify.session.PublicKey[:]...)
	material = append(material, device.Name()...)
	material = append(material, clientPublicKey...)
	signature, err := crypto.ED25519Signature(device.PrivateKey(), material)
	if err != nil {
		log.Fatal(err)
		return nil, err
	}

	// Encrypt
	encryptedOut := util.NewTLV8Container()
	encryptedOut.SetString(TagUsername, device.Name())
	encryptedOut.SetBytes(TagSignature, signature)

	encryptedBytes, mac, _ := chacha20poly1305.EncryptAndSeal(verify.session.EncryptionKey[:], []byte("PV-Msg02"), encryptedOut.BytesBuffer().Bytes(), nil)

	out := util.NewTLV8Container()
	out.SetByte(TagSequence, verify.step.Byte())
	out.SetBytes(TagPublicKey, verify.session.PublicKey[:])
	out.SetBytes(TagEncryptedData, append(encryptedBytes, mac[:]...))

	log.Println("[VERB]        K:", hex.EncodeToString(verify.session.EncryptionKey[:]))
	log.Println("[VERB]        B:", hex.EncodeToString(verify.session.PublicKey[:]))
	log.Println("[VERB]        S:", hex.EncodeToString(verify.session.PrivateKey[:]))
	log.Println("[VERB]   Shared:", hex.EncodeToString(verify.session.SharedKey[:]))

	log.Println("[VERB] <-     B:", hex.EncodeToString(out.GetBytes(TagPublicKey)))

	return out, nil
}
// Client -> Server
// - A: entity public key
// - M1: proof
//
// Server -> entity
// - M2: proof
// or
// - auth error
func (setup *SetupServerController) handlePairVerify(in util.Container) (util.Container, error) {
	setup.step = PairStepVerifyResponse
	out := util.NewTLV8Container()
	out.SetByte(TagSequence, setup.step.Byte())

	clientPublicKey := in.GetBytes(TagPublicKey)
	log.Println("[VERB] ->     A:", hex.EncodeToString(clientPublicKey))

	err := setup.session.SetupPrivateKeyFromClientPublicKey(clientPublicKey)
	if err != nil {
		return nil, err
	}

	clientProof := in.GetBytes(TagProof)
	log.Println("[VERB] ->     M1:", hex.EncodeToString(clientProof))

	proof, err := setup.session.ProofFromClientProof(clientProof)
	if err != nil || len(proof) == 0 { // proof `M1` is wrong
		log.Println("[WARN] Proof M1 is wrong")
		setup.reset()
		out.SetByte(TagErrCode, ErrCodeAuthenticationFailed.Byte()) // return error 2
	} else {
		log.Println("[INFO] Proof M1 is valid")
		err := setup.session.SetupEncryptionKey([]byte("Pair-Setup-Encrypt-Salt"), []byte("Pair-Setup-Encrypt-Info"))
		if err != nil {
			return nil, err
		}

		// Return proof `M2`
		out.SetBytes(TagProof, proof)
	}

	log.Println("[VERB] <-     M2:", hex.EncodeToString(out.GetBytes(TagProof)))
	log.Println("[VERB]         S:", hex.EncodeToString(setup.session.PrivateKey))
	log.Println("[VERB]         K:", hex.EncodeToString(setup.session.EncryptionKey[:]))

	return out, nil
}