From f9699d2d774c3b8e69871f11f50acc775082e303 Mon Sep 17 00:00:00 2001 From: ograce Date: Mon, 18 Mar 2019 09:56:24 +1100 Subject: [PATCH] Added new routes based on the resources provided. Refactored "get" requests to avoid repetition. --- devices.json | 312 ++++++++++++++++++++++++++++++++++++++++++++++ dpi.json | 90 +++++++++++++ requirements.txt | 1 + ubiquiti/unifi.py | 105 +++++++++++++--- 4 files changed, 489 insertions(+), 19 deletions(-) create mode 100644 devices.json create mode 100644 dpi.json create mode 100644 requirements.txt diff --git a/devices.json b/devices.json new file mode 100644 index 0000000..1cb5b63 --- /dev/null +++ b/devices.json @@ -0,0 +1,312 @@ +[ + { + "Device Code": "BZ2", + "Device Name": "UniFi AP", + "Device Type": "uap" + }, + { + "Device Code": "BZ2LR", + "Device Name": "UniFi AP-LR", + "Device Type": "uap" + }, + { + "Device Code": "U2HSR", + "Device Name": "UniFi AP-Outdoor+", + "Device Type": "uap" + }, + { + "Device Code": "U2IW", + "Device Name": "UniFi AP-In Wall", + "Device Type": "uap" + }, + { + "Device Code": "U2L48", + "Device Name": "UniFi AP-LR", + "Device Type": "uap" + }, + { + "Device Code": "U2Lv2", + "Device Name": "UniFi AP-LR v2", + "Device Type": "uap" + }, + { + "Device Code": "U2M", + "Device Name": "UniFi AP-Mini", + "Device Type": "uap" + }, + { + "Device Code": "U2O", + "Device Name": "UniFi AP-Outdoor", + "Device Type": "uap" + }, + { + "Device Code": "U2S48", + "Device Name": "UniFi AP", + "Device Type": "uap" + }, + { + "Device Code": "U2Sv2", + "Device Name": "UniFi AP v2", + "Device Type": "uap" + }, + { + "Device Code": "U5O", + "Device Name": "UniFi AP-Outdoor 5G", + "Device Type": "uap" + }, + { + "Device Code": "U7E", + "Device Name": "UniFi AP-AC", + "Device Type": "uap" + }, + { + "Device Code": "U7EDU", + "Device Name": "UniFi AP-AC-EDU", + "Device Type": "uap" + }, + { + "Device Code": "U7Ev2", + "Device Name": "UniFi AP-AC v2", + "Device Type": "uap" + }, + { + "Device Code": "U7HD", + "Device Name": "UniFi AP-HD", + "Device Type": "uap" + }, + { + "Device Code": "U7SHD", + "Device Name": "UniFi AP-SHD", + "Device Type": "uap" + }, + { + "Device Code": "U7NHD", + "Device Name": "UniFi AP-nanoHD", + "Device Type": "uap" + }, + { + "Device Code": "UCXG", + "Device Name": "UniFi AP-XG", + "Device Type": "uap" + }, + { + "Device Code": "UXSDM", + "Device Name": "UniFi AP-BaseStationXG", + "Device Type": "uap" + }, + { + "Device Code": "UCMSH", + "Device Name": "UniFi AP-MeshXG", + "Device Type": "uap" + }, + { + "Device Code": "U7IW", + "Device Name": "UniFi AP-AC-In Wall", + "Device Type": "uap" + }, + { + "Device Code": "U7IWP", + "Device Name": "UniFi AP-AC-In Wall Pro", + "Device Type": "uap" + }, + { + "Device Code": "U7MP", + "Device Name": "UniFi AP-AC-Mesh-Pro", + "Device Type": "uap" + }, + { + "Device Code": "U7LR", + "Device Name": "UniFi AP-AC-LR", + "Device Type": "uap" + }, + { + "Device Code": "U7LT", + "Device Name": "UniFi AP-AC-Lite", + "Device Type": "uap" + }, + { + "Device Code": "U7O", + "Device Name": "UniFi AP-AC Outdoor", + "Device Type": "uap" + }, + { + "Device Code": "U7P", + "Device Name": "UniFi AP-Pro", + "Device Type": "uap" + }, + { + "Device Code": "U7MSH", + "Device Name": "UniFi AP-AC-Mesh", + "Device Type": "uap" + }, + { + "Device Code": "U7PG2", + "Device Name": "UniFi AP-AC-Pro", + "Device Type": "uap" + }, + { + "Device Code": "p2N", + "Device Name": "PicoStation M2", + "Device Type": "uap" + }, + { + "Device Code": "US8", + "Device Name": "UniFi Switch 8", + "Device Type": "usw" + }, + { + "Device Code": "US8P60", + "Device Name": "UniFi Switch 8 POE-60W", + "Device Type": "usw" + }, + { + "Device Code": "US8P150", + "Device Name": "UniFi Switch 8 POE-150W", + "Device Type": "usw" + }, + { + "Device Code": "S28150", + "Device Name": "UniFi Switch 8 AT-150W", + "Device Type": "usw" + }, + { + "Device Code": "USC8", + "Device Name": "UniFi Switch 8", + "Device Type": "usw" + }, + { + "Device Code": "US16P150", + "Device Name": "UniFi Switch 16 POE-150W", + "Device Type": "usw" + }, + { + "Device Code": "S216150", + "Device Name": "UniFi Switch 16 AT-150W", + "Device Type": "usw" + }, + { + "Device Code": "US24", + "Device Name": "UniFi Switch 24", + "Device Type": "usw" + }, + { + "Device Code": "US24P250", + "Device Name": "UniFi Switch 24 POE-250W", + "Device Type": "usw" + }, + { + "Device Code": "US24PL2", + "Device Name": "UniFi Switch 24 L2 POE", + "Device Type": "usw" + }, + { + "Device Code": "US24P500", + "Device Name": "UniFi Switch 24 POE-500W", + "Device Type": "usw" + }, + { + "Device Code": "S224250", + "Device Name": "UniFi Switch 24 AT-250W", + "Device Type": "usw" + }, + { + "Device Code": "S224500", + "Device Name": "UniFi Switch 24 AT-500W", + "Device Type": "usw" + }, + { + "Device Code": "US48", + "Device Name": "UniFi Switch 48", + "Device Type": "usw" + }, + { + "Device Code": "US48P500", + "Device Name": "UniFi Switch 48 POE-500W", + "Device Type": "usw" + }, + { + "Device Code": "US48PL2", + "Device Name": "UniFi Switch 48 L2 POE", + "Device Type": "usw" + }, + { + "Device Code": "US48P750", + "Device Name": "UniFi Switch 48 POE-750W", + "Device Type": "usw" + }, + { + "Device Code": "S248500", + "Device Name": "UniFi Switch 48 AT-500W", + "Device Type": "usw" + }, + { + "Device Code": "S248750", + "Device Name": "UniFi Switch 48 AT-750W", + "Device Type": "usw" + }, + { + "Device Code": "US6XG150", + "Device Name": "UniFi Switch 6XG POE-150W", + "Device Type": "usw" + }, + { + "Device Code": "USXG", + "Device Name": "UniFi Switch 16XG", + "Device Type": "usw" + }, + { + "Device Code": "UGW3", + "Device Name": "UniFi Security Gateway 3P", + "Device Type": "ugw" + }, + { + "Device Code": "UGW4", + "Device Name": "UniFi Security Gateway 4P", + "Device Type": "ugw" + }, + { + "Device Code": "UGWHD4", + "Device Name": "UniFi Security Gateway HD", + "Device Type": "ugw" + }, + { + "Device Code": "UGWXG", + "Device Name": "UniFi Security Gateway XG-8", + "Device Type": "ugw" + }, + { + "Device Code": "UP4", + "Device Name": "UniFi Phone-X", + "Device Type": "uph" + }, + { + "Device Code": "UP5", + "Device Name": "UniFi Phone", + "Device Type": "uph" + }, + { + "Device Code": "UP5t", + "Device Name": "UniFi Phone-Pro", + "Device Type": "uph" + }, + { + "Device Code": "UP7", + "Device Name": "UniFi Phone-Executive", + "Device Type": "uph" + }, + { + "Device Code": "UP5c", + "Device Name": "UniFi Phone", + "Device Type": "uph" + }, + { + "Device Code": "UP5tc", + "Device Name": "UniFi Phone-Pro", + "Device Type": "uph" + }, + { + "Device Code": "UP7c", + "Device Name": "UniFi Phone-Executive", + "Device Type": "uph" + } +] \ No newline at end of file diff --git a/dpi.json b/dpi.json new file mode 100644 index 0000000..4d4ba75 --- /dev/null +++ b/dpi.json @@ -0,0 +1,90 @@ +[ + { + "DPI Category Code": 0, + "Name": "Instant messaging" + }, + { + "DPI Category Code": 1, + "Name": "P2P" + }, + { + "DPI Category Code": 3, + "Name": "File Transfer" + }, + { + "DPI Category Code": 4, + "Name": "Streaming Media" + }, + { + "DPI Category Code": 5, + "Name": "Mail and Collaboration" + }, + { + "DPI Category Code": 6, + "Name": "Voice over IP" + }, + { + "DPI Category Code": 7, + "Name": "Database" + }, + { + "DPI Category Code": 8, + "Name": "Games" + }, + { + "DPI Category Code": 9, + "Name": "Network Management" + }, + { + "DPI Category Code": 10, + "Name": "Remote Access Terminals" + }, + { + "DPI Category Code": 11, + "Name": "Bypass Proxies and Tunnels" + }, + { + "DPI Category Code": 12, + "Name": "Stock Market" + }, + { + "DPI Category Code": 13, + "Name": "Web" + }, + { + "DPI Category Code": 14, + "Name": "Security Update" + }, + { + "DPI Category Code": 15, + "Name": "Web IM" + }, + { + "DPI Category Code": 17, + "Name": "Business" + }, + { + "DPI Category Code": 18, + "Name": "Network Protocols" + }, + { + "DPI Category Code": 19, + "Name": "Network Protocols" + }, + { + "DPI Category Code": 20, + "Name": "Network Protocols" + }, + { + "DPI Category Code": 23, + "Name": "Private Protocol" + }, + { + "DPI Category Code": 24, + "Name": "Social Network" + }, + { + "DPI Category Code": 255, + "Name": "Unknown" + } +] \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..663bd1f --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +requests \ No newline at end of file diff --git a/ubiquiti/unifi.py b/ubiquiti/unifi.py index 788c445..5b41885 100644 --- a/ubiquiti/unifi.py +++ b/ubiquiti/unifi.py @@ -1,8 +1,10 @@ -from requests import Session import json import re +import warnings from typing import Pattern, Dict, Union +from requests import Session + class LoggedInException(Exception): @@ -18,15 +20,23 @@ class API(object): _login_data = {} _current_status_code = None - def __init__(self, username: str="ubnt", password: str="ubnt", site: str="default", baseurl: str="https://unifi:8443", verify_ssl: bool=True): + def __init__(self, + username: str="ubnt", + password: str="ubnt", + site: str="default", + baseurl: str="https://unifi:8443", + verify_ssl: bool=True): """ - Initiates tha api with default settings if none other are set. + Initiates the api with default settings if none other are set. + Based off https://ubntwiki.com/products/software/unifi-controller/api :param username: username for the controller user :param password: password for the controller user - :param site: which site to connect to (Not the name you've given the site, but the url-defined name) + :param site: which site to connect to (Not the name you've given the + site, but the url-defined name) :param baseurl: where the controller is located - :param verify_ssl: Check if certificate is valid or not, throws warning if set to False + :param verify_ssl: Check if certificate is valid or not, throws warning + if set to False """ self._login_data['username'] = username self._login_data['password'] = password @@ -34,6 +44,7 @@ def __init__(self, username: str="ubnt", password: str="ubnt", site: str="defaul self._verify_ssl = verify_ssl self._baseurl = baseurl self._session = Session() + self._session.verify = self._verify_ssl def __enter__(self): """ @@ -58,9 +69,12 @@ def login(self): :return: None """ - self._current_status_code = self._session.post("{}/api/login".format(self._baseurl), data=json.dumps(self._login_data), verify=self._verify_ssl).status_code - if self._current_status_code == 400: - raise LoggedInException("Failed to log in to api with provided credentials") + url = "{}/api/login".format(self._baseurl) + with self._session as s: + r = s.post(url, data=json.dumps(self._login_data)) + if r.status_code == 400: + raise LoggedInException("Failed to log in to api with provided " + "credentials") def logout(self): """ @@ -71,30 +85,83 @@ def logout(self): self._session.get("{}/logout".format(self._baseurl)) self._session.close() - def list_clients(self, filters: Dict[str, Union[str, Pattern]]=None, order_by: str=None) -> list: + def _get(self, url): + with self._session as s: + r = s.get(url, data="json={}") + status_code = r.status_code + if status_code == 401: + raise LoggedInException("Invalid login, or login has expired") + if status_code != 200: + warnings.warn('Status code of {} received for {}'.format( + status_code, url + )) + return r.json()['data'] + + def list_clients(self, + filters: Dict[str, Union[str, Pattern]]=None, + order_by: str=None) -> list: """ List all available clients from the api - :param filters: dict with valid key, value pairs, string supplied is compiled to a regular expression - :param order_by: order by a valid client key, defaults to '_id' if key is not found + :param filters: dict with valid key, value pairs, string supplied is + compiled to a regular expression + :param order_by: order by a valid client key, defaults to '_id' if key + is not found :return: A list of clients on the format of a dict """ - r = self._session.get("{}/api/s/{}/stat/sta".format(self._baseurl, self._site, verify=self._verify_ssl), data="json={}") - self._current_status_code = r.status_code - - if self._current_status_code == 401: - raise LoggedInException("Invalid login, or login has expired") - - data = r.json()['data'] + url = "{}/api/s/{}/stat/sta".format(self._baseurl, self._site) + data = self._get(url) if filters: for term, value in filters.items(): value_re = value if isinstance(value, Pattern) else re.compile(value) - data = [x for x in data if term in x.keys() and re.fullmatch(value_re, x[term])] + data = [x for x in data if term in x.keys() and + re.fullmatch(value_re, x[term])] if order_by: data = sorted(data, key=lambda x: x[order_by] if order_by in x.keys() else x['_id']) return data + + def all_configured_clients(self) -> list: + """ + List of all configured/known clients on the site. Differs from the above + as it includes + + :return: list of clients known (dicts) + """ + url = '{}/api/s/{}/rest/user'.format(self._baseurl, self._site) + return self._get(url) + + def get_devices(self) -> list: + """ + List of site devices + + :return: list of devices on site + """ + url = '{}/api/s/{}/stat/device'.format(self._baseurl, self._site) + return self._get(url) + + def get_routes(self) -> list: + """ + All active routes on the device + + :return: list of routes on site + """ + url = '{}/api/s/{}/stat/routing'.format(self._baseurl, self._site) + return self._get(url) + + def get_port_forwarding(self) -> list: + """ + List of routes for site + + :return: list of routes on site + """ + url = '{}/api/s/{}/rest/portforward'.format(self._baseurl, self._site) + return self._get(url) + + +if __name__ == '__main__': + pass \ No newline at end of file