Last active
May 17, 2024 17:18
-
-
Save davidraedev/9a0a7aa707da9ab710650d0484428bd2 to your computer and use it in GitHub Desktop.
Download Debian Package and all dependencies (node)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// remote | |
const axios = require( "axios" ); | |
const cheerio = require( "cheerio" ); | |
const path = require( "path" ); | |
const fs = require( "fs" ); | |
const { exec } = require( "child_process" ); | |
const crypto = require( "crypto" ); | |
// vars | |
const downloaded_packages = new Set(); | |
// config | |
const package_name = "wpasupplicant"; | |
const repo_name = "bookworm"; | |
const arch = "amd64"; | |
const mirror = "ftp.us.debian.org/debian"; | |
const download_dir = path.resolve( "..", "packages" ); | |
// run | |
run( package_name ); | |
// code | |
function run( | |
package_name | |
) { | |
console.log( `run [${ package_name }]` ); | |
if ( ! fs.existsSync( download_dir ) ) { | |
console.log( `download_dir does not exist, creating [${ download_dir }]` ) | |
fs.mkdirSync( download_dir ); | |
} | |
process.chdir( download_dir ); | |
downloadPackage( package_name ); | |
} | |
async function downloadPackage( | |
package_name | |
) { | |
console.log( `downloadPackage [${ package_name }]` ); | |
// If the package has already been downloaded, return | |
if ( downloaded_packages.has( package_name ) ) { | |
console.log( `Already downloaded` ); | |
return; | |
} | |
const url = `https://packages.debian.org/${ repo_name }/${ package_name }`; | |
const response = await axios.get( url ); | |
const $ = cheerio.load( response.data ); | |
const package_el = $( "#pdownload a" ).filter( ( i, el ) => $( el ).text() === arch )[0]; | |
if ( package_el ) { | |
console.log( `has package_el` ); | |
const download_page_url = $( package_el ).attr( "href" ); | |
console.log( `download_page_url [${ download_page_url }]` ); | |
const result = await parseDownloadPage( `https://packages.debian.org${ download_page_url }` ); | |
const file_name = path.resolve( ".", result.download_url.split( "/" ).pop() ); | |
let did_download = false; | |
if ( checkFileExists( file_name ) ) { | |
console.log( "File already exists" ); | |
const local_sha_256 = getFileSHA256( file_name ); | |
console.log( `local_sha_256 [${ local_sha_256 }]` ); | |
if ( local_sha_256 !== result.sha_256 ) { | |
console.warn( "File is damaged, deleting" ); | |
fs.rmSync( file_name ); | |
did_download = true; | |
await execPromise( `wget ${ result.download_url }` ); | |
} | |
} | |
else { | |
did_download = true; | |
await execPromise( `wget ${ result.download_url }` ); | |
} | |
if ( did_download ) { | |
const local_sha_256 = getFileSHA256( file_name ); | |
console.log( `local_sha_256 [${ local_sha_256 }]` ); | |
if ( local_sha_256 !== result.sha_256 ) { | |
console.error( `File is damaged [${ file_name }]` ); | |
} | |
} | |
downloaded_packages.add( package_name ); | |
} | |
else { | |
console.log( `missing package_el` ); | |
} | |
const dependencies = $( ".uldep a" ); | |
// Download each dependency using wget | |
for ( let i = 0; i < dependencies.length; i++ ) { | |
const dependency_name = $( dependencies[ i ] ).text().trim(); | |
console.log( `dependency_name [${ dependency_name }]` ); | |
await downloadPackage( dependency_name ); | |
} | |
} | |
async function parseDownloadPage( | |
url | |
) { | |
console.log( `parseDownloadPage [${ url }]` ); | |
const response = await axios.get( url ); | |
const $ = cheerio.load( response.data ); | |
const download_url = $( $( "#content a" ).filter( ( i, el ) => $( el ).text() === mirror )[0] ).attr( "href" ); | |
console.log( `download_url [${ download_url }]` ); | |
const sha_256 = $( $( "#pdownloadmeta tr" ).filter( ( i, el ) => { | |
return ( $( el ).find( "th" ).text() === "SHA256 checksum" ); | |
})[0] ).find( "tt" ).text().trim(); | |
console.log( `sha_256 [${ sha_256 }]` ); | |
return { | |
download_url: download_url, | |
sha_256: sha_256 | |
}; | |
} | |
function checkFileExists( | |
file_name | |
) { | |
return fs.existsSync( file_name ); | |
} | |
function getFileSHA256( | |
file_path | |
) { | |
const content = fs.readFileSync( file_path ); | |
const hashSum = crypto.createHash( "sha256" ); | |
hashSum.update( content ); | |
return hashSum.digest( "hex" ); | |
} | |
function execPromise( | |
command | |
) { | |
return new Promise( ( resolve, reject ) => { | |
exec( | |
command, | |
( error, stdout, stderr ) => { | |
if ( error ) { | |
console.error( `exec error: ${ error }` ); | |
return reject( error ); | |
} | |
return resolve( stdout ); | |
} | |
); | |
}); | |
} |
Updated to check against sha256 and re-download if mismatched
Especially useful if you are setting up a machine that needs a package installed to get on the network
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
TODO: add in hash verification