import { isSecureURL } from '@baserow/modules/core/utils/string' import jwtDecode from 'jwt-decode' import { getDomain } from 'tldjs' const cookieTokenName = 'jwt_token' export const userSourceCookieTokenName = 'user_source_token' export const userSessionCookieName = 'user_session' const refreshTokenMaxAge = 60 * 60 * 24 * 7 export const setToken = ( { $config, $cookies }, token, key = cookieTokenName, configuration = { sameSite: null } ) => { if (process.SERVER_BUILD) return const secure = isSecureURL($config.PUBLIC_WEB_FRONTEND_URL) $cookies.set(key, token, { path: '/', maxAge: refreshTokenMaxAge, sameSite: configuration.sameSite || $config.BASEROW_FRONTEND_SAME_SITE_COOKIE, secure, }) } /** * Sets a session cookie in the browser to store the user's signed session payload upon * login. This cookie facilitates backend authentication for GET requests, such as * downloading files with the secure_file_serve feature, when the Authorization header * is unavailable. The payload includes a token hash to invalidate the cookie upon * logout. * * @param {*} app: the nuxt app instance * @param {*} signedUserSession: the signed user session payload to be stored in the * cookie * @param {*} key: the cookie name * @param {*} configuration: the configuration object with the sameSite key * @returns */ export const setUserSessionCookie = ( { $config, $cookies }, signedUserSession, key = userSessionCookieName, configuration = { sameSite: null } ) => { if (process.SERVER_BUILD) return const secure = isSecureURL($config.PUBLIC_WEB_FRONTEND_URL) // To make the cookie available to all subdomains, set the domain to the top-level // domain. This is necessary for the secure_file_serve feature to work across // subdomains, as when the backend serves files from a different subdomain from the // frontend. The top-level domain is extracted from the backend URL. // NOTE: For security reasons, it's not possible to set a cookie for a different // domain, so this won't work if the frontend and backend are on different domains. const topLevelDomain = getDomain($config.PUBLIC_BACKEND_URL) $cookies.set(key, signedUserSession, { path: '/', maxAge: refreshTokenMaxAge, sameSite: configuration.sameSite || $config.BASEROW_FRONTEND_SAME_SITE_COOKIE, secure, domain: topLevelDomain, }) } export const unsetToken = ({ $cookies }, key = cookieTokenName) => { if (process.SERVER_BUILD) return $cookies.remove(key) } export const unsetUserSessionCookie = ( { $cookies }, key = userSessionCookieName ) => { if (process.SERVER_BUILD) return $cookies.remove(key) } export const getToken = ({ $cookies }, key = cookieTokenName) => { return $cookies.get(key) } export const getTokenIfEnoughTimeLeft = ( { $cookies }, key = cookieTokenName ) => { const token = getToken({ $cookies }, key) const now = Math.ceil(new Date().getTime() / 1000) let data try { data = jwtDecode(token) } catch (error) { return null } // Return the token if it is still valid for more of the 10% of the lifespan. return data && (data.exp - now) / (data.exp - data.iat) > 0.1 ? token : null } export const logoutAndRedirectToLogin = ( router, store, showSessionExpiredToast = false, showPasswordChangedToast = false, invalidateToken = false ) => { if (showPasswordChangedToast) { store.dispatch('auth/forceLogoff') } else { store.dispatch('auth/logoff', { invalidateToken }) } router.push({ name: 'login', query: { noredirect: null } }, () => { if (showSessionExpiredToast) { store.dispatch('toast/setUserSessionExpired', true) } else if (showPasswordChangedToast) { store.dispatch('toast/setUserPasswordChanged', true) } store.dispatch('auth/clearAllStoreUserData') }) }