refactor: cleanup

This commit is contained in:
zhom
2026-08-24 00:10:37 +04:00
parent c602a1ce0c
commit de88fbbafe
10 changed files with 1250 additions and 167 deletions
+91 -52
View File
@@ -41,6 +41,14 @@ const isFingerprintEditingDisabled = (config: WayfernConfig): boolean => {
return config.randomize_fingerprint_on_launch === true;
};
/** What `generate_sample_fingerprint` returns. Identity fields are null on a
* browser version that predates the Wayfern identity API. */
interface GeneratedFingerprint {
fingerprint: string;
identity_id: string | null;
identity_baseline: string | null;
}
const getCurrentOS = (): WayfernOS => {
if (typeof navigator === "undefined") return "linux";
const platform = navigator.platform.toLowerCase();
@@ -83,12 +91,23 @@ export function WayfernConfigForm({
setIsGeneratingFingerprint(true);
try {
const configJson = JSON.stringify(config);
const result = await invoke<string>("generate_sample_fingerprint", {
browser: profileBrowser ?? "wayfern",
version: profileVersion,
configJson,
});
onConfigChange("fingerprint", result);
const result = await invoke<GeneratedFingerprint>(
"generate_sample_fingerprint",
{
browser: profileBrowser ?? "wayfern",
version: profileVersion,
configJson,
},
);
onConfigChange("fingerprint", result.fingerprint);
// The identity travels with the fingerprint it produced. Storing one
// without the other leaves a device the launch path cannot reproduce, so
// it would be discarded and re-minted on the next launch.
onConfigChange("identity_id", result.identity_id ?? undefined);
onConfigChange(
"identity_baseline",
result.identity_baseline ?? undefined,
);
} catch (error) {
console.error("Failed to generate fingerprint:", error);
} finally {
@@ -171,6 +190,12 @@ export function WayfernConfigForm({
const isEditingDisabled = isFingerprintEditingDisabled(config) || readOnly;
/** For an identity-backed profile these fields have no stored value to show,
* and editing them by hand produces an inconsistent device. Hidden rather
* than rendered blank-and-disabled, because a blank box reads as data loss
* whereas their absence is the truth. */
const isIdentityDerived = config.identity_id != null;
const renderAdvancedForm = () => (
<div className="space-y-6">
{/* Operating System Selection */}
@@ -894,21 +919,23 @@ export function WayfernConfigForm({
</div>
{/* WebGL Parameters (JSON) */}
<div className="space-y-3">
<Label>{t("fingerprint.webglParametersJson")}</Label>
<Textarea
value={fingerprintConfig.webglParameters ?? ""}
onChange={(e) => {
updateFingerprintConfig(
"webglParameters",
e.target.value || undefined,
);
}}
placeholder='{"7936": "Intel", "7937": "Intel(R) HD Graphics"}'
className="font-mono text-sm"
rows={4}
/>
</div>
{!isIdentityDerived && (
<div className="space-y-3">
<Label>{t("fingerprint.webglParametersJson")}</Label>
<Textarea
value={fingerprintConfig.webglParameters ?? ""}
onChange={(e) => {
updateFingerprintConfig(
"webglParameters",
e.target.value || undefined,
);
}}
placeholder='{"7936": "Intel", "7937": "Intel(R) HD Graphics"}'
className="font-mono text-sm"
rows={4}
/>
</div>
)}
{/* Canvas Noise Seed */}
<div className="space-y-3">
@@ -1040,37 +1067,49 @@ export function WayfernConfigForm({
{/* Vendor Info */}
<div className="space-y-3">
<Label>{t("fingerprint.vendorInfo")}</Label>
<div className="grid grid-cols-1 gap-4 @md:grid-cols-2 @2xl:grid-cols-3">
<div className="space-y-2">
<Label htmlFor="vendor">{t("fingerprint.vendor")}</Label>
<Input
id="vendor"
value={fingerprintConfig.vendor ?? ""}
onChange={(e) => {
updateFingerprintConfig(
"vendor",
e.target.value || undefined,
);
}}
placeholder={t("common.placeholders.example", {
value: "Google Inc.",
})}
/>
</div>
<div className="space-y-2">
<Label htmlFor="vendor-sub">{t("fingerprint.vendorSub")}</Label>
<Input
id="vendor-sub"
value={fingerprintConfig.vendorSub ?? ""}
onChange={(e) => {
updateFingerprintConfig(
"vendorSub",
e.target.value || undefined,
);
}}
placeholder=""
/>
</div>
<div
className={
isIdentityDerived
? "grid grid-cols-1 gap-4"
: "grid grid-cols-1 gap-4 @md:grid-cols-2 @2xl:grid-cols-3"
}
>
{!isIdentityDerived && (
<>
<div className="space-y-2">
<Label htmlFor="vendor">{t("fingerprint.vendor")}</Label>
<Input
id="vendor"
value={fingerprintConfig.vendor ?? ""}
onChange={(e) => {
updateFingerprintConfig(
"vendor",
e.target.value || undefined,
);
}}
placeholder={t("common.placeholders.example", {
value: "Google Inc.",
})}
/>
</div>
<div className="space-y-2">
<Label htmlFor="vendor-sub">
{t("fingerprint.vendorSub")}
</Label>
<Input
id="vendor-sub"
value={fingerprintConfig.vendorSub ?? ""}
onChange={(e) => {
updateFingerprintConfig(
"vendorSub",
e.target.value || undefined,
);
}}
placeholder=""
/>
</div>
</>
)}
<div className="space-y-2">
<Label htmlFor="product-sub">
{t("fingerprint.productSub")}
+6 -1
View File
@@ -994,6 +994,7 @@
"autoLocationDescription": "Automatically configure location information based on proxy configuration or your connection if no proxy provided",
"editingDisabledRunning": "Fingerprint editing is disabled because the profile is currently running. Stop the profile to make changes.",
"editingDisabledRandomized": "Fingerprint editing is disabled because random fingerprint generation is enabled. Disable the option above to manually edit the fingerprint configuration.",
"derivedFromIdentity": "Derived from this profile's identity and not editable.",
"advancedWarning": "Warning: Only edit these parameters if you know what you're doing. Incorrect values may break websites, make them detect you, and lead to hard-to-debug bugs.",
"basicWarning": "Warning: Only edit these parameters if you know what you're doing.",
"automatic": "Automatic",
@@ -1977,7 +1978,11 @@
"noE2ePasswordSet": "No end-to-end encryption password is set. Set one before syncing encrypted data.",
"importSourceNotChromium": "This folder is not a Chromium browser profile",
"importSourceNotChromiumNamed": "{{family}} profiles cannot be imported; only Chromium-based browsers are supported",
"importSourceBrowserRunning": "Close {{browser}} first, or choose to import anyway"
"importSourceBrowserRunning": "Close {{browser}} first, or choose to import anyway",
"wayfernFingerprintApplyFailed": "Could not apply this profile's fingerprint, so the browser was not started. {{detail}}",
"wayfernFingerprintGenerationFailed": "Could not create a fingerprint for this profile. {{detail}}",
"wayfernGenerationLimitReached": "The fingerprint generation limit for this account has been reached. New fingerprints are unavailable for up to 24 hours. This limit applies to this computer, not to one profile.",
"wayfernCrossOsRequiresPlan": "This profile claims {{detail}}, which needs a paid plan and an active sign-in. Sign in or switch the profile to your own operating system."
},
"rail": {
"profiles": "Profiles",
+29
View File
@@ -128,6 +128,21 @@ export type BackendErrorCode =
| "COOKIE_BOT_REQUIRES_PROXY"
| "COOKIE_BOT_TOUCH_FINGERPRINT_UNSUPPORTED"
| "FINGERPRINT_EXIT_MISMATCH"
// The launch refuses instead of opening a window on an unmanaged device: a
// silent fallback would leave the user browsing a random fingerprint while
// the UI reported success, which is the worst failure an anti-detect product
// can have. `detail` carries the underlying browser error for support.
| "WAYFERN_FINGERPRINT_APPLY_FAILED"
| "WAYFERN_FINGERPRINT_GENERATION_FAILED"
// Its own code rather than a generation failure: the browser's quota block is
// account-wide and lasts 24 hours, so "try again" is wrong advice, and a user
// whose every profile refuses at once has to be told this is one limit and
// not a broken install.
| "WAYFERN_GENERATION_LIMIT_REACHED"
// A cross-OS claim needs a signed plan token, so an expired or offline
// session cannot apply one. Distinct from the generic apply failure because
// signing in again is the fix; `detail` names the claimed OS.
| "WAYFERN_CROSS_OS_REQUIRES_PLAN"
| "LAUNCH_CONSENT_EXPIRED"
| "VPN_WORKER_START_FAILED"
| "EXIT_PROBE_FAILED"
@@ -472,6 +487,20 @@ export function translateBackendError(t: TFunction, err: unknown): string {
// room for one sentence.
case "FINGERPRINT_EXIT_MISMATCH":
return t("backendErrors.fingerprintExitMismatch");
case "WAYFERN_FINGERPRINT_APPLY_FAILED":
return t("backendErrors.wayfernFingerprintApplyFailed", {
detail: parsed.params?.detail ?? "",
});
case "WAYFERN_FINGERPRINT_GENERATION_FAILED":
return t("backendErrors.wayfernFingerprintGenerationFailed", {
detail: parsed.params?.detail ?? "",
});
case "WAYFERN_GENERATION_LIMIT_REACHED":
return t("backendErrors.wayfernGenerationLimitReached");
case "WAYFERN_CROSS_OS_REQUIRES_PLAN":
return t("backendErrors.wayfernCrossOsRequiresPlan", {
detail: parsed.params?.detail ?? "",
});
case "LAUNCH_CONSENT_EXPIRED":
return t("backendErrors.launchConsentExpired");
case "VPN_WORKER_START_FAILED":
+2
View File
@@ -395,6 +395,8 @@ export interface WayfernConfig {
randomize_fingerprint_on_launch?: boolean; // Generate new fingerprint on every launch
os?: WayfernOS; // Operating system for fingerprint generation
geo_proxy_signature?: string; // Internal: routing the fingerprint's location was computed for
identity_id?: string; // Internal: UUID the device is derived from on browsers with the identity API
identity_baseline?: string; // Internal: derived fingerprint before edits, diffed to recover overrides
}
// Wayfern fingerprint config - matches the C++ FingerprintData structure