| Age | Commit message (Collapse) | Author |
|
Turn it into the identity function because I completely messed up the
URL highlighting due to replacing the OOC chat lines with plain text
rather than them getting appended to the inner HTML.
|
|
Similar to removal of inline scripts, everything was taken out into the
CSS files, with the same styles applied there directly. This lets us
use `script-src 'self'` in the CSP.
Additionally, serve Golden Layout CSS locally to avoid third-party
connection.
|
|
The next layer after input validaton to achive the paranoid levels of
security. Remove all event handlers inside HTML attributes and add them
in TS for each element, allowing `script-src 'self'` to be used as a CSP
directive.
Buttons that passed some value and had a shared function went into
a global listener with data-action attribute, while all the individual
elements received their own event listener. This is a mess, but my goal
was to end up as close as I could to one-to-one translation of how
functions were originally attached to elements.
|
|
Following the removal of innerHTML manipulation, we no longer need these
sanitization functions.
I've reviewed every safeTags call site to make sure the outputs don't
end up anywhere unsafe, and malicious input can't malipulate DOM or
execute code. These values either end up either as plain text
(textContent, innerText, createTextNode, title, option) or as a URL
path to request assets to the server (encoded using encodeURI).
That is, if safeTags was even effective, considering all that function
did was replace '<' and '>' symbols with Unicode lookalikes. Even the
comment was suggesting the use of fundamentally safer functions instead
of these hacks.
Replace remaining uses of prepChat with unescapeChat as we still need
to do the token substitution (like "<and>" to "&"). decodeChat was
escaping Unicode sequences like \uXXXX, but I don't see the reason for
this, AO2 Client doesn't have this feature, and considering WebSocket
text frames are strictly UTF-8, we don't need these encodings.
|
|
Construct DOM nodes directly instead of trying to sanitize every input
string and dynamically updating HTML.
Replace all uses of innerHTML with textContent, replaceChildren, and
appendChild.
This removes the need to use safeTags and replace newlines, but now
requires preserving whitespace via CSS pre-wrap.
Every OOC chat line is now placed into its own element instead of simply
being appended to the log. This might be worse, and createTextNode
is another alternative.
|
|
Blips aren't handled correctly every time, resulting in a lot of 404
URLs and invalid blips.
|
|
The following packets are unused and have no reason to have handlers:
- CI: character information, unused and handled by SC.
- EI: evidence information, unused and handled by LE.
- EM: area and music information, handled by SM, and obsoleted by
dedicated FA and FM.
- MM: clientside toggle of whether a client is allowed to change music.
The handler doesn't even do anything beyond acknowledging its
existence.
- RMC: plays a music track with an offset. Unused in practice, not
present in AO2 Client.
- ackMS: sent by the server to acknowledge an IC message, a relic from
AO1.
|
|
In an IC message, x and y offsets are separated by an ampersand, which
is unfortunately a conventional separator within packet fields. So, it
looks like `25&10` for x = 25 and y = 10. A consequence of that is you
have to substitute '&' if you actually want to send it. AO does it by
substituting it to `<and>` and back.
The MS handler instead expected it to never be decoded, and instead
assumed `25<and>10`. By the time the MS packet reaches the handler, the
token has already been decoded into '&', however, thus breaking offsets.
|
|
For whatever reason, WebAO decides to normalize almost every string
component in URLs, packets, and INI files to lower case.
First, the glaring issue. In the URLs, this handling of paths is utterly
broken and corrupts data. By mangling characters, you change the
resource identity and break valid URLs. According to section 6.2.2.1 of
RFC 3986 (Case Normalization):
> When a URI uses components of the generic syntax, the component syntax
> equivalence rules always apply; namely, that the scheme and host are
> case-insensitive and therefore should be normalized to lowercase. For
> example, the URI <HTTP://www.EXAMPLE.com/> is equivalent to
> <http://www.example.com/>. The other generic syntax components are
> assumed to be case-sensitive unless specifically defined otherwise by
> the scheme (see Section 6.2.3)
Scheme and host _are_ case-insensitive. Path is _not_, so isn't
everything else. Section 6.2.3 doesn't define any normalization for the
path component in HTTP schemes. Thus, example.com/item and
example.com/Item are two different resources.
I can only think of idiotic conventions of a particular poorly designed
file system when it comes to this absurdity. There's no reason to drag
them around in our developments. For these systems, case doesn't matter
anyway, normalization is their job, not server hosts' who end up having
to either rewrite every URL request for every asset, or mangle their
asset directory and then rewrite almost every INI config (and spam
"showname=Name" everywhere because now your character directory has to
be "name").
So, instead of using absurd ad-hoc solutions to a broken implementation
such as forcing everything to lower case on the server side, this commit
attempts to fix the root issue and make URL handling conformant to
relevant standards.
Similar situation with strings within packets, although not as severe
in practice. Case must be preserved, otherwise it's corrupting data for
no reason. If a normalization is needed, it should be done at the call
site of whatever requires it (like a filtering function), not by the
parser.
As for the INI, it's opinionated. While the values absolutely must not
be normalized, a case can be made for keys and section names: why not
allow "Options", "options", or even "oPtiOnS"? It's more convenient, and
corresponds to the platform quirk of Windows (which Qt unfortunately
inherits in AO2 Client). I don't think there's a good reason to allow
such leniency in parsing, and removing superfluous normalization is a
better move: less data transformations, less ambiguity, more strictness.
In practice, INIs tend to be well-formed, and it's good discipline to
write them this way.
In several places, the case-folding does make sense: callwords,
OOC commands, CSS class names for areas, and character list filters.
These will behave weirdly and inconveniently without it. In most places,
however, it only causes unnecessary breakage.
|
|
If there's no sound section in the INI, that means no sounds are
intended for the character, no need to warn us for that.
|
|
|
|
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
|
|
|
|
|
|
|
|
Better charloading
|
|
Instead of probing extensions for every emote button (N*M HEAD requests),
probe once using button1_off and reuse the result for all buttons.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
|
handlePR and handlePU now only update client.playerlist state,
and renderPlayerList handles all DOM rendering from that state.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
|
setAOhost now returns the current AO_HOST so handleASS can use the
freshly set value rather than the import captured before the update.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
|
PR/PU packets arrive before the ASS packet, so playerlist icon srcs
were set with the default AO_HOST. Now handleASS re-applies the
correct asset URL to existing playerlist images after AO_HOST updates.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
|
Store player data (charId, area) in an in-memory Map on the client,
updated by PR/PU packet handlers. Use this to eagerly load char.ini
when a player's character appears in our area or when switching areas,
eliminating the lazy-load delay on first IC message.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
|
Instead of hardcoding .png, read the preferred extension from
client.charicon_extensions[0] (populated via extensions.json),
falling back to .png if unavailable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
|
Browsers reject .play() with a DOMException when the user hasn't
interacted with the document yet. Add .catch(() => {}) to all 9
play() call sites to suppress the uncaught promise rejection.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
|
Instead of eagerly fetching char_icon (with HEAD requests per extension)
and char.ini for every character on join, set img.src directly to
char_icon.png and defer char.ini loading until actually needed (character
selection via handlePV, or first IC message via handleMS). This
eliminates thousands of HTTP requests on join for large character lists.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
|
|
|
See https://github.com/AttorneyOnline/AO2-Client/blob/54afceec66744e758595e6a4e9bd861523f5b016/src/widgets/playerlistwidget.cpp#L207
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fix #263
|
|
|
|
|
|
|
|
|
|
plan is to migrate to createTextNode
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|