diff --git a/README.md b/README.md index bf22ca9..6081995 100755 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ There, you will also find examples and detailed instructions on how to use it. Please keep the following in mind when using the UniFi API browser: - The tool does not support all available data collections and API endpoints. See the list below for those currently supported. -- Currently, versions 5.X.X, 6.X.X, 7.X.X, and 8.X.X of the UniFi Controller software are supported (version **8.4.60** has been confirmed to work) +- Currently, versions 5.X.X, 6.X.X, 7.X.X, and 8.X.X of the UniFi Controller software are supported (version **8.5.60** has been confirmed to work) - The Network Application on UniFi OS-based controllers is also supported, same versions as above - When accessing UniFi OS-based controllers through this tool, please read the remarks regarding UniFi OS support - Please read the Security Notice before installing this tool. @@ -99,6 +99,7 @@ The UniFi API browser tool offers the following features: - list alarms - count alarms - list IDS/IPS events + - list system log entries Please note that the bundled API client supports many more API endpoints, not all make sense to add to the API browser though. diff --git a/ajax/fetch_collection.php b/ajax/fetch_collection.php index f0ac6c9..452e1e2 100755 --- a/ajax/fetch_collection.php +++ b/ajax/fetch_collection.php @@ -13,6 +13,8 @@ require_once '../common.php'; require_once '../collections.php'; +use Kint\Renderer\TextRenderer; +use Kint\Renderer\RichRenderer; use UniFi_API\Client as ApiClient; /** @@ -163,6 +165,13 @@ */ $results['count'] = count($data_array); + /** + * For results returned from API v2, we need to check for the 'data' property and count that. + */ + if(property_exists($data_array, 'data')) { + $results['count'] = count($data_array->data); + } + if ($debug) { error_log('DEBUG: ' . $results['count'] . ' objects collected'); } @@ -173,18 +182,18 @@ * * @note using Rich render mode */ - Kint::$display_called_from = false; - Kint\Renderer\RichRenderer::$folder = false; - $results['data'] = @d($data_array); + Kint::$display_called_from = false; + RichRenderer::$folder = false; + $results['data'] = @d($data_array); } else { if ($output_method === 'kint_plain') { /** * @note using Plain render mode */ - Kint::$display_called_from = false; - Kint\Renderer\RichRenderer::$folder = false; - Kint\Renderer\TextRenderer::$decorations = false; - $results['data'] = @s($data_array); + Kint::$display_called_from = false; + RichRenderer::$folder = false; + TextRenderer::$decorations = false; + $results['data'] = @s($data_array); } else { $results['data'] = $data_array; } diff --git a/collections.php b/collections.php index de37a82..4dcefa7 100755 --- a/collections.php +++ b/collections.php @@ -10,7 +10,7 @@ * this array defines the menu options for the various collections * * NOTES: - * - do not modify this file, instead add a custom sub menu to the config.php file as explained in the README.md file + * - do not modify this file, instead add a custom submenu to the config.php file as explained in the README.md file * - a valid value for params looks like this: * [true, true, 'no'] (note the quotes surrounding strings) */ @@ -485,6 +485,57 @@ 'method' => 'stat_ips_events', 'params' => [], ], + [ + 'type' => 'divider', // or collection + ], + [ + 'type' => 'collection', // or divider + 'label' => 'system log: device alerts', + 'method' => 'get_system_log', + 'params' => ['device-alert'], + ], + [ + 'type' => 'collection', // or divider + 'label' => 'system log: critical alerts', + 'method' => 'get_system_log', + 'params' => ['next-ai-alert'], + ], + [ + 'type' => 'collection', // or divider + 'label' => 'system log: VPN alerts', + 'method' => 'get_system_log', + 'params' => ['vpn-alert'], + ], + [ + 'type' => 'collection', // or divider + 'label' => 'system log: admin activity', + 'method' => 'get_system_log', + 'params' => ['admin-activity'], + ], + [ + 'type' => 'collection', // or divider + 'label' => 'system log: update alerts', + 'method' => 'get_system_log', + 'params' => ['update-alert'], + ], + [ + 'type' => 'collection', // or divider + 'label' => 'system log: client alerts', + 'method' => 'get_system_log', + 'params' => ['client-alert'], + ], + [ + 'type' => 'collection', // or divider + 'label' => 'system log: threat alerts', + 'method' => 'get_system_log', + 'params' => ['threat-alert'], + ], + [ + 'type' => 'collection', // or divider + 'label' => 'system log: triggers', + 'method' => 'get_system_log', + 'params' => ['triggers'], + ], ], ], ]; diff --git a/common.php b/common.php index ea84212..ae654cf 100755 --- a/common.php +++ b/common.php @@ -10,7 +10,7 @@ use UniFi_API\Client as ApiClient; -const TOOL_VERSION = '2.0.29'; +const TOOL_VERSION = '2.0.30'; /** * Gather some basic information for the About modal. diff --git a/composer.lock b/composer.lock index 3655532..f81afb7 100755 --- a/composer.lock +++ b/composer.lock @@ -8,16 +8,16 @@ "packages": [ { "name": "art-of-wifi/unifi-api-client", - "version": "v1.1.97", + "version": "v1.1.99", "source": { "type": "git", "url": "https://github.com/Art-of-WiFi/UniFi-API-client.git", - "reference": "6498b0255b0963ad914076ddda7f74df4fd2eb73" + "reference": "70f6a374e2c73eb91a9aa20f6c9375b235d55ce1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Art-of-WiFi/UniFi-API-client/zipball/6498b0255b0963ad914076ddda7f74df4fd2eb73", - "reference": "6498b0255b0963ad914076ddda7f74df4fd2eb73", + "url": "https://api.github.com/repos/Art-of-WiFi/UniFi-API-client/zipball/70f6a374e2c73eb91a9aa20f6c9375b235d55ce1", + "reference": "70f6a374e2c73eb91a9aa20f6c9375b235d55ce1", "shasum": "" }, "require": { @@ -54,9 +54,9 @@ ], "support": { "issues": "https://github.com/Art-of-WiFi/UniFi-API-client/issues", - "source": "https://github.com/Art-of-WiFi/UniFi-API-client/tree/v1.1.97" + "source": "https://github.com/Art-of-WiFi/UniFi-API-client/tree/v1.1.99" }, - "time": "2024-10-17T12:56:47+00:00" + "time": "2024-10-23T11:30:34+00:00" }, { "name": "kint-php/kint", diff --git a/vendor/art-of-wifi/unifi-api-client/src/Client.php b/vendor/art-of-wifi/unifi-api-client/src/Client.php index 72af179..ad3f76e 100755 --- a/vendor/art-of-wifi/unifi-api-client/src/Client.php +++ b/vendor/art-of-wifi/unifi-api-client/src/Client.php @@ -20,7 +20,7 @@ class Client { /** Constants. */ - const CLASS_VERSION = '1.1.96'; + const CLASS_VERSION = '1.1.99'; const CURL_METHODS_ALLOWED = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH']; const DEFAULT_CURL_METHOD = 'GET'; @@ -677,7 +677,7 @@ public function stat_monthly_aps(int $start = null, int $end = null, string $mac } /** - * Fetch 5-minutes stats for a single user/client device. + * Fetch 5-minutes stats for a single user/client device or all user/client devices. * * @note - defaults to the past 12 hours * - only supported with UniFi controller versions 5.8.X and higher @@ -685,16 +685,16 @@ public function stat_monthly_aps(int $start = null, int $end = null, string $mac * the controller settings * - make sure that "Clients Historical Data" has been enabled in the UniFi controller settings in the Maintenance * section - * @param string $mac MAC address of the user/client device to return stats for + * @param string|null $mac optional, MAC address of the user/client device to return stats for * @param int|null $start optional, Unix timestamp in milliseconds * @param int|null $end optional, Unix timestamp in milliseconds * @param array|null $attribs array containing attributes (strings) to be returned, valid values are: * rx_bytes, tx_bytes, signal, rx_rate, tx_rate, rx_retries, tx_retries, rx_packets, - * tx_packets, satisfaction, wifi_tx_attempts - * default value is ['rx_bytes', 'tx_bytes'] + * tx_packets, satisfaction, wifi_tx_attempts, 'duration' + * default value is ['rx_bytes', 'tx_bytes', 'time'] * @return array|bool returns an array of 5-minute stats objects */ - public function stat_5minutes_user(string $mac, int $start = null, int $end = null, array $attribs = null) + public function stat_5minutes_user(string $mac = null, int $start = null, int $end = null, array $attribs = null) { $end = empty($end) ? time() * 1000 : $end; $start = empty($start) ? $end - (12 * 3600 * 1000) : $start; @@ -705,7 +705,7 @@ public function stat_5minutes_user(string $mac, int $start = null, int $end = nu } /** - * Fetch hourly stats for a single user/client device. + * Fetch hourly stats for a single user/client device or all user/client devices. * * @note - defaults to the past 7*24 hours * - only supported with UniFi controller versions 5.8.X and higher @@ -714,24 +714,28 @@ public function stat_5minutes_user(string $mac, int $start = null, int $end = nu * - make sure that "Clients Historical Data" has been enabled in the UniFi controller settings in the Maintenance * section * @see stat_5minutes_user() for details on attribs - * @param string $mac MAC address of the user/client device to return stats fo + * @param string|null $mac optional, MAC address of the user/client device to return stats for * @param int|null $start optional, Unix timestamp in milliseconds * @param int|null $end optional, Unix timestamp in milliseconds * @param array|null $attribs array containing attributes (strings) to be returned * @return array|bool returns an array of hourly stats objects */ - public function stat_hourly_user(string $mac, int $start = null, int $end = null, array $attribs = null) + public function stat_hourly_user(string $mac = null, int $start = null, int $end = null, array $attribs = null) { $end = empty($end) ? time() * 1000 : $end; $start = empty($start) ? $end - (7 * 24 * 3600 * 1000) : $start; $attribs = empty($attribs) ? ['time', 'rx_bytes', 'tx_bytes'] : array_merge(['time'], $attribs); - $payload = ['attrs' => $attribs, 'start' => $start, 'end' => $end, 'mac' => strtolower($mac)]; + $payload = ['attrs' => $attribs, 'start' => $start, 'end' => $end]; + + if (!empty($mac)) { + $payload['mac'] = strtolower($mac); + } return $this->fetch_results('/api/s/' . $this->site . '/stat/report/hourly.user', $payload); } /** - * Fetch daily stats for a single user/client device. + * Fetch daily stats for a single user/client device or all user/client devices. * * @note - defaults to the past 7*24 hours * - only supported with UniFi controller versions 5.8.X and higher @@ -740,24 +744,28 @@ public function stat_hourly_user(string $mac, int $start = null, int $end = null * - make sure that "Clients Historical Data" has been enabled in the UniFi controller settings in the Maintenance * section * @see stat_5minutes_user() for details on attribs - * @param string $mac MAC address of the user/client device to return stats for + * @param string|null $mac optional, MAC address of the user/client device to return stats for * @param int|null $start optional, Unix timestamp in milliseconds * @param int|null $end optional, Unix timestamp in milliseconds * @param array|null $attribs array containing attributes (strings) to be returned * @return array|bool returns an array of daily stats objects */ - public function stat_daily_user(string $mac, int $start = null, int $end = null, array $attribs = null) + public function stat_daily_user(string $mac = null, int $start = null, int $end = null, array $attribs = null) { $end = empty($end) ? time() * 1000 : $end; $start = empty($start) ? $end - (7 * 24 * 3600 * 1000) : $start; $attribs = empty($attribs) ? ['time', 'rx_bytes', 'tx_bytes'] : array_merge(['time'], $attribs); - $payload = ['attrs' => $attribs, 'start' => $start, 'end' => $end, 'mac' => strtolower($mac)]; + $payload = ['attrs' => $attribs, 'start' => $start, 'end' => $end]; + + if (!empty($mac)) { + $payload['mac'] = strtolower($mac); + } return $this->fetch_results('/api/s/' . $this->site . '/stat/report/daily.user', $payload); } /** - * Fetch monthly stats for a single user/client device. + * Fetch monthly stats for a single user/client device or all user/client devices. * * @note - defaults to the past 13 weeks (52*7*24 hours) * - only supported with UniFi controller versions 5.8.X and higher @@ -765,19 +773,23 @@ public function stat_daily_user(string $mac, int $start = null, int $end = null, * the controller settings * - make sure that "Clients Historical Data" has been enabled in the UniFi controller settings in the Maintenance * section - * @see stat_5minutes_user() for details on attribs - * @param string $mac MAC address of the user/client device to return stats for + * @param string|null $mac optional, MAC address of the user/client device to return stats for * @param int|null $start optional, Unix timestamp in milliseconds * @param int|null $end optional, Unix timestamp in milliseconds * @param array|null $attribs array containing attributes (strings) to be returned * @return array|bool returns an array of monthly stats objects + * @see stat_5minutes_user() for details on attribs */ - public function stat_monthly_user(string $mac, int $start = null, int $end = null, array $attribs = null) + public function stat_monthly_user(string $mac = null, int $start = null, int $end = null, array $attribs = null) { $end = empty($end) ? time() * 1000 : $end; $start = empty($start) ? $end - (13 * 7 * 24 * 3600 * 1000) : $start; $attribs = empty($attribs) ? ['time', 'rx_bytes', 'tx_bytes'] : array_merge(['time'], $attribs); - $payload = ['attrs' => $attribs, 'start' => $start, 'end' => $end, 'mac' => strtolower($mac)]; + $payload = ['attrs' => $attribs, 'start' => $start, 'end' => $end]; + + if (!empty($mac)) { + $payload['mac'] = strtolower($mac); + } return $this->fetch_results('/api/s/' . $this->site . '/stat/report/monthly.user', $payload); } @@ -3107,13 +3119,14 @@ public function upgrade_device_external(string $firmware_url, $macs): bool /** * Start rolling upgrade. * - * @note updates all UniFi devices to the latest firmware known to the controller in a + * @note upgrades all UniFi devices to the latest firmware known to the controller in a * staggered/rolling fashion + * @param array $payload optional, array of device types to upgrade, default is all device types * @return bool true upon success */ - public function start_rolling_upgrade(): bool + public function start_rolling_upgrade(array $payload = ['uap', 'usw', 'ugw', 'uxg']): bool { - return $this->fetch_results_boolean('/api/s/' . $this->site . '/cmd/devmgr/set-rollupgrade', ['uap', 'usw', 'ugw']); + return $this->fetch_results_boolean('/api/s/' . $this->site . '/cmd/devmgr/set-rollupgrade', $payload); } /** @@ -3364,6 +3377,63 @@ public function set_element_adoption(bool $enable): bool return $this->fetch_results_boolean('/api/s/' . $this->site . '/set/setting/element_adopt', $payload); } + /** + * Fetch system log entries. + * + * @note - defaults to the past 7*24 hours + * - results are paged; use $page_number to iterate over pages and $page_size to set page size + * @param string $class optional, class of the system log entries to fetch, known valid values: + * 'device-alert', 'next-ai-alert', 'vpn-alert', 'admin-activity', 'update-alert', + * 'client-alert', 'threat-alert', 'triggers', default value is 'device-alert' + * @param ?int $start optional, start time in milliseconds since the Unix epoch + * @param ?int $end optional, end time in milliseconds since the Unix epoch + * @param int $page_number optional, page number to fetch, default value is 0 (first page) + * @param int $page_size optional, number of entries to fetch per page, default value is 100 + * @param array $custom_payload optional, an array of additional parameters to pass with the request. Is merged + * with the default payload array constructed by this method using array_merge(). + * @return array|bool array containing results from the selected system log section/class, false on error. + * The 'data' key in the returned array contains the actual system log entries. + * The returned array also contains the page number and size, and the total number of entries + * available. + */ + public function get_system_log(string $class = 'device-alert', int $start = null, int $end = null, int $page_number = 0, int $page_size = 100, array $custom_payload = []) + { + $end = empty($end) ? time() * 1000 : $end; + $start = empty($start) ? $end - (7 * 24 * 3600 * 1000) : $start; + + $payload = [ + 'pageNumber' => $page_number, + 'pageSize' => $page_size, + 'timestampFrom' => $start, + 'timestampTo' => $end, + ]; + + switch ($class) { + case 'next-ai-alert': + $payload['nextAiCategory'] = ['CLIENT', 'DEVICE', 'INTERNET', 'VPN']; + break; + case 'admin-activity': + $payload['activity_keys'] = ['ACCESSED_NETWORK_WEB', 'ACCESSED_NETWORK_IOS', 'ACCESSED_NETWORK_ANDROID']; + $payload['change_keys'] = ['CLIENT', 'DEVICE', 'HOTSPOT', 'INTERNET', 'NETWORK', 'PROFILE', 'ROUTING', 'SECURITY', 'SYSTEM', 'VPN', 'WIFI']; + break; + case 'update-alert': + $payload['systemLogDeviceTypes'] = ['GATEWAYS', 'SWITCHES', 'ACCESS_POINT', 'SMART_POWER', 'BUILDING_TO_BUILDING_BRIDGES', 'UNIFI_LTE']; + break; + case 'client-alert': + $payload['clientType'] = ['GUEST', 'TELEPORT', 'VPN', 'WIRELESS', 'RADIUS', 'WIRED']; + $payload['guestAuthorizationMethod'] = ['FACEBOOK_SOCIAL_GATEWAY', 'FREE_TRIAL', 'GOOGLE_SOCIAL_GATEWAY', 'NONE', 'PASSWORD', 'PAYMENT', 'RADIUS', 'VOUCHER']; + break; + case 'threat-alert': + $payload['threatTypes'] = ['HONEYPOT', 'THREAT']; + break; + case 'triggers': + $payload['triggerTypes'] = ['TRAFFIC_RULE', 'TRAFFIC_ROUTE', 'FIREWALL_RULE']; + break; + } + + return $this->fetch_results('/v2/api/site/' . $this->site . '/system-log/' . $class, array_merge($payload, $custom_payload)); + } + /** * List device states * @@ -3953,38 +4023,30 @@ protected function catch_json_last_error(): bool return true; case JSON_ERROR_DEPTH: $error = 'The maximum stack depth has been exceeded'; - break; case JSON_ERROR_STATE_MISMATCH: $error = 'Invalid or malformed JSON'; - break; case JSON_ERROR_CTRL_CHAR: $error = 'Control character error, possibly incorrectly encoded'; - break; case JSON_ERROR_SYNTAX: $error = 'Syntax error, malformed JSON'; - break; case JSON_ERROR_UTF8: /** PHP >= 5.3.3 */ $error = 'Malformed UTF-8 characters, possibly incorrectly encoded'; - break; case JSON_ERROR_RECURSION: /** PHP >= 5.5.0 */ $error = 'One or more recursive references in the value to be encoded'; - break; case JSON_ERROR_INF_OR_NAN: /** PHP >= 5.5.0 */ $error = 'One or more NAN or INF values in the value to be encoded'; - break; case JSON_ERROR_UNSUPPORTED_TYPE: $error = 'A value of a type that cannot be encoded was given'; - break; } @@ -3993,11 +4055,9 @@ protected function catch_json_last_error(): bool switch (json_last_error()) { case JSON_ERROR_INVALID_PROPERTY_NAME: $error = 'A property name that cannot be encoded was given'; - break; case JSON_ERROR_UTF16: $error = 'Malformed UTF-16 characters, possibly incorrectly encoded'; - break; } } @@ -4115,7 +4175,6 @@ protected function response_header_callback($ch, string $header_line): int $this->cookies = $cookie_crumb; $this->is_logged_in = true; $this->is_unifi_os = false; - break; } @@ -4123,7 +4182,6 @@ protected function response_header_callback($ch, string $header_line): int $this->cookies = $cookie_crumb; $this->is_logged_in = true; $this->is_unifi_os = true; - break; } } diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 25135a5..75bcb3e 100755 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -2,17 +2,17 @@ "packages": [ { "name": "art-of-wifi/unifi-api-client", - "version": "v1.1.97", - "version_normalized": "1.1.97.0", + "version": "v1.1.99", + "version_normalized": "1.1.99.0", "source": { "type": "git", "url": "https://github.com/Art-of-WiFi/UniFi-API-client.git", - "reference": "6498b0255b0963ad914076ddda7f74df4fd2eb73" + "reference": "70f6a374e2c73eb91a9aa20f6c9375b235d55ce1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Art-of-WiFi/UniFi-API-client/zipball/6498b0255b0963ad914076ddda7f74df4fd2eb73", - "reference": "6498b0255b0963ad914076ddda7f74df4fd2eb73", + "url": "https://api.github.com/repos/Art-of-WiFi/UniFi-API-client/zipball/70f6a374e2c73eb91a9aa20f6c9375b235d55ce1", + "reference": "70f6a374e2c73eb91a9aa20f6c9375b235d55ce1", "shasum": "" }, "require": { @@ -20,7 +20,7 @@ "ext-json": "*", "php": ">=7.4.0" }, - "time": "2024-10-17T12:56:47+00:00", + "time": "2024-10-23T11:30:34+00:00", "type": "library", "installation-source": "source", "autoload": { @@ -51,7 +51,7 @@ ], "support": { "issues": "https://github.com/Art-of-WiFi/UniFi-API-client/issues", - "source": "https://github.com/Art-of-WiFi/UniFi-API-client/tree/v1.1.97" + "source": "https://github.com/Art-of-WiFi/UniFi-API-client/tree/v1.1.99" }, "install-path": "../art-of-wifi/unifi-api-client" }, diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index 21b9c27..5d96265 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -3,7 +3,7 @@ 'name' => '__root__', 'pretty_version' => 'dev-master', 'version' => 'dev-master', - 'reference' => '3bb0801a23ac0ce6861bfb24571f2418ee07b61c', + 'reference' => '2aa4eacd2a3939191239784be9a1f9a622eb5db1', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -13,16 +13,16 @@ '__root__' => array( 'pretty_version' => 'dev-master', 'version' => 'dev-master', - 'reference' => '3bb0801a23ac0ce6861bfb24571f2418ee07b61c', + 'reference' => '2aa4eacd2a3939191239784be9a1f9a622eb5db1', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev_requirement' => false, ), 'art-of-wifi/unifi-api-client' => array( - 'pretty_version' => 'v1.1.97', - 'version' => '1.1.97.0', - 'reference' => '6498b0255b0963ad914076ddda7f74df4fd2eb73', + 'pretty_version' => 'v1.1.99', + 'version' => '1.1.99.0', + 'reference' => '70f6a374e2c73eb91a9aa20f6c9375b235d55ce1', 'type' => 'library', 'install_path' => __DIR__ . '/../art-of-wifi/unifi-api-client', 'aliases' => array(),