const fs = require("node:fs") const path = require("node:path") const crypto = require("node:crypto") const { DefaultError } = require("../errors/errors") const { pipeline } = require("node:stream/promises") const productsDataPath = path.join(process.cwd(), "data", "products") fs.promises.exists = async function exists(path) { try { await fs.promises.access(path) return true } catch { return false } }; function normalizePath($path) { return $path.split(path.win32.sep).join(path.posix.sep) } async function getFileSha1(filePath) { const hash = crypto.createHash("sha1") const readStream = fs.createReadStream(filePath) try { await pipeline(readStream, hash) return hash.digest("hex") } catch (error) { throw new Error(`Error when calculating SHA-1 hash: ${error.message}`); } } async function getProductFiles(productName, platform) { const finalPath = path.join(productsDataPath, productName, "files", platform) const files = await fs.promises.readdir(finalPath, { recursive: true }) const productFilesIndex = { root: [] } for (const file of files) { const filePath = path.join(finalPath, file) const fileMetadata = await fs.promises.stat(filePath) if (!fileMetadata.isDirectory() && !filePath.endsWith(".brikcfg")) { const normalizedFilePath = normalizePath(file) const artifact = { path: normalizedFilePath, sha1: await getFileSha1(filePath), size: fileMetadata.size, url: (process.env.BASE_POINT || "") + normalizedFilePath } const downloadObject = { downloads: { artifact, }, name: path.parse(normalizedFilePath).base } productFilesIndex.root.push(downloadObject) } } return productFilesIndex } async function getFile(basePath, productName, productPlatform) { try { const fixedPath = path.join(productsDataPath, productName, "files", productPlatform, decodeURI(basePath)) const fileMetadata = await fs.promises.stat(fixedPath) if (fileMetadata.isDirectory()) { throw new DefaultError(409, "Can't download a directory", "", "NotDownloadableException") } return { code: 200, path: fixedPath } } catch (error) { if (error.code == "ENOENT") { throw new DefaultError(404, "File not found", "", "NotFoundException") } else { throw error } } } async function canAccess(productName) { const fixedPath = path.join(productsDataPath, productName, "files", ".brikcfg") const fileState = await fs.promises.exists(fixedPath, fs.constants.F_OK) if (!fileState) { return { code: 200 } } try { const brikConfig = JSON.parse(await fs.promises.readFile(fixedPath)) if (!brikConfig.public) { throw new DefaultError(403, "Forbidden", "Locked resource.", "InsuffisentPrivilegeException") } return { code: 200 } } catch (error) { if (!error instanceof DefaultError) { throw new DefaultError(500, "Please contact the maintener", "CONFIGURATION", "0x00") } throw error } } async function getProduct(productName) { const fixedPath = path.join(productsDataPath, productName, ".brikpkg") const fileState = await fs.promises.exists(fixedPath, fs.constants.F_OK) if (!fileState) { throw new DefaultError(404, "Not found", "MissingDir", "NotFoundException") } try { const brikPackage = JSON.parse(await fs.promises.readFile(fixedPath)) if (!brikPackage.public) { throw new DefaultError(403, "Forbidden", "Locked resource.", "InsuffisentPrivilegeException") } return brikPackage } catch (error) { if (!error instanceof DefaultError) { throw new DefaultError(500, "Please contact the maintener", "CONFIGURATION", "0x00") } throw error } } async function getProducts() { const files = await fs.promises.readdir(path.join(productsDataPath), { recursive: false }) return files } async function getRequirementsForPlatform(productName, productPlatform) { const fixedPath = path.join(productsDataPath, productName, "files", ".brikcfg") if (!(await fs.promises.exists(fixedPath))) return [] const config = JSON.parse(await fs.promises.readFile(fixedPath, "utf8")) const globalReqs = config.requirements?.global || [] const platformReqs = config.requirements?.[productPlatform] || [] return [...globalReqs, ...platformReqs] } async function getInstallerResources(productName) { const fixedPath = path.join(productsDataPath, productName, "files", ".brikcfg") if (!(await fs.promises.exists(fixedPath))) return [] const config = JSON.parse(await fs.promises.readFile(fixedPath, "utf8")) return config["installerResources"] } async function getInstallerConfig(productName, productPlatform) { const fixedPath = path.join(productsDataPath, productName, "files", ".brikcfg") if (!(await fs.promises.exists(fixedPath))) return [] const config = JSON.parse(await fs.promises.readFile(fixedPath, "utf8")) const globalReqs = config.configurations?.global || [] const platformReqs = config.configurations?.[productPlatform] || [] return { ...globalReqs, ...platformReqs } } module.exports = { getFile, canAccess, getProduct, getFileSha1, getProducts, getProductFiles, getInstallerConfig, getInstallerResources, getRequirementsForPlatform }