From 414aec97e5426c733181e69ae36ad60108c620ae Mon Sep 17 00:00:00 2001 From: Guillem George Date: Fri, 15 May 2026 18:31:16 +0200 Subject: [PATCH] step 1 ? nn en vrai j'y crois pas --- src/pages/complete/epita/index.js | 24 +-- src/utils/auth.js | 239 ++++++++++++++++++------------ src/utils/redirect.js | 36 +++-- 3 files changed, 175 insertions(+), 124 deletions(-) diff --git a/src/pages/complete/epita/index.js b/src/pages/complete/epita/index.js index 2ad4790..27aa298 100644 --- a/src/pages/complete/epita/index.js +++ b/src/pages/complete/epita/index.js @@ -1,20 +1,20 @@ -import * as auth from "../../../utils/auth" +import * as auth from "../../../utils/auth"; let code; try { - const params = new URLSearchParams(window.location.search) - code = params.get("code") -} -catch { - console.error("Unable to retrieve code") - alert("Unable to retrieve code") + const params = new URLSearchParams(window.location.search); + + code = params.get("code"); +} catch { + console.error("Unable to retrieve code"); + alert("Unable to retrieve code"); } -if (! await auth.getToken(code)) { - console.error("Unable to retrieve token") - alert("Unable to retrieve token") +if (!(await auth.getToken(code))) { + console.error("Unable to retrieve token"); + alert("Unable to retrieve token"); } -console.debug("Redirecting...") -window.location = import.meta.env.VITE_URL +console.debug("Redirecting..."); +window.location = import.meta.env.VITE_URL; diff --git a/src/utils/auth.js b/src/utils/auth.js index 36c8246..c492072 100644 --- a/src/utils/auth.js +++ b/src/utils/auth.js @@ -1,123 +1,176 @@ import * as redirect from "./redirect"; async function sendRequest(endpoint, body) { - const request = { - method: "POST", - headers: { - "Content-Type": "application/x-www-form-urlencoded", - }, + const formData = new FormData(); - body: new URLSearchParams(body) - }; - console.debug(request) - - let response; - try { - response = await fetch(endpoint, request) - if (!response.ok) { - throw new Error(response.statusText) + for (var key in body) { + formData.append(key, body[key]); } - } - catch (err) { - console.error(err) - return null - } - - return await response.json() + + const request = { + method: "POST", + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + + body: formData, + }; + + let response; + + try { + response = await fetch(endpoint, request); + if (!response.ok) { + throw new Error(response.statusText); + } + } catch (err) { + console.error(err); + return null; + } + + return await response.json(); } /** -* @param {string} code the authorization code received from the OIDC -* provider -* @returns {boolean} true if the token was fetched, false otherwise -*/ + * @param {string} code the authorization code received from the OIDC + * provider + * @returns {Promise} true if the token was fetched, false otherwise + */ async function getToken(code) { + const auth_url = import.meta.env.VITE_URL; + const endpoint = `${auth_url}/auth-api/token`; + const formData = { + grant_type: "authorization_code", + code: code, + redirect_uri: `${auth_url}/complete/epita/`, + client_id: import.meta.env.VITE_CLIENT_ID, + }; + const response = await sendRequest(endpoint, formData); - const auth_url = import.meta.env.VITE_URL; - const endpoint = `${auth_url}/auth-api/token`; - const formData = { - "grant_type": "authorization_code", - "code": code, - "redirect_uri": `${auth_url}/complete/epita/`, - "client_id": import.meta.env.VITE_CLIENT_ID - } - const response = await sendRequest(endpoint, formData) - if (response === null) { - console.error("Failed to retrieve OIDC token") - alert("Failed to retrieve OIDC token") + if (response === null) { + console.error("Failed to retrieve OIDC token"); + alert("Failed to retrieve OIDC token"); - localStorage.clear(); - redirect.redirectToLoginPage() - return false; - } + localStorage.clear(); + redirect.redirectToLoginPage(); + return false; + } - localStorage.setItem("token", response.id_token); - localStorage.setItem("refresh_token", response.refresh_token); - console.debug("Saved token and refresh tokens") + localStorage.setItem("token", response.id_token); + localStorage.setItem("refresh_token", response.refresh_token); + console.debug("Saved token and refresh tokens"); - return true + return true; } - /** -* @param {string} refreshToken the refresh token (optional) -* @returns {boolean} whether the token has been refreshed or not -*/ + * @param {string} refreshToken the refresh token (optional) + * @returns {Promise} whether the token has been refreshed or not + */ async function refreshToken(refreshToken) { + refreshToken = refreshToken || localStorage.getItem("refresh_token"); + if (!refreshToken) { + console.error("Unable to retrieve refresh token"); + return false; + } - refreshToken= refreshToken || localStorage.getItem("refresh_token"); - if (!refreshToken) { - console.error("Unable to retrieve refresh token") - return false - } - - const auth_url = import.meta.env.VITE_URL; - const endpoint = `${auth_url}/auth-api/token`; - const formData = { - "client_id": import.meta.env.VITE_CLIENT_ID, - // client_secret: "", - "grant_type": "authorization_code", - refresh_token: refreshToken, - scope: "epita profile picture" - } - const response = await sendRequest(endpoint, formData) - if (response === null) { - console.error("Failed to retrieve OIDC token") - alert("Failed to retrieve OIDC token") + const auth_url = import.meta.env.VITE_URL; + const endpoint = `${auth_url}/auth-api/token`; + const formData = { + client_id: import.meta.env.VITE_CLIENT_ID, + // client_secret: "", + grant_type: "authorization_code", + refresh_token: refreshToken, + scope: "epita profile picture", + }; + const response = await sendRequest(endpoint, formData); - localStorage.clear(); - redirect.redirectToLoginPage() - return false; - } + if (response === null) { + console.error("Failed to retrieve OIDC token"); + alert("Failed to retrieve OIDC token"); - localStorage.setItem("token", response.id_token); - localStorage.setItem("refresh_token", response.refresh_token); - console.debug("Saved token and refresh tokens") + localStorage.clear(); + redirect.redirectToLoginPage(); + return false; + } - return true + localStorage.setItem("token", response.id_token); + localStorage.setItem("refresh_token", response.refresh_token); + console.debug("Saved token and refresh tokens"); + + return true; } /** -* @returns {boolean} true if the user is authenticated, false otherwise -*/ + * @returns {Promise} true if the user is authenticated, false otherwise + */ async function authenticate() { - const token = localStorage.getItem("token"); - if (token !== null) - return true; - const refresh_token = localStorage.getItem("refresh_token"); - if (refresh_token !== null) - return true; + const token = localStorage.getItem("token"); - redirect.redirectToLoginPage(); - return false; + if (token !== null) { + return true; + } + + const refresh_token = localStorage.getItem("refresh_token"); + + if (refresh_token !== null) { + return true; + } + + localStorage.clear(); + redirect.redirectToLoginPage(); + return false; } -// FIXME -// missing functions: -// - authedAPIRequest (makes an authenticated request to the API) +/** + * @param {string} endpoint + * @param {object} options this object should at least contain the method. + * @returns {Promise} the response or null + * We want a {Promise} so we can read the headers as well as the + * body, rather than just the body + */ +async function authedAPIRequest(endpoint, options) { + console.log("Attemtping to make a request to: " + endpoint); // TODO remove + if (!authenticate()) { + return null; + } -export { - getToken, - refreshToken, - authenticate + if (!options.method) { + console.error("Invalid parameter: options (missing method)"); + } + + if (!options.headers) { + options.headers = {}; + } + + options.headers.Authorization = localStorage.getItem("token"); + options.mode = "cors"; + + let response; + + try { + response = await fetch(endpoint, options); + if (!response.ok) { + throw new Error(response.statusText); + } + } catch (err) { + if (response.status === 401) { + const response_err = await response.text(); + + if (response_err.includes("Token expired")) { + refreshToken(null); + return null; + } + + localStorage.clear(); + redirect.redirectToLoginPage(); + return null; + } + + console.error(err); + } + + return response; } + +export { getToken, refreshToken, authenticate, authedAPIRequest }; diff --git a/src/utils/redirect.js b/src/utils/redirect.js index d8d3ae8..9c0a6d3 100644 --- a/src/utils/redirect.js +++ b/src/utils/redirect.js @@ -1,29 +1,27 @@ /** -* @returns {URL} the URL to redirect the user to the login page. -*/ + * @returns {URL} the URL to redirect the user to the login page. + */ function createLink() { - const params = new URLSearchParams({ - client_id: import.meta.env.VITE_CLIENT_ID, - response_type: "code", - redirect_uri: import.meta.env.VITE_URL + "/complete/epita/", - scope: "epita profile picture" - }); + const params = new URLSearchParams({ + client_id: import.meta.env.VITE_CLIENT_ID, + response_type: "code", + redirect_uri: import.meta.env.VITE_URL + "/complete/epita/", + scope: "epita profile picture", + }); - const base_url = import.meta.env.VITE_AUTH_URL - const res = `${base_url}/authorize?${params}` - return res; + const base_url = import.meta.env.VITE_AUTH_URL; + const res = `${base_url}/authorize?${params}`; + return new URL(res); } /** -* @returns {void} -*/ + * @returns {void} + */ function redirectToLoginPage() { - const redirectUrl = createLink(); - window.location.href = redirectUrl; + const redirectUrl = createLink(); + + window.location.href = redirectUrl; } -export { - createLink, - redirectToLoginPage -} +export { createLink, redirectToLoginPage };