mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
[security] replace innerHTML usages in js/subscriptions.js — convert to safe DOM APIs
Co-authored-by: PR0M3TH3AN <[email protected]>
This commit is contained in:
1 parent
6aa9da1383
commit
8536f2f858
8 files changed
+113
-16
No files matched your search
@@ -0,0 +1,16 @@
|
||||
# Context
|
||||
|
||||
- **File:** `js/subscriptions.js`
|
||||
- **Reason:** Migrating `innerHTML` assignments to safe DOM APIs as part of security hardening.
|
||||
- **Date:** 2026-02-13
|
||||
- **Commit:** (will be added)
|
||||
- **Node:** v22.22.0
|
||||
- **npm:** 11.7.0
|
||||
|
||||
## Plan
|
||||
|
||||
1. Replace `innerHTML` assignments with `textContent` where possible.
|
||||
2. Implement `renderStatusMessage` helper for simple messages.
|
||||
3. Implement `renderLoadingIndicator` helper to replace `getSidebarLoadingMarkup`.
|
||||
4. Verify changes with lint and tests.
|
||||
5. Update `check-innerhtml` baseline.
|
||||
@@ -0,0 +1,7 @@
|
||||
# Decisions
|
||||
|
||||
- **File:** `js/subscriptions.js`
|
||||
- **Migration:** Replaced `innerHTML` assignments with `replaceChildren()` and `document.createElement()`.
|
||||
- **Helpers:** Added `_renderStatusMessage` and `_renderLoading` to `SubscriptionsManager` to encapsulate DOM creation for status and loading states.
|
||||
- **Dependency:** Removed dependency on `getSidebarLoadingMarkup` (which returned a string) in this file, preferring local DOM creation.
|
||||
- **Baseline:** Updated baseline for `js/subscriptions.js` from 7 to 0.
|
||||
@@ -0,0 +1,8 @@
|
||||
# Agent Task Log Entry
|
||||
|
||||
- **Date:** 2026-02-13
|
||||
- **Agent:** innerhtml-migration-agent
|
||||
- **Prompt:** bitvid-innerhtml-migration-agent.md
|
||||
- **Status:** started
|
||||
- **Branch:** chore/scheduler/innerhtml-migration-2026-02-13
|
||||
- **Summary:** Task claimed — execution beginning
|
||||
@@ -0,0 +1,8 @@
|
||||
# Agent Task Log Entry
|
||||
|
||||
- **Date:** 2026-02-13
|
||||
- **Agent:** innerhtml-migration-agent
|
||||
- **Prompt:** bitvid-innerhtml-migration-agent.md
|
||||
- **Status:** completed
|
||||
- **Branch:** ai/innerhtml-fix/subscriptions
|
||||
- **Summary:** Migrated 7 innerHTML assignments in js/subscriptions.js to safe DOM APIs and updated baseline
|
||||
+48
-15
@@ -19,7 +19,6 @@ import {
|
||||
NOTE_TYPES,
|
||||
} from "./nostrEventSchemas.js";
|
||||
import { CACHE_POLICIES, STORAGE_TIERS } from "./nostr/cachePolicies.js";
|
||||
import { getSidebarLoadingMarkup } from "./sidebarLoading.js";
|
||||
import {
|
||||
publishEventToRelays,
|
||||
assertAnyRelayAccepted
|
||||
@@ -1563,8 +1562,7 @@ class SubscriptionsManager {
|
||||
const container = document.getElementById(containerId);
|
||||
if (!userPubkey) {
|
||||
if (container) {
|
||||
container.innerHTML =
|
||||
"<p class='text-muted-strong'>Please log in first.</p>";
|
||||
this._renderStatusMessage(container, "Please log in first.");
|
||||
}
|
||||
this.lastRunOptions = null;
|
||||
this.lastResult = null;
|
||||
@@ -1593,8 +1591,7 @@ class SubscriptionsManager {
|
||||
}
|
||||
|
||||
if (!channelHexes.length) {
|
||||
container.innerHTML =
|
||||
"<p class='text-muted-strong'>No subscriptions found.</p>";
|
||||
this._renderStatusMessage(container, "No subscriptions found.");
|
||||
this.lastRunOptions = {
|
||||
actorPubkey: userPubkey,
|
||||
limit,
|
||||
@@ -1606,7 +1603,7 @@ class SubscriptionsManager {
|
||||
}
|
||||
|
||||
if (!this.hasRenderedOnce) {
|
||||
container.innerHTML = getSidebarLoadingMarkup("Fetching subscriptions…");
|
||||
this._renderLoading(container, "Fetching subscriptions…");
|
||||
}
|
||||
|
||||
this.lastRunOptions = {
|
||||
@@ -1634,8 +1631,7 @@ class SubscriptionsManager {
|
||||
|
||||
const engine = this.getFeedEngine();
|
||||
if (!engine || typeof engine.run !== "function") {
|
||||
container.innerHTML =
|
||||
"<p class='text-muted-strong'>Subscriptions are unavailable right now.</p>";
|
||||
this._renderStatusMessage(container, "Subscriptions are unavailable right now.");
|
||||
this.hasRenderedOnce = true;
|
||||
return null;
|
||||
}
|
||||
@@ -1714,8 +1710,7 @@ class SubscriptionsManager {
|
||||
reason: fallbackReason,
|
||||
});
|
||||
} else if (container) {
|
||||
container.innerHTML =
|
||||
"<p class='text-muted-strong'>Unable to load subscriptions right now.</p>";
|
||||
this._renderStatusMessage(container, "Unable to load subscriptions right now.");
|
||||
}
|
||||
this.hasRenderedOnce = Boolean(container);
|
||||
return this.lastResult;
|
||||
@@ -1904,10 +1899,11 @@ class SubscriptionsManager {
|
||||
|
||||
const listView = this.getListView(container, app);
|
||||
if (!listView) {
|
||||
container.innerHTML = `
|
||||
<p class="flex justify-center items-center h-full w-full text-center text-muted-strong">
|
||||
Unable to render subscriptions feed.
|
||||
</p>`;
|
||||
this._renderStatusMessage(
|
||||
container,
|
||||
"Unable to render subscriptions feed.",
|
||||
"flex justify-center items-center h-full w-full text-center"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1942,7 +1938,7 @@ class SubscriptionsManager {
|
||||
? message.trim()
|
||||
: "No playable subscription videos found yet. We'll keep watching for new posts.";
|
||||
|
||||
container.innerHTML = getSidebarLoadingMarkup(copy, { showSpinner: false });
|
||||
this._renderLoading(container, copy, false);
|
||||
|
||||
if (this.subscriptionListView && this.subscriptionListView.state) {
|
||||
const currentMetadata =
|
||||
@@ -2365,6 +2361,43 @@ class SubscriptionsManager {
|
||||
convertEventToVideo(evt) {
|
||||
return sharedConvertEventToVideo(evt);
|
||||
}
|
||||
|
||||
_renderStatusMessage(container, message, extraClasses = "") {
|
||||
if (!container) return;
|
||||
container.replaceChildren();
|
||||
const p = document.createElement("p");
|
||||
p.className = `text-muted-strong ${extraClasses}`.trim();
|
||||
p.textContent = message;
|
||||
container.appendChild(p);
|
||||
}
|
||||
|
||||
_renderLoading(container, message, showSpinner = true) {
|
||||
if (!container) return;
|
||||
container.replaceChildren();
|
||||
|
||||
const wrapper = document.createElement("div");
|
||||
wrapper.className = "sidebar-loading-wrapper";
|
||||
wrapper.setAttribute("role", "status");
|
||||
wrapper.setAttribute("aria-live", "polite");
|
||||
|
||||
const indicator = document.createElement("div");
|
||||
indicator.className = "sidebar-loading-indicator";
|
||||
|
||||
if (showSpinner) {
|
||||
const spinner = document.createElement("span");
|
||||
spinner.className = "status-spinner status-spinner--inline";
|
||||
spinner.setAttribute("aria-hidden", "true");
|
||||
indicator.appendChild(spinner);
|
||||
}
|
||||
|
||||
const text = document.createElement("span");
|
||||
text.className = "sidebar-loading-text";
|
||||
text.textContent = message;
|
||||
indicator.appendChild(text);
|
||||
|
||||
wrapper.appendChild(indicator);
|
||||
container.appendChild(wrapper);
|
||||
}
|
||||
}
|
||||
|
||||
SubscriptionsManager.listVideoViewEvents = listVideoViewEventsApi;
|
||||
|
||||
@@ -31,7 +31,6 @@ const BASELINE = {
|
||||
"js/historyView.js": 4,
|
||||
"js/index.js": 1,
|
||||
"js/kidsView.js": 1,
|
||||
"js/subscriptions.js": 7,
|
||||
"js/ui/components/DeleteModal.js": 3,
|
||||
"js/ui/components/EditModal.js": 1,
|
||||
"js/ui/components/EmbedVideoModal.js": 1,
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# Test Log
|
||||
|
||||
- **Date:** 2026-02-13
|
||||
- **File:** `js/subscriptions.js`
|
||||
|
||||
## Commands
|
||||
|
||||
### Lint
|
||||
`npm run lint` -> Passed (after `npm ci`).
|
||||
|
||||
### innerHTML Audit
|
||||
`node scripts/check-innerhtml.mjs --report` -> `js/subscriptions.js` removed from list (count 0).
|
||||
|
||||
## Verification
|
||||
- Replaced 7 assignments of `innerHTML` with `_renderStatusMessage` and `_renderLoading`.
|
||||
- These helpers use `replaceChildren()` and `document.createElement()`.
|
||||
- Verified that `getSidebarLoadingMarkup` dependency was removed from the file.
|
||||
@@ -0,0 +1,9 @@
|
||||
# TODO - js/subscriptions.js Migration
|
||||
|
||||
- [ ] Line 1566: `container.innerHTML = "<p class='text-muted-strong'>Please log in first.</p>";`
|
||||
- [ ] Line 1596: `container.innerHTML = "<p class='text-muted-strong'>No subscriptions found.</p>";`
|
||||
- [ ] Line 1609: `container.innerHTML = getSidebarLoadingMarkup("Fetching subscriptions…");`
|
||||
- [ ] Line 1637: `container.innerHTML = "<p class='text-muted-strong'>Subscriptions are unavailable right now.</p>";`
|
||||
- [ ] Line 1717: `container.innerHTML = "<p class='text-muted-strong'>Unable to load subscriptions right now.</p>";`
|
||||
- [ ] Line 1907: `container.innerHTML = ...` (template literal with `p` class `flex justify-center...`)
|
||||
- [ ] Line 1945: `container.innerHTML = getSidebarLoadingMarkup(copy, { showSpinner: false });`
|
||||
Reference in new issue
Block a user