UNPKG

supakit

Version:

A Supabase auth helper for SvelteKit.

120 lines (119 loc) 4.18 kB
import { getSupabaseLoadClientCookieOptions } from './config/index.js'; import { error, json, text } from '@sveltejs/kit'; const regexs = { code_verifier: /^.*-code-verifier$/, csrf: /^.*-csrf$/, remember_me: /^supakit-rememberme$/, auth_token: /^sb-.*-auth-token$/, provider_token: /^sb-provider.*token$/ }; export const browserEnv = () => typeof document !== 'undefined'; export const getCookieOptions = (type, options) => { const { name, ...rest_cookie_options } = options; const remember_me_cookie_options = { ...rest_cookie_options, httpOnly: false, maxAge: 60 * 60 * 24 * 365 * 100 }; const { expires, maxAge, ...session_cookie_options } = rest_cookie_options; const expire_cookie_options = { ...options, maxAge: -1 }; switch (type) { case 'expire': return { expire_cookie_options }; case 'remember_me': return { remember_me_cookie_options }; case 'session': return { session_cookie_options }; case 'all': return { expire_cookie_options, remember_me_cookie_options, session_cookie_options }; } }; export const isAuthToken = (cookie_name) => { return cookie_name === getSupabaseLoadClientCookieOptions().name || testRegEx(cookie_name, 'auth_token'); }; export const isProviderToken = (cookie_name) => { return testRegEx(cookie_name, 'provider_token'); }; export const merge = (current, updates) => { if (updates) { for (let key of Object.keys(updates)) { if (!current.hasOwnProperty(key) || typeof updates[key] !== 'object') current[key] = updates[key]; else merge(current[key], updates[key]); } } return current; }; export const stringToBoolean = (string) => { switch (string) { case 'true': return true; case 'false': return false; default: return true; } }; export const testRegEx = (string, type) => { for (const key in regexs) { if (key === type) return regexs[key].test(string); } return false; }; export const decodeBase64URL = (value) => { const key = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; let base64 = ''; let chr1, chr2, chr3; let enc1, enc2, enc3, enc4; let i = 0; value = value.replace('-', '+').replace('_', '/'); while (i < value.length) { enc1 = key.indexOf(value.charAt(i++)); enc2 = key.indexOf(value.charAt(i++)); enc3 = key.indexOf(value.charAt(i++)); enc4 = key.indexOf(value.charAt(i++)); chr1 = (enc1 << 2) | (enc2 >> 4); chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); chr3 = ((enc3 & 3) << 6) | enc4; base64 = base64 + String.fromCharCode(chr1); if (enc3 != 64 && chr2 != 0) { base64 = base64 + String.fromCharCode(chr2); } if (enc4 != 64 && chr3 != 0) { base64 = base64 + String.fromCharCode(chr3); } } return base64; }; /** * CSRF protection, taken from @sveltejs/kit */ const isContentType = (request, ...types) => { const type = request.headers.get('content-type')?.split(';', 1)[0].trim() ?? ''; return types.includes(type.toLowerCase()); }; const isFormContentType = (request) => { return isContentType(request, 'application/x-www-form-urlencoded', 'multipart/form-data', 'text/plain'); }; export const csrfCheck = (event) => { const { request, url } = event; const forbidden = isFormContentType(request) && (request.method === 'POST' || request.method === 'DELETE' || request.method === 'PUT' || request.method === 'PATCH') && request.headers.get('origin') !== url.origin; if (forbidden) { if (request.headers.get('accept') === 'application/json') { return json(`Cross-site ${request.method} form submissions are forbidden`, { status: 403 }); } return text(`Cross-site ${request.method} form submissions are forbidden`, { status: 403 }); } return false; };