Пример #1
0
    def update(self, ip, failmsg='Exceeded threshold.'):
        """
        Store the time of the latest failure.

        Args:
            ip (str): IP address of requestor
            failmsg (str, optional): Message to display in logs upon activation
                of throttle.

        Returns:
            None

        """
        # Get current status
        previously_throttled = self.check(ip)

        # Enforce length limits
        if not self.storage[ip].maxlen:
            self.storage[ip] = deque(maxlen=self.cache_size)

        self.storage[ip].append(time.time())

        # See if this update caused a change in status
        currently_throttled = self.check(ip)

        # If this makes it engage, log a single activation event
        if (not previously_throttled and currently_throttled):
            logger.log_sec(
                'Throttle Activated: %s (IP: %s, %i hits in %i seconds.)' %
                (failmsg, ip, self.limit, self.timeout))
Пример #2
0
    def func(self):
        """hook function."""

        account = self.account
        if not self.rhs:
            self.msg("Usage: password <oldpass> = <newpass>")
            return
        oldpass = self.lhslist[0]  # Both of these are
        newpass = self.rhslist[0]  # already stripped by parse()

        # Validate password
        validated, error = account.validate_password(newpass)

        if not account.check_password(oldpass):
            self.msg("The specified old password isn't correct.")
        elif not validated:
            errors = [e for suberror in error.messages for e in error.messages]
            string = "\n".join(errors)
            self.msg(string)
        else:
            account.set_password(newpass)
            account.save()
            self.msg("Password changed.")
            logger.log_sec("Password Changed: %s (Caller: %s, IP: %s)." %
                           (account, account, self.session.address))
Пример #3
0
    def func(self):
        """Destroy objects cleanly."""
        caller = self.caller

        if not self.args:
            self.msg("Usage: cdestroy <channelname>")
            return
        channel = find_channel(caller, self.args)
        if not channel:
            self.msg("Could not find channel %s." % self.args)
            return
        if not channel.access(caller, "control"):
            self.msg("You are not allowed to do that.")
            return
        channel_key = channel.key
        message = "%s is being destroyed. Make sure to change your aliases." % channel_key
        msgobj = create.create_message(caller, message, channel)
        channel.msg(msgobj)
        channel.delete()
        CHANNELHANDLER.update()
        self.msg("Channel '%s' was destroyed." % channel_key)
        logger.log_sec(
            "Channel Deleted: %s (Caller: %s, IP: %s)."
            % (channel_key, caller, self.session.address)
        )
Пример #4
0
    def func(self):
        """Implement unbanning"""

        banlist = ServerConfig.objects.conf('server_bans')

        if not self.args:
            self.caller.msg(list_bans(self, banlist))
            return

        try:
            num = int(self.args)
        except Exception:
            self.caller.msg("You must supply a valid ban id to clear.")
            return

        if not banlist:
            self.caller.msg("There are no bans to clear.")
        elif not (0 < num < len(banlist) + 1):
            self.caller.msg("Ban id |w%s|x was not found." % self.args)
        else:
            # all is ok, clear ban
            ban = banlist[num - 1]
            del banlist[num - 1]
            ServerConfig.objects.conf('server_bans', banlist)
            value = " ".join([s for s in ban[:2]])
            self.caller.msg("Cleared ban %s: %s" % (num, value))
            logger.log_sec('Unbanned: %s (Caller: %s, IP: %s).' %
                           (value.strip(), self.caller, self.session.address))
Пример #5
0
    def func(self):
        """Implement the function."""

        caller = self.caller

        if not self.rhs:
            self.msg("Usage: userpassword <user obj> = <new password>")
            return

        # the account search also matches 'me' etc.
        account = caller.search_account(self.lhs)
        if not account:
            return

        newpass = self.rhs

        # Validate password
        validated, error = account.validate_password(newpass)
        if not validated:
            errors = [e for suberror in error.messages for e in error.messages]
            string = "\n".join(errors)
            caller.msg(string)
            return

        account.set_password(newpass)
        account.save()
        self.msg("%s - new password set to '%s'." % (account.name, newpass))
        if account.character != caller:
            account.msg("%s has changed your password to '%s'." %
                        (caller.name, newpass))
        logger.log_sec('Password Changed: %s (Caller: %s, IP: %s).' %
                       (account, caller, self.session.address))
