mirror of
https://github.com/dscalzi/HeliosLauncher.git
synced 2024-12-22 03:32:12 -08:00
Use AthShield for mod verification
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.
This commit is contained in:
parent
5f3e229360
commit
886b29e356
@ -66,96 +66,122 @@ async function dlAsync(login = true) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --------- Mod Verification Logic ---------
|
// --------- Mod Verification Logic ---------
|
||||||
const modsDir = path.join(ConfigManager.getDataDirectory(), 'instances', serv.rawServer.id, 'mods')
|
|
||||||
|
|
||||||
// Check if mods directory exists, if not, create it
|
if (athShield.status) {
|
||||||
if (!fs.existsSync(modsDir)) {
|
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.usingAthShield'))
|
||||||
fs.mkdirSync(modsDir, { recursive: true })
|
|
||||||
}
|
|
||||||
|
|
||||||
const distroMods = {}
|
const modsDir = path.join(ConfigManager.getDataDirectory(), 'instances', serv.rawServer.id, 'mods')
|
||||||
const mdls = serv.modules
|
|
||||||
|
|
||||||
// Populate expected mod identities and log them
|
// Check if mods directory exists, if not, create it
|
||||||
mdls.forEach(mdl => {
|
if (!fs.existsSync(modsDir)) {
|
||||||
if (mdl.rawModule.name.endsWith('.jar')) {
|
fs.mkdirSync(modsDir, {recursive: true})
|
||||||
const modPath = path.join(modsDir, mdl.rawModule.name)
|
|
||||||
const modIdentity = mdl.rawModule.identity || mdl.rawModule.MD5
|
|
||||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.distributionIdentityError', {'moduleName': mdl.rawModule.name, 'moduleIdentity': modIdentity}))
|
|
||||||
distroMods[modPath] = modIdentity
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Function to extract mod identity from the jar file
|
|
||||||
const extractModIdentity = (filePath) => {
|
|
||||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.modIdentityExtraction', {'filePath': filePath}))
|
|
||||||
const zip = new AdmZip(filePath)
|
|
||||||
const manifestEntry = zip.getEntry('META-INF/MANIFEST.MF')
|
|
||||||
|
|
||||||
if (manifestEntry) {
|
|
||||||
const manifestContent = manifestEntry.getData().toString('utf8')
|
|
||||||
const lines = manifestContent.split('\n')
|
|
||||||
const identityLine = lines.find(line => line.startsWith('Mod-Id:') || line.startsWith('Implementation-Title:'))
|
|
||||||
if (identityLine) {
|
|
||||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.manifestIdentityFound', {'filePath': filePath, 'identityLine': identityLine}))
|
|
||||||
return identityLine.split(':')[1].trim()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fall back to a hash if no identity is found
|
const distroMods = {}
|
||||||
const fileBuffer = fs.readFileSync(filePath)
|
const mdls = serv.modules
|
||||||
const hashSum = crypto.createHash('md5') // Use MD5 to match the distribution configuration
|
|
||||||
hashSum.update(fileBuffer)
|
|
||||||
const hash = hashSum.digest('hex')
|
|
||||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.identityNotFoundInManifest', {'filePath': filePath, 'hash': hash}))
|
|
||||||
return hash
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate mods function
|
// Populate expected mod identities and log them
|
||||||
const validateMods = () => {
|
mdls.forEach(mdl => {
|
||||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.startingModValidation'))
|
if (mdl.rawModule.name.endsWith('.jar')) {
|
||||||
const installedMods = fs.readdirSync(modsDir)
|
const modPath = path.join(modsDir, mdl.rawModule.name)
|
||||||
let valid = true
|
const modIdentity = mdl.rawModule.identity || mdl.rawModule.MD5
|
||||||
|
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.distributionIdentityError', {
|
||||||
|
'moduleName': mdl.rawModule.name,
|
||||||
|
'moduleIdentity': modIdentity
|
||||||
|
}))
|
||||||
|
distroMods[modPath] = modIdentity
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
for (let mod of installedMods) {
|
// Function to extract mod identity from the jar file
|
||||||
const modPath = path.join(modsDir, mod)
|
const extractModIdentity = (filePath) => {
|
||||||
|
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.modIdentityExtraction', {'filePath': filePath}))
|
||||||
|
const zip = new AdmZip(filePath)
|
||||||
|
const manifestEntry = zip.getEntry('META-INF/MANIFEST.MF')
|
||||||
|
|
||||||
// Skip validation for mods in the excluded list
|
if (manifestEntry) {
|
||||||
if (EXCLUDED_MODS.includes(mod)) {
|
const manifestContent = manifestEntry.getData().toString('utf8')
|
||||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.modValidationBypassed', {'mod': mod}))
|
const lines = manifestContent.split('\n')
|
||||||
continue
|
const identityLine = lines.find(line => line.startsWith('Mod-Id:') || line.startsWith('Implementation-Title:'))
|
||||||
|
if (identityLine) {
|
||||||
|
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.manifestIdentityFound', {
|
||||||
|
'filePath': filePath,
|
||||||
|
'identityLine': identityLine
|
||||||
|
}))
|
||||||
|
return identityLine.split(':')[1].trim()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const expectedIdentity = distroMods[modPath]
|
// Fall back to a hash if no identity is found
|
||||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.validatingMod', {'mod': mod}))
|
const fileBuffer = fs.readFileSync(filePath)
|
||||||
|
const hashSum = crypto.createHash('md5') // Use MD5 to match the distribution configuration
|
||||||
|
hashSum.update(fileBuffer)
|
||||||
|
const hash = hashSum.digest('hex')
|
||||||
|
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.identityNotFoundInManifest', {
|
||||||
|
'filePath': filePath,
|
||||||
|
'hash': hash
|
||||||
|
}))
|
||||||
|
return hash
|
||||||
|
}
|
||||||
|
|
||||||
if (expectedIdentity) {
|
// Validate mods function
|
||||||
const modIdentity = extractModIdentity(modPath)
|
const validateMods = () => {
|
||||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.expectedAndCalculatedIdentity', {'expectedIdentity': expectedIdentity, 'mod': mod, 'modIdentity': modIdentity}))
|
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.startingModValidation'))
|
||||||
|
const installedMods = fs.readdirSync(modsDir)
|
||||||
|
let valid = true
|
||||||
|
|
||||||
if (modIdentity !== expectedIdentity) {
|
for (let mod of installedMods) {
|
||||||
loggerLanding.error(Lang.queryJS('landing.dlAsync.AthShield.modIdentityMismatchError', {'mod': mod, 'expectedIdentity': expectedIdentity, 'modIdentity': modIdentity}))
|
const modPath = path.join(modsDir, mod)
|
||||||
|
|
||||||
|
// Skip validation for mods in the excluded list
|
||||||
|
if (EXCLUDED_MODS.includes(mod)) {
|
||||||
|
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.modValidationBypassed', {'mod': mod}))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const expectedIdentity = distroMods[modPath]
|
||||||
|
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.validatingMod', {'mod': mod}))
|
||||||
|
|
||||||
|
if (expectedIdentity) {
|
||||||
|
const modIdentity = extractModIdentity(modPath)
|
||||||
|
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.expectedAndCalculatedIdentity', {
|
||||||
|
'expectedIdentity': expectedIdentity,
|
||||||
|
'mod': mod,
|
||||||
|
'modIdentity': modIdentity
|
||||||
|
}))
|
||||||
|
|
||||||
|
if (modIdentity !== expectedIdentity) {
|
||||||
|
loggerLanding.error(Lang.queryJS('landing.dlAsync.AthShield.modIdentityMismatchError', {
|
||||||
|
'mod': mod,
|
||||||
|
'expectedIdentity': expectedIdentity,
|
||||||
|
'modIdentity': modIdentity
|
||||||
|
}))
|
||||||
|
valid = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
loggerLanding.warn(Lang.queryJS('landing.dlAsync.AthShield.expectedIdentityNotFound', {'mod': mod}))
|
||||||
valid = false
|
valid = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
loggerLanding.warn(Lang.queryJS('landing.dlAsync.AthShield.expectedIdentityNotFound', {'mod': mod}))
|
|
||||||
valid = false
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.modValidationCompleted'))
|
||||||
|
return valid
|
||||||
}
|
}
|
||||||
|
|
||||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.modValidationCompleted'))
|
// Perform mod validation before proceeding
|
||||||
return valid
|
if (!validateMods()) {
|
||||||
|
const errorMessage = Lang.queryJS('landing.dlAsync.AthShield.invalidModsDetectedMessage', {'folder': dataPath})
|
||||||
|
loggerLanding.error(errorMessage)
|
||||||
|
showLaunchFailure(errorMessage, null)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.notUsingAthShield'))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform mod validation before proceeding
|
|
||||||
if (!validateMods()) {
|
|
||||||
const errorMessage = Lang.queryJS('landing.dlAsync.AthShield.invalidModsDetectedMessage', {'folder': dataPath})
|
|
||||||
loggerLanding.error(errorMessage)
|
|
||||||
showLaunchFailure(errorMessage, null)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// --------- End of Mod Verification Logic ---------
|
// --------- End of Mod Verification Logic ---------
|
||||||
|
|
||||||
setLaunchDetails(Lang.queryJS('landing.dlAsync.pleaseWait'))
|
setLaunchDetails(Lang.queryJS('landing.dlAsync.pleaseWait'))
|
||||||
|
Loading…
Reference in New Issue
Block a user