Access Condition System (ACS)
ENiGMA½ uses an Access Condition System (ACS) that is both familiar to oldschool BBS operators and has its own style. With ACS, SysOps are able to control access to various areas of the system based on conditions such as group membership, connection type, terminal capabilities, and more. Various touch points in the system are configured to allow for acs checks. In some cases ACS is a simple boolean check while others (via ACS blocks) allow defining what conditions must be true for certain rights such as read and write (though others exist as well).
Group Membership
Section titled “Group Membership”ENiGMA½ does not utilize legacy “security levels” (see note below) but instead uses a group system. Users may belong to one or more groups which can be checked by the GM ACS code (see ACS Codes below). Two special groups exist out of the box:
users: Any regular user.sysops: System Operators. The first user (your root/admin) will always belong to this group.
You do not need to explicitly create groups: by checking for them via ACS and adding members to a group, they implicitly exist within the system. You may use as many groups as you like. See oputil user group for adding and removing users to groups.
ACS Grammar
Section titled “ACS Grammar”ACS strings are one or more ACS codes combined with logical operators. Whitespace (spaces) between operators, codes, and parentheses is optional — you can write compact strings like GM[users]|NC5 or readable ones like GM[users] | NC5.
Operators
Section titled “Operators”| Operator | Name | Description |
|---|---|---|
& | AND | Both sides must be true. This is also the default — two adjacent codes with no operator are implicitly AND’d. |
| | OR | Either side must be true. |
! | NOT | Negates the following check. |
( ) | Grouping | Control evaluation order. |
Operator Precedence
Section titled “Operator Precedence”From highest to lowest:
!(NOT) — binds tightest, applies to the immediately following code or group- Implicit AND /
&— adjacent codes or explicit& |(OR) — loosest binding
Parentheses override precedence: (A | B) & C requires either A or B to be true, AND C to be true.
Arguments
Section titled “Arguments”ACS codes take an optional argument immediately after the two-letter code:
| Form | Description | Examples |
|---|---|---|
| number | A single integer value | NC5, TH24, AA30 |
[values] | A comma-separated list of values in brackets | GM[users,sysops], ID[1,42], WD[0,6] |
| (none) | Some codes take no argument | SC, LC |
Spaces are allowed around commas inside lists: GM[users, sysops] is valid.
Examples
Section titled “Examples”| ACS String | Meaning |
|---|---|
GM[users] | User belongs to the users group |
NC2 | User has called at least 2 times |
ID1 | User is ID 1 (the SysOp) |
GM[elite,power] | User belongs to elite or power group |
ID1 | GM[co-op] | User is the SysOp OR belongs to co-op |
!TH24 | Terminal height is NOT exactly 24 (i.e., 24 fails; 25+ passes since TH checks >=) |
GM[users] & SC | User is in users group AND connection is secure |
GM[users] NC5 | Same as above but with implicit AND — user is in group AND has 5+ calls |
(GM[sysops] | ID1) & SC | SysOp or ID 1, AND secure connection required |
!GM[banned] | User is NOT in the banned group |
GM[users] & !GM[restricted] | In users but not in restricted |
ACS Codes
Section titled “ACS Codes”The following ACS codes are available:
User & Authentication
Section titled “User & Authentication”| Code | Condition |
|---|---|
IDn, ID[n,…] | User’s ID is n or one of [n,…] |
GM[group,…] | User belongs to one of [group,…] |
AGage | User’s age is >= age years |
ASstatus, AS[status,…] | User’s account status is status or one of [status,…]. 0=inactive, 1=active. |
AFfactor | User’s current authentication factor is >= factor. Factor 1 = password/pubkey, factor 2 = 2FA (OTP). |
ARfactor | User requires authentication factor >= factor. 1=always true, 2=true only if user has 2FA configured. |
PV[name,value] | User property name is exactly value. Allows arbitrary property checks, e.g. PV[message_conf,local]. |
Activity & Statistics
Section titled “Activity & Statistics”| Code | Condition |
|---|---|
NCcalls | User’s login/call count is >= calls |
NPposts | User’s message post count is >= posts |
AAdays | User’s account is >= days old |
UPcount | User’s upload file count is >= count |
DLcount | User’s download file count is >= count |
BUbytes | User’s total uploaded bytes is >= bytes |
BDbytes | User’s total downloaded bytes is >= bytes |
NRratio | User’s upload/download count ratio is >= ratio% |
KRratio | User’s upload/download byte ratio is >= ratio% |
PCratio | User’s post/call ratio is >= ratio% |
Achievements
Section titled “Achievements”| Code | Condition |
|---|---|
ACcount | User’s total achievement count is >= count |
APpoints | User’s total achievement points is >= points |
Connection & Terminal
Section titled “Connection & Terminal”| Code | Condition |
|---|---|
LC | Connection is local |
SC | Connection is secure (SSL/TLS, secure WebSocket, etc.) |
ECencoding | Terminal encoding: 0 = CP437, 1 = UTF-8 |
THheight | Terminal height is >= height |
TWwidth | Terminal width is >= width |
TT[type,…] | Terminal type is one of [type,…] (ansi, xterm, etc.) |
TM[theme,…] | User’s current theme ID is one of [theme,…] (e.g. luciano_blocktronics) |
NNnode, NN[node,…] | Current node number is node or one of [node,…] |
Time & Date
Section titled “Time & Date”| Code | Condition |
|---|---|
WDday, WD[day,…] | Day of week is day or one of [day,…]. 0=Sunday, 1=Monday, …, 6=Saturday. |
MMminutes | Current time is >= minutes past midnight (system time) |
Services & Features
Section titled “Services & Features”| Code | Condition |
|---|---|
SE[service,…] | All listed services are enabled. Service names are case-insensitive. Available: http, https, web (either http or https), gopher, nntp, nntps, activitypub (requires web), nodeinfo2 (requires web), webfinger (requires web). Unknown service names always fail. |
AEenabled | ActivityPub is enabled for the current user: 1=yes, 0=no |
ACS Blocks
Section titled “ACS Blocks”Some areas of the system require more than a single ACS string. In these situations an ACS block is used to allow finer-grained control. Each key in the block names a right (read, write, download, etc.) and maps to an ACS string.
acs: { read: GM[users] write: GM[sysops,co-ops] download: GM[elite] | UP10}All users can read (see) the area, sysops and co-ops can write (upload), and only members of elite or those with 10+ uploads can download.
Defaults
Section titled “Defaults”When an ACS block is not specified (or a particular scope is missing), the system applies sensible defaults:
| Context | Scope | Default |
|---|---|---|
| Message Conference | read | GM[users] |
| Message Conference | write | GM[users] |
| Message Area | read | GM[users] |
| Message Area | write | GM[users] |
| File Area | read | GM[users] |
| File Area | write | GM[sysops] |
| File Area | download | GM[users] |
| FSE Body Upload | uploadAcs | GM[users] |
| Menu Module | acs | (no check — all users can access) |
ACS Touch Points
Section titled “ACS Touch Points”The following areas of the system support ACS checks:
- Message conferences and areas
- File base areas and Access & Uploads
- Menus within Menu HJSON (menu.hjson) — use
acsin a menu’sconfigblock to restrict access - Conditional
next/actionarrays in menu configuration — each entry can include anacsfield to control which branch is taken
See the specific area documentation for details on available scopes and defaults.
Conditional Values
Section titled “Conditional Values”Some configuration fields (such as next in menus) support conditional arrays where each element may include an acs check. The first matching condition is used:
next: [ { acs: GM[sysops] next: sysopMainMenu } { acs: GM[users] next: userMainMenu } { // No acs — fallback for everyone else next: guestMenu }]