evennia/docs/6.x/Components/Locks.html
2026-02-15 19:06:04 +01:00

463 lines
No EOL
52 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en" data-content_root="../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Locks &#8212; Evennia latest documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=d75fae25" />
<link rel="stylesheet" type="text/css" href="../_static/nature.css?v=279e0f84" />
<link rel="stylesheet" type="text/css" href="../_static/custom.css?v=e4a91a55" />
<script src="../_static/documentation_options.js?v=c6e86fd7"></script>
<script src="../_static/doctools.js?v=9bcbadda"></script>
<script src="../_static/sphinx_highlight.js?v=dc90522c"></script>
<link rel="icon" href="../_static/favicon.ico"/>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="next" title="Commands" href="Commands.html" />
<link rel="prev" title="Permissions" href="Permissions.html" />
</head><body>
<div class="related" role="navigation" aria-label="Related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Commands.html" title="Commands"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Permissions.html" title="Permissions"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Locks</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="locks">
<h1>Locks<a class="headerlink" href="#locks" title="Link to this heading"></a></h1>
<p>For most games it is a good idea to restrict what people can do. In Evennia such restrictions are applied and checked by something called <em>locks</em>. All Evennia entities (<a class="reference internal" href="Commands.html"><span class="std std-doc">Commands</span></a>, <a class="reference internal" href="Objects.html"><span class="std std-doc">Objects</span></a>, <a class="reference internal" href="Scripts.html"><span class="std std-doc">Scripts</span></a>, <a class="reference internal" href="Accounts.html"><span class="std std-doc">Accounts</span></a>, <a class="reference internal" href="Help-System.html"><span class="std std-doc">Help System</span></a>, <a class="reference internal" href="Msg.html"><span class="std std-doc">messages</span></a> and <a class="reference internal" href="Channels.html"><span class="std std-doc">channels</span></a>) are accessed through locks.</p>
<p>A lock can be thought of as an “access rule” restricting a particular use of an Evennia entity.
Whenever another entity wants that kind of access the lock will analyze that entity in different ways to determine if access should be granted or not. Evennia implements a “lockdown” philosophy - all entities are inaccessible unless you explicitly define a lock that allows some or full access.</p>
<p>Lets take an example: An object has a lock on itself that restricts how people may “delete” that object. Apart from knowing that it restricts deletion, the lock also knows that only players with the specific ID of, say, <code class="docutils literal notranslate"><span class="pre">34</span></code> are allowed to delete it. So whenever a player tries to run <code class="docutils literal notranslate"><span class="pre">delete</span></code> on the object, the <code class="docutils literal notranslate"><span class="pre">delete</span></code> command makes sure to check if this player is really allowed to do so. It calls the lock, which in turn checks if the players id is <code class="docutils literal notranslate"><span class="pre">34</span></code>. Only then will it allow <code class="docutils literal notranslate"><span class="pre">delete</span></code> to go on with its job.</p>
<section id="working-with-locks">
<h2>Working with locks<a class="headerlink" href="#working-with-locks" title="Link to this heading"></a></h2>
<p>The in-game command for setting locks on objects is <code class="docutils literal notranslate"><span class="pre">lock</span></code>:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> &gt; lock obj = &lt;lockstring&gt;
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">&lt;lockstring&gt;</span></code> is a string of a certain form that defines the behaviour of the lock. We will go into more detail on how <code class="docutils literal notranslate"><span class="pre">&lt;lockstring&gt;</span></code> should look in the next section.</p>
<p>Code-wise, Evennia handles locks through what is usually called <code class="docutils literal notranslate"><span class="pre">locks</span></code> on all relevant entities. This is a handler that allows you to add, delete and check locks.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">myobj</span><span class="o">.</span><span class="n">locks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="o">&lt;</span><span class="n">lockstring</span><span class="o">&gt;</span><span class="p">)</span>
</pre></div>
</div>
<p>One can call <code class="docutils literal notranslate"><span class="pre">locks.check()</span></code> to perform a lock check, but to hide the underlying implementation all objects also have a convenience function called <code class="docutils literal notranslate"><span class="pre">access</span></code>. This should preferably be used. In the example below, <code class="docutils literal notranslate"><span class="pre">accessing_obj</span></code> is the object requesting the delete access whereas <code class="docutils literal notranslate"><span class="pre">obj</span></code> is the object that might get deleted. This is how it would look (and does look) from inside the <code class="docutils literal notranslate"><span class="pre">delete</span></code> command:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="k">if</span> <span class="ow">not</span> <span class="n">obj</span><span class="o">.</span><span class="n">access</span><span class="p">(</span><span class="n">accessing_obj</span><span class="p">,</span> <span class="s1">&#39;delete&#39;</span><span class="p">):</span>
<span class="n">accessing_obj</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;Sorry, you may not delete that.&quot;</span><span class="p">)</span>
<span class="k">return</span>
</pre></div>
</div>
<section id="defining-locks">
<h3>Defining locks<a class="headerlink" href="#defining-locks" title="Link to this heading"></a></h3>
<p>Defining a lock (i.e. an access restriction) in Evennia is done by adding simple strings of lock
definitions to the objects <code class="docutils literal notranslate"><span class="pre">locks</span></code> property using <code class="docutils literal notranslate"><span class="pre">obj.locks.add()</span></code>.</p>
<p>Here are some examples of lock strings (not including the quotes):</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">delete</span><span class="p">:</span><span class="nb">id</span><span class="p">(</span><span class="mi">34</span><span class="p">)</span> <span class="c1"># only allow obj #34 to delete</span>
<span class="n">edit</span><span class="p">:</span><span class="nb">all</span><span class="p">()</span> <span class="c1"># let everyone edit</span>
<span class="c1"># only those who are not &quot;very_weak&quot; or are Admins may pick this up</span>
<span class="n">get</span><span class="p">:</span> <span class="ow">not</span> <span class="n">attr</span><span class="p">(</span><span class="n">very_weak</span><span class="p">)</span> <span class="ow">or</span> <span class="n">perm</span><span class="p">(</span><span class="n">Admin</span><span class="p">)</span>
</pre></div>
</div>
<p>Formally, a lockstring has the following syntax:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">access_type</span><span class="p">:</span> <span class="p">[</span><span class="n">NOT</span><span class="p">]</span> <span class="n">lockfunc1</span><span class="p">([</span><span class="n">arg1</span><span class="p">,</span><span class="o">..</span><span class="p">])</span> <span class="p">[</span><span class="n">AND</span><span class="o">|</span><span class="n">OR</span><span class="p">]</span> <span class="p">[</span><span class="n">NOT</span><span class="p">]</span> <span class="n">lockfunc2</span><span class="p">([</span><span class="n">arg1</span><span class="p">,</span><span class="o">...</span><span class="p">])</span> <span class="p">[</span><span class="o">...</span><span class="p">]</span>
</pre></div>
</div>
<p>where <code class="docutils literal notranslate"><span class="pre">[]</span></code> marks optional parts. <code class="docutils literal notranslate"><span class="pre">AND</span></code>, <code class="docutils literal notranslate"><span class="pre">OR</span></code> and <code class="docutils literal notranslate"><span class="pre">NOT</span></code> are not case sensitive and excess spaces are ignored. <code class="docutils literal notranslate"><span class="pre">lockfunc1,</span> <span class="pre">lockfunc2</span></code> etc are special <em>lock functions</em> available to the lock system.</p>
<p>So, a lockstring consists of the type of restriction (the <code class="docutils literal notranslate"><span class="pre">access_type</span></code>), a colon (<code class="docutils literal notranslate"><span class="pre">:</span></code>) and then an expression involving function calls that determine what is needed to pass the lock. Each function returns either <code class="docutils literal notranslate"><span class="pre">True</span></code> or <code class="docutils literal notranslate"><span class="pre">False</span></code>. <code class="docutils literal notranslate"><span class="pre">AND</span></code>, <code class="docutils literal notranslate"><span class="pre">OR</span></code> and <code class="docutils literal notranslate"><span class="pre">NOT</span></code> work as they do normally in Python. If the total result is <code class="docutils literal notranslate"><span class="pre">True</span></code>, the lock is passed.</p>
<p>You can create several lock types one after the other by separating them with a semicolon (<code class="docutils literal notranslate"><span class="pre">;</span></code>) in the lockstring. The string below yields the same result as the previous example:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>delete:id(34);edit:all();get: not attr(very_weak) or perm(Admin)
</pre></div>
</div>
</section>
<section id="valid-access-types">
<h3>Valid access_types<a class="headerlink" href="#valid-access-types" title="Link to this heading"></a></h3>
<p>An <code class="docutils literal notranslate"><span class="pre">access_type</span></code>, the first part of a lockstring, defines what kind of capability a lock controls, such as “delete” or “edit”. You may in principle name your <code class="docutils literal notranslate"><span class="pre">access_type</span></code> anything as long as it is unique for the particular object. The name of the access types is not case-sensitive.</p>
<p>If you want to make sure the lock is used however, you should pick <code class="docutils literal notranslate"><span class="pre">access_type</span></code> names that you (or the default command set) actually checks for, as in the example of <code class="docutils literal notranslate"><span class="pre">delete</span></code> above that uses the delete <code class="docutils literal notranslate"><span class="pre">access_type</span></code>.</p>
<p>Below are the access_types checked by the default commandset.</p>
<ul class="simple">
<li><p><a class="reference internal" href="Commands.html"><span class="std std-doc">Commands</span></a></p>
<ul>
<li><p><code class="docutils literal notranslate"><span class="pre">cmd</span></code> - this defines who may call this command at all.</p></li>
</ul>
</li>
<li><p><a class="reference internal" href="Objects.html"><span class="std std-doc">Objects</span></a>:</p>
<ul>
<li><p><code class="docutils literal notranslate"><span class="pre">control</span></code> - who is the “owner” of the object. Can set locks, delete it etc. Defaults to the creator of the object.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">call</span></code> - who may call Object-commands stored on this Object except for the Object itself. By default, Objects share their Commands with anyone in the same location (e.g. so you can press a <code class="docutils literal notranslate"><span class="pre">Button</span></code> object in the room). For Characters and Mobs (who likely only use those Commands for themselves and dont want to share them) this should usually be turned off completely, using something like <code class="docutils literal notranslate"><span class="pre">call:false()</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">examine</span></code> - who may examine this objects properties.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">delete</span></code> - who may delete the object.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">edit</span></code> - who may edit properties and attributes of the object.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">view</span></code> - if the <code class="docutils literal notranslate"><span class="pre">look</span></code> command will display/list this object in descriptions and if you will be able to see its description. Note that if you target it specifically by name, the system will still find it, just not be able to look at it. See <code class="docutils literal notranslate"><span class="pre">search</span></code> lock to completely hide the item.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">search</span></code> - this controls if the object can be found with the <code class="docutils literal notranslate"><span class="pre">DefaultObject.search</span></code> method (usually referred to with <code class="docutils literal notranslate"><span class="pre">caller.search</span></code> in Commands). This is how to create entirely undetectable in-game objects. If not setting this lock explicitly, all objects are assumed searchable.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">get</span></code>- who may pick up the object and carry it around.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">puppet</span></code> - who may “become” this object and control it as their “character”.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">attrcreate</span></code> - who may create new attributes on the object (default True)</p></li>
</ul>
</li>
<li><p><a class="reference internal" href="Objects.html#characters"><span class="std std-ref">Characters</span></a>:</p>
<ul>
<li><p>Same as for Objects</p></li>
</ul>
</li>
<li><p><a class="reference internal" href="Objects.html#exits"><span class="std std-ref">Exits</span></a>:</p>
<ul>
<li><p>Same as for Objects</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">traverse</span></code> - who may pass the exit.</p></li>
</ul>
</li>
<li><p><a class="reference internal" href="Accounts.html"><span class="std std-doc">Accounts</span></a>:</p>
<ul>
<li><p><code class="docutils literal notranslate"><span class="pre">examine</span></code> - who may examine the accounts properties.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">delete</span></code> - who may delete the account.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">edit</span></code> - who may edit the accounts attributes and properties.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">msg</span></code> - who may send messages to the account.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">boot</span></code> - who may boot the account.</p></li>
</ul>
</li>
<li><p><a class="reference internal" href="Attributes.html"><span class="std std-doc">Attributes</span></a>: (only checked by <code class="docutils literal notranslate"><span class="pre">obj.secure_attr</span></code>)</p>
<ul>
<li><p><code class="docutils literal notranslate"><span class="pre">attrread</span></code> - see/access attribute</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">attredit</span></code> - change/delete attribute</p></li>
</ul>
</li>
<li><p><a class="reference internal" href="Channels.html"><span class="std std-doc">Channels</span></a>:</p>
<ul>
<li><p><code class="docutils literal notranslate"><span class="pre">control</span></code> - who is administrating the channel. This means the ability to delete the channel, boot listeners etc.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">send</span></code> - who may send to the channel.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">listen</span></code> - who may subscribe and listen to the channel.</p></li>
</ul>
</li>
<li><p><a class="reference internal" href="Help-System.html"><span class="std std-doc">HelpEntry</span></a>:</p>
<ul>
<li><p><code class="docutils literal notranslate"><span class="pre">view</span></code> - if the help entry header should show up in the help index</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">read</span></code> - who may view this help entry (usually everyone)</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">edit</span></code> - who may edit this help entry.</p></li>
</ul>
</li>
</ul>
<p>So to take an example, whenever an exit is to be traversed, a lock of the type <em>traverse</em> will be checked. Defining a suitable lock type for an exit object would thus involve a lockstring <code class="docutils literal notranslate"><span class="pre">traverse:</span> <span class="pre">&lt;lock</span> <span class="pre">functions&gt;</span></code>.</p>
</section>
<section id="custom-access-types">
<h3>Custom access_types<a class="headerlink" href="#custom-access-types" title="Link to this heading"></a></h3>
<p>As stated above, the <code class="docutils literal notranslate"><span class="pre">access_type</span></code> part of the lock is simply the name or type of the lock. The text is an arbitrary string that must be unique for an object. If adding a lock with the same <code class="docutils literal notranslate"><span class="pre">access_type</span></code> as one that already exists on the object, the new one override the old one.</p>
<p>For example, if you wanted to create a bulletin board system and wanted to restrict who can either read a board or post to a board. You could then define locks such as:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">obj</span><span class="o">.</span><span class="n">locks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&quot;read:perm(Player);post:perm(Admin)&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>This will create a read access type for Characters having the <code class="docutils literal notranslate"><span class="pre">Player</span></code> permission or above and a post access type for those with <code class="docutils literal notranslate"><span class="pre">Admin</span></code> permissions or above (see below how the <code class="docutils literal notranslate"><span class="pre">perm()</span></code> lock function works). When it comes time to test these permissions, simply check like this (in this example, the <code class="docutils literal notranslate"><span class="pre">obj</span></code> may be a board on the bulletin board system and <code class="docutils literal notranslate"><span class="pre">accessing_obj</span></code> is the player trying to read the board):</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="k">if</span> <span class="ow">not</span> <span class="n">obj</span><span class="o">.</span><span class="n">access</span><span class="p">(</span><span class="n">accessing_obj</span><span class="p">,</span> <span class="s1">&#39;read&#39;</span><span class="p">):</span>
<span class="n">accessing_obj</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;Sorry, you may not read that.&quot;</span><span class="p">)</span>
<span class="k">return</span>
</pre></div>
</div>
</section>
<section id="lock-functions">
<h3>Lock functions<a class="headerlink" href="#lock-functions" title="Link to this heading"></a></h3>
<p>A <em>lock function</em> is a normal Python function put in a place Evennia looks for such functions. The modules Evennia looks at is the list <code class="docutils literal notranslate"><span class="pre">settings.LOCK_FUNC_MODULES</span></code>. <em>All functions</em> in any of those modules will automatically be considered a valid lock function. The default ones are found in <code class="docutils literal notranslate"><span class="pre">evennia/locks/lockfuncs.py</span></code> and you can start adding your own in <code class="docutils literal notranslate"><span class="pre">mygame/server/conf/lockfuncs.py</span></code>. You can append the setting to add more module paths. To replace a default lock function, just add your own with the same name.</p>
<p>This is the basic definition of a lock function:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">lockfunc_name</span><span class="p">(</span><span class="n">accessing_obj</span><span class="p">,</span> <span class="n">accessed_obj</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="k">return</span> <span class="kc">True</span> <span class="c1"># or False</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">accessing</span> <span class="pre">object</span></code> is the object wanting to get access. The <code class="docutils literal notranslate"><span class="pre">accessed</span> <span class="pre">object</span></code> is the object being accessed (the object with the lock). The function always return a boolean determining if the lock is passed or not.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">*args</span></code> will become the tuple of arguments given to the lockfunc. So for a lockstring <code class="docutils literal notranslate"><span class="pre">&quot;edit:id(3)&quot;</span></code> (a lockfunc named <code class="docutils literal notranslate"><span class="pre">id</span></code>), <code class="docutils literal notranslate"><span class="pre">*args</span></code> in the lockfunc would be <code class="docutils literal notranslate"><span class="pre">(3,)</span></code> .</p>
<p>The <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> dict has one default keyword always provided by Evennia, the <code class="docutils literal notranslate"><span class="pre">access_type</span></code>, which is a string with the access type being checked for. For the lockstring <code class="docutils literal notranslate"><span class="pre">&quot;edit:id(3)&quot;</span></code>, <code class="docutils literal notranslate"><span class="pre">access_type&quot;</span></code> would be <code class="docutils literal notranslate"><span class="pre">&quot;edit&quot;</span></code>. This is unused by default Evennia.</p>
<p>Any arguments explicitly given in the lock definition will appear as extra arguments.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># A simple example lock function. Called with e.g. `id(34)`. This is</span>
<span class="c1"># defined in, say mygame/server/conf/lockfuncs.py</span>
<span class="k">def</span><span class="w"> </span><span class="nf">id</span><span class="p">(</span><span class="n">accessing_obj</span><span class="p">,</span> <span class="n">accessed_obj</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="k">if</span> <span class="n">args</span><span class="p">:</span>
<span class="n">wanted_id</span> <span class="o">=</span> <span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">return</span> <span class="n">accessing_obj</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="n">wanted_id</span>
<span class="k">return</span> <span class="kc">False</span>
</pre></div>
</div>
<p>The above could for example be used in a lock function like this:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="c1"># we have `obj` and `owner_object` from before</span>
<span class="n">obj</span><span class="o">.</span><span class="n">locks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;edit: id(</span><span class="si">{</span><span class="n">owner_object</span><span class="o">.</span><span class="n">id</span><span class="si">}</span><span class="s2">)&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>We could check if the “edit” lock is passed with something like this:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="c1"># as part of a Command&#39;s func() method, for example</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">obj</span><span class="o">.</span><span class="n">access</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="s2">&quot;edit&quot;</span><span class="p">):</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;You don&#39;t have access to edit this!&quot;</span><span class="p">)</span>
<span class="k">return</span>
</pre></div>
</div>
<p>In this example, everyone except the <code class="docutils literal notranslate"><span class="pre">caller</span></code> with the right <code class="docutils literal notranslate"><span class="pre">id</span></code> will get the error.</p>
<blockquote>
<div><p>(Using the <code class="docutils literal notranslate"><span class="pre">*</span></code> and <code class="docutils literal notranslate"><span class="pre">**</span></code> syntax causes Python to magically put all extra arguments into a list <code class="docutils literal notranslate"><span class="pre">args</span></code> and all keyword arguments into a dictionary <code class="docutils literal notranslate"><span class="pre">kwargs</span></code> respectively. If you are unfamiliar with how <code class="docutils literal notranslate"><span class="pre">*args</span></code> and <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> work, see the Python manuals).</p>
</div></blockquote>
<p>Some useful default lockfuncs (see <code class="docutils literal notranslate"><span class="pre">src/locks/lockfuncs.py</span></code> for more):</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">true()/all()</span></code> - give access to everyone</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">false()/none()/superuser()</span></code> - give access to none. Superusers bypass the check entirely and are thus the only ones who will pass this check.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">perm(perm)</span></code> - this tries to match a given <code class="docutils literal notranslate"><span class="pre">permission</span></code> property, on an Account firsthand, on a Character second. See <a class="reference internal" href="Permissions.html"><span class="std std-doc">below</span></a>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">perm_above(perm)</span></code> - like <code class="docutils literal notranslate"><span class="pre">perm</span></code> but requires a “higher” permission level than the one given.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">id(num)/dbref(num)</span></code> - checks so the access_object has a certain dbref/id.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">attr(attrname)</span></code> - checks if a certain <a class="reference internal" href="Attributes.html"><span class="std std-doc">Attribute</span></a> exists on accessing_object.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">attr(attrname,</span> <span class="pre">value)</span></code> - checks so an attribute exists on accessing_object <em>and</em> has the given value.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">attr_gt(attrname,</span> <span class="pre">value)</span></code> - checks so accessing_object has a value larger (<code class="docutils literal notranslate"><span class="pre">&gt;</span></code>) than the given value.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">attr_ge,</span> <span class="pre">attr_lt,</span> <span class="pre">attr_le,</span> <span class="pre">attr_ne</span></code> - corresponding for <code class="docutils literal notranslate"><span class="pre">&gt;=</span></code>, <code class="docutils literal notranslate"><span class="pre">&lt;</span></code>, <code class="docutils literal notranslate"><span class="pre">&lt;=</span></code> and <code class="docutils literal notranslate"><span class="pre">!=</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">tag(tagkey[,</span> <span class="pre">category])</span></code> - checks if the accessing_object has the specified tag and optional category.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">objtag(tagkey[,</span> <span class="pre">category])</span></code> - checks if the <em>accessed_object</em> has the specified tag and optional category.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">objloctag(tagkey[,</span> <span class="pre">category])</span></code> - checks if the <em>accessed_obj</em>s location has the specified tag and optional category.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">holds(objid)</span></code> - checks so the accessing objects contains an object of given name or dbref.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">inside()</span></code> - checks so the accessing object is inside the accessed object (the inverse of <code class="docutils literal notranslate"><span class="pre">holds()</span></code>).</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">pperm(perm)</span></code>, <code class="docutils literal notranslate"><span class="pre">pid(num)/pdbref(num)</span></code> - same as <code class="docutils literal notranslate"><span class="pre">perm</span></code>, <code class="docutils literal notranslate"><span class="pre">id/dbref</span></code> but always looks for permissions and dbrefs of <em>Accounts</em>, not on Characters.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">serversetting(settingname,</span> <span class="pre">value)</span></code> - Only returns True if Evennia has a given setting or a setting set to a given value.</p></li>
</ul>
</section>
<section id="checking-simple-strings">
<h3>Checking simple strings<a class="headerlink" href="#checking-simple-strings" title="Link to this heading"></a></h3>
<p>Sometimes you dont really need to look up a certain lock, you just want to check a lockstring. A common use is inside Commands, in order to check if a user has a certain permission. The lockhandler has a method <code class="docutils literal notranslate"><span class="pre">check_lockstring(accessing_obj,</span> <span class="pre">lockstring,</span> <span class="pre">bypass_superuser=False)</span></code> that allows this.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="c1"># inside command definition</span>
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">locks</span><span class="o">.</span><span class="n">check_lockstring</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="p">,</span> <span class="s2">&quot;dummy:perm(Admin)&quot;</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;You must be an Admin or higher to do this!&quot;</span><span class="p">)</span>
<span class="k">return</span>
</pre></div>
</div>
<p>Note here that the <code class="docutils literal notranslate"><span class="pre">access_type</span></code> can be left to a dummy value since this method does not actually do a Lock lookup.</p>
</section>
<section id="default-locks">
<h3>Default locks<a class="headerlink" href="#default-locks" title="Link to this heading"></a></h3>
<p>Evennia sets up a few basic locks on all new objects and accounts (if we didnt, noone would have any access to anything from the start). This is all defined in the root <a class="reference internal" href="Typeclasses.html"><span class="std std-doc">Typeclasses</span></a> of the respective entity, in the hook method <code class="docutils literal notranslate"><span class="pre">basetype_setup()</span></code> (which you usually dont want to edit unless you want to change how basic stuff like rooms and exits store their internal variables). This is called once, before <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code>, so just put them in the latter method on your child object to change the default. Also creation commands like <code class="docutils literal notranslate"><span class="pre">create</span></code> changes the locks of objects you create - for example it sets the <code class="docutils literal notranslate"><span class="pre">control</span></code> lock_type so as to allow you, its creator, to control and delete the object.</p>
</section>
</section>
<section id="more-lock-definition-examples">
<h2>More Lock definition examples<a class="headerlink" href="#more-lock-definition-examples" title="Link to this heading"></a></h2>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>examine: attr(eyesight, excellent) or perm(Builders)
</pre></div>
</div>
<p>You are only allowed to do <em>examine</em> on this object if you have excellent eyesight (that is, has an Attribute <code class="docutils literal notranslate"><span class="pre">eyesight</span></code> with the value <code class="docutils literal notranslate"><span class="pre">excellent</span></code> defined on yourself) or if you have the “Builders” permission string assigned to you.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>open: holds(&#39;the green key&#39;) or perm(Builder)
</pre></div>
</div>
<p>This could be called by the <code class="docutils literal notranslate"><span class="pre">open</span></code> command on a “door” object. The check is passed if you are a Builder or has the right key in your inventory.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>cmd: perm(Builders)
</pre></div>
</div>
<p>Evennias command handler looks for a lock of type <code class="docutils literal notranslate"><span class="pre">cmd</span></code> to determine if a user is allowed to even call upon a particular command or not. When you define a command, this is the kind of lock you must set. See the default command set for lots of examples. If a character/account dont pass the <code class="docutils literal notranslate"><span class="pre">cmd</span></code> lock type the command will not even appear in their <code class="docutils literal notranslate"><span class="pre">help</span></code> list.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>cmd: not perm(no_tell)
</pre></div>
</div>
<p>“Permissions” can also be used to block users or implement highly specific bans. The above example would be be added as a lock string to the <code class="docutils literal notranslate"><span class="pre">tell</span></code> command. This will allow everyone <em>not</em> having the “permission” <code class="docutils literal notranslate"><span class="pre">no_tell</span></code> to use the <code class="docutils literal notranslate"><span class="pre">tell</span></code> command. You could easily give an account the “permission” <code class="docutils literal notranslate"><span class="pre">no_tell</span></code> to disable their use of this particular command henceforth.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">dbref</span> <span class="o">=</span> <span class="n">caller</span><span class="o">.</span><span class="n">id</span>
<span class="n">lockstring</span> <span class="o">=</span> <span class="s2">&quot;control:id(</span><span class="si">%s</span><span class="s2">);examine:perm(Builders);delete:id(</span><span class="si">%s</span><span class="s2">) or perm(Admin);get:all()&quot;</span> <span class="o">%</span>
<span class="p">(</span><span class="n">dbref</span><span class="p">,</span> <span class="n">dbref</span><span class="p">)</span>
<span class="n">new_obj</span><span class="o">.</span><span class="n">locks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">lockstring</span><span class="p">)</span>
</pre></div>
</div>
<p>This is how the <code class="docutils literal notranslate"><span class="pre">create</span></code> command sets up new objects. In sequence, this permission string sets the owner of this object be the creator (the one running <code class="docutils literal notranslate"><span class="pre">create</span></code>). Builders may examine the object whereas only Admins and the creator may delete it. Everyone can pick it up.</p>
<section id="a-complete-example-of-setting-locks-on-an-object">
<h3>A complete example of setting locks on an object<a class="headerlink" href="#a-complete-example-of-setting-locks-on-an-object" title="Link to this heading"></a></h3>
<p>Assume we have two objects - one is ourselves (not superuser) and the other is an <a class="reference internal" href="Objects.html"><span class="std std-doc">Object</span></a>
called <code class="docutils literal notranslate"><span class="pre">box</span></code>.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> &gt; create/drop box
&gt; desc box = &quot;This is a very big and heavy box.&quot;
</pre></div>
</div>
<p>We want to limit which objects can pick up this heavy box. Lets say that to do that we require the would-be lifter to to have an attribute <em>strength</em> on themselves, with a value greater than 50. We assign it to ourselves to begin with.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> &gt; set self/strength = 45
</pre></div>
</div>
<p>Ok, so for testing we made ourselves strong, but not strong enough. Now we need to look at what happens when someone tries to pick up the the box - they use the <code class="docutils literal notranslate"><span class="pre">get</span></code> command (in the default set). This is defined in <code class="docutils literal notranslate"><span class="pre">evennia/commands/default/general.py</span></code>. In its code we find this snippet:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="k">if</span> <span class="ow">not</span> <span class="n">obj</span><span class="o">.</span><span class="n">access</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="s1">&#39;get&#39;</span><span class="p">):</span>
<span class="k">if</span> <span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">get_err_msg</span><span class="p">:</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">get_err_msg</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;You can&#39;t get that.&quot;</span><span class="p">)</span>
<span class="k">return</span>
</pre></div>
</div>
<p>So the <code class="docutils literal notranslate"><span class="pre">get</span></code> command looks for a lock with the type <em>get</em> (not so surprising). It also looks for an <a class="reference internal" href="Attributes.html"><span class="std std-doc">Attribute</span></a> on the checked object called <em>get_err_msg</em> in order to return a customized error message. Sounds good! Lets start by setting that on the box:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> &gt; set box/get_err_msg = You are not strong enough to lift this box.
</pre></div>
</div>
<p>Next we need to craft a Lock of type <em>get</em> on our box. We want it to only be passed if the accessing object has the attribute <em>strength</em> of the right value. For this we would need to create a lock function that checks if attributes have a value greater than a given value. Luckily there is already such a one included in Evennia (see <code class="docutils literal notranslate"><span class="pre">evennia/locks/lockfuncs.py</span></code>), called <code class="docutils literal notranslate"><span class="pre">attr_gt</span></code>.</p>
<p>So the lock string will look like this: <code class="docutils literal notranslate"><span class="pre">get:attr_gt(strength,</span> <span class="pre">50)</span></code>. We put this on the box now:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> lock box = get:attr_gt(strength, 50)
</pre></div>
</div>
<p>Try to <code class="docutils literal notranslate"><span class="pre">get</span></code> the object and you should get the message that we are not strong enough. Increase your strength above 50 however and youll pick it up no problem. Done! A very heavy box!</p>
<p>If you wanted to set this up in python code, it would look something like this:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
<span class="kn">from</span><span class="w"> </span><span class="nn">evennia</span><span class="w"> </span><span class="kn">import</span> <span class="n">create_object</span>
<span class="c1"># create, then set the lock</span>
<span class="n">box</span> <span class="o">=</span> <span class="n">create_object</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;box&quot;</span><span class="p">)</span>
<span class="n">box</span><span class="o">.</span><span class="n">locks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&quot;get:attr_gt(strength, 50)&quot;</span><span class="p">)</span>
<span class="c1"># or we can assign locks in one go right away</span>
<span class="n">box</span> <span class="o">=</span> <span class="n">create_object</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;box&quot;</span><span class="p">,</span> <span class="n">locks</span><span class="o">=</span><span class="s2">&quot;get:attr_gt(strength, 50)&quot;</span><span class="p">)</span>
<span class="c1"># set the attributes</span>
<span class="n">box</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">desc</span> <span class="o">=</span> <span class="s2">&quot;This is a very big and heavy box.&quot;</span>
<span class="n">box</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">get_err_msg</span> <span class="o">=</span> <span class="s2">&quot;You are not strong enough to lift this box.&quot;</span>
<span class="c1"># one heavy box, ready to withstand all but the strongest...</span>
</pre></div>
</div>
</section>
</section>
<section id="on-djangos-permission-system">
<h2>On Djangos permission system<a class="headerlink" href="#on-djangos-permission-system" title="Link to this heading"></a></h2>
<p>Django also implements a comprehensive permission/security system of its own. The reason we dont use that is because it is app-centric (app in the Django sense). Its permission strings are of the form <code class="docutils literal notranslate"><span class="pre">appname.permstring</span></code> and it automatically adds three of them for each database model in the app - for the app evennia/object this would be for example object.create, object.admin and object.edit. This makes a lot of sense for a web application, not so much for a MUD, especially when we try to hide away as much of the underlying architecture as possible.</p>
<p>The django permissions are not completely gone however. We use it for validating passwords during login. It is also used exclusively for managing Evennias web-based admin site, which is a graphical front-end for the database of Evennia. You edit and assign such permissions directly from the web interface. Its stand-alone from the permissions described above.</p>
</section>
</section>
<div class="clearer"></div>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="Main">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo of Evennia"/>
</a></p>
<search id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
<input type="submit" value="Go" />
</form>
</div>
</search>
<script>document.getElementById('searchbox').style.display = "block"</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Locks</a><ul>
<li><a class="reference internal" href="#working-with-locks">Working with locks</a><ul>
<li><a class="reference internal" href="#defining-locks">Defining locks</a></li>
<li><a class="reference internal" href="#valid-access-types">Valid access_types</a></li>
<li><a class="reference internal" href="#custom-access-types">Custom access_types</a></li>
<li><a class="reference internal" href="#lock-functions">Lock functions</a></li>
<li><a class="reference internal" href="#checking-simple-strings">Checking simple strings</a></li>
<li><a class="reference internal" href="#default-locks">Default locks</a></li>
</ul>
</li>
<li><a class="reference internal" href="#more-lock-definition-examples">More Lock definition examples</a><ul>
<li><a class="reference internal" href="#a-complete-example-of-setting-locks-on-an-object">A complete example of setting locks on an object</a></li>
</ul>
</li>
<li><a class="reference internal" href="#on-djangos-permission-system">On Djangos permission system</a></li>
</ul>
</li>
</ul>
<div>
<h4>Previous topic</h4>
<p class="topless"><a href="Permissions.html"
title="previous chapter">Permissions</a></p>
</div>
<div>
<h4>Next topic</h4>
<p class="topless"><a href="Commands.html"
title="next chapter">Commands</a></p>
</div>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Locks.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com/docs/latest/index.html">Documentation Top</a> </li>
<li><a href="https://www.evennia.com">Evennia Home</a> </li>
<li><a href="https://github.com/evennia/evennia">Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Doc Versions</h3>
<ul>
<li>
<a href="https://www.evennia.com/docs/latest/index.html">latest (main branch)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/5.x/index.html">v5.0.0 branch (outdated)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/4.x/index.html">v4.0.0 branch (outdated)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/3.x/index.html">v3.0.0 branch (outdated)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/2.x/index.html">v2.0.0 branch (outdated)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/1.x/index.html">v1.0.0 branch (outdated)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/0.x/index.html">v0.9.5 branch (outdated)</a>
</li>
</ul>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="Related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Commands.html" title="Commands"
>next</a> |</li>
<li class="right" >
<a href="Permissions.html" title="Permissions"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Locks</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2024, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.2.3.
</div>
</body>
</html>