Skip to content

Commit 5ad55e7

Browse files
committed
require join discord server
1 parent daf8875 commit 5ad55e7

File tree

5 files changed

+368
-1
lines changed

5 files changed

+368
-1
lines changed

src/AuthManager.ts

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
import { app, shell, BrowserWindow } from 'electron';
2+
import * as fs from 'fs';
3+
import * as path from 'path';
4+
import axios from 'axios';
5+
import * as http from 'http';
6+
import * as url from 'url';
7+
8+
export class AuthManager {
9+
private tokenPath: string;
10+
private backendUrl: string = 'https://backend-launcher.vercel.app';
11+
private callbackPort: number = 5173;
12+
private authServer: http.Server | null = null;
13+
private mainWindow: BrowserWindow | null = null;
14+
15+
constructor() {
16+
this.tokenPath = path.join(app.getPath('userData'), 'auth.json');
17+
}
18+
19+
setMainWindow(window: BrowserWindow) {
20+
this.mainWindow = window;
21+
}
22+
23+
getToken(): string | null {
24+
try {
25+
if (fs.existsSync(this.tokenPath)) {
26+
const data = JSON.parse(fs.readFileSync(this.tokenPath, 'utf-8'));
27+
return data.token;
28+
}
29+
} catch (error) {
30+
console.error('[AuthManager] Erro ao ler token:', error);
31+
}
32+
return null;
33+
}
34+
35+
saveToken(token: string) {
36+
try {
37+
fs.writeFileSync(this.tokenPath, JSON.stringify({ token }), 'utf-8');
38+
console.log('[AuthManager] Token salvo com sucesso.');
39+
} catch (error) {
40+
console.error('[AuthManager] Erro ao salvar token:', error);
41+
}
42+
}
43+
44+
logout() {
45+
try {
46+
if (fs.existsSync(this.tokenPath)) {
47+
fs.unlinkSync(this.tokenPath);
48+
console.log('[AuthManager] Token removido (logout).');
49+
return true;
50+
}
51+
} catch (error) {
52+
console.error('[AuthManager] Erro ao remover token:', error);
53+
}
54+
return false;
55+
}
56+
57+
async validateToken(): Promise<boolean> {
58+
const token = this.getToken();
59+
if (!token) return false;
60+
61+
try {
62+
const response = await axios.get(`${this.backendUrl}/auth/validate`, {
63+
headers: { Authorization: `Bearer ${token}` }
64+
});
65+
return response.data.valid;
66+
} catch (error) {
67+
console.error('[AuthManager] Token inválido ou erro de conexão:', error);
68+
return false;
69+
}
70+
}
71+
72+
async startLoginFlow() {
73+
// 1. Abrir navegador externo
74+
await shell.openExternal(`${this.backendUrl}/auth/discord`);
75+
76+
// 2. Iniciar servidor local para escutar o callback
77+
this.startLocalServer();
78+
}
79+
80+
private startLocalServer() {
81+
if (this.authServer) {
82+
this.authServer.close();
83+
}
84+
85+
this.authServer = http.createServer((req, res) => {
86+
const parsedUrl = url.parse(req.url || '', true);
87+
88+
// O backend redireciona para /auth-success?token=...
89+
if (parsedUrl.pathname === '/auth-success') {
90+
const token = parsedUrl.query.token as string;
91+
92+
if (token) {
93+
this.saveToken(token);
94+
console.log('[AuthManager] Token recebido via servidor local.');
95+
96+
// Notificar a janela principal para atualizar a UI
97+
if (this.mainWindow) {
98+
this.mainWindow.webContents.send('auth:success');
99+
}
100+
101+
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
102+
const html = `
103+
<!DOCTYPE html>
104+
<html lang="pt-BR">
105+
<head>
106+
<meta charset="UTF-8">
107+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
108+
<title>Login Realizado - Futhero</title>
109+
<style>
110+
body {
111+
background-color: #0a0a0a;
112+
color: white;
113+
font-family: system-ui, -apple-system, sans-serif;
114+
display: flex;
115+
flex-direction: column;
116+
align-items: center;
117+
justify-content: center;
118+
height: 100vh;
119+
margin: 0;
120+
overflow: hidden;
121+
}
122+
.container {
123+
padding: 40px;
124+
background: rgba(255, 255, 255, 0.03);
125+
border-radius: 24px;
126+
border: 1px solid rgba(249, 115, 22, 0.2);
127+
text-align: center;
128+
max-width: 90%;
129+
width: 400px;
130+
box-shadow: 0 0 40px rgba(0,0,0,0.5);
131+
animation: popIn 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
132+
}
133+
h1 { color: #f97316; margin: 20px 0 10px; font-size: 28px; }
134+
p { color: #888; margin-bottom: 20px; line-height: 1.5; }
135+
.icon { font-size: 64px; margin-bottom: 10px; animation: bounce 1s infinite alternate; }
136+
@keyframes popIn { from { transform: scale(0.8); opacity: 0; } to { transform: scale(1); opacity: 1; } }
137+
@keyframes bounce { from { transform: translateY(0); } to { transform: translateY(-10px); } }
138+
</style>
139+
</head>
140+
<body>
141+
<div class="container">
142+
<div class="icon">✨</div>
143+
<h1>Login Concluído!</h1>
144+
<p>Sua autenticação foi realizada com sucesso.</p>
145+
<p style="font-size: 14px;">Você já pode fechar esta aba e voltar para o launcher.</p>
146+
</div>
147+
<script>
148+
// Tenta fechar a janela automaticamente
149+
setTimeout(() => {
150+
window.opener = null;
151+
window.open('', '_self');
152+
window.close();
153+
}, 1500);
154+
</script>
155+
</body>
156+
</html>`;
157+
res.end(html);
158+
159+
// Fechar o servidor após sucesso
160+
this.stopLocalServer();
161+
} else {
162+
res.writeHead(400);
163+
res.end('Token não encontrado.');
164+
}
165+
} else {
166+
res.writeHead(404);
167+
res.end('Not Found');
168+
}
169+
});
170+
171+
this.authServer.listen(this.callbackPort, () => {
172+
console.log(`[AuthManager] Escutando callback na porta ${this.callbackPort}...`);
173+
});
174+
175+
this.authServer.on('error', (err) => {
176+
console.error('[AuthManager] Erro no servidor local:', err);
177+
});
178+
}
179+
180+
private stopLocalServer() {
181+
if (this.authServer) {
182+
this.authServer.close();
183+
this.authServer = null;
184+
console.log('[AuthManager] Servidor local encerrado.');
185+
}
186+
}
187+
}

src/main.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { autoUpdater } from "electron-updater";
66
import { GameManager } from "./handlers/GameManager";
77
import { BonkHandler } from "./handlers/BonkHandler";
88
import { ADS_CONTENT, getRandomAd } from "./types/ads.types";
9+
import { AuthManager } from "./AuthManager";
910

1011
app.commandLine.appendSwitch('no-sandbox');
1112

@@ -36,6 +37,7 @@ console.log(" - Owner: brenoluizdev");
3637
console.log(" - Repo: Futhero-Desktop");
3738

3839
const gameManager = new GameManager();
40+
const authManager = new AuthManager();
3941

4042
let mainWindow: BrowserWindow | null = null;
4143
let joinWindow: BrowserWindow | null = null;
@@ -150,6 +152,8 @@ function createWindow(gameType?: GameType) {
150152
webPreferences: webPrefs,
151153
});
152154

155+
authManager.setMainWindow(mainWindow);
156+
153157
if (!gameType) {
154158
const selectorPath = path.join(__dirname, "pages", "game-selector.html");
155159

@@ -371,8 +375,25 @@ app.whenReady().then(() => {
371375
}
372376
}, 3000);
373377

378+
// Auth IPCs
379+
ipcMain.handle('auth:check', async () => {
380+
return await authManager.validateToken();
381+
});
382+
383+
ipcMain.handle('auth:login', async () => {
384+
await authManager.startLoginFlow();
385+
});
386+
387+
ipcMain.handle('auth:logout', async () => {
388+
return authManager.logout();
389+
});
390+
374391
ipcMain.on("close-window", () => mainWindow?.close());
375392

393+
ipcMain.on('auth:start', () => authManager.startLoginFlow());
394+
ipcMain.handle('auth:logout', () => authManager.logout());
395+
ipcMain.handle('auth:check', () => authManager.validateToken());
396+
376397
ipcMain.on("switch-game", (event, type: string) => {
377398
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
378399
console.log(`[Launcher] 🎮 switch-game recebido: ${type}`);
@@ -696,6 +717,19 @@ app.whenReady().then(() => {
696717
`).catch(error => console.error('[Notification] Erro:', error));
697718
});
698719

720+
// Auth Handlers
721+
ipcMain.on('auth:start', () => {
722+
authManager.startLoginFlow();
723+
});
724+
725+
ipcMain.handle('auth:check', async () => {
726+
return await authManager.validateToken();
727+
});
728+
729+
ipcMain.handle('auth:logout', () => {
730+
return authManager.logout();
731+
});
732+
699733
if (app.isPackaged) {
700734
console.log("[AutoUpdater] App empacotado detectado. Verificando atualizações em 3s...");
701735
setTimeout(() => {

0 commit comments

Comments
 (0)