mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2025-07-09 04:20:17 +02:00
285 lines
11 KiB
Python
285 lines
11 KiB
Python
import random
|
|
import string
|
|
from allianceauth.eveonline.models import EveCharacter
|
|
from allianceauth.services.hooks import NameFormatter
|
|
from passlib.hash import bcrypt_sha256
|
|
from django.db import models
|
|
from allianceauth.services.abstract import AbstractServiceModel
|
|
import logging
|
|
from django.contrib.auth.models import User
|
|
from django.utils.translation import gettext_lazy as _
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class MumbleUser(AbstractServiceModel):
|
|
class HashFunction(models.TextChoices):
|
|
SHA256 = 'bcrypt-sha256', _('SHA256')
|
|
SHA1 = 'sha1', _('SHA1')
|
|
user = models.OneToOneField(
|
|
User,
|
|
primary_key=True,
|
|
on_delete=models.CASCADE,
|
|
related_name='mumble'
|
|
)
|
|
username = models.CharField(max_length=254, unique=True)
|
|
pwhash = models.CharField(max_length=90)
|
|
hashfn = models.CharField(
|
|
max_length=15,
|
|
choices=HashFunction.choices,
|
|
default=HashFunction.SHA256)
|
|
certhash = models.CharField(
|
|
verbose_name="Certificate Hash",
|
|
max_length=254,blank=True, null=True, editable=False,
|
|
help_text="Hash of Mumble client certificate as presented when user authenticates")
|
|
release = models.TextField(
|
|
verbose_name="Mumble Release",
|
|
blank=True, null=True, editable=False,
|
|
help_text="Client release. For official releases, this equals the version. For snapshots and git compiles, this will be something else.")
|
|
version = models.IntegerField(
|
|
verbose_name="Mumble Version",
|
|
blank=True, null=True, editable=False,
|
|
help_text="Client version. Major version in upper 16 bits, followed by 8 bits of minor version and 8 bits of patchlevel. Version 1.2.3 = 0x010203.")
|
|
last_connect = models.DateTimeField(
|
|
verbose_name="Last Connection",
|
|
blank=True, null=True, editable=False,
|
|
help_text="Timestamp of the users Last Connection to Mumble")
|
|
last_disconnect = models.DateTimeField(
|
|
verbose_name="Last Disconnection",
|
|
blank=True, null=True, editable=False,
|
|
help_text="Timestamp of the users Last Disconnection from Mumble")
|
|
|
|
@property
|
|
def display_name(self) -> str:
|
|
from .auth_hooks import MumbleService
|
|
return NameFormatter(MumbleService(), self.user).format_name()
|
|
|
|
@staticmethod
|
|
def get_username(user) -> str:
|
|
return user.profile.main_character.character_name # main character as the user.username may be incorrect
|
|
|
|
@staticmethod
|
|
def sanitise_username(username) -> str:
|
|
return username.replace(" ", "_")
|
|
|
|
@staticmethod
|
|
def generate_random_pass() -> str:
|
|
return ''.join([random.choice(string.ascii_letters + string.digits) for n in range(16)])
|
|
|
|
@staticmethod
|
|
def gen_pwhash(password) -> str:
|
|
return bcrypt_sha256.encrypt(password.encode('utf-8'))
|
|
|
|
def __str__(self) -> str:
|
|
return f"{self.username}"
|
|
|
|
def update_password(self, password=None) -> None:
|
|
init_password = password
|
|
logger.debug(f"Updating mumble user {self.user} password.")
|
|
if not password:
|
|
password = self.generate_random_pass()
|
|
pwhash = self.gen_pwhash(password)
|
|
logger.debug(f"Proceeding with mumble user {self.user} password update - pwhash starts with {pwhash[0:5]}")
|
|
self.pwhash = pwhash
|
|
self.hashfn = self.HashFunction.SHA256
|
|
self.save()
|
|
if init_password is None:
|
|
self.credentials.update({'username': self.username, 'password': password})
|
|
|
|
def reset_password(self) -> None:
|
|
self.update_password()
|
|
|
|
def group_string(self) -> str:
|
|
"""Return a Mumble Safe Formatted List of Groups
|
|
This used to be a ModelField, generated on the fly now with DjangoAuthenticatorTM
|
|
|
|
Returns:
|
|
LiteralString: Mumble Safe Formatted List of Groups
|
|
"""
|
|
groups_str = [self.user.profile.state.name]
|
|
for group in self.user.groups.all():
|
|
groups_str.append(str(group.name))
|
|
return ','.join({g.replace(' ', '-') for g in groups_str})
|
|
|
|
def create(self, user):
|
|
try:
|
|
username = self.get_username(user)
|
|
logger.debug(f"Creating mumble user with username {username}")
|
|
username_clean = self.sanitise_username(username)
|
|
password = self.generate_random_pass()
|
|
pwhash = self.gen_pwhash(password)
|
|
logger.debug("Proceeding with mumble user creation: clean username {}, pwhash starts with {}".format(
|
|
username_clean, pwhash[0:5]))
|
|
logger.info(f"Creating mumble user {username_clean}")
|
|
|
|
result = super().create(user=user, username=username_clean, pwhash=pwhash)
|
|
result.credentials.update({'username': result.username, 'password': password})
|
|
return result
|
|
except AttributeError: # No Main or similar errors
|
|
return False
|
|
return False
|
|
|
|
class Meta:
|
|
verbose_name = _("User")
|
|
verbose_name_plural = _("Users")
|
|
permissions = (
|
|
("access_mumble", "Can access the Mumble service"),
|
|
("view_connection_history", "Can access the connection history of the Mumble service"),
|
|
)
|
|
|
|
|
|
class TempLink(models.Model):
|
|
expires = models.DateTimeField(_("Expiry"), auto_now=False, auto_now_add=False)
|
|
link_ref = models.CharField(max_length=20)
|
|
creator = models.ForeignKey(EveCharacter, on_delete=models.SET_NULL, null=True, default=None)
|
|
|
|
class Meta:
|
|
permissions = (("create_new_links", "Can Create Temp Links"),)
|
|
|
|
def __str__(self):
|
|
return f"Link {self.link_ref} - {self.expires}"
|
|
|
|
|
|
class TempUser(models.Model):
|
|
class HashFunction(models.TextChoices):
|
|
SHA256 = 'bcrypt-sha256', _('SHA256')
|
|
SHA1 = 'sha1', _('SHA1')
|
|
name = models.CharField(max_length=200) # Display name to show
|
|
username = models.CharField(max_length=254, unique=True)
|
|
pwhash = models.CharField(max_length=90)
|
|
hashfn = models.CharField(
|
|
max_length=15,
|
|
choices=HashFunction.choices,
|
|
default=HashFunction.SHA256)
|
|
certhash = models.CharField(
|
|
verbose_name="Certificate Hash",
|
|
max_length=254,blank=True, null=True, editable=False,
|
|
help_text="Hash of Mumble client certificate as presented when user authenticates")
|
|
release = models.TextField(
|
|
verbose_name="Mumble Release",
|
|
blank=True, null=True, editable=False,
|
|
help_text="Client release. For official releases, this equals the version. For snapshots and git compiles, this will be something else.")
|
|
version = models.IntegerField(
|
|
verbose_name="Mumble Version",
|
|
blank=True, null=True, editable=False,
|
|
help_text="Client version. Major version in upper 16 bits, followed by 8 bits of minor version and 8 bits of patchlevel. Version 1.2.3 = 0x010203.")
|
|
last_connect = models.DateTimeField(
|
|
verbose_name="Last Connection",
|
|
blank=True, null=True, editable=False,
|
|
help_text="Timestamp of the users Last Connection to Mumble")
|
|
last_disconnect = models.DateTimeField(
|
|
verbose_name="Last Disconnection",
|
|
blank=True, null=True, editable=False,
|
|
help_text="Timestamp of the users Last Disconnection from Mumble")
|
|
expires = models.DateTimeField(_("Expiry"), auto_now=False, auto_now_add=False)
|
|
|
|
templink = models.ForeignKey(TempLink, on_delete=models.CASCADE, null=True, default=None)
|
|
character_id = models.IntegerField(default=None, blank=True, null=True)
|
|
|
|
@property
|
|
def display_name(self) -> str:
|
|
from .auth_hooks import MumbleService
|
|
return NameFormatter(MumbleService(), self.user).format_name()
|
|
|
|
@staticmethod
|
|
def get_username(user) -> str:
|
|
return user.profile.main_character.character_name # main character as the user.username may be incorrect
|
|
|
|
@staticmethod
|
|
def sanitise_username(username) -> str:
|
|
return username.replace(" ", "_")
|
|
|
|
@staticmethod
|
|
def generate_random_pass() -> str:
|
|
return ''.join([random.choice(string.ascii_letters + string.digits) for n in range(16)])
|
|
|
|
@staticmethod
|
|
def gen_pwhash(password) -> str:
|
|
return bcrypt_sha256.encrypt(password.encode('utf-8'))
|
|
|
|
def __str__(self) -> str:
|
|
return f"Temp User: {self.username} - {self.name}"
|
|
|
|
def group_string(self) -> str:
|
|
"""Overwritten from MumbleUser, we could add features to this in the future
|
|
"""
|
|
return str(["Guest"])
|
|
|
|
class Meta:
|
|
verbose_name = _("Temp User")
|
|
verbose_name_plural = _("Temp Users")
|
|
permissions = ()
|
|
|
|
|
|
class IdlerHandler(models.Model):
|
|
name = models.CharField(_("Name"), max_length=50)
|
|
enabled = models.BooleanField(_("Enabled"), default=False)
|
|
seconds = models.SmallIntegerField(_("Idle Seconds"), default=3600)
|
|
interval = models.SmallIntegerField(_("Run Interval"), default=60)
|
|
channel = models.SmallIntegerField(_("AFK Channel"))
|
|
denylist = models.BooleanField(_("DenyList"), default=True, help_text="True for DenyList, False for Allowlist")
|
|
list = models.CharField(_("Allow/Deny list"), max_length=50, default="")
|
|
|
|
class Meta:
|
|
verbose_name = _("Idler Handler")
|
|
verbose_name_plural = _("Idler Handlers")
|
|
default_permissions = ()
|
|
|
|
def __str__(self) -> str:
|
|
return f"{self.name}"
|
|
|
|
|
|
class MumbleServerServer(models.Model): # This will clash with ICE MumbleServer
|
|
class ServerVersion(models.TextChoices):
|
|
MUMBLESERVER_ICE = 'MumbleServer.ice', _('MumbleServer.ice (Mumble >=1.5.17)')
|
|
MURMUR_ICE = 'Murmur.Ice', _('Murmur.Ice (Mumble <=1.5.17)')
|
|
name = models.CharField(max_length=50)
|
|
ip = models.GenericIPAddressField(
|
|
verbose_name=_("Host IP Address"),
|
|
protocol="both",
|
|
unpack_ipv4=False,
|
|
default="127.0.0.1")
|
|
endpoint = models.GenericIPAddressField(
|
|
verbose_name=_("Endpoint IP Address"),
|
|
protocol="both",
|
|
unpack_ipv4=False,
|
|
default="127.0.0.1")
|
|
|
|
port = models.PositiveSmallIntegerField(verbose_name=_("Port"), default=6502)
|
|
secret = models.CharField(verbose_name=_("ICE Secret"), max_length=50)
|
|
watchdog = models.SmallIntegerField(verbose_name=_("Watchdog Interval"), default=30)
|
|
slice = models.CharField(
|
|
max_length=16,
|
|
choices=ServerVersion.choices,
|
|
default=ServerVersion.MUMBLESERVER_ICE)
|
|
virtual_servers = models.CharField(
|
|
verbose_name=_("Virtual Servers"),
|
|
max_length=50,
|
|
default="1")
|
|
avatar_enable = models.BooleanField(
|
|
verbose_name=_("Enable EVE Avatars"),
|
|
default=True)
|
|
reject_on_error = models.BooleanField(
|
|
verbose_name=_("Reject Unauthenticated"),
|
|
default=True)
|
|
offset = models.IntegerField(
|
|
verbose_name=_("ID Offset"),
|
|
default=1000000000)
|
|
idler_handler = models.ForeignKey(
|
|
IdlerHandler,
|
|
verbose_name=_("Idler Handler"),
|
|
on_delete=models.SET_NULL,
|
|
null=True,
|
|
blank=True)
|
|
|
|
class Meta:
|
|
verbose_name = _("Mumble Server")
|
|
verbose_name_plural = _("Mumble Servers")
|
|
default_permissions = ()
|
|
|
|
def __str__(self) -> str:
|
|
return f"{self.name}"
|
|
|
|
def virtual_servers_list(self) -> list:
|
|
return [int(num) for num in self.virtual_servers.replace(",", " ").split() if num]
|