Skip to content

Instantly share code, notes, and snippets.

@davidraedev
Last active May 17, 2024 17:18
Show Gist options
  • Save davidraedev/9a0a7aa707da9ab710650d0484428bd2 to your computer and use it in GitHub Desktop.
Save davidraedev/9a0a7aa707da9ab710650d0484428bd2 to your computer and use it in GitHub Desktop.
Download Debian Package and all dependencies (node)
// 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 );
}
);
});
}
@davidraedev
Copy link
Author

TODO: add in hash verification

@davidraedev
Copy link
Author

Updated to check against sha256 and re-download if mismatched

@davidraedev
Copy link
Author

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