mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2026-02-06 07:06:19 +01:00
The Great Services Refactor (#594)
* Hooks registration, discovery and retrieval module Will discover @hooks.register decorated functions inside the auth_hooks module in any installed django app. * Class to register modular service apps * Register service modules URLs * Example service module * Refactor services into modules Each service type has been split out into its own django app/module. A hook mechanism is provided to register a subclass of the ServiceHook class. The modules then overload functions defined in ServiceHook as required to provide interoperability with alliance auth. Service modules provide their own urls and views for user registration and account management and a partial template to display on the services page. Where possible, new modules should provide their own models for local data storage. * Added menu items hooks and template tags * Added menu item hook for broadcasts * Added str method to ServicesHook * Added exception handling to hook iterators * Refactor mumble migration and table name Upgrading will require `migrate mumble --fake-initial` to be run first and then `migrate mumble` to rename the table. * Refactor teamspeak3 migration and rename table Upgrading will require `migrate teamspeak3 --fake-initial` * Added module models and migrations for refactoring AuthServicesInfo * Migrate AuthServiceInfo fields to service modules models * Added helper for getting a users main character * Added new style celery instance * Changed Discord from AuthServicesInfo to DiscordUser model * Switch celery tasks to staticmethods * Changed Discourse from AuthServicesInfo to DiscourseUser model * Changed IPBoard from AuthServicesInfo to IpboardUser model * Changed Ips4 from AuthServicesInfo to Ips4User model Also added disable service task. This service still needs some love though. Was always missing a deactivate services hook (before refactoring) for reasons I'm unsure of so I'm reluctant to add it without knowing why. * Changed Market from AuthServicesInfo to MarketUser model * Changed Mumble from AuthServicesInfo to MumbleUser model Switched user foreign key to one to one relationship. Removed implicit password change on user exists. Combined regular and blue user creation. * Changed Openfire from AuthServicesInfo to OpenfireUser model * Changed SMF from AuthServicesInfo to SmfUser model Added disable task * Changed Phpbb3 from AuthServicesInfo to Phpbb3User model * Changed XenForo from AuthServicesInfo to XenforoUser model * Changed Teamspeak3 from AuthServicesInfo to Teamspeak3User model * Remove obsolete manager functions * Standardise URL format This will break some callback URLs Discord changes from /discord_callback/ to /discord/callback/ * Removed unnecessary imports * Mirror upstream decorator change * Setup for unit testing * Unit tests for discord service * Added add main character helper * Added Discourse unit tests * Added Ipboard unit tests * Added Ips4 unit tests * Fix naming of market manager, switch to use class methods * Remove unused hook functions * Added market service unit tests * Added corp ticker to add main character helper * Added mumble unit tests * Fix url name and remove namespace * Fix missing return and add missing URL * Added openfire unit tests * Added missing return * Added phpbb3 unit tests * Fix SmfManager naming inconsistency and switch to classmethods * Added smf unit tests * Remove unused functions, Added missing return * Added xenforo unit tests * Added missing return * Fixed reference to old model * Fixed error preventing groups from syncing on reset request * Added teamspeak3 unit tests * Added nose as test runner and some test settings * Added package requirements for running tests * Added unit tests for services signals and tasks * Remove unused tests file * Fix teamspeak3 service signals * Added unit tests for teamspeak3 signals Changed other unit tests setUp to inert signals * Fix password gen and hashing python3 compatibility Fixes #630 Adds unit tests to check the password functions run on both platforms. * Fix unit test to not rely on checking url params * Add Travis CI settings file * Remove default blank values from services models * Added dynamic user model admin actions for syncing service groups * Remove unused search fields * Add hook function for syncing nicknames * Added discord hook for sync nickname * Added user admin model menu actions for sync nickname hook * Remove obsolete code * Rename celery config app to avoid package name clash * Added new style celerybeat schedule configuration periodic_task decorator is depreciated * Added string representations * Added admin pages for services user models * Removed legacy code * Move link discord button to correct template * Remove blank default fields from example model * Disallow empty django setting * Fix typos * Added coverage configuration file * Add coverage and coveralls to travis config Should probably use nose's built in coverage, but this works for now. * Replace AuthServicesInfo get_or_create instances with get Reflects upstream changes to AuthServicesInfo behaviour. * Update mumble user table name * Split out mumble authenticator requirements zeroc-ice seems to cause long build times on travis-ci and isn't required for the core projects functionality or testing.
This commit is contained in:
@@ -1,201 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
import requests
|
||||
import json
|
||||
import re
|
||||
from django.conf import settings
|
||||
from services.models import GroupCache
|
||||
from requests_oauthlib import OAuth2Session
|
||||
import logging
|
||||
import datetime
|
||||
from django.utils import timezone
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
DISCORD_URL = "https://discordapp.com/api"
|
||||
EVE_IMAGE_SERVER = "https://image.eveonline.com"
|
||||
|
||||
AUTH_URL = "https://discordapp.com/api/oauth2/authorize"
|
||||
TOKEN_URL = "https://discordapp.com/api/oauth2/token"
|
||||
|
||||
# needs administrator, since Discord can't get their permissions system to work
|
||||
# was kick members, manage roles, manage nicknames
|
||||
#BOT_PERMISSIONS = 0x00000002 + 0x10000000 + 0x08000000
|
||||
BOT_PERMISSIONS = 0x00000008
|
||||
|
||||
# get user ID, accept invite
|
||||
SCOPES = [
|
||||
'identify',
|
||||
'guilds.join',
|
||||
]
|
||||
|
||||
GROUP_CACHE_MAX_AGE = datetime.timedelta(minutes=30)
|
||||
|
||||
|
||||
class DiscordOAuthManager:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def _sanitize_groupname(name):
|
||||
name = name.strip(' _')
|
||||
return re.sub('[^\w.-]', '', name)
|
||||
|
||||
@staticmethod
|
||||
def generate_bot_add_url():
|
||||
return AUTH_URL + '?client_id=' + settings.DISCORD_APP_ID + '&scope=bot&permissions=' + str(BOT_PERMISSIONS)
|
||||
|
||||
@staticmethod
|
||||
def generate_oauth_redirect_url():
|
||||
oauth = OAuth2Session(settings.DISCORD_APP_ID, redirect_uri=settings.DISCORD_CALLBACK_URL, scope=SCOPES)
|
||||
url, state = oauth.authorization_url(AUTH_URL)
|
||||
return url
|
||||
|
||||
@staticmethod
|
||||
def _process_callback_code(code):
|
||||
oauth = OAuth2Session(settings.DISCORD_APP_ID, redirect_uri=settings.DISCORD_CALLBACK_URL)
|
||||
token = oauth.fetch_token(TOKEN_URL, client_secret=settings.DISCORD_APP_SECRET, code=code)
|
||||
return token
|
||||
|
||||
@staticmethod
|
||||
def add_user(code):
|
||||
try:
|
||||
token = DiscordOAuthManager._process_callback_code(code)['access_token']
|
||||
logger.debug("Received token from OAuth")
|
||||
|
||||
custom_headers = {'accept': 'application/json', 'authorization': 'Bearer ' + token}
|
||||
path = DISCORD_URL + "/invites/" + str(settings.DISCORD_INVITE_CODE)
|
||||
r = requests.post(path, headers=custom_headers)
|
||||
logger.debug("Got status code %s after accepting Discord invite" % r.status_code)
|
||||
r.raise_for_status()
|
||||
|
||||
path = DISCORD_URL + "/users/@me"
|
||||
r = requests.get(path, headers=custom_headers)
|
||||
logger.debug("Got status code %s after retrieving Discord profile" % r.status_code)
|
||||
r.raise_for_status()
|
||||
|
||||
user_id = r.json()['id']
|
||||
logger.info("Added Discord user ID %s to server." % user_id)
|
||||
return user_id
|
||||
except:
|
||||
logger.exception("Failed to add Discord user")
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def update_nickname(user_id, nickname):
|
||||
try:
|
||||
custom_headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
||||
data = {'nick': nickname, }
|
||||
path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/members/" + str(user_id)
|
||||
r = requests.patch(path, headers=custom_headers, json=data)
|
||||
logger.debug("Got status code %s after setting nickname for Discord user ID %s (%s)" % (
|
||||
r.status_code, user_id, nickname))
|
||||
if r.status_code == 404:
|
||||
logger.warn("Discord user ID %s could not be found in server." % user_id)
|
||||
return True
|
||||
r.raise_for_status()
|
||||
return True
|
||||
except:
|
||||
logger.exception("Failed to set nickname for Discord user ID %s (%s)" % (user_id, nickname))
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def delete_user(user_id):
|
||||
try:
|
||||
custom_headers = {'accept': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
||||
path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/members/" + str(user_id)
|
||||
r = requests.delete(path, headers=custom_headers)
|
||||
logger.debug("Got status code %s after removing Discord user ID %s" % (r.status_code, user_id))
|
||||
if r.status_code == 404:
|
||||
logger.warn("Discord user ID %s already left the server." % user_id)
|
||||
return True
|
||||
r.raise_for_status()
|
||||
return True
|
||||
except:
|
||||
logger.exception("Failed to remove Discord user ID %s" % user_id)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def __get_groups():
|
||||
custom_headers = {'accept': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
||||
path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/roles"
|
||||
r = requests.get(path, headers=custom_headers)
|
||||
logger.debug("Got status code %s after retrieving Discord roles" % r.status_code)
|
||||
r.raise_for_status()
|
||||
return r.json()
|
||||
|
||||
@staticmethod
|
||||
def __update_group_cache():
|
||||
GroupCache.objects.filter(service="discord").delete()
|
||||
cache = GroupCache.objects.create(service="discord")
|
||||
cache.groups = json.dumps(DiscordOAuthManager.__get_groups())
|
||||
cache.save()
|
||||
return cache
|
||||
|
||||
@staticmethod
|
||||
def __get_group_cache():
|
||||
if not GroupCache.objects.filter(service="discord").exists():
|
||||
DiscordOAuthManager.__update_group_cache()
|
||||
cache = GroupCache.objects.get(service="discord")
|
||||
age = timezone.now() - cache.created
|
||||
if age > GROUP_CACHE_MAX_AGE:
|
||||
logger.debug("Group cache has expired. Triggering update.")
|
||||
cache = DiscordOAuthManager.__update_group_cache()
|
||||
return json.loads(cache.groups)
|
||||
|
||||
@staticmethod
|
||||
def __group_name_to_id(name):
|
||||
cache = DiscordOAuthManager.__get_group_cache()
|
||||
for g in cache:
|
||||
if g['name'] == name:
|
||||
return g['id']
|
||||
logger.debug("Group %s not found on Discord. Creating" % name)
|
||||
DiscordOAuthManager.__create_group(name)
|
||||
return DiscordOAuthManager.__group_name_to_id(name)
|
||||
|
||||
@staticmethod
|
||||
def __group_id_to_name(id):
|
||||
cache = DiscordOAuthManager.__get_group_cache()
|
||||
for g in cache:
|
||||
if g['id'] == id:
|
||||
return g['name']
|
||||
raise KeyError("Group ID %s not found on Discord" % id)
|
||||
|
||||
@staticmethod
|
||||
def __generate_role():
|
||||
custom_headers = {'accept': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
||||
path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/roles"
|
||||
r = requests.post(path, headers=custom_headers)
|
||||
logger.debug("Received status code %s after generating new role." % r.status_code)
|
||||
r.raise_for_status()
|
||||
return r.json()
|
||||
|
||||
@staticmethod
|
||||
def __edit_role(role_id, name, color=0, hoist=True, permissions=36785152):
|
||||
custom_headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
||||
data = {
|
||||
'color': color,
|
||||
'hoist': hoist,
|
||||
'name': name,
|
||||
'permissions': permissions,
|
||||
}
|
||||
path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/roles/" + str(role_id)
|
||||
r = requests.patch(path, headers=custom_headers, data=json.dumps(data))
|
||||
logger.debug("Received status code %s after editing role id %s" % (r.status_code, role_id))
|
||||
r.raise_for_status()
|
||||
return r.json()
|
||||
|
||||
@staticmethod
|
||||
def __create_group(name):
|
||||
role = DiscordOAuthManager.__generate_role()
|
||||
DiscordOAuthManager.__edit_role(role['id'], name)
|
||||
DiscordOAuthManager.__update_group_cache()
|
||||
|
||||
@staticmethod
|
||||
def update_groups(user_id, groups):
|
||||
custom_headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
||||
group_ids = [DiscordOAuthManager.__group_name_to_id(DiscordOAuthManager._sanitize_groupname(g)) for g in groups]
|
||||
path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/members/" + str(user_id)
|
||||
data = {'roles': group_ids}
|
||||
r = requests.patch(path, headers=custom_headers, json=data)
|
||||
logger.debug("Received status code %s after setting user roles" % r.status_code)
|
||||
r.raise_for_status()
|
||||
@@ -1,378 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
import logging
|
||||
import requests
|
||||
import os
|
||||
import datetime
|
||||
import json
|
||||
import re
|
||||
from django.conf import settings
|
||||
from django.utils import timezone
|
||||
from services.models import GroupCache
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class DiscourseError(Exception):
|
||||
def __init__(self, endpoint, errors):
|
||||
self.endpoint = endpoint
|
||||
self.errors = errors
|
||||
def __str__(self):
|
||||
return "API execution failed.\nErrors: %s\nEndpoint: %s" % (self.errors, self.endpoint)
|
||||
|
||||
# not exhaustive, only the ones we need
|
||||
ENDPOINTS = {
|
||||
'groups': {
|
||||
'list': {
|
||||
'path': "/admin/groups.json",
|
||||
'method': requests.get,
|
||||
'args': {
|
||||
'required': [],
|
||||
'optional': [],
|
||||
},
|
||||
},
|
||||
'create': {
|
||||
'path': "/admin/groups",
|
||||
'method': requests.post,
|
||||
'args': {
|
||||
'required': ['name'],
|
||||
'optional': ['visible'],
|
||||
}
|
||||
},
|
||||
'add_user': {
|
||||
'path': "/admin/groups/%s/members.json",
|
||||
'method': requests.put,
|
||||
'args': {
|
||||
'required': ['usernames'],
|
||||
'optional': [],
|
||||
},
|
||||
},
|
||||
'remove_user': {
|
||||
'path': "/admin/groups/%s/members.json",
|
||||
'method': requests.delete,
|
||||
'args': {
|
||||
'required': ['username'],
|
||||
'optional': [],
|
||||
},
|
||||
},
|
||||
'delete': {
|
||||
'path': "/admin/groups/%s.json",
|
||||
'method': requests.delete,
|
||||
'args': {
|
||||
'required': [],
|
||||
'optional': [],
|
||||
},
|
||||
},
|
||||
},
|
||||
'users': {
|
||||
'create': {
|
||||
'path': "/users",
|
||||
'method': requests.post,
|
||||
'args': {
|
||||
'required': ['name', 'email', 'password', 'username'],
|
||||
'optional': ['active'],
|
||||
},
|
||||
},
|
||||
'update': {
|
||||
'path': "/users/%s.json",
|
||||
'method': requests.put,
|
||||
'args': {
|
||||
'required': ['params'],
|
||||
'optional': [],
|
||||
}
|
||||
},
|
||||
'get': {
|
||||
'path': "/users/%s.json",
|
||||
'method': requests.get,
|
||||
'args': {
|
||||
'required': [],
|
||||
'optional': [],
|
||||
},
|
||||
},
|
||||
'activate': {
|
||||
'path': "/admin/users/%s/activate",
|
||||
'method': requests.put,
|
||||
'args': {
|
||||
'required': [],
|
||||
'optional': [],
|
||||
},
|
||||
},
|
||||
'set_email': {
|
||||
'path': "/users/%s/preferences/email",
|
||||
'method': requests.put,
|
||||
'args': {
|
||||
'required': ['email'],
|
||||
'optional': [],
|
||||
},
|
||||
},
|
||||
'suspend': {
|
||||
'path': "/admin/users/%s/suspend",
|
||||
'method': requests.put,
|
||||
'args': {
|
||||
'required': ['duration', 'reason'],
|
||||
'optional': [],
|
||||
},
|
||||
},
|
||||
'unsuspend': {
|
||||
'path': "/admin/users/%s/unsuspend",
|
||||
'method': requests.put,
|
||||
'args': {
|
||||
'required': [],
|
||||
'optional': [],
|
||||
},
|
||||
},
|
||||
'logout': {
|
||||
'path': "/admin/users/%s/log_out",
|
||||
'method': requests.post,
|
||||
'args': {
|
||||
'required': [],
|
||||
'optional': [],
|
||||
},
|
||||
},
|
||||
'external': {
|
||||
'path': "/users/by-external/%s.json",
|
||||
'method': requests.get,
|
||||
'args': {
|
||||
'required': [],
|
||||
'optional': [],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class DiscourseManager:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
GROUP_CACHE_MAX_AGE = datetime.timedelta(minutes=30)
|
||||
REVOKED_EMAIL = 'revoked@' + settings.DOMAIN
|
||||
SUSPEND_DAYS = 99999
|
||||
SUSPEND_REASON = "Disabled by auth."
|
||||
|
||||
@staticmethod
|
||||
def __exc(endpoint, *args, **kwargs):
|
||||
params = {
|
||||
'api_key': settings.DISCOURSE_API_KEY,
|
||||
'api_username': settings.DISCOURSE_API_USERNAME,
|
||||
}
|
||||
silent = kwargs.pop('silent', False)
|
||||
if args:
|
||||
endpoint['parsed_url'] = endpoint['path'] % args
|
||||
else:
|
||||
endpoint['parsed_url'] = endpoint['path']
|
||||
data = {}
|
||||
for arg in endpoint['args']['required']:
|
||||
data[arg] = kwargs[arg]
|
||||
for arg in endpoint['args']['optional']:
|
||||
if arg in kwargs:
|
||||
data[arg] = kwargs[arg]
|
||||
for arg in kwargs:
|
||||
if arg not in endpoint['args']['required'] and arg not in endpoint['args']['optional'] and not silent:
|
||||
logger.warn("Received unrecognized kwarg %s for endpoint %s" % (arg, endpoint))
|
||||
r = endpoint['method'](settings.DISCOURSE_URL + endpoint['parsed_url'], params=params, json=data)
|
||||
try:
|
||||
if 'errors' in r.json() and not silent:
|
||||
logger.error("Discourse execution failed.\nEndpoint: %s\nErrors: %s" % (endpoint, r.json()['errors']))
|
||||
raise DiscourseError(endpoint, r.json()['errors'])
|
||||
if 'success' in r.json():
|
||||
if not r.json()['success'] and not silent:
|
||||
raise DiscourseError(endpoint, None)
|
||||
out = r.json()
|
||||
except ValueError:
|
||||
out = r.text
|
||||
finally:
|
||||
try:
|
||||
r.raise_for_status()
|
||||
except requests.exceptions.HTTPError as e:
|
||||
raise DiscourseError(endpoint, e.response.status_code)
|
||||
return out
|
||||
|
||||
@staticmethod
|
||||
def __generate_random_pass():
|
||||
return os.urandom(8).encode('hex')
|
||||
|
||||
@staticmethod
|
||||
def __get_groups():
|
||||
endpoint = ENDPOINTS['groups']['list']
|
||||
data = DiscourseManager.__exc(endpoint)
|
||||
return [g for g in data if not g['automatic']]
|
||||
|
||||
@staticmethod
|
||||
def __update_group_cache():
|
||||
GroupCache.objects.filter(service="discourse").delete()
|
||||
cache = GroupCache.objects.create(service="discourse")
|
||||
cache.groups = json.dumps(DiscourseManager.__get_groups())
|
||||
cache.save()
|
||||
return cache
|
||||
|
||||
@staticmethod
|
||||
def __get_group_cache():
|
||||
if not GroupCache.objects.filter(service="discourse").exists():
|
||||
DiscourseManager.__update_group_cache()
|
||||
cache = GroupCache.objects.get(service="discourse")
|
||||
age = timezone.now() - cache.created
|
||||
if age > DiscourseManager.GROUP_CACHE_MAX_AGE:
|
||||
logger.debug("Group cache has expired. Triggering update.")
|
||||
cache = DiscourseManager.__update_group_cache()
|
||||
return json.loads(cache.groups)
|
||||
|
||||
@staticmethod
|
||||
def __create_group(name):
|
||||
endpoint = ENDPOINTS['groups']['create']
|
||||
DiscourseManager.__exc(endpoint, name=name[:20], visible=True)
|
||||
DiscourseManager.__update_group_cache()
|
||||
|
||||
@staticmethod
|
||||
def __group_name_to_id(name):
|
||||
cache = DiscourseManager.__get_group_cache()
|
||||
for g in cache:
|
||||
if g['name'] == name[0:20]:
|
||||
return g['id']
|
||||
logger.debug("Group %s not found on Discourse. Creating" % name)
|
||||
DiscourseManager.__create_group(name)
|
||||
return DiscourseManager.__group_name_to_id(name)
|
||||
|
||||
@staticmethod
|
||||
def __group_id_to_name(id):
|
||||
cache = DiscourseManager.__get_group_cache()
|
||||
for g in cache:
|
||||
if g['id'] == id:
|
||||
return g['name']
|
||||
raise KeyError("Group ID %s not found on Discourse" % id)
|
||||
|
||||
@staticmethod
|
||||
def __add_user_to_group(id, username):
|
||||
endpoint = ENDPOINTS['groups']['add_user']
|
||||
DiscourseManager.__exc(endpoint, id, usernames=[username])
|
||||
|
||||
@staticmethod
|
||||
def __remove_user_from_group(id, username):
|
||||
endpoint = ENDPOINTS['groups']['remove_user']
|
||||
DiscourseManager.__exc(endpoint, id, username=username)
|
||||
|
||||
@staticmethod
|
||||
def __generate_group_dict(names):
|
||||
group_dict = {}
|
||||
for name in names:
|
||||
group_dict[name] = DiscourseManager.__group_name_to_id(name)
|
||||
return group_dict
|
||||
|
||||
@staticmethod
|
||||
def __get_user_groups(username):
|
||||
data = DiscourseManager.__get_user(username)
|
||||
return [g['id'] for g in data['user']['groups'] if not g['automatic']]
|
||||
|
||||
@staticmethod
|
||||
def __user_name_to_id(name, silent=False):
|
||||
data = DiscourseManager.__get_user(name, silent=silent)
|
||||
return data['user']['id']
|
||||
|
||||
@staticmethod
|
||||
def __user_id_to_name(id):
|
||||
raise NotImplementedError
|
||||
|
||||
@staticmethod
|
||||
def __get_user(username, silent=False):
|
||||
endpoint = ENDPOINTS['users']['get']
|
||||
return DiscourseManager.__exc(endpoint, username, silent=silent)
|
||||
|
||||
@staticmethod
|
||||
def __activate_user(username):
|
||||
endpoint = ENDPOINTS['users']['activate']
|
||||
id = DiscourseManager.__user_name_to_id(username)
|
||||
DiscourseManager.__exc(endpoint, id)
|
||||
|
||||
@staticmethod
|
||||
def __update_user(username, **kwargs):
|
||||
endpoint = ENDPOINTS['users']['update']
|
||||
id = DiscourseManager.__user_name_to_id(username)
|
||||
DiscourseManager.__exc(endpoint, id, params=kwargs)
|
||||
|
||||
@staticmethod
|
||||
def __create_user(username, email, password):
|
||||
endpoint = ENDPOINTS['users']['create']
|
||||
DiscourseManager.__exc(endpoint, name=username, username=username, email=email, password=password, active=True)
|
||||
|
||||
@staticmethod
|
||||
def __check_if_user_exists(username):
|
||||
try:
|
||||
DiscourseManager.__user_name_to_id(username, silent=True)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def __suspend_user(username):
|
||||
id = DiscourseManager.__user_name_to_id(username)
|
||||
endpoint = ENDPOINTS['users']['suspend']
|
||||
return DiscourseManager.__exc(endpoint, id, duration=DiscourseManager.SUSPEND_DAYS,
|
||||
reason=DiscourseManager.SUSPEND_REASON)
|
||||
|
||||
@staticmethod
|
||||
def __unsuspend(username):
|
||||
id = DiscourseManager.__user_name_to_id(username)
|
||||
endpoint = ENDPOINTS['users']['unsuspend']
|
||||
return DiscourseManager.__exc(endpoint, id)
|
||||
|
||||
@staticmethod
|
||||
def __set_email(username, email):
|
||||
endpoint = ENDPOINTS['users']['set_email']
|
||||
return DiscourseManager.__exc(endpoint, username, email=email)
|
||||
|
||||
@staticmethod
|
||||
def __logout(id):
|
||||
endpoint = ENDPOINTS['users']['logout']
|
||||
return DiscourseManager.__exc(endpoint, id)
|
||||
|
||||
@staticmethod
|
||||
def __get_user_by_external(id):
|
||||
endpoint = ENDPOINTS['users']['external']
|
||||
return DiscourseManager.__exc(endpoint, id)
|
||||
|
||||
@staticmethod
|
||||
def __user_id_by_external_id(id):
|
||||
data = DiscourseManager.__get_user_by_external(id)
|
||||
return data['user']['id']
|
||||
|
||||
@staticmethod
|
||||
def _sanitize_username(username):
|
||||
sanitized = username.replace(" ", "_")
|
||||
sanitized = sanitized.strip(' _')
|
||||
sanitized = sanitized.replace("'", "")
|
||||
return sanitized
|
||||
|
||||
@staticmethod
|
||||
def _sanitize_groupname(name):
|
||||
name = name.strip(' _')
|
||||
name = re.sub('[^\w]', '', name)
|
||||
if len(name) < 3:
|
||||
name = name + "".join('_' for i in range(3-len(name)))
|
||||
return name[:20]
|
||||
|
||||
@staticmethod
|
||||
def update_groups(user):
|
||||
groups = []
|
||||
for g in user.groups.all():
|
||||
groups.append(DiscourseManager._sanitize_groupname(str(g)[:20]))
|
||||
logger.debug("Updating discourse user %s groups to %s" % (user, groups))
|
||||
group_dict = DiscourseManager.__generate_group_dict(groups)
|
||||
inv_group_dict = {v: k for k, v in group_dict.items()}
|
||||
username = DiscourseManager.__get_user_by_external(user.pk)['user']['username']
|
||||
user_groups = DiscourseManager.__get_user_groups(username)
|
||||
add_groups = [group_dict[x] for x in group_dict if not group_dict[x] in user_groups]
|
||||
rem_groups = [x for x in user_groups if not x in inv_group_dict]
|
||||
if add_groups or rem_groups:
|
||||
logger.info(
|
||||
"Updating discourse user %s groups: adding %s, removing %s" % (username, add_groups, rem_groups))
|
||||
for g in add_groups:
|
||||
DiscourseManager.__add_user_to_group(g, username)
|
||||
for g in rem_groups:
|
||||
DiscourseManager.__remove_user_from_group(g, username)
|
||||
|
||||
@staticmethod
|
||||
def disable_user(user):
|
||||
logger.debug("Disabling user %s Discourse access." % user)
|
||||
d_user = DiscourseManager.__get_user_by_external(user.pk)
|
||||
DiscourseManager.__logout(d_user['user']['id'])
|
||||
DiscourseManager.__suspend_user(d_user['user']['username'])
|
||||
logger.info("Disabled user %s Discourse access." % user)
|
||||
return True
|
||||
@@ -1,178 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
from django.conf import settings
|
||||
from datetime import datetime
|
||||
|
||||
import logging
|
||||
import requests
|
||||
import json
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
appkey = settings.FLEETUP_APP_KEY
|
||||
userid = settings.FLEETUP_USER_ID
|
||||
apiid = settings.FLEETUP_API_ID
|
||||
groupid = settings.FLEETUP_GROUP_ID
|
||||
|
||||
|
||||
class FleetUpManager:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def get_fleetup_members():
|
||||
url = "http://api.fleet-up.com/Api.svc/" + str(appkey) + "/" + str(userid) + "/" + str(
|
||||
apiid) + "/GroupCharacters/" + str(groupid) + ""
|
||||
try:
|
||||
jsondata = requests.get(url).content
|
||||
fmembers = json.loads(jsondata.decode())
|
||||
return {row["UserId"]: {"user_id": row["UserId"],
|
||||
"char_name": row["EveCharName"],
|
||||
"char_id": row["EveCharId"],
|
||||
"corporation": row["Corporation"]} for row in fmembers["Data"]}
|
||||
except requests.exceptions.ConnectionError:
|
||||
logger.warn("Can't connect to Fleet-Up API, is it offline?!")
|
||||
except (ValueError, UnicodeDecodeError, TypeError):
|
||||
logger.debug("No fleetup members retrieved.")
|
||||
return {}
|
||||
|
||||
@staticmethod
|
||||
def get_fleetup_operations():
|
||||
url = "http://api.fleet-up.com/Api.svc/" + str(appkey) + "/" + str(userid) + "/" + str(
|
||||
apiid) + "/Operations/" + str(groupid) + ""
|
||||
try:
|
||||
jsondata = requests.get(url).content
|
||||
foperations = json.loads(jsondata.decode())
|
||||
return {row["StartString"]: {"subject": row["Subject"],
|
||||
"start": (datetime.strptime(row["StartString"], "%Y-%m-%d %H:%M:%S")),
|
||||
"end": (datetime.strptime(row["EndString"], "%Y-%m-%d %H:%M:%S")),
|
||||
"operation_id": row["OperationId"],
|
||||
"location": row["Location"],
|
||||
"location_info": row["LocationInfo"],
|
||||
"details": row["Details"],
|
||||
"url": row["Url"],
|
||||
"doctrine": row["Doctrines"],
|
||||
"organizer": row["Organizer"]} for row in foperations["Data"]}
|
||||
except requests.exceptions.ConnectionError:
|
||||
logger.warn("Can't connect to Fleet-Up API, is it offline?!")
|
||||
except (ValueError, UnicodeDecodeError):
|
||||
logger.debug("No fleetup operations retrieved.")
|
||||
return {}
|
||||
|
||||
@staticmethod
|
||||
def get_fleetup_timers():
|
||||
url = "http://api.fleet-up.com/Api.svc/" + str(appkey) + "/" + str(userid) + "/" + str(
|
||||
apiid) + "/Timers/" + str(groupid) + ""
|
||||
try:
|
||||
jsondata = requests.get(url).content
|
||||
ftimers = json.loads(jsondata.decode())
|
||||
return {row["ExpiresString"]: {"solarsystem": row["SolarSystem"],
|
||||
"planet": row["Planet"],
|
||||
"moon": row["Moon"],
|
||||
"owner": row["Owner"],
|
||||
"type": row["Type"],
|
||||
"timer_type": row["TimerType"],
|
||||
"expires": (datetime.strptime(row["ExpiresString"], "%Y-%m-%d %H:%M:%S")),
|
||||
"notes": row["Notes"]} for row in ftimers["Data"]}
|
||||
except requests.exceptions.ConnectionError:
|
||||
logger.warn("Can't connect to Fleet-Up API, is it offline?!")
|
||||
except (ValueError, UnicodeDecodeError, TypeError):
|
||||
logger.debug("No fleetup timers retrieved.")
|
||||
return {}
|
||||
|
||||
@staticmethod
|
||||
def get_fleetup_doctrines():
|
||||
url = "http://api.fleet-up.com/Api.svc/" + str(appkey) + "/" + str(userid) + "/" + str(
|
||||
apiid) + "/Doctrines/" + str(groupid) + ""
|
||||
try:
|
||||
jsondata = requests.get(url).content
|
||||
fdoctrines = json.loads(jsondata.decode())
|
||||
return {"fleetup_doctrines": fdoctrines["Data"]}
|
||||
except requests.exceptions.ConnectionError:
|
||||
logger.warn("Can't connect to Fleet-Up API, is it offline?!")
|
||||
except (ValueError, UnicodeDecodeError):
|
||||
logger.debug("No fleetup doctrines retrieved.")
|
||||
return {"fleetup_doctrines": []}
|
||||
|
||||
@staticmethod
|
||||
def get_fleetup_doctrine(doctrinenumber):
|
||||
url = "http://api.fleet-up.com/Api.svc/" + str(appkey) + "/" + str(userid) + "/" + str(
|
||||
apiid) + "/DoctrineFittings/%s" % doctrinenumber
|
||||
try:
|
||||
jsondata = requests.get(url).content
|
||||
fdoctrine = json.loads(jsondata.decode())
|
||||
return {"fitting_doctrine": fdoctrine}
|
||||
except requests.exceptions.ConnectionError:
|
||||
logger.warn("Can't connect to Fleet-Up API, is it offline?!")
|
||||
except (ValueError, UnicodeDecodeError):
|
||||
logger.warn("Fleetup doctrine number %s not found" % doctrinenumber)
|
||||
return {"fitting_doctrine": {}}
|
||||
|
||||
@staticmethod
|
||||
def get_fleetup_fittings():
|
||||
url = "http://api.fleet-up.com/Api.svc/" + str(appkey) + "/" + str(userid) + "/" + str(
|
||||
apiid) + "/Fittings/" + str(groupid) + ""
|
||||
try:
|
||||
jsondata = requests.get(url).content
|
||||
ffittings = json.loads(jsondata.decode())
|
||||
return {row["FittingId"]: {"fitting_id": row["FittingId"],
|
||||
"name": row["Name"],
|
||||
"icon_id": row["EveTypeId"],
|
||||
"hull": row["HullType"],
|
||||
"shiptype": row["ShipType"],
|
||||
"estimated": row["EstPrice"],
|
||||
"faction": row["Faction"],
|
||||
"categories": row["Categories"],
|
||||
"last_update": (
|
||||
datetime.strptime(row["LastUpdatedString"], "%Y-%m-%d %H:%M:%S"))} for row in
|
||||
ffittings["Data"]}
|
||||
except requests.exceptions.ConnectionError:
|
||||
logger.warn("Can't connect to Fleet-Up API, is it offline?!")
|
||||
except (ValueError, UnicodeDecodeError, TypeError):
|
||||
logger.debug("No fleetup fittings retrieved.")
|
||||
return {}
|
||||
|
||||
@staticmethod
|
||||
def get_fleetup_fitting(fittingnumber):
|
||||
url = "http://api.fleet-up.com/Api.svc/" + str(appkey) + "/" + str(userid) + "/" + str(
|
||||
apiid) + "/Fitting/%s" % fittingnumber
|
||||
try:
|
||||
jsondata = requests.get(url).content
|
||||
ffitting = json.loads(jsondata.decode())
|
||||
return {"fitting_data": ffitting["Data"]}
|
||||
except requests.exceptions.ConnectionError:
|
||||
logger.warn("Can't connect to Fleet-Up API, is it offline?!")
|
||||
except (ValueError, UnicodeDecodeError):
|
||||
logger.warn("Fleetup fitting number %s not found" % fittingnumber)
|
||||
except KeyError:
|
||||
logger.warn("Failed to retrieve fleetup fitting number %s" % fittingnumber)
|
||||
return {"fitting_data": {}}
|
||||
|
||||
@staticmethod
|
||||
def get_fleetup_doctrineid(fittingnumber):
|
||||
url = "http://api.fleet-up.com/Api.svc/" + str(appkey) + "/" + str(userid) + "/" + str(
|
||||
apiid) + "/Fitting/%s" % fittingnumber
|
||||
try:
|
||||
jsondata = requests.get(url).content
|
||||
fdoctrineid = json.loads(jsondata.decode())
|
||||
return fdoctrineid['Data']['Doctrines'][0]['DoctrineId']
|
||||
except requests.exceptions.ConnectionError:
|
||||
logger.warn("Can't connect to Fleet-Up API, is it offline?!")
|
||||
except (ValueError, UnicodeDecodeError):
|
||||
logger.warn("Fleetup doctrine number not found for fitting number %s" % fittingnumber)
|
||||
except (KeyError, IndexError):
|
||||
logger.debug("Fleetup fitting number %s not in a doctrine." % fittingnumber)
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def get_fleetup_fitting_eft(fittingnumber):
|
||||
url = "http://api.fleet-up.com/Api.svc/" + str(appkey) + "/" + str(userid) + "/" + str(
|
||||
apiid) + "/Fitting/%s/eft" % fittingnumber
|
||||
try:
|
||||
jsondata = requests.get(url).content
|
||||
ffittingeft = json.loads(jsondata.decode())
|
||||
return {"fitting_eft": ffittingeft["Data"]["FittingData"]}
|
||||
except requests.exceptions.ConnectionError:
|
||||
logger.warn("Can't connect to Fleet-Up API, is it offline?!")
|
||||
except (ValueError, UnicodeDecodeError):
|
||||
logger.warn("Fleetup fitting eft not found for fitting number %s" % fittingnumber)
|
||||
return {"fitting_eft": {}}
|
||||
@@ -1,156 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
import os
|
||||
import re
|
||||
from hashlib import md5
|
||||
try:
|
||||
from xmlrpclib import Server
|
||||
except ImportError:
|
||||
# python 3
|
||||
from xmlrpc import server as Server
|
||||
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class IPBoardManager:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def __santatize_username(username):
|
||||
sanatized = username.replace(" ", "_")
|
||||
return sanatized.lower()
|
||||
|
||||
@staticmethod
|
||||
def __generate_random_pass():
|
||||
return os.urandom(8).encode('hex')
|
||||
|
||||
@staticmethod
|
||||
def _sanitize_groupname(name):
|
||||
name = name.strip(' _')
|
||||
return re.sub('[^\w.-]', '', name)
|
||||
|
||||
@staticmethod
|
||||
def exec_xmlrpc(func, **kwargs):
|
||||
""" Send a XMLRPC request """
|
||||
try:
|
||||
server = Server(settings.IPBOARD_ENDPOINT, verbose=False)
|
||||
params = {}
|
||||
for i in kwargs:
|
||||
params[i] = kwargs[i]
|
||||
params['api_key'] = settings.IPBOARD_APIKEY
|
||||
params['api_module'] = settings.IPBOARD_APIMODULE
|
||||
|
||||
return getattr(server, func)(params)
|
||||
except:
|
||||
return {}
|
||||
|
||||
@staticmethod
|
||||
def add_user(username, email):
|
||||
""" Add user to service """
|
||||
sanatized = str(IPBoardManager.__santatize_username(username))
|
||||
logger.debug("Adding user to IPBoard with username %s" % sanatized)
|
||||
plain_password = IPBoardManager.__generate_random_pass()
|
||||
password = md5(plain_password).hexdigest()
|
||||
IPBoardManager.exec_xmlrpc('createUser', username=sanatized, email=str(email), display_name=sanatized,
|
||||
md5_passwordHash=password)
|
||||
logger.info("Added IPBoard user with username %s" % sanatized)
|
||||
return sanatized, plain_password
|
||||
|
||||
@staticmethod
|
||||
def delete_user(username):
|
||||
""" Delete user """
|
||||
IPBoardManager.exec_xmlrpc('deleteUser', username=username)
|
||||
logger.info("Deleted IPBoard user with username %s" % username)
|
||||
return username
|
||||
|
||||
@staticmethod
|
||||
def disable_user(username):
|
||||
""" Disable user """
|
||||
IPBoardManager.exec_xmlrpc('disableUser', username=username)
|
||||
logger.info("Disabled IPBoard user with username %s" % username)
|
||||
return username
|
||||
|
||||
@staticmethod
|
||||
def update_user(username, email, password):
|
||||
""" Add user to service """
|
||||
password = md5(password).hexdigest()
|
||||
logger.debug("Updating IPBoard username %s with email %s and password hash starting with %s" % (
|
||||
username, email, password[0:5]))
|
||||
IPBoardManager.exec_xmlrpc('updateUser', username=username, email=email, md5_passwordHash=password)
|
||||
logger.info("Updated IPBoard user with username %s" % username)
|
||||
return username
|
||||
|
||||
@staticmethod
|
||||
def get_all_groups():
|
||||
groups = []
|
||||
ret = IPBoardManager.exec_xmlrpc('getAllGroups')
|
||||
for group in ret:
|
||||
groups.append(group["g_title"])
|
||||
logger.debug("Retrieved group list from IPBoard: %s" % groups)
|
||||
return groups
|
||||
|
||||
@staticmethod
|
||||
def get_user_groups(username):
|
||||
groups = []
|
||||
ret = IPBoardManager.exec_xmlrpc('getUserGroups', username=username)
|
||||
if type(ret) is list:
|
||||
for group in ret:
|
||||
groups.append(group["g_title"])
|
||||
logger.debug("Got user %s IPBoard groups %s" % (username, groups))
|
||||
return groups
|
||||
|
||||
@staticmethod
|
||||
def add_group(group):
|
||||
ret = IPBoardManager.exec_xmlrpc('addGroup', group=group)
|
||||
logger.info("Added IPBoard group %s" % group)
|
||||
return ret
|
||||
|
||||
@staticmethod
|
||||
def add_user_to_group(username, group):
|
||||
ret = IPBoardManager.exec_xmlrpc('addUserToGroup', username=username, group=group)
|
||||
logger.info("Added IPBoard user %s to group %s" % (username, group))
|
||||
return ret
|
||||
|
||||
@staticmethod
|
||||
def remove_user_from_group(username, group):
|
||||
ret = IPBoardManager.exec_xmlrpc('removeUserFromGroup', username=username, group=group)
|
||||
logger.info("Removed IPBoard user %s from group %s" % (username, group))
|
||||
return ret
|
||||
|
||||
@staticmethod
|
||||
def help_me():
|
||||
ret = IPBoardManager.exec_xmlrpc('helpMe')
|
||||
return ret
|
||||
|
||||
@staticmethod
|
||||
def update_groups(username, groups):
|
||||
logger.debug("Updating IPBoard user %s with groups %s" % (username, groups))
|
||||
forum_groups = IPBoardManager.get_all_groups()
|
||||
user_groups = set(IPBoardManager.get_user_groups(username))
|
||||
act_groups = set([IPBoardManager._sanitize_groupname(g) for g in groups])
|
||||
addgroups = act_groups - user_groups
|
||||
remgroups = user_groups - act_groups
|
||||
|
||||
logger.info("Updating IPBoard groups for user %s - adding %s, removing %s" % (username, addgroups, remgroups))
|
||||
for g in addgroups:
|
||||
if g not in forum_groups:
|
||||
IPBoardManager.add_group(g)
|
||||
logger.debug("Adding user %s to IPBoard group %s" % (username, g))
|
||||
IPBoardManager.add_user_to_group(username, g)
|
||||
|
||||
for g in remgroups:
|
||||
logger.debug("Removing user %s from IPBoard group %s" % (username, g))
|
||||
IPBoardManager.remove_user_from_group(username, g)
|
||||
|
||||
@staticmethod
|
||||
def update_user_password(username, email, plain_password=None):
|
||||
logger.debug("Settings new IPBoard password for user %s" % username)
|
||||
if not plain_password:
|
||||
plain_password = IPBoardManager.__generate_random_pass()
|
||||
IPBoardManager.update_user(username, email, plain_password)
|
||||
return plain_password
|
||||
@@ -1,102 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
import logging
|
||||
import os
|
||||
from django.db import connections
|
||||
from passlib.hash import bcrypt
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Ips4Manager:
|
||||
SQL_ADD_USER = r"INSERT INTO core_members (name, email, members_pass_hash, members_pass_salt, " \
|
||||
r"member_group_id) VALUES (%s, %s, %s, %s, %s)"
|
||||
SQL_GET_ID = r"SELECT member_id FROM core_members WHERE name = %s"
|
||||
SQL_UPDATE_PASSWORD = r"UPDATE core_members SET members_pass_hash = %s, members_pass_salt = %s WHERE name = %s"
|
||||
SQL_DEL_USER = r"DELETE FROM core_members WHERE member_id = %s"
|
||||
|
||||
MEMBER_GROUP_ID = 3
|
||||
|
||||
@staticmethod
|
||||
def add_user(username, email):
|
||||
logger.debug("Adding new IPS4 user %s" % username)
|
||||
plain_password = Ips4Manager.__generate_random_pass()
|
||||
hash = bcrypt.encrypt(plain_password, rounds=13)
|
||||
hash_result = hash
|
||||
rounds_striped = hash_result.strip('$2a$13$')
|
||||
salt = rounds_striped[:22]
|
||||
group = Ips4Manager.MEMBER_GROUP_ID
|
||||
cursor = connections['ips4'].cursor()
|
||||
cursor.execute(Ips4Manager.SQL_ADD_USER, [username, email, hash, salt, group])
|
||||
member_id = Ips4Manager.get_user_id(username)
|
||||
return username, plain_password, member_id
|
||||
|
||||
@staticmethod
|
||||
def get_user_id(username):
|
||||
cursor = connections['ips4'].cursor()
|
||||
cursor.execute(Ips4Manager.SQL_GET_ID, [username])
|
||||
row = cursor.fetchone()
|
||||
if row is not None:
|
||||
logger.debug("Got user id %s for username %s" % (row[0], username))
|
||||
return row[0]
|
||||
else:
|
||||
logger.error("username %s not found. Unable to determine id." % username)
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def __generate_random_pass():
|
||||
return os.urandom(8).encode('hex')
|
||||
|
||||
@staticmethod
|
||||
def delete_user(id):
|
||||
logger.debug("Deleting IPS4 user id %s" % id)
|
||||
try:
|
||||
cursor = connections['ips4'].cursor()
|
||||
cursor.execute(Ips4Manager.SQL_DEL_USER, [id])
|
||||
logger.info("Deleted IPS4 user %s" % id)
|
||||
return True
|
||||
except:
|
||||
logger.exception("Failed to delete IPS4 user id %s" % id)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def update_user_password(username):
|
||||
logger.debug("Updating IPS4 user id %s password" % id)
|
||||
if Ips4Manager.check_user(username):
|
||||
plain_password = Ips4Manager.__generate_random_pass()
|
||||
hash = bcrypt.encrypt(plain_password, rounds=13)
|
||||
hash_result = hash
|
||||
rounds_striped = hash_result.strip('$2a$13$')
|
||||
salt = rounds_striped[:22]
|
||||
cursor = connections['ips4'].cursor()
|
||||
cursor.execute(Ips4Manager.SQL_UPDATE_PASSWORD, [hash, salt, username])
|
||||
return plain_password
|
||||
else:
|
||||
logger.error("Unable to update ips4 user %s password" % username)
|
||||
return ""
|
||||
|
||||
@staticmethod
|
||||
def check_user(username):
|
||||
logger.debug("Checking IPS4 username %s" % username)
|
||||
cursor = connections['ips4'].cursor()
|
||||
cursor.execute(Ips4Manager.SQL_GET_ID, [username])
|
||||
row = cursor.fetchone()
|
||||
if row:
|
||||
logger.debug("Found user %s on IPS4" % username)
|
||||
return True
|
||||
logger.debug("User %s not found on IPS4" % username)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def update_custom_password(username, plain_password):
|
||||
logger.debug("Updating IPS4 user id %s password" % id)
|
||||
if Ips4Manager.check_user(username):
|
||||
hash = bcrypt.encrypt(plain_password, rounds=13)
|
||||
hash_result = hash
|
||||
rounds_striped = hash_result.strip('$2a$13$')
|
||||
salt = rounds_striped[:22]
|
||||
cursor = connections['ips4'].cursor()
|
||||
cursor.execute(Ips4Manager.SQL_UPDATE_PASSWORD, [hash, salt, username])
|
||||
return plain_password
|
||||
else:
|
||||
logger.error("Unable to update ips4 user %s password" % username)
|
||||
return ""
|
||||
@@ -1,145 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
import logging
|
||||
import os
|
||||
|
||||
from django.db import connections
|
||||
from passlib.hash import bcrypt
|
||||
|
||||
# requires yum install libffi-devel and pip install bcrypt
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class marketManager:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
SQL_ADD_USER = r"INSERT INTO fos_user (username, username_canonical, email, email_canonical, enabled, salt," \
|
||||
r"password, locked, expired, roles, credentials_expired, characterid, characterName)" \
|
||||
r"VALUES (%s, %s, %s, %s, 1,%s, %s, 0, 0, 'a:0:{}', 0, %s, %s) "
|
||||
SQL_GET_USER_ID = r"SELECT id FROM fos_user WHERE username = %s"
|
||||
SQL_DISABLE_USER = r"UPDATE fos_user SET enabled = '0' WHERE username = %s"
|
||||
SQL_ENABLE_USER = r"UPDATE fos_user SET enabled = '1' WHERE username = %s"
|
||||
SQL_UPDATE_PASSWORD = r"UPDATE fos_user SET password = %s, salt = %s WHERE username = %s"
|
||||
SQL_CHECK_EMAIL = r"SELECT email FROM fos_user WHERE email = %s"
|
||||
SQL_CHECK_USERNAME = r"SELECT username FROM fos_user WHERE username = %s"
|
||||
SQL_UPDATE_USER = r"UPDATE fos_user SET password = %s, salt = %s, enabled = '1' WHERE username = %s"
|
||||
|
||||
@staticmethod
|
||||
def __santatize_username(username):
|
||||
sanatized = username.replace(" ", "_")
|
||||
return sanatized.lower()
|
||||
|
||||
@staticmethod
|
||||
def __generate_random_pass():
|
||||
return os.urandom(8).encode('hex')
|
||||
|
||||
@staticmethod
|
||||
def check_username(username):
|
||||
logger.debug("Checking alliance market username %s" % username)
|
||||
cursor = connections['market'].cursor()
|
||||
cursor.execute(marketManager.SQL_CHECK_USERNAME, [marketManager.__santatize_username(username)])
|
||||
row = cursor.fetchone()
|
||||
if row:
|
||||
logger.debug("Found user %s on alliance market" % username)
|
||||
return True
|
||||
logger.debug("User %s not found on alliance market" % username)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def check_user_email(username, email):
|
||||
logger.debug("Checking if alliance market email exists for user %s" % username)
|
||||
cursor = connections['market'].cursor()
|
||||
cursor.execute(marketManager.SQL_CHECK_EMAIL, [email])
|
||||
row = cursor.fetchone()
|
||||
if row:
|
||||
logger.debug("Found user %s email address on alliance market" % username)
|
||||
return True
|
||||
logger.debug("User %s email address not found on alliance market" % username)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def add_user(username, email, characterid, charactername):
|
||||
logger.debug("Adding new market user %s" % username)
|
||||
plain_password = marketManager.__generate_random_pass()
|
||||
hash = bcrypt.encrypt(plain_password, rounds=13)
|
||||
hash_result = hash
|
||||
rounds_striped = hash_result.strip('$2a$13$')
|
||||
salt = rounds_striped[:22]
|
||||
username_clean = marketManager.__santatize_username(username)
|
||||
if not marketManager.check_username(username):
|
||||
if not marketManager.check_user_email(username, email):
|
||||
try:
|
||||
logger.debug("Adding user %s to alliance market" % username)
|
||||
cursor = connections['market'].cursor()
|
||||
cursor.execute(marketManager.SQL_ADD_USER, [username_clean, username_clean, email, email, salt,
|
||||
hash, characterid, charactername])
|
||||
return username_clean, plain_password
|
||||
except:
|
||||
logger.debug("Unsuccessful attempt to add market user %s" % username)
|
||||
return "", ""
|
||||
else:
|
||||
logger.debug("Alliance market email %s already exists Updating instead" % email)
|
||||
username_clean, password = marketManager.update_user_info(username)
|
||||
return username_clean, password
|
||||
else:
|
||||
logger.debug("Alliance market username %s already exists Updating instead" % username)
|
||||
username_clean, password = marketManager.update_user_info(username)
|
||||
return username_clean, password
|
||||
|
||||
@staticmethod
|
||||
def disable_user(username):
|
||||
logger.debug("Disabling alliance market user %s " % username)
|
||||
cursor = connections['market'].cursor()
|
||||
cursor.execute(marketManager.SQL_DISABLE_USER, [username])
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def update_custom_password(username, plain_password):
|
||||
logger.debug("Updating alliance market user %s password" % username)
|
||||
if marketManager.check_username(username):
|
||||
username_clean = marketManager.__santatize_username(username)
|
||||
hash = bcrypt.encrypt(plain_password, rounds=13)
|
||||
hash_result = hash
|
||||
rounds_striped = hash_result.strip('$2a$13$')
|
||||
salt = rounds_striped[:22]
|
||||
cursor = connections['market'].cursor()
|
||||
cursor.execute(marketManager.SQL_UPDATE_PASSWORD, [hash, salt, username_clean])
|
||||
return plain_password
|
||||
else:
|
||||
logger.error("Unable to update alliance market user %s password" % username)
|
||||
return ""
|
||||
|
||||
@staticmethod
|
||||
def update_user_password(username):
|
||||
logger.debug("Updating alliance market user %s password" % username)
|
||||
if marketManager.check_username(username):
|
||||
username_clean = marketManager.__santatize_username(username)
|
||||
plain_password = marketManager.__generate_random_pass()
|
||||
hash = bcrypt.encrypt(plain_password, rounds=13)
|
||||
hash_result = hash
|
||||
rounds_striped = hash_result.strip('$2a$13$')
|
||||
salt = rounds_striped[:22]
|
||||
cursor = connections['market'].cursor()
|
||||
cursor.execute(marketManager.SQL_UPDATE_PASSWORD, [hash, salt, username_clean])
|
||||
return plain_password
|
||||
else:
|
||||
logger.error("Unable to update alliance market user %s password" % username)
|
||||
return ""
|
||||
|
||||
@staticmethod
|
||||
def update_user_info(username):
|
||||
logger.debug("Updating alliance market user %s" % username)
|
||||
try:
|
||||
username_clean = marketManager.__santatize_username(username)
|
||||
plain_password = marketManager.__generate_random_pass()
|
||||
hash = bcrypt.encrypt(plain_password, rounds=13)
|
||||
hash_result = hash
|
||||
rounds_striped = hash_result.strip('$2a$13$')
|
||||
salt = rounds_striped[:22]
|
||||
cursor = connections['market'].cursor()
|
||||
cursor.execute(marketManager.SQL_UPDATE_USER, [hash, salt, username_clean])
|
||||
return username_clean, plain_password
|
||||
except:
|
||||
logger.debug("Alliance market update user failed for %s" % username)
|
||||
return "", ""
|
||||
@@ -1,121 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
import os
|
||||
import hashlib
|
||||
|
||||
from services.models import MumbleUser
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MumbleManager:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def __santatize_username(username):
|
||||
sanatized = username.replace(" ", "_")
|
||||
return sanatized
|
||||
|
||||
@staticmethod
|
||||
def __generate_random_pass():
|
||||
return os.urandom(8).encode('hex')
|
||||
|
||||
@staticmethod
|
||||
def __generate_username(username, corp_ticker):
|
||||
return "[" + corp_ticker + "]" + username
|
||||
|
||||
@staticmethod
|
||||
def __generate_username_blue(username, corp_ticker):
|
||||
return "[BLUE][" + corp_ticker + "]" + username
|
||||
|
||||
@staticmethod
|
||||
def _gen_pwhash(password):
|
||||
return hashlib.sha1(password).hexdigest()
|
||||
|
||||
@staticmethod
|
||||
def create_user(corp_ticker, username):
|
||||
logger.debug("Creating mumble user with username %s and ticker %s" % (username, corp_ticker))
|
||||
username_clean = MumbleManager.__santatize_username(MumbleManager.__generate_username(username, corp_ticker))
|
||||
password = MumbleManager.__generate_random_pass()
|
||||
pwhash = MumbleManager._gen_pwhash(password)
|
||||
logger.debug("Proceeding with mumble user creation: clean username %s, pwhash starts with %s" % (
|
||||
username_clean, pwhash[0:5]))
|
||||
if MumbleUser.objects.filter(username=username_clean).exists() is False:
|
||||
logger.info("Creating mumble user %s" % username_clean)
|
||||
MumbleUser.objects.create(username=username_clean, pwhash=pwhash)
|
||||
return username_clean, password
|
||||
else:
|
||||
logger.warn("Mumble user %s already exists. Updating password")
|
||||
model = MumbleUser.objects.get(username=username_clean)
|
||||
model.pwhash = pwhash
|
||||
model.save()
|
||||
logger.info("Updated mumble user %s" % username_clean)
|
||||
return username_clean, password
|
||||
|
||||
@staticmethod
|
||||
def create_blue_user(corp_ticker, username):
|
||||
logger.debug("Creating mumble blue user with username %s and ticker %s" % (username, corp_ticker))
|
||||
username_clean = MumbleManager.__santatize_username(
|
||||
MumbleManager.__generate_username_blue(username, corp_ticker))
|
||||
password = MumbleManager.__generate_random_pass()
|
||||
pwhash = MumbleManager._gen_pwhash(password)
|
||||
logger.debug("Proceeding with mumble user creation: clean username %s, pwhash starts with %s" % (
|
||||
username_clean, pwhash[0:5]))
|
||||
if MumbleUser.objects.filter(username=username_clean).exists() is False:
|
||||
logger.info("Creating mumble user %s" % username_clean)
|
||||
MumbleUser.objects.create(username=username_clean, pwhash=pwhash)
|
||||
return username_clean, password
|
||||
else:
|
||||
logger.warn("Mumble user %s already exists. Updating password")
|
||||
model = MumbleUser.objects.get(username=username_clean)
|
||||
model.pwhash = pwhash
|
||||
model.save()
|
||||
logger.info("Updated mumble user %s" % username_clean)
|
||||
return username_clean, password
|
||||
|
||||
@staticmethod
|
||||
def delete_user(username):
|
||||
logger.debug("Deleting user %s from mumble." % username)
|
||||
if MumbleUser.objects.filter(username=username).exists():
|
||||
MumbleUser.objects.filter(username=username).delete()
|
||||
logger.info("Deleted user %s from mumble" % username)
|
||||
return True
|
||||
logger.error("Unable to delete user %s from mumble: MumbleUser model not found" % username)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def update_user_password(username, password=None):
|
||||
logger.debug("Updating mumble user %s password." % username)
|
||||
if not password:
|
||||
password = MumbleManager.__generate_random_pass()
|
||||
pwhash = MumbleManager._gen_pwhash(password)
|
||||
logger.debug("Proceeding with mumble user %s password update - pwhash starts with %s" % (username, pwhash[0:5]))
|
||||
if MumbleUser.objects.filter(username=username).exists():
|
||||
model = MumbleUser.objects.get(username=username)
|
||||
model.pwhash = pwhash
|
||||
model.save()
|
||||
return password
|
||||
logger.error("User %s not found on mumble. Unable to update password." % username)
|
||||
return ""
|
||||
|
||||
@staticmethod
|
||||
def update_groups(username, groups):
|
||||
logger.debug("Updating mumble user %s groups %s" % (username, groups))
|
||||
safe_groups = list(set([g.replace(' ', '-') for g in groups]))
|
||||
groups = ''
|
||||
for g in safe_groups:
|
||||
groups = groups + g + ','
|
||||
groups = groups.strip(',')
|
||||
if MumbleUser.objects.filter(username=username).exists():
|
||||
logger.info("Updating mumble user %s groups to %s" % (username, safe_groups))
|
||||
model = MumbleUser.objects.get(username=username)
|
||||
model.groups = groups
|
||||
model.save()
|
||||
else:
|
||||
logger.error("User %s not found on mumble. Unable to update groups." % username)
|
||||
|
||||
@staticmethod
|
||||
def user_exists(username):
|
||||
return MumbleUser.objects.filter(username=username).exists()
|
||||
@@ -1,200 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
from django.utils import six
|
||||
import re
|
||||
import os
|
||||
try:
|
||||
from urlparse import urlparse
|
||||
except ImportError:
|
||||
# python 3
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import sleekxmpp
|
||||
from django.conf import settings
|
||||
import threading
|
||||
from ofrestapi.users import Users as ofUsers
|
||||
from ofrestapi import exception
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OpenfireManager:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def send_broadcast_threaded(group_name, broadcast_message):
|
||||
logger.debug("Starting broadcast to %s with message %s" % (group_name, broadcast_message))
|
||||
broadcast_thread = XmppThread(1, "XMPP Broadcast Thread", 1, group_name, broadcast_message)
|
||||
broadcast_thread.start()
|
||||
|
||||
@staticmethod
|
||||
def __add_address_to_username(username):
|
||||
address = urlparse(settings.OPENFIRE_ADDRESS).netloc.split(":")[0]
|
||||
completed_username = username + "@" + address
|
||||
return completed_username
|
||||
|
||||
@staticmethod
|
||||
def __santatize_username(username):
|
||||
sanatized = username.replace(" ", "_")
|
||||
return sanatized.lower()
|
||||
|
||||
@staticmethod
|
||||
def __generate_random_pass():
|
||||
return os.urandom(8).encode('hex')
|
||||
|
||||
@staticmethod
|
||||
def _sanitize_groupname(name):
|
||||
name = name.strip(' _')
|
||||
return re.sub('[^\w.-]', '', name)
|
||||
|
||||
@staticmethod
|
||||
def add_user(username):
|
||||
logger.debug("Adding username %s to openfire." % username)
|
||||
try:
|
||||
sanatized_username = OpenfireManager.__santatize_username(username)
|
||||
password = OpenfireManager.__generate_random_pass()
|
||||
api = ofUsers(settings.OPENFIRE_ADDRESS, settings.OPENFIRE_SECRET_KEY)
|
||||
api.add_user(sanatized_username, password)
|
||||
logger.info("Added openfire user %s" % username)
|
||||
except exception.UserAlreadyExistsException:
|
||||
# User exist
|
||||
logger.error("Attempting to add a user %s to openfire which already exists on server." % username)
|
||||
return "", ""
|
||||
|
||||
return sanatized_username, password
|
||||
|
||||
@staticmethod
|
||||
def delete_user(username):
|
||||
logger.debug("Deleting user %s from openfire." % username)
|
||||
try:
|
||||
api = ofUsers(settings.OPENFIRE_ADDRESS, settings.OPENFIRE_SECRET_KEY)
|
||||
api.delete_user(username)
|
||||
logger.info("Deleted user %s from openfire." % username)
|
||||
return True
|
||||
except exception.UserNotFoundException:
|
||||
logger.error("Attempting to delete a user %s from openfire which was not found on server." % username)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def lock_user(username):
|
||||
logger.debug("Locking openfire user %s" % username)
|
||||
api = ofUsers(settings.OPENFIRE_ADDRESS, settings.OPENFIRE_SECRET_KEY)
|
||||
api.lock_user(username)
|
||||
logger.info("Locked openfire user %s" % username)
|
||||
|
||||
@staticmethod
|
||||
def unlock_user(username):
|
||||
logger.debug("Unlocking openfire user %s" % username)
|
||||
api = ofUsers(settings.OPENFIRE_ADDRESS, settings.OPENFIRE_SECRET_KEY)
|
||||
api.unlock_user(username)
|
||||
logger.info("Unlocked openfire user %s" % username)
|
||||
|
||||
@staticmethod
|
||||
def update_user_pass(username, password=None):
|
||||
logger.debug("Updating openfire user %s password." % username)
|
||||
try:
|
||||
if not password:
|
||||
password = OpenfireManager.__generate_random_pass()
|
||||
api = ofUsers(settings.OPENFIRE_ADDRESS, settings.OPENFIRE_SECRET_KEY)
|
||||
api.update_user(username, password=password)
|
||||
logger.info("Updated openfire user %s password." % username)
|
||||
return password
|
||||
except exception.UserNotFoundException:
|
||||
logger.error("Unable to update openfire user %s password - user not found on server." % username)
|
||||
return ""
|
||||
|
||||
@staticmethod
|
||||
def update_user_groups(username, groups):
|
||||
logger.debug("Updating openfire user %s groups %s" % (username, groups))
|
||||
api = ofUsers(settings.OPENFIRE_ADDRESS, settings.OPENFIRE_SECRET_KEY)
|
||||
response = api.get_user_groups(username)
|
||||
remote_groups = []
|
||||
if response:
|
||||
remote_groups = response['groupname']
|
||||
if isinstance(remote_groups, six.string_types):
|
||||
remote_groups = [remote_groups]
|
||||
logger.debug("Openfire user %s has groups %s" % (username, remote_groups))
|
||||
add_groups = []
|
||||
del_groups = []
|
||||
for g in groups:
|
||||
g = OpenfireManager._sanitize_groupname(g)
|
||||
if g not in remote_groups:
|
||||
add_groups.append(g)
|
||||
for g in remote_groups:
|
||||
g = OpenfireManager._sanitize_groupname(g)
|
||||
if g not in groups:
|
||||
del_groups.append(g)
|
||||
logger.info(
|
||||
"Updating openfire groups for user %s - adding %s, removing %s" % (username, add_groups, del_groups))
|
||||
if add_groups:
|
||||
api.add_user_groups(username, add_groups)
|
||||
if del_groups:
|
||||
api.delete_user_groups(username, del_groups)
|
||||
|
||||
@staticmethod
|
||||
def delete_user_groups(username, groups):
|
||||
logger.debug("Deleting openfire groups %s from user %s" % (groups, username))
|
||||
api = ofUsers(settings.OPENFIRE_ADDRESS, settings.OPENFIRE_SECRET_KEY)
|
||||
api.delete_user_groups(username, groups)
|
||||
logger.info("Deleted groups %s from openfire user %s" % (groups, username))
|
||||
|
||||
@staticmethod
|
||||
def send_broadcast_message(group_name, broadcast_message):
|
||||
logger.debug("Sending jabber ping to group %s with message %s" % (group_name, broadcast_message))
|
||||
to_address = group_name + '@' + settings.BROADCAST_SERVICE_NAME + '.' + settings.JABBER_URL
|
||||
xmpp = PingBot(settings.BROADCAST_USER, settings.BROADCAST_USER_PASSWORD, to_address, broadcast_message)
|
||||
xmpp.register_plugin('xep_0030') # Service Discovery
|
||||
xmpp.register_plugin('xep_0199') # XMPP Ping
|
||||
if xmpp.connect():
|
||||
xmpp.process(block=True)
|
||||
logger.info("Sent jabber ping to group %s" % group_name)
|
||||
else:
|
||||
raise ValueError("Unable to connect to jabber server.")
|
||||
|
||||
|
||||
class PingBot(sleekxmpp.ClientXMPP):
|
||||
"""
|
||||
A copy-paste of the example client bot from
|
||||
http://sleekxmpp.com/getting_started/sendlogout.html
|
||||
"""
|
||||
def __init__(self, jid, password, recipient, message):
|
||||
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||
|
||||
# The message we wish to send, and the JID that
|
||||
# will receive it.
|
||||
self.recipient = recipient
|
||||
self.msg = message
|
||||
|
||||
# The session_start event will be triggered when
|
||||
# the bot establishes its connection with the server
|
||||
# and the XML streams are ready for use. We want to
|
||||
# listen for this event so that we we can initialize
|
||||
# our roster.
|
||||
self.add_event_handler("session_start", self.start)
|
||||
|
||||
def start(self, event):
|
||||
self.send_presence()
|
||||
self.get_roster()
|
||||
|
||||
self.send_message(mto=self.recipient,
|
||||
mbody=self.msg,
|
||||
mtype='chat')
|
||||
|
||||
# Using wait=True ensures that the send queue will be
|
||||
# emptied before ending the session.
|
||||
self.disconnect(wait=True)
|
||||
|
||||
|
||||
class XmppThread(threading.Thread):
|
||||
def __init__(self, thread_id, name, counter, group, message, ):
|
||||
threading.Thread.__init__(self)
|
||||
self.threadID = thread_id
|
||||
self.name = name
|
||||
self.counter = counter
|
||||
self.group = group
|
||||
self.message = message
|
||||
|
||||
def run(self):
|
||||
OpenfireManager.send_broadcast_message(self.group, self.message)
|
||||
@@ -1,301 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
import os
|
||||
import calendar
|
||||
import re
|
||||
from datetime import datetime
|
||||
|
||||
from passlib.apps import phpbb3_context
|
||||
from django.db import connections
|
||||
|
||||
import logging
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Phpbb3Manager:
|
||||
SQL_ADD_USER = r"INSERT INTO phpbb_users (username, username_clean, " \
|
||||
r"user_password, user_email, group_id, user_regdate, user_permissions, " \
|
||||
r"user_sig) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)"
|
||||
|
||||
SQL_DEL_USER = r"DELETE FROM phpbb_users where username = %s"
|
||||
|
||||
SQL_DIS_USER = r"UPDATE phpbb_users SET user_email= %s, user_password=%s WHERE username = %s"
|
||||
|
||||
SQL_USER_ID_FROM_USERNAME = r"SELECT user_id from phpbb_users WHERE username = %s"
|
||||
|
||||
SQL_ADD_USER_GROUP = r"INSERT INTO phpbb_user_group (group_id, user_id, user_pending) VALUES (%s, %s, %s)"
|
||||
|
||||
SQL_GET_GROUP_ID = r"SELECT group_id from phpbb_groups WHERE group_name = %s"
|
||||
|
||||
SQL_ADD_GROUP = r"INSERT INTO phpbb_groups (group_name,group_desc,group_legend) VALUES (%s,%s,0)"
|
||||
|
||||
SQL_UPDATE_USER_PASSWORD = r"UPDATE phpbb_users SET user_password = %s WHERE username = %s"
|
||||
|
||||
SQL_REMOVE_USER_GROUP = r"DELETE FROM phpbb_user_group WHERE user_id=%s AND group_id=%s "
|
||||
|
||||
SQL_GET_ALL_GROUPS = r"SELECT group_id, group_name FROM phpbb_groups"
|
||||
|
||||
SQL_GET_USER_GROUPS = r"SELECT phpbb_groups.group_name FROM phpbb_groups , phpbb_user_group WHERE " \
|
||||
r"phpbb_user_group.group_id = phpbb_groups.group_id AND user_id=%s"
|
||||
|
||||
SQL_ADD_USER_AVATAR = r"UPDATE phpbb_users SET user_avatar_type=2, user_avatar_width=64, user_avatar_height=64, " \
|
||||
"user_avatar=%s WHERE user_id = %s"
|
||||
|
||||
SQL_CLEAR_USER_PERMISSIONS = r"UPDATE phpbb_users SET user_permissions = '' WHERE user_Id = %s"
|
||||
|
||||
SQL_DEL_SESSION = r"DELETE FROM phpbb_sessions where session_user_id = %s"
|
||||
|
||||
SQL_DEL_AUTOLOGIN = r"DELETE FROM phpbb_sessions_keys where user_id = %s"
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def __add_avatar(username, characterid):
|
||||
logger.debug("Adding EVE character id %s portrait as phpbb avater for user %s" % (characterid, username))
|
||||
avatar_url = "https://image.eveonline.com/Character/" + characterid + "_64.jpg"
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
userid = Phpbb3Manager.__get_user_id(username)
|
||||
cursor.execute(Phpbb3Manager.SQL_ADD_USER_AVATAR, [avatar_url, userid])
|
||||
|
||||
@staticmethod
|
||||
def __generate_random_pass():
|
||||
return os.urandom(8).encode('hex')
|
||||
|
||||
@staticmethod
|
||||
def __gen_hash(password):
|
||||
return phpbb3_context.encrypt(password)
|
||||
|
||||
@staticmethod
|
||||
def __santatize_username(username):
|
||||
sanatized = username.replace(" ", "_")
|
||||
sanatized = sanatized.replace("'", "_")
|
||||
return sanatized.lower()
|
||||
|
||||
@staticmethod
|
||||
def _sanitize_groupname(name):
|
||||
name = name.strip(' _')
|
||||
return re.sub('[^\w.-]', '', name)
|
||||
|
||||
@staticmethod
|
||||
def __get_group_id(groupname):
|
||||
logger.debug("Getting phpbb3 group id for groupname %s" % groupname)
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
cursor.execute(Phpbb3Manager.SQL_GET_GROUP_ID, [groupname])
|
||||
row = cursor.fetchone()
|
||||
logger.debug("Got phpbb group id %s for groupname %s" % (row[0], groupname))
|
||||
return row[0]
|
||||
|
||||
@staticmethod
|
||||
def __get_user_id(username):
|
||||
logger.debug("Getting phpbb3 user id for username %s" % username)
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
cursor.execute(Phpbb3Manager.SQL_USER_ID_FROM_USERNAME, [username])
|
||||
row = cursor.fetchone()
|
||||
if row is not None:
|
||||
logger.debug("Got phpbb user id %s for username %s" % (row[0], username))
|
||||
return row[0]
|
||||
else:
|
||||
logger.error("Username %s not found on phpbb. Unable to determine user id." % username)
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def __get_all_groups():
|
||||
logger.debug("Getting all phpbb3 groups.")
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
cursor.execute(Phpbb3Manager.SQL_GET_ALL_GROUPS)
|
||||
rows = cursor.fetchall()
|
||||
out = {}
|
||||
for row in rows:
|
||||
out[row[1]] = row[0]
|
||||
logger.debug("Got phpbb groups %s" % out)
|
||||
return out
|
||||
|
||||
@staticmethod
|
||||
def __get_user_groups(userid):
|
||||
logger.debug("Getting phpbb3 user id %s groups" % userid)
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
cursor.execute(Phpbb3Manager.SQL_GET_USER_GROUPS, [userid])
|
||||
out = [row[0] for row in cursor.fetchall()]
|
||||
logger.debug("Got user %s phpbb groups %s" % (userid, out))
|
||||
return out
|
||||
|
||||
@staticmethod
|
||||
def __get_current_utc_date():
|
||||
d = datetime.utcnow()
|
||||
unixtime = calendar.timegm(d.utctimetuple())
|
||||
return unixtime
|
||||
|
||||
@staticmethod
|
||||
def __create_group(groupname):
|
||||
logger.debug("Creating phpbb3 group %s" % groupname)
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
cursor.execute(Phpbb3Manager.SQL_ADD_GROUP, [groupname, groupname])
|
||||
logger.info("Created phpbb group %s" % groupname)
|
||||
return Phpbb3Manager.__get_group_id(groupname)
|
||||
|
||||
@staticmethod
|
||||
def __add_user_to_group(userid, groupid):
|
||||
logger.debug("Adding phpbb3 user id %s to group id %s" % (userid, groupid))
|
||||
try:
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
cursor.execute(Phpbb3Manager.SQL_ADD_USER_GROUP, [groupid, userid, 0])
|
||||
cursor.execute(Phpbb3Manager.SQL_CLEAR_USER_PERMISSIONS, [userid])
|
||||
logger.info("Added phpbb user id %s to group id %s" % (userid, groupid))
|
||||
except:
|
||||
logger.exception("Unable to add phpbb user id %s to group id %s" % (userid, groupid))
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def __remove_user_from_group(userid, groupid):
|
||||
logger.debug("Removing phpbb3 user id %s from group id %s" % (userid, groupid))
|
||||
try:
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
cursor.execute(Phpbb3Manager.SQL_REMOVE_USER_GROUP, [userid, groupid])
|
||||
cursor.execute(Phpbb3Manager.SQL_CLEAR_USER_PERMISSIONS, [userid])
|
||||
logger.info("Removed phpbb user id %s from group id %s" % (userid, groupid))
|
||||
except:
|
||||
logger.exception("Unable to remove phpbb user id %s from group id %s" % (userid, groupid))
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def add_user(username, email, groups, characterid):
|
||||
logger.debug("Adding phpbb user with username %s, email %s, groups %s, characterid %s" % (
|
||||
username, email, groups, characterid))
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
|
||||
username_clean = Phpbb3Manager.__santatize_username(username)
|
||||
password = Phpbb3Manager.__generate_random_pass()
|
||||
pwhash = Phpbb3Manager.__gen_hash(password)
|
||||
logger.debug("Proceeding to add phpbb user %s and pwhash starting with %s" % (username_clean, pwhash[0:5]))
|
||||
# check if the username was simply revoked
|
||||
if Phpbb3Manager.check_user(username_clean):
|
||||
logger.warn("Unable to add phpbb user with username %s - already exists. Updating user instead." % username)
|
||||
Phpbb3Manager.__update_user_info(username_clean, email, pwhash)
|
||||
else:
|
||||
try:
|
||||
|
||||
cursor.execute(Phpbb3Manager.SQL_ADD_USER, [username_clean, username_clean, pwhash,
|
||||
email, 2, Phpbb3Manager.__get_current_utc_date(),
|
||||
"", ""])
|
||||
Phpbb3Manager.update_groups(username_clean, groups)
|
||||
Phpbb3Manager.__add_avatar(username_clean, characterid)
|
||||
logger.info("Added phpbb user %s" % username_clean)
|
||||
except:
|
||||
logger.exception("Unable to add phpbb user %s" % username_clean)
|
||||
pass
|
||||
|
||||
return username_clean, password
|
||||
|
||||
@staticmethod
|
||||
def disable_user(username):
|
||||
logger.debug("Disabling phpbb user %s" % username)
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
|
||||
password = Phpbb3Manager.__gen_hash(Phpbb3Manager.__generate_random_pass())
|
||||
revoke_email = "revoked@" + settings.DOMAIN
|
||||
try:
|
||||
pwhash = Phpbb3Manager.__gen_hash(password)
|
||||
cursor.execute(Phpbb3Manager.SQL_DIS_USER, [revoke_email, pwhash, username])
|
||||
userid = Phpbb3Manager.__get_user_id(username)
|
||||
cursor.execute(Phpbb3Manager.SQL_DEL_AUTOLOGIN, [userid])
|
||||
cursor.execute(Phpbb3Manager.SQL_DEL_SESSION, [userid])
|
||||
Phpbb3Manager.update_groups(username, [])
|
||||
logger.info("Disabled phpbb user %s" % username)
|
||||
return True
|
||||
except TypeError:
|
||||
logger.exception("TypeError occured while disabling user %s - failed to disable." % username)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def delete_user(username):
|
||||
logger.debug("Deleting phpbb user %s" % username)
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
|
||||
if Phpbb3Manager.check_user(username):
|
||||
cursor.execute(Phpbb3Manager.SQL_DEL_USER, [username])
|
||||
logger.info("Deleted phpbb user %s" % username)
|
||||
return True
|
||||
logger.error("Unable to delete phpbb user %s - user not found on phpbb." % username)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def update_groups(username, groups):
|
||||
userid = Phpbb3Manager.__get_user_id(username)
|
||||
logger.debug("Updating phpbb user %s with id %s groups %s" % (username, userid, groups))
|
||||
if userid is not None:
|
||||
forum_groups = Phpbb3Manager.__get_all_groups()
|
||||
user_groups = set(Phpbb3Manager.__get_user_groups(userid))
|
||||
act_groups = set([Phpbb3Manager._sanitize_groupname(g) for g in groups])
|
||||
addgroups = act_groups - user_groups
|
||||
remgroups = user_groups - act_groups
|
||||
logger.info("Updating phpbb user %s groups - adding %s, removing %s" % (username, addgroups, remgroups))
|
||||
for g in addgroups:
|
||||
if not g in forum_groups:
|
||||
forum_groups[g] = Phpbb3Manager.__create_group(g)
|
||||
Phpbb3Manager.__add_user_to_group(userid, forum_groups[g])
|
||||
|
||||
for g in remgroups:
|
||||
Phpbb3Manager.__remove_user_from_group(userid, forum_groups[g])
|
||||
|
||||
@staticmethod
|
||||
def remove_group(username, group):
|
||||
logger.debug("Removing phpbb user %s from group %s" % (username, group))
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
userid = Phpbb3Manager.__get_user_id(username)
|
||||
if userid is not None:
|
||||
groupid = Phpbb3Manager.__get_group_id(group)
|
||||
|
||||
if userid:
|
||||
if groupid:
|
||||
try:
|
||||
cursor.execute(Phpbb3Manager.SQL_REMOVE_USER_GROUP, [userid, groupid])
|
||||
logger.info("Removed phpbb user %s from group %s" % (username, group))
|
||||
except:
|
||||
logger.exception(
|
||||
"Exception prevented removal of phpbb user %s with id %s from group %s with id %s" % (
|
||||
username, userid, group, groupid))
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def check_user(username):
|
||||
logger.debug("Checking phpbb username %s" % username)
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
cursor.execute(Phpbb3Manager.SQL_USER_ID_FROM_USERNAME, [Phpbb3Manager.__santatize_username(username)])
|
||||
row = cursor.fetchone()
|
||||
if row:
|
||||
logger.debug("Found user %s on phpbb" % username)
|
||||
return True
|
||||
logger.debug("User %s not found on phpbb" % username)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def update_user_password(username, characterid, password=None):
|
||||
logger.debug("Updating phpbb user %s password" % username)
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
if not password:
|
||||
password = Phpbb3Manager.__generate_random_pass()
|
||||
if Phpbb3Manager.check_user(username):
|
||||
pwhash = Phpbb3Manager.__gen_hash(password)
|
||||
logger.debug(
|
||||
"Proceeding to update phpbb user %s password with pwhash starting with %s" % (username, pwhash[0:5]))
|
||||
cursor.execute(Phpbb3Manager.SQL_UPDATE_USER_PASSWORD, [pwhash, username])
|
||||
Phpbb3Manager.__add_avatar(username, characterid)
|
||||
logger.info("Updated phpbb user %s password." % username)
|
||||
return password
|
||||
logger.error("Unable to update phpbb user %s password - user not found on phpbb." % username)
|
||||
return ""
|
||||
|
||||
@staticmethod
|
||||
def __update_user_info(username, email, password):
|
||||
logger.debug(
|
||||
"Updating phpbb user %s info: username %s password of length %s" % (username, email, len(password)))
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
try:
|
||||
cursor.execute(Phpbb3Manager.SQL_DIS_USER, [email, password, username])
|
||||
logger.info("Updated phpbb user %s info" % username)
|
||||
except:
|
||||
logger.exception("Unable to update phpbb user %s info." % username)
|
||||
pass
|
||||
@@ -1,266 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
import os
|
||||
import calendar
|
||||
from datetime import datetime
|
||||
import hashlib
|
||||
import logging
|
||||
import re
|
||||
|
||||
from django.db import connections
|
||||
from django.conf import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class smfManager:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
SQL_ADD_USER = r"INSERT INTO smf_members (member_name, passwd, email_address, date_registered, real_name," \
|
||||
r" buddy_list, message_labels, openid_uri, signature, ignore_boards) " \
|
||||
r"VALUES (%s, %s, %s, %s, %s, 0, 0, 0, 0, 0)"
|
||||
|
||||
SQL_DEL_USER = r"DELETE FROM smf_members where member_name = %s"
|
||||
|
||||
SQL_DIS_USER = r"UPDATE smf_members SET email_address = %s, passwd = %s WHERE member_name = %s"
|
||||
|
||||
SQL_USER_ID_FROM_USERNAME = r"SELECT id_member from smf_members WHERE member_name = %s"
|
||||
|
||||
SQL_ADD_USER_GROUP = r"UPDATE smf_members SET additional_groups = %s WHERE id_member = %s"
|
||||
|
||||
SQL_GET_GROUP_ID = r"SELECT id_group from smf_membergroups WHERE group_name = %s"
|
||||
|
||||
SQL_ADD_GROUP = r"INSERT INTO smf_membergroups (group_name,description) VALUES (%s,%s)"
|
||||
|
||||
SQL_UPDATE_USER_PASSWORD = r"UPDATE smf_members SET passwd = %s WHERE member_name = %s"
|
||||
|
||||
SQL_REMOVE_USER_GROUP = r"UPDATE smf_members SET additional_groups = %s WHERE id_member = %s"
|
||||
|
||||
SQL_GET_ALL_GROUPS = r"SELECT id_group, group_name FROM smf_membergroups"
|
||||
|
||||
SQL_GET_USER_GROUPS = r"SELECT additional_groups FROM smf_members WHERE id_member = %s"
|
||||
|
||||
SQL_ADD_USER_AVATAR = r"UPDATE smf_members SET avatar = %s WHERE id_member = %s"
|
||||
|
||||
@staticmethod
|
||||
def _sanitize_groupname(name):
|
||||
name = name.strip(' _')
|
||||
return re.sub('[^\w.-]', '', name)
|
||||
|
||||
@staticmethod
|
||||
def generate_random_pass():
|
||||
return os.urandom(8).encode('hex')
|
||||
|
||||
@staticmethod
|
||||
def gen_hash(username_clean, passwd):
|
||||
return hashlib.sha1(username_clean + passwd).hexdigest()
|
||||
|
||||
@staticmethod
|
||||
def santatize_username(username):
|
||||
sanatized = username.replace(" ", "_")
|
||||
sanatized = sanatized.replace("'", "_")
|
||||
return sanatized.lower()
|
||||
|
||||
@staticmethod
|
||||
def get_current_utc_date():
|
||||
d = datetime.utcnow()
|
||||
unixtime = calendar.timegm(d.utctimetuple())
|
||||
return unixtime
|
||||
|
||||
@staticmethod
|
||||
def create_group(groupname):
|
||||
logger.debug("Creating smf group %s" % groupname)
|
||||
cursor = connections['smf'].cursor()
|
||||
cursor.execute(smfManager.SQL_ADD_GROUP, [groupname, groupname])
|
||||
logger.info("Created smf group %s" % groupname)
|
||||
return smfManager.get_group_id(groupname)
|
||||
|
||||
@staticmethod
|
||||
def get_group_id(groupname):
|
||||
logger.debug("Getting smf group id for groupname %s" % groupname)
|
||||
cursor = connections['smf'].cursor()
|
||||
cursor.execute(smfManager.SQL_GET_GROUP_ID, [groupname])
|
||||
row = cursor.fetchone()
|
||||
logger.debug("Got smf group id %s for groupname %s" % (row[0], groupname))
|
||||
return row[0]
|
||||
|
||||
@staticmethod
|
||||
def check_user(username):
|
||||
logger.debug("Checking smf username %s" % username)
|
||||
cursor = connections['smf'].cursor()
|
||||
cursor.execute(smfManager.SQL_USER_ID_FROM_USERNAME, [smfManager.santatize_username(username)])
|
||||
row = cursor.fetchone()
|
||||
if row:
|
||||
logger.debug("Found user %s on smf" % username)
|
||||
return True
|
||||
logger.debug("User %s not found on smf" % username)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def add_avatar(member_name, characterid):
|
||||
logger.debug("Adding EVE character id %s portrait as smf avatar for user %s" % (characterid, member_name))
|
||||
avatar_url = "https://image.eveonline.com/Character/" + characterid + "_64.jpg"
|
||||
cursor = connections['smf'].cursor()
|
||||
id_member = smfManager.get_user_id(member_name)
|
||||
cursor.execute(smfManager.SQL_ADD_USER_AVATAR, [avatar_url, id_member])
|
||||
|
||||
@staticmethod
|
||||
def get_user_id(username):
|
||||
logger.debug("Getting smf user id for username %s" % username)
|
||||
cursor = connections['smf'].cursor()
|
||||
cursor.execute(smfManager.SQL_USER_ID_FROM_USERNAME, [username])
|
||||
row = cursor.fetchone()
|
||||
if row is not None:
|
||||
logger.debug("Got smf user id %s for username %s" % (row[0], username))
|
||||
return row[0]
|
||||
else:
|
||||
logger.error("username %s not found on smf. Unable to determine user id ." % username)
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def get_all_groups():
|
||||
logger.debug("Getting all smf groups.")
|
||||
cursor = connections['smf'].cursor()
|
||||
cursor.execute(smfManager.SQL_GET_ALL_GROUPS)
|
||||
rows = cursor.fetchall()
|
||||
out = {}
|
||||
for row in rows:
|
||||
out[row[1]] = row[0]
|
||||
logger.debug("Got smf groups %s" % out)
|
||||
return out
|
||||
|
||||
@staticmethod
|
||||
def get_user_groups(userid):
|
||||
logger.debug("Getting smf user id %s groups" % userid)
|
||||
cursor = connections['smf'].cursor()
|
||||
cursor.execute(smfManager.SQL_GET_USER_GROUPS, [userid])
|
||||
out = [row[0] for row in cursor.fetchall()]
|
||||
logger.debug("Got user %s smf groups %s" % (userid, out))
|
||||
return out
|
||||
|
||||
@staticmethod
|
||||
def add_user(username, email_address, groups, characterid):
|
||||
logger.debug("Adding smf user with member_name %s, email_address %s, characterid %s" % (
|
||||
username, email_address, characterid))
|
||||
cursor = connections['smf'].cursor()
|
||||
username_clean = smfManager.santatize_username(username)
|
||||
passwd = smfManager.generate_random_pass()
|
||||
pwhash = smfManager.gen_hash(username_clean, passwd)
|
||||
logger.debug("Proceeding to add smf user %s and pwhash starting with %s" % (username, pwhash[0:5]))
|
||||
register_date = smfManager.get_current_utc_date()
|
||||
# check if the username was simply revoked
|
||||
if smfManager.check_user(username) is True:
|
||||
logger.warn("Unable to add smf user with username %s - already exists. Updating user instead." % username)
|
||||
smfManager.__update_user_info(username_clean, email_address, pwhash)
|
||||
else:
|
||||
try:
|
||||
cursor.execute(smfManager.SQL_ADD_USER,
|
||||
[username_clean, passwd, email_address, register_date, username_clean])
|
||||
smfManager.add_avatar(username_clean, characterid)
|
||||
logger.info("Added smf member_name %s" % username_clean)
|
||||
smfManager.update_groups(username_clean, groups)
|
||||
except:
|
||||
logger.warn("Unable to add smf user %s" % username_clean)
|
||||
pass
|
||||
return username_clean, passwd
|
||||
|
||||
@staticmethod
|
||||
def __update_user_info(username, email_address, passwd):
|
||||
logger.debug(
|
||||
"Updating smf user %s info: username %s password of length %s" % (username, email_address, len(passwd)))
|
||||
cursor = connections['smf'].cursor()
|
||||
try:
|
||||
cursor.execute(smfManager.SQL_DIS_USER, [email_address, passwd, username])
|
||||
logger.info("Updated smf user %s info" % username)
|
||||
except:
|
||||
logger.exception("Unable to update smf user %s info." % username)
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def delete_user(username):
|
||||
logger.debug("Deleting smf user %s" % username)
|
||||
cursor = connections['smf'].cursor()
|
||||
|
||||
if smfManager.check_user(username):
|
||||
cursor.execute(smfManager.SQL_DEL_USER, [username])
|
||||
logger.info("Deleted smf user %s" % username)
|
||||
return True
|
||||
logger.error("Unable to delete smf user %s - user not found on smf." % username)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def update_groups(username, groups):
|
||||
userid = smfManager.get_user_id(username)
|
||||
logger.debug("Updating smf user %s with id %s groups %s" % (username, userid, groups))
|
||||
if userid is not None:
|
||||
forum_groups = smfManager.get_all_groups()
|
||||
user_groups = set(smfManager.get_user_groups(userid))
|
||||
act_groups = set([smfManager._sanitize_groupname(g) for g in groups])
|
||||
addgroups = act_groups - user_groups
|
||||
remgroups = user_groups - act_groups
|
||||
logger.info("Updating smf user %s groups - adding %s, removing %s" % (username, addgroups, remgroups))
|
||||
act_group_id = set()
|
||||
for g in addgroups:
|
||||
if g not in forum_groups:
|
||||
forum_groups[g] = smfManager.create_group(g)
|
||||
act_group_id.add(str(smfManager.get_group_id(g)))
|
||||
string_groups = ','.join(act_group_id)
|
||||
smfManager.add_user_to_group(userid, string_groups)
|
||||
|
||||
@staticmethod
|
||||
def add_user_to_group(userid, groupid):
|
||||
logger.debug("Adding smf user id %s to group id %s" % (userid, groupid))
|
||||
try:
|
||||
cursor = connections['smf'].cursor()
|
||||
cursor.execute(smfManager.SQL_ADD_USER_GROUP, [groupid, userid])
|
||||
logger.info("Added smf user id %s to group id %s" % (userid, groupid))
|
||||
except:
|
||||
logger.exception("Unable to add smf user id %s to group id %s" % (userid, groupid))
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def remove_user_from_group(userid, groupid):
|
||||
logger.debug("Removing smf user id %s from group id %s" % (userid, groupid))
|
||||
try:
|
||||
cursor = connections['smf'].cursor()
|
||||
cursor.execute(smfManager.SQL_REMOVE_USER_GROUP, [groupid, userid])
|
||||
logger.info("Removed smf user id %s from group id %s" % (userid, groupid))
|
||||
except:
|
||||
logger.exception("Unable to remove smf user id %s from group id %s" % (userid, groupid))
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def disable_user(username):
|
||||
logger.debug("Disabling smf user %s" % username)
|
||||
cursor = connections['smf'].cursor()
|
||||
|
||||
password = smfManager.generate_random_pass()
|
||||
revoke_email = "revoked@" + settings.DOMAIN
|
||||
try:
|
||||
pwhash = smfManager.gen_hash(username, password)
|
||||
cursor.execute(smfManager.SQL_DIS_USER, [revoke_email, pwhash, username])
|
||||
smfManager.get_user_id(username)
|
||||
smfManager.update_groups(username, [])
|
||||
logger.info("Disabled smf user %s" % username)
|
||||
return True
|
||||
except TypeError:
|
||||
logger.exception("TypeError occured while disabling user %s - failed to disable." % username)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def update_user_password(username, characterid, password=None):
|
||||
logger.debug("Updating smf user %s password" % username)
|
||||
cursor = connections['smf'].cursor()
|
||||
if not password:
|
||||
password = smfManager.generate_random_pass()
|
||||
if smfManager.check_user(username):
|
||||
username_clean = smfManager.santatize_username(username)
|
||||
pwhash = smfManager.gen_hash(username_clean, password)
|
||||
logger.debug(
|
||||
"Proceeding to update smf user %s password with pwhash starting with %s" % (username, pwhash[0:5]))
|
||||
cursor.execute(smfManager.SQL_UPDATE_USER_PASSWORD, [pwhash, username])
|
||||
smfManager.add_avatar(username, characterid)
|
||||
logger.info("Updated smf user %s password." % username)
|
||||
return password
|
||||
logger.error("Unable to update smf user %s password - user not found on smf." % username)
|
||||
return ""
|
||||
@@ -1,314 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
from django.conf import settings
|
||||
|
||||
from services.managers.util.ts3 import TS3Server, TeamspeakError
|
||||
from services.models import TSgroup
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Teamspeak3Manager:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def __get_created_server():
|
||||
server = TS3Server(settings.TEAMSPEAK3_SERVER_IP, settings.TEAMSPEAK3_SERVER_PORT)
|
||||
server.login(settings.TEAMSPEAK3_SERVERQUERY_USER, settings.TEAMSPEAK3_SERVERQUERY_PASSWORD)
|
||||
server.use(settings.TEAMSPEAK3_VIRTUAL_SERVER)
|
||||
logger.debug("Got TS3 server instance based on settings.")
|
||||
return server
|
||||
|
||||
@staticmethod
|
||||
def __santatize_username(username):
|
||||
sanatized = username.replace(" ", "_")
|
||||
sanatized = sanatized.replace("'", "-")
|
||||
return sanatized
|
||||
|
||||
@staticmethod
|
||||
def __generate_username(username, corp_ticker):
|
||||
sanatized = "[" + corp_ticker + "]" + username
|
||||
return sanatized[:30]
|
||||
|
||||
@staticmethod
|
||||
def __generate_username_blue(username, corp_ticker):
|
||||
sanatized = "[BLUE][" + corp_ticker + "]" + username
|
||||
return sanatized[:30]
|
||||
|
||||
@staticmethod
|
||||
def _get_userid(uid):
|
||||
logger.debug("Looking for uid %s on TS3 server." % uid)
|
||||
server = Teamspeak3Manager.__get_created_server()
|
||||
try:
|
||||
ret = server.send_command('customsearch', {'ident': 'sso_uid', 'pattern': uid})
|
||||
if ret and 'keys' in ret and 'cldbid' in ret['keys']:
|
||||
logger.debug("Got userid %s for uid %s" % (ret['keys']['cldbid'], uid))
|
||||
return ret['keys']['cldbid']
|
||||
except TeamspeakError as e:
|
||||
if not e.code == '1281':
|
||||
raise e
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _group_id_by_name(groupname):
|
||||
server = Teamspeak3Manager.__get_created_server()
|
||||
logger.debug("Looking for group %s on TS3 server." % groupname)
|
||||
group_cache = server.send_command('servergrouplist')
|
||||
logger.debug("Received group cache from server: %s" % group_cache)
|
||||
for group in group_cache:
|
||||
logger.debug("Checking group %s" % group)
|
||||
if group['keys']['name'] == groupname:
|
||||
logger.debug("Found group %s, returning id %s" % (groupname, group['keys']['sgid']))
|
||||
return group['keys']['sgid']
|
||||
logger.debug("Group %s not found on server." % groupname)
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _create_group(groupname):
|
||||
logger.debug("Creating group %s on TS3 server." % groupname)
|
||||
server = Teamspeak3Manager.__get_created_server()
|
||||
sgid = Teamspeak3Manager._group_id_by_name(groupname)
|
||||
if not sgid:
|
||||
logger.debug("Group does not yet exist. Proceeding with creation.")
|
||||
ret = server.send_command('servergroupadd', {'name': groupname})
|
||||
Teamspeak3Manager.__group_cache = None
|
||||
sgid = ret['keys']['sgid']
|
||||
server.send_command('servergroupaddperm',
|
||||
{'sgid': sgid, 'permsid': 'i_group_needed_modify_power', 'permvalue': 75,
|
||||
'permnegated': 0, 'permskip': 0})
|
||||
server.send_command('servergroupaddperm',
|
||||
{'sgid': sgid, 'permsid': 'i_group_needed_member_add_power', 'permvalue': 100,
|
||||
'permnegated': 0, 'permskip': 0})
|
||||
server.send_command('servergroupaddperm',
|
||||
{'sgid': sgid, 'permsid': 'i_group_needed_member_remove_power', 'permvalue': 100,
|
||||
'permnegated': 0, 'permskip': 0})
|
||||
logger.info("Created group on TS3 server with name %s and id %s" % (groupname, sgid))
|
||||
return sgid
|
||||
|
||||
@staticmethod
|
||||
def _user_group_list(cldbid):
|
||||
logger.debug("Retrieving group list for user with id %s" % cldbid)
|
||||
server = Teamspeak3Manager.__get_created_server()
|
||||
try:
|
||||
groups = server.send_command('servergroupsbyclientid', {'cldbid': cldbid})
|
||||
except TeamspeakError as e:
|
||||
if e.code == '1281': # no groups
|
||||
groups = []
|
||||
else:
|
||||
raise e
|
||||
logger.debug("Retrieved group list: %s" % groups)
|
||||
outlist = {}
|
||||
|
||||
if type(groups) == list:
|
||||
logger.debug("Recieved multiple groups. Iterating.")
|
||||
for group in groups:
|
||||
outlist[group['keys']['name']] = group['keys']['sgid']
|
||||
elif type(groups) == dict:
|
||||
logger.debug("Recieved single group.")
|
||||
outlist[groups['keys']['name']] = groups['keys']['sgid']
|
||||
logger.debug("Returning name/id pairing: %s" % outlist)
|
||||
return outlist
|
||||
|
||||
@staticmethod
|
||||
def _group_list():
|
||||
logger.debug("Retrieving group list on TS3 server.")
|
||||
server = Teamspeak3Manager.__get_created_server()
|
||||
group_cache = server.send_command('servergrouplist')
|
||||
logger.debug("Received group cache from server: %s" % group_cache)
|
||||
outlist = {}
|
||||
if group_cache:
|
||||
for group in group_cache:
|
||||
logger.debug("Assigning name/id dict: %s = %s" % (group['keys']['name'], group['keys']['sgid']))
|
||||
outlist[group['keys']['name']] = group['keys']['sgid']
|
||||
else:
|
||||
logger.error("Received empty group cache while retrieving group cache from TS3 server. 1024 error.")
|
||||
logger.debug("Returning name/id pairing: %s" % outlist)
|
||||
return outlist
|
||||
|
||||
@staticmethod
|
||||
def _add_user_to_group(uid, groupid):
|
||||
logger.debug("Adding group id %s to TS3 user id %s" % (groupid, uid))
|
||||
server = Teamspeak3Manager.__get_created_server()
|
||||
user_groups = Teamspeak3Manager._user_group_list(uid)
|
||||
|
||||
if groupid not in user_groups.values():
|
||||
logger.debug("User does not have group already. Issuing command to add.")
|
||||
server.send_command('servergroupaddclient',
|
||||
{'sgid': str(groupid), 'cldbid': uid})
|
||||
logger.info("Added user id %s to group id %s on TS3 server." % (uid, groupid))
|
||||
|
||||
@staticmethod
|
||||
def _remove_user_from_group(uid, groupid):
|
||||
logger.debug("Removing group id %s from TS3 user id %s" % (groupid, uid))
|
||||
server = Teamspeak3Manager.__get_created_server()
|
||||
user_groups = Teamspeak3Manager._user_group_list(uid)
|
||||
|
||||
if str(groupid) in user_groups.values():
|
||||
logger.debug("User is in group. Issuing command to remove.")
|
||||
server.send_command('servergroupdelclient',
|
||||
{'sgid': str(groupid), 'cldbid': uid})
|
||||
logger.info("Removed user id %s from group id %s on TS3 server." % (uid, groupid))
|
||||
|
||||
@staticmethod
|
||||
def _sync_ts_group_db():
|
||||
logger.debug("_sync_ts_group_db function called.")
|
||||
try:
|
||||
remote_groups = Teamspeak3Manager._group_list()
|
||||
local_groups = TSgroup.objects.all()
|
||||
logger.debug("Comparing remote groups to TSgroup objects: %s" % local_groups)
|
||||
for key in remote_groups:
|
||||
logger.debug("Typecasting remote_group value at position %s to int: %s" % (key, remote_groups[key]))
|
||||
remote_groups[key] = int(remote_groups[key])
|
||||
|
||||
for group in local_groups:
|
||||
logger.debug("Checking local group %s" % group)
|
||||
if group.ts_group_id not in remote_groups.values():
|
||||
logger.debug(
|
||||
"Local group id %s not found on server. Deleting model %s" % (group.ts_group_id, group))
|
||||
TSgroup.objects.filter(ts_group_id=group.ts_group_id).delete()
|
||||
for key in remote_groups:
|
||||
g = TSgroup(ts_group_id=remote_groups[key], ts_group_name=key)
|
||||
q = TSgroup.objects.filter(ts_group_id=g.ts_group_id)
|
||||
if not q:
|
||||
logger.debug("Local group does not exist for TS group %s. Creating TSgroup model %s" % (
|
||||
remote_groups[key], g))
|
||||
g.save()
|
||||
except TeamspeakError as e:
|
||||
logger.error("Error occured while syncing TS group db: %s" % str(e))
|
||||
except:
|
||||
logger.exception("An unhandled exception has occured while syncing TS groups.")
|
||||
|
||||
@staticmethod
|
||||
def add_user(username, corp_ticker):
|
||||
username_clean = Teamspeak3Manager.__santatize_username(Teamspeak3Manager.__generate_username(username,
|
||||
corp_ticker))
|
||||
server = Teamspeak3Manager.__get_created_server()
|
||||
logger.debug("Adding user to TS3 server with cleaned username %s" % username_clean)
|
||||
server_groups = Teamspeak3Manager._group_list()
|
||||
|
||||
if settings.DEFAULT_AUTH_GROUP not in server_groups:
|
||||
Teamspeak3Manager._create_group(settings.DEFAULT_AUTH_GROUP)
|
||||
|
||||
alliance_group_id = Teamspeak3Manager._group_id_by_name(settings.DEFAULT_AUTH_GROUP)
|
||||
|
||||
try:
|
||||
ret = server.send_command('tokenadd', {'tokentype': 0, 'tokenid1': alliance_group_id, 'tokenid2': 0,
|
||||
'tokendescription': username_clean,
|
||||
'tokencustomset': "ident=sso_uid value=%s" % username_clean})
|
||||
except TeamspeakError as e:
|
||||
logger.error("Failed to add teamspeak user %s: %s" % (username, str(e)))
|
||||
return "",""
|
||||
|
||||
try:
|
||||
token = ret['keys']['token']
|
||||
logger.info("Created permission token for user %s on TS3 server" % username_clean)
|
||||
return username_clean, token
|
||||
except:
|
||||
logger.exception("Failed to add teamspeak user %s - received response: %s" % (username_clean, ret))
|
||||
return "", ""
|
||||
|
||||
@staticmethod
|
||||
def add_blue_user(username, corp_ticker):
|
||||
username_clean = Teamspeak3Manager.__santatize_username(Teamspeak3Manager.__generate_username_blue(username,
|
||||
corp_ticker))
|
||||
server = Teamspeak3Manager.__get_created_server()
|
||||
logger.debug("Adding user to TS3 server with cleaned username %s" % username_clean)
|
||||
server_groups = Teamspeak3Manager._group_list()
|
||||
if settings.DEFAULT_BLUE_GROUP not in server_groups:
|
||||
Teamspeak3Manager._create_group(settings.DEFAULT_BLUE_GROUP)
|
||||
|
||||
blue_group_id = Teamspeak3Manager._group_id_by_name(settings.DEFAULT_BLUE_GROUP)
|
||||
|
||||
try:
|
||||
ret = server.send_command('tokenadd', {'tokentype': 0, 'tokenid1': blue_group_id, 'tokenid2': 0,
|
||||
'tokendescription': username_clean,
|
||||
'tokencustomset': "ident=sso_uid value=%s" % username_clean})
|
||||
except TeamspeakError as e:
|
||||
logger.error("Failed to add blue teamspeak user %s: %s" % (username, str(e)))
|
||||
return "",""
|
||||
|
||||
try:
|
||||
token = ret['keys']['token']
|
||||
logger.info("Created permission token for blue user %s on TS3 server" % username_clean)
|
||||
return username_clean, token
|
||||
except:
|
||||
logger.exception("Failed to add blue teamspeak user %s - received response: %s" % (username_clean, ret))
|
||||
return "", ""
|
||||
|
||||
@staticmethod
|
||||
def delete_user(uid):
|
||||
server = Teamspeak3Manager.__get_created_server()
|
||||
user = Teamspeak3Manager._get_userid(uid)
|
||||
logger.debug("Deleting user %s with id %s from TS3 server." % (user, uid))
|
||||
if user:
|
||||
clients = server.send_command('clientlist')
|
||||
for client in clients:
|
||||
try:
|
||||
if client['keys']['client_database_id'] == user:
|
||||
logger.debug("Found user %s on TS3 server - issuing deletion command." % user)
|
||||
server.send_command('clientkick', {'clid': client['keys']['clid'], 'reasonid': 5,
|
||||
'reasonmsg': 'Auth service deleted'})
|
||||
except:
|
||||
logger.exception("Failed to delete user id %s from TS3 - received response %s" % (uid, client))
|
||||
return False
|
||||
try:
|
||||
ret = server.send_command('clientdbdelete', {'cldbid': user})
|
||||
except TeamspeakError as e:
|
||||
logger.error("Failed to delete teamspeak user %s: %s" % (uid, str(e)))
|
||||
return False
|
||||
if ret == '0':
|
||||
logger.info("Deleted user with id %s from TS3 server." % uid)
|
||||
return True
|
||||
else:
|
||||
logger.exception("Failed to delete user id %s from TS3 - received response %s" % (uid, ret))
|
||||
return False
|
||||
else:
|
||||
logger.warn("User with id %s not found on TS3 server. Assuming succesful deletion." % uid)
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def check_user_exists(uid):
|
||||
if Teamspeak3Manager._get_userid(uid):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def generate_new_permissionkey(uid, username, corpticker):
|
||||
logger.debug("Re-issuing permission key for user id %s" % uid)
|
||||
Teamspeak3Manager.delete_user(uid)
|
||||
return Teamspeak3Manager.add_user(username, corpticker)
|
||||
|
||||
@staticmethod
|
||||
def generate_new_blue_permissionkey(uid, username, corpticker):
|
||||
logger.debug("Re-issuing blue permission key for user id %s" % uid)
|
||||
Teamspeak3Manager.delete_user(uid)
|
||||
return Teamspeak3Manager.add_blue_user(username, corpticker)
|
||||
|
||||
@staticmethod
|
||||
def update_groups(uid, ts_groups):
|
||||
logger.debug("Updating uid %s TS3 groups %s" % (uid, ts_groups))
|
||||
userid = Teamspeak3Manager._get_userid(uid)
|
||||
addgroups = []
|
||||
remgroups = []
|
||||
if userid is not None:
|
||||
user_ts_groups = Teamspeak3Manager._user_group_list(userid)
|
||||
logger.debug("User has groups on TS3 server: %s" % user_ts_groups)
|
||||
for key in user_ts_groups:
|
||||
user_ts_groups[key] = int(user_ts_groups[key])
|
||||
for ts_group_key in ts_groups:
|
||||
logger.debug("Checking if user has group %s on TS3 server." % ts_group_key)
|
||||
if ts_groups[ts_group_key] not in user_ts_groups.values():
|
||||
addgroups.append(ts_groups[ts_group_key])
|
||||
for user_ts_group_key in user_ts_groups:
|
||||
if user_ts_groups[user_ts_group_key] not in ts_groups.values():
|
||||
remgroups.append(user_ts_groups[user_ts_group_key])
|
||||
|
||||
for g in addgroups:
|
||||
logger.info("Adding Teamspeak user %s into group %s" % (userid, g))
|
||||
Teamspeak3Manager._add_user_to_group(userid, g)
|
||||
|
||||
for g in remgroups:
|
||||
logger.info("Removing Teamspeak user %s from group %s" % (userid, g))
|
||||
Teamspeak3Manager._remove_user_from_group(userid, g)
|
||||
@@ -1,2 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
__author__ = 'r4stl1n'
|
||||
@@ -1,459 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
import socket
|
||||
import logging
|
||||
|
||||
|
||||
class ConnectionError:
|
||||
def __init__(self, ip, port):
|
||||
self.ip = ip
|
||||
self.port = port
|
||||
|
||||
def __str__(self):
|
||||
return 'Error connecting to host %s port %s' % (self.ip, self.port)
|
||||
|
||||
|
||||
ts3_escape = {'/': r"\/",
|
||||
' ': r'\s',
|
||||
'|': r'\p',
|
||||
"\a": r'\a',
|
||||
"\b": r'\b',
|
||||
"\f": r'\f',
|
||||
"\n": r'\n',
|
||||
"\r": r'\r',
|
||||
"\t": r'\t',
|
||||
"\v": r'\v'}
|
||||
|
||||
class TS3Proto:
|
||||
bytesin = 0
|
||||
bytesout = 0
|
||||
|
||||
_connected = False
|
||||
|
||||
def __init__(self):
|
||||
self._log = logging.getLogger('%s.%s' % (__name__, self.__class__.__name__))
|
||||
pass
|
||||
|
||||
def connect(self, ip, port):
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
try:
|
||||
s.connect((ip, port))
|
||||
except:
|
||||
# raise ConnectionError(ip, port)
|
||||
raise
|
||||
else:
|
||||
self._sock = s
|
||||
self._sockfile = s.makefile('r', 0)
|
||||
|
||||
data = self._sockfile.readline()
|
||||
if data.strip() == "TS3":
|
||||
self._sockfile.readline()
|
||||
self._connected = True
|
||||
return True
|
||||
|
||||
def disconnect(self):
|
||||
self.send_command("quit")
|
||||
self._sock.close()
|
||||
self._sock = None
|
||||
self._connected = False
|
||||
self._log.info('Disconnected')
|
||||
|
||||
def send_command(self, command, keys=None, opts=None):
|
||||
cmd = self.construct_command(command, keys=keys, opts=opts)
|
||||
self.send('%s\n' % cmd)
|
||||
|
||||
data = []
|
||||
|
||||
while True:
|
||||
resp = self._sockfile.readline()
|
||||
resp = self.parse_command(resp)
|
||||
if 'command' not in resp:
|
||||
data.append(resp)
|
||||
else:
|
||||
break
|
||||
|
||||
if resp['command'] == 'error':
|
||||
if resp['keys']['id'] == '0':
|
||||
if data:
|
||||
if len(data) > 1:
|
||||
return data
|
||||
else:
|
||||
return data[0]
|
||||
else:
|
||||
return resp['keys']['id']
|
||||
else:
|
||||
raise TeamspeakError(resp['keys']['id'])
|
||||
|
||||
def construct_command(self, command, keys=None, opts=None):
|
||||
"""
|
||||
Constructs a TS3 formatted command string
|
||||
Keys can have a single nested list to construct a nested parameter
|
||||
@param command: Command list
|
||||
@type command: string
|
||||
@param keys: Key/Value pairs
|
||||
@type keys: dict
|
||||
@param opts: Options
|
||||
@type opts: list
|
||||
"""
|
||||
|
||||
cstr = [command]
|
||||
|
||||
# Add the keys and values, escape as needed
|
||||
if keys:
|
||||
for key in keys:
|
||||
if isinstance(keys[key], list):
|
||||
ncstr = []
|
||||
for nest in keys[key]:
|
||||
ncstr.append("%s=%s" % (key, self._escape_str(nest)))
|
||||
cstr.append("|".join(ncstr))
|
||||
else:
|
||||
cstr.append("%s=%s" % (key, self._escape_str(keys[key])))
|
||||
|
||||
# Add in options
|
||||
if opts:
|
||||
for opt in opts:
|
||||
cstr.append("-%s" % opt)
|
||||
|
||||
return " ".join(cstr)
|
||||
|
||||
def parse_command(self, commandstr):
|
||||
"""
|
||||
Parses a TS3 command string into command/keys/opts tuple
|
||||
@param commandstr: Command string
|
||||
@type commandstr: string
|
||||
"""
|
||||
|
||||
if len(commandstr.split('|')) > 1:
|
||||
vals = []
|
||||
for cmd in commandstr.split('|'):
|
||||
vals.append(self.parse_command(cmd))
|
||||
return vals
|
||||
|
||||
cmdlist = commandstr.strip().split(' ')
|
||||
command = None
|
||||
keys = {}
|
||||
opts = []
|
||||
|
||||
for key in cmdlist:
|
||||
v = key.strip().split('=')
|
||||
if len(v) > 1:
|
||||
# Key
|
||||
if len > 2:
|
||||
# Fix the stupidities in TS3 escaping
|
||||
v = [v[0], '='.join(v[1:])]
|
||||
key, value = v
|
||||
keys[key] = self._unescape_str(value)
|
||||
elif not v == ['']:
|
||||
if v[0][0] and v[0][0] == '-':
|
||||
# Option
|
||||
opts.append(v[0][1:])
|
||||
else:
|
||||
command = v[0]
|
||||
|
||||
d = {'keys': keys, 'opts': opts}
|
||||
if command:
|
||||
d['command'] = command
|
||||
return d
|
||||
|
||||
@staticmethod
|
||||
def _escape_str(value):
|
||||
"""
|
||||
Escape a value into a TS3 compatible string
|
||||
@param value: Value
|
||||
@type value: string/int
|
||||
"""
|
||||
|
||||
if isinstance(value, int):
|
||||
return "%d" % value
|
||||
value = value.replace("\\", r'\\')
|
||||
for i, j in ts3_escape.items():
|
||||
value = value.replace(i, j)
|
||||
return value
|
||||
|
||||
@staticmethod
|
||||
def _unescape_str(value):
|
||||
"""
|
||||
Unescape a TS3 compatible string into a normal string
|
||||
@param value: Value
|
||||
@type value: string/int
|
||||
"""
|
||||
|
||||
if isinstance(value, int):
|
||||
return "%d" % value
|
||||
value = value.replace(r"\\", "\\")
|
||||
for i, j in ts3_escape.items():
|
||||
value = value.replace(j, i)
|
||||
return value
|
||||
|
||||
def send(self, payload):
|
||||
if self._connected:
|
||||
self._log.debug('Sent: %s' % payload)
|
||||
self._sockfile.write(payload)
|
||||
|
||||
|
||||
class TS3Server(TS3Proto):
|
||||
def __init__(self, ip, port, id=0, sock=None):
|
||||
"""
|
||||
Abstraction class for TS3 Servers
|
||||
@param ip: IP Address
|
||||
@type ip: str
|
||||
@param port: Port Number
|
||||
@type port: int
|
||||
"""
|
||||
TS3Proto.__init__(self)
|
||||
|
||||
if not sock:
|
||||
if self.connect(ip, port) and id > 0:
|
||||
self.use(id)
|
||||
else:
|
||||
self._sock = sock
|
||||
self._sockfile = sock.makefile('r', 0)
|
||||
self._connected = True
|
||||
|
||||
def login(self, username, password):
|
||||
"""
|
||||
Login to the TS3 Server
|
||||
@param username: Username
|
||||
@type username: str
|
||||
@param password: Password
|
||||
@type password: str
|
||||
"""
|
||||
d = self.send_command('login', keys={'client_login_name': username, 'client_login_password': password})
|
||||
if d == 0:
|
||||
self._log.info('Login Successful')
|
||||
return True
|
||||
return False
|
||||
|
||||
def serverlist(self):
|
||||
"""
|
||||
Get a list of all Virtual Servers on the connected TS3 instance
|
||||
"""
|
||||
if self._connected:
|
||||
return self.send_command('serverlist')
|
||||
|
||||
def gm(self, msg):
|
||||
"""
|
||||
Send a global message to the current Virtual Server
|
||||
@param msg: Message
|
||||
@type msg: str
|
||||
"""
|
||||
if self._connected:
|
||||
return self.send_command('gm', keys={'msg': msg})
|
||||
|
||||
def use(self, id):
|
||||
"""
|
||||
Use a particular Virtual Server instance
|
||||
@param id: Virtual Server ID
|
||||
@type id: int
|
||||
"""
|
||||
if self._connected and id > 0:
|
||||
self.send_command('use', keys={'sid': id})
|
||||
|
||||
|
||||
class TeamspeakError(Exception):
|
||||
def __init__(self, code, msg=None):
|
||||
self.code = str(code)
|
||||
if not msg:
|
||||
msg = ts3_errors[self.code]
|
||||
self.msg = msg
|
||||
|
||||
def __str__(self):
|
||||
return self.code + ' ' + self.msg
|
||||
|
||||
ts3_errors = {
|
||||
'0': 'unknown error code',
|
||||
'1': 'undefined error',
|
||||
'2': 'not implemented',
|
||||
'3': '',
|
||||
'4': '',
|
||||
'5': 'library time limit reached',
|
||||
'256': 'command not found',
|
||||
'257': 'unable to bind network port',
|
||||
'258': 'no network port available',
|
||||
'512': 'invalid clientID',
|
||||
'513': 'nickname is already in use',
|
||||
'514': 'invalid error code',
|
||||
'515': 'max clients protocol limit reached',
|
||||
'516': 'invalid client type',
|
||||
'517': 'already subscribed',
|
||||
'518': 'not logged in',
|
||||
'519': 'could not validate client identity',
|
||||
'520': 'invalid loginname or password',
|
||||
'521': 'too many clones already connected',
|
||||
'522': 'client version outdated, please update',
|
||||
'523': 'client is online',
|
||||
'524': 'client is flooding',
|
||||
'525': 'client is modified',
|
||||
'526': 'can not verify client at this moment',
|
||||
'527': 'client is not permitted to log in',
|
||||
'528': 'client is not subscribed to the channel',
|
||||
'768': 'invalid channelID',
|
||||
'769': 'max channels protocol limit reached',
|
||||
'770': 'already member of channel',
|
||||
'771': 'channel name is already in use',
|
||||
'772': 'channel not empty',
|
||||
'773': 'can not delete default channel',
|
||||
'774': 'default channel requires permanent',
|
||||
'775': 'invalid channel flags',
|
||||
'776': 'permanent channel can not be child of non permanent channel',
|
||||
'777': 'channel maxclient reached',
|
||||
'778': 'channel maxfamily reached',
|
||||
'779': 'invalid channel order',
|
||||
'780': 'channel does not support filetransfers',
|
||||
'781': 'invalid channel password',
|
||||
'782': 'channel is private channel',
|
||||
'783': 'invalid security hash supplied by client',
|
||||
'1024': 'invalid serverID',
|
||||
'1025': 'server is running',
|
||||
'1026': 'server is shutting down',
|
||||
'1027': 'server maxclient reached',
|
||||
'1028': 'invalid server password',
|
||||
'1029': 'deployment active',
|
||||
'1030': 'unable to stop own server in your connection class',
|
||||
'1031': 'server is virtual',
|
||||
'1032': 'server wrong machineID',
|
||||
'1033': 'server is not running',
|
||||
'1034': 'server is booting up',
|
||||
'1035': 'server got an invalid status for this operation',
|
||||
'1036': 'server modal quit',
|
||||
'1037': 'server version is too old for command',
|
||||
'1280': 'database error',
|
||||
'1281': 'database empty result set',
|
||||
'1282': 'database duplicate entry',
|
||||
'1283': 'database no modifications',
|
||||
'1284': 'database invalid constraint',
|
||||
'1285': 'database reinvoke command',
|
||||
'1536': 'invalid quote',
|
||||
'1537': 'invalid parameter count',
|
||||
'1538': 'invalid parameter',
|
||||
'1539': 'parameter not found',
|
||||
'1540': 'convert error',
|
||||
'1541': 'invalid parameter size',
|
||||
'1542': 'missing required parameter',
|
||||
'1543': 'invalid checksum',
|
||||
'1792': 'virtual server got a critical error',
|
||||
'1793': 'Connection lost',
|
||||
'1794': 'not connected',
|
||||
'1795': 'no cached connection info',
|
||||
'1796': 'currently not possible',
|
||||
'1797': 'failed connection initialization',
|
||||
'1798': 'could not resolve hostname',
|
||||
'1799': 'invalid server connection handler ID',
|
||||
'1800': 'could not initialize Input Manager',
|
||||
'1801': 'client library not initialized',
|
||||
'1802': 'server library not initialized',
|
||||
'1803': 'too many whisper targets',
|
||||
'1804': 'no whisper targets found',
|
||||
'2048': 'invalid file name',
|
||||
'2049': 'invalid file permissions',
|
||||
'2050': 'file already exists',
|
||||
'2051': 'file not found',
|
||||
'2052': 'file input/output error',
|
||||
'2053': 'invalid file transfer ID',
|
||||
'2054': 'invalid file path',
|
||||
'2055': 'no files available',
|
||||
'2056': 'overwrite excludes resume',
|
||||
'2057': 'invalid file size',
|
||||
'2058': 'file already in use',
|
||||
'2059': 'could not open file transfer connection',
|
||||
'2060': 'no space left on device (disk full?)',
|
||||
'2061': "file exceeds file system's maximum file size",
|
||||
'2062': 'file transfer connection timeout',
|
||||
'2063': 'lost file transfer connection',
|
||||
'2064': 'file exceeds supplied file size',
|
||||
'2065': 'file transfer complete',
|
||||
'2066': 'file transfer canceled',
|
||||
'2067': 'file transfer interrupted',
|
||||
'2068': 'file transfer server quota exceeded',
|
||||
'2069': 'file transfer client quota exceeded',
|
||||
'2070': 'file transfer reset',
|
||||
'2071': 'file transfer limit reached',
|
||||
'2304': 'preprocessor disabled',
|
||||
'2305': 'internal preprocessor',
|
||||
'2306': 'internal encoder',
|
||||
'2307': 'internal playback',
|
||||
'2308': 'no capture device available',
|
||||
'2309': 'no playback device available',
|
||||
'2310': 'could not open capture device',
|
||||
'2311': 'could not open playback device',
|
||||
'2312': 'ServerConnectionHandler has a device registered',
|
||||
'2313': 'invalid capture device',
|
||||
'2314': 'invalid clayback device',
|
||||
'2315': 'invalid wave file',
|
||||
'2316': 'wave file type not supported',
|
||||
'2317': 'could not open wave file',
|
||||
'2318': 'internal capture',
|
||||
'2319': 'device still in use',
|
||||
'2320': 'device already registerred',
|
||||
'2321': 'device not registered/known',
|
||||
'2322': 'unsupported frequency',
|
||||
'2323': 'invalid channel count',
|
||||
'2324': 'read error in wave',
|
||||
'2325': 'sound need more data',
|
||||
'2326': 'sound device was busy',
|
||||
'2327': 'there is no sound data for this period',
|
||||
'2328': 'Channelmask set bits count (speakers) is not the same as channel (count)',
|
||||
'2560': 'invalid group ID',
|
||||
'2561': 'duplicate entry',
|
||||
'2562': 'invalid permission ID',
|
||||
'2563': 'empty result set',
|
||||
'2564': 'access to default group is forbidden',
|
||||
'2565': 'invalid size',
|
||||
'2566': 'invalid value',
|
||||
'2567': 'group is not empty',
|
||||
'2568': 'insufficient client permissions',
|
||||
'2569': 'insufficient group modify power',
|
||||
'2570': 'insufficient permission modify power',
|
||||
'2571': 'template group is currently used',
|
||||
'2572': 'permission error',
|
||||
'2816': 'virtualserver limit reached',
|
||||
'2817': 'max slot limit reached',
|
||||
'2818': 'license file not found',
|
||||
'2819': 'license date not ok',
|
||||
'2820': 'unable to connect to accounting server',
|
||||
'2821': 'unknown accounting error',
|
||||
'2822': 'accounting server error',
|
||||
'2823': 'instance limit reached',
|
||||
'2824': 'instance check error',
|
||||
'2825': 'license file invalid',
|
||||
'2826': 'virtualserver is running elsewhere',
|
||||
'2827': 'virtualserver running in same instance already',
|
||||
'2828': 'virtualserver already started',
|
||||
'2829': 'virtualserver not started',
|
||||
'2830': '',
|
||||
'3072': 'invalid message id',
|
||||
'3328': 'invalid ban id',
|
||||
'3329': 'connection failed, you are banned',
|
||||
'3330': 'rename failed, new name is banned',
|
||||
'3331': 'flood ban',
|
||||
'3584': 'unable to initialize tts',
|
||||
'3840': 'invalid privilege key',
|
||||
'4096': '',
|
||||
'4097': '',
|
||||
'4098': '',
|
||||
'4099': '',
|
||||
'4100': '',
|
||||
'4101': '',
|
||||
'4102': '',
|
||||
'4103': '',
|
||||
'4352': 'invalid password',
|
||||
'4353': 'invalid request',
|
||||
'4354': 'no (more) slots available',
|
||||
'4355': 'pool missing',
|
||||
'4356': 'pool unknown',
|
||||
'4357': 'unknown ip location (perhaps LAN ip?)',
|
||||
'4358': 'internal error (tried exceeded)',
|
||||
'4359': 'too many slots requested',
|
||||
'4360': 'too many reserved',
|
||||
'4361': 'could not connect to provisioning server',
|
||||
'4368': 'authentication server not connected',
|
||||
'4369': 'authentication data too large',
|
||||
'4370': 'already initialized',
|
||||
'4371': 'not initialized',
|
||||
'4372': 'already connecting',
|
||||
'4373': 'already connected',
|
||||
'4374': '',
|
||||
'4375': 'io_error',
|
||||
'4376': '',
|
||||
'4377': '',
|
||||
'4378': '',
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
import os
|
||||
import requests
|
||||
import json
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class XenForoManager:
|
||||
def __init__(self):
|
||||
if not settings.XENFORO_ENDPOINT:
|
||||
logger.debug("Could not find XenForo endpoint")
|
||||
if not settings.XENFORO_APIKEY:
|
||||
logger.debug("XenForo API Key not found")
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def __sanitize_username(username):
|
||||
sanitized = username.replace(" ", "_")
|
||||
return sanitized
|
||||
|
||||
@staticmethod
|
||||
def __generate_password():
|
||||
return os.urandom(8).encode('hex')
|
||||
|
||||
@staticmethod
|
||||
def exec_http_request(http_params):
|
||||
default_params = {
|
||||
'hash': settings.XENFORO_APIKEY
|
||||
}
|
||||
http_params.update(default_params)
|
||||
r = requests.get(settings.XENFORO_ENDPOINT, params=http_params)
|
||||
return r
|
||||
|
||||
@staticmethod
|
||||
def add_user(username, email):
|
||||
|
||||
sanitized = XenForoManager.__sanitize_username(username)
|
||||
password = XenForoManager.__generate_password()
|
||||
|
||||
data = {
|
||||
'action': 'register',
|
||||
'username': sanitized,
|
||||
'password': password,
|
||||
'email': email,
|
||||
'group': settings.XENFORO_DEFAULT_GROUP,
|
||||
'visible': '1',
|
||||
'user_state': 'valid'
|
||||
}
|
||||
|
||||
r = XenForoManager.exec_http_request(data)
|
||||
|
||||
# check if the user already exist but was disabled
|
||||
if r.status_code != 200:
|
||||
if json.loads(r.text)['error'] == 7:
|
||||
data = XenForoManager.reactivate_user(sanitized)
|
||||
return data
|
||||
|
||||
response = {
|
||||
'response': {
|
||||
'message': r.text,
|
||||
'status_code': r.status_code
|
||||
}
|
||||
}
|
||||
data.update(response)
|
||||
return data
|
||||
|
||||
@staticmethod
|
||||
def reset_password(username):
|
||||
|
||||
password = XenForoManager.__generate_password()
|
||||
|
||||
data = {
|
||||
'action': 'editUser',
|
||||
'user': username,
|
||||
'password': password
|
||||
}
|
||||
|
||||
r = XenForoManager.exec_http_request(data)
|
||||
|
||||
response = {
|
||||
'response': {
|
||||
'message': r.text,
|
||||
'status_code': r.status_code
|
||||
}
|
||||
}
|
||||
data.update(response)
|
||||
return data
|
||||
|
||||
@staticmethod
|
||||
def disable_user(username):
|
||||
data = {
|
||||
'action': 'editUser',
|
||||
'user': username,
|
||||
'remove_groups': settings.XENFORO_DEFAULT_GROUP
|
||||
}
|
||||
r = XenForoManager.exec_http_request(data)
|
||||
return r
|
||||
|
||||
@staticmethod
|
||||
def reactivate_user(username):
|
||||
data = {
|
||||
'action': 'editUser',
|
||||
'user': username,
|
||||
'add_groups': settings.XENFORO_DEFAULT_GROUP,
|
||||
'password': XenForoManager.__generate_password()
|
||||
}
|
||||
r = XenForoManager.exec_http_request(data)
|
||||
response = {
|
||||
'response': {
|
||||
'message': r.text,
|
||||
'status_code': r.status_code
|
||||
},
|
||||
'username': username
|
||||
}
|
||||
data.update(response)
|
||||
return data
|
||||
|
||||
@staticmethod
|
||||
def update_user_password(username, raw_password):
|
||||
data = {
|
||||
'action': 'editUser',
|
||||
'user': username,
|
||||
'password': raw_password
|
||||
}
|
||||
r = XenForoManager.exec_http_request(data)
|
||||
response = {
|
||||
'response': {
|
||||
'message': r.text,
|
||||
'status_code': r.status_code
|
||||
},
|
||||
'username': username
|
||||
}
|
||||
data.update(response)
|
||||
return data
|
||||
Reference in New Issue
Block a user