import { randomBytes } from "crypto"; import { SHA256 } from "crypto-js"; import { app, remote } from "electron"; import fse from "fs-extra"; import { action, makeObservable, observable } from "mobx"; import path from "path"; import { BaseStore } from "../common/base-store"; import { LensExtensionId } from "../extensions/lens-extension"; import { toJS } from "../common/utils"; interface FSProvisionModel { extensions: Record; // extension names to paths } export class FilesystemProvisionerStore extends BaseStore { registeredExtensions = observable.map(); constructor() { super({ configName: "lens-filesystem-provisioner-store", accessPropertiesByDotNotation: false, // To make dots safe in cluster context names }); makeObservable(this); } /** * This function retrieves the saved path to the folder which the extension * can saves files to. If the folder is not present then it is created. * @param extensionName the name of the extension requesting the path * @returns path to the folder that the extension can safely write files to. */ async requestDirectory(extensionName: string): Promise { if (!this.registeredExtensions.has(extensionName)) { const salt = randomBytes(32).toString("hex"); const hashedName = SHA256(`${extensionName}/${salt}`).toString(); const dirPath = path.resolve((app || remote.app).getPath("userData"), "extension_data", hashedName); this.registeredExtensions.set(extensionName, dirPath); } const dirPath = this.registeredExtensions.get(extensionName); await fse.ensureDir(dirPath); return dirPath; } @action protected fromStore({ extensions }: FSProvisionModel = { extensions: {} }): void { this.registeredExtensions.merge(extensions); } toJSON(): FSProvisionModel { return toJS({ extensions: Object.fromEntries(this.registeredExtensions), }); } }