Skip to content

Add CSST.at Extension - #207

Open
TOR968 wants to merge 3 commits into
SteamClientHomebrew:mainfrom
TOR968:csst-at-extension
Open

Add CSST.at Extension#207
TOR968 wants to merge 3 commits into
SteamClientHomebrew:mainfrom
TOR968:csst-at-extension

Conversation

@TOR968

@TOR968 TOR968 commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

CSST.at

plugin that injects a csst.at profile button into Steam community profile pages

зображення

Hi @shdwmtr, fair point — the injection setup was a leftover from the period when webkit didn't reach the community browser, and it outlived its purpose. In v1.0.3 the plugin is now plain webkit-only: the CDP path, mode selector and status badge are removed, the backend uses the utils module (get_backend_path, read_file/write_file), there is no raw MILLENNIUM_API access, and the settings panel is a single native ToggleField. The frontend entry is now ~40 lines.

Task Checklist

Developer

  • I am the original author or an authorized maintainer of this plugin.
  • I have complied with all license requirements for the libraries used, including providing appropriate notices where necessary.
  • My plugin is fully open source and does not depend on any external paid services, except for widely trusted and well-known platforms. Additionally, neither I nor anyone associated with me profits from any such services.

Plugin Functionality

  • I have tested the plugin on both the Stable and Beta Steam update channels.
  • My plugin is unique, or provides additional or alternative functionality to plugins already on the store.

Backend Configuration

  • Yes: I use a standard Millennium lua backend in my plugin.
  • No: I use custom binaries that or rely on other FOSS projects that aren't written directly using Millennium's lua backend.

Community Contribution

  • I have tested and left feedback on two other plugin pull requests.
  • I have added links to those feedback comments in this PR.

Testing Instructions

  • Verified by a third party on Steam Client Stable.
  • Verified by a third party on Steam Client Beta.

@github-actions github-actions Bot changed the title Add Csst.at extension Add CSST.at Extension Jul 29, 2026
@shdwmtr
shdwmtr requested a review from Copilot July 30, 2026 00:56

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@MuhammedResulBilkil

Copy link
Copy Markdown

Read the source at the pinned commit aab7491 (v1.0.3), then installed it and ran it on Steam Stable with Millennium. Findings ordered by how much I think each matters.

1. The toggle can end up disagreeing with what's actually stored.

frontend/index.tsx:19-22 sets React state first, then fires saveSettings. In frontend/services/settings.ts:38-45 a failed write restores cachedSettings = previous — but nothing restores the React state, and saveSettings returns Promise<void>, so the caller can't detect the failure either.

I ran that logic verbatim with the backend write forced to return '0':

after failed save -> toggle shows false, cached=true, disk=true
PASS  toggle position diverges from stored value on backend write failure  ui=false stored=true
PASS  reopening the panel silently snaps the toggle back  snaps false -> true

So on a failed write the switch sits where the user put it while the stored value is the old one, and the panel silently reverts next time it mounts. It needs a real write failure to surface, which is why it wouldn't show up in ordinary testing. Returning a boolean, or re-reading getSettings() after the await, closes it.

2. The host check is a substring test on the whole URL.

webkit/index.tsx:4 and webkit/inject.ts:26 both run /steamcommunity\.com\/(id|profiles)\// against location.href. That matches any URL merely containing the string — https://example.com/?u=steamcommunity.com/id/x passes. Testing location.hostname against /(^|\.)steamcommunity\.com$/ is tighter.

3. The SteamID is neither validated nor encoded before it goes into a URL.

getSteamId() (webkit/inject.ts:3-22) returns whatever g_rgProfileData.steamid64 holds, or whatever text sits inside <steamID64> in the fetched XML, with no format check. inject.ts:46 then does 'https://csst.at/profile/' + steamId. On its own that's fine — the source is Steam. It matters in combination with (2): the XML is fetched from location.href, which under that regex need not be a Steam host. A /^\d{17}$/ test plus encodeURIComponent makes both moot. I confirmed the shipped v1.0.3 bundle carries both patterns, not just the repo.

4. Nothing is cleaned up when the plugin is disabled. The anchor, the container div and #csstat-extension-style stay on any page already open. A reload clears it, but someone who toggles the plugin off and looks back at the profile tab they already had open still sees the button.

5. /profiles/{steamid64} does work it doesn't need to. The ID is in the URL, but getSteamId() never looks there — it tries g_rgProfileData, then [data-miniprofile], then a network fetch. Reading the URL first makes the common case free.

6. Trivial. plugin.json's $schema points at .../src/sys/plugin-schema.json, which 404s. The live path is .../src/system/plugin-schema.json. Same in csstats-extension.


What I expected to break and didn't. I went in assuming /id/{vanity} resolution would be the weak point, since the SteamID isn't in that URL. It resolves correctly. On both /profiles/{id} and /id/{vanity} the button injects into .profile_rightcol with the right 17-digit ID in its href, #csstat-extension-style is present, and there were no console errors or warnings from the plugin. g_rgProfileData is populated on both page types, so the XML fallback never ran — which also means the network path in (5) is genuinely rare rather than just theoretically rare.

openExternal defaults to true as the source says, and the rendered href was steam://openurl_external/https://csst.at/profile/<id>, so the Cloudflare workaround the panel describes does what it claims. Worth noting the webkit default and the client default agree (webkit/index.tsx:9 and services/settings.ts:8) — a mismatch there would silently route people to the external browser while the panel said otherwise. And the container div is inserted synchronously before the await, so the duplicate-injection guard actually holds; easy to get backwards.

Tested on Steam Stable, plugin confirmed loaded in PLUGIN_LIST with its settings panel registered.

Disclosure: I have a submission open in this queue, also a CS-stats profile button, so weigh this accordingly.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants