From fcbf6a4b3f52e67f2b7f636050b8f5a6e3529499 Mon Sep 17 00:00:00 2001 From: TJ da Tuna Date: Sat, 14 Feb 2026 14:16:13 -0600 Subject: [PATCH] Add Furbo to cloud camera vendor list Furbo dog cameras require internet for remote access and should be categorized as CloudCamera for proper IoT VLAN recommendations. Co-authored-by: ekobres Extracted from #269 - the rest of that PR (Apple device detection improvements) is pending review and testing. --- .../Services/DeviceTypeDetectionService.cs | 3 +- .../DeviceTypeDetectionServiceTests.cs | 45 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/NetworkOptimizer.Audit/Services/DeviceTypeDetectionService.cs b/src/NetworkOptimizer.Audit/Services/DeviceTypeDetectionService.cs index ec3492c2..ce1487eb 100644 --- a/src/NetworkOptimizer.Audit/Services/DeviceTypeDetectionService.cs +++ b/src/NetworkOptimizer.Audit/Services/DeviceTypeDetectionService.cs @@ -1191,7 +1191,8 @@ private static bool IsCloudSecurityVendor(string vendorLower) System.Text.RegularExpressions.Regex.IsMatch(vendorLower, @"\barlo\b") || System.Text.RegularExpressions.Regex.IsMatch(vendorLower, @"\bsimplisafe\b") || System.Text.RegularExpressions.Regex.IsMatch(vendorLower, @"\btp-link\b") || - System.Text.RegularExpressions.Regex.IsMatch(vendorLower, @"\bcanary\b"); + System.Text.RegularExpressions.Regex.IsMatch(vendorLower, @"\bcanary\b") || + System.Text.RegularExpressions.Regex.IsMatch(vendorLower, @"\bfurbo\b"); } /// diff --git a/tests/NetworkOptimizer.Audit.Tests/Services/DeviceTypeDetectionServiceTests.cs b/tests/NetworkOptimizer.Audit.Tests/Services/DeviceTypeDetectionServiceTests.cs index bd809853..c1a32988 100644 --- a/tests/NetworkOptimizer.Audit.Tests/Services/DeviceTypeDetectionServiceTests.cs +++ b/tests/NetworkOptimizer.Audit.Tests/Services/DeviceTypeDetectionServiceTests.cs @@ -228,6 +228,25 @@ public void DetectDeviceType_RingVendor_ReturnsCloudCamera() result.Category.Should().Be(ClientDeviceCategory.CloudCamera); } + [Fact] + public void DetectDeviceType_FurboVendor_ReturnsCloudCamera() + { + // Arrange - Furbo is a cloud camera vendor (dog camera with treat tossing) + var client = new UniFiClientResponse + { + Mac = "11:22:33:44:55:66", + Name = "Furbo Dog Camera", + Oui = "Furbo", + DevCat = 9 // Camera fingerprint (9 = IP Network Camera) + }; + + // Act + var result = _service.DetectDeviceType(client); + + // Assert - Furbo cameras are cloud cameras (require internet for remote access) + result.Category.Should().Be(ClientDeviceCategory.CloudCamera); + } + #endregion #region Camera Name Override Tests (Nest/Google cameras) @@ -258,6 +277,29 @@ public void DetectDeviceType_NestOrGoogleWithCameraName_ReturnsCloudCamera(strin result.Category.Should().Be(ClientDeviceCategory.CloudCamera); } + [Theory] + [InlineData("Furbo", "Living Room")] + [InlineData("FURBO", "Dog Camera")] + [InlineData("Furbo Inc", "Pet Camera")] + [InlineData("Furbo Dog Camera", "Kitchen Cam")] + public void DetectDeviceType_FurboVendorVariations_ReturnsCloudCamera(string vendor, string deviceName) + { + // Arrange - Test various Furbo vendor name formats (case-insensitive, with suffixes) + var client = new UniFiClientResponse + { + Mac = "11:22:33:44:55:66", + Name = deviceName, + Oui = vendor, + DevCat = 9 // Camera fingerprint + }; + + // Act + var result = _service.DetectDeviceType(client); + + // Assert - All Furbo variations should be detected as cloud cameras + result.Category.Should().Be(ClientDeviceCategory.CloudCamera); + } + [Theory] [InlineData("Nest Labs Inc.", "Living Room Thermostat", ClientDeviceCategory.SmartThermostat)] [InlineData("Nest Labs Inc.", "Hallway Ecobee", ClientDeviceCategory.SmartThermostat)] @@ -976,6 +1018,7 @@ public void SetClientHistory_FiltersEntriesWithEmptyMac() [InlineData("Blink", ClientDeviceCategory.CloudCamera)] [InlineData("TP-Link", ClientDeviceCategory.CloudCamera)] [InlineData("Canary", ClientDeviceCategory.CloudCamera)] + [InlineData("Furbo", ClientDeviceCategory.CloudCamera)] public void DetectFromMac_HistoryCameraFingerprint_WithCloudVendor_ReturnsCloudCamera(string vendor, ClientDeviceCategory expected) { // Arrange - history with camera fingerprint (DevCat 9) and cloud vendor via OUI @@ -1733,6 +1776,7 @@ public void DetectDeviceType_VendorWithCloudKeywordSubstring_DoesNotFalsePositiv [InlineData("SimpliSafe Inc")] [InlineData("TP-Link Technologies")] [InlineData("Canary Connect")] + [InlineData("Furbo Inc")] // Bare vendor names (word boundary should still match) [InlineData("Ring")] [InlineData("Nest")] @@ -1743,6 +1787,7 @@ public void DetectDeviceType_VendorWithCloudKeywordSubstring_DoesNotFalsePositiv [InlineData("SimpliSafe")] [InlineData("TP-Link")] [InlineData("Canary")] + [InlineData("Furbo")] public void DetectDeviceType_ActualCloudVendor_BecomesCloudCamera(string oui) { // Arrange - Actual cloud camera vendor OUI