Пример #6
0
    def func(self):
        """Implementing the function"""
        caller = self.caller
        args = self.args

        if not args:
            caller.msg("Usage: @boot[/switches] <account> [:reason]")
            return

        if ':' in args:
            args, reason = [a.strip() for a in args.split(':', 1)]
        else:
            args, reason = args, ""

        boot_list = []

        if 'sid' in self.switches:
            # Boot a particular session id.
            sessions = SESSIONS.get_sessions(True)
            for sess in sessions:
                # Find the session with the matching session id.
                if sess.sessid == int(args):
                    boot_list.append(sess)
                    break
        else:
            # Boot by account object
            pobj = search.account_search(args)
            if not pobj:
                caller.msg("Account %s was not found." % args)
                return
            pobj = pobj[0]
            if not pobj.access(caller, 'boot'):
                string = "You don't have the permission to boot %s." % (pobj.key, )
                caller.msg(string)
                return
            # we have a bootable object with a connected user
            matches = SESSIONS.sessions_from_account(pobj)
            for match in matches:
                boot_list.append(match)

        if not boot_list:
            caller.msg("No matching sessions found. The Account does not seem to be online.")
            return

        # Carry out the booting of the sessions in the boot list.

        feedback = None
        if 'quiet' not in self.switches:
            feedback = "You have been disconnected by %s.\n" % caller.name
            if reason:
                feedback += "\nReason given: %s" % reason

        for session in boot_list:
            session.msg(feedback)
            session.account.disconnect_session_from_account(session)

        if pobj and boot_list:
            logger.log_sec('Booted: %s (Reason: %s, Caller: %s, IP: %s).' % (pobj, reason, caller, self.session.address))
Пример #7
0
    def func(self):
        """create the new character"""
        account = self.account
        if not self.args:
            self.msg("Utilisation : créer <nom du personnage> [= description]")
            return

        key = self.lhs
        desc = self.rhs

        charmax = _MAX_NR_CHARACTERS

        if not account.is_superuser and (
                account.db._playable_characters
                and len(account.db._playable_characters) >= charmax):
            plural = "" if charmax == 1 else "s"
            self.msg(f"Vous pouvez seulement créer un maximum de {charmax} "
                     f"personnage{plural}.")
            return
        from evennia.objects.models import ObjectDB

        typeclass = settings.BASE_CHARACTER_TYPECLASS

        if ObjectDB.objects.filter(db_typeclass_path=typeclass,
                                   db_key__iexact=key):
            # check if this Character already exists. Note that we are only
            # searching the base character typeclass here, not any child
            # classes.
            self.msg(f"|rUn personnage nommé '|w{key}|r' existe déjà.|n")
            return

        # create the character
        start_location = ObjectDB.objects.get_id(settings.START_LOCATION)
        default_home = ObjectDB.objects.get_id(settings.DEFAULT_HOME)
        permissions = settings.PERMISSION_ACCOUNT_DEFAULT
        new_character = create.create_object(typeclass,
                                             key=key,
                                             location=start_location,
                                             home=default_home,
                                             permissions=permissions)
        # only allow creator (and developers) to puppet this char
        new_character.locks.add(
            f"puppet:id({new_character.id}) or pid({account.id}) or "
            f"perm(Developer) or pperm(Developer);delete:id({account.id}) or "
            f"perm(Admin)")
        account.db._playable_characters.append(new_character)
        if desc:
            new_character.db.desc = desc
        elif not new_character.db.desc:
            new_character.db.desc = "Ceci est un personnage"
        self.msg(
            "Nouveau personnage créé : {name}. "
            "Use |wic {name}|n to enter the game as this character.".format(
                name=new_character.key))
        logger.log_sec(
            f"Character Created: {new_character} (Caller: {account}, "
            f"IP: {self.session.address}).")
