PageSourceSearch

https://app.refect.app/static/dist-v/1790357571/auth/squareOAuth.js

js refect.app collected 2026-09-28 06:16:09 UTC 3,893 bytes, 94 lines download raw bytes

1import { getStoredSession } from './sessionState.js';
2import { trackOAuthStartIntentThenContinue } from '../marketing/googleAds.js';
3import { trackInstallSquareCtaThenContinue } from '../marketing/googleAds.js';
4const SQUARE_OAUTH_START_ENDPOINT = '/api/business/oauth/square/start';
5/**
6 * Valide un chemin de redirection pour prévenir les open redirects et XSS
7 * SÉCURITÉ: Seuls les chemins relatifs commençant par / sont autorisés
8 */
9function validateRedirectPath(redirectTo) {
10    if (!redirectTo || typeof redirectTo !== 'string') {
11        return null;
12    }
13    const trimmed = redirectTo.trim();
14    // SÉCURITÉ: Rejeter les URLs absolues, javascript:, data:, etc.
15    if (!trimmed.startsWith('/') ||
16        trimmed.startsWith('//') ||
17        trimmed.includes('://') ||
18        trimmed.includes('javascript:') ||
19        trimmed.includes('data:') ||
20        trimmed.includes('<') ||
21        trimmed.includes('>')) {
22        console.warn('[Square OAuth] Chemin de redirection invalide rejeté:', trimmed);
23        return null;
24    }
25    return trimmed;
26}
27/**
28 * Construit l'URL de démarrage OAuth Square (avec query params).
29 */
30function buildSquareOAuthStartUrl(options) {
31    const params = new URLSearchParams();
32    const safeRedirectTo = validateRedirectPath(options.redirectTo);
33    if (safeRedirectTo) {
34        params.set('redirectTo', safeRedirectTo);
35    }
36    if (options.source && ['login', 'register', 'dashboard', 'home', 'landing'].includes(options.source)) {
37        params.set('source', options.source);
38    }
39    const query = params.toString();
40    const targetUrl = query
41        ? `${SQUARE_OAUTH_START_ENDPOINT}?${query}`
42        : SQUARE_OAUTH_START_ENDPOINT;
43    if (!targetUrl.startsWith('/') || targetUrl.startsWith('//')) {
44        throw new Error('URL de redirection invalide');
45    }
46    return targetUrl;
47}
48/**
49 * Récupère le token de session depuis localStorage (session Supabase).
50 * La session est stockée en localStorage ; une simple navigation vers /start n’envoie pas
51 * le token (le serveur ne reçoit que les cookies), donc le serveur ne sait pas que l’utilisateur
52 * est connecté et ne peut pas vérifier « Square déjà connecté » → on envoie toujours vers Square.
53 */
54function getSessionTokenFromStorage() {
55    return getStoredSession()?.access_token ?? null;
56}
57/**
58 * Démarre le flux OAuth Square
59 * SÉCURITÉ: Valide tous les paramètres avant de construire l'URL
60 *
61 * - Si une session existe en localStorage : on appelle /start avec Authorization pour que le serveur
62 *   sache qui on est ; il peut alors skip Square si déjà connecté, ou renvoyer redirectUrl en JSON.
63 *   On navigue vers cette URL (dashboard ou Square). Pas de 302 suivie par fetch (Safari).
64 * - Sinon : navigation directe vers /start (le serveur renverra 302 vers Square).
65 */
66export function startSquareOAuth(options = {}) {
67    const targetUrl = buildSquareOAuthStartUrl(options);
68    const token = getSessionTokenFromStorage();
69    trackInstallSquareCtaThenContinue(() => {
70        trackOAuthStartIntentThenContinue('square', () => {
71            if (token) {
72                fetch(targetUrl, {
73                    method: 'GET',
74                    headers: { Authorization: `Bearer ${token}` },
75                    credentials: 'include',
76                })
77                    .then((res) => res.json())
78                    .then((data) => {
79                    if (typeof data?.redirectUrl === 'string') {
80                        window.location.href = data.redirectUrl;
81                    }
82                    else {
83                        window.location.href = targetUrl;
84                    }
85                })
86                    .catch(() => {
87                    window.location.href = targetUrl;
88                });
89                return;
90            }
91            window.location.href = targetUrl;
92        });
93    });
94}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.