New ejabberd API endpoint (check_account) and added api_request helper

This commit is contained in:
spla 2022-08-09 21:55:05 +02:00
pare 79e7f6fc4a
commit 7170f6592d
S'han modificat 3 arxius amb 159 adicions i 23 eliminacions

Veure arxiu

@ -255,6 +255,7 @@ class Akkomabot:
self.node_users_str = self.__get_parameter("node_users_str", lang_file_path) self.node_users_str = self.__get_parameter("node_users_str", lang_file_path)
self.uptime_str = self.__get_parameter("uptime_str", lang_file_path) self.uptime_str = self.__get_parameter("uptime_str", lang_file_path)
self.processes_str = self.__get_parameter("processes_str", lang_file_path) self.processes_str = self.__get_parameter("processes_str", lang_file_path)
self.account_exists_str = self.__get_parameter("account_exists_str", lang_file_path)
@staticmethod @staticmethod
def __modify_file(self, file_name, pattern,value=""): def __modify_file(self, file_name, pattern,value=""):

Veure arxiu

@ -58,16 +58,34 @@ class Ejabberd:
return password return password
def check_account(self, username, host):
data = {'user':username,
'host':self.__local_vhost,
}
endpoint = self.__api_base_url + '/api/check_account?'
response = self.__api_request(endpoint, data)
account_exists = True if response.json() == 0 else False
return account_exists
def register(self, username, host, user_password): def register(self, username, host, user_password):
account_exists = self.account_exists(username, host)
if not account_exists:
data = {'user':username, data = {'user':username,
'host':self.__local_vhost, 'host':self.__local_vhost,
'password':user_password, 'password':user_password,
} }
API_ENDPOINT = self.__api_base_url + '/api/register?' endpoint = self.__api_base_url + '/api/register?'
response = requests.post(url = API_ENDPOINT, json = data, auth=(self.__admin_account, self.__admin_pass)) response = self.__api_request(endpoint, data)
is_registered = response.ok is_registered = response.ok
@ -79,6 +97,12 @@ class Ejabberd:
response_text = f"{response.json()['status']}: {response.json()['message']}" response_text = f"{response.json()['status']}: {response.json()['message']}"
else:
is_registered = False
response_text = f"el compte {username}@{host} ja existeix!"
return (is_registered, response_text) return (is_registered, response_text)
def unregister(self, username, host): def unregister(self, username, host):
@ -97,9 +121,9 @@ class Ejabberd:
'host':self.__local_vhost, 'host':self.__local_vhost,
} }
API_ENDPOINT = self.__api_base_url + '/api/unregister?' endpoint = self.__api_base_url + '/api/unregister?'
response = requests.post(url = API_ENDPOINT, json = data, auth=(self.__admin_account, self.__admin_pass)) response = self.__api_request(endpoint, data)
is_unregistered = response.ok is_unregistered = response.ok
@ -119,9 +143,9 @@ class Ejabberd:
"name": name "name": name
} }
API_ENDPOINT = self.__api_base_url + '/api/stats?' endpoint = self.__api_base_url + '/api/stats?'
response = requests.post(url = API_ENDPOINT, json = data, auth=(self.__admin_account, self.__admin_pass)) response = self.__api_request(endpoint, data)
result = response.json()['stat'] result = response.json()['stat']
@ -136,14 +160,73 @@ class Ejabberd:
data = { data = {
} }
API_ENDPOINT = self.__api_base_url + '/api/status?' endpoint = self.__api_base_url + '/api/status?'
response = requests.post(url = API_ENDPOINT, json = data, auth=(self.__admin_account, self.__admin_pass)) response = self.__api_request(endpoint, data)
result = response.json() result = response.json()
return result return result
def __api_request(self, endpoint, data):
try:
response = requests.post(url = endpoint, json = data, auth=(self._Ejabberd__admin_account, self._Ejabberd__admin_pass))
except Exception as e:
raise EjabberdNetworkError(f"Could not complete request: {e}")
if response is None:
raise EjabberdIllegalArgumentError("Illegal request.")
if not response.ok:
try:
if isinstance(response, dict) and 'error' in response:
error_msg = response['error']
elif isinstance(response, str):
error_msg = response
else:
error_msg = None
except ValueError:
error_msg = None
if response.status_code == 404:
ex_type = EjabberdNotFoundError
if not error_msg:
error_msg = 'Endpoint not found.'
# this is for compatibility with older versions
# which raised EjabberdAPIError('Endpoint not found.')
# on any 404
elif response.status_code == 401:
ex_type = EjabberdUnauthorizedError
elif response.status_code == 500:
ex_type = EjabberdInternalServerError
elif response.status_code == 502:
ex_type = EjabberdBadGatewayError
elif response.status_code == 503:
ex_type = EjabberdServiceUnavailableError
elif response.status_code == 504:
ex_type = EjabberdGatewayTimeoutError
elif response.status_code >= 500 and \
response.status_code <= 511:
ex_type = EjabberdServerError
else:
ex_type = EjabberdAPIError
raise ex_type(
'Ejabberd API returned error',
response.status_code,
response.reason,
error_msg)
else:
return response
@staticmethod @staticmethod
def __check_setup(self): def __check_setup(self):
@ -197,3 +280,47 @@ class Ejabberd:
if isinstance(json_object, dict): if isinstance(json_object, dict):
return AttribAccessDict(json_object) return AttribAccessDict(json_object)
return json_object return json_object
##
# Exceptions
##
class EjabberdError(Exception):
"""Base class for Mastodon.py exceptions"""
class EjabberdIOError(IOError, EjabberdError):
"""Base class for Mastodon.py I/O errors"""
class EjabberdNetworkError(EjabberdIOError):
"""Raised when network communication with the server fails"""
pass
class EjabberdAPIError(EjabberdError):
"""Raised when the mastodon API generates a response that cannot be handled"""
pass
class EjabberdServerError(EjabberdAPIError):
"""Raised if the Server is malconfigured and returns a 5xx error code"""
pass
class EjabberdInternalServerError(EjabberdServerError):
"""Raised if the Server returns a 500 error"""
pass
class EjabberdBadGatewayError(EjabberdServerError):
"""Raised if the Server returns a 502 error"""
pass
class EjabberdServiceUnavailableError(EjabberdServerError):
"""Raised if the Server returns a 503 error"""
pass
class EjabberdGatewayTimeoutError(EjabberdServerError):
"""Raised if the Server returns a 504 error"""
pass
class EjabberdNotFoundError(EjabberdAPIError):
"""Raised when the ejabberd API returns a 404 Not Found error"""
pass
class EjabberdUnauthorizedError(EjabberdAPIError):
"""Raised when the ejabberd API returns a 401 Unauthorized error
This happens when an OAuth token is invalid or has been revoked,
or when trying to access an endpoint that can't be used without
authentication without providing credentials."""
pass

