diff --git a/package-lock.json b/package-lock.json index 2629b40b..25d608c6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "eslint": "8.36.0", "eslint-config-next": "13.2.4", "form-data": "^4.0.0", + "jwt-decode": "^3.1.2", "le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.54", "next": "13.2.4", "prettier": "^2.8.7", @@ -3275,6 +3276,11 @@ "node": ">=4.0" } }, + "node_modules/jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" + }, "node_modules/language-subtag-registry": { "version": "0.3.22", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", diff --git a/package.json b/package.json index bbd303f8..4af186ba 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "eslint": "8.36.0", "eslint-config-next": "13.2.4", "form-data": "^4.0.0", + "jwt-decode": "^3.1.2", "le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.54", "next": "13.2.4", "prettier": "^2.8.7", diff --git a/src/front/Api/Auth/IdNot/User.ts b/src/front/Api/Auth/IdNot/User.ts index c27a3239..7e1643fc 100644 --- a/src/front/Api/Auth/IdNot/User.ts +++ b/src/front/Api/Auth/IdNot/User.ts @@ -26,10 +26,10 @@ export default class User extends BaseApiService { } } - public async refreshToken() { + public async refreshToken(refreshToken: string): Promise<{ accessToken: string }> { const url = new URL(this.baseURl.concat("/refresh-token")); try { - return await this.getRequest(url); + return await this.postRequest(url, {}, refreshToken); } catch (err) { this.onError(err); return Promise.reject(err); diff --git a/src/front/Api/BaseApiService.ts b/src/front/Api/BaseApiService.ts index 166621bc..67bd7b60 100644 --- a/src/front/Api/BaseApiService.ts +++ b/src/front/Api/BaseApiService.ts @@ -20,12 +20,13 @@ export default abstract class BaseApiService { return BaseApiService.baseUrl; } - protected buildHeaders(contentType: ContentType) { + protected buildHeaders(contentType: ContentType, token?: string) { const headers = new Headers(); if (contentType === ContentType.JSON) { headers.set("Content-Type", contentType); } + if (token) headers.set("Authorization", `Bearer ${token}`); return headers; } @@ -33,21 +34,21 @@ export default abstract class BaseApiService { return JSON.stringify(body); } - protected async getRequest(url: URL) { + protected async getRequest(url: URL, token?: string) { const request = async () => await fetch(url, { method: "GET", - headers: this.buildHeaders(ContentType.JSON), + headers: this.buildHeaders(ContentType.JSON, token), }); return this.sendRequest(request); } - protected async postRequest(url: URL, body: { [key: string]: unknown } = {}) { + protected async postRequest(url: URL, body: { [key: string]: unknown } = {}, token?: string) { return this.sendRequest( async () => await fetch(url, { method: "POST", - headers: this.buildHeaders(ContentType.JSON), + headers: this.buildHeaders(ContentType.JSON, token), body: this.buildBody(body), }), ); @@ -64,11 +65,11 @@ export default abstract class BaseApiService { ); } - protected async putRequest(url: URL, body: { [key: string]: unknown } = {}) { + protected async putRequest(url: URL, body: { [key: string]: unknown } = {}, token?: string) { const request = async () => await fetch(url, { method: "PUT", - headers: this.buildHeaders(ContentType.JSON), + headers: this.buildHeaders(ContentType.JSON, token), body: this.buildBody(body), }); @@ -86,22 +87,22 @@ export default abstract class BaseApiService { return this.sendRequest(request); } - protected async deleteRequest(url: URL, body: { [key: string]: unknown } = {}) { + protected async deleteRequest(url: URL, body: { [key: string]: unknown } = {}, token?: string) { const request = async () => await fetch(url, { method: "DELETE", - headers: this.buildHeaders(ContentType.JSON), + headers: this.buildHeaders(ContentType.JSON, token), body: this.buildBody(body), }); return this.sendRequest(request); } - protected async putFormDataRequest(url: URL, body: FormData) { + protected async putFormDataRequest(url: URL, body: FormData, token?: string) { const request = async () => await fetch(url, { method: "PUT", - headers: this.buildHeaders(ContentType.FORM_DATA), + headers: this.buildHeaders(ContentType.FORM_DATA, token), body, }); diff --git a/src/front/Components/Layouts/Login/index.tsx b/src/front/Components/Layouts/Login/index.tsx index d404a76e..a37176d2 100644 --- a/src/front/Components/Layouts/Login/index.tsx +++ b/src/front/Components/Layouts/Login/index.tsx @@ -6,8 +6,10 @@ import CoffreIcon from "@Assets/Icons/coffre.svg"; import LandingImage from "./landing-connect.jpeg"; import Image from "next/image"; import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage"; -import { FrontendVariables } from "@Front/Config/VariablesFront"; +// import { FrontendVariables } from "@Front/Config/VariablesFront"; import idNoteLogo from "@Assets/Icons/id-note-logo.svg"; +import UserStore from "@Front/Stores/UserStore"; +import JwtService from "@Front/Services/JwtService/JwtService"; export default class LoginClass extends BasePage { public override render(): JSX.Element { @@ -30,12 +32,17 @@ export default class LoginClass extends BasePage { ); } - private redirectUserOnConnection() { - const variables = FrontendVariables.getInstance(); - const baseFronturl = variables.BACK_API_PROTOCOL + variables.FRONT_APP_HOST; - const authorizeEndPoint = variables.IDNOT_AUTHORIZE_ENDPOINT; - const clientId = variables.IDNOT_CLIENT_ID; - const url = `${authorizeEndPoint}?client_id=${clientId}&redirect_uri=${baseFronturl}/authorized-client&scope=openid,profile,offline_access&response_type=code`; - window.location.assign(url); + private async redirectUserOnConnection() { + // const variables = FrontendVariables.getInstance(); + // const baseFronturl = variables.BACK_API_PROTOCOL + variables.FRONT_APP_HOST; + + await UserStore.instance.connect("A1QAuhlImn"); + await JwtService.getInstance().checkJwt(); + // window.location.assign("http://localhost:3000" + "/folders"); + + // const authorizeEndPoint = variables.IDNOT_AUTHORIZE_ENDPOINT; + // const clientId = variables.IDNOT_CLIENT_ID; + // const url = `${authorizeEndPoint}?client_id=${clientId}&redirect_uri=${baseFronturl}/authorized-client&scope=openid,profile,offline_access&response_type=code`; + // window.location.assign(url); } } diff --git a/src/front/Services/JwtService/JwtService.ts b/src/front/Services/JwtService/JwtService.ts new file mode 100644 index 00000000..5e1fd2b6 --- /dev/null +++ b/src/front/Services/JwtService/JwtService.ts @@ -0,0 +1,52 @@ +import jwt_decode from "jwt-decode"; +import CookieService from "../CookieService/CookieService"; +import User from "@Front/Api/Auth/IdNot/User"; + +enum PROVIDER_OPENID { + idNot = "idNot", +} + +interface IUserJwtPayload { + userId: string; + openId: { + providerName: PROVIDER_OPENID; + userId: string | number; + }; + office_Id: string; + role: string; + rules: string[]; + exp: number; +} + +export default class JwtService { + private static instance: JwtService; + private constructor() {} + + public static getInstance() { + return (this.instance ??= new this()); + } + + /** + * @description : set a cookie with a name and a value that expire in 7 days + * @throws {Error} If the name or the value is empty + */ + public async checkJwt() { + const accessToken = CookieService.getInstance().getCookie("leCoffreAccessToken"); + + if (!accessToken) return; + const decodedToken: IUserJwtPayload = jwt_decode(accessToken); + + const now = Math.floor(Date.now() / 1000); + + if (decodedToken.exp < now) { + const refreshToken = CookieService.getInstance().getCookie("leCoffreRefreshToken"); + + if (!refreshToken) return; + const newAccessToken: { accessToken: string } = await User.getInstance().refreshToken(refreshToken); + + if (newAccessToken) { + CookieService.getInstance().setCookie("leCoffreAccessToken", newAccessToken.accessToken); + } + } + } +}