mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-05 09:32:06 +00:00
Update MultiTabDetector.ts (#588)
## Description: Replaced the original focus/visibility-based MultiTabDetector implementation with a lock-based system using localStorage to reliably prevent multitabbing in OpenFront. The new system enforces a single active tab per browser instance by using a unique tabId and a shared lock key with periodic heartbeats. This eliminates race conditions, prevents event-hook tampering, and avoids fingerprinting while maintaining compatibility with existing punishment callbacks and UI warnings. ## Please complete the following: - [X] I have added screenshots for all UI updates - [X] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced - [X] I understand that submitting code with bugs that could have been caught through manual testing blocks releases and new features for all contributors ## Please put your Discord username so you can be contacted if a bug or regression is found: Lucas --------- Co-authored-by: evan <openfrontio@gmail.com>
This commit is contained in:
@@ -15,6 +15,9 @@ export class MultiTabModal extends LitElement implements Layer {
|
||||
@property({ type: Number }) duration: number = 5000;
|
||||
@state() private countdown: number = 5;
|
||||
@state() private isVisible: boolean = false;
|
||||
@state() private fakeIp: string = "";
|
||||
@state() private deviceFingerprint: string = "";
|
||||
@state() private reported: boolean = true;
|
||||
|
||||
private intervalId?: number;
|
||||
|
||||
@@ -38,6 +41,26 @@ export class MultiTabModal extends LitElement implements Layer {
|
||||
}
|
||||
}
|
||||
|
||||
init() {
|
||||
this.fakeIp = this.generateFakeIp();
|
||||
this.deviceFingerprint = this.generateDeviceFingerprint();
|
||||
this.reported = true;
|
||||
}
|
||||
|
||||
// Generate fake IP in format xxx.xxx.xxx.xxx
|
||||
private generateFakeIp(): string {
|
||||
return Array.from({ length: 4 }, () =>
|
||||
Math.floor(Math.random() * 255),
|
||||
).join(".");
|
||||
}
|
||||
|
||||
// Generate fake device fingerprint (32 character hex)
|
||||
private generateDeviceFingerprint(): string {
|
||||
return Array.from({ length: 32 }, () =>
|
||||
Math.floor(Math.random() * 16).toString(16),
|
||||
).join("");
|
||||
}
|
||||
|
||||
// Show the modal with penalty information
|
||||
public show(duration: number): void {
|
||||
if (!this.game.myPlayer()?.isAlive()) {
|
||||
@@ -98,14 +121,44 @@ export class MultiTabModal extends LitElement implements Layer {
|
||||
<div
|
||||
class="relative p-6 bg-white dark:bg-gray-800 rounded-xl shadow-xl max-w-md w-full m-4 transition-all transform"
|
||||
>
|
||||
<h2 class="text-2xl font-bold mb-4 text-red-600 dark:text-red-400">
|
||||
${translateText("multi_tab.warning")}
|
||||
</h2>
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="text-2xl font-bold text-red-600 dark:text-red-400">
|
||||
${translateText("multi_tab.warning")}
|
||||
</h2>
|
||||
<div
|
||||
class="px-2 py-1 bg-red-600 text-white text-xs font-bold rounded-full animate-pulse"
|
||||
>
|
||||
RECORDING
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="mb-4 text-gray-800 dark:text-gray-200">
|
||||
${translateText("multi_tab.detected")}
|
||||
</p>
|
||||
|
||||
<div
|
||||
class="mb-4 p-3 bg-gray-100 dark:bg-gray-900 rounded-md text-sm font-mono"
|
||||
>
|
||||
<div class="flex justify-between mb-1">
|
||||
<span class="text-gray-500 dark:text-gray-400">IP:</span>
|
||||
<span class="text-red-600 dark:text-red-400">${this.fakeIp}</span>
|
||||
</div>
|
||||
<div class="flex justify-between mb-1">
|
||||
<span class="text-gray-500 dark:text-gray-400"
|
||||
>Device Fingerprint:</span
|
||||
>
|
||||
<span class="text-red-600 dark:text-red-400"
|
||||
>${this.deviceFingerprint}</span
|
||||
>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-500 dark:text-gray-400">Reported:</span>
|
||||
<span class="text-red-600 dark:text-red-400"
|
||||
>${this.reported ? "TRUE" : "FALSE"}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="mb-4 text-gray-800 dark:text-gray-200">
|
||||
${translateText("multi_tab.please_wait")}
|
||||
<span class="font-bold text-xl">${this.countdown}</span>
|
||||
@@ -124,6 +177,10 @@ export class MultiTabModal extends LitElement implements Layer {
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">
|
||||
${translateText("multi_tab.explanation")}
|
||||
</p>
|
||||
|
||||
<p class="mt-3 text-xs text-red-500 font-semibold">
|
||||
Repeated violations may result in permanent account suspension.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user