On this page
Abstract
A comment moderation is a publication signed by a holder of a moderation role in a community
(owner, admin, or moderator) that changes the moderation state of one comment or the standing
of its author in that community. It can remove or approve the comment; lock, archive, or pin a post;
override spoiler, NSFW, and flairs; ban or flair the author; or purge the comment and its replies
from the community. The community authorizes the signer against its roles (BSIP-3),
records the moderation, and reflects the result in the community-signed comment update
(BSIP-5). This BSIP defines the commentModeration publication, how role holders are
recognized, what each action does, and how conflicting moderations resolve.
Motivation
Communities are the unit of moderation in Bitsocial, but moderators rarely hold the community’s private key or run its node. They need a signed message that the hosting node can authorize and act on, and clients need to agree on what each action means for display, for which later publications are accepted, and for the author’s standing. This BSIP specifies that message and those effects so that any client can moderate any community and any community can honor any client’s moderation.
Specification
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119 and RFC 8174.
Overview
- A role holder signs a
commentModerationnaming the target comment bycommentCidand listing one or more actions, and publishes it to the community under thecommentModerationkey of an encryptedCHALLENGEREQUEST(BSIP-4). - The community applies the common acceptance rules
(BSIP-4, Publication acceptance), checks the signer’s
role, applies the moderation rules below, and answers with a
CHALLENGEVERIFICATION. - The community records the moderation and applies its effects. The result appears in the comment’s next comment update and, for author actions, in the comment updates of all the author’s comments.
Moderations themselves are not published as records; readers see only their effect, asserted by the community in its signed comment updates.
Fields
A commentModeration is a JSON object with:
commentCid— REQUIRED. String, the CID of the target comment.commentModeration— REQUIRED. An object of actions, all OPTIONAL:removed— boolean. Remove (true) or restore (false) the comment.approved— boolean. Approve or disapprove a comment that is pending approval.locked— boolean. Lock or unlock a post.archived— boolean. Archive or unarchive a post.pinned— boolean. Pin or unpin a post or reply.spoiler,nsfw— boolean. Override the author’s values.flairs— array of flair objects, replacing the comment’s flairs.reason— string, a public explanation of the moderation.purged— boolean.truepurges the comment and its replies from the community.author— object of actions on the comment’s author:banExpiresAt— positive integer Unix time in seconds; the author is banned until then.flairs— array of flair objects, the author’s moderator-assigned flairs in this community.
and the common publication fields: timestamp,
protocolVersion, and signature (REQUIRED), author (OPTIONAL), and communityPublicKey and
communityName (BSIP-2, Community addressing).
A key present in commentModeration is an action; an absent key leaves that state unchanged. One
moderation MAY carry several actions. Unknown keys inside commentModeration or its author object
are accepted and ignored by communities that do not understand them, and do not appear in comment
updates.
The moderation is signed by the role holder following BSIP-2, Signatures.
Every top-level field other than signature MUST be listed in signedPropertyNames. pkc-js lists
the present fields in this order: author, communityPublicKey, communityName,
protocolVersion, timestamp, commentModeration, commentCid. Verifiers MUST NOT depend on the
order.
Example moderation removing a comment and banning its author, signed by a moderator whose role entry
in the community record is "tom.bso": { "role": "moderator" }:
{
"commentCid": "QmbKFFGL9EMwdMVrkJUqz2yQAorzUBExchK1qogsU8BJ7e",
"commentModeration": {
"removed": true,
"reason": "Spam link",
"author": { "banExpiresAt": 1795356000 }
},
"communityPublicKey": "12D3KooWBexQF4qDvyaxDgK4r2qPNk5z8s9b1eU5z2bnR6dExamPLe",
"communityName": "jokes.bso",
"author": { "name": "tom.bso" },
"timestamp": 1792764000,
"protocolVersion": "1.0.0",
"signature": {
"type": "ed25519",
"signature": "<base64>",
"publicKey": "<base64, 32 bytes>",
"signedPropertyNames": ["author", "communityPublicKey", "communityName", "protocolVersion", "timestamp", "commentModeration", "commentCid"]
}
}
Role matching
A publication’s signer holds a role when a key of the community’s roles
(BSIP-3, Roles) whose role object carries that role matches the publication
under BSIP-10, Identity lists: a key-form entry matches the signer
address, and a name-form entry matches only when the publication’s own author.name is the same
name and resolves, without a cached result, to the signer address. A community deciding authority
MUST apply that rule and MUST NOT match a role against a runtime author address. In addition:
- Only the roles
owner,admin, andmoderatorgrant authority. Other role strings grant nothing. - Roles are read from the community’s current state when the publication is validated. A community SHOULD evaluate the match again immediately before applying a publication that waited on an interactive challenge.
- When the only possible match failed because the community could not resolve the name, the
community SHOULD say so in the rejection
reasonrather than report that the signer has no role.
Authorization
A community MUST reject a commentModeration unless its signer holds the owner, admin, or
moderator role under Role matching. The three roles have the same moderation
powers. Authority comes only from roles: the key that signs the community record has no implicit
role.
Roles confer no rank over targets. Any role holder may moderate any comment, including comments by other role holders, and may ban any comment’s author.
Validation
A community MUST reject a commentModeration that fails the rules every publication must meet
(BSIP-4, Publication acceptance). Those rules include the ban
check, so a banned role holder cannot moderate, and reject a moderation whose comment does not exist
in the community (pending comments exist; purged ones do not). BSIP-4’s checks on the state of the
targeted comment and its thread do not apply: a moderator can act on a removed, deleted, locked,
archived, pending, or disapproved comment and on any comment in such a thread. In addition, a
community MUST reject a commentModeration that:
- carries a reserved top-level field:
insertedAt,modSignerAddress,extraProps,targetAuthorSignerAddress,targetAuthorDomain,challengeAnswers,challengeCommentCids,shortCommentCid,shortCommunityAddress,communityAddress,state,publishingState,signer,clients, ornameResolved; - is not authorized, under Authorization;
- has a
timestampearlier than the target comment’stimestamp; - sets
lockedorarchivedtotrueon a reply. Only posts are locked or archived; afalsevalue on a reply is accepted and has no effect; - sets
archivedtotruewhile the community record’sfeatures.noArchiveistrue, unless the post is already archived; - carries
approved, with either value, for a comment that is not pending approval; - has the same signature as a moderation the community already accepted. BSIP-4, Duplicate requests governs the answer to a resend.
Moderator flairs, spoiler, and nsfw are not checked against the community’s flair lists or
features.
A community answers a rejected moderation with challengeSuccess: false and a reason, and an
accepted one with challengeSuccess: true and no encrypted payload.
Actions
Each action below describes the effect on the target comment’s update U (BSIP-5)
and on later publications. Rejections of later publications are enforced by BSIP-4’s checks on the
targeted comment (BSIP-4, Publication acceptance).
removedsetsU.removed. While a comment is removed, votes and replies on it and edits of it are rejected; while a post is removed, every vote, reply, and edit in its thread is rejected. Replies under a removed reply remain open. A removed comment is not counted in its ancestors’ reply counts. By default pkc-js leaves removed posts out of the posts pages and keeps removed replies in reply pages as tombstones (BSIP-3, Pages).falserestores it.spoiler,nsfwsetU.spoilerandU.nsfw, which take precedence over the comment’s and the author’s edit values (BSIP-7).flairssetsU.flairs, which takes precedence over the comment’s and the edit’s flairs. An empty array clears them.pinnedsetsU.pinned. Pages list pinned comments first unless a sort says otherwise (BSIP-3, Pages).lockedsetsU.lockedon a post. Replies in a locked post’s thread, and edits of the post or of any comment in its thread, are accepted only from role holders; votes on the post or on anything in its thread are rejected for everyone, role holders included.falseunlocks.archivedsetsU.archivedon a post. Replies, votes, and edits in an archived post’s thread, the post included, are rejected for everyone; only moderations are still accepted.falseunarchives.reasonsetsU.reason.approved: truemakes a pending comment live. The community adds the comment record to IPFS (it was not published there while pending), assigns itsnumberandpostNumber, includes it in pages, and setsU.approvedtotrue.approved: falsedisapproves a pending comment:- if
approvedis the only key incommentModeration, the community deletes the comment from its store entirely, leaving no comment update; - otherwise the comment leaves the moderation queue but is kept:
U.approvedisfalseandU.removedistrueunless a moderation has setremovedexplicitly. Votes, replies, and edits on it are rejected, except an author edit deleting it (BSIP-7).
- if
purged: truedeletes the comment and its entire reply subtree from the community: their records, comment updates, and the votes and edits targeting them. The community stops serving and unpins them, removes them from pages and counts, and from then on rejects any publication that references them as unknown. Purging cannot be undone. The other comment actions of a purging moderation have no lasting effect; itsauthoractions still apply, because the community records the target author before purging.author.banExpiresAtbans the target comment’s author (see Author standing) until that time. BSIP-4’s ban check rejects every publication from a banned author, of every type, whilebanExpiresAtis later than the current time. The value appears asauthor.community.banExpiresAtin the comment updates of the author’s comments. A ban is lifted by a later moderation that setsbanExpiresAtto a past time.author.flairssets the author’s moderator-assigned flairs, which appear asauthor.community.flairsin the comment updates of the author’s comments and take precedence over author-chosen flairs.
Author standing
The target author of a moderation is the author of the target comment: the address derived from
the comment record’s signature.publicKey and, if the comment record has an author.name, that
name. For a comment stored under a pseudonymity alias
(BSIP-2, Pseudonymity), the target author is the original author: the
original public key and name the community recorded when it accepted the comment, not the alias.
A community MUST record the target author when it accepts a moderation with author actions, and
MUST keep that record when the target comment is later purged, so that bans outlive the comment.
When the community computes an author’s standing, either to run BSIP-4’s ban check on a new
publication or to fill author.community in a comment update, an author moderation applies when its
recorded target author is:
- the address derived from the publication’s or comment’s signing key;
- for an original author, any alias address the community issued to them, and for an alias address, the original author it belongs to; or
- the exact
author.nameof the publication, or the original author name recorded for the comment.
pkc-js compares names exactly here, so a ban recorded for x.eth does not match x.bso.
Communities SHOULD treat names that are the same under
BSIP-10, Name equivalence as the same author.
In a comment update for a pseudonymous comment, author.community.banExpiresAt and
author.community.flairs reflect moderations targeting the alias or its original author, while the
karma fields count only the alias’s own comments.
Resolving conflicts
A community MUST resolve the state it publishes as follows:
- Per field, the last accepted moderation wins. For each of
removed,approved,locked,archived,pinned,spoiler,nsfw, andflairs, the comment’s value is the value in the moderation of that comment the community accepted last among those that set the field. Acceptance order decides, nottimestamp, and it does not matter which role holder signed. reasonresolves on its own:U.reasonis the reason in the last accepted moderation of the comment that carried one. It may explain a different action than the latest flag change, and clients SHOULD NOT assume otherwise.- Author actions resolve per author, across all of that author’s comments: the ban is the
banExpiresAtof the last accepted moderation targeting the author that set one, even if it is earlier than a previous ban, and the author flairs are those of the last accepted moderation targeting the author that set them. - Moderators override authors.
U.spoiler,U.nsfw, andU.flairstake precedence over the author’s edit (BSIP-7) whichever was published later. - Removal and deletion are independent. A comment may be removed (
U.removed), deleted by its author (U.edit.deleted), or both. - Purge is terminal. Nothing can target a purged comment.
Rationale
- Role holders sign, the community asserts. A moderation is authenticated once, by the node that applies it. Readers already trust that node for its comment updates (BSIP-5), so republishing every moderation as a separate verifiable record would add data without adding trust.
- Matching on the signing key, or on a name proven to resolve to it, means a role cannot be
claimed by writing someone else’s name into
author.name. Resolving at match time makes revoking a name, or pointing it at a new key, take effect immediately. - Per-field last-writer-wins lets several moderators act at once without coordinating: each moderation states only what it changes.
- Locking and archiving apply to posts because they close a whole thread; pinning applies to any comment because replies can be pinned within their parent’s reply pages.
- Disapproval with or without a reason. A bare
approved: falsediscards spam with no trace; a disapproval carrying anything else keeps a record so the author can see why. - Bans keyed to the author, not the comment, survive purges and apply across all of the author’s aliases and, by name, to new keys that claim the same name.
Backwards Compatibility
Unknown keys inside commentModeration and its author object are accepted and ignored, so new
moderation actions can be added without breaking older communities; older communities simply do not
apply them. A community that has not implemented an action MUST NOT claim its effect in comment
updates.
Security Considerations
- Authorization bypass. The role check is the only barrier between any key and full moderation
power. A community MUST implement Role matching exactly: matching a role key
against a claimed
author.namewithout resolving it, or against a runtime author address, lets anyone moderate. - Stale authorization. Roles are checked when the request is validated, before any interactive challenge. pkc-js does not check again before applying the moderation, so a role revoked while the moderator answers a challenge (up to the exchange’s lifetime) does not stop it; hence the re-check recommended in Role matching.
- No rank among roles. A
moderatorcan remove an owner’s posts and ban an owner or admin, and a banned role holder can no longer moderate or publish community edits (BSIP-9) over pubsub. Only the node operator can repair this. Communities SHOULD grant roles only to trusted keys; implementations MAY refuse moderations whose target author holds a higher role, as a local policy. - Replay. Duplicate detection by signature and the timestamp window stop replays, and the signed
communityPublicKey,communityName, andcommentCidstop a moderation from being replayed to another community or comment. - Unverifiable history. Readers see only the community-signed result, not who moderated. A community can therefore claim moderation that no role holder performed; this is inside the trust readers already give it for comment updates.
- Ban evasion. Bans match keys, aliases, and names. A banned author can publish under a fresh key without a name; resisting that is the job of the community’s anti-spam challenges and exclusion policy (BSIP-4). A publication claiming a banned name is rejected even if its signer does not own the name, which harms only the claimant.
- Purge is not erasure. Purging stops the community serving the records and unpins them, but peers that fetched them may keep copies.
- Pending content is already visible. A pending comment is not added to IPFS under its own CID until it is approved, but its record is carried in the community’s moderation queue pages (BSIP-3), which anyone can fetch. Disapproval and purging stop serving it; they cannot recall copies already fetched.
- Reasons are public.
reasonappears in signed comment updates; moderators SHOULD NOT put private information in it.
Copyright
Copyright and related rights waived via CC0.