Device Field Lock/Unlock API
Overview
The Device Field Lock/Unlock feature allows users to lock specific device fields to prevent plugin overwrites. This is part of the authoritative device field update system that ensures data integrity while maintaining flexibility for user customization.
Concepts
Tracked Fields
Only certain device fields support locking. These are the fields that can be modified by both plugins and users:
devName- Device name/hostnamedevVendor- Device vendor/manufacturerdevFQDN- Fully qualified domain namedevSSID- Network SSIDdevParentMAC- Parent device MAC addressdevParentPort- Parent device portdevParentRelType- Parent device relationship typedevVlan- VLAN identifier
Field Source Tracking
Every tracked field has an associated *Source field that indicates where the current value originated:
NEWDEV- Created via the UI as a new deviceUSER- Manually edited by a userLOCKED- Field is locked; prevents any plugin overwrites- Plugin name (e.g.,
UNIFIAPI,PIHOLE) - Last updated by this plugin
Locking Mechanism
When a field is locked, its source is set to LOCKED. This prevents plugin overwrites based on the authorization logic:
- Plugin wants to update field
- Authoritative handler checks field's
*Sourcevalue - If
*Source==LOCKED, plugin update is rejected - User can still manually unlock the field
When a field is unlocked, its source is set to NEWDEV, allowing plugins to resume updates.
Endpoints
Lock or Unlock a Field
POST /device/{mac}/field/lock
Authorization: Bearer {API_TOKEN}
Content-Type: application/json
{
"fieldName": "devName",
"lock": true
}
Parameters
mac(path, required): Device MAC address (e.g.,AA:BB:CC:DD:EE:FF)fieldName(body, required): Name of the field to lock/unlock. Must be one of the tracked fields listed above.lock(body, required): Boolean.trueto lock,falseto unlock.
Responses
Success (200)
{
"success": true,
"message": "Field devName locked",
"fieldName": "devName",
"locked": true
}
Bad Request (400)
{
"success": false,
"error": "fieldName is required"
}
{
"success": false,
"error": "Field 'devInvalidField' cannot be locked"
}
Unauthorized (403)
{
"success": false,
"error": "Unauthorized"
}
Not Found (404)
{
"success": false,
"error": "Device not found"
}
Examples
Lock a Device Name
Prevent the device name from being overwritten by plugins:
curl -X POST https://your-netalertx.local/api/device/AA:BB:CC:DD:EE:FF/field/lock \
-H "Authorization: Bearer your-api-token" \
-H "Content-Type: application/json" \
-d '{
"fieldName": "devName",
"lock": true
}'
Unlock a Field
Allow plugins to resume updating a field:
curl -X POST https://your-netalertx.local/api/device/AA:BB:CC:DD:EE:FF/field/lock \
-H "Authorization: Bearer your-api-token" \
-H "Content-Type: application/json" \
-d '{
"fieldName": "devName",
"lock": false
}'
UI Integration
The Device Edit form displays lock/unlock buttons for all tracked fields:
- Lock Button (🔒): Click to prevent plugin overwrites
- Unlock Button (🔓): Click to allow plugin overwrites again
- Source Indicator: Shows current field source (USER, LOCKED, NEWDEV, or plugin name)
UI Workflow
Locking a Field via UI
- Navigate to Device Details
- Find the field you want to protect
- Click the lock button (🔒) next to the field
- Button changes to unlock (🔓) and source indicator turns red (LOCKED)
- Field is now protected from plugin overwrites
Unlocking a Field via UI
- Find the locked field (button shows 🔓)
- Click the unlock button
- Button changes back to lock (🔒) and source resets to NEWDEV
- Plugins can now update this field again
Authorization
All lock/unlock operations require:
- Valid API token in Authorization: Bearer {token} header
- User must be authenticated to the NetAlertX instance
Implementation Details
Backend Logic
The lock/unlock feature is implemented in:
- API Endpoint: /server/api_server/api_server_start.py - api_device_field_lock()
- Data Model: /server/models/device_instance.py - Authorization checks in setDeviceData()
- Database: Devices table with *Source columns tracking field origins
Authorization Handler
The authoritative field update logic prevents plugin overwrites:
- Plugin provides new value for field via plugin config
SET_ALWAYS/SET_EMPTY - Authoritative handler (in DeviceInstance) checks
{field}Sourcevalue - If source is
LOCKEDorUSER, plugin update is rejected - If source is
NEWDEVor plugin name, plugin update is accepted