Comparing version 2.7.0 to 2.7.1
#!/usr/bin/env node | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const axios = require('axios'); | ||
const chalk = require('chalk'); | ||
const crypto = require('crypto'); | ||
const RPC = require('discord-rpc'); | ||
const chalk = require('chalk'); | ||
const fs = require('node:fs'); | ||
const path = require('node:path'); | ||
const { Readable } = require('node:stream'); | ||
const RC_FILE_NAME = ".altvpkgrc.json"; | ||
const CDN_ADDRESS = "cdn.alt-mp.com"; | ||
const DISCORD_ID = "580868196270342175" | ||
const RC_FILE_NAME = '.altvpkgrc.json'; | ||
const CDN_ADDRESS = 'cdn.alt-mp.com'; | ||
const DISCORD_ID = '580868196270342175'; | ||
const args = process.argv; | ||
@@ -32,3 +31,3 @@ const rootPath = process.cwd(); | ||
client_id: DISCORD_ID, | ||
prompt: 'none', | ||
prompt: 'none' | ||
}); | ||
@@ -53,11 +52,20 @@ resolve(code); | ||
console.log(chalk.greenBright('===== Authorizing in CDN =====')); | ||
try { | ||
const res = await fetchJsonData('https://qa-auth.alt-mp.com/auth', { | ||
responseType: 'application/json', | ||
const response = await axios.get('https://qa-auth.alt-mp.com/auth', { | ||
responseType: 'json', | ||
headers: { Authorization: code }, | ||
}); | ||
return res.token; | ||
const { data } = response; | ||
if (!data || !data.token) { | ||
throw new Error('Failed to retrieve authorization token.'); | ||
} | ||
console.log(chalk.greenBright('Authorization successful.')); | ||
return data.token; | ||
} catch (e) { | ||
if (e?.response?.status != 403) throw e; | ||
throw new Error('You do not have permissions to access this branch'); | ||
throw new Error("You do not have permissions to access this branch"); | ||
} | ||
@@ -82,3 +90,3 @@ } | ||
if (args[i].startsWith('qa')) { | ||
if (args[i].startsWith("qa")) { | ||
branch = args[i]; | ||
@@ -88,9 +96,9 @@ continue; | ||
if (args[i] === 'windows') { | ||
platform = 'x64_win32'; | ||
if (args[i] === "windows") { | ||
platform = "x64_win32"; | ||
continue; | ||
} | ||
if (args[i] === 'linux') { | ||
platform = 'x64_linux'; | ||
if (args[i] === "linux") { | ||
platform = "x64_linux"; | ||
continue; | ||
@@ -101,27 +109,7 @@ } | ||
if (!branch) { | ||
branch = 'release'; | ||
console.log(chalk.yellowBright('Branch not specified, using release')); | ||
console.log(chalk.redBright('Please specify a branch: release, rc, or dev. \r\nExample:\r')); | ||
console.log(chalk.green('npx altv-pkg release')); | ||
process.exit(0); | ||
} | ||
/** | ||
* Fetch JSON data and return an object | ||
* | ||
* @param {string} url | ||
* @param {Object} headers | ||
* @return {Promise<Object>} | ||
*/ | ||
async function fetchJsonData(url, headers) { | ||
const response = await fetch(url, headers).catch((err) => { | ||
throw err; | ||
}); | ||
if (!response || !response.ok) { | ||
console.log(chalk.redBright('Failed to download latest ')); | ||
return undefined; | ||
} | ||
const res = await response.json(); | ||
return res; | ||
} | ||
async function start() { | ||
@@ -131,5 +119,5 @@ console.log(chalk.greenBright('===== altv-pkg =====')); | ||
console.log(chalk.whiteBright(`Branch: `), chalk.yellowBright(branch)); | ||
const isQa = branch.startsWith('qa'); | ||
const isQa = branch.startsWith("qa"); | ||
const SERVER_CDN_ADDRESS = isQa ? 'qa-cdn.altmp.workers.dev' : CDN_ADDRESS; | ||
const SERVER_CDN_ADDRESS = isQa ? "qa-cdn.altmp.workers.dev" : CDN_ADDRESS; | ||
const serverBranch = branch; | ||
@@ -140,4 +128,4 @@ | ||
if (isQa) { | ||
branch = 'dev'; | ||
console.log(chalk.yellowBright('===== QA branches require additional authorization! =====')); | ||
branch = "dev"; | ||
console.log(chalk.yellowBright('===== QA branches require additional authorization! =====')) | ||
@@ -147,5 +135,5 @@ try { | ||
const token = await authorizeCDN(code); | ||
headers = { 'X-Auth': token }; | ||
headers = { 'X-Auth': token } | ||
} catch (e) { | ||
console.error(chalk.redBright(`Failed to authorize: ${e}`)); | ||
console.error(chalk.redBright(`Failed to authorize: ${e.message}`)); | ||
return; | ||
@@ -156,8 +144,4 @@ } | ||
const sharedFiles = {}; | ||
let res = await fetchJsonData(`https://${CDN_ADDRESS}/data/${branch}/update.json`, { | ||
responseType: 'application/json', | ||
headers, | ||
}); | ||
for ([file, hash] of Object.entries(res.hashList)) { | ||
let res = await axios.get(`https://${CDN_ADDRESS}/data/${branch}/update.json`, { responseType: 'json', headers }); | ||
for ([file, hash] of Object.entries(res.data.hashList)) { | ||
sharedFiles[file] = `https://${CDN_ADDRESS}/data/${branch}/${file}`; | ||
@@ -171,8 +155,4 @@ } | ||
res = await fetchJsonData(`https://${SERVER_CDN_ADDRESS}/server/${serverBranch}/x64_linux/update.json`, { | ||
responseType: 'application/json', | ||
headers, | ||
}); | ||
for ([file, hash] of Object.entries(res.hashList)) { | ||
res = await axios.get(`https://${SERVER_CDN_ADDRESS}/server/${serverBranch}/x64_linux/update.json`, { responseType: 'json', headers }); | ||
for ([file, hash] of Object.entries(res.data.hashList)) { | ||
linuxFiles[file] = `https://${SERVER_CDN_ADDRESS}/server/${serverBranch}/x64_linux/${file}`; | ||
@@ -183,15 +163,14 @@ } | ||
res = await fetchJsonData(`https://${SERVER_CDN_ADDRESS}/server/${serverBranch}/x64_win32/update.json`, { | ||
responseType: 'application/json', | ||
headers, | ||
}); | ||
for ([file, hash] of Object.entries(res.hashList)) { | ||
res = await axios.get(`https://${SERVER_CDN_ADDRESS}/server/${serverBranch}/x64_win32/update.json`, { responseType: 'json', headers }); | ||
for ([file, hash] of Object.entries(res.data.hashList)) { | ||
windowsFiles[file] = `https://${SERVER_CDN_ADDRESS}/server/${serverBranch}/x64_win32/${file}`; | ||
} | ||
const sharedUpdates = [`https://${CDN_ADDRESS}/data/${branch}/update.json`]; | ||
const sharedUpdates = [ | ||
`https://${CDN_ADDRESS}/data/${branch}/update.json`, | ||
]; | ||
const linuxUpdates = [ | ||
...sharedUpdates, | ||
`https://${SERVER_CDN_ADDRESS}/server/${serverBranch}/x64_linux/update.json`, | ||
`https://${SERVER_CDN_ADDRESS}/server/${serverBranch}/x64_linux/update.json` | ||
]; | ||
@@ -201,23 +180,17 @@ | ||
...sharedUpdates, | ||
`https://${SERVER_CDN_ADDRESS}/server/${serverBranch}/x64_win32/update.json`, | ||
`https://${SERVER_CDN_ADDRESS}/server/${serverBranch}/x64_win32/update.json` | ||
]; | ||
if (loadJSModule) { | ||
res = await fetchJsonData(`https://${CDN_ADDRESS}/js-module/${branch}/x64_linux/update.json`, { | ||
responseType: 'application/json', | ||
headers, | ||
}); | ||
for ([file, hash] of Object.entries(res.hashList)) { | ||
res = await axios.get(`https://${CDN_ADDRESS}/js-module/${branch}/x64_linux/update.json`, { responseType: 'json', headers }); | ||
for ([file, hash] of Object.entries(res.data.hashList)) { | ||
linuxFiles[file] = `https://${CDN_ADDRESS}/js-module/${branch}/x64_linux/${file}`; | ||
} | ||
res = await fetchJsonData(`https://${CDN_ADDRESS}/js-module/${branch}/x64_win32/update.json`, { | ||
responseType: 'application/json', | ||
headers, | ||
}); | ||
for ([file, hash] of Object.entries(res.hashList)) { | ||
res = await axios.get(`https://${CDN_ADDRESS}/js-module/${branch}/x64_win32/update.json`, { responseType: 'json', headers }); | ||
for ([file, hash] of Object.entries(res.data.hashList)) { | ||
windowsFiles[file] = `https://${CDN_ADDRESS}/js-module/${branch}/x64_win32/${file}`; | ||
} | ||
linuxUpdates.push(`https://${CDN_ADDRESS}/js-module/${branch}/x64_linux/update.json`); | ||
linuxUpdates.push(`https://${CDN_ADDRESS}/js-module/${branch}/x64_linux/update.json`) | ||
windowsUpdates.push(`https://${CDN_ADDRESS}/js-module/${branch}/x64_win32/update.json`); | ||
@@ -227,19 +200,13 @@ } | ||
if (loadBytecodeModule) { | ||
res = await fetchJsonData(`https://${CDN_ADDRESS}/js-bytecode-module/${branch}/x64_linux/update.json`, { | ||
responseType: 'application/json', | ||
headers, | ||
}); | ||
for ([file, hash] of Object.entries(res.hashList)) { | ||
res = await axios.get(`https://${CDN_ADDRESS}/js-bytecode-module/${branch}/x64_linux/update.json`, { responseType: 'json', headers }); | ||
for ([file, hash] of Object.entries(res.data.hashList)) { | ||
linuxFiles[file] = `https://${CDN_ADDRESS}/js-bytecode-module/${branch}/x64_linux/${file}`; | ||
} | ||
res = await fetchJsonData(`https://${CDN_ADDRESS}/js-bytecode-module/${branch}/x64_win32/update.json`, { | ||
responseType: 'application/json', | ||
headers, | ||
}); | ||
for ([file, hash] of Object.entries(res.hashList)) { | ||
res = await axios.get(`https://${CDN_ADDRESS}/js-bytecode-module/${branch}/x64_win32/update.json`, { responseType: 'json', headers }); | ||
for ([file, hash] of Object.entries(res.data.hashList)) { | ||
windowsFiles[file] = `https://${CDN_ADDRESS}/js-bytecode-module/${branch}/x64_win32/${file}`; | ||
} | ||
linuxUpdates.push(`https://${CDN_ADDRESS}/js-bytecode-module/${branch}/x64_linux/update.json`); | ||
linuxUpdates.push(`https://${CDN_ADDRESS}/js-bytecode-module/${branch}/x64_linux/update.json`) | ||
windowsUpdates.push(`https://${CDN_ADDRESS}/js-bytecode-module/${branch}/x64_win32/update.json`); | ||
@@ -249,15 +216,9 @@ } | ||
if (loadCSharpModule) { | ||
res = await fetchJsonData(`https://${CDN_ADDRESS}/coreclr-module/${branch}/x64_linux/update.json`, { | ||
responseType: 'application/json', | ||
headers, | ||
}); | ||
for ([file, hash] of Object.entries(res.hashList)) { | ||
res = await axios.get(`https://${CDN_ADDRESS}/coreclr-module/${branch}/x64_linux/update.json`, { responseType: 'json', headers }); | ||
for ([file, hash] of Object.entries(res.data.hashList)) { | ||
linuxFiles[file] = `https://${CDN_ADDRESS}/coreclr-module/${branch}/x64_linux/${file}`; | ||
} | ||
res = await fetchJsonData(`https://${CDN_ADDRESS}/coreclr-module/${branch}/x64_win32/update.json`, { | ||
responseType: 'application/json', | ||
headers, | ||
}); | ||
for ([file, hash] of Object.entries(res.hashList)) { | ||
res = await axios.get(`https://${CDN_ADDRESS}/coreclr-module/${branch}/x64_win32/update.json`, { responseType: 'json', headers }); | ||
for ([file, hash] of Object.entries(res.data.hashList)) { | ||
windowsFiles[file] = `https://${CDN_ADDRESS}/coreclr-module/${branch}/x64_win32/${file}`; | ||
@@ -274,15 +235,9 @@ } | ||
} else { | ||
res = await fetchJsonData(`https://${CDN_ADDRESS}/js-module-v2/${branch}/x64_linux/update.json`, { | ||
responseType: 'application/json', | ||
headers, | ||
}); | ||
for ([file, hash] of Object.entries(res.hashList)) { | ||
res = await axios.get(`https://${CDN_ADDRESS}/js-module-v2/${branch}/x64_linux/update.json`, { responseType: 'json', headers }); | ||
for ([file, hash] of Object.entries(res.data.hashList)) { | ||
linuxFiles[file] = `https://${CDN_ADDRESS}/js-module-v2/${branch}/x64_linux/${file}`; | ||
} | ||
res = await fetchJsonData(`https://${CDN_ADDRESS}/js-module-v2/${branch}/x64_win32/update.json`, { | ||
responseType: 'application/json', | ||
headers, | ||
}); | ||
for ([file, hash] of Object.entries(res.hashList)) { | ||
res = await axios.get(`https://${CDN_ADDRESS}/js-module-v2/${branch}/x64_win32/update.json`, { responseType: 'json', headers }); | ||
for ([file, hash] of Object.entries(res.data.hashList)) { | ||
windowsFiles[file] = `https://${CDN_ADDRESS}/js-module-v2/${branch}/x64_win32/${file}`; | ||
@@ -297,15 +252,9 @@ } | ||
if (loadVoiceServer) { | ||
res = await fetchJsonData(`https://${CDN_ADDRESS}/voice-server/${branch}/x64_linux/update.json`, { | ||
responseType: 'application/json', | ||
headers, | ||
}); | ||
for ([file, hash] of Object.entries(res.hashList)) { | ||
res = await axios.get(`https://${CDN_ADDRESS}/voice-server/${branch}/x64_linux/update.json`, { responseType: 'json', headers }); | ||
for ([file, hash] of Object.entries(res.data.hashList)) { | ||
linuxFiles[file] = `https://${CDN_ADDRESS}/voice-server/${branch}/x64_linux/${file}`; | ||
} | ||
res = await fetchJsonData(`https://${CDN_ADDRESS}/voice-server/${branch}/x64_win32/update.json`, { | ||
responseType: 'application/json', | ||
headers, | ||
}); | ||
for ([file, hash] of Object.entries(res.hashList)) { | ||
res = await axios.get(`https://${CDN_ADDRESS}/voice-server/${branch}/x64_win32/update.json`, { responseType: 'json', headers }); | ||
for ([file, hash] of Object.entries(res.data.hashList)) { | ||
windowsFiles[file] = `https://${CDN_ADDRESS}/voice-server/${branch}/x64_win32/${file}`; | ||
@@ -318,4 +267,5 @@ } | ||
const [filesUpdate, filesToUse] = | ||
platform == 'x64_win32' ? [windowsUpdates, windowsFiles] : [linuxUpdates, linuxFiles]; | ||
const [filesUpdate, filesToUse] = (platform == 'x64_win32') | ||
? [windowsUpdates, windowsFiles] | ||
: [linuxUpdates, linuxFiles]; | ||
@@ -338,30 +288,28 @@ if (!fs.existsSync(path.join(rootPath, 'data'))) { | ||
for (const url of filesUpdate) { | ||
const promise = new Promise(async (resolve, reject) => { | ||
/** @type {{ hashList: { [key: string]: string }}} */ | ||
const data = await fetchJsonData(url, { responseType: 'application/json', headers }); | ||
const promise = new Promise((resolve, reject) => { | ||
axios.get(url, { responseType: 'json', headers }).then(({ data: { | ||
hashList | ||
} }) => { | ||
for (let [file, hash] of Object.entries(hashList)) { | ||
const correctedFileName = correctPathIfNecessary(file); | ||
if (!data) { | ||
console.error(chalk.redBright(`Failed to check hash ${url}: ${error}`)); | ||
reject(); | ||
return; | ||
} | ||
if (getLocalFileHash(correctedFileName) === hash) { | ||
console.log(chalk.cyanBright('✓'), chalk.whiteBright(correctedFileName)); | ||
continue; | ||
} | ||
for (let [file, hash] of Object.entries(data.hashList)) { | ||
const correctedFileName = correctPathIfNecessary(file); | ||
console.log(chalk.redBright('x'), chalk.whiteBright(correctedFileName)); | ||
if (getLocalFileHash(correctedFileName) === hash) { | ||
console.log(chalk.cyanBright('✓'), chalk.whiteBright(correctedFileName)); | ||
continue; | ||
if (anyHashRejected) return; | ||
filesToDownload[correctedFileName] = filesToUse[file]; | ||
} | ||
console.log(chalk.redBright('x'), chalk.whiteBright(correctedFileName)); | ||
resolve(); | ||
}).catch(error => { | ||
reject(); | ||
if (anyHashRejected) { | ||
return; | ||
} | ||
filesToDownload[correctedFileName] = filesToUse[file]; | ||
} | ||
resolve(); | ||
if (anyHashRejected) return; | ||
anyHashRejected = true; | ||
console.error(chalk.redBright(`Failed to check hash ${url}: ${error}`)); | ||
}); | ||
}); | ||
@@ -375,3 +323,4 @@ | ||
console.log(chalk.greenBright('===== File hash check complete =====')); | ||
} catch { | ||
} | ||
catch { | ||
console.log(chalk.redBright('===== File hash check corrupted -> download all =====')); | ||
@@ -385,29 +334,20 @@ filesToDownload = filesToUse; | ||
promises = []; | ||
console.log(chalk.greenBright('===== Downloading =====')); | ||
console.log(chalk.greenBright('===== Download =====')); | ||
for (const [file, url] of Object.entries(filesToDownload)) { | ||
// Avoid overwriting existing runtimeconfig.json file | ||
if (file == 'AltV.Net.Host.runtimeconfig.json' && !shouldIncludeRuntimeConfig) { | ||
if (file == "AltV.Net.Host.runtimeconfig.json" && !shouldIncludeRuntimeConfig) | ||
continue; | ||
} | ||
console.log(chalk.whiteBright(`${file}`)); | ||
const promise = new Promise(async (resolve) => { | ||
const response = await fetch(url).catch((err) => { | ||
return undefined; | ||
}); | ||
if (!response || !response.ok) { | ||
return resolve(); | ||
} | ||
const body = Readable.fromWeb(response.body); | ||
const writeStream = fs.createWriteStream(path.join(rootPath, file)); | ||
body.pipe(writeStream); | ||
body.on('close', () => { | ||
const promise = new Promise((resolve) => { | ||
axios.get(url, { responseType: 'arraybuffer', headers }).then(response => { | ||
fs.writeFileSync(path.join(rootPath, file), response.data); | ||
resolve(); | ||
}).catch(error => { | ||
console.error(chalk.redBright(`Failed to download ${url}: ${error}`)); | ||
if (file.includes('.bin')) { | ||
console.log(`File may only be available in another branch. Can be safely ignored`) | ||
} | ||
resolve(); | ||
}); | ||
body.on('error', (err) => { | ||
console.log(err); | ||
}); | ||
}); | ||
@@ -458,5 +398,4 @@ | ||
if (typeof parsedData.loadJSModule !== 'undefined') { | ||
if (typeof parsedData.loadJSModule !== 'undefined') | ||
loadJSModule = !!parsedData.loadJSModule; | ||
} | ||
@@ -463,0 +402,0 @@ loadBytecodeModule = !!parsedData.loadBytecodeModule; |
{ | ||
"name": "altv-pkg", | ||
"version": "2.7.0", | ||
"version": "2.7.1", | ||
"description": "Install alt:V Binaries Quickly", | ||
@@ -5,0 +5,0 @@ "main": "bin/index.js", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
0
52500
316
1