78 lines
3.6 KiB
JavaScript
78 lines
3.6 KiB
JavaScript
import {awaitWithAbort} from './abortable.js';
|
||
/**
|
||
* Google ile Giriş — frontend istemcisi (GIS ID-token akışı).
|
||
* Token localStorage'da 'ihaleist_token', kullanıcı 'ihaleist_user' altında saklanır.
|
||
*/
|
||
|
||
const TOKEN_KEY = 'ihaleist_token';
|
||
const USER_KEY = 'ihaleist_user';
|
||
|
||
export function getToken() {
|
||
try { return localStorage.getItem(TOKEN_KEY); } catch { return null; }
|
||
}
|
||
export function getStoredUser() {
|
||
try { return JSON.parse(localStorage.getItem(USER_KEY) || 'null'); } catch { return null; }
|
||
}
|
||
export function setSession(token, user) {
|
||
try {
|
||
localStorage.setItem(TOKEN_KEY, token);
|
||
localStorage.setItem(USER_KEY, JSON.stringify(user));
|
||
} catch { /* yoksay */ }
|
||
}
|
||
export function clearSession() {
|
||
try {
|
||
localStorage.removeItem(TOKEN_KEY);
|
||
localStorage.removeItem(USER_KEY);
|
||
} catch { /* yoksay */ }
|
||
}
|
||
|
||
async function authRequest(url,options={}) {
|
||
const {signal,...requestOptions}=options,controller=new AbortController();
|
||
const cancel=()=>controller.abort(signal.reason);
|
||
if(signal?.aborted)cancel();else signal?.addEventListener('abort',cancel,{once:true});
|
||
let timeout=false;
|
||
const timer=setTimeout(()=>{timeout=true;controller.abort();},30000);
|
||
try{
|
||
controller.signal.throwIfAborted();
|
||
const res=await awaitWithAbort(fetch(url,{...requestOptions,signal:controller.signal}),controller.signal);
|
||
const data=await awaitWithAbort(res.json().catch(error=>{if(res.ok)throw error;return null;}),controller.signal);
|
||
controller.signal.throwIfAborted();
|
||
if(!res.ok){const error=new Error(data?.error || 'Giriş hizmetine ulaşılamadı. Yeniden deneyin.');error.status=res.status;throw error;}
|
||
return data;
|
||
}catch(error){if(timeout)throw new Error('Giriş hizmeti zamanında yanıt vermedi. Yeniden deneyin.');throw error;}
|
||
finally{clearTimeout(timer);signal?.removeEventListener('abort',cancel);}
|
||
}
|
||
export async function getGoogleConfig({signal}={}) {
|
||
const data=await authRequest('/api/auth/google/config',{signal});
|
||
if(!data || !Object.hasOwn(data,'clientId') || (data.clientId!==null&&typeof data.clientId!=='string'))throw new Error('Giriş yapılandırması doğrulanamadı. Yeniden deneyin.');
|
||
return data;
|
||
}
|
||
export async function loginWithGoogle(credential,{signal}={}) {
|
||
const data=await authRequest('/api/auth/google',{method:'POST',signal,headers:{'Content-Type':'application/json'},body:JSON.stringify({credential})});
|
||
if(!data?.success)throw new Error(data?.error || 'Giriş başarısız');
|
||
if(typeof data.token!=='string'||!data.token||typeof data.user?.email!=='string'||!data.user.email)throw new Error('Giriş yanıtı doğrulanamadı.');
|
||
signal?.throwIfAborted();
|
||
setSession(data.token,data.user);
|
||
if(getToken()!==data.token||getStoredUser()?.email!==data.user.email){clearSession();throw new Error('Tarayıcı oturumu saklayamadı. Site depolama iznini kontrol edip tekrar deneyin.');}
|
||
return data.user;
|
||
}
|
||
|
||
// Geçici hizmet hatası oturumu silmez; yalnız açık yetki reddi sona erdirir.
|
||
export async function restoreSession() {
|
||
const token = getToken();
|
||
if (!token) return null;
|
||
try {
|
||
const data = await authRequest('/api/auth/me', { headers: { Authorization: `Bearer ${token}` } });
|
||
if (getToken() !== token) return getStoredUser();
|
||
if (data?.success && typeof data.user?.email === 'string' && data.user.email) {
|
||
setSession(token, data.user);
|
||
return data.user;
|
||
}
|
||
return getStoredUser();
|
||
} catch (error) {
|
||
if (getToken() !== token) return getStoredUser();
|
||
if (error.status === 401 || error.status === 403) { clearSession(); return null; }
|
||
return getStoredUser();
|
||
}
|
||
}
|