Skip to content

User Timestamp Parsing#1812

Draft
chenosaurus wants to merge 7 commits intomainfrom
dc/feature/user_timestamp
Draft

User Timestamp Parsing#1812
chenosaurus wants to merge 7 commits intomainfrom
dc/feature/user_timestamp

Conversation

@chenosaurus
Copy link

No description provided.

@changeset-bot
Copy link

changeset-bot bot commented Feb 18, 2026

⚠️ No Changeset found

Latest commit: 7db8729

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

<span id="e2ee-${identity}" class="e2ee-on"></span>
</div>
</div>
<div id="user-ts-${identity}" class="user-ts-overlay">

Check warning

Code scanning / CodeQL

Unsafe HTML constructed from library input Medium

This HTML construction which depends on
library input
might later allow
cross-site scripting
.
This HTML construction which depends on
library input
might later allow
cross-site scripting
.
This HTML construction which depends on
library input
might later allow
cross-site scripting
.
This HTML construction which depends on
library input
might later allow
cross-site scripting
.
This HTML construction which depends on
library input
might later allow
cross-site scripting
.
This HTML construction which depends on
library input
might later allow
cross-site scripting
.
This HTML construction which depends on
library input
might later allow
cross-site scripting
.
This HTML construction which depends on
library input
might later allow
cross-site scripting
.
This HTML construction which depends on
library input
might later allow
cross-site scripting
.
This HTML construction which depends on
library input
might later allow
cross-site scripting
.
This HTML construction which depends on
library input
might later allow
cross-site scripting
.
This HTML construction which depends on
library input
might later allow
cross-site scripting
.
This HTML construction which depends on
library input
might later allow
cross-site scripting
.
This HTML construction which depends on
library input
might later allow
cross-site scripting
.
This HTML construction which depends on
library input
might later allow
cross-site scripting
.
This HTML construction which depends on
library input
might later allow
cross-site scripting
.
This HTML construction which depends on
library input
might later allow
cross-site scripting
.
This HTML construction which depends on
library input
might later allow
cross-site scripting
.
This HTML construction which depends on
library input
might later allow
cross-site scripting
.
This HTML construction which depends on
library input
might later allow
cross-site scripting
.
This HTML construction which depends on
library input
might later allow
cross-site scripting
.
This HTML construction which depends on
library input
might later allow
cross-site scripting
.
This HTML construction which depends on
library input
might later allow
cross-site scripting
.
This HTML construction which depends on
library input
might later allow
cross-site scripting
.
This HTML construction which depends on
library input
might later allow
cross-site scripting
.

Copilot Autofix

AI 13 days ago

General approach: Avoid constructing HTML with untrusted values via innerHTML and instead either (1) construct the DOM tree with document.createElement/appendChild while assigning IDs directly as properties, or (2) sanitize/escape untrusted data before inserting into HTML. Since the only dynamic piece here is identity used for element IDs, the safest, least invasive fix is to build the elements programmatically and assign id/className via DOM properties, which do not interpret the string as HTML.

Best way to fix this case without changing functionality:

  • Replace the block that sets div.innerHTML = \...`` with code that:
    • Creates video, audio, div, span, progress/input elements via document.createElement.
    • Sets id, className, inline style, and other attributes using properties or setAttribute.
    • Uses the existing isLocalParticipant(participant) check to decide whether to append a volume-control <div> with an <input> range or a <progress> element.
  • This preserves all existing element IDs and classes, so the rest of the code that looks them up by ID (#video-${identity}, #user-ts-${identity}, etc.) continues to work.
  • No changes are required in Room.ts, Participant.ts, RemoteParticipant.ts, or LocalParticipant.ts; CodeQL’s taint traces into those files will be cut once the innerHTML sink is removed.

Concretely:

  • In examples/demo/demo.ts, inside renderParticipant, replace lines 833–863 (the template literal assigned to div.innerHTML) with imperative DOM creation code as described above.

No new helper methods or imports are required; we can use the standard DOM API already available.


Suggested changeset 1
examples/demo/demo.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/examples/demo/demo.ts b/examples/demo/demo.ts
--- a/examples/demo/demo.ts
+++ b/examples/demo/demo.ts
@@ -830,37 +830,91 @@
     div = document.createElement('div');
     div.id = `participant-${identity}`;
     div.className = 'participant';
-    div.innerHTML = `
-      <video id="video-${identity}"></video>
-      <audio id="audio-${identity}"></audio>
-      <div class="info-bar">
-        <div id="name-${identity}" class="name">
-        </div>
-        <div style="text-align: center;">
-          <span id="codec-${identity}" class="codec">
-          </span>
-          <span id="size-${identity}" class="size">
-          </span>
-          <span id="bitrate-${identity}" class="bitrate">
-          </span>
-        </div>
-        <div class="right">
-          <span id="signal-${identity}"></span>
-          <span id="mic-${identity}" class="mic-on"></span>
-          <span id="e2ee-${identity}" class="e2ee-on"></span>
-        </div>
-      </div>
-      <div id="user-ts-${identity}" class="user-ts-overlay">
-      </div>
-      ${
-        !isLocalParticipant(participant)
-          ? `<div class="volume-control">
-        <input id="volume-${identity}" type="range" min="0" max="1" step="0.1" value="1" orient="vertical" />
-      </div>`
-          : `<progress id="local-volume" max="1" value="0" />`
-      }
 
-    `;
+    const videoEl = document.createElement('video');
+    videoEl.id = `video-${identity}`;
+    const audioEl = document.createElement('audio');
+    audioEl.id = `audio-${identity}`;
+
+    const infoBar = document.createElement('div');
+    infoBar.className = 'info-bar';
+
+    const nameEl = document.createElement('div');
+    nameEl.id = `name-${identity}`;
+    nameEl.className = 'name';
+    infoBar.appendChild(nameEl);
+
+    const centerInfo = document.createElement('div');
+    centerInfo.style.textAlign = 'center';
+
+    const codecEl = document.createElement('span');
+    codecEl.id = `codec-${identity}`;
+    codecEl.className = 'codec';
+    centerInfo.appendChild(codecEl);
+
+    const sizeElSpan = document.createElement('span');
+    sizeElSpan.id = `size-${identity}`;
+    sizeElSpan.className = 'size';
+    centerInfo.appendChild(sizeElSpan);
+
+    const bitrateEl = document.createElement('span');
+    bitrateEl.id = `bitrate-${identity}`;
+    bitrateEl.className = 'bitrate';
+    centerInfo.appendChild(bitrateEl);
+
+    infoBar.appendChild(centerInfo);
+
+    const rightInfo = document.createElement('div');
+    rightInfo.className = 'right';
+
+    const signalEl = document.createElement('span');
+    signalEl.id = `signal-${identity}`;
+    rightInfo.appendChild(signalEl);
+
+    const micEl = document.createElement('span');
+    micEl.id = `mic-${identity}`;
+    micEl.className = 'mic-on';
+    rightInfo.appendChild(micEl);
+
+    const e2eeEl = document.createElement('span');
+    e2eeEl.id = `e2ee-${identity}`;
+    e2eeEl.className = 'e2ee-on';
+    rightInfo.appendChild(e2eeEl);
+
+    infoBar.appendChild(rightInfo);
+
+    const userTsOverlay = document.createElement('div');
+    userTsOverlay.id = `user-ts-${identity}`;
+    userTsOverlay.className = 'user-ts-overlay';
+
+    div.appendChild(videoEl);
+    div.appendChild(audioEl);
+    div.appendChild(infoBar);
+    div.appendChild(userTsOverlay);
+
+    if (!isLocalParticipant(participant)) {
+      const volumeControl = document.createElement('div');
+      volumeControl.className = 'volume-control';
+
+      const volumeInput = document.createElement('input');
+      volumeInput.id = `volume-${identity}`;
+      volumeInput.type = 'range';
+      volumeInput.min = '0';
+      volumeInput.max = '1';
+      volumeInput.step = '0.1';
+      volumeInput.value = '1';
+      (volumeInput as any).orient = 'vertical';
+
+      volumeControl.appendChild(volumeInput);
+      div.appendChild(volumeControl);
+    } else {
+      const localVolume = document.createElement('progress');
+      localVolume.id = 'local-volume';
+      localVolume.max = 1;
+      localVolume.value = 0;
+      div.appendChild(localVolume);
+    }
+
     container.appendChild(div);
 
     const sizeElm = container.querySelector(`#size-${identity}`);
EOF
Copilot is powered by AI and may make mistakes. Always verify output.
@github-actions
Copy link
Contributor

size-limit report 📦

Path Size
dist/livekit-client.esm.mjs 87.5 KB (+0.84% 🔺)
dist/livekit-client.umd.js 97.96 KB (+0.68% 🔺)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant