chore(history): squash 100 commit(s) from 2026-09-24

- fix(backend): case-insensitive unique email, revoke PUBLIC schema access, pin Argon2id params
- test(backend): assert password length cap boundary (256 ok, 257 rejected)
- docs(backend): plan — typed JWT token kinds so refresh/device tokens cannot pass as access tokens
- feat(backend): JWT access/refresh token issue and verify
- feat(backend): accounts repository (create/find_by_email/find_by_id)
- refactor(gui): LoVisualAddonManagerScreen 989→10 файлов addon/ (8.5.2)
- docs(backend): plan — fix sqlx::migrate! path in integration tests
- feat(backend): POST /auth/register and /auth/login
- refactor(settings): SettingsPanelComponent 715→81 + 6 helpers (8.5.2)
- docs(backend): plan — harden device flow (single-use codes, bounded store, 404/429)
- feat(backend): OAuth device authorization grant for mod login
- fix(backend): first confirm wins for device codes
- docs(backend): plan — split Task 8 (refactor) and Task 9 (avatars), harden avatar handling
- refactor(mixins): LocalPlayerMixin 691→111 + 4 handlers (8.5.2)
- refactor(visuals): Trails 687→130 (8.5.2)
- refactor(render): ItemBatchRenderer 677->100 (8.5.2)
- refactor(visuals): ReimaginedVisual 674→118 + 5 helpers (8.5.2)
- refactor(config): ConfigSerializer 668→91 + 4 helpers (8.5.2)
- refactor(hud): DynamicIsland 661→158 + 4 helpers (8.5.2)
- refactor(render): GlStencilFramebufferSupport 666→169 (8.5.2)
- refactor(gui): MenuScreen 669→128 + 4 helpers (8.5.2)
- refactor(render): UiStyle 644→170 + 3 helpers (8.5.2)
- refactor(gui): ModuleComponent 613→98 + 4 helpers (8.5.2)
- refactor(media): MediaSessionService 616→200 + 4 helpers (8.5.2)
- refactor(gui): RelationsComponent 661→59 + 4 helpers (8.5.2)
- chore(license): strip GPL file headers from all Java sources
- refactor(aiming): PointTracker 583→168 + 2 helpers (8.5.2)
- refactor(gui): LoVisualProxyManagerScreen 591→132 + 2 helpers (8.5.2)
- refactor(visuals): KillEffect 588→96 + 4 helpers (8.5.2)
- refactor(render): MeshBuilder +4 helpers (8.5.2)
- refactor(visuals): extract WorldParticlesRender helper (8.5.2)
- refactor(world): ExplosionDamageUtil 551→116 + 2 helpers (8.5.2)
- refactor(visuals): TazikHat 596->179 + Model + Palette in hats/tazik (8.5.2)
- chore(license): strip GPL header from remaining 30 files and make strip script variant-aware
- refactor(gui): ThemeComponent 561->166 + CardRenderer + ScrollState (8.5.2)
- refactor(hud): CustomHotbar 556→178 + Renderer + Selection + SelectionGradient (8.5.2)
- refactor(gui): ThemeCardRenderer perf + readability polish
- refactor(clickgui): CooldownRulesSetting 596->198 + Editor + DetailRenderer (8.5.2)
- refactor(hud): HudNotifier 561->200 + Painter + runtime/HudNotifierRuntime (8.5.2)
- refactor(theme): Themes 555->168 + impl/Transition + impl/Blending + impl/ProfileCodec (8.5.2)
- refactor(theme): EditableClickGuiTheme 205->185 + JavaDoc (8.5.2)
- refactor(theme): ThemeStore 491->128 + store/ThemeStoreJson + store/ThemeStoreIO (8.5.2)
- refactor(clickgui): ClickGuiRenderer 604->200 compacted one-line delegators + JavaDoc (8.5.2)
- refactor(mainmenu): LoVisualMainMenuScreen 551->161 + impl/Painter + impl/Renderer + impl/TextUtil (8.5.2)
- refactor(clickgui): ClickGuiTextEditorState 531->187 + impl/EditorCaret + impl/EditorPainter (8.5.2)
- refactor(tab): TabListModel 525->139 + model/Collector + model/Reader + model/Signature + model/TextSplitter (8.5.2)
- refactor(backend): shared bearer helper and test helpers, build_app takes Config, validate JWT secret strength
- refactor(module): ModuleManager 521->198 + impl/Registrar + impl/Dispatcher (8.5.2)
- feat(backend): avatar upload with decode, square crop, PNG re-encode and S3 storage
- refactor(clip): ClipFunction 512->146 + impl/Geometry + impl/Debug (8.5.2)
- docs(backend): implementation plans for gateway (auth hardening, gRPC, rate limits) and configs-service
- refactor(iris-patch): ShaderPatchEngine 499->146 + impl/Repo (8.5.2)
- chore(frontend): add router, react-query, fonts and vitest; dev proxy to gateway
- refactor(hud): ScriptedListHudPanel 499->158 + panel/Props + panel/Signature (8.5.2)
- refactor(hud): BaseHudElement 499->199 + impl/Registry + impl/Namer + impl/Prewarm (8.5.2)
- refactor(clickgui): Setting 498->170 + impl/Localization + impl/I18n (8.5.2)
- refact(viewmodel): split swing animations into camera/swing package
- refact(kineticlyrics): split module into stage, playback and modes
- rename(holeesp): module HoleESP -> CrystalHoles
- refact(crystalholes): split module into crystal scanner, renderer and safety
- refact(addonmanager): split manager into lifecycle, runtime, descriptors and profiles
- refact(accountconfig): split config into store, session and value helpers
- refactor(render): CustomTextRenderer 229->195, extract glyph-pass into GradientTexts helper
- docs(TODO): mark AddonManager split done; close 9.2 refactor gate
- refactor(media): LinuxMediaSession 441->148, split reader + track/seek state
- refactor(nametags): split NameTags into facade + impl helpers
- refactor(clickgui): split MainSettingsComponent into facade + scroll + model
- refactor(hud): split CustomBar into facade, model and BarSettings
- docs(frontend): implementation plan with design system from the mod theme
- feat(frontend): design tokens from the mod theme, fonts and shared UI kit
- fix(accounts): run migrations on startup, offload Argon2, validate register input, JSON error shape
- docs(gateway): plan note on splitting auth handlers before refresh endpoints
- feat(frontend): API client with silent refresh, error descriptions and test helpers
- style(mod): group compact one-line bulk query methods in ModuleManager
- feat(frontend): session restore, login and registration with client-side validation
- refactor(hud): split CustomHealthBar into facade + painter + script renderer
- docs(mod): record the 2026-09-24 HUD/settings split wave in TODO phase 8.5
- refactor(rhi): split GlStencilShapeClipBackend into facade + native-state + pass-lifecycle helpers
- refactor(rhi): split VulkanRenderStateBridge into facade + MSAA and stencil state helpers
- refactor(backtrack): split BacktrackController into facade + model + impl helpers
- refactor(svg): split SvgPathParser into facade + arc geometry + command/curve helpers
- refactor(mixin): split ClientPacketListenerMixin into hook-only mixin + handlers
- refactor(renderer3d): un-nest batch bindings + culling into sibling impl types
- refactor(renderwarp): extract static factories + geometry into impl helpers
- feat(backend): add common crate with shared JWT, internal gateway contract and accounts proto
- refactor(guimixin): move hook bodies into handlers, keep mixin as hooks + shadows
- feat(accounts): accept only gateway traffic, read identity from gateway header
- refactor(cacheduiscriptruntime): extract engine, hashing and frame stats into impl
- refactor(customskyboxrenderer): extract projection, shader passes and sun into impl
- refactor(betterchatstoremanager): extract persistence, key/path and hover helpers into impl
- feat(accounts): rotating opaque refresh tokens in httpOnly cookie, /auth/refresh and /auth/logout
- refactor(targetesp): extract crystal rendering subsystem into impl/TargetEspCrystalRenderer
- refactor(betterchathovercache): extract disk codec and lookup indexing into impl/ChatHoverCacheCodec
- refactor(microsoftauth): split HTTP transport, device-code and Xbox flows into impl/
- refactor(pvpcooldowns): extract local item-rule engine and defaults into impl/PvpCooldownRules
- refactor(lovisual): extract HUD/world render orchestration into HudRender helper
- refactor(statuseffectheuristics): extract palette/inference into ParticlePalette and color utils into ParticleColors
- refactor(dropesp): extract overlay/label render subsystem into impl/DropEspOverlayRenderer
- refactor(proxy): extract SOCKS handshake message builders into ProxyProtocolMessages
- refactor(eagleutil): promote EdgeRecovery controller and RecoveryMode to top-level class
This commit is contained in:
loki5512344 2026-09-24 23:52:12 +02:00
parent 9d08fa910a
commit 72bc4c7148
1897 changed files with 36199 additions and 39289 deletions

View file

@ -1,10 +1,3 @@
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
package dev.loki.lovisual.util.proxy;
import dev.loki.lovisual.util.proxy.model.ProxyConfig;
import dev.loki.lovisual.util.proxy.model.ProxyEntry;

View file

@ -1,10 +1,3 @@
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
package dev.loki.lovisual.util.proxy;
import dev.loki.lovisual.util.proxy.model.ProxyEntry;
@ -15,12 +8,8 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.util.ReferenceCountUtil;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
public final class ProxyHandshakeHandler extends ChannelDuplexHandler {
@ -105,11 +94,11 @@ public final class ProxyHandshakeHandler extends ChannelDuplexHandler {
switch (proxy.type()) {
case SOCKS4 -> {
state = State.SOCKS4_RESPONSE;
ctx.writeAndFlush(createSocks4ConnectRequest(ctx));
ctx.writeAndFlush(ProxyProtocolMessages.socks4ConnectRequest(ctx, proxy, targetAddress));
}
case SOCKS5 -> {
state = State.SOCKS5_METHOD;
ctx.writeAndFlush(createSocks5Greeting(ctx));
ctx.writeAndFlush(ProxyProtocolMessages.greeting(ctx, proxy));
}
}
} catch (Throwable t) {
@ -145,10 +134,10 @@ public final class ProxyHandshakeHandler extends ChannelDuplexHandler {
}
if (method == 0x02) {
state = State.SOCKS5_AUTH;
ctx.writeAndFlush(createSocks5AuthRequest(ctx));
ctx.writeAndFlush(ProxyProtocolMessages.authRequest(ctx, proxy));
} else if (method == 0x00) {
state = State.SOCKS5_CONNECT;
ctx.writeAndFlush(createSocks5ConnectRequest(ctx));
ctx.writeAndFlush(ProxyProtocolMessages.socks5ConnectRequest(ctx, targetAddress));
} else {
throw new IllegalStateException("Unsupported SOCKS5 auth method: " + method);
}
@ -162,7 +151,7 @@ public final class ProxyHandshakeHandler extends ChannelDuplexHandler {
throw new IllegalStateException("SOCKS5 authentication failed: " + status);
}
state = State.SOCKS5_CONNECT;
ctx.writeAndFlush(createSocks5ConnectRequest(ctx));
ctx.writeAndFlush(ProxyProtocolMessages.socks5ConnectRequest(ctx, targetAddress));
again = inbound.isReadable();
}
case SOCKS5_CONNECT -> {
@ -217,91 +206,6 @@ public final class ProxyHandshakeHandler extends ChannelDuplexHandler {
return true;
}
private ByteBuf createSocks5Greeting(ChannelHandlerContext ctx) {
ByteBuf out = ctx.alloc().buffer(3);
out.writeByte(5);
out.writeByte(1);
out.writeByte(proxy.hasCredentials() ? 0x02 : 0x00);
return out;
}
private ByteBuf createSocks5AuthRequest(ChannelHandlerContext ctx) {
byte[] username = ascii(proxy.username());
byte[] password = ascii(proxy.password());
if (username.length > 255 || password.length > 255) {
throw new IllegalArgumentException("SOCKS5 username/password is too long");
}
ByteBuf out = ctx.alloc().buffer(3 + username.length + password.length);
out.writeByte(1);
out.writeByte(username.length);
out.writeBytes(username);
out.writeByte(password.length);
out.writeBytes(password);
return out;
}
private ByteBuf createSocks5ConnectRequest(ChannelHandlerContext ctx) {
ByteBuf out = ctx.alloc().buffer(32);
out.writeByte(5);
out.writeByte(1);
out.writeByte(0);
writeSocks5Address(out, targetAddress);
out.writeShort(targetAddress.getPort());
return out;
}
private ByteBuf createSocks4ConnectRequest(ChannelHandlerContext ctx) {
ByteBuf out = ctx.alloc().buffer(64);
out.writeByte(4);
out.writeByte(1);
out.writeShort(targetAddress.getPort());
InetAddress address = targetAddress.getAddress();
boolean ipv4 = address instanceof Inet4Address;
if (ipv4) {
out.writeBytes(address.getAddress());
} else {
out.writeByte(0);
out.writeByte(0);
out.writeByte(0);
out.writeByte(1);
}
if (proxy.hasUsername()) {
out.writeBytes(ascii(proxy.username()));
}
out.writeByte(0);
if (!ipv4) {
out.writeBytes(ascii(targetAddress.getHostString()));
out.writeByte(0);
}
return out;
}
private static void writeSocks5Address(ByteBuf out, InetSocketAddress address) {
InetAddress inetAddress = address.getAddress();
if (inetAddress instanceof Inet4Address) {
out.writeByte(1);
out.writeBytes(inetAddress.getAddress());
return;
}
if (inetAddress instanceof Inet6Address) {
out.writeByte(4);
out.writeBytes(inetAddress.getAddress());
return;
}
byte[] host = ascii(address.getHostString());
if (host.length > 255) {
throw new IllegalArgumentException("SOCKS5 host is too long: " + address.getHostString());
}
out.writeByte(3);
out.writeByte(host.length);
out.writeBytes(host);
}
private void finish(ChannelHandlerContext ctx) {
state = State.DONE;
@ -343,10 +247,6 @@ public final class ProxyHandshakeHandler extends ChannelDuplexHandler {
}
}
private static byte[] ascii(String value) {
return (value == null ? "" : value).getBytes(StandardCharsets.US_ASCII);
}
private enum State {
INIT,
SOCKS4_RESPONSE,

View file

@ -1,10 +1,3 @@
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
package dev.loki.lovisual.util.proxy;
import dev.loki.lovisual.util.proxy.model.ProxyEntry;

View file

@ -0,0 +1,111 @@
package dev.loki.lovisual.util.proxy;
import dev.loki.lovisual.util.proxy.model.ProxyEntry;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
/**
* Outbound SOCKS4/SOCKS5 handshake message encoders used by {@link ProxyHandshakeHandler}. These are
* pure {@link ByteBuf} builders that read only the resolved {@link ProxyEntry} credentials and the
* target address handed in by the handler, keeping behaviour identical to the original inlined
* request-creation methods.
*/
final class ProxyProtocolMessages {
private ProxyProtocolMessages() {
}
static ByteBuf greeting(ChannelHandlerContext ctx, ProxyEntry proxy) {
ByteBuf out = ctx.alloc().buffer(3);
out.writeByte(5);
out.writeByte(1);
out.writeByte(proxy.hasCredentials() ? 0x02 : 0x00);
return out;
}
static ByteBuf authRequest(ChannelHandlerContext ctx, ProxyEntry proxy) {
byte[] username = ascii(proxy.username());
byte[] password = ascii(proxy.password());
if (username.length > 255 || password.length > 255) {
throw new IllegalArgumentException("SOCKS5 username/password is too long");
}
ByteBuf out = ctx.alloc().buffer(3 + username.length + password.length);
out.writeByte(1);
out.writeByte(username.length);
out.writeBytes(username);
out.writeByte(password.length);
out.writeBytes(password);
return out;
}
static ByteBuf socks5ConnectRequest(ChannelHandlerContext ctx, InetSocketAddress target) {
ByteBuf out = ctx.alloc().buffer(32);
out.writeByte(5);
out.writeByte(1);
out.writeByte(0);
writeSocks5Address(out, target);
out.writeShort(target.getPort());
return out;
}
static ByteBuf socks4ConnectRequest(ChannelHandlerContext ctx, ProxyEntry proxy, InetSocketAddress target) {
ByteBuf out = ctx.alloc().buffer(64);
out.writeByte(4);
out.writeByte(1);
out.writeShort(target.getPort());
InetAddress address = target.getAddress();
boolean ipv4 = address instanceof Inet4Address;
if (ipv4) {
out.writeBytes(address.getAddress());
} else {
out.writeByte(0);
out.writeByte(0);
out.writeByte(0);
out.writeByte(1);
}
if (proxy.hasUsername()) {
out.writeBytes(ascii(proxy.username()));
}
out.writeByte(0);
if (!ipv4) {
out.writeBytes(ascii(target.getHostString()));
out.writeByte(0);
}
return out;
}
private static void writeSocks5Address(ByteBuf out, InetSocketAddress address) {
InetAddress inetAddress = address.getAddress();
if (inetAddress instanceof Inet4Address) {
out.writeByte(1);
out.writeBytes(inetAddress.getAddress());
return;
}
if (inetAddress instanceof Inet6Address) {
out.writeByte(4);
out.writeBytes(inetAddress.getAddress());
return;
}
byte[] host = ascii(address.getHostString());
if (host.length > 255) {
throw new IllegalArgumentException("SOCKS5 host is too long: " + address.getHostString());
}
out.writeByte(3);
out.writeByte(host.length);
out.writeBytes(host);
}
private static byte[] ascii(String value) {
return (value == null ? "" : value).getBytes(StandardCharsets.US_ASCII);
}
}

View file

@ -1,10 +1,3 @@
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
package dev.loki.lovisual.util.proxy.model;
import com.google.gson.Gson;

View file

@ -1,10 +1,3 @@
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
package dev.loki.lovisual.util.proxy.model;
import java.net.InetSocketAddress;

View file

@ -1,10 +1,3 @@
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
package dev.loki.lovisual.util.proxy.model;
import com.google.gson.annotations.SerializedName;