12
xmpp.py
Veure arxiu

@ -13,9 +13,9 @@ if __name__ == '__main__':
notifications = bot.akkoma.notifications() notifications = bot.akkoma.notifications()
except: except bot.akkoma.AkkomaNetworkError as net_error:
pass sys.exit(net_error)
for notif in notifications: for notif in notifications:
@ -33,6 +33,10 @@ if __name__ == '__main__':
if mention.question == bot.register_str: if mention.question == bot.register_str:
account_exists = ejabberd.check_account(mention.acct, bot.akkoma_hostname)
if not account_exists:
password = ejabberd.generate_pass() password = ejabberd.generate_pass()
is_registered, text = ejabberd.register(mention.acct, bot.akkoma_hostname, password) is_registered, text = ejabberd.register(mention.acct, bot.akkoma_hostname, password)
@ -49,6 +53,10 @@ if __name__ == '__main__':
bot.akkoma.status_post(f'@{mention.acct}, {text}', in_reply_to_id=mention.status_id, visibility='direct') bot.akkoma.status_post(f'@{mention.acct}, {text}', in_reply_to_id=mention.status_id, visibility='direct')
else:
bot.akkoma.status_post(f'@{mention.acct}, {bot.account_exists_str}', in_reply_to_id=mention.status_id, visibility='direct')
elif mention.question == bot.unregister_str: elif mention.question == bot.unregister_str:
is_unregistered, is_admin = ejabberd.unregister(mention.acct, bot.akkoma_hostname) is_unregistered, is_admin = ejabberd.unregister(mention.acct, bot.akkoma_hostname)