Guide
Set up permissions on a Counter-Strike 2 server, manage groups and players with commands and check permissions from your own plugin.
The guide has two parts. The first is for server owners: storage, settings and commands. The second is for plugin authors: how to check and change permissions through the API.
Permission lines
A permission is a line of segments separated by dots. Plugins choose their own lines, usually starting with the plugin name.
| Line | Meaning |
|---|---|
admin.kick | One permission |
admin.* | Everything under admin. |
* | Everything |
-admin.ban | A denial: forbids admin.ban |
*may only be the last segment. Empty segments (a..b,a.) are not allowed.admin.*coversadmin.kick, but the plain lineadmindoes not.- A denial is how you take away one permission from someone who has a wildcard:
admin.*together with-admin.ban.
How a check is resolved
When a permission is checked for a player, the first place that knows the answer wins:
- temporary permissions of the player;
- permanent permissions of the player;
- the player's groups, from the highest priority to the lowest. Each group is asked first, then its parent, then the parent of the parent.
The player's own permissions therefore override the groups, and a group with a higher priority overrides a lower one.
Immunity
Every player has an immunity level. An admin can act on a player only when the admin's immunity is equal or higher. An immunity of -1 means "use the priority of my highest group".
For server owners
Installation
All three plugins are part of the Plugify Source 2 build and work out of the box with an SQLite database. To install them on their own, see Installation.
Storage
The storage plugin keeps its settings in permissions_storage.settings.yaml. The defaults lie next to the plugin. To change them, create configs/permissions/permissions_storage.settings.yaml with the keys you change:
| Setting | Meaning |
|---|---|
storage_method | sqlite3 (default), mysql or postgres |
data | Connection to MySQL or PostgreSQL: host, port, username, password, database, schema (PostgreSQL), params and pool_settings |
server_id | Id of this server. 0 means all servers: groups and permissions given on server 0 apply everywhere |
global_cookie | Share cookies between all servers instead of keeping them per server |
delete_expired_records | Delete expired groups and permissions from the database |
delete_removed_records | Delete removed groups and permissions from the database instead of marking them |
- SQLite needs no setup. The database is
data/permissions/permissions.db, created on the first start with aDefaultgroup that every player receives. SQLite always works as server0. - MySQL and PostgreSQL tables are not created by the plugin. Create them before the first start with
tables_mysql.sqlortables_postgres.sqlfrom the permissions-storage repository.
Connector settings
The connector reads permissions_connector_s2.settings.yaml the same way, with overrides in configs/permissions/:
| Setting | Meaning |
|---|---|
notify_mode | Where players are notified: console, chat, hint, each true or false |
hint_duration | How long a hint stays on screen, in seconds |
time_mode | Unit of <duration> in commands: 0 seconds, 1 minutes, 2 hours, 3 days |
abbreviate_time | Short units (5 min.) instead of full words |
format_timestamp | Date format in Go layout, for example 2006-01-02 15:04:05 |
display_active_groups | Show players their active groups when they join |
hidden_groups | Groups that are not shown to players, Default by default |
Phrases live in permissions_connector_s2.translations.yaml. To change them, put your copy into data/permissions/. Apply changes without a restart with perms_reload_cfg and perms_reload_translations.
Commands
The commands work in the server console and in chat. From the server console everything is allowed. A player needs the permission from the table and cannot act on players with higher immunity.
<player> is #userid, $steamid64, &account_id or a name. <duration> is a number in the unit of time_mode, and 0 means forever. In perms_creategroup pass "" for no parent and put several permissions in quotes, separated by spaces.
| Command | Permission | What it does |
|---|---|---|
perms | none | List of the commands available to you |
perms_reload_cfg | permissions.reload_config | Reload the settings |
perms_reload_translations | permissions.reload_translations | Reload the phrases |
perms_users | permissions.user.list | List of players on the server |
perms_user_info <player> | permissions.user.info | Everything about a player |
perms_user_permissions <player> | permissions.user.permission.info | Permissions and denials of a player |
perms_user_groups <player> | permissions.user.group.info | Groups of a player |
perms_user_check_permission <player> <permission> | permissions.user.permission.check | Check a permission |
perms_user_check_group <player> <group> | permissions.user.group.check | Check whether a player is in a group |
perms_user_add_permission <player> <permission> <duration> | permissions.user.permission.add | Add a permission or denial |
perms_user_set_permission <player> <permission> <duration> | permissions.user.permission.set | Set a permission or denial, replacing the current one |
perms_user_remove_permission <player> <permission> | permissions.user.permission.remove | Remove a permission or denial |
perms_user_add_group <player> <group> <duration> | permissions.user.group.add | Add a group |
perms_user_set_group <player> <group> <duration> | permissions.user.group.set | Set a group, replacing its duration |
perms_user_remove_group <player> <group> | permissions.user.group.remove | Remove a group |
perms_groups | permissions.listgroups | List of groups |
perms_group_info <group> | permissions.group.info | Information about a group |
perms_group_permissions <group> | permissions.group.permissions | Permissions of a group |
perms_group_check_permission <group> <permission> | permissions.group.permission.check | Check a permission of a group |
perms_creategroup <group> <priority> <parent> <permissions> | permissions.creategroup | Create a group |
perms_deletegroup <group> | permissions.deletegroup | Delete a group |
perms_group_parent_set <child> <parent> | permissions.group.parent.set | Set the parent group |
perms_group_parent_info <group> | permissions.group.parent.info | Show the parent group |
perms_group_parent_check <child> <parent> | permissions.group.parent.check | Check whether a group is a parent of another |
perms_group_set_option <group> <option> <value> | permissions.group.option.set | Set a group option |
perms_group_option <group> <option> | permissions.group.option | Show a group option |
perms_group_add_permission <group> <permission> | permissions.group.permission.add | Add a permission |
perms_group_set_permission <group> <permission> | permissions.group.permission.set | Set a permission, replacing the current one |
perms_group_remove_permission <group> <permission> | permissions.group.permission.remove | Remove a permission |
First setup
Run these in the server console to create an admin group and give it to yourself:
The player must be on the server: users are loaded when they join and unloaded when they leave.
For plugin authors
Add the dependency
The examples below are in Go and use the ready-made bindings, go get github.com/fr0nch/go-plugify-permissions. In other languages the same functions are imported from the permissions plugin, see the Import Functions page of your language.
Check a permission
HasPermission returns a Status: Allow, Disallow, PermNotFound, or TargetUserNotFound when the player is not loaded. Compare with Allow, so a missing permission means "no".
Change permissions and listen to changes
- Times are Unix timestamps of the moment the permission or group expires.
0means forever. - Functions that change something take
pluginID, which is passed to the callbacks, anddontBroadcast, which applies the change without notifying listeners. - Every status above
ErrorsStartis an error. AddPermissionrefuses to change a permission that already exists with the opposite state (PermConflict).SetPermissionreplaces it.
Main functions
| Function | Purpose |
|---|---|
HasPermission(targetID, perm) | Check a permission of a user |
HasPermissionExtended(targetID, perm, exact, permSource, timestamp) | Same, and tells where the permission came from and when it expires |
AddPermission, SetPermission, RemovePermission | Change permissions of a user |
HasGroup, AddGroup, RemoveGroup, GetUserGroups | Groups of a user |
GetImmunity, SetImmunity, CanAffectUser | Immunity |
GetCookie, SetCookie, GetAllCookies | Named values stored per user |
CreateGroup, DeleteGroup, GroupExists, GetAllGroups | Groups |
SetParent, GetParent, HasParentGroup, GetPriorityGroup | Group hierarchy |
HasPermissionGroup, AddPermissionGroup, SetPermissionGroup, RemovePermissionGroup | Permissions of a group |
GetOptionGroup, SetOptionGroup, GetAllOptionsGroup | Options of a group |
UserExists, DumpUsersList, DumpPermissions | What is loaded now |
Events
Every event has a pair of functions, On<Event>_Register and On<Event>_Unregister.
| Event | When it fires |
|---|---|
OnUserLoaded | A user has been loaded with all groups and permissions |
OnUserCreate, OnUserDelete | A user appeared in the core or was removed |
OnUserPermissionChange, OnUserGroupChange | A permission or group of a user was added, replaced or removed |
OnUserCookieChange, OnUserImmunityChange | A cookie or the immunity of a user changed |
OnPermissionExpiration, OnGroupExpiration | A temporary permission or group expired |
OnGroupCreate, OnGroupDelete, OnSetParent | Groups were created, deleted or linked |
OnGroupPermissionChange, OnGroupOptionChange | A permission or option of a group changed |
OnGroupsLoaded | The groups of the server have been loaded |
Writing your own storage or connector
The core loads nothing by itself. LoadGroups and LoadUser call the OnGroupsLoad and OnUserRequest callbacks, and the plugin that registered them fills the core with CreateGroup, CreateUser, AddGroup, AddPermission and SetCookie.
To save changes, register the storage callbacks: OnUserPermissionChangeStorage, OnUserGroupChangeStorage, OnUserCookieChangeStorage, OnUserImmunityChangeStorage, OnGroupCreateStorage, OnGroupDeleteStorage, OnGroupPermissionChangeStorage, OnGroupOptionChangeStorage and OnSetParentStorage. They are called before the change is applied and return bool. Returning false cancels the change, and the caller gets the DBNotReady status.
The full list of functions, callbacks and status codes is on the API Hub.