Пример #8
0
    def func(self):
        """create the new character"""
        account = self.account
        if not self.args:
            self.msg("Usage: charcreate <charname> [= description]")
            return
        key = self.lhs
        desc = self.rhs

        charmax = _MAX_NR_CHARACTERS

        if not account.is_superuser and (
                account.db._playable_characters
                and len(account.db._playable_characters) >= charmax):
            plural = "" if charmax == 1 else "s"
            self.msg(
                f"You may only create a maximum of {charmax} character{plural}."
            )
            return
        from evennia.objects.models import ObjectDB

        typeclass = settings.BASE_CHARACTER_TYPECLASS

        if ObjectDB.objects.filter(db_typeclass_path=typeclass,
                                   db_key__iexact=key):
            # check if this Character already exists. Note that we are only
            # searching the base character typeclass here, not any child
            # classes.
            self.msg("|rA character named '|w%s|r' already exists.|n" % key)
            return

        # create the character
        start_location = ObjectDB.objects.get_id(settings.START_LOCATION)
        default_home = ObjectDB.objects.get_id(settings.DEFAULT_HOME)
        permissions = settings.PERMISSION_ACCOUNT_DEFAULT
        new_character = create.create_object(typeclass,
                                             key=key,
                                             location=start_location,
                                             home=default_home,
                                             permissions=permissions)
        # only allow creator (and developers) to puppet this char
        new_character.locks.add(
            "puppet:id(%i) or pid(%i) or perm(Developer) or pperm(Developer);delete:id(%i) or perm(Admin)"
            % (new_character.id, account.id, account.id))
        account.db._playable_characters.append(new_character)
        if desc:
            new_character.db.desc = desc
        elif not new_character.db.desc:
            new_character.db.desc = "This is a character."
        self.msg(
            "Created new character %s. Use |wic %s|n to enter the game as this character."
            % (new_character.key, new_character.key))
        logger.log_sec("Character Created: %s (Caller: %s, IP: %s)." %
                       (new_character, account, self.session.address))
Пример #9
0
    def func(self):
        """
        Bans are stored in a serverconf db object as a list of
        dictionaries:
          [ (name, ip, ipregex, date, reason),
            (name, ip, ipregex, date, reason),...  ]
        where name and ip are set by the user and are shown in
        lists. ipregex is a converted form of ip where the * is
        replaced by an appropriate regex pattern for fast
        matching. date is the time stamp the ban was instigated and
        'reason' is any optional info given to the command. Unset
        values in each tuple is set to the empty string.
        """
        banlist = ServerConfig.objects.conf('server_bans')
        if not banlist:
            banlist = []

        if not self.args or (self.switches
                             and not any(switch in ('ip', 'name')
                                         for switch in self.switches)):
            self.caller.msg(list_bans(self, banlist))
            return

        now = time.ctime()
        reason = ""
        if ':' in self.args:
            ban, reason = self.args.rsplit(':', 1)
        else:
            ban = self.args
        ban = ban.lower()
        ipban = IPREGEX.findall(ban)
        if not ipban:
            # store as name
            typ = "Name"
            bantup = (ban, "", "", now, reason)
        else:
            # an ip address.
            typ = "IP"
            ban = ipban[0]
            # replace * with regex form and compile it
            ipregex = ban.replace('.', '\.')
            ipregex = ipregex.replace('*', '[0-9]{1,3}')
            ipregex = re.compile(r"%s" % ipregex)
            bantup = ("", ban, ipregex, now, reason)
        # save updated banlist
        banlist.append(bantup)
        ServerConfig.objects.conf('server_bans', banlist)
        self.caller.msg("%s-Ban |w%s|n was added." % (typ, ban))
        logger.log_sec('Banned %s: %s (Caller: %s, IP: %s).' %
                       (typ, ban.strip(), self.caller, self.session.address))
Пример #10
0
    def func(self):
        """implement the function"""

        if not self.args or not self.rhs:
            string = "Usage: cboot[/quiet] <channel> = <account> [:reason]"
            self.msg(string)
            return

        channel = find_channel(self.caller, self.lhs)
        if not channel:
            return
        reason = ""
        if ":" in self.rhs:
            accountname, reason = self.rhs.rsplit(":", 1)
            searchstring = accountname.lstrip("*")
        else:
            searchstring = self.rhs.lstrip("*")
        account = self.caller.search(searchstring, account=True)
        if not account:
            return
        if reason:
            reason = " (reason: %s)" % reason
        if not channel.access(self.caller, "control"):
            string = "You don't control this channel."
            self.msg(string)
            return
        if not channel.subscriptions.has(account):
            string = "Account %s is not connected to channel %s." % (
                account.key, channel.key)
            self.msg(string)
            return
        if "quiet" not in self.switches:
            string = "%s boots %s from channel.%s" % (self.caller, account.key,
                                                      reason)
            channel.msg(string)
        # find all account's nicks linked to this channel and delete them
        for nick in [
                nick for nick in account.character.nicks.get(
                    category="channel") or []
                if nick.value[3].lower() == channel.key
        ]:
            nick.delete()
        # disconnect account
        channel.disconnect(account)
        CHANNELHANDLER.update()
        logger.log_sec(
            "Channel Boot: %s (Channel: %s, Reason: %s, Caller: %s, IP: %s)." %
            (account, channel, reason, self.caller, self.session.address))
Пример #11
0
 def _callback(caller, callback_prompt, result):
     if result.lower() == "yes":
         # only take action
         delobj = caller.ndb._char_to_delete
         key = delobj.key
         caller.db._playable_characters = [
             pc for pc in caller.db._playable_characters
             if pc != delobj
         ]
         delobj.delete()
         self.msg("Character '%s' was permanently deleted." % key)
         logger.log_sec(
             "Character Deleted: %s (Caller: %s, IP: %s)." %
             (key, account, self.session.address))
     else:
         self.msg("Deletion was aborted.")
     del caller.ndb._char_to_delete
Пример #12
0
 def _callback(caller, callback_prompt, result):
     if result.lower() == "oui":
         # only take action
         delobj = caller.ndb._char_to_delete
         key = delobj.key
         caller.db._playable_characters = [
             pc for pc in caller.db._playable_characters
             if pc != delobj
         ]
         delobj.delete()
         self.msg(f"Le personnage '{key}' a été supprimé de "
                  f"manière permanente.")
         logger.log_sec(
             "Character Deleted: %s (Caller: %s, IP: %s)." %
             (key, account, self.session.address))
     else:
         self.msg("La suppression de personnage à été annulée.")
     del caller.ndb._char_to_delete
Пример #13
0
    def func(self):
        """
        Main puppet method
        """
        account = self.account
        session = self.session

        new_character = None
        if not self.args:
            new_character = account.db._last_puppet
            if not new_character:
                self.msg("Usage: ic <character>")
                return
        if not new_character:
            # search for a matching character
            new_character = [
                char for char in search.object_search(self.args) if char.access(account, "puppet")
            ]
            if not new_character:
                self.msg("That is not a valid character choice.")
                return
            if len(new_character) > 1:
                self.msg(
                    "Multiple targets with the same name:\n %s"
                    % ", ".join("%s(#%s)" % (obj.key, obj.id) for obj in new_character)
                )
                return
            else:
                new_character = new_character[0]
        try:
            account.puppet_object(session, new_character)
            account.db._last_puppet = new_character
            logger.log_sec(
                "Puppet Success: (Caller: %s, Target: %s, IP: %s)."
                % (account, new_character, self.session.address)
            )
        except RuntimeError as exc:
            self.msg("|rYou cannot become |C%s|n: %s" % (new_character.name, exc))
            logger.log_sec(
                "Puppet Failed: %s (Caller: %s, Target: %s, IP: %s)."
                % (exc, account, new_character, self.session.address)
            )
Пример #14
0
    def func(self):
        """List the accounts"""

        caller = self.caller
        args = self.args

        if "delete" in self.switches:
            account = getattr(caller, "account")
            if not account or not account.check_permstring("Developer"):
                caller.msg("You are not allowed to delete accounts.")
                return
            if not args:
                caller.msg("Usage: accounts/delete <name or #id> [: reason]")
                return
            reason = ""
            if ":" in args:
                args, reason = [arg.strip() for arg in args.split(":", 1)]
            # We use account_search since we want to be sure to find also accounts
            # that lack characters.
            accounts = search.account_search(args)
            if not accounts:
                self.msg("Could not find an account by that name.")
                return
            if len(accounts) > 1:
                string = "There were multiple matches:\n"
                string += "\n".join(" %s %s" % (account.id, account.key) for account in accounts)
                self.msg(string)
                return
            account = accounts.first()
            if not account.access(caller, "delete"):
                self.msg("You don't have the permissions to delete that account.")
                return
            username = account.username
            # ask for confirmation
            confirm = (
                "It is often better to block access to an account rather than to delete it. "
                "|yAre you sure you want to permanently delete "
                "account '|n{}|y'|n yes/[no]?".format(username)
            )
            answer = yield (confirm)
            if answer.lower() not in ("y", "yes"):
                caller.msg("Canceled deletion.")
                return

            # Boot the account then delete it.
            self.msg("Informing and disconnecting account ...")
            string = "\nYour account '%s' is being *permanently* deleted.\n" % username
            if reason:
                string += " Reason given:\n  '%s'" % reason
            account.msg(string)
            logger.log_sec(
                "Account Deleted: %s (Reason: %s, Caller: %s, IP: %s)."
                % (account, reason, caller, self.session.address)
            )
            account.delete()
            self.msg("Account %s was successfully deleted." % username)
            return

        # No switches, default to displaying a list of accounts.
        if self.args and self.args.isdigit():
            nlim = int(self.args)
        else:
            nlim = 10

        naccounts = AccountDB.objects.count()

        # typeclass table
        dbtotals = AccountDB.objects.object_totals()
        typetable = self.styled_table(
            "|wtypeclass|n", "|wcount|n", "|w%%|n", border="cells", align="l"
        )
        for path, count in dbtotals.items():
            typetable.add_row(path, count, "%.2f" % ((float(count) / naccounts) * 100))
        # last N table
        plyrs = AccountDB.objects.all().order_by("db_date_created")[max(0, naccounts - nlim) :]
        latesttable = self.styled_table(
            "|wcreated|n", "|wdbref|n", "|wname|n", "|wtypeclass|n", border="cells", align="l"
        )
        for ply in plyrs:
            latesttable.add_row(
                utils.datetime_format(ply.date_created), ply.dbref, ply.key, ply.path
            )

        string = "\n|wAccount typeclass distribution:|n\n%s" % typetable
        string += "\n|wLast %s Accounts created:|n\n%s" % (min(naccounts, nlim), latesttable)
        caller.msg(string)
