Merge pull request #44 from MasterAcnolo/sync

Sync
This commit is contained in:
Axel Nicolas
2026-07-26 15:15:52 +02:00
committed by GitHub
8 changed files with 1642 additions and 940 deletions

View File

@@ -134,6 +134,7 @@ sudo apt install ./freedom-loader_1.x.x_amd64.deb
#### RPM (Fedora/RHEL/openSUSE, without Copr) #### RPM (Fedora/RHEL/openSUSE, without Copr)
```bash ```bash
# Download the latest .rpm from the Releases page, then:
sudo dnf install ./freedom-loader-1.x.y.x86_64.rpm sudo dnf install ./freedom-loader-1.x.y.x86_64.rpm
``` ```
@@ -162,7 +163,8 @@ freedom-loader
## Usage ## Usage
> [!TIP] On Linux, you can start Freedom Loader using `freedom-loader` command > [!TIP]
> On Linux, you can start Freedom Loader using `freedom-loader` command
### Basic Download ### Basic Download

View File

@@ -2,15 +2,14 @@
## Supported Versions ## Supported Versions
We actively maintain and provide security updates for the following versions of Freedom Loader: Freedom Loader follows a **latest-only** support model. Security fixes are applied to the current release only — no backports to older versions.
| Version | Supported | | Version | Supported |
|---------|--------------------| | ------------- | ------------------ |
| 1.4.x | :white_check_mark: | | Latest stable | :white_check_mark: |
| 1.3.x | :white_check_mark: | | Older versions | :x: |
| < 1.3.0 | :x: |
**Note**: We recommend always using the latest version to benefit from the most recent security patches and features. I recommend always running the latest version. The built-in auto-updater will notify you when a new release is available. Older versions will not receive security patches regardless of severity.
## Reporting a Vulnerability ## Reporting a Vulnerability
@@ -32,37 +31,40 @@ Instead, please report security issues privately by:
### What to Expect ### What to Expect
- **Acknowledgment**: We will acknowledge receipt of your report within 48 hours - **Acknowledgment**: I will acknowledge receipt of your report within 48 hours
- **Assessment**: We will assess the vulnerability and determine its severity - **Assessment**: I will assess the vulnerability and determine its severity
- **Updates**: We will keep you informed of our progress - **Updates**: I will keep you informed of our progress
- **Resolution**: We aim to release a fix within 7-14 days for critical vulnerabilities - **Resolution**: I aim to release a fix within 7-14 days for critical vulnerabilities
- **Credit**: We will credit you in the release notes (unless you prefer to remain anonymous) - **Credit**: I will credit you in the release notes (unless you prefer to remain anonymous)
## Security Best Practices for Users ## Security Best Practices for Users
When using Freedom Loader, we recommend: When using Freedom Loader, I recommend:
### General Security ### General Security
- **Keep Updated**: Always use the latest version of Freedom Loader - **Keep Updated**: Always use the latest version of Freedom Loader — older versions receive no security patches
- **Official Sources**: Download only from official releases on [GitHub](https://github.com/MasterAcnolo/Freedom-Loader/releases) - **Official Sources**: Download only from official sources:
- **Verify Downloads**: Check that installers are properly signed (Windows SmartScreen may show warnings for new releases) - [GitHub Releases](https://github.com/MasterAcnolo/Freedom-Loader/releases)
- [Fedora COPR](https://copr.fedorainfracloud.org/coprs/masteracnolo/freedom-loader/)
<!-- - [Snap Store](https://snapcraft.io/freedom-loader) -->
- **Verify Downloads**: Check that installers are from one of the above sources
- **Antivirus**: Keep your antivirus software up to date - **Antivirus**: Keep your antivirus software up to date
### Configuration Security ### Configuration Security
- **Download Path**: Only set download paths within your user directory (`C:\Users\[USERNAME]\...`) - **Download Path**: Only set download paths within your user directory
- **Cookies**: Be aware that Firefox cookies are used for authenticationkeep Firefox secure - **Cookies**: Be aware that Firefox cookies are used for authenticationkeep Firefox secure
- **Logs**: Logs may contain sensitive informationavoid sharing them publicly without review - **Logs**: Logs may contain sensitive information such as URLs or local paths — avoid sharing them publicly without review
### Privacy Considerations ### Privacy Considerations
Freedom Loader respects your privacy: Freedom Loader respects your privacy:
- **No Data Collection**: We don't collect, store, or transmit your personal data - **No Data Collection**: I don't collect, store, or transmit your personal data
- **No Telemetry**: No usage tracking or analytics - **No Telemetry**: No usage tracking or analytics
- **Local Operation**: All downloads are processed locally on your machine - **Local Operation**: All downloads are processed locally on your machine
- **Optional Features**: Discord RPC is optional and can be disabled - **Optional Features**: Discord RPC is optional and can be disabled in settings
## Known Security Considerations ## Known Security Considerations
@@ -71,16 +73,16 @@ Freedom Loader respects your privacy:
Freedom Loader accesses Firefox cookies to download protected content. This is: Freedom Loader accesses Firefox cookies to download protected content. This is:
- **By Design**: Required for age-restricted or member-only content - **By Design**: Required for age-restricted or member-only content
- **Local Only**: Cookies are read locally and never transmitted - **Local Only**: Cookies are read locally and never transmitted outside your machine
- **User Controlled**: You can control what content you download - **User Controlled**: You control what content you download
### Native Dependencies ### Native Dependencies
Freedom Loader bundles native binaries: Freedom Loader bundles the following official binaries:
- **yt-dlp**: Official builds from [yt-dlp/yt-dlp](https://github.com/yt-dlp/yt-dlp) - **yt-dlp**: Official builds from [yt-dlp/yt-dlp](https://github.com/yt-dlp/yt-dlp) — auto-updated on each launch
- **FFmpeg**: Official builds from [FFmpeg.org](https://ffmpeg.org/) - **FFmpeg**: Official builds from [FFmpeg.org](https://ffmpeg.org/)
- **Deno**: Official builds from [Deno.land](https://deno.land/) - **Deno**: Official builds from [Deno.com](https://deno.com/)
These dependencies are verified and updated regularly. These dependencies are verified and updated regularly.
@@ -91,13 +93,13 @@ New releases may trigger Windows Defender warnings because:
- The application is not yet widely distributed - The application is not yet widely distributed
- Code signing certificates are expensive for open-source projects - Code signing certificates are expensive for open-source projects
This is expected behavior for new releases. The warning will decrease as more users download the software. This is expected behavior for new releases and will diminish as more users download the software.
## Vulnerability Disclosure Policy ## Vulnerability Disclosure Policy
### Our Commitment ### Our Commitment
We are committed to: I am committed to:
- Responding promptly to security reports - Responding promptly to security reports
- Working with security researchers to verify and address issues - Working with security researchers to verify and address issues
@@ -107,9 +109,9 @@ We are committed to:
### Disclosure Timeline ### Disclosure Timeline
1. **Day 0**: Vulnerability reported privately 1. **Day 0**: Vulnerability reported privately
2. **Day 1-2**: Acknowledgment sent to reporter 2. **Day 12**: Acknowledgment sent to reporter
3. **Day 3-7**: Vulnerability assessed and fix developed 3. **Day 37**: Vulnerability assessed and fix developed
4. **Day 7-14**: Fix released (critical vulnerabilities prioritized) 4. **Day 714**: Fix released (critical vulnerabilities prioritized)
5. **Day 14+**: Public disclosure (coordinated with reporter) 5. **Day 14+**: Public disclosure (coordinated with reporter)
### Scope ### Scope
@@ -129,16 +131,16 @@ The following are generally not considered security vulnerabilities:
- Issues requiring physical access to the user's machine - Issues requiring physical access to the user's machine
- Social engineering attacks - Social engineering attacks
- Denial of service against third-party services - Denial of service against third-party services
- Issues in third-party dependencies (report to upstream projects) - Issues in third-party dependencies (report to upstream projects directly)
- Missing security headers on local HTTP server (no remote access) - Missing security headers on the local HTTP server (not exposed remotely)
## Security Updates ## Security Updates
Security updates are released as: Security updates are released as:
- **Patch Releases**: For critical security fixes (e.g., 1.4.1 1.4.2) - **Patch Releases**: For critical security fixes (e.g., 1.6.0 → 1.6.1)
- **Automatic Updates**: Users are notified via the built-in update system - **Automatic Updates**: Users are notified via the built-in update system
- **Release Notes**: Security fixes are clearly marked in changelog - **Release Notes**: Security fixes are clearly marked in the changelog
## Additional Resources ## Additional Resources
@@ -150,6 +152,7 @@ Security updates are released as:
For security-related questions or concerns: For security-related questions or concerns:
- **Email**: masteracnolo25@gmail.com
- **GitHub**: [@MasterAcnolo](https://github.com/MasterAcnolo) - **GitHub**: [@MasterAcnolo](https://github.com/MasterAcnolo)
--- ---

View File

@@ -37,7 +37,7 @@ app.setAppUserModelId("com.masteracnolo.freedomloader");
/** /**
* Load the app dependencies for hardware choice * Load the app dependencies for hardware choice
*/ */
const { logger, logSessionStart, logSessionEnd } = require("./server/logger"); const { logger, logSessionStart, logSessionEnd, logDir } = require("./server/logger");
const { configFeatures } = require("./config"); const { configFeatures } = require("./config");
/** /**
@@ -79,7 +79,7 @@ const { updateYtDlp } = require("./app/ytDlpUpdater");
const { createMainWindow, getMainWindow } = require("./app/windowManager"); const { createMainWindow, getMainWindow } = require("./app/windowManager");
const { registerIpcHandlers } = require("./app/ipcHandlers"); const { registerIpcHandlers } = require("./app/ipcHandlers");
const { createSplashWindow, closeSplashWindow, setSplashProgress } = require("./app/splashManager"); const { createSplashWindow, closeSplashWindow, setSplashProgress } = require("./app/splashManager");
const { userThemesPath, initUserThemes, isWindows } = require("./server/helpers/path.helpers"); const { userThemesPath, initUserThemes, isWindows, validateBinaries, defaultDownloadFolder } = require("./server/helpers/path.helpers");
/** /**
@@ -99,7 +99,7 @@ app.on("second-instance", () => {
}); });
app.whenReady().then(async () => { app.whenReady().then(async () => {
logSessionStart(); logSessionStart(logDir, defaultDownloadFolder);
createSplashWindow(); createSplashWindow();
@@ -117,6 +117,8 @@ app.whenReady().then(async () => {
setSplashProgress(2); // Loading themes setSplashProgress(2); // Loading themes
validateBinaries();
initUserThemes(); initUserThemes();
await initThemes(userThemesPath); await initThemes(userThemesPath);

2203
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -27,9 +27,9 @@
"winston-daily-rotate-file": "^5.0.0" "winston-daily-rotate-file": "^5.0.0"
}, },
"devDependencies": { "devDependencies": {
"@electron/devtron": "^2.1.1",
"electron": "^41.2.0", "electron": "^41.2.0",
"electron-builder": "^26.8.1", "electron-builder": "^25.1.8"
"@electron/devtron": "^2.1.1"
}, },
"build": { "build": {
"appId": "com.masteracnolo.freedomloader", "appId": "com.masteracnolo.freedomloader",
@@ -53,22 +53,52 @@
}, },
"asar": true, "asar": true,
"extraResources": [ "extraResources": [
{ "from": "theme", "to": "theme" }, {
{ "from": "build/confirm-icon.png", "to": "confirm-icon.png" }, "from": "theme",
{ "from": "build/banner.bmp", "to": "banner.bmp" }, "to": "theme"
{ "from": "build/banner.png", "to": "banner.png" }, },
{ "from": "build/error.png", "to": "error.png" }, {
{ "from": "config/config.default.json", "to": "config/config.default.json" } "from": "build/confirm-icon.png",
"to": "confirm-icon.png"
},
{
"from": "build/banner.bmp",
"to": "banner.bmp"
},
{
"from": "build/banner.png",
"to": "banner.png"
},
{
"from": "build/error.png",
"to": "error.png"
},
{
"from": "config/config.default.json",
"to": "config/config.default.json"
}
], ],
"win": { "win": {
"target": "nsis", "target": "nsis",
"icon": "build/app-icon.ico", "icon": "build/app-icon.ico",
"artifactName": "${productName}-Setup-${version}.${ext}", "artifactName": "${productName}-Setup-${version}.${ext}",
"extraResources": [ "extraResources": [
{ "from": "resources/binaries/win-32/yt-dlp.exe", "to": "binaries/yt-dlp.exe" }, {
{ "from": "resources/binaries/win-32/ffmpeg.exe", "to": "binaries/ffmpeg.exe" }, "from": "resources/binaries/win-32/yt-dlp.exe",
{ "from": "resources/binaries/win-32/ffprobe.exe", "to": "binaries/ffprobe.exe" }, "to": "binaries/yt-dlp.exe"
{ "from": "resources/binaries/win-32/deno.exe", "to": "binaries/deno.exe" } },
{
"from": "resources/binaries/win-32/ffmpeg.exe",
"to": "binaries/ffmpeg.exe"
},
{
"from": "resources/binaries/win-32/ffprobe.exe",
"to": "binaries/ffprobe.exe"
},
{
"from": "resources/binaries/win-32/deno.exe",
"to": "binaries/deno.exe"
}
] ]
}, },
"nsis": { "nsis": {
@@ -83,14 +113,31 @@
"shortcutName": "Freedom Loader" "shortcutName": "Freedom Loader"
}, },
"linux": { "linux": {
"target": ["AppImage", "deb","rpm", "snap"], "target": [
"AppImage",
"deb",
"rpm",
"snap"
],
"category": "Utility", "category": "Utility",
"icon": "build/app-icon.png", "icon": "build/app-icon.png",
"extraResources": [ "extraResources": [
{ "from": "resources/binaries/linux/yt-dlp", "to": "binaries/yt-dlp" }, {
{ "from": "resources/binaries/linux/ffmpeg", "to": "binaries/ffmpeg" }, "from": "resources/binaries/linux/yt-dlp",
{ "from": "resources/binaries/linux/ffprobe", "to": "binaries/ffprobe" }, "to": "binaries/yt-dlp"
{ "from": "resources/binaries/linux/deno", "to": "binaries/deno" } },
{
"from": "resources/binaries/linux/ffmpeg",
"to": "binaries/ffmpeg"
},
{
"from": "resources/binaries/linux/ffprobe",
"to": "binaries/ffprobe"
},
{
"from": "resources/binaries/linux/deno",
"to": "binaries/deno"
}
] ]
}, },
"deb": { "deb": {

View File

@@ -164,7 +164,7 @@ function initUserThemes() {
if (!fs.existsSync(userThemesPath)) { if (!fs.existsSync(userThemesPath)) {
fs.mkdirSync(userThemesPath, { recursive: true }); fs.mkdirSync(userThemesPath, { recursive: true });
fs.chmodSync(userThemesPath, 0o777); fs.chmodSync(userThemesPath, 0o777);
getLogger().info("Created user themes directory"); getLogger().info("Created user themes directory");
} }
if (fs.existsSync(defaultThemesSourcePath)) { if (fs.existsSync(defaultThemesSourcePath)) {
@@ -172,27 +172,37 @@ function initUserThemes() {
for (const theme of defaultThemes) { for (const theme of defaultThemes) {
const srcPath = path.join(defaultThemesSourcePath, theme); const srcPath = path.join(defaultThemesSourcePath, theme);
const destPath = path.join(userThemesPath, theme); const destPath = path.join(userThemesPath, theme);
const srcIsFile = !fs.statSync(srcPath).isDirectory();
if (!fs.existsSync(destPath)) { if (fs.existsSync(destPath)) {
try { const destIsDir = fs.statSync(destPath).isDirectory();
if (fs.statSync(srcPath).isDirectory()) { if (srcIsFile && destIsDir) {
copyDirectory(srcPath, destPath); getLogger().warn(`Corrupted theme entry: ${theme}, fixing...`);
fs.chmodSync(destPath, 0o777); fs.rmSync(destPath, { recursive: true, force: true });
} else {
fs.copyFileSync(srcPath, destPath); } else {
fs.chmodSync(destPath, 0o666); continue;
}
getLogger().info(`Copied default theme: ${theme}`);
} catch (copyErr) {
getLogger().warn(`Failed to copy theme ${theme}: ${copyErr.message}`);
} }
} }
try {
if (srcIsFile) {
fs.copyFileSync(srcPath, destPath);
fs.chmodSync(destPath, 0o666);
} else {
copyDirectory(srcPath, destPath);
fs.chmodSync(destPath, 0o777);
}
getLogger().info(`Copied default theme: ${theme}`);
} catch (copyErr) {
getLogger().warn(`Failed to copy theme ${theme}: ${copyErr.message}`);
}
} }
} else { } else {
getLogger().warn(`Default themes source path not found: ${defaultThemesSourcePath}`); getLogger().warn(`Default themes source path not found: ${defaultThemesSourcePath}`);
} }
} catch (err) { } catch (err) {
getLogger().error(`Failed to initialize user themes: ${err.message}`); getLogger().error(`Failed to initialize user themes: ${err.message}`);
} }
} }
/** /**
@@ -229,16 +239,23 @@ function copyDirectory(src, dest) {
} }
// Runtime validation of critical binaries // Runtime validation of critical binaries
if (!userYtDlp) { // if (!userYtDlp) {
getLogger().error("Missing yt-dlp binary"); // getLogger().error("Missing yt-dlp binary");
} // }
if (!ffmpegPath) { // if (!ffmpegPath) {
getLogger().error("Missing ffmpeg binary"); // getLogger().error("Missing ffmpeg binary");
} // }
if (!denoPath) { // if (!denoPath) {
getLogger().error("Missing deno binary"); // getLogger().error("Missing deno binary");
// }
function validateBinaries() {
if (!userYtDlp) getLogger().error("Missing yt-dlp binary");
if (!ffmpegPath) getLogger().error("Missing ffmpeg binary");
if (!denoPath) getLogger().error("Missing deno binary");
} }
/** /**
@@ -249,4 +266,4 @@ function getLogger() {
return require("../logger.js").logger; return require("../logger.js").logger;
} }
module.exports = { userYtDlp, ffmpegPath, denoPath, iconPaths, binaryPaths, resourcesPath, defaultDownloadFolder, userThemesPath, initUserThemes, isWindows }; module.exports = { userYtDlp, ffmpegPath, denoPath, iconPaths, binaryPaths, resourcesPath, defaultDownloadFolder, userThemesPath, initUserThemes, isWindows, validateBinaries };

View File

@@ -5,6 +5,7 @@ const path = require("path");
const os = require("os"); const os = require("os");
const config = require("../config"); const config = require("../config");
const {isWindows} = require("./helpers/path.helpers"); const {isWindows} = require("./helpers/path.helpers");
const { logSystemInfo } = require("./sysinfo");
// Logs folder in Windows // Logs folder in Windows
const logDir = isWindows ? path.join(os.homedir(), "AppData", "Local", "FreedomLoader", "logs") : path.join(process.env.XDG_DATA_HOME || path.join(os.homedir(), ".local", "share"), "FreedomLoader", "logs"); const logDir = isWindows ? path.join(os.homedir(), "AppData", "Local", "FreedomLoader", "logs") : path.join(process.env.XDG_DATA_HOME || path.join(os.homedir(), ".local", "share"), "FreedomLoader", "logs");
@@ -52,9 +53,10 @@ const logger = createLogger({
/** /**
* Start Log Session * Start Log Session
*/ */
function logSessionStart() { function logSessionStart(logDir, downloadPath) {
logger.info(`--- Starting session: ${new Date().toISOString()} ---`); logger.info(`--- Starting session: ${new Date().toISOString()} ---`);
logger.info(`Application Version: ${config.version}`) logger.info(`Application Version: ${config.version}`)
logSystemInfo(logger, logDir, downloadPath)
} }
/** /**

142
server/sysinfo.js Normal file
View File

@@ -0,0 +1,142 @@
const os = require("os");
const fs = require("fs");
const { execSync } = require("child_process");
const { app } = require("electron");
/**
* Reads /etc/os-release to get the Linux distribution name
*/
function getLinuxDistro() {
try {
const content = fs.readFileSync("/etc/os-release", "utf-8");
const pretty = content.match(/^PRETTY_NAME="?(.+?)"?$/m);
if (pretty) return pretty[1];
const name = content.match(/^NAME="?(.+?)"?$/m);
return name ? name[1] : "Unknown Linux";
} catch {
return "Unknown Linux";
}
}
/**
* Reads the package-type file written by electron-builder
* to determine how the app was distributed (rpm, snap, AppImage, deb...)
*/
function getPackageType() {
try {
const pkgTypePath = require("path").join(process.resourcesPath, "package-type");
if (fs.existsSync(pkgTypePath)) {
return fs.readFileSync(pkgTypePath, "utf-8").trim();
}
} catch { /* ignore */ }
return "unknown";
}
/**
* Checks if Firefox is installed on the current platform
*/
function detectFirefox() {
const platform = process.platform;
if (platform === "win32") {
const paths = [
"C:\\Program Files\\Mozilla Firefox\\firefox.exe",
"C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe",
`${process.env.LOCALAPPDATA}\\Mozilla Firefox\\firefox.exe`,
];
return paths.some(p => fs.existsSync(p));
}
if (platform === "linux") {
const paths = [
"/usr/bin/firefox",
"/usr/bin/firefox-esr",
"/usr/local/bin/firefox",
"/snap/bin/firefox",
"/var/lib/flatpak/exports/bin/org.mozilla.firefox",
`${os.homedir()}/.local/share/flatpak/exports/bin/org.mozilla.firefox`,
];
if (paths.some(p => fs.existsSync(p))) return true;
try { execSync("which firefox", { stdio: "ignore" }); return true; } catch { return false; }
}
return false;
}
/**
* Builds the system info object logged at startup
*
* @param {string} logDir - path to the log directory
* @param {string} downloadPath - current configured download path
*/
function getSystemInfo(logDir, downloadPath) {
const platform = process.platform;
const cpus = os.cpus();
const totalMem = (os.totalmem() / 1024 / 1024 / 1024).toFixed(1);
const freeMem = (os.freemem() / 1024 / 1024 / 1024).toFixed(1);
let platformLabel;
if (platform === "win32") {
platformLabel = `Windows (${os.release()})`;
} else if (platform === "linux") {
platformLabel = `Linux — ${getLinuxDistro()}`;
} else {
platformLabel = `${platform} ${os.release()} (unsupported)`;
}
const info = {
"Platform": platformLabel,
"Architecture": os.arch(),
"CPU": cpus.length ? `${cpus[0].model.trim()} (${cpus.length} cores)` : "Unknown",
"Memory": `${freeMem} GB free / ${totalMem} GB total`,
"Locale": app.getLocale(),
"Electron": process.versions.electron,
"Node": process.versions.node,
"Packaged": String(app.isPackaged),
"Package type": app.isPackaged ? getPackageType() : "dev",
"Firefox present": detectFirefox() ? "Yes" : "No — cookie features unavailable",
"Log directory": logDir,
"Download path": downloadPath,
};
// Linux-specific extras
if (platform === "linux") {
const sessionType = process.env.XDG_SESSION_TYPE || "unknown";
const waylandDisplay = process.env.WAYLAND_DISPLAY;
const x11Display = process.env.DISPLAY;
info["Display server"] = waylandDisplay
? `Wayland (${waylandDisplay})`
: x11Display
? `X11 (${x11Display})`
: sessionType !== "unknown"
? sessionType
: "unknown";
info["Desktop env"] = process.env.XDG_CURRENT_DESKTOP || process.env.DESKTOP_SESSION || "unknown";
}
return info;
}
/**
* Logs system info at application startup
*
* @param {object} logger - winston logger instance
* @param {string} logDir - path to the log directory
* @param {string} downloadPath - current configured download path
*/
function logSystemInfo(logger, logDir, downloadPath) {
const info = getSystemInfo(logDir, downloadPath);
const maxKeyLen = Math.max(...Object.keys(info).map(k => k.length));
logger.info("=".repeat(60));
logger.info("SYSTEM INFO");
logger.info("=".repeat(60));
for (const [key, val] of Object.entries(info)) {
logger.info(` ${key.padEnd(maxKeyLen)} : ${val}`);
}
logger.info("=".repeat(60));
}
module.exports = { logSystemInfo };