diff --git a/.vscode/settings.json b/.vscode/settings.json index 2d9dc4b..71d5ef0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,9 +10,14 @@ }, "cSpell.words": [ "admzip", + "antd", "APPDATA", "catched", + "Classname", "execa", + "getstation", + "imjs", + "ragestudio", "rclone", "sevenzip", "unzipper", diff --git a/packages/core/package.json b/packages/core/package.json index 5768cb2..ea3e7fc 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -29,6 +29,7 @@ "open": "8.4.2", "request": "^2.88.2", "rimraf": "^5.0.5", + "signal-exit": "^4.1.0", "unzipper": "^0.10.14", "upath": "^2.0.1", "uuid": "^9.0.1", diff --git a/packages/core/src/classes/ManifestAuthDB.js b/packages/core/src/classes/ManifestAuthDB.js new file mode 100644 index 0000000..fe32684 --- /dev/null +++ b/packages/core/src/classes/ManifestAuthDB.js @@ -0,0 +1,36 @@ +import path from "path" +import { JSONFilePreset } from "../libraries/lowdb/presets/node" + +import Vars from "../vars" + +//! WARNING: Please DO NOT storage any password or sensitive data here, +// cause its not use any encryption method, and it will be stored in plain text. +// This is intended to store session tokens among other vars. + +export default class ManifestAuthService { + static vaultPath = path.resolve(Vars.runtime_path, "auth.json") + + static async withDB() { + return await JSONFilePreset(ManifestAuthService.vaultPath, {}) + } + + static has = async (pkg_id) => { + const db = await this.withDB() + + return !!db.data[pkg_id] + } + + static set = async (pkg_id, value) => { + const db = await this.withDB() + + return await db.update((data) => { + data[pkg_id] = value + }) + } + + static get = async (pkg_id) => { + const db = await this.withDB() + + return await db.data[pkg_id] + } +} \ No newline at end of file diff --git a/packages/core/src/handlers/authorize.js b/packages/core/src/handlers/authorize.js new file mode 100644 index 0000000..e1d19ab --- /dev/null +++ b/packages/core/src/handlers/authorize.js @@ -0,0 +1,33 @@ +import ManifestAuthDB from "../classes/ManifestAuthDB" +import DB from "../db" + +import Logger from "../logger" + +const Log = Logger.child({ service: "AUTH" }) + +export default async (pkg_id, value) => { + if (!pkg_id) { + Log.error("pkg_id is required") + return false + } + + if (!value) { + Log.error("value is required") + return false + } + + const pkg = await DB.getPackages(pkg_id) + + if (!pkg) { + Log.error("Package not found") + return false + } + + Log.info(`Setting auth for [${pkg_id}]`) + + await ManifestAuthDB.set(pkg_id, value) + + global._relic_eventBus.emit("pkg:authorized", pkg) + + return true +} \ No newline at end of file diff --git a/packages/core/src/handlers/execute.js b/packages/core/src/handlers/execute.js index 6f31d7b..4351d24 100644 --- a/packages/core/src/handlers/execute.js +++ b/packages/core/src/handlers/execute.js @@ -67,7 +67,9 @@ export default async function execute(pkg_id, { useRemote = false, force = false } catch (error) { global._relic_eventBus.emit(`pkg:error`, { id: pkg_id, - error + event: "execute", + last_status: "installed", + error, }) BaseLog.error(`Failed to execute package [${pkg_id}]`, error) diff --git a/packages/core/src/helpers/setup.js b/packages/core/src/helpers/setup.js index 737040b..0058dcc 100644 --- a/packages/core/src/helpers/setup.js +++ b/packages/core/src/helpers/setup.js @@ -32,17 +32,40 @@ export default async () => { if (!fs.existsSync(prerequisite.finalBin)) { Log.info(`Missing prerequisite: ${prerequisite.id}, installing...`) + global._relic_eventBus.emit("app:setup", { + installed: false, + message: `Installing ${prerequisite.id}`, + }) + if (fs.existsSync(prerequisite.destination)) { Log.info(`Deleting temporal file [${prerequisite.destination}]`) + + global._relic_eventBus.emit("app:setup", { + installed: false, + message: `Deleting temporal file [${prerequisite.destination}]`, + }) + await fs.promises.rm(prerequisite.destination) } if (fs.existsSync(prerequisite.extract)) { Log.info(`Deleting temporal directory [${prerequisite.extract}]`) + + global._relic_eventBus.emit("app:setup", { + installed: false, + message: `Deleting temporal directory [${prerequisite.extract}]`, + }) + await fs.promises.rm(prerequisite.extract, { recursive: true }) } Log.info(`Creating base directory: ${Vars.binaries_path}/${prerequisite.id}...`) + + global._relic_eventBus.emit("app:setup", { + installed: false, + message: `Creating base directory: ${Vars.binaries_path}/${prerequisite.id}`, + }) + await fs.promises.mkdir(path.resolve(Vars.binaries_path, prerequisite.id), { recursive: true }) if (typeof prerequisite.url === "function") { @@ -52,10 +75,21 @@ export default async () => { Log.info(`Downloading ${prerequisite.id} from [${prerequisite.url}] to destination [${prerequisite.destination}]...`) + global._relic_eventBus.emit("app:setup", { + installed: false, + message: `Starting download ${prerequisite.id} from [${prerequisite.url}] to destination [${prerequisite.destination}]`, + }) + try { await downloadFile( prerequisite.url, - prerequisite.destination + prerequisite.destination, + (progress) => { + global._relic_eventBus.emit("app:setup", { + installed: false, + message: `Downloaded ${progress.transferredString} / ${progress.totalString} | ${progress.speedString}/s`, + }) + } ) } catch (error) { await fs.promises.rm(prerequisite.destination) @@ -66,6 +100,11 @@ export default async () => { if (typeof prerequisite.extract === "string") { Log.info(`Extracting ${prerequisite.id} to destination [${prerequisite.extract}]...`) + global._relic_eventBus.emit("app:setup", { + installed: false, + message: `Extracting ${prerequisite.id} to destination [${prerequisite.extract}]`, + }) + const zip = new admzip(prerequisite.destination) await zip.extractAllTo(prerequisite.extract, true) @@ -88,6 +127,12 @@ export default async () => { if (prerequisite.deleteBeforeExtract === true) { Log.info(`Deleting temporal file [${prerequisite.destination}]`) + + global._relic_eventBus.emit("app:setup", { + installed: false, + message: `Deleting temporal file [${prerequisite.destination}]`, + }) + await fs.promises.unlink(prerequisite.destination) } @@ -97,6 +142,12 @@ export default async () => { prerequisite.finalBin Log.info(`Rewriting permissions to ${to}...`) + + global._relic_eventBus.emit("app:setup", { + installed: false, + message: `Rewriting permissions to ${to}`, + }) + await chmodRecursive(to, 0o755) } @@ -104,6 +155,11 @@ export default async () => { for (const dir of prerequisite.moveDirs) { Log.info(`Moving ${dir.from} to ${dir.to}...`) + global._relic_eventBus.emit("app:setup", { + installed: false, + message: `Moving ${dir.from} to ${dir.to}`, + }) + await fs.promises.rename(dir.from, dir.to) if (dir.deleteParentBefore === true) { @@ -113,8 +169,19 @@ export default async () => { } } + global._relic_eventBus.emit("app:setup", { + installed: true, + message: null, + }) + Log.info(`Prerequisite: ${prerequisite.id} is ready!`) } catch (error) { + global._relic_eventBus.emit("app:setup", { + installed: false, + error: error, + message: error.message, + }) + Log.error(error) Log.error("Aborting setup due to an error...") return false diff --git a/packages/core/src/index.js b/packages/core/src/index.js index 0b24d70..841c1f7 100644 --- a/packages/core/src/index.js +++ b/packages/core/src/index.js @@ -16,6 +16,7 @@ import PackageUpdate from "./handlers/update" import PackageApply from "./handlers/apply" import PackageList from "./handlers/list" import PackageRead from "./handlers/read" +import PackageAuthorize from "./handlers/authorize" export default class RelicCore { constructor(params) { @@ -26,8 +27,6 @@ export default class RelicCore { logger = Logger - db = DB - async initialize() { await DB.initialize() @@ -52,6 +51,7 @@ export default class RelicCore { apply: PackageApply, list: PackageList, read: PackageRead, + authorize: PackageAuthorize, } openPath(pkg_id) { diff --git a/packages/core/src/manifest/libs/auth/index.js b/packages/core/src/manifest/libs/auth/index.js index f095692..2f1371a 100644 --- a/packages/core/src/manifest/libs/auth/index.js +++ b/packages/core/src/manifest/libs/auth/index.js @@ -1,5 +1,6 @@ import open from "open" import axios from "axios" +import ManifestAuthDB from "../../../classes/ManifestAuthDB" export default class Auth { constructor(ctx) { @@ -7,31 +8,24 @@ export default class Auth { } async get() { - return { - assigned_username: "test", - } + const storagedData = await ManifestAuthDB.get(this.manifest.id) - const authData = global.authService.getAuth(this.manifest.id) + if (storagedData && this.manifest.authService) { + if (!this.manifest.authService.getter) { + return storagedData + } - console.log(authData) - - if (authData && this.manifest.auth && this.manifest.auth.getter) { const result = await axios({ method: "POST", - url: this.manifest.auth.getter, + url: this.manifest.authService.getter, headers: { "Content-Type": "application/json", }, data: { - auth_data: authData, + auth_data: storagedData, } }).catch((err) => { - sendToRender(`new:notification`, { - type: "error", - message: "Failed to authorize", - description: err.response.data.message ?? err.response.data.error ?? err.message, - duration: 10 - }) + global._relic_eventBus.emit("auth:getter:error", err) return err }) @@ -41,20 +35,19 @@ export default class Auth { } console.log(result.data) - + return result.data } - return authData + return storagedData } request() { - return true - if (!this.manifest.auth) { + if (!this.manifest.authService || !this.manifest.authService.fetcher) { return false } - const authURL = this.manifest.auth.fetcher + const authURL = this.manifest.authService.fetcher open(authURL) } diff --git a/packages/gui/electron-builder.yml b/packages/gui/electron-builder.yml index 1293417..5ec3133 100644 --- a/packages/gui/electron-builder.yml +++ b/packages/gui/electron-builder.yml @@ -19,12 +19,7 @@ nsis: uninstallDisplayName: ${productName} createDesktopShortcut: always mac: - entitlementsInherit: build/entitlements.mac.plist - extendInfo: - - NSCameraUsageDescription: Application requests access to the device's camera. - - NSMicrophoneUsageDescription: Application requests access to the device's microphone. - - NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder. - - NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder. + icon: resources/icon.icns notarize: false dmg: artifactName: ${name}-${version}.${ext} diff --git a/packages/gui/src/main/classes/CoreAdapter.js b/packages/gui/src/main/classes/CoreAdapter.js index 8f6ed83..9fa931d 100644 --- a/packages/gui/src/main/classes/CoreAdapter.js +++ b/packages/gui/src/main/classes/CoreAdapter.js @@ -19,7 +19,7 @@ export default class CoreAdapter { if (!data.id) { return false } - + if (data.use_id_only === true) { return sendToRender(`pkg:update:state:${data.id}`, data) } @@ -28,6 +28,33 @@ export default class CoreAdapter { }, "pkg:new:done": (pkg) => { sendToRender("pkg:new:done", pkg) + }, + "app:setup": (data) => { + sendToRender("app:setup", data) + }, + "auth:getter:error": (err) => { + sendToRender(`new:notification`, { + type: "error", + message: "Failed to authorize", + description: err.response.data.message ?? err.response.data.error ?? err.message, + duration: 10 + }) + }, + "pkg:authorized": (pkg) => { + sendToRender(`new:notification`, { + type: "success", + message: "Package authorized", + description: `${pkg.name} has been authorized! You can start the package now.`, + }) + }, + "pkg:error": (data) => { + sendToRender(`new:notification`, { + type: "error", + message: `An error occurred`, + description: `Something failed to ${data.event} package ${data.pkg_id}`, + }) + + sendToRender(`pkg:update:state`, data) } } diff --git a/packages/gui/src/main/index.js b/packages/gui/src/main/index.js index a54b0b0..c21f305 100644 --- a/packages/gui/src/main/index.js +++ b/packages/gui/src/main/index.js @@ -169,18 +169,18 @@ class ElectronApp { case "authorize": { if (!explicitAction[2]) { const [pkg_id, token] = explicitAction[1].split("%23") - return this.core.auth.authorize(pkg_id, token) + return this.core.package.authorize(pkg_id, token) } else { - return this.core.auth.authorize(explicitAction[1], explicitAction[2]) + return this.core.package.authorize(explicitAction[1], explicitAction[2]) } } default: { - return sendToRender("installation:invoked", explicitAction[0]) + return sendToRender("pkg:installation:invoked", explicitAction[0]) } } } else { // by default if no action is specified, assume is a install action - return sendToRender("installation:invoked", urlValue) + return sendToRender("pkg:installation:invoked", urlValue) } } } diff --git a/packages/gui/src/renderer/index.html b/packages/gui/src/renderer/index.html index c994f68..3155c2f 100644 --- a/packages/gui/src/renderer/index.html +++ b/packages/gui/src/renderer/index.html @@ -1,16 +1,15 @@ -
- -