-
Notifications
You must be signed in to change notification settings - Fork 185
feat: refactor countdown update in AFKOverlay #757
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Refactor updateCountdown method to use textContent for countdown updates.
|
lukehb
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have highlighted an issue with the PR that would be need to be addressed before we could accept it.
Additionally, our linter has highlighted some issues that would also need to be addressed.
| */ | ||
| public updateCountdown(countdown: number): void { | ||
| this.textElement.innerHTML = `<center>No activity detected<br>Disconnecting in <span id="afkCountDownNumber">${countdown}</span> seconds<br>Click to continue<br></center>`; | ||
| const countDownSpan = this.textElement.querySelector('#afkCountDownNumber') as HTMLSpanElement | null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Selecting the afkCountDownNumber by its id is problematic as we potentially allow for multiple Pixel Streaming instances on the same page.
Instead, it would be better if the afkCountDownNumber element is actually constructed programmatically and the constructed element was stored as a field in this class. That way no query is required to retrieve it, the field, if it exists, can simply be accessed in this function and have its textContent updated accordingly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The change replaces the previous full innerHTML assignment with a targeted DOM update:
-
Instead of recreating the entire overlay markup on every tick, we query for the existing and update its textContent. This:
- Prevents re-creating DOM nodes (so attached event listeners or state on child elements aren’t lost),
- Avoids flicker/layout churn and is more efficient,
- Eliminates an unnecessary innerHTML write (reducing XSS surface compared to injecting HTML),
- Gracefully no-ops if the span is not found (we intentionally check for null instead of throwing).
-
Type-wise I cast the result as HTMLSpanElement | null to keep TypeScript happy while allowing the null check.
I tested this manually (overlay shows, countdown value updates each second, click-to-continue still works) and saw no regressions. If you prefer, I can:
- Use document.getElementById('afkCountDownNumber') for an even clearer lookup, or
- Add a small unit/DOM test to assert the span's textContent is updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @odaysec,
What Luke's stating is that querying DOM elements by id or class is problematic. This includes document.getElementById().
As he states in his original comment, there could be potentially multiple instances of a PixelStreamingPlayer per web page (see /stresstest.html for an example) which means that all elements must be queried and updated programmatically without querying selectors.
Refactor updateCountdown method to use textContent for countdown updates.
fix unsafe HTML construction, avoid writing untrusted data into
innerHTML. Instead, build the DOM structure usingdocument.createElement, and insert dynamic pieces viatextContent/innerTextor by explicitly setting properties on elements. This prevents the dynamic value from being interpreted as HTML and eliminates the XSS sink.For this specific case, the overlay content is simple and mostly static. The only dynamic part is the numeric countdown. The safest and least intrusive fix is:
<span id="afkCountDownNumber">, is created without dynamic content (this is already done increateContentElement).updateCountdownso it does not rebuild the full HTML string withinnerHTML. Instead, locate the existing<span id="afkCountDownNumber">withinthis.textElementand update itstextContentwith the currentcountdownvalue.Concretely, in
Frontend/ui-library/src/Overlay/AFKOverlay.ts, replace line 47’sinnerHTMLassignment with logic like:const span = this.textElement.querySelector('#afkCountDownNumber') as HTMLSpanElement | null;span.textContent = String(countdown);this.textElement.textContentor do nothing; here, a simple defensive check is enough.No changes are needed in
Frontend/ui-library/src/Application/Application.ts, because after the AFKOverlay is made safe, passingcountDownintoupdateCountdownno longer reaches a dangerous sink.Relevant components: