Add OAuth login support and streamline authentication flows

- Introduced `oauthLogin` method in `electron/preload.ts` and backend IPC handlers for OAuth via `BrowserWindow`.
- Replaced web-based OAuth redirection with Electron-specific implementation for Google, Facebook, and Apple.
- Refactored `SocialForm.tsx` to handle OAuth login success and token management via Electron.
- Updated `User`, `QuillSense`, and context methods to include `quill-trial` subscriptions and extended login logic.
- Cleaned up code, removed unused imports, and improved error handling for authentication scenarios.
This commit is contained in:
natreex
2026-01-08 11:03:19 -05:00
parent 7378d3c1f9
commit 060693f152
8 changed files with 206 additions and 62 deletions

View File

@@ -188,6 +188,114 @@ ipcMain.handle('open-external', async (_event, url: string) => {
}
});
// IPC Handler pour OAuth login via BrowserWindow
let oauthWindow: BrowserWindow | null = null;
interface OAuthResult {
success: boolean;
code?: string;
state?: string;
error?: string;
}
interface OAuthRequest {
provider: 'google' | 'facebook' | 'apple';
baseUrl: string;
}
ipcMain.handle('oauth-login', async (_event, request: OAuthRequest): Promise<OAuthResult> => {
return new Promise((resolve) => {
const { provider, baseUrl } = request;
const redirectUri = `${baseUrl}login?provider=${provider}`;
const encodedRedirectUri = encodeURIComponent(redirectUri);
// Fermer une éventuelle fenêtre OAuth existante
if (oauthWindow) {
oauthWindow.close();
oauthWindow = null;
}
// Configuration OAuth par provider
const oauthConfigs: Record<string, string> = {
google: `https://accounts.google.com/o/oauth2/v2/auth?client_id=911482317931-pvjog1br22r6l8k1afq0ki94em2fsoen.apps.googleusercontent.com&redirect_uri=${encodedRedirectUri}&response_type=code&scope=openid%20email%20profile&access_type=offline`,
facebook: `https://www.facebook.com/v18.0/dialog/oauth?client_id=1015270470233591&redirect_uri=${encodedRedirectUri}&scope=email&response_type=code&state=abc123`,
apple: `https://appleid.apple.com/auth/authorize?client_id=eritors.apple.login&redirect_uri=${encodedRedirectUri}&response_type=code&scope=email%20name&response_mode=query&state=abc123`
};
const authUrl = oauthConfigs[provider];
if (!authUrl) {
resolve({ success: false, error: 'Invalid provider' });
return;
}
oauthWindow = new BrowserWindow({
width: 600,
height: 700,
show: true,
autoHideMenuBar: true,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
}
});
// Intercepter les redirections pour capturer le code OAuth
const handleNavigation = (url: string): boolean => {
try {
const parsedUrl = new URL(url);
// Vérifier si c'est notre redirect URI (compare sans le query string)
const baseRedirectUri = `${baseUrl}login`;
if (url.startsWith(baseRedirectUri)) {
const code = parsedUrl.searchParams.get('code');
const state = parsedUrl.searchParams.get('state');
const error = parsedUrl.searchParams.get('error');
if (error) {
resolve({ success: false, error });
} else if (code) {
resolve({ success: true, code, state: state || undefined });
} else {
resolve({ success: false, error: 'No code received' });
}
if (oauthWindow) {
oauthWindow.close();
oauthWindow = null;
}
return true; // Navigation interceptée
}
} catch (e) {
// URL invalide, continuer
}
return false; // Laisser la navigation continuer
};
// Écouter will-redirect (redirections HTTP)
oauthWindow.webContents.on('will-redirect', (event, url) => {
if (handleNavigation(url)) {
event.preventDefault();
}
});
// Écouter will-navigate (navigations normales)
oauthWindow.webContents.on('will-navigate', (event, url) => {
if (handleNavigation(url)) {
event.preventDefault();
}
});
// Gérer la fermeture de la fenêtre par l'utilisateur
oauthWindow.on('closed', () => {
oauthWindow = null;
resolve({ success: false, error: 'Window closed by user' });
});
// Charger l'URL OAuth
oauthWindow.loadURL(authUrl);
});
});
// IPC Handlers pour la gestion du token (OS-encrypted storage)
ipcMain.handle('get-token', () => {
const storage:SecureStorage = getSecureStorage();

View File

@@ -38,6 +38,10 @@ contextBridge.exposeInMainWorld('electron', {
// Open external links (browser/native app)
openExternal: (url: string) => ipcRenderer.invoke('open-external', url),
// OAuth login via BrowserWindow
oauthLogin: (provider: 'google' | 'facebook' | 'apple', baseUrl: string) =>
ipcRenderer.invoke('oauth-login', { provider, baseUrl }),
// Offline mode management
offlinePinSet: (pin: string) => ipcRenderer.invoke('offline:pin:set', { pin }),
offlinePinVerify: (pin: string) => ipcRenderer.invoke('offline:pin:verify', { pin }),