// Decode decodes the payload using the Decoder function into a map func (f *UplinkFunctions) Decode(payload []byte, port uint8) (map[string]interface{}, error) { if f.Decoder == "" { return nil, errors.NewErrInternal("Decoder function not set") } env := map[string]interface{}{ "payload": payload, "port": port, } code := fmt.Sprintf(` %s; Decoder(payload.slice(0), port); `, f.Decoder) value, err := functions.RunCode("decoder", code, env, timeOut, f.Logger) if err != nil { return nil, err } if !value.IsObject() { return nil, errors.NewErrInvalidArgument("Decoder", "does not return an object") } v, _ := value.Export() m, ok := v.(map[string]interface{}) if !ok { return nil, errors.NewErrInvalidArgument("Decoder", "does not return an object") } return m, nil }
// Convert converts the values in the specified map to a another map using the // Converter function. If the Converter function is not set, this function // returns the data as-is func (f *UplinkFunctions) Convert(fields map[string]interface{}, port uint8) (map[string]interface{}, error) { if f.Converter == "" { return fields, nil } env := map[string]interface{}{ "fields": fields, "port": port, } code := fmt.Sprintf(` %s; Converter(fields, port) `, f.Converter) value, err := functions.RunCode("converter", code, env, timeOut, f.Logger) if err != nil { return nil, err } if !value.IsObject() { return nil, errors.NewErrInvalidArgument("Converter", "does not return an object") } v, _ := value.Export() m, ok := v.(map[string]interface{}) if !ok { return nil, errors.NewErrInvalidArgument("Converter", "does not return an object") } return m, nil }
func (s *networkServerRPC) ValidateContext(ctx context.Context) error { md, ok := metadata.FromContext(ctx) if !ok { return errors.NewErrInternal("Could not get metadata from context") } var id, token string if ids, ok := md["id"]; ok && len(ids) == 1 { id = ids[0] } if id == "" { return errors.NewErrInvalidArgument("Metadata", "id missing") } if tokens, ok := md["token"]; ok && len(tokens) == 1 { token = tokens[0] } if token == "" { return errors.NewErrInvalidArgument("Metadata", "token missing") } var claims *jwt.StandardClaims claims, err := security.ValidateJWT(token, []byte(s.networkServer.(*networkServer).Identity.PublicKey)) if err != nil { return err } if claims.Subject != id { return errors.NewErrInvalidArgument("Metadata", "token was issued for a different component id") } return nil }
// ValidateNetworkContext validates the context of a network request (router-broker, broker-handler, etc) func (c *Component) ValidateNetworkContext(ctx context.Context) (component *pb_discovery.Announcement, err error) { defer func() { if err != nil { time.Sleep(time.Second) } }() md, ok := metadata.FromContext(ctx) if !ok { err = errors.NewErrInternal("Could not get metadata from context") return } var id, serviceName, token string if ids, ok := md["id"]; ok && len(ids) == 1 { id = ids[0] } if id == "" { err = errors.NewErrInvalidArgument("Metadata", "id missing") return } if serviceNames, ok := md["service-name"]; ok && len(serviceNames) == 1 { serviceName = serviceNames[0] } if serviceName == "" { err = errors.NewErrInvalidArgument("Metadata", "service-name missing") return } if tokens, ok := md["token"]; ok && len(tokens) == 1 { token = tokens[0] } var announcement *pb_discovery.Announcement announcement, err = c.Discover(serviceName, id) if err != nil { return } if announcement.PublicKey == "" { return announcement, nil } if token == "" { err = errors.NewErrInvalidArgument("Metadata", "token missing") return } var claims *jwt.StandardClaims claims, err = security.ValidateJWT(token, []byte(announcement.PublicKey)) if err != nil { return } if claims.Issuer != id { err = errors.NewErrInvalidArgument("Metadata", "token was issued by different component id") return } return announcement, nil }
// Validate implements the api.Validator interface func (m *RxMetadata) Validate() error { if m.Protocol == nil { return errors.NewErrInvalidArgument("Protocol", "can not be empty") } if err := api.Validate(m.Protocol); err != nil { return errors.NewErrInvalidArgument("Protocol", err.Error()) } return nil }
// Validate implements the api.Validator interface func (m *DeviceIdentifier) Validate() error { if m.AppEui == nil || m.AppEui.IsEmpty() { return errors.NewErrInvalidArgument("AppEui", "can not be empty") } if m.DevEui == nil || m.DevEui.IsEmpty() { return errors.NewErrInvalidArgument("DevEui", "can not be empty") } return nil }
// NotEmptyAndValidID checks if the ID is not empty AND has a valid format func NotEmptyAndValidID(id string, argument string) error { if id == "" { return errors.NewErrInvalidArgument(argument, "can not be empty") } if !ValidID(id) { return errors.NewErrInvalidArgument(argument, "has wrong format "+id) } return nil }
// Validate implements the api.Validator interface func (m *JoinRequestPayload) Validate() error { if m.AppEui.IsEmpty() { return errors.NewErrInvalidArgument("AppEui", "can not be empty") } if m.DevEui.IsEmpty() { return errors.NewErrInvalidArgument("DevEui", "can not be empty") } return nil }
func (n *networkServer) UsePrefix(prefix types.DevAddrPrefix, usage []string) error { if prefix.Length < 7 { return errors.NewErrInvalidArgument("Prefix", "invalid length") } if prefix.DevAddr[0]>>1 != n.netID[2] { return errors.NewErrInvalidArgument("Prefix", "invalid netID") } n.prefixes[prefix] = usage return nil }
func (n *networkServer) HandleDownlink(message *pb_broker.DownlinkMessage) (*pb_broker.DownlinkMessage, error) { // Get Device dev, err := n.devices.Get(*message.AppEui, *message.DevEui) if err != nil { return nil, err } n.status.downlink.Mark(1) dev.StartUpdate() if dev.AppID != message.AppId || dev.DevID != message.DevId { return nil, errors.NewErrInvalidArgument("Downlink", "AppID and DevID do not match AppEUI and DevEUI") } // Unmarshal LoRaWAN Payload var phyPayload lorawan.PHYPayload err = phyPayload.UnmarshalBinary(message.Payload) if err != nil { return nil, err } macPayload, ok := phyPayload.MACPayload.(*lorawan.MACPayload) if !ok { return nil, errors.NewErrInvalidArgument("Downlink", "does not contain a MAC payload") } // Set DevAddr macPayload.FHDR.DevAddr = lorawan.DevAddr(dev.DevAddr) // FIRST set and THEN increment FCntDown // TODO: For confirmed downlink, FCntDown should be incremented AFTER ACK macPayload.FHDR.FCnt = dev.FCntDown dev.FCntDown++ err = n.devices.Set(dev) if err != nil { return nil, err } // Sign MIC phyPayload.SetMIC(lorawan.AES128Key(dev.NwkSKey)) // Update message bytes, err := phyPayload.MarshalBinary() if err != nil { return nil, err } message.Payload = bytes return message, nil }
// Validate implements the api.Validator interface func (m *Message) Validate() error { if m.Major != Major_LORAWAN_R1 { return errors.NewErrInvalidArgument("Major", "invalid value "+Major_LORAWAN_R1.String()) } switch m.MType { case MType_JOIN_REQUEST: if m.GetJoinRequestPayload() == nil { return errors.NewErrInvalidArgument("JoinRequestPayload", "can not be empty") } if err := m.GetJoinRequestPayload().Validate(); err != nil { return errors.NewErrInvalidArgument("JoinRequestPayload", err.Error()) } case MType_JOIN_ACCEPT: if m.GetJoinAcceptPayload() == nil { return errors.NewErrInvalidArgument("JoinAcceptPayload", "can not be empty") } if err := m.GetJoinAcceptPayload().Validate(); err != nil { return errors.NewErrInvalidArgument("JoinAcceptPayload", err.Error()) } case MType_UNCONFIRMED_UP, MType_UNCONFIRMED_DOWN, MType_CONFIRMED_UP, MType_CONFIRMED_DOWN: if m.GetMacPayload() == nil { return errors.NewErrInvalidArgument("MacPayload", "can not be empty") } if err := m.GetMacPayload().Validate(); err != nil { return errors.NewErrInvalidArgument("MacPayload", err.Error()) } default: return errors.NewErrInvalidArgument("MType", "unknown type "+m.MType.String()) } return nil }
// Validate implements the api.Validator interface func (m *ActivationMetadata) Validate() error { if m.AppEui == nil || m.AppEui.IsEmpty() { return errors.NewErrInvalidArgument("AppEui", "can not be empty") } if m.DevEui == nil || m.DevEui.IsEmpty() { return errors.NewErrInvalidArgument("DevEui", "can not be empty") } if m.DevAddr != nil && m.DevAddr.IsEmpty() { return errors.NewErrInvalidArgument("DevAddr", "can not be empty") } if m.NwkSKey != nil && m.NwkSKey.IsEmpty() { return errors.NewErrInvalidArgument("NwkSKey", "can not be empty") } return nil }
// Validate implements the api.Validator interface func (m *Device) Validate() error { if m.AppEui == nil || m.AppEui.IsEmpty() { return errors.NewErrInvalidArgument("AppEui", "can not be empty") } if m.DevEui == nil || m.DevEui.IsEmpty() { return errors.NewErrInvalidArgument("DevEui", "can not be empty") } if err := api.NotEmptyAndValidID(m.AppId, "AppId"); err != nil { return err } if err := api.NotEmptyAndValidID(m.DevId, "DevId"); err != nil { return err } return nil }
// Validate implements the api.Validator interface func (m *DownlinkOption) Validate() error { if m.Identifier == "" { return errors.NewErrInvalidArgument("Identifier", "can not be empty") } if m.GatewayId == "" { return errors.NewErrInvalidArgument("GatewayId", "can not be empty") } if err := api.NotNilAndValid(m.ProtocolConfig, "ProtocolConfig"); err != nil { return err } if err := api.NotNilAndValid(m.GatewayConfig, "GatewayConfig"); err != nil { return err } return nil }
func (n *networkServer) HandleActivate(activation *pb_handler.DeviceActivationResponse) (*pb_handler.DeviceActivationResponse, error) { meta := activation.GetActivationMetadata() if meta == nil { return nil, errors.NewErrInvalidArgument("Activation", "missing ActivationMetadata") } lorawan := meta.GetLorawan() if lorawan == nil { return nil, errors.NewErrInvalidArgument("Activation", "missing LoRaWAN ActivationMetadata") } n.status.activations.Mark(1) err := n.devices.Activate(*lorawan.AppEui, *lorawan.DevEui, *lorawan.DevAddr, *lorawan.NwkSKey) if err != nil { return nil, err } return activation, nil }
// Validate implements the api.Validator interface func (m *TxConfiguration) Validate() error { switch m.Modulation { case Modulation_LORA: if m.DataRate == "" { return errors.NewErrInvalidArgument("DataRate", "can not be empty") } case Modulation_FSK: if m.BitRate == 0 { return errors.NewErrInvalidArgument("BitRate", "can not be empty") } } if m.CodingRate == "" { return errors.NewErrInvalidArgument("CodingRate", "can not be empty") } return nil }
func (h *handlerManager) validateTTNAuthAppContext(ctx context.Context, appID string) (context.Context, *claims.Claims, error) { md, err := api.MetadataFromContext(ctx) if err != nil { return ctx, nil, err } // If token is empty, try to get the access key and convert it into a token token, err := api.TokenFromMetadata(md) if err != nil || token == "" { key, err := api.KeyFromMetadata(md) if err != nil { return ctx, nil, errors.NewErrInvalidArgument("Metadata", "neither token nor key present") } token, err := h.handler.Component.ExchangeAppKeyForToken(appID, key) if err != nil { return ctx, nil, err } md = metadata.Join(md, metadata.Pairs("token", token)) ctx = metadata.NewContext(ctx, md) } claims, err := h.handler.Component.ValidateTTNAuthContext(ctx) if err != nil { return ctx, nil, err } if h.clientRate.Limit(claims.Subject) { return ctx, claims, grpc.Errorf(codes.ResourceExhausted, "Rate limit for client reached") } if h.applicationRate.Limit(appID) { return ctx, claims, grpc.Errorf(codes.ResourceExhausted, "Rate limit for application reached") } return ctx, claims, nil }
// ConvertFieldsUp converts the payload to fields using payload functions func (h *handler) ConvertFieldsUp(ctx log.Interface, ttnUp *pb_broker.DeduplicatedUplinkMessage, appUp *types.UplinkMessage) error { // Find Application app, err := h.applications.Get(ttnUp.AppId) if err != nil { return nil // Do not process if application not found } functions := &UplinkFunctions{ Decoder: app.Decoder, Converter: app.Converter, Validator: app.Validator, Logger: functions.Ignore, } fields, valid, err := functions.Process(appUp.PayloadRaw, appUp.FPort) if err != nil { return nil // Do not set fields if processing failed } if !valid { return errors.NewErrInvalidArgument("Payload", "payload validator function returned false") } appUp.PayloadFields = fields return nil }
// ConvertFieldsDown converts the fields into a payload func (h *handler) ConvertFieldsDown(ctx log.Interface, appDown *types.DownlinkMessage, ttnDown *pb_broker.DownlinkMessage) error { if appDown.PayloadFields == nil || len(appDown.PayloadFields) == 0 { return nil } if appDown.PayloadRaw != nil { return errors.NewErrInvalidArgument("Downlink", "Both Fields and Payload provided") } app, err := h.applications.Get(appDown.AppID) if err != nil { return nil } functions := &DownlinkFunctions{ Encoder: app.Encoder, Logger: functions.Ignore, } message, _, err := functions.Process(appDown.PayloadFields, appDown.FPort) if err != nil { return err } appDown.PayloadRaw = message return nil }
// Validate validates the values in the specified map using the Validator // function. If the Validator function is not set, this function returns true func (f *UplinkFunctions) Validate(fields map[string]interface{}, port uint8) (bool, error) { if f.Validator == "" { return true, nil } env := map[string]interface{}{ "fields": fields, "port": port, } code := fmt.Sprintf(` %s; Validator(fields, port) `, f.Validator) value, err := functions.RunCode("valdator", code, env, timeOut, f.Logger) if err != nil { return false, err } if !value.IsBoolean() { return false, errors.NewErrInvalidArgument("Validator", "does not return a boolean") } return value.ToBoolean() }
// Validate implements the api.Validator interface func (m *JoinAcceptPayload) Validate() error { if len(m.Encrypted) != 0 { return nil } if m.CfList != nil && len(m.CfList.Freq) != 5 { return errors.NewErrInvalidArgument("CfList.Freq", "length must be 5") } if m.DevAddr.IsEmpty() { return errors.NewErrInvalidArgument("DevAddr", "can not be empty") } if m.NetId.IsEmpty() { return errors.NewErrInvalidArgument("NetId", "can not be empty") } return nil }
// Validate implements the api.Validator interface func (m *ApplicationHandlerRegistration) Validate() error { if err := api.NotEmptyAndValidID(m.AppId, "AppId"); err != nil { return err } if m.HandlerId == "" { return errors.NewErrInvalidArgument("HandlerId", "can not be empty") } return nil }
// Validate implements the api.Validator interface func (m *DeduplicatedDeviceActivationRequest) Validate() error { if err := api.NotNilAndValid(m.ProtocolMetadata, "ProtocolMetadata"); err != nil { return err } if m.Message != nil { if err := m.Message.Validate(); err != nil { return errors.NewErrInvalidArgument("Message", err.Error()) } } return nil }
// Validate implements the api.Validator interface func (m *Announcement) Validate() error { if err := api.NotEmptyAndValidID(m.Id, "Id"); err != nil { return err } switch m.ServiceName { case "router", "broker", "handler": default: return errors.NewErrInvalidArgument("ServiceName", "expected one of router, broker, handler but was "+m.ServiceName) } return nil }
// Announce the component to TTN discovery func (c *Component) Announce() error { if c.Identity.Id == "" { return errors.NewErrInvalidArgument("Component ID", "can not be empty") } err := c.Discovery.Announce(c.AccessToken) if err != nil { return errors.Wrapf(errors.FromGRPCError(err), "Failed to announce this component to TTN discovery: %s", err.Error()) } c.Ctx.Info("ttn: Announced to TTN discovery") return nil }
// Validate implements the api.Validator interface func (m *DeduplicatedUplinkMessage) Validate() error { if err := api.NotEmptyAndValidID(m.AppId, "AppId"); err != nil { return err } if err := api.NotEmptyAndValidID(m.DevId, "DevId"); err != nil { return err } if err := api.NotNilAndValid(m.ProtocolMetadata, "ProtocolMetadata"); err != nil { return err } if m.ResponseTemplate != nil { if err := m.ResponseTemplate.Validate(); err != nil { return errors.NewErrInvalidArgument("ResponseTemplate", err.Error()) } } if m.Message != nil { if err := m.Message.Validate(); err != nil { return errors.NewErrInvalidArgument("Message", err.Error()) } } return nil }
// Validate implements the api.Validator interface func (m *UplinkMessage) Validate() error { if err := api.NotNilAndValid(m.GatewayMetadata, "GatewayMetadata"); err != nil { return err } if err := api.NotNilAndValid(m.ProtocolMetadata, "ProtocolMetadata"); err != nil { return err } if m.Message != nil { if err := m.Message.Validate(); err != nil { return errors.NewErrInvalidArgument("Message", err.Error()) } } return nil }
// Validate implements the api.Validator interface func (m *DownlinkMessage) Validate() error { if err := api.NotNilAndValid(m.ProtocolConfiguration, "ProtocolConfiguration"); err != nil { return err } if err := api.NotNilAndValid(m.GatewayConfiguration, "GatewayConfiguration"); err != nil { return err } if m.Message != nil { if err := m.Message.Validate(); err != nil { return errors.NewErrInvalidArgument("Message", err.Error()) } } return nil }
// Validate implements the api.Validator interface func (m *DeviceActivationResponse) Validate() error { if err := api.NotNilAndValid(m.DownlinkOption, "DownlinkOption"); err != nil { return err } if err := api.NotNilAndValid(m.ActivationMetadata, "ActivationMetadata"); err != nil { return err } if m.Message != nil { if err := m.Message.Validate(); err != nil { return errors.NewErrInvalidArgument("Message", err.Error()) } } return nil }
// Validate implements the api.Validator interface func (m *DownlinkMessage) Validate() error { if err := api.NotEmptyAndValidID(m.DevId, "DevId"); err != nil { return err } if err := api.NotEmptyAndValidID(m.AppId, "AppId"); err != nil { return err } if err := api.NotNilAndValid(m.DownlinkOption, "DownlinkOption"); err != nil { return err } if m.Message != nil { if err := m.Message.Validate(); err != nil { return errors.NewErrInvalidArgument("Message", err.Error()) } } return nil }