Spaces:
Sleeping
Sleeping
| import { useCallback, useEffect, useState } from 'react'; | |
| import { DRIVE_READONLY_SCOPE, GOOGLE_CLIENT_ID } from './config.js'; | |
| function decodeJwtPayload(token) { | |
| try { | |
| const payload = token.split('.')[1]; | |
| const normalized = payload.replace(/-/g, '+').replace(/_/g, '/'); | |
| const json = decodeURIComponent( | |
| window | |
| .atob(normalized) | |
| .split('') | |
| .map((char) => `%${`00${char.charCodeAt(0).toString(16)}`.slice(-2)}`) | |
| .join(''), | |
| ); | |
| return JSON.parse(json); | |
| } catch { | |
| return null; | |
| } | |
| } | |
| function createNonce() { | |
| const bytes = new Uint8Array(16); | |
| window.crypto.getRandomValues(bytes); | |
| return Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join(''); | |
| } | |
| export function useGoogleDriveAuth() { | |
| const [idToken, setIdToken] = useState(''); | |
| const [accessToken, setAccessToken] = useState(''); | |
| const [user, setUser] = useState(null); | |
| const [authReady, setAuthReady] = useState(Boolean(GOOGLE_CLIENT_ID)); | |
| const [authError, setAuthError] = useState(''); | |
| useEffect(() => { | |
| if (!GOOGLE_CLIENT_ID) { | |
| setAuthError('GOOGLE_CLIENT_ID is not configured.'); | |
| return; | |
| } | |
| const hashParams = new URLSearchParams(window.location.hash.slice(1)); | |
| const tokenFromHash = hashParams.get('access_token'); | |
| const idTokenFromHash = hashParams.get('id_token'); | |
| const errorFromHash = hashParams.get('error'); | |
| if (errorFromHash) { | |
| setAuthError(errorFromHash); | |
| window.history.replaceState(null, '', window.location.pathname + window.location.search); | |
| return; | |
| } | |
| if (tokenFromHash && idTokenFromHash) { | |
| setAuthError(''); | |
| setAccessToken(tokenFromHash); | |
| setIdToken(idTokenFromHash); | |
| setUser(decodeJwtPayload(idTokenFromHash)); | |
| window.history.replaceState(null, '', window.location.pathname + window.location.search); | |
| } | |
| }, []); | |
| const signIn = useCallback(() => { | |
| if (!GOOGLE_CLIENT_ID) return; | |
| const params = new URLSearchParams({ | |
| client_id: GOOGLE_CLIENT_ID, | |
| redirect_uri: `${window.location.origin}/`, | |
| response_type: 'token id_token', | |
| scope: `openid email profile ${DRIVE_READONLY_SCOPE}`, | |
| include_granted_scopes: 'true', | |
| prompt: accessToken && idToken ? '' : 'consent', | |
| nonce: createNonce(), | |
| hd: 'baby-helmet.com', | |
| }); | |
| window.location.assign(`https://accounts.google.com/o/oauth2/v2/auth?${params}`); | |
| }, [accessToken, idToken]); | |
| const signOut = useCallback(() => { | |
| setAccessToken(''); | |
| setIdToken(''); | |
| setUser(null); | |
| }, []); | |
| return { | |
| idToken, | |
| accessToken, | |
| user, | |
| authReady, | |
| authError, | |
| signIn, | |
| signOut, | |
| }; | |
| } | |