- Add testCountEntitiesWithOrKeyFiltersOperation: verifies OR count returns entities matching any filter
- Add testFindEntityDataWithOrKeyFiltersOperation: verifies OR data query with different keys
- Add testFindEntityDataWithOrSameKeyFilters: verifies same-key OR ungrouping
- Add testCountEntitiesWithoutKeyFiltersOperation: verifies null defaults to AND
- Add testAlarmDataQueryWithOrKeyFiltersOperation: verifies alarm queries with OR
- Add OrConditionsDisabledEntityQueryControllerTest: verifies OR rejected when toggle disabled
- Add sql.query.key-filters-or-conditions.enabled property to thingsboard.yml
- Add allowKeyFiltersOrConditions field to SystemParams
- Wire config value into SystemInfoController for /api/system/params
- Add validateKeyFiltersOperation to DefaultEntityQueryService
- Add throws ThingsboardException to EntityQueryService interface methods
- Reject OR queries with 400 when feature is disabled
- Add keyFiltersOperation field with null-safe getKeyFiltersOperationOrDefault()
- Add 3-arg constructor to EntityCountQuery for explicit operation
- Add 6-arg constructors to AbstractDataQuery and EntityDataQuery
- Add 7-arg constructor to AlarmDataQuery
- Update next() methods to propagate keyFiltersOperation
- Update buildEntityDataQuery methods to pass operation from alarm queries
- Deduplicate forEach iteration over both session maps (HashSet)
- Use null-safe getEdgeId() instead of getEdge().getId() in remove()
- Add defensive null checks on getState() in onConfigurationUpdate and destroyAndMarkAsZombieIfFailed
- Add null check on pendingMsgsMap.get() in onDownlinkResponse
- Move scheduleAtFixedRate to @PostConstruct in DefaultZombieSessionCleanupService
- Fix misleading "kafka sessions" log message to "zombie sessions"
- Chain IOException in GrpcServer RuntimeException
- Guard against race condition on removeByEdgeId in onEdgeDisconnect
- Rename shadowed parameter in shutdownExecutorSafely
Route DataAccessException and PersistenceException (including bare
ConstraintViolationException) to a unified handler that extracts the
constraint name and returns "Constraint violation: <name>" instead of
the raw PSQLException message. Other DB errors continue to return the
generic "Database error" response.
Adds DaoUtil.extractConstraintViolation helper and an integration test
that verifies no SQL details leak when an FK constraint is violated.
Keep both save-time validation (Oauth2ClientDataValidator) and runtime
re-validation as defense-in-depth: DNS records can change between config
save and OAuth2 login, creating a TOCTOU gap.
- Use kebab-case 'report-only' in web-ui configs to match thingsboard.yml
- Add log.warn for unrecognized X-Frame-Options values in customizer
- Replace @Configuration with @Component on HttpSecurityHeadersProperties
- Add comment explaining '!== false' vs truthiness pattern in server.ts
- Extract shared parseHostEntries() to deduplicate setAllowedHosts/setAdditionalBlockedHosts
- Add isHostnameAllowed() and propagate hostname allow-list check in resolver
- Move OAuth2 custom mapper URL SSRF validation to save-time (Oauth2ClientDataValidator)
- Remove runtime SSRF checks from CustomOAuth2ClientMapper and GithubOAuth2ClientMapper
(custom URL now validated at save; GitHub emailUrl is server config, not user input)
- Replace example.com with 8.8.8.8 in resolver test to avoid DNS dependency
Fix security issues from penetration test report:
- M2: Add configurable X-Frame-Options and CSP headers (disabled by default)
- L2: Add X-Content-Type-Options and Referrer-Policy headers (enabled by default)
- L3: Make CORS allowed-origin-patterns configurable via TB_CORS_* env vars
Root cause: ThingsboardSecurityConfiguration called .disable() on the entire
HeadersConfigurer, which removed ALL security headers including Cache-Control.
Fix uses defaultsDisabled() + selective header enablement via a new
HttpSecurityHeadersCustomizer component.
Both Spring Boot (tb-node) and Express.js (web-ui) share the same
SECURITY_HEADERS_* environment variables for consistent configuration
across monolith and microservice deployments.
Add SsrfSafeAddressResolverGroup that validates resolved IPs at Netty
connection time, eliminating the TOCTOU gap where DNS rebinding domains
resolve to safe IPs during validation but to private/metadata IPs at
connection time. Disable HTTP redirects in TbHttpClient to prevent
redirect-based SSRF bypass.
Add allow-list support (SSRF_ALLOWED_HOSTS) to SsrfProtectionValidator
so customers with IoT devices on private networks can whitelist specific
addresses or CIDR ranges while keeping SSRF protection enabled.
Add SSRF validation to MS Teams webhook, custom OAuth2 mapper, and
GitHub OAuth2 mapper endpoints. Log a warning when SSRF protection is
disabled.
Apply CustomTranslatePipe to unitTitle and title properties in analogue
and digital gauge widgets, and add customTranslation to the label widget
controller script to support i18n translations.
- Extract RuleChainDetailsDao from RuleChainDao to reuse JpaAbstractDao
save logic (proper @Version increment, flush, detach)
- Reduce notes column size from 10MB to 1MB in schema and migration
- Catch "value too long" DB error with user-friendly message
- Pass tenantId consistently through the details DAO API
- Exclude content/markdownCss from RuleChainNote toString
- Add tests: save/load notes, update notes, preserve notes on
RuleChain save, remove notes, exceeded size limit
- Refactor update/delete endpoints to use installed item's own ID instead of marketplace itemId
- Add SHA-256 checksum comparison to detect local entity modifications before update
- Support force update to skip checksum check when user confirms overwrite
- Add per-type update methods (widget, dashboard, calculated field, rule chain)
- Add entityId field to CalculatedFieldInstalledItemDescriptor
- Replace checkForUpdates with getItemsPublishedVersions API
- Replace getInstalledItemInfos with getInstalledItemIds returning List<UUID>
- Remove unused IotHubInstalledItemInfo class and resolver
- Set metadata version from saved rule chain in install/update flows
- Add entity-modified confirmation dialog in update UI
Static fields RESOURCE_ID_3303_12_5700_TS_0/TS_1 in Lwm2mTestHelper are never
reset between test runs. On CI retries the await() at the start of the test
passes immediately (both timestamps are still > 0 from the previous run), so
the telemetry query uses stale timestamps and the second await() times out.
Fix: add @Before that resets both timestamps to 0 before each test method,
which was already correctly implied by the unused @Before import.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Leshan's NotificationDataStore.toKey() can throw NPE when the server reference
is null during CoAP observe-relation cleanup on client shutdown (race condition).
This NPE was caught by the outer try-catch in startUpdating(), which prevented
leshanClient.start() from being called, leaving the simulated device stuck in
UPDATING state and causing the awaitility timeout in the OTA integration test.
Fix: wrap leshanClient.stop(false) in its own try-catch so that a Leshan
internal exception during stop does not abort the subsequent client restart.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>