@amxts/perms 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,35 @@
1
+ /*
2
+ * perms - natives
3
+ * Author: kukson777
4
+ *
5
+ * Generated by amxts from perms.ts. Do not edit it: change the plugin
6
+ * and build it again.
7
+ *
8
+ * A string result is written into out[], len being its size (charsmax).
9
+ * The native returns the string's length - or, when there may be no
10
+ * string, bool: whether there was one. An array result goes into out[],
11
+ * size being its size, and the native returns how many cells it wrote.
12
+ */
13
+
14
+ #if defined _perms_included
15
+ #endinput
16
+ #endif
17
+ #define _perms_included
18
+
19
+ /** Whether the player has a permission node, e.g. "myplugin.kick". */
20
+ native bool:perms_has(id, const node[]);
21
+
22
+ /** Declares a node the plugin checks, for the web editor; byDefault gives it to every player no grant says otherwise for. */
23
+ native perms_declare(const node[], const description[], bool:byDefault = false);
24
+
25
+ /** The player's primary group: his group of the highest weight, "default" when he has none. */
26
+ native perms_get_group(id, out[], len);
27
+
28
+ /** Whether the player is in a group now. */
29
+ native bool:perms_in_group(id, const group[]);
30
+
31
+ /** Puts the player into a group, for seconds (0 - for good). */
32
+ native perms_add_group(id, const group[], seconds = 0);
33
+
34
+ /** Takes the player out of a group. */
35
+ native perms_remove_group(id, const group[]);
package/package.json CHANGED
@@ -1,6 +1,72 @@
1
1
  {
2
- "name": "@amxts/perms",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
2
+ "name": "@amxts/perms",
3
+ "type": "module",
4
+ "version": "0.1.0",
5
+ "description": "Permissions and groups for amxts servers in place of admin.amxx: nodes, wildcards, inheritance, temporary grants, a file or MySQL, AMX Mod X's flags for Pawn plugins, and a web editor.",
6
+ "author": {
7
+ "name": "kukson777",
8
+ "url": "https://github.com/kukson777"
9
+ },
10
+ "license": "MIT",
11
+ "homepage": "https://github.com/amxts/perms#readme",
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/amxts/perms.git"
15
+ },
16
+ "keywords": [
17
+ "amxts-module",
18
+ "amxts-admin",
19
+ "amxmodx",
20
+ "counter-strike"
21
+ ],
22
+ "exports": {
23
+ ".": "./src/index.ts",
24
+ "./testing": "./testing/index.ts"
25
+ },
26
+ "types": "./src/index.ts",
27
+ "files": [
28
+ "PAWN.md",
29
+ "PAWN.ru.md",
30
+ "README.md",
31
+ "README.ru.md",
32
+ "include",
33
+ "src",
34
+ "testing",
35
+ "prebuilt"
36
+ ],
37
+ "amxts": {
38
+ "module": "src/index.ts",
39
+ "natives": "src/natives.ts",
40
+ "include": "include/perms.inc",
41
+ "testing": "testing/index.ts"
42
+ },
43
+ "scripts": {
44
+ "test": "vitest run",
45
+ "store": "node store/dev.ts",
46
+ "check": "amxts check",
47
+ "lint": "oxlint && oxfmt --check",
48
+ "lint:fix": "oxfmt && oxlint --fix --silent || oxlint --fix --silent || oxlint --fix"
49
+ },
50
+ "peerDependencies": {
51
+ "@amxts/config-core": "^0.2.0",
52
+ "@amxts/core": "^0.3.2"
53
+ },
54
+ "devDependencies": {
55
+ "@e18e/eslint-plugin": "^0.8.1",
56
+ "@eslint-community/eslint-plugin-eslint-comments": "^4.8.1",
57
+ "@stylistic/eslint-plugin": "^5.10.0",
58
+ "@types/node": "^24.0.0",
59
+ "eslint-plugin-antfu": "^3.2.3",
60
+ "eslint-plugin-command": "^4.0.0",
61
+ "eslint-plugin-n": "^18.4.0",
62
+ "eslint-plugin-perfectionist": "^5.12.1",
63
+ "eslint-plugin-regexp": "^3.3.1",
64
+ "oxfmt": "^0.70.0",
65
+ "oxlint": "^1.85.0",
66
+ "typescript": "^6.0.3",
67
+ "vitest": "^5.0.3"
68
+ },
69
+ "publishConfig": {
70
+ "access": "public"
71
+ }
72
+ }
Binary file
@@ -0,0 +1,205 @@
1
+ {
2
+ "format": 2,
3
+ "module": "@amxts/perms",
4
+ "version": "0.1.0",
5
+ "from": {
6
+ "@amxts/core": {
7
+ "version": "0.3.2",
8
+ "hash": "f84df0428cf96aeb83404895c9a07e9fb69ba2e3",
9
+ "abi": "0.3.2+abi.1ff73017\nDate.now ()F\nLookupLangKey (iiii)i t,v,s,[1 leaf\nabort (iiii)\nadmins_flush ()i\nadmins_push (iiii)i s,s,v,v\namxts_owner (ii)i\namxts_rpc (iiii)i\namxts_rpc_reply (ii)\namxts_rpc_result (i)\namxts_rpc_take (i)\namxts_serve (ii)\narg (i)i\narg_array (iii)i\narg_string (iii)i\narg_text (iii)i\nargc ()i\ncall (iiii)i\nchain_set (ii)\nclcmd (iiii)\nco_entered ()i\nco_spawn (iiiii)i\nco_suspend (i)\nco_wake ()\nconsole.error (i)\nconsole.log (i)\nconsole.warn (i)\ncreate_cvar (iiiiiiii)i s,s,v,s,v,v,v,v\ncvar_exact ()i\ncvar_hook (ii)i\ndb_close (i)\ndb_open (ii)i\ndb_query (iiiiiiii)i\ndb_status (i)i\ndb_text (iiii)i\nemit_local (iiii)\nenv_get (iii)i\nexport (ii)i\nfclose (i)i\nfind_plugin_byfile (ii)i s,v leaf\nfopen (iiii)i s,s,v,s leaf\nfread_blocks (iiii)i v,[n1>,v,v\ngame_api ()i\nget_cvar_pointer (i)i s leaf\nget_localinfo (iii)i s,t,v leaf\nget_maxplayers ()i\nget_name (iii)i\nget_pcvar_float (i)i\nget_pcvar_string (iii)i v,t,v leaf\nget_players (iiii)i [32>,[1>,s,s\nget_user_authid (iii)i v,t,v\nget_user_flags (ii)i\nget_user_info (iiii)i v,s,t,v leaf\nget_user_ip (iiii)i v,t,v,v leaf\nget_user_msgid (i)i s leaf\nget_user_name (iii)i v,t,v leaf\nget_user_userid (i)i\nham (iiii)i\nhash_string (iiii)i s,v,t,v leaf\nhook (iii)i\nhook_direct (iiii)\nhook_on (ii)\ninfo_get (iiii)i\nis_user_bot (i)i\nis_user_connected (i)i\nlog_count ()i\nlog_text (iii)i\nmsg_hook (ii)i\nnet_body (iii)\nnet_cancel (i)\nnet_close (i)\nnet_open (i)i\nnet_option (iii)i\nnet_read (iii)i\nnet_redirects (i)i\nnet_reply (i)i\nnet_send (ii)i\nnet_size (i)i\nnet_status (i)i\nnet_text (iiii)i\noff (ii)\non (iii)\non_direct (iiiiii)\noutcome (i)\nplayer_data_set (iiF)\nplayer_names (i)\nplayer_slots (i)\nplayer_stat (ii)i\nplugin (iiii)\nprecache_generic (i)i s\nprecache_model (i)i s\nprecache_sound (i)i s\nprint_client (iii)\nread_argc ()i\nread_args (ii)i t,v leaf\nread_argv (iii)i v,t,v leaf\nread_flags (i)i s leaf\nregister_dictionary (i)i s leaf\nremove_user_flags (iii)i\nsay_text (iii)\nset_arg_text (iii)i\nset_user_flags (iii)i\nsrvcmd (iii)\nstack_frames (ii)i\nstop_task (i)i\ntag (i)\ntask (iii)i"
10
+ },
11
+ "@amxts/config-core": {
12
+ "version": "0.2.0",
13
+ "hash": "fc3b2c2731f6044d4ce8dab8fe1471b4441ad8c9"
14
+ },
15
+ "@amxts/perms": {
16
+ "version": "0.1.0",
17
+ "hash": "6321fd1b3ec8491acbe7ad42eadf48110cbe8381"
18
+ }
19
+ },
20
+ "options": {
21
+ "@amxts/config-core": {
22
+ "baseDir": ""
23
+ },
24
+ "@amxts/perms": {
25
+ "file": "perms",
26
+ "editor": ""
27
+ }
28
+ },
29
+ "forwards": {
30
+ "perms_changed": null
31
+ },
32
+ "places": [
33
+ "constants.ts",
34
+ "database.ts",
35
+ "effects.ts",
36
+ "entities.ts",
37
+ "events.ts",
38
+ "facade.ts",
39
+ "fetch.ts",
40
+ "flags.ts",
41
+ "fs.ts",
42
+ "hlds.ts",
43
+ "hooks.ts",
44
+ "jobs.ts",
45
+ "kit.ts",
46
+ "modules/config-core.ts",
47
+ "modules/config-core/src/files.ts",
48
+ "modules/config-core/src/ini-tree.ts",
49
+ "modules/config-core/src/ini.ts",
50
+ "modules/config-core/src/internal.ts",
51
+ "modules/config-core/src/json.ts",
52
+ "modules/config-core/src/tree.ts",
53
+ "modules/config-core/src/types.ts",
54
+ "modules/config-core/src/yaml.ts",
55
+ "modules/perms.ts",
56
+ "modules/perms/src/commands.ts",
57
+ "modules/perms/src/db-store.ts",
58
+ "modules/perms/src/editor.ts",
59
+ "modules/perms/src/file-store.ts",
60
+ "modules/perms/src/import.ts",
61
+ "modules/perms/src/model.ts",
62
+ "modules/perms/src/players.ts",
63
+ "modules/perms/src/server.ts",
64
+ "modules/perms/src/state.ts",
65
+ "modules/perms/src/time.ts",
66
+ "modules/perms/src/types.ts",
67
+ "natives.ts",
68
+ "os.ts",
69
+ "perms.ts",
70
+ "promise.ts",
71
+ "sql.ts",
72
+ "vector.ts"
73
+ ],
74
+ "natives": [
75
+ {
76
+ "name": "perms_has",
77
+ "params": [
78
+ {
79
+ "name": "player",
80
+ "kind": "player",
81
+ "pawnDefault": null
82
+ },
83
+ {
84
+ "name": "node",
85
+ "kind": "string",
86
+ "pawnDefault": null
87
+ }
88
+ ],
89
+ "result": "bool",
90
+ "doc": "/** Whether the player has a permission node, e.g. \"myplugin.kick\". */"
91
+ },
92
+ {
93
+ "name": "perms_declare",
94
+ "params": [
95
+ {
96
+ "name": "node",
97
+ "kind": "string",
98
+ "pawnDefault": null
99
+ },
100
+ {
101
+ "name": "description",
102
+ "kind": "string",
103
+ "pawnDefault": null
104
+ },
105
+ {
106
+ "name": "byDefault",
107
+ "kind": "bool",
108
+ "pawnDefault": "false"
109
+ }
110
+ ],
111
+ "result": "void",
112
+ "doc": "/** Declares a node the plugin checks, for the web editor; byDefault gives it to every player no grant says otherwise for. */"
113
+ },
114
+ {
115
+ "name": "perms_get_group",
116
+ "params": [
117
+ {
118
+ "name": "player",
119
+ "kind": "player",
120
+ "pawnDefault": null
121
+ }
122
+ ],
123
+ "result": "string",
124
+ "doc": "/** The player's primary group: his group of the highest weight, \"default\" when he has none. */"
125
+ },
126
+ {
127
+ "name": "perms_in_group",
128
+ "params": [
129
+ {
130
+ "name": "player",
131
+ "kind": "player",
132
+ "pawnDefault": null
133
+ },
134
+ {
135
+ "name": "group",
136
+ "kind": "string",
137
+ "pawnDefault": null
138
+ }
139
+ ],
140
+ "result": "bool",
141
+ "doc": "/** Whether the player is in a group now. */"
142
+ },
143
+ {
144
+ "name": "perms_add_group",
145
+ "params": [
146
+ {
147
+ "name": "player",
148
+ "kind": "player",
149
+ "pawnDefault": null
150
+ },
151
+ {
152
+ "name": "group",
153
+ "kind": "string",
154
+ "pawnDefault": null
155
+ },
156
+ {
157
+ "name": "seconds",
158
+ "kind": "int",
159
+ "pawnDefault": "0"
160
+ }
161
+ ],
162
+ "result": "void",
163
+ "doc": "/** Puts the player into a group, for seconds (0 - for good). */"
164
+ },
165
+ {
166
+ "name": "perms_remove_group",
167
+ "params": [
168
+ {
169
+ "name": "player",
170
+ "kind": "player",
171
+ "pawnDefault": null
172
+ },
173
+ {
174
+ "name": "group",
175
+ "kind": "string",
176
+ "pawnDefault": null
177
+ }
178
+ ],
179
+ "result": "void",
180
+ "doc": "/** Takes the player out of a group. */"
181
+ }
182
+ ],
183
+ "beside": {
184
+ "enums": [],
185
+ "contract": null,
186
+ "author": "kukson777"
187
+ },
188
+ "systems": {
189
+ "windows": {
190
+ "file": "prebuilt/windows/perms.aot",
191
+ "size": 1666794,
192
+ "sha256": "68ca54fa913e76e78bb7142bc830724e4b9e2170b7363a3de16a78c1f12bdd61"
193
+ },
194
+ "linux": {
195
+ "file": "prebuilt/linux/perms.aot",
196
+ "size": 1681078,
197
+ "sha256": "c8fe1c50085ec2862124c1e8c4c5710f96bcf58d59bedf7bf25ca4612f5b349c"
198
+ }
199
+ },
200
+ "surface": {
201
+ "proxy": "// GENERATED by scripts/shared-modules.ts: ~/modules/perms in a plugin that does not own it.\n// Each function runs in perms.aot, the one instance on the server.\nimport { Reader as __Reader, Writer as __Writer, beginCallback as __beginCallback, callBack as __callBack, receiveFunction as __receiveFunction, remoteTarget as __remoteTarget, sendFunction as __sendFunction, Service as __Service } from \"~/remote\";\nimport { Player as __Player } from \"~/facade\";\nimport { Player } from \"~/facade\";\nimport * as players from \"~/modules/perms/src/players\";\n\nexport interface PermsOptions {\n\t/** The file under `configs/` the permissions are kept in, without its extension; `\"perms\"` reads `perms.yaml` (or `.json`). */\n\tfile: string;\n\t/** The editor's store; `PERMS_EDITOR_URL` in `.env` overrides it. */\n\teditor: string;\n}\n\nexport interface PermissionInfo {\n\t/** What it lets a player do, as the editor shows it: `\"Kick players\"`. */\n\tdescription: string;\n\t/** Whether a player no group or grant says anything about has it; `false` by default. */\n\teveryone?: boolean;\n}\n\nexport interface GrantOptions {\n\t/** Seconds from now; left out, it is permanent. */\n\tfor?: number;\n\t/** The server it counts on (`PERMS_SERVER`); left out, every server. */\n\tserver?: string;\n}\n\nexport interface PermsChangeEvent {\n\tplayer: Player;\n}\n\n\n\n\n\nconst __service = new __Service(\"perms\", 1224716718);\n\nfunction __w2(w: __Writer, v: string): void { w.str(v); }\n\nfunction __r2(r: __Reader): string { return r.str(); }\n\nfunction __w3(w: __Writer, v: bool): void { w.bool(v); }\n\nfunction __r3(r: __Reader): bool { return r.bool(); }\n\nfunction __w1(w: __Writer, v: PermissionInfo): void {\n\t__w2(w, v.description);\n\tw.bool(v.everyone !== undefined);\n\tif (v.everyone !== undefined) __w3(w, v.everyone);\n}\n\nfunction __u1(r: __Reader, o: PermissionInfo): void {\n\to.description = __r2(r);\n\tif (r.bool()) o.everyone = __r3(r);\n\telse o.everyone = undefined;\n}\n\nfunction __r1(r: __Reader): PermissionInfo {\n\tconst o = changetype<PermissionInfo>(__new(offsetof<PermissionInfo>(), idof<PermissionInfo>()));\n\t__u1(r, o);\n\treturn o;\n}\n\nfunction __w0(w: __Writer, v: Record<string, PermissionInfo>): void {\n\tconst keys = Object.keys(v);\n\tw.i32(keys.length);\n\tfor (let i: i32 = 0; i < keys.length; i++) {\n\t\tw.str(keys[i]);\n\t\t__w1(w, v[keys[i]]);\n\t}\n}\n\nfunction __r0(r: __Reader): Record<string, PermissionInfo> {\n\tconst count = r.i32();\n\tconst record: Record<string, PermissionInfo> = {};\n\tfor (let i: i32 = 0; i < count; i++) {\n\t\tconst key = r.str();\n\t\trecord[key] = __r1(r);\n\t}\n\treturn record;\n}\n\nfunction __w4(w: __Writer, v: __Player): void { w.i32(<i32>v.id); }\n\nfunction __r4(r: __Reader): __Player { return new __Player(r.i32()); }\n\nfunction __w5(w: __Writer, v: Array<string>): void {\n\tw.i32(v.length);\n\tfor (let i: i32 = 0; i < v.length; i++) __w2(w, v[i]);\n}\n\nfunction __r5(r: __Reader): Array<string> {\n\tconst count = r.i32();\n\tconst list = new Array<string>();\n\tfor (let i: i32 = 0; i < count; i++) list.push(__r2(r));\n\treturn list;\n}\n\nfunction __w7(w: __Writer, v: f64): void { w.f64(<f64>v); }\n\nfunction __r7(r: __Reader): f64 { return <f64>r.f64(); }\n\nfunction __w8(w: __Writer, v: string | null): void {\n\tif (v == null) {\n\t\tw.bool(false);\n\t\treturn;\n\t}\n\tw.bool(true);\n\t__w2(w, v!);\n}\n\nfunction __r8(r: __Reader): string | null {\n\tif (!r.bool()) return null;\n\treturn __r2(r);\n}\n\nfunction __w6(w: __Writer, v: GrantOptions): void {\n\t__w7(w, v.for);\n\t__w8(w, v.server);\n}\n\nfunction __u6(r: __Reader, o: GrantOptions): void {\n\to.for = __r7(r);\n\to.server = __r8(r);\n}\n\nfunction __r6(r: __Reader): GrantOptions {\n\tconst o = changetype<GrantOptions>(__new(offsetof<GrantOptions>(), idof<GrantOptions>()));\n\t__u6(r, o);\n\treturn o;\n}\n\nfunction __w9(w: __Writer, v: (a0: PermsChangeEvent) => void): void { w.i32(__sendFunction(changetype<usize>(v), 0, __invoke)); }\n\nfunction __r9(r: __Reader): (a0: PermsChangeEvent) => void { return changetype<(a0: PermsChangeEvent) => void>(__receiveFunction(r, changetype<usize>(__stub0))); }\n\nfunction __w10(w: __Writer, v: PermsChangeEvent): void {\n\t__w4(w, v.player);\n}\n\nfunction __u10(r: __Reader, o: PermsChangeEvent): void {\n\to.player = __r4(r);\n}\n\nfunction __r10(r: __Reader): PermsChangeEvent {\n\tconst o = changetype<PermsChangeEvent>(__new(offsetof<PermsChangeEvent>(), idof<PermsChangeEvent>()));\n\t__u10(r, o);\n\treturn o;\n}\n\nfunction __stub0(a0: PermsChangeEvent): void {\n\tconst target = __remoteTarget();\n\tconst w = __beginCallback(target);\n\t__w10(w, a0);\n\tconst r = __callBack(target, w);\n}\n\nfunction __invoke(fn: usize, sig: i32, r: __Reader, w: __Writer): void {\n\tswitch (sig) {\n\t\tcase 0: {\n\t\t\tconst a0 = __r10(r);\n\t\t\tconst f = changetype<(a0: PermsChangeEvent) => void>(fn);\n\t\t\tf(a0);\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\nexport function declare(permissions: Record<string, PermissionInfo>): void {\n\tconst __w = __service.begin(0);\n\t__w0(__w, permissions);\n\tconst __r = __service.call(__w);\n}\n\nexport function has(player: Player, node: string): bool {\n\tconst __w = __service.begin(1);\n\t__w4(__w, player);\n\t__w2(__w, node);\n\tconst __r = __service.call(__w);\n\treturn __r3(__r);\n}\n\nexport function groupOf(player: Player): string {\n\tconst __w = __service.begin(2);\n\t__w4(__w, player);\n\tconst __r = __service.call(__w);\n\treturn __r2(__r);\n}\n\nexport function groupsOf(player: Player): Array<string> {\n\tconst __w = __service.begin(3);\n\t__w4(__w, player);\n\tconst __r = __service.call(__w);\n\treturn __r5(__r);\n}\n\nexport function addGroup(player: Player, group: string, options: GrantOptions = {}): void {\n\tconst __w = __service.begin(4);\n\t__w4(__w, player);\n\t__w2(__w, group);\n\t__w6(__w, options);\n\tconst __r = __service.call(__w);\n}\n\nexport function removeGroup(player: Player, group: string, options: GrantOptions = {}): void {\n\tconst __w = __service.begin(5);\n\t__w4(__w, player);\n\t__w2(__w, group);\n\t__w6(__w, options);\n\tconst __r = __service.call(__w);\n}\n\nexport function set(player: Player, node: string, value: boolean, options: GrantOptions = {}): void {\n\tconst __w = __service.begin(6);\n\t__w4(__w, player);\n\t__w2(__w, node);\n\t__w3(__w, value);\n\t__w6(__w, options);\n\tconst __r = __service.call(__w);\n}\n\nexport function unset(player: Player, node: string, options: GrantOptions = {}): void {\n\tconst __w = __service.begin(7);\n\t__w4(__w, player);\n\t__w2(__w, node);\n\t__w6(__w, options);\n\tconst __r = __service.call(__w);\n}\n\nexport function addEventListener(_type: \"change\", listener: (event: PermsChangeEvent) => void): void {\n\tconst __w = __service.begin(8);\n\t__w2(__w, _type);\n\t__w9(__w, listener);\n\tconst __r = __service.call(__w);\n}\n",
202
+ "serve": "// GENERATED by scripts/shared-modules.ts: ~/modules/perms, run by this plugin for every other.\nimport { Reader as __Reader, Writer as __Writer, beginCallback as __beginCallback, callBack as __callBack, receiveFunction as __receiveFunction, remoteTarget as __remoteTarget, sendFunction as __sendFunction, Handles as __Handles, serve as __serve } from \"~/remote\";\nimport * as __m from \"~/modules/perms\";\nimport { Player as __Player } from \"~/facade\";\nimport { PermissionInfo as __M_PermissionInfo, GrantOptions as __M_GrantOptions, PermsChangeEvent as __M_PermsChangeEvent } from \"~/modules/perms\";\n\nconst __handles = new __Handles();\n// The exported objects are handles 1, 2, ... - the numbers the proxies have.\n\nfunction __dispatch(op: i32, r: __Reader, w: __Writer): void {\n\tswitch (op) {\n\t\tcase 0: {\n\t\t\tconst a0 = __r0(r);\n\t\t\t__m.declare(a0);\n\t\t\tbreak;\n\t\t}\n\t\tcase 1: {\n\t\t\tconst a0 = __r4(r);\n\t\t\tconst a1 = __r2(r);\n\t\t\tconst result = __m.has(a0, a1);\n\t\t\t__w3(w, result);\n\t\t\tbreak;\n\t\t}\n\t\tcase 2: {\n\t\t\tconst a0 = __r4(r);\n\t\t\tconst result = __m.groupOf(a0);\n\t\t\t__w2(w, result);\n\t\t\tbreak;\n\t\t}\n\t\tcase 3: {\n\t\t\tconst a0 = __r4(r);\n\t\t\tconst result = __m.groupsOf(a0);\n\t\t\t__w5(w, result);\n\t\t\tbreak;\n\t\t}\n\t\tcase 4: {\n\t\t\tconst a0 = __r4(r);\n\t\t\tconst a1 = __r2(r);\n\t\t\tconst a2 = __r6(r);\n\t\t\t__m.addGroup(a0, a1, a2);\n\t\t\tbreak;\n\t\t}\n\t\tcase 5: {\n\t\t\tconst a0 = __r4(r);\n\t\t\tconst a1 = __r2(r);\n\t\t\tconst a2 = __r6(r);\n\t\t\t__m.removeGroup(a0, a1, a2);\n\t\t\tbreak;\n\t\t}\n\t\tcase 6: {\n\t\t\tconst a0 = __r4(r);\n\t\t\tconst a1 = __r2(r);\n\t\t\tconst a2 = __r3(r);\n\t\t\tconst a3 = __r6(r);\n\t\t\t__m.set(a0, a1, a2, a3);\n\t\t\tbreak;\n\t\t}\n\t\tcase 7: {\n\t\t\tconst a0 = __r4(r);\n\t\t\tconst a1 = __r2(r);\n\t\t\tconst a2 = __r6(r);\n\t\t\t__m.unset(a0, a1, a2);\n\t\t\tbreak;\n\t\t}\n\t\tcase 8: {\n\t\t\tconst a0 = __r2(r);\n\t\t\tconst a1 = __r9(r);\n\t\t\t__m.addEventListener(a0, a1);\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\nfunction __stub0(a0: __M_PermsChangeEvent): void {\n\tconst target = __remoteTarget();\n\tconst w = __beginCallback(target);\n\t__w10(w, a0);\n\tconst r = __callBack(target, w);\n}\n\nfunction __invoke(fn: usize, sig: i32, r: __Reader, w: __Writer): void {\n\tswitch (sig) {\n\t\tcase 0: {\n\t\t\tconst a0 = __r10(r);\n\t\t\tconst f = changetype<(a0: __M_PermsChangeEvent) => void>(fn);\n\t\t\tf(a0);\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\nfunction __w2(w: __Writer, v: string): void { w.str(v); }\n\nfunction __r2(r: __Reader): string { return r.str(); }\n\nfunction __w3(w: __Writer, v: bool): void { w.bool(v); }\n\nfunction __r3(r: __Reader): bool { return r.bool(); }\n\nfunction __w1(w: __Writer, v: __M_PermissionInfo): void {\n\t__w2(w, v.description);\n\tw.bool(v.everyone !== undefined);\n\tif (v.everyone !== undefined) __w3(w, v.everyone);\n}\n\nfunction __u1(r: __Reader, o: __M_PermissionInfo): void {\n\to.description = __r2(r);\n\tif (r.bool()) o.everyone = __r3(r);\n\telse o.everyone = undefined;\n}\n\nfunction __r1(r: __Reader): __M_PermissionInfo {\n\tconst o = changetype<__M_PermissionInfo>(__new(offsetof<__M_PermissionInfo>(), idof<__M_PermissionInfo>()));\n\t__u1(r, o);\n\treturn o;\n}\n\nfunction __w0(w: __Writer, v: Record<string, __M_PermissionInfo>): void {\n\tconst keys = Object.keys(v);\n\tw.i32(keys.length);\n\tfor (let i: i32 = 0; i < keys.length; i++) {\n\t\tw.str(keys[i]);\n\t\t__w1(w, v[keys[i]]);\n\t}\n}\n\nfunction __r0(r: __Reader): Record<string, __M_PermissionInfo> {\n\tconst count = r.i32();\n\tconst record: Record<string, __M_PermissionInfo> = {};\n\tfor (let i: i32 = 0; i < count; i++) {\n\t\tconst key = r.str();\n\t\trecord[key] = __r1(r);\n\t}\n\treturn record;\n}\n\nfunction __w4(w: __Writer, v: __Player): void { w.i32(<i32>v.id); }\n\nfunction __r4(r: __Reader): __Player { return new __Player(r.i32()); }\n\nfunction __w5(w: __Writer, v: Array<string>): void {\n\tw.i32(v.length);\n\tfor (let i: i32 = 0; i < v.length; i++) __w2(w, v[i]);\n}\n\nfunction __r5(r: __Reader): Array<string> {\n\tconst count = r.i32();\n\tconst list = new Array<string>();\n\tfor (let i: i32 = 0; i < count; i++) list.push(__r2(r));\n\treturn list;\n}\n\nfunction __w7(w: __Writer, v: f64): void { w.f64(<f64>v); }\n\nfunction __r7(r: __Reader): f64 { return <f64>r.f64(); }\n\nfunction __w8(w: __Writer, v: string | null): void {\n\tif (v == null) {\n\t\tw.bool(false);\n\t\treturn;\n\t}\n\tw.bool(true);\n\t__w2(w, v!);\n}\n\nfunction __r8(r: __Reader): string | null {\n\tif (!r.bool()) return null;\n\treturn __r2(r);\n}\n\nfunction __w6(w: __Writer, v: __M_GrantOptions): void {\n\t__w7(w, v.for);\n\t__w8(w, v.server);\n}\n\nfunction __u6(r: __Reader, o: __M_GrantOptions): void {\n\to.for = __r7(r);\n\to.server = __r8(r);\n}\n\nfunction __r6(r: __Reader): __M_GrantOptions {\n\tconst o = changetype<__M_GrantOptions>(__new(offsetof<__M_GrantOptions>(), idof<__M_GrantOptions>()));\n\t__u6(r, o);\n\treturn o;\n}\n\nfunction __w9(w: __Writer, v: (a0: __M_PermsChangeEvent) => void): void { w.i32(__sendFunction(changetype<usize>(v), 0, __invoke)); }\n\nfunction __r9(r: __Reader): (a0: __M_PermsChangeEvent) => void { return changetype<(a0: __M_PermsChangeEvent) => void>(__receiveFunction(r, changetype<usize>(__stub0))); }\n\nfunction __w10(w: __Writer, v: __M_PermsChangeEvent): void {\n\t__w4(w, v.player);\n}\n\nfunction __u10(r: __Reader, o: __M_PermsChangeEvent): void {\n\to.player = __r4(r);\n}\n\nfunction __r10(r: __Reader): __M_PermsChangeEvent {\n\tconst o = changetype<__M_PermsChangeEvent>(__new(offsetof<__M_PermsChangeEvent>(), idof<__M_PermsChangeEvent>()));\n\t__u10(r, o);\n\treturn o;\n}\n\n__serve(\"perms\", 1224716718, __dispatch);\n",
203
+ "callbacks": true
204
+ }
205
+ }
Binary file
@@ -0,0 +1,221 @@
1
+ /**
2
+ * `perms ...` in the server console and over rcon. A player with `perms.view`
3
+ * runs the commands that only show - `groups`, `check`, `nodes`, `user ...
4
+ * info`, `group ... info` - in his console or chat (`/perms`); changes are the
5
+ * server console's and the web editor's, which the server console opens:
6
+ *
7
+ * perms user <player|id> info
8
+ * perms user <player|id> group add|remove <group> [30d]
9
+ * perms user <player|id> permission set|unset <node> [true|false] [30d]
10
+ * perms group <group> info|create [weight]|delete
11
+ * perms group <group> permission set|unset <node> [true|false] [30d]
12
+ * perms group <group> parent add|remove <group>
13
+ * perms group <group> weight <n>
14
+ * perms groups | check <player|id> <node> | nodes [plugin] | editor [close] | reload | import [users.ini]
15
+ */
16
+ import { Player, server } from "@amxts/core";
17
+ import type { Change } from "./model";
18
+ import { DEFAULT_GROUP, allGroups, answer, changeOf, declaredNodes, explain, groupNamed, groupsOf, normalId, sourcesOf, userWith } from "./model";
19
+ import { closeEditor, openEditor } from "./editor";
20
+ import { importUsers } from "./import";
21
+ import { has, idOf, userOf } from "./players";
22
+ import { commit, reload, writeEverything } from "./state";
23
+ import { durationSeconds, leftOf } from "./time";
24
+
25
+ const USAGE = "perms user|group|groups|check|nodes|editor|reload|import - see the module's README";
26
+
27
+ type Print = (line: string) => void;
28
+
29
+ function word(words: string[], at: number) {
30
+ return at < words.length ? words[at] : "";
31
+ }
32
+
33
+ /** A player online by `#userid` or a part of his name, or an id as entries write it. */
34
+ function targetId(text: string) {
35
+ if (text.startsWith("STEAM_") || text.startsWith("ip:") || text.startsWith("name:")) return normalId(text);
36
+
37
+ const wanted = text.toLowerCase();
38
+ const found = server.players.find(player => `#${player.userId}` == text || player.name.toLowerCase().includes(wanted));
39
+ return found != null ? idOf(found) : "";
40
+ }
41
+
42
+ function onlineWith(id: string) {
43
+ return server.players.find(player => idOf(player) == id) ?? null;
44
+ }
45
+
46
+ /** The moment `30d` from now ends, 0 for none; -1 for a word that is no duration. */
47
+ function untilOf(text: string) {
48
+ if (text == "") return 0;
49
+
50
+ const seconds = durationSeconds(text);
51
+ return seconds < 0 ? -1 : Date.now() + seconds * 1000;
52
+ }
53
+
54
+ /** Commits changes and prints what was skipped once the store has them. */
55
+ function apply(changes: Change[], print: Print) {
56
+ commit(changes).then((committed) => {
57
+ committed.skipped.forEach(skip => print(`[perms] ${skip.reason}`));
58
+ if (committed.done.length > 0) print("[perms] Done");
59
+ });
60
+ }
61
+
62
+ /** What a player may run: the commands that only show; a change is the server console's or the editor's. */
63
+ function onlyShows(words: string[]) {
64
+ const what = word(words, 0);
65
+ const action = word(words, 2);
66
+ if (what == "user" || what == "group") return action == "" || action == "info";
67
+ return what == "groups" || what == "check" || what == "nodes";
68
+ }
69
+
70
+ export async function run(player: Player | null, words: string[], print: Print) {
71
+ const what = word(words, 0);
72
+ if (player != null && !has(player, "perms.view")) {
73
+ print("[perms] You need perms.view");
74
+ return;
75
+ }
76
+ if (player != null && !onlyShows(words)) {
77
+ print("[perms] Permissions are changed in the editor: perms editor in the server console");
78
+ return;
79
+ }
80
+
81
+ if (what == "user") userCommand(words, print);
82
+ else if (what == "group") groupCommand(words, print);
83
+ else if (what == "groups") listGroups(print);
84
+ else if (what == "check") checkCommand(words, print);
85
+ else if (what == "nodes") nodesCommand(word(words, 1), print);
86
+ else if (what == "editor") print(word(words, 1) == "close" ? await closed() : await openEditor());
87
+ else if (what == "reload") await reloaded(print);
88
+ else if (what == "import") await importCommand(word(words, 1), print);
89
+ else print(USAGE);
90
+ }
91
+
92
+ function listGroups(print: Print) {
93
+ const groups = allGroups().slice().sort((a, b) => b.weight - a.weight);
94
+ groups.forEach(group => print(`${group.name} (${group.weight})${group.inherits.length > 0 ? ` < ${group.inherits.join(", ")}` : ""}`));
95
+ }
96
+
97
+ async function reloaded(print: Print) {
98
+ await reload();
99
+ print("[perms] Reloaded");
100
+ }
101
+
102
+ async function closed() {
103
+ await closeEditor();
104
+ return "[perms] The editor is closed";
105
+ }
106
+
107
+ function userCommand(words: string[], print: Print) {
108
+ const id = targetId(word(words, 1));
109
+ if (id == "") return print(`[perms] No player "${word(words, 1)}" on the server; give his SteamID`);
110
+
111
+ const action = word(words, 2);
112
+ if (action == "info" || action == "") return userInfo(id, print);
113
+
114
+ const change = changeOf("grant");
115
+ change.user = id;
116
+ const sub = word(words, 3);
117
+
118
+ if (action == "group" && (sub == "add" || sub == "remove")) {
119
+ change.op = sub == "add" ? "memberAdd" : "memberRemove";
120
+ change.group = word(words, 4);
121
+ change.until = untilOf(word(words, 5));
122
+ if (change.until < 0) return print(`[perms] "${word(words, 5)}" is no duration: 30d, 12h, 90m`);
123
+ return apply([change], print);
124
+ }
125
+
126
+ if (action == "permission" && (sub == "set" || sub == "unset")) return permissionCommand(change, words, print);
127
+ print("[perms] perms user <player|id> info | group add|remove <group> [30d] | permission set|unset <node> [true|false] [30d]");
128
+ }
129
+
130
+ /** `permission set|unset <node> [true|false] [30d]`, words from the sub-command on. */
131
+ function permissionCommand(change: Change, words: string[], print: Print) {
132
+ change.op = word(words, 3) == "set" ? "grant" : "revoke";
133
+ change.node = word(words, 4);
134
+
135
+ const valueWord = word(words, 5);
136
+ const isValue = valueWord == "true" || valueWord == "false";
137
+ change.value = valueWord != "false";
138
+ change.until = untilOf(word(words, isValue ? 6 : 5));
139
+ if (change.until < 0) return print(`[perms] "${word(words, isValue ? 6 : 5)}" is no duration: 30d, 12h, 90m`);
140
+ return apply([change], print);
141
+ }
142
+
143
+ function userInfo(id: string, print: Print) {
144
+ const now = Date.now();
145
+ const user = userWith(id);
146
+ const player = onlineWith(id);
147
+ print(`[perms] ${id}${user != null && user.name != "" ? ` (${user.name})` : ""}${player != null ? " - online" : ""}`);
148
+ print(` groups: ${groupsOf(user, now).map<string>(group => group.name).join(", ")}`);
149
+ if (user == null) return;
150
+
151
+ user.groups.forEach(membership => print(` group ${membership.group}${membership.until != 0 ? `, ${leftOf(membership.until, now)} left` : ""}${membership.server != "" ? ` on ${membership.server}` : ""}`));
152
+ user.grants.forEach(grant => print(` ${grant.value ? "" : "-"}${grant.node}${grant.until != 0 ? `, ${leftOf(grant.until, now)} left` : ""}`));
153
+ if (player != null) print(` flags: ${player.access.join(", ")}`);
154
+ }
155
+
156
+ function groupCommand(words: string[], print: Print) {
157
+ const name = word(words, 1);
158
+ const action = word(words, 2);
159
+ const change = changeOf("groupCreate");
160
+ change.group = name;
161
+ if (name == "") return print("[perms] perms group <group> info|create|delete|permission|parent|weight");
162
+
163
+ if (action == "create") {
164
+ if (!/^[a-z0-9_-]+$/.test(name)) return print("[perms] A group's name is lower-case letters, digits, - and _");
165
+
166
+ change.weight = Number(word(words, 3) == "" ? "0" : word(words, 3));
167
+ return apply([change], print);
168
+ }
169
+ if (action == "delete") {
170
+ change.op = "groupDelete";
171
+ return apply([change], print);
172
+ }
173
+ if (action == "weight") {
174
+ change.op = "groupWeight";
175
+ change.weight = Number(word(words, 3));
176
+ return apply([change], print);
177
+ }
178
+ if (action == "parent" && (word(words, 3) == "add" || word(words, 3) == "remove")) {
179
+ change.op = word(words, 3) == "add" ? "parentAdd" : "parentRemove";
180
+ change.parent = word(words, 4);
181
+ return apply([change], print);
182
+ }
183
+ if (action == "permission" && (word(words, 3) == "set" || word(words, 3) == "unset")) return permissionCommand(change, words, print);
184
+ return groupInfo(name, print);
185
+ }
186
+
187
+ function groupInfo(name: string, print: Print) {
188
+ const group = groupNamed(name);
189
+ if (group == null) return print(`[perms] There is no group "${name}"`);
190
+
191
+ const now = Date.now();
192
+ print(`[perms] ${group.name}: weight ${group.weight}${group.inherits.length > 0 ? `, inherits ${group.inherits.join(", ")}` : ""}`);
193
+ group.grants.forEach(grant => print(` ${grant.value ? "" : "-"}${grant.node}${grant.until != 0 ? `, ${leftOf(grant.until, now)} left` : ""}${grant.server != "" ? ` on ${grant.server}` : ""}`));
194
+ }
195
+
196
+ function checkCommand(words: string[], print: Print) {
197
+ const id = targetId(word(words, 1));
198
+ const node = word(words, 2);
199
+ if (id == "" || node == "") return print("[perms] perms check <player|id> <node>");
200
+
201
+ const player = onlineWith(id);
202
+ const user = player != null ? userOf(player) : userWith(id);
203
+ const now = Date.now();
204
+ const yes = player != null ? has(player, node) : answer(sourcesOf(user, now), node);
205
+ print(`[perms] ${id} ${node}: ${yes ? "yes" : "no"} - from ${explain(user, node, now)}`);
206
+ }
207
+
208
+ function nodesCommand(plugin: string, print: Print) {
209
+ declaredNodes().filter(each => plugin == "" || each.node.startsWith(`${plugin}.`)).forEach(each => print(`${each.node}${each.byDefault ? " (everyone)" : ""} - ${each.description}`));
210
+ }
211
+
212
+ async function importCommand(file: string, print: Print) {
213
+ const count = importUsers(file == "" ? "users.ini" : file);
214
+ if (count < 0) {
215
+ print(`[perms] There is no ${file == "" ? "users.ini" : file} in the configs folder`);
216
+ return;
217
+ }
218
+
219
+ await writeEverything();
220
+ print(`[perms] Imported ${count} lines; ${DEFAULT_GROUP} and the other groups are as they were`);
221
+ }