Пример #15
0
    {"connect": r"^[@\s]*[connect]{5,8}\s+(?P<secret>[\w]+)"},
    {"create": r"^[^@]?[create]{5,6}\s+(\w+|\".+?\")\s+(?P<secret>[\w]+)"},
    {"create": r"^[^@]?[create]{5,6}\s+(?P<secret>[\w]+)"},
    {"userpassword": r"^[@\s]*[userpassword]{11,14}\s+(\w+|\".+?\")\s+=*\s*(?P<secret>[\w]+)"},
    {"userpassword": r"^.*new password set to '(?P<secret>[^']+)'\."},
    {"userpassword": r"^.* has changed your password to '(?P<secret>[^']+)'\."},
    {"password": r"^[@\s]*[password]{6,9}\s+(?P<secret>.*)"},
] + getattr(ev_settings, "AUDIT_MASKS", [])


if AUDIT_CALLBACK:
    try:
        AUDIT_CALLBACK = getattr(
            mod_import(".".join(AUDIT_CALLBACK.split(".")[:-1])), AUDIT_CALLBACK.split(".")[-1]
        )
        logger.log_sec("Auditing module online.")
        logger.log_sec(
            "Audit record User input: {}, output: {}.\n"
            "Audit sparse recording: {}, Log callback: {}".format(
                AUDIT_IN, AUDIT_OUT, AUDIT_ALLOW_SPARSE, AUDIT_CALLBACK
            )
        )
    except Exception as e:
        logger.log_err("Failed to activate Auditing module. %s" % e)


class AuditedServerSession(ServerSession):
    """
    This particular implementation parses all server inputs and/or outputs and
    passes a dict containing the parsed metadata to a callback method of your
    creation. This is useful for recording player activity where necessary for
Пример #16
0
    {'connect': r"^[@\s]*[connect]{5,8}\s+(\".+?\"|[^\s]+)\s+(?P<secret>.+)"},
    {'connect': r"^[@\s]*[connect]{5,8}\s+(?P<secret>[\w]+)"},
    {'create': r"^[^@]?[create]{5,6}\s+(\w+|\".+?\")\s+(?P<secret>[\w]+)"},
    {'create': r"^[^@]?[create]{5,6}\s+(?P<secret>[\w]+)"},
    {'userpassword': r"^[@\s]*[userpassword]{11,14}\s+(\w+|\".+?\")\s+=*\s*(?P<secret>[\w]+)"},
    {'userpassword': r"^.*new password set to '(?P<secret>[^']+)'\."},
    {'userpassword': r"^.* has changed your password to '(?P<secret>[^']+)'\."},
    {'password': r"^[@\s]*[password]{6,9}\s+(?P<secret>.*)"},
] + getattr(ev_settings, 'AUDIT_MASKS', [])


if AUDIT_CALLBACK:
    try:
        AUDIT_CALLBACK = getattr(
            mod_import('.'.join(AUDIT_CALLBACK.split('.')[:-1])), AUDIT_CALLBACK.split('.')[-1])
        logger.log_sec("Auditing module online.")
        logger.log_sec("Audit record User input: {}, output: {}.\n"
                       "Audit sparse recording: {}, Log callback: {}".format(
                            AUDIT_IN, AUDIT_OUT, AUDIT_ALLOW_SPARSE, AUDIT_CALLBACK))
    except Exception as e:
        logger.log_err("Failed to activate Auditing module. %s" % e)


class AuditedServerSession(ServerSession):
    """
    This particular implementation parses all server inputs and/or outputs and
    passes a dict containing the parsed metadata to a callback method of your
    creation. This is useful for recording player activity where necessary for
    security auditing, usage analysis or post-incident forensic discovery.

    *** WARNING ***
Пример #17
0
    def func(self):
        """create the new character"""
        # This is the top level menu
        account = self.account
        if self.args:
            self.msg(
                "Usage: despite the directions above, just type 'charcreate' without arguments"
            )
            return

        charmax = _MAX_NR_CHARACTERS

        if not account.is_superuser and (
                account.db._playable_characters
                and len(account.db._playable_characters) >= charmax):
            self.msg("You may only create a maximum of %i characters." %
                     charmax)
            return
        self.msg("About to create a character")
        from evennia.objects.models import ObjectDB

        genders = ['f', 'm']
        while True:
            answer = yield ("Please select a gender: [(F)emale/(M)ale] ")
            answer = answer.strip().lower()
            if answer.lower() in genders:
                self.gender = int(genders.index(answer) + 1)
                break
            else:
                self.msg(
                    "I'm afraid that was not an acceptable answer. Please try  again."
                )

        clan_list = list(self.gentes.keys())
        for index, value in enumerate(clan_list):
            self.msg(f"{index + 1}) |c{value}|n")
        self.msg(
            "\nIn ancient Rome, the 'gens' was the largest kin unit, comprising several families who shared a common name. A Roman's 'nomen,' or primary name, would be based on their 'gens;' for example, a man belonging to the 'gens Sempronia' would be known as 'Sempronius' and a woman from that same gens would be 'Sempronia.'\n"
        )
        while True:
            answer = yield (f"Select a gens: (1-{len(clan_list)}) ")
            answer = int(answer)
            if answer in range(1, len(clan_list) + 1):
                self.gens = clan_list[answer - 1]
                if self.gender == 2:
                    self.nomen = self.gens[:-1] + 'us'
                else:
                    self.nomen = self.gens
                break
            else:
                self.msg(
                    "I'm sorry. That was not an acceptable answer. Please try again."
                )
        self.msg(f"\nYou have selected '{self.gens}' as your gens.")

        self.msg(
            "\nThe 'praenomen' was used by intimates and immediate family members. The available 'praenomina' are determined by a person's 'gens' and gender.\n\n"
        )
        temp_names = self.gentes[self.gens]['praenomina']
        if self.gender == 1:
            for index, value in enumerate(temp_names):
                if value in ['Marcus', 'Titus', 'Tullus']:
                    temp_names[index] = value[:-2] + 'ia'
                elif value[-2:] == 'us':
                    temp_names[index] = value[:-2] + 'a'
                elif value == 'Agrippa':
                    temp_names[index] = 'Agrippina'
                elif value == 'Caeso':
                    temp_names[index] = 'Caesula'
                elif value == 'Opiter':
                    temp_names[index] = 'Opita'
                elif value == 'Sertor':
                    temp_names[index] = 'Sertora'
                elif value == 'Volero':
                    temp_names[index] = 'Volerona'

        for index, value in enumerate(temp_names):
            self.msg(f"{index + 1}) |c{value}|n")
        while True:
            answer = yield (f"\nSelect a praenomen: (1-{len(temp_names)})")
            answer = int(answer)
            if answer in range(1, len(temp_names) + 1):
                self.praenomen = temp_names[answer - 1].strip()
                break
            else:
                self.msg("I'm sorry. That is not an acceptable answer.")
                return
        if self.praenomen[-1] == 'a':
            self.genitive = self.praenomen + 'e'
        elif self.praenomen[-1] == 'r':
            self.genitive = self.praenomen + 'is'
        elif self.praenomen[-2:] == 'us':
            self.genitive = self.praenomen[:-2] + 'i'
        else:
            self.genitive = self.praenomen + 'nis'

        self.msg(f"\nYou have selected '{self.praenomen}' as your praenomen.")

        #
        # Create stats
        #
        def makeStats():
            statNums = [0, 0, 0, 0, 0, 0]
            points = 27
            while points > 0:
                index = random.randint(0, 5)
                if statNums[index] < 5 and points > 0:
                    statNums[index] += 1
                    points -= 1
                elif statNums[index] in [5, 6] and points > 1:
                    statNums[index] += 1
                    points -= 2
            for index, value in enumerate(statNums):
                statNums[index] += 9
            return statNums
#
# Roll and/or reroll stats
#

        self.msg(
            "\nThe following character attributes are based on the point-buy system from the 5th edition of 'Dungeons and Dragons,' which means each group of generated attributes has an equivalent value overall. Still, please feel free to generate a new set if the first does not appeal.\n\n"
        )
        self.msg('The minimum value is 9, the maximum is 16')
        self.msg('The English equivalents are:\n\n')
        self.msg('Vires: Strength')
        self.msg('Celeritas: Speed')
        self.msg('Valetudo: Constitution')
        self.msg('Scientia: Intelligence')
        self.msg('Sapientia: Wisdom')
        self.msg('Gratia: Charisma\n\n')

        while True:
            stats = makeStats()
            answer = yield (
                f"Vires: |c{stats[0]}|n Celeritas: |c{stats[1]}|n Valetudo: |c{stats[2]}|n Scientia: |c{stats[3]}|n Sapientia: |c{stats[4]}|n Gratia: |c{stats[5]}|n; Are these acceptable? [(Y)es/(N)o] "
            )
            while True:
                if answer.lower() in ['y', 'yes', 'n', 'no']:
                    break
                else:
                    answer = yield ("Please select: [(Y)es/(N)o] ")
            if answer in ['y', 'yes']:
                self.stats = stats
                break

        self.name = self.praenomen + ' ' + self.nomen

        self.msg(f"You are about to create a character named {self.name}")

        typeclass = settings.BASE_CHARACTER_TYPECLASS

        if ObjectDB.objects.filter(db_typeclass_path=typeclass,
                                   db_key__iexact=self.name):
            # check if this Character already exists. Note that we are only
            # searching the base character typeclass here, not any child
            # classes.
            self.msg("|rA character named '|w%s|r' already exists.|n" %
                     self.name)
            return

        # create the character


#        start_location = ObjectDB.objects.get_id(settings.START_LOCATION)
        default_home = ObjectDB.objects.get_id(settings.DEFAULT_HOME)
        self.msg("Before assigning permissions")
        permissions = settings.PERMISSION_ACCOUNT_DEFAULT
        self.msg("after assigning permissions")
        nom_list = [self.praenomen]
        gen_list = [self.genitive]
        self.msg(f"nom: {nom_list}; gen: {gen_list}")
        new_character = create.create_object(
            typeclass,
            key=self.name,
            #                location=start_location,
            home=default_home,
            permissions=permissions,
            attributes=[('gens', self.gens), ('gender', self.gender),
                        ('praenomen', self.praenomen), ('nomen', self.nomen),
                        ('age', 18), ('nom_sg', nom_list),
                        ('gen_sg', gen_list),
                        ('stats', {
                            'str': self.stats[0],
                            'dex': self.stats[1],
                            'con': self.stats[2],
                            'int': self.stats[3],
                            'wis': self.stats[4],
                            'cha': self.stats[5]
                        })])
        # only allow creator (and developers) to puppet this char
        new_character.locks.add(
            "puppet:id(%i) or pid(%i) or perm(Developer) or pperm(Developer);delete:id(%i) or perm(Admin)"
            % (new_character.id, account.id, account.id))
        account.db._playable_characters.append(new_character)
        if desc:
            new_character.db.desc = desc
        else:
            new_character.db.desc = "This is a character."
        self.msg(
            "Created new character %s. Use |wic %s|n to enter the game as this character."
            % (new_character.key, new_character.key))
        logger.log_sec("Character Created: %s (Caller: %s, IP: %s)." %
                       (new_character, account, self.session.address))

        self.msg(
            f"You have successfully created: {praenomen} of the gens {gens}")
Пример #18
0
    def func(self):
        """Implement function"""

        caller = self.caller
        switches = self.switches
        lhs, rhs = self.lhs, self.rhs

        if not self.args:
            string = "Usage: perm[/switch] object [ = permission, permission, ...]"
            caller.msg(string)
            return

        accountmode = 'account' in self.switches or lhs.startswith('*')
        lhs = lhs.lstrip("*")

        if accountmode:
            obj = caller.search_account(lhs)
        else:
            obj = caller.search(lhs, global_search=True)
        if not obj:
            return

        if not rhs:
            if not obj.access(caller, 'examine'):
                caller.msg("You are not allowed to examine this object.")
                return

            string = "Permissions on |w%s|n: " % obj.key
            if not obj.permissions.all():
                string += "<None>"
            else:
                string += ", ".join(obj.permissions.all())
                if (hasattr(obj, 'account')
                        and hasattr(obj.account, 'is_superuser')
                        and obj.account.is_superuser):
                    string += "\n(... but this object is currently controlled by a SUPERUSER! "
                    string += "All access checks are passed automatically.)"
            caller.msg(string)
            return

        # we supplied an argument on the form obj = perm
        locktype = "edit" if accountmode else "control"
        if not obj.access(caller, locktype):
            caller.msg("You are not allowed to edit this %s's permissions." %
                       ("account" if accountmode else "object"))
            return

        caller_result = []
        target_result = []
        if 'del' in switches:
            # delete the given permission(s) from object.
            for perm in self.rhslist:
                obj.permissions.remove(perm)
                if obj.permissions.get(perm):
                    caller_result.append(
                        "\nPermissions %s could not be removed from %s." %
                        (perm, obj.name))
                else:
                    caller_result.append(
                        "\nPermission %s removed from %s (if they existed)." %
                        (perm, obj.name))
                    target_result.append(
                        "\n%s revokes the permission(s) %s from you." %
                        (caller.name, perm))
                    logger.log_sec(
                        'Permissions Deleted: %s, %s (Caller: %s, IP: %s).' %
                        (perm, obj, caller, self.session.address))
        else:
            # add a new permission
            permissions = obj.permissions.all()

            for perm in self.rhslist:

                # don't allow to set a permission higher in the hierarchy than
                # the one the caller has (to prevent self-escalation)
                if (perm.lower() in PERMISSION_HIERARCHY
                        and not obj.locks.check_lockstring(
                            caller, "dummy:perm(%s)" % perm)):
                    caller.msg(
                        "You cannot assign a permission higher than the one you have yourself."
                    )
                    return

                if perm in permissions:
                    caller_result.append(
                        "\nPermission '%s' is already defined on %s." %
                        (perm, obj.name))
                else:
                    obj.permissions.add(perm)
                    plystring = "the Account" if accountmode else "the Object/Character"
                    caller_result.append(
                        "\nPermission '%s' given to %s (%s)." %
                        (perm, obj.name, plystring))
                    target_result.append(
                        "\n%s gives you (%s, %s) the permission '%s'." %
                        (caller.name, obj.name, plystring, perm))
                    logger.log_sec(
                        'Permissions Added: %s, %s (Caller: %s, IP: %s).' %
                        (obj, perm, caller, self.session.address))

        caller.msg("".join(caller_result).strip())
        if target_result:
            obj.msg("".join(target_result).strip())
Пример #19
0
    def func(self):
        """
        Main puppet method
        """
        account = self.account
        session = self.session

        new_character = None
        character_candidates = []

        if not self.args:
            character_candidates = [account.db._last_puppet
                                    ] if account.db._last_puppet else []
            if not character_candidates:
                self.msg("Usage: ic <character>")
                return
        else:
            # argument given

            if account.db._playable_characters:
                # look at the playable_characters list first
                character_candidates.extend(
                    account.search(
                        self.args,
                        candidates=account.db._playable_characters,
                        search_object=True,
                        quiet=True,
                    ))

            if account.locks.check_lockstring(account, "perm(Builder)"):
                # builders and higher should be able to puppet more than their
                # playable characters.
                if session.puppet:
                    # start by local search - this helps to avoid the user
                    # getting locked into their playable characters should one
                    # happen to be named the same as another. We replace the suggestion
                    # from playable_characters here - this allows builders to puppet objects
                    # with the same name as their playable chars should it be necessary
                    # (by going to the same location).
                    character_candidates = [
                        char for char in session.puppet.search(self.args,
                                                               quiet=True)
                        if char.access(account, "puppet")
                    ]
                if not character_candidates:
                    # fall back to global search only if Builder+ has no
                    # playable_characers in list and is not standing in a room
                    # with a matching char.
                    character_candidates.extend([
                        char for char in search.object_search(self.args)
                        if char.access(account, "puppet")
                    ])

        # handle possible candidates
        if not character_candidates:
            self.msg("That is not a valid character choice.")
            return
        if len(character_candidates) > 1:
            self.msg("Multiple targets with the same name:\n %s" %
                     ", ".join("%s(#%s)" % (obj.key, obj.id)
                               for obj in character_candidates))
            return
        else:
            new_character = character_candidates[0]

        # do the puppet puppet
        try:
            account.puppet_object(session, new_character)
            account.db._last_puppet = new_character
            logger.log_sec(
                "Puppet Success: (Caller: %s, Target: %s, IP: %s)." %
                (account, new_character, self.session.address))
        except RuntimeError as exc:
            self.msg("|rYou cannot become |C%s|n: %s" %
                     (new_character.name, exc))
            logger.log_sec(
                "Puppet Failed: %s (Caller: %s, Target: %s, IP: %s)." %
                (exc, account, new_character, self.session.address))