mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 16:02:26 +00:00
100 lines
5.0 KiB
Markdown
100 lines
5.0 KiB
Markdown
# Moderation Service Overview
|
|
|
|
**File**: `js/services/moderationService.js`
|
|
|
|
## Purpose
|
|
|
|
The `ModerationService` implements the decentralized Trust & Safety model for bitvid. It filters content based on a "Web of Trust" derived from the current user's social graph (NIP-02 Contact List, Kind 3) and administrative overrides.
|
|
|
|
Instead of a central authority deciding what is "safe," the service aggregates reports (NIP-56) only from users the viewer follows (their "trusted contacts"). This creates a personalized moderation layer where spam and abuse are filtered by community consensus within the user's network.
|
|
|
|
## Key Concepts
|
|
|
|
### Web of Trust
|
|
- **Viewer Context**: The service tracks the currently logged-in user (`viewerPubkey`).
|
|
- **Trusted Contacts**: The set of pubkeys the viewer follows (from their Kind 3 event).
|
|
- **Trust Score**: The number of unique trusted users who have reported a specific piece of content.
|
|
- **Thresholds**: Actions (e.g., blurring, disabling autoplay) are triggered when the Trust Score exceeds defined limits (`AUTOPLAY_TRUST_THRESHOLD`, `BLUR_TRUST_THRESHOLD`).
|
|
|
|
### NIP-56 Reports (Kind 1984)
|
|
- Users can report content for reasons like `nudity`, `spam`, `illegal`, etc.
|
|
- Reports are public events signed by the reporter.
|
|
- The service subscribes to reports for active content and aggregates them locally.
|
|
- **Crucially**: Reports from users *outside* the trusted contact list are ignored. Creator whitelist membership does not establish moderation trust.
|
|
|
|
### NIP-51 Mutes (Kind 10000)
|
|
- Users can mute other users to hide their content entirely.
|
|
- The service syncs with `UserBlocks` to enforce mutes.
|
|
- It also supports "Trusted Mutes" where mutes from trusted contacts can influence visibility (though this feature is evolving).
|
|
|
|
### Admin Overrides
|
|
- The service integrates with `AccessControl` to respect an instance-wide **Blacklist** (always hidden). The creator whitelist is access-only and never establishes moderation trust.
|
|
|
|
## Architecture & Data Flow
|
|
|
|
### 1. Initialization (Setting the Viewer)
|
|
When a user logs in, `setViewerPubkey(pubkey)` is called:
|
|
1. The service fetches the user's latest Kind 3 Contact List.
|
|
2. It extracts all followed pubkeys into `trustedContacts`.
|
|
3. It merges any admin-defined "Trust Seeds" (default trusted users).
|
|
4. It recomputes trust scores for all currently loaded content based on the new graph.
|
|
|
|
### 2. Report Aggregation
|
|
When viewing a video, the app calls `subscribeToReports(eventId)`:
|
|
1. The service subscribes to Kind 1984 events referencing the video ID.
|
|
2. Incoming reports are ingested via `ingestReportEvent`.
|
|
3. `recomputeSummaryForEvent` checks if the reporter is in `trustedContacts`.
|
|
4. If trusted, the report increments the score for its category.
|
|
5. If the score crosses a threshold, the service emits a `summary` event, updating the UI (e.g., to blur the video).
|
|
|
|
## Usage Example
|
|
|
|
```javascript
|
|
import moderationService from './services/moderationService.js';
|
|
|
|
// 1. Initialize with the logged-in user
|
|
await moderationService.setViewerPubkey(myPubkey);
|
|
|
|
// 2. Subscribe to reports for a video
|
|
await moderationService.subscribeToReports(videoEventId);
|
|
|
|
// 3. Listen for trust score updates
|
|
const unsubscribe = moderationService.on('summary', ({ eventId, summary }) => {
|
|
if (summary.totalTrusted >= 1) {
|
|
console.log(`Video ${eventId} is flagged by trusted users!`);
|
|
// UI logic: blur thumbnail, show warning
|
|
}
|
|
});
|
|
|
|
// 4. Submit a report (as the viewer)
|
|
await moderationService.submitReport({
|
|
eventId: videoEventId,
|
|
type: 'nudity',
|
|
targetPubkey: videoAuthorPubkey,
|
|
content: 'Contains explicit content'
|
|
});
|
|
```
|
|
|
|
## Public API Summary
|
|
|
|
| Method | Description |
|
|
| :--- | :--- |
|
|
| `setViewerPubkey(pubkey)` | Sets the active user and rebuilds the trust graph from their contacts. |
|
|
| `subscribeToReports(eventId)` | Starts listening for NIP-56 reports for the given event ID. |
|
|
| `submitReport(params)` | Publishes a signed Kind 1984 report event to relays. |
|
|
| `getTrustedReportSummary(eventId)` | Returns the current aggregated trust score and report types. |
|
|
| `isPubkeyBlockedByViewer(pubkey)` | Checks if the author is blocked/muted by the viewer. |
|
|
| `refreshViewerFromClient()` | Helper to sync the viewer with the active Nostr client state. |
|
|
|
|
## Invariants
|
|
|
|
- **Trust is Subjective**: A report only counts if the *viewer* follows the reporter. Changing the viewer changes all trust scores immediately.
|
|
- **Admin Trumps Trust**: Blacklisted users are ignored even if followed. Creator whitelist membership neither grants nor removes trust.
|
|
- **Reactive**: The service emits events (`summary`, `contacts`, `user-blocks`) to drive UI updates; it does not directly manipulate the DOM.
|
|
|
|
## When to Change
|
|
|
|
- **Refactoring**: Logic for "Trusted Mutes" (NIP-51 lists from others) is complex and partially deprecated/evolved. This area may need cleanup.
|
|
- **Performance**: If the number of reports or contacts grows large, the in-memory aggregation (`reportEvents` map) might need optimization or worker offloading.
|
|
- **Protocol Updates**: Changes to NIP-56 or NIP-51 should be reflected here.
|