lorawan-stack icon indicating copy to clipboard operation
lorawan-stack copied to clipboard

EUI with `null` value converted to zeros on gateway update

Open nicholaspcr opened this issue 3 months ago • 0 comments

Summary

Error found internally where trying to update a gateway's EUI with a body that explicitly passes null as its EUI value yields a EUI filled with zeros instead of generating an empty string.

This causes trouble as when unsetting a gateway EUI via a http request with this specific value, it either returns a 409 conflict or sets its value to "0000000000000000" (depending if a gateway with that EUI already exists).

{
  "gateway": {
    "ids": {
      "eui": null
    }
  },
  "field_mask": {
    "paths": [
      "ids.eui"
    ]
  }
}

Could not generate this error attempting to do this via a gRPC request.

Steps to Reproduce

  1. Login
  2. Create a gtw with an EUI containing only zeros
  3. Create a gtw with an EUI
  4. Update the second gateway and pass null in the ids.eui field

Examples done with CLI And curl:

# first gateway
ttn-lw-cli gtw create gtw-0 --user-id admin --gateway-eui "0000000000000000" --frequency-plan-id "EU_863_870_TTN"

# second gateway
ttn-lw-cli gtw create gtw-1 --user-id admin --gateway-eui "0000000000000001" --frequency-plan-id "EU_863_870_TTN"

# use curl to provide the body with `gateways.ids.eui` as `null`
curl -X PUT \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <token>" \
  -d '{ "gateway": { "ids": { "eui": null }}, "field_mask": { "paths": [ "ids.eui" ] } }' \
  "http://localhost:1885/api/v3/gateways/gtw-1"

# Returns
{"code":6,"message":"error:pkg/util/store:eui_taken (EUI already taken)","details":[{"@type":"type.googleapis.com/ttn.lorawan.v3.ErrorDetails","namespace":"pkg/util/store","name":"eui_taken","message_format":"EUI already taken","correlation_id":"e792040de0f64cb3b150c2d167d5eaff","cause":{"namespace":"pkg/util/store","name":"already_exists","message_format":"already exists","correlation_id":"8485628b99cf4cf2890e1b02f36487e8","code":6},"code":6}]}%

Current Result

It works only if not providing null as the value of the field.

curl -X PUT \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <token>" \
  -d '{ "field_mask": { "paths": [ "ids.eui" ] } }' \
  "http://localhost:1885/api/v3/gateways/gtw-1"

# response
{"ids":{"gateway_id":"gtw-1"},"created_at":"2024-05-17T14:17:00.408035Z","updated_at":"2024-05-17T14:24:24.632342Z"}%

Expected Result

It should set the EUI to an empty value when passing the null as a value.

Relevant Logs

No response

URL

No response

Deployment

The Things Stack Open Source (self-hosted)

The Things Stack Version

v3.30-dev

Client Name and Version

No response

Other Information

No response

Proposed Fix

Investigate the unmarshalNBytes in pkg/types/types.go to validate why this conversion happens.

Contributing

  • [X] I can help by doing more research.
  • [X] I can help by implementing a fix after the proposal above is approved.
  • [X] I can help by testing the fix before it's released.

Validation

Code of Conduct

nicholaspcr avatar May 17 '24 14:05 nicholaspcr