mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-11-02 19:02:28 +00:00
feat: refine trust controls and harden BitLogin
This commit is contained in:
1 parent
f25c2ac242
commit
18e08bf2cb
32 files changed
+1207
-740
No files matched your search
@@ -9,7 +9,7 @@ Instead of a centralized moderation authority, the service builds a local "trust
|
||||
- **Viewer**: The currently logged-in user.
|
||||
- **Trusted Contacts**: Users followed by the Viewer (Kind 3 contact list).
|
||||
- **Trusted Seeds**: An optional set of admin-defined pubkeys that provide a baseline of trust (e.g., project maintainers).
|
||||
- **Admin Whitelist/Blacklist**: Hardcoded lists in `accessControl` that override dynamic trust.
|
||||
- **Admin Whitelist/Blacklist**: Nostr-backed lists in `accessControl`. The creator whitelist controls access only; a blacklist always filters first and suppresses its members' content and reports.
|
||||
|
||||
### 2. Trust Aggregation
|
||||
When a piece of content (Event) is reported (Kind 1984), the service aggregates these reports but *only counts reports from trusted users*.
|
||||
|
||||
@@ -6,7 +6,7 @@ bitvid is follow-centric. Your Home feed comes from people you follow (F1). Disc
|
||||
## Core principles
|
||||
- **Freedom to choose**: User picks filters. Defaults are safe but reversible.
|
||||
- **Explain decisions**: Every blur/hide shows a “why” badge and a “show anyway” control.
|
||||
- **Blacklist > whitelist**: Admin blacklists and moderation gates always win; whitelists only influence Discovery ranking.
|
||||
- **Separate access and trust**: The creator whitelist controls site and content access only; moderation uses the viewer's trust graph and admin blacklists.
|
||||
- **Minimal central power**: Admin lists are opt-in; users can unsubscribe.
|
||||
|
||||
## Threat model (short)
|
||||
@@ -47,10 +47,10 @@ Thread new moderation behaviors through the same service → stage → app → U
|
||||
- Hide videos when `DEFAULT_TRUSTED_MUTE_HIDE_THRESHOLD` trusted contacts mute the author. Cards render with `data-moderation-hidden="true"`, the badge reads `Hidden · {count} trusted mute(s)`, and a "Show anyway" button becomes available alongside a "Restore default moderation" control once the override is active.
|
||||
- Hide videos when `DEFAULT_TRUSTED_SPAM_HIDE_THRESHOLD` trusted contacts file spam reports. The badge copy escalates to `Hidden · {count} trusted spam report(s)` and the card stays hidden until the viewer overrides it.
|
||||
- Downrank author when any F1 has them in mute list (10000).
|
||||
- Opt-in admin lists (30000 with `d=bitvid:admin:*`) can hard-hide content, but whitelist entries no longer bypass moderation gates—they only influence Discovery rankings when a viewer opts into that list.
|
||||
- Opt-in admin lists (30000 with `d=bitvid:admin:*`) can hard-hide content through the blacklist. The creator whitelist is access-only and does not change web-of-trust blur, autoplay, or hide decisions.
|
||||
- Trust seeds now come from the Super Admin plus every active moderator, so their reports shape anonymous/default visitor filters automatically. The `DEFAULT_TRUST_SEED_NPUBS` export only activates as an emergency fallback when those live lists cannot be loaded (toggle via `FEATURE_TRUST_SEEDS`).
|
||||
|
||||
> Default thresholds now come directly from [`config/instance-config.js`](../../config/instance-config.js). Look for the exports `DEFAULT_BLUR_THRESHOLD`, `DEFAULT_AUTOPLAY_BLOCK_THRESHOLD`, `DEFAULT_TRUSTED_MUTE_HIDE_THRESHOLD`, and `DEFAULT_TRUSTED_SPAM_HIDE_THRESHOLD` to adjust the instance-wide behavior before deploying. The upstream repo currently publishes example values of 1 trusted report for blur, 1 for autoplay blocking, 20 trusted mutes to hide authors, and 1 trusted spam report to hide videos.
|
||||
> Default thresholds now come directly from [`config/instance-config.js`](../../config/instance-config.js). Look for the exports `DEFAULT_BLUR_THRESHOLD`, `DEFAULT_AUTOPLAY_BLOCK_THRESHOLD`, `DEFAULT_TRUSTED_MUTE_HIDE_THRESHOLD`, and `DEFAULT_TRUSTED_SPAM_HIDE_THRESHOLD` to adjust the instance-wide behavior before deploying. The hosted defaults require 3 trusted reports for blur and autoplay blocking, 20 trusted mutes to hide authors, and 5 trusted spam reports to hide videos.
|
||||
|
||||
> Operators can still override these thresholds on a per-viewer basis in **Settings → Safety & Moderation**; leaving the UI fields blank restores the config-driven defaults. Update [`config/instance-config.js`](../../config/instance-config.js) to change what new viewers receive out of the box.
|
||||
|
||||
@@ -89,7 +89,7 @@ The trusted mute hide helper copy clarifies the escalation path: once the truste
|
||||
### Runtime flags
|
||||
|
||||
- `TRUSTED_MUTE_HIDE_THRESHOLD` — numeric default for the trusted mute hide control. Initialized from `DEFAULT_TRUSTED_MUTE_HIDE_THRESHOLD` in [`config/instance-config.js`](../../config/instance-config.js); the upstream config sets this to `20`, but adjust the export to match your policy.
|
||||
- `TRUSTED_SPAM_HIDE_THRESHOLD` — numeric default for the trusted spam hide control. Initialized from `DEFAULT_TRUSTED_SPAM_HIDE_THRESHOLD` in [`config/instance-config.js`](../../config/instance-config.js); the upstream config example is `1`.
|
||||
- `TRUSTED_SPAM_HIDE_THRESHOLD` — numeric default for the trusted spam hide control. Initialized from `DEFAULT_TRUSTED_SPAM_HIDE_THRESHOLD` in [`config/instance-config.js`](../../config/instance-config.js); the hosted default is `5`.
|
||||
- `FEATURE_TRUSTED_HIDE_CONTROLS` — boolean toggle to hide/show the new trusted hide controls in the UI (default `true`).
|
||||
|
||||
## Files in this folder
|
||||
|
||||
@@ -40,8 +40,8 @@ Create three distinct F1 reporter keys; each sends:
|
||||
Expected:
|
||||
|
||||
* After 1 report → no blur; autoplay allowed.
|
||||
* Once reports reach `DEFAULT_AUTOPLAY_BLOCK_THRESHOLD` → autoplay blocked (the upstream configuration currently sets this to 2, but rely on your `config/instance-config.js` value).
|
||||
* Once reports reach `DEFAULT_BLUR_THRESHOLD` → thumbnail blurred; reason chip shown (upstream example: 1). At the spam threshold (`TRUSTED_SPAM_HIDE_THRESHOLD` sourced from `DEFAULT_TRUSTED_SPAM_HIDE_THRESHOLD` in [`config/instance-config.js`](../../config/instance-config.js)) the card hides entirely and the badge copy switches to "Hidden · {count} trusted spam report(s)" until the viewer overrides it.
|
||||
* Once reports reach `DEFAULT_AUTOPLAY_BLOCK_THRESHOLD` → autoplay blocked (the hosted configuration currently sets this to 3, but rely on your `config/instance-config.js` value).
|
||||
* Once reports reach `DEFAULT_BLUR_THRESHOLD` → thumbnail blurred; reason chip shown (the hosted default is 3). At the spam threshold (`TRUSTED_SPAM_HIDE_THRESHOLD` sourced from `DEFAULT_TRUSTED_SPAM_HIDE_THRESHOLD` in [`config/instance-config.js`](../../config/instance-config.js), currently 5) the card hides entirely and the badge copy switches to "Hidden · {count} trusted spam report(s)" until the viewer overrides it.
|
||||
|
||||
**Exercises:** [`ModerationService.ingestReportEvent()`](../../js/services/moderationService.js) and [`ModerationService.getTrustedReportSummary()`](../../js/services/moderationService.js) wire through [`createModerationStage()`](../../js/feedEngine/stages.js) so [`bitvidApp.decorateVideoModeration()`](../../js/app.js) can hand the summary to [`VideoCard.refreshModerationUi()`](../../js/ui/components/VideoCard.js).
|
||||
|
||||
|
||||
@@ -54,8 +54,8 @@ list. Blocking still follows the precedence rules above.
|
||||
- A video has 3 `nudity` reports from those seed accounts.
|
||||
|
||||
Result:
|
||||
- Thumbnail is blurred if `DEFAULT_BLUR_THRESHOLD` is 1 (met).
|
||||
- Autoplay is blocked if `DEFAULT_AUTOPLAY_BLOCK_THRESHOLD` is 1 (met).
|
||||
- Thumbnail is blurred because the 3 trusted reports meet `DEFAULT_BLUR_THRESHOLD`.
|
||||
- Autoplay is blocked because the 3 trusted reports meet `DEFAULT_AUTOPLAY_BLOCK_THRESHOLD`.
|
||||
- No hard hide unless trusted mute/spam thresholds are met.
|
||||
|
||||
### Example 2: Logged-in viewer with personal blocks
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
- `hideIfTrustedMuteCount(author, category) >= trustedMuteHideThresholds[category] ?? DEFAULT_TRUSTED_MUTE_HIDE_THRESHOLD`
|
||||
- `hideIfTrustedSpamReports(event) >= DEFAULT_TRUSTED_SPAM_HIDE_THRESHOLD`
|
||||
|
||||
Threshold constants are exported from [`config/instance-config.js`](../../config/instance-config.js) so operators can change the defaults without touching moderation code. Inspect the `DEFAULT_BLUR_THRESHOLD`, `DEFAULT_AUTOPLAY_BLOCK_THRESHOLD`, `DEFAULT_TRUSTED_MUTE_HIDE_THRESHOLD`, and `DEFAULT_TRUSTED_SPAM_HIDE_THRESHOLD` exports to set your policy. The upstream repo includes example values (blur at 1, autoplay block at 1, trusted mute hide at 20, trusted spam hide at 1), but treat those as guidance rather than hard-coded requirements. Per-category trusted mute hide thresholds now live in moderation settings as `trustedMuteHideThresholds` (e.g., `{ spam: 5, nudity: 10 }`), and any category not present falls back to the default trusted mute hide threshold. When evaluating trusted mutes we use the content's report type if available, otherwise we fall back to any category metadata attached to trusted mute list entries.
|
||||
Threshold constants are exported from [`config/instance-config.js`](../../config/instance-config.js) so operators can change the defaults without touching moderation code. The hosted baseline requires 3 trusted reports to blur or block autoplay, 20 trusted mutes to hide an author, and 5 trusted spam reports to hide a video. Per-category trusted mute hide thresholds now live in moderation settings as `trustedMuteHideThresholds` (e.g., `{ spam: 5, nudity: 10 }`), and any category not present falls back to the default trusted mute hide threshold. When evaluating trusted mutes we use the content's report type if available, otherwise we fall back to any category metadata attached to trusted mute list entries.
|
||||
|
||||
### Trusted mute decay window
|
||||
- Trusted mute counts are **time-bounded**: only mute lists updated within the rolling window (currently 60 days) contribute to `trustedMuteCount`.
|
||||
@@ -34,7 +34,7 @@ Threshold constants are exported from [`config/instance-config.js`](../../config
|
||||
## Admin lists (opt-in)
|
||||
- We recognize curated lists using `30000` events:
|
||||
- `['d','bitvid:admin:blacklist']` → hard-hide when subscribed.
|
||||
- `['d','bitvid:admin:whitelist']` → improves Discovery ranking when subscribed but no longer bypasses moderation gates.
|
||||
- `['d','bitvid:admin:whitelist']` → controls creator access only; it does not add a reporter to the trust graph or alter moderation decisions.
|
||||
- `['d','bitvid:admin:editors']` → trusted channel editors.
|
||||
- Users can subscribe/unsubscribe any time.
|
||||
|
||||
@@ -42,7 +42,7 @@ Threshold constants are exported from [`config/instance-config.js`](../../config
|
||||
|
||||
1. **Personal blocks win first.** If a viewer blocks an author or reporter, we ignore their content and reports regardless of admin lists.
|
||||
2. **Admin blacklist applies next.** Entries on `bitvid:admin:blacklist` are hard-hidden and their reports suppressed before looking at thresholds.
|
||||
3. **F1 thresholds run last.** Blur/autoplay gating only evaluates trusted-report counts after personal blocks and admin blacklists. Admin whitelists contribute to Discovery ranking when a viewer subscribes, but they never override moderation gates or a viewer block.
|
||||
3. **F1 thresholds run last.** Blur/autoplay gating evaluates trusted-report counts after personal blocks and admin blacklists. The creator whitelist is not an input to these decisions.
|
||||
|
||||
## Pseudocode
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ Instead of a central authority deciding what is "safe," the service aggregates r
|
||||
- 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 (unless whitelisted by admin).
|
||||
- **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.
|
||||
@@ -28,7 +28,7 @@ Instead of a central authority deciding what is "safe," the service aggregates r
|
||||
- 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) and **Whitelist** (always trusted).
|
||||
- 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
|
||||
|
||||
@@ -89,7 +89,7 @@ await moderationService.submitReport({
|
||||
## 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. Whitelisted users are trusted even if not followed.
|
||||
- **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
|
||||
|
||||
@@ -38,7 +38,7 @@ Bootstrapping is intentionally defensive so the UI can initialize quickly:
|
||||
- **Access control hydration**: `waitForAccessControl()` races `accessControl.ensureReady()` against a 3.5s timeout. If hydration times out, bootstrapping logs a dev warning and falls back to defaults.
|
||||
- **Immediate apply**: Seeds are applied immediately after the first hydration attempt, even if the admin list hydration failed, so moderation does not block on relay availability.
|
||||
- **Retry when relays are ready**: If hydration failed, `bootstrapTrustedSeeds()` checks for relay readiness via `nostrService.nostrClient.relays` (and pool existence). If relays become available within 3.5s, it retries admin list hydration once. If relays never become ready, it logs a dev warning and re-applies the current seeds to keep moderation functional.
|
||||
- **Change listeners**: `accessControl.onWhitelistChange()` and `accessControl.onEditorsChange()` are registered so any subsequent admin/editor updates re-run seed application and recompute moderation summaries.
|
||||
- **Change listeners**: `accessControl.onEditorsChange()` and `accessControl.onBlacklistChange()` are registered so changes affecting the moderator roster or eligibility re-run seed application and recompute moderation summaries. Creator-whitelist changes do not affect trust seeds.
|
||||
|
||||
## Relay list persistence and refresh
|
||||
|
||||
|
||||
Reference in new issue
Block a user