add crypto services to decrypt files path (#28)
Co-authored-by: OxSaitama <arnaud.daubernatali@smart-chain.fr>
This commit is contained in:
parent
36e60ecfc7
commit
9934816b77
@ -21,7 +21,7 @@
|
|||||||
"dotenv": "^16.0.3",
|
"dotenv": "^16.0.3",
|
||||||
"eslint": "8.36.0",
|
"eslint": "8.36.0",
|
||||||
"eslint-config-next": "13.2.4",
|
"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",
|
"next": "13.2.4",
|
||||||
"prettier": "^2.8.7",
|
"prettier": "^2.8.7",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
|
87
src/front/Api/LeCoffreApi/SuperAdmin/Files/Files.ts
Normal file
87
src/front/Api/LeCoffreApi/SuperAdmin/Files/Files.ts
Normal file
@ -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<File[]> {
|
||||||
|
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<File[]>(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<File> {
|
||||||
|
const url = new URL(this.baseURl);
|
||||||
|
try {
|
||||||
|
return await this.postRequest<File>(url, body);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getByUid(uid: string, q?: any): Promise<File> {
|
||||||
|
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<File>(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<File> {
|
||||||
|
const url = new URL(this.baseURl.concat(`/${uid}`));
|
||||||
|
try {
|
||||||
|
return await this.putRequest<File>(url, body);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -143,8 +143,10 @@ export const fileMock: File = {
|
|||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
document: document,
|
document: document,
|
||||||
|
file_name: "file_1",
|
||||||
file_path:
|
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",
|
"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 = {
|
export const fileMock2: File = {
|
||||||
@ -152,8 +154,10 @@ export const fileMock2: File = {
|
|||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
document: document,
|
document: document,
|
||||||
|
file_name: "file_2",
|
||||||
file_path:
|
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",
|
"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 = {
|
export const identityFile: File = {
|
||||||
@ -161,7 +165,9 @@ export const identityFile: File = {
|
|||||||
created_at: new Date(),
|
created_at: new Date(),
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
document: document,
|
document: document,
|
||||||
|
file_name: "file_3",
|
||||||
file_path: "https://minteed-stg-euwest3-s3.s3.eu-west-3.amazonaws.com/cni_fake_c7259d4923.png",
|
file_path: "https://minteed-stg-euwest3-s3.s3.eu-west-3.amazonaws.com/cni_fake_c7259d4923.png",
|
||||||
|
iv: "3"
|
||||||
};
|
};
|
||||||
|
|
||||||
export const documentIdentity: Document = {
|
export const documentIdentity: Document = {
|
||||||
|
@ -19,6 +19,8 @@ export class FrontendVariables {
|
|||||||
|
|
||||||
public IDNOT_CLIENT_ID!: string;
|
public IDNOT_CLIENT_ID!: string;
|
||||||
|
|
||||||
|
public KEY_DATA!: string;
|
||||||
|
|
||||||
private constructor() {}
|
private constructor() {}
|
||||||
|
|
||||||
public static getInstance(): FrontendVariables {
|
public static getInstance(): FrontendVariables {
|
||||||
|
64
src/front/Services/CryptoService/CryptoService.ts
Normal file
64
src/front/Services/CryptoService/CryptoService.ts
Normal file
@ -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<string> {
|
||||||
|
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');
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user