Refactor Permissions documentation
This commit is contained in:
parent
2a8cc57bbe
commit
73990e851c
1 changed files with 148 additions and 65 deletions
|
|
@ -3,12 +3,119 @@
|
||||||
A *permission* is simply a text string stored in the handler `permissions` on `Objects`
|
A *permission* is simply a text string stored in the handler `permissions` on `Objects`
|
||||||
and `Accounts`. Think of it as a specialized sort of [Tag](./Tags) - one specifically dedicated
|
and `Accounts`. Think of it as a specialized sort of [Tag](./Tags) - one specifically dedicated
|
||||||
to access checking. They are thus often tightly coupled to [Locks](./Locks).
|
to access checking. They are thus often tightly coupled to [Locks](./Locks).
|
||||||
|
Permission strings are not case-sensitive, so "Builder" is the same as "builder"
|
||||||
|
etc.
|
||||||
|
|
||||||
Permissions are used as a convenient way to structure access levels and
|
Permissions are used as a convenient way to structure access levels and
|
||||||
hierarchies. It is set by the `perm` command. Permissions are especially
|
hierarchies. It is set by the `perm` command and checked by the
|
||||||
handled by the `perm()` and `pperm()` [lock functions](./Locks).
|
`PermissionHandler.check` method as well as by the specially the `perm()` and
|
||||||
|
`pperm()` [lock functions](./Locks).
|
||||||
|
|
||||||
Let's say we have a `red_key` object. We also have red chests that we want to unlock with this key.
|
All new accounts are given a default set of permissions defined by
|
||||||
|
`settings.PERMISSION_ACCOUNT_DEFAULT`.
|
||||||
|
|
||||||
|
## Managing Permissions
|
||||||
|
|
||||||
|
In-game, you use the `perm` command to add and remove permissions
|
||||||
|
|
||||||
|
perm/account Tommy = Builders
|
||||||
|
perm/account/del Tommy = Builders
|
||||||
|
|
||||||
|
Note the use of the `/account` switch. It means you assign the permission to the
|
||||||
|
[Accounts](./Accounts) Tommy instead of any [Character](./Objects) that also
|
||||||
|
happens to be named "Tommy".
|
||||||
|
|
||||||
|
There can be reasons for putting permissions on Objects (especially NPCS), but
|
||||||
|
for granting powers to players, you should usually put the permission on the
|
||||||
|
`Account` - this guarantees that they are kept, *regardless*
|
||||||
|
of which Character they are currently puppeting. This is especially important to
|
||||||
|
remember when assigning permissions from the *hierarchy tree* (see below), as an
|
||||||
|
Account's permissions will overrule that of its character. So to be sure to
|
||||||
|
avoid confusion you should generally put hierarchy permissions on the Account,
|
||||||
|
not on their Characters (but see also [quelling](./Locks#Quelling)).
|
||||||
|
|
||||||
|
In code, you add/remove Permissions via the `PermissionHandler`, which sits on all
|
||||||
|
typeclassed entities as the property `.permissions`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
account.permissions.add("Builders")
|
||||||
|
account.permissions.add("cool_guy")
|
||||||
|
obj.permissions.add("Blacksmith")
|
||||||
|
obj.permissions.remove("Blacksmith")
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## The permission hierarchy
|
||||||
|
|
||||||
|
Selected permission strings can be organized in a *permission hierarchy* by editing the tuple
|
||||||
|
`settings.PERMISSION_HIERARCHY`. Evennia's default permission hierarchy is as follows
|
||||||
|
(in increasing order of power):
|
||||||
|
|
||||||
|
Player # can chat and send tells (default level) (lowest)
|
||||||
|
Helper # can edit help files
|
||||||
|
Builder # can edit the world
|
||||||
|
Admin # can administrate accounts
|
||||||
|
Developer # like superuser but affected by locks (highest)
|
||||||
|
|
||||||
|
(Besides being case-insensitive, hierarchical permissions also understand the
|
||||||
|
plural form, so you could use `Developers` and `Developer` interchangeably).
|
||||||
|
|
||||||
|
> There is also a `Guest` level below `Player` that is only active if `settings.GUEST_ENABLED` is
|
||||||
|
set. The Guest is is never part of `settings.PERMISSION_HIERARCHY`.
|
||||||
|
|
||||||
|
When checking a hierarchical permission (using one of the methods to follow),
|
||||||
|
you will pass checks for your level and all *below* you. That is, even if the
|
||||||
|
check explicitly checks for "Builder" level access, you will actually pass if you have
|
||||||
|
one of "Builder", "Admin" or "Developer". By contrast, if you check for a
|
||||||
|
non-hierarchical permission, like "Blacksmith" you *must* have exactly
|
||||||
|
that permission to pass.
|
||||||
|
|
||||||
|
## Checking permissions
|
||||||
|
|
||||||
|
It's important to note that you check for the permission of a *puppeted*
|
||||||
|
[Object](./Objects) (like a Character), the check will always first use the
|
||||||
|
permissions of any `Account` connected to that Object before checking for
|
||||||
|
permissions on the Object. In the case of hierarchical permissions (Admins,
|
||||||
|
Builders etc), the Account permission will always be used (this stops an Account
|
||||||
|
from escalating their permission by puppeting a high-level Character). If the
|
||||||
|
permission looked for is not in the hierarchy, an exact match is required, first
|
||||||
|
on the Account and if not found there (or if no Account is connected), then on
|
||||||
|
the Object itself.
|
||||||
|
|
||||||
|
### Checking with obj.permissions.check()
|
||||||
|
|
||||||
|
The simplest way to check if an entity has a permission is to check its
|
||||||
|
_PermissionHandler_, stored as `.permissions` on all typeclassed entities.
|
||||||
|
|
||||||
|
if obj.permissions.check("Builder"):
|
||||||
|
# allow builder to do stuff
|
||||||
|
|
||||||
|
if obj.permissions.check("Blacksmith", "Warrior"):
|
||||||
|
# do stuff for blacksmiths OR warriors
|
||||||
|
|
||||||
|
if obj.permissions.check("Blacksmith", "Warrior", require_all=True):
|
||||||
|
# only for those that are both blacksmiths AND warriors
|
||||||
|
|
||||||
|
Using the `.check` method is the way to go, it will take hierarchical
|
||||||
|
permissions into account, check accounts/sessions etc.
|
||||||
|
|
||||||
|
```warning
|
||||||
|
|
||||||
|
Don't confuse `.permissions.check()` with `.permissions.has()`. The .has()
|
||||||
|
method checks if a string is defined specifically on that PermissionHandler.
|
||||||
|
It will not consider permission-hierarchy, puppeting etc. `.has` can be useful
|
||||||
|
if you are manipulating permissions, but use `.check` for access checking.
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lock funcs
|
||||||
|
|
||||||
|
While the `PermissionHandler` offers a simple way to check perms, [Lock
|
||||||
|
strings](Locks) offers a mini-language for describing how something is accessed.
|
||||||
|
The `perm()` _lock function_ is the main tool for using Permissions in locks.
|
||||||
|
|
||||||
|
Let's say we have a `red_key` object. We also have red chests that we want to
|
||||||
|
unlock with this key.
|
||||||
|
|
||||||
perm red_key = unlocks_red_chests
|
perm red_key = unlocks_red_chests
|
||||||
|
|
||||||
|
|
@ -32,87 +139,63 @@ class TreasureChest(Object):
|
||||||
if not chest.access(who, tried_key, "unlock"):
|
if not chest.access(who, tried_key, "unlock"):
|
||||||
who.msg("The key does not fit!")
|
who.msg("The key does not fit!")
|
||||||
return
|
return
|
||||||
|
else:
|
||||||
|
who.msg("The key fits! The chest opens.")
|
||||||
|
# ...
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
All new accounts are given a default set of permissions defined by
|
There are several variations to the default `perm` lockfunc:
|
||||||
`settings.PERMISSION_ACCOUNT_DEFAULT`.
|
|
||||||
|
|
||||||
Selected permission strings can be organized in a *permission hierarchy* by editing the tuple
|
- `perm_above` - requires a hierarchical permission *higher* than the one
|
||||||
`settings.PERMISSION_HIERARCHY`. Evennia's default permission hierarchy is as follows:
|
provided. Example: `"edit: perm_above(Player)"`
|
||||||
|
- `pperm` - looks *only* for permissions on `Accounts`, never at any puppeted
|
||||||
|
objects (regardless of hierarchical perm or not).
|
||||||
|
- `pperm_above` - like `perm_above`, but for Accounts only.
|
||||||
|
|
||||||
Developer # like superuser but affected by locks
|
|
||||||
Admin # can administrate accounts
|
|
||||||
Builder # can edit the world
|
|
||||||
Helper # can edit help files
|
|
||||||
Player # can chat and send tells (default level)
|
|
||||||
|
|
||||||
(Also the plural form works, so you could use `Developers` etc too).
|
### Some examples
|
||||||
|
|
||||||
> There is also a `Guest` level below `Player` that is only active if `settings.GUEST_ENABLED` is
|
Adding permissions and checking with locks
|
||||||
set. This is never part of `settings.PERMISSION_HIERARCHY`.
|
|
||||||
|
|
||||||
The main use of this is that if you use the lock function `perm()` mentioned above, a lock check for
|
|
||||||
a particular permission in the hierarchy will *also* grant access to those with *higher* hierarchy
|
|
||||||
access. So if you have the permission "Admin" you will also pass a lock defined as `perm(Builder)`
|
|
||||||
or any of those levels below "Admin".
|
|
||||||
|
|
||||||
When doing an access check from an [Object](./Objects) or Character, the `perm()` lock function will
|
|
||||||
always first use the permissions of any Account connected to that Object before checking for
|
|
||||||
permissions on the Object. In the case of hierarchical permissions (Admins, Builders etc), the
|
|
||||||
Account permission will always be used (this stops an Account from escalating their permission by
|
|
||||||
puppeting a high-level Character). If the permission looked for is not in the hierarchy, an exact
|
|
||||||
match is required, first on the Account and if not found there (or if no Account is connected), then
|
|
||||||
on the Object itself.
|
|
||||||
|
|
||||||
Here is how you use `perm` to give an account more permissions:
|
|
||||||
|
|
||||||
perm/account Tommy = Builders
|
|
||||||
perm/account/del Tommy = Builders # remove it again
|
|
||||||
|
|
||||||
Note the use of the `/account` switch. It means you assign the permission to the
|
|
||||||
[Accounts](./Accounts) Tommy instead of any [Character](./Objects) that also happens to be named
|
|
||||||
"Tommy".
|
|
||||||
|
|
||||||
Putting permissions on the *Account* guarantees that they are kept, *regardless* of which Character
|
|
||||||
they are currently puppeting. This is especially important to remember when assigning permissions
|
|
||||||
from the *hierarchy tree* - as mentioned above, an Account's permissions will overrule that of its
|
|
||||||
character. So to be sure to avoid confusion you should generally put hierarchy permissions on the
|
|
||||||
Account, not on their Characters (but see also [quelling](./Locks#Quelling)).
|
|
||||||
|
|
||||||
Below is an example of an object without any connected account
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
obj1.permissions = ["Builders", "cool_guy"]
|
account.permissions.add("Builder")
|
||||||
obj2.locks.add("enter:perm_above(Accounts) and perm(cool_guy)")
|
account.permissions.add("cool_guy")
|
||||||
|
account.locks.add("enter:perm_above(Player) and perm(cool_guy)")
|
||||||
obj2.access(obj1, "enter") # this returns True!
|
account.access(obj1, "enter") # this returns True!
|
||||||
```
|
```
|
||||||
|
|
||||||
And one example of a puppet with a connected account:
|
An example of a puppet with a connected account:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
account.permissions.add("Accounts")
|
account.permissions.add("Player")
|
||||||
puppet.permissions.add("Builders", "cool_guy")
|
puppet.permissions.add("Builders")
|
||||||
|
puppet.permissions.add("cool_guy")
|
||||||
obj2.locks.add("enter:perm_above(Accounts) and perm(cool_guy)")
|
obj2.locks.add("enter:perm_above(Accounts) and perm(cool_guy)")
|
||||||
|
|
||||||
obj2.access(puppet, "enter") # this returns False!
|
obj2.access(puppet, "enter") # this returns False, since puppet permission
|
||||||
|
# is lower than Account's perm, and perm takes
|
||||||
|
# precedence.
|
||||||
```
|
```
|
||||||
|
|
||||||
## Superusers
|
## Superusers
|
||||||
|
|
||||||
There is normally only one *superuser* account and that is the one first created when starting
|
There is normally only one *superuser* account and that is the one first created
|
||||||
Evennia (User #1). This is sometimes known as the "Owner" or "God" user. A superuser has more than
|
when starting Evennia (User #1). This is sometimes known as the "Owner" or "God"
|
||||||
full access - it completely *bypasses* all locks so no checks are even run. This allows for the
|
user. A superuser has more than full access - it completely *bypasses* all
|
||||||
superuser to always have access to everything in an emergency. But it also hides any eventual errors
|
locks and will always pass the `PermissionHandler.check()` check. This allows
|
||||||
you might have made in your lock definitions. So when trying out game systems you should either use
|
for the superuser to always have access to everything in an emergency. But it
|
||||||
quelling (see below) or make a second Developer-level character so your locks get tested correctly.
|
could also hide any eventual errors you might have made in your lock definitions. So
|
||||||
|
when trying out game systems you should either use quelling (see below) or make
|
||||||
|
a second Developer-level character that does not bypass such checks.
|
||||||
|
|
||||||
## Quelling
|
## Quelling
|
||||||
|
|
||||||
The `quell` command can be used to enforce the `perm()` lockfunc to ignore permissions on the
|
The `quell` command can be used to enforce the `perm()` lockfunc to ignore
|
||||||
Account and instead use the permissions on the Character only. This can be used e.g. by staff to
|
permissions on the Account and instead use the permissions on the Character
|
||||||
test out things with a lower permission level. Return to the normal operation with `unquell`. Note
|
only. This can be used e.g. by staff to test out things with a lower permission
|
||||||
that quelling will use the smallest of any hierarchical permission on the Account or Character, so
|
level. Return to the normal operation with `unquell`. Note that quelling will
|
||||||
one cannot escalate one's Account permission by quelling to a high-permission Character. Also the
|
use the smallest of any hierarchical permission on the Account or Character, so
|
||||||
superuser can quell their powers this way, making them affectable by locks.
|
one cannot escalate one's Account permission by quelling to a high-permission
|
||||||
|
Character. Also the superuser can quell their powers this way, making them
|
||||||
|
affectable by locks.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue