-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Athena's Shield | The Extra File Verification System #364
base: master
Are you sure you want to change the base?
Conversation
Introduce AthenaShield class to manage configuration, CLI for user setup, and update package.json with new script. This enhances the application's configurability and user interaction.
Implemented a new `dlAsync.js` file and updated the `en_US.toml` with new mod validation messages. This includes the logic for mod verification and error handling, ensuring the integrity of mods before launching the game. Ajout prochainement de l'utilitaire npm run athshield
Replaced 'path' with 'fs' module and removed unused 'Lang'. Added support for the new HeliosLauncher version and implemented a whitelist for mods. Fixed a typo in the logging message.
Corrected the typo from "launchingGame" to "waintingLaunchingGame" in the en_US language file. This ensures the message displayed to users is accurate and free of errors.
Implemented a whitelist for mods and added support for the new version of HeliosLauncher. Also corrected a language key for launch information logging.
Implemented mod verification using AthShield when enabled. Added detailed mod identity extraction and validation logic for better integrity checks. Added logs for each verification step and fallback to hash-based identity if the manifest is missing. Grande ligne : quand tu actives ath shield alors il utilise le système Athena's Shield.
Integrated Athena's Shield for mod verification, including mod identity extraction and validation against expected identities. Added exclusion list for mods, and implemented fallbacks for missing mod identities using MD5 hashes. Adjusted logging and error reporting to provide clearer feedback.
Relocated athshield files to app/assets/athshield for better organization and maintainability. This change improves the project's folder structure and simplifies file management.
Include messages for when Athena's Shield is activated and deactivated in the English localization file. This will provide users with clear notifications on the status of Athena's Shield.
Relocated the athshield.js script from ./athshield/ to app/assets/athshield/. This change ensures better organization of script files within the project structure.
Renamed the `view` method to `type` in parserAthShield.js to better reflect its purpose. Removed unused `athShield` import from landing.js and added it to settings.js. Added a manageModCategory function in settings.js to manage the display and interaction state of the Mods tab based on the type of `athShield`.
Separate logic for 'cacher' and 'bloquer' options and update corresponding values to 'hidden' and 'blocked' respectively. Ensure configuration is saved after setting the menu visibility.
Updated all comments and user prompts in athshield.js from French to English for better code readability and broader usability. No functional changes were made.
Updated console log messages in athshield.js to use single quotes for consistent escape character handling. This adjustment ensures better compatibility and readability of string literals in the code.
Replaced direct assignment of `dataPath` with variable `nameDataPath` for consistent naming. Introduced `getNameDataPath` function to return the launcher directory name string.
Remove unused dataPath constant and replace its usage in mod validation error message with ConfigManager.getNameDataPath(). This ensures the config path is retrieved dynamically.
Changed "private" field in package.json from true to false. This will make the package accessible on npm and allow others to install it.
Added .gitignore to exclude IDE-specific files, set up project code style configuration, included game and launcher settings in config.json, and created minimal discord and distribution JSON files for project setup.
Introduced an option to activate debug mode in Athena's Shield. Updated relevant JavaScript files and configuration to handle the debug mode setting. Added a new method for retrieving the debug status within the parserAthShield.js class.
Wrapped several logging statements related to module identity extraction and validation with a conditional check on the athShield.debug flag. This ensures that detailed logging information is recorded only when debugging is enabled, optimizing performance and log clarity.
Switched the distribution URL to a more reliable API endpoint to improve stability and performance. The new URL is 'https://api.skym-mc.fr/api/v1/servers/distro', which replaces the old one.
Simplify the log message for identity not found in the manifest by combining it with the hash usage statement. This improves readability and reduces redundancy in the code.
Revert distribution URL to 'https://helios-files.geekcorner.eu.org/distribution.json'. This change ensures compatibility with the older distribution endpoint and corrects the previous, unintended URL.
This commit refactors the mod identity extraction and validation process to include detailed debug logs, which are conditionally logged based on the `athShield.debug` flag. It also updates the import statements and correctly references the `ConfigManager.getNameDataPath` function for error messages.
Corrected the typo "discovereds" to "discovered" in the comment section of the landing.js file. This ensures accuracy and professionalism in the documentation.
Deleted the dlAsync.js and landing.js files from both "ancien code" and "version code final" directories. This cleanup removes outdated functionality related to mod validation and launcher processes, streamlining the codebase.
Renamed Athena's Shield documentation file and added detailed sections explaining its purpose, key features, and user benefits. Introduced a new security feature for HeliosLauncher, ensuring the integrity of installed mods.
The crypto package is added to the dependencies in package.json to support encryption-related functionalities. This addition helps in enhancing the security features of the application.
I made a lot of commits, but I wanted my pull request to be really clean, and all the code is available in the "changed files" section. |
Does it fix deleting something from nebula but i does not get deleted in the launcher? |
What do you mean by deleting something from Nebula? All the mods in your distribution are compared by file name and hash (MD5). The Athena’s Shield code is integrated into the launcher, and when you add the feature, it doesn’t cause any issues, even if you have an older version of the launcher. |
I mean, sometimes you delete something from the distro, but it dosen't get deleted form the user instance, like config files |
That’s completely normal; it’s due to the application’s cache. The cache stores information it expects to reuse often, so it doesn’t check the data and instead uses the cached version to speed things up. However, Athena's Shield doesn’t manage this aspect. I’d recommend clearing the cache if this issue occurs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, it looks nice, thanks for your contribution.
I think @dscalzi will probably not merge it under the "Athena's Shield" name however.
I also added a few comments.
README.md
Outdated
**How to active this ?** | ||
|
||
```console | ||
> npm run athshield | ||
``` | ||
|
||
``` | ||
Would you like to activate Athena's Shield? (yes/no): yes | ||
Would you like to activate debug mode? (yes/no): yes | ||
Would you like to hide or block the menu? (hide/block): block | ||
|
||
Athena's Shield activated. Menu blocked. | ||
``` | ||
|
||
You can choose whether Athena's Shield hides the mod category or blocks interaction with the drop-in mod. | ||
|
||
```console | ||
▄▄▄ ▄▄▄█████▓ ██░ ██ ▓█████ ███▄ █ ▄▄▄ ██████ ██████ ██░ ██ ██▓▓█████ ██▓ ▓█████▄ | ||
▒████▄ ▓ ██▒ ▓▒▓██░ ██▒▓█ ▀ ██ ▀█ █ ▒████▄ ▒██ ▒ ▒██ ▒ ▓██░ ██▒▓██▒▓█ ▀ ▓██▒ ▒██▀ ██▌ | ||
▒██ ▀█▄ ▒ ▓██░ ▒░▒██▀▀██░▒███ ▓██ ▀█ ██▒▒██ ▀█▄ ░ ▓██▄ ░ ▓██▄ ▒██▀▀██░▒██▒▒███ ▒██░ ░██ █▌ | ||
░██▄▄▄▄██░ ▓██▓ ░ ░▓█ ░██ ▒▓█ ▄ ▓██▒ ▐▌██▒░██▄▄▄▄██ ▒ ██▒ ▒ ██▒░▓█ ░██ ░██░▒▓█ ▄ ▒██░ ░▓█▄ ▌ | ||
▓█ ▓██▒ ▒██▒ ░ ░▓█▒░██▓░▒████▒▒██░ ▓██░ ▓█ ▓██▒▒██████▒▒ ▒██████▒▒░▓█▒░██▓░██░░▒████▒░██████▒░▒████▓ | ||
▒▒ ▓▒█░ ▒ ░░ ▒ ░░▒░▒░░ ▒░ ░░ ▒░ ▒ ▒ ▒▒ ▓▒█░▒ ▒▓▒ ▒ ░ ▒ ▒▓▒ ▒ ░ ▒ ░░▒░▒░▓ ░░ ▒░ ░░ ▒░▓ ░ ▒▒▓ ▒ | ||
▒ ▒▒ ░ ░ ▒ ░▒░ ░ ░ ░ ░░ ░░ ░ ▒░ ▒ ▒▒ ░░ ░▒ ░ ░ ░ ░▒ ░ ░ ▒ ░▒░ ░ ▒ ░ ░ ░ ░░ ░ ▒ ░ ░ ▒ ▒ | ||
░ ▒ ░ ░ ░░ ░ ░ ░ ░ ░ ░ ▒ ░ ░ ░ ░ ░ ░ ░ ░░ ░ ▒ ░ ░ ░ ░ ░ ░ ░ | ||
░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ | ||
``` | ||
|
||
--- | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this belongs in the readme. I'd put it either in the docs folder, or in the wiki
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pour ça si le code sera merge il faudra le faire mais pour l'instant je ne peux pas
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For that, if the code is going to be merged, it will have to be done, but for now, I can’t.
const path = require('path') | ||
|
||
// Chemin vers le fichier de configuration | ||
const configPath = path.join(__dirname, 'variables.athshield') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not simply use a json extension?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Je vais faire en sorte d'utiliser un fichier json
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll make sure to use a JSON file.
app/assets/js/scripts/landing.js
Outdated
/** | ||
* @Name dlAsync Function | ||
* @returns {Promise<void>} | ||
* | ||
* @author Sandro642 | ||
* @Cheating Athena's Shield | ||
* | ||
* @Added whitelist for mods | ||
* @Added support for the new HeliosLauncher version | ||
*/ | ||
|
||
/** | ||
* @Reviewed on 10.26.2024 expires on XX.XX.2025 | ||
* @Bugs discovereds: 0 | ||
* @Athena's Shield | ||
* @Sandro642 | ||
*/ | ||
|
||
|
||
// ▄▄▄ ▄▄▄█████▓ ██░ ██ ▓█████ ███▄ █ ▄▄▄ ██████ ██████ ██░ ██ ██▓▓█████ ██▓ ▓█████▄ | ||
// ▒████▄ ▓ ██▒ ▓▒▓██░ ██▒▓█ ▀ ██ ▀█ █ ▒████▄ ▒██ ▒ ▒██ ▒ ▓██░ ██▒▓██▒▓█ ▀ ▓██▒ ▒██▀ ██▌ | ||
// ▒██ ▀█▄ ▒ ▓██░ ▒░▒██▀▀██░▒███ ▓██ ▀█ ██▒▒██ ▀█▄ ░ ▓██▄ ░ ▓██▄ ▒██▀▀██░▒██▒▒███ ▒██░ ░██ █▌ | ||
// ░██▄▄▄▄██░ ▓██▓ ░ ░▓█ ░██ ▒▓█ ▄ ▓██▒ ▐▌██▒░██▄▄▄▄██ ▒ ██▒ ▒ ██▒░▓█ ░██ ░██░▒▓█ ▄ ▒██░ ░▓█▄ ▌ | ||
// ▓█ ▓██▒ ▒██▒ ░ ░▓█▒░██▓░▒████▒▒██░ ▓██░ ▓█ ▓██▒▒██████▒▒ ▒██████▒▒░▓█▒░██▓░██░░▒████▒░██████▒░▒████▓ | ||
// ▒▒ ▓▒█░ ▒ ░░ ▒ ░░▒░▒░░ ▒░ ░░ ▒░ ▒ ▒ ▒▒ ▓▒█░▒ ▒▓▒ ▒ ░ ▒ ▒▓▒ ▒ ░ ▒ ░░▒░▒░▓ ░░ ▒░ ░░ ▒░▓ ░ ▒▒▓ ▒ | ||
// ▒ ▒▒ ░ ░ ▒ ░▒░ ░ ░ ░ ░░ ░░ ░ ▒░ ▒ ▒▒ ░░ ░▒ ░ ░ ░ ░▒ ░ ░ ▒ ░▒░ ░ ▒ ░ ░ ░ ░░ ░ ▒ ░ ░ ▒ ▒ | ||
// ░ ▒ ░ ░ ░░ ░ ░ ░ ░ ░ ░ ▒ ░ ░ ░ ░ ░ ░ ░ ░░ ░ ▒ ░ ░ ░ ░ ░ ░ ░ | ||
// ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ | ||
// ░ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was this necessary?
/** | |
* @Name dlAsync Function | |
* @returns {Promise<void>} | |
* | |
* @author Sandro642 | |
* @Cheating Athena's Shield | |
* | |
* @Added whitelist for mods | |
* @Added support for the new HeliosLauncher version | |
*/ | |
/** | |
* @Reviewed on 10.26.2024 expires on XX.XX.2025 | |
* @Bugs discovereds: 0 | |
* @Athena's Shield | |
* @Sandro642 | |
*/ | |
// ▄▄▄ ▄▄▄█████▓ ██░ ██ ▓█████ ███▄ █ ▄▄▄ ██████ ██████ ██░ ██ ██▓▓█████ ██▓ ▓█████▄ | |
// ▒████▄ ▓ ██▒ ▓▒▓██░ ██▒▓█ ▀ ██ ▀█ █ ▒████▄ ▒██ ▒ ▒██ ▒ ▓██░ ██▒▓██▒▓█ ▀ ▓██▒ ▒██▀ ██▌ | |
// ▒██ ▀█▄ ▒ ▓██░ ▒░▒██▀▀██░▒███ ▓██ ▀█ ██▒▒██ ▀█▄ ░ ▓██▄ ░ ▓██▄ ▒██▀▀██░▒██▒▒███ ▒██░ ░██ █▌ | |
// ░██▄▄▄▄██░ ▓██▓ ░ ░▓█ ░██ ▒▓█ ▄ ▓██▒ ▐▌██▒░██▄▄▄▄██ ▒ ██▒ ▒ ██▒░▓█ ░██ ░██░▒▓█ ▄ ▒██░ ░▓█▄ ▌ | |
// ▓█ ▓██▒ ▒██▒ ░ ░▓█▒░██▓░▒████▒▒██░ ▓██░ ▓█ ▓██▒▒██████▒▒ ▒██████▒▒░▓█▒░██▓░██░░▒████▒░██████▒░▒████▓ | |
// ▒▒ ▓▒█░ ▒ ░░ ▒ ░░▒░▒░░ ▒░ ░░ ▒░ ▒ ▒ ▒▒ ▓▒█░▒ ▒▓▒ ▒ ░ ▒ ▒▓▒ ▒ ░ ▒ ░░▒░▒░▓ ░░ ▒░ ░░ ▒░▓ ░ ▒▒▓ ▒ | |
// ▒ ▒▒ ░ ░ ▒ ░▒░ ░ ░ ░ ░░ ░░ ░ ▒░ ▒ ▒▒ ░░ ░▒ ░ ░ ░ ░▒ ░ ░ ▒ ░▒░ ░ ▒ ░ ░ ░ ░░ ░ ▒ ░ ░ ▒ ▒ | |
// ░ ▒ ░ ░ ░░ ░ ░ ░ ░ ░ ░ ▒ ░ ░ ░ ░ ░ ░ ░ ░░ ░ ▒ ░ ░ ░ ░ ░ ░ ░ | |
// ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ | |
// ░ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's just a matter of aesthetics, but it's not necessary.
{ | ||
"athenaShieldActivated": false, | ||
"menuVisibility": "visible", | ||
"debug": "false" | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, why not use a json file
Also please add a new line at the end of this file.
{ | |
"athenaShieldActivated": false, | |
"menuVisibility": "visible", | |
"debug": "false" | |
} | |
{ | |
"athenaShieldActivated": false, | |
"menuVisibility": "visible", | |
"debug": "false" | |
} | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it about the JSON file, and I’ll add a line at the end.
mdls.forEach(mdl => { | ||
if (mdl.rawModule.name.endsWith('.jar')) { | ||
const modPath = path.join(modsDir, mdl.rawModule.name) | ||
const modIdentity = mdl.rawModule.identity || mdl.rawModule.artifact.MD5 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the identity
property is not a thing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll take a look at that.
app/assets/js/scripts/landing.js
Outdated
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.modIdentityExtraction', {'filePath': filePath})) | ||
} | ||
|
||
// Fall back to a hash if no identity is found |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see other code in that function other than the one generating a md5 hash?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Previously, there was an old function, but I removed it and forgot to delete the comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are the comments in french?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I started my code in French, but I had to translate it into English, and this is the only file I didn’t translate—a lapse in attention.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this file meant to be here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the documentation to check if the system works, but I can remove it. These are the procedures to ensure the extra file verification system functions correctly.
Thank you GeekCorner for responding to my message; of course, it will always be possible to change the name. And I will redo certain parts in the code as you reviewed some sections of it. |
This commit refactors the code in extraverif.js to improve the activation logic for the extra file verification CLI. It now handles comment lines correctly and ignores them. Additionally, the debug capabilities have been enhanced. The landing script has also been updated to improve debug capabilities. Unnecessary comment separators have been removed.
I have revised my code based on the reviews you provided. I changed the name from 'Athena's Shield' to 'Extra File Verification,' removed unnecessary aesthetic lines, and eliminated the PDF file. Additionally, for the text in the readme.md file, if my pull request is merged, please add it to the wiki |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few more changes needed
app/assets/extraverif/variables.json
Outdated
"extraFileVerifActivated": false, | ||
"menuVisibility": "visible", | ||
"debug": false | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} | |
} | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had deliberately added a space, but when I commit and push, it doesn't show, but there is one.
app/assets/js/scripts/landing.js
Outdated
mdls.forEach(mdl => { | ||
if (mdl.rawModule.name.endsWith('.jar')) { | ||
const modPath = path.join(modsDir, mdl.rawModule.name) | ||
const modIdentity = mdl.rawModule || mdl.rawModule.artifact.MD5 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const modIdentity = mdl.rawModule || mdl.rawModule.artifact.MD5 | |
const modIdentity = mdl.rawModule |
MD5 can be blank, so I don't think it's a good idea to base the mod identity on that value. Also there will always be a rawModule property afaik
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I need to keep the .md5 file because if I don't include it, I won't be able to perform the verification. The MD5 is based on the file size, and during the creation of the distribution, it generates the hash. The value cannot be null.
package.json
Outdated
}, | ||
"engines": { | ||
"node": "20.x.x" | ||
}, | ||
"dependencies": { | ||
"@electron/remote": "^2.1.2", | ||
"adm-zip": "^0.5.16", | ||
"crypto": "^1.0.1", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"crypto": "^1.0.1", |
Crypto module is already included in nodejs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure? I had to add it because it was telling me that it couldn't find the crypto dependency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, I just tried it. My mistake, it works. But by the way, when I remove the identity, I can't retrieve the MD5 hash; it returns [Object object]. I put the identity back, and it works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Weird, but fine
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I know, but so far I haven’t noticed any bugs related to that.
Let me know if there's anything else to change or not ;) |
app/assets/extraverif/variables.json
Outdated
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that a workaround for your editor?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean by that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The empty line before the closing bracket
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will remove the space
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM overall, Dan will probably request more changes when he'll have enough time to review this PR
Thank you, GeekCorner! I wish you a good day. I just hope that Daniel will see my PR. |
Hello Daniel Scalzi,
I am reaching out to present a project I have been working on called Athena's Shield. This security system is designed to integrate with your game launcher, HeliosLauncher, to ensure a secure and reliable gaming experience for Minecraft users.
What is Athena's Shield?
Athena's Shield verifies the integrity of the mods used in HeliosLauncher. It ensures that only authorized and validated mods are present by blocking unauthorized modifications. With a validation system based on the names and digital fingerprints of the mods, Athena's Shield protects users from malicious or altered mods.
Why should you consider integrating Athena's Shield?
Enhanced Security: Athena's Shield prevents the use of unauthorized mods, protecting users from security risks.
Reliability: This system guarantees a stable gaming experience by ensuring that only verified mods are used.
Ease of Use: Clear error messages and instructions help users resolve potential issues.
I have dedicated a lot of time and effort to developing Athena's Shield, taking into account feedback from other users. Although I attempted a similar project in the past without success, I have learned from my mistakes and improved this project to make it more credible and functional.
I invite you to try Athena's Shield on my GitHub repository, where you will also find a detailed explanatory video outlining its functionality and features just below this paragraph. This will allow you to personally evaluate the effectiveness of this system and see the efforts invested in its development.
I am confident that Athena's Shield could bring real added value to HeliosLauncher, and I hope to have the opportunity to discuss this proposal with you.
I am currently seeking your trust to assist you with this project by demonstrating my genuine dedication to you and HeliosLauncher.
Thank you for your time and consideration.
Respectfully,
Soria Sandro (Sandro642).
https://youtu.be/wpsLfU47tG0