diff --git a/package.json b/package.json index 188cf199..80137aaf 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "dotenv": "^16.0.3", "eslint": "8.36.0", "eslint-config-next": "13.2.4", - "le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.35", + "le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.38", "next": "13.2.4", "prettier": "^2.8.7", "react": "18.2.0", diff --git a/src/front/Api/LeCoffreApi/SuperAdmin/Files/Files.ts b/src/front/Api/LeCoffreApi/SuperAdmin/Files/Files.ts new file mode 100644 index 00000000..28a49068 --- /dev/null +++ b/src/front/Api/LeCoffreApi/SuperAdmin/Files/Files.ts @@ -0,0 +1,87 @@ +import { File } from "le-coffre-resources/dist/SuperAdmin"; +import Container, { Service } from "typedi"; + +import BaseSuperAdmin from "../BaseSuperAdmin"; +import CryptoService from "@Front/Services/CryptoService/CryptoService"; + +// TODO Type get query params -> Where + inclue + orderby +export interface IGetFilesparams { + where?: {}; + include?: {}; +} + +// TODO Type getbyuid query params + +export type IPutFilesParams = {}; + +export interface IPostFilesParams {} + +@Service() +export default class Files extends BaseSuperAdmin { + private static instance: Files; + private readonly baseURl = this.namespaceUrl.concat("/files"); + + private constructor(private cryptoService: CryptoService) { + super(); + } + + public static getInstance() { + if (!this.instance) { + return new this(Container.get(CryptoService)); + } else { + return this.instance; + } + } + + public async get(q: IGetFilesparams): Promise { + const url = new URL(this.baseURl); + Object.entries(q).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value))); + try { + const files = await this.getRequest(url); + files.forEach(async(file) => { + file.file_path = await this.cryptoService.decrypt(file.file_path!, file.iv); + }) + return files + } catch (err) { + this.onError(err); + return Promise.reject(err); + } + } + + /** + * @description : Create a File + */ + public async post(body: any): Promise { + const url = new URL(this.baseURl); + try { + return await this.postRequest(url, body); + } catch (err) { + this.onError(err); + return Promise.reject(err); + } + } + + public async getByUid(uid: string, q?: any): Promise { + const url = new URL(this.baseURl.concat(`/${uid}`)); + const query = { q }; + if (q) Object.entries(query).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value))); + try { + const file = await this.getRequest(url); + file.file_path = await this.cryptoService.decrypt(file.file_path!, file.iv); + return file; + } catch (err) { + this.onError(err); + return Promise.reject(err); + } + } + + public async put(uid: string, body: IPutFilesParams): Promise { + const url = new URL(this.baseURl.concat(`/${uid}`)); + try { + return await this.putRequest(url, body); + } catch (err) { + this.onError(err); + return Promise.reject(err); + } + } +} diff --git a/src/front/Components/Layouts/DesignSystem/dummyData.ts b/src/front/Components/Layouts/DesignSystem/dummyData.ts index a180eeed..552a023f 100644 --- a/src/front/Components/Layouts/DesignSystem/dummyData.ts +++ b/src/front/Components/Layouts/DesignSystem/dummyData.ts @@ -143,8 +143,10 @@ export const fileMock: File = { created_at: new Date(), updated_at: new Date(), document: document, + file_name: "file_1", file_path: "https://minteed-stg-euwest3-s3.s3.eu-west-3.amazonaws.com/Qmf_Yb_Eh_X9st_F_Srq_Ve_Bj_Yb_Aj56xv_AV_Nj6_Wjypo_B4r5ubce_U_ae3303e7ab.pdf", + iv: "1" }; export const fileMock2: File = { @@ -152,8 +154,10 @@ export const fileMock2: File = { created_at: new Date(), updated_at: new Date(), document: document, + file_name: "file_2", file_path: "https://minteed-prod-euwest3-s3.s3.eu-west-3.amazonaws.com/Qm_Wq_En1_DCA_8yt_RX_Qx_QFA_9_Fm_ZKZH_Qqb_VH_1_Q_Mnv_G_Jtt1_FS_Xp_2a35a36e19", + iv: "2" }; export const identityFile: File = { @@ -161,7 +165,9 @@ export const identityFile: File = { created_at: new Date(), updated_at: new Date(), document: document, + file_name: "file_3", file_path: "https://minteed-stg-euwest3-s3.s3.eu-west-3.amazonaws.com/cni_fake_c7259d4923.png", + iv: "3" }; export const documentIdentity: Document = { diff --git a/src/front/Config/VariablesFront.ts b/src/front/Config/VariablesFront.ts index 3c132865..8b4cc36e 100644 --- a/src/front/Config/VariablesFront.ts +++ b/src/front/Config/VariablesFront.ts @@ -19,6 +19,8 @@ export class FrontendVariables { public IDNOT_CLIENT_ID!: string; + public KEY_DATA!: string; + private constructor() {} public static getInstance(): FrontendVariables { diff --git a/src/front/Services/CryptoService/CryptoService.ts b/src/front/Services/CryptoService/CryptoService.ts new file mode 100644 index 00000000..c2d62524 --- /dev/null +++ b/src/front/Services/CryptoService/CryptoService.ts @@ -0,0 +1,64 @@ +import { Service } from "typedi"; +import { FrontendVariables } from "@Front/Config/VariablesFront"; +import crypto from "crypto"; + +@Service() +export default class CryptoService { + private jwkKey: JsonWebKey; + private subtle: SubtleCrypto = crypto.webcrypto.subtle + constructor(protected variables: FrontendVariables) { + this.jwkKey = { + kty: "oct", + k: variables.KEY_DATA, + alg: "A256GCM", + ext: true, + }; + } + + private async getKey() { + return await this.subtle.importKey("jwk", this.jwkKey, {name: "AES-GCM"}, false, ["encrypt", "decrypt"]); + } + + /** + * @description : encrypt data + * @throws {Error} If data cannot be encrypted + */ + public async encrypt(data: string) { + const encodedData = Buffer.from(data); + const iv = crypto.getRandomValues(new Uint8Array(16)); + const key = await this.getKey(); + const cipherData = await this.subtle.encrypt( + { + name: "AES-GCM", + iv, + }, + key, + encodedData, + ); + + const cipherText = Buffer.from(cipherData).toString('base64'); + const ivStringified = Buffer.from(iv).toString('base64'); + + return { cipherText, ivStringified }; + } + + /** + * @description : decrypt data with an initialization vector + * @throws {Error} If data cannot be decrypted + */ + public async decrypt(cipherText: string, ivStringified: string): Promise { + const cipherData = Buffer.from(cipherText, 'base64'); + const iv = Buffer.from(ivStringified, 'base64'); + const key = await this.getKey(); + const decryptedData = await this.subtle.decrypt( + { + name: "AES-GCM", + iv, + }, + key, + cipherData, + ); + + return Buffer.from(decryptedData).toString('utf-8'); + } +}