Skip to content

Instantly share code, notes, and snippets.

@deskoh
Last active May 17, 2020 04:54
Show Gist options
  • Select an option

  • Save deskoh/b92316a6251c60ebad05a8448d32b0c1 to your computer and use it in GitHub Desktop.

Select an option

Save deskoh/b92316a6251c60ebad05a8448d32b0c1 to your computer and use it in GitHub Desktop.
SFTP Client
const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
const Client = require('ssh2-sftp-client');
// Host public key e.g. /etc/ssh/ssh_host_ecdsa_key.pub
const fingerprint = process.env.HOST_FINGERPRINT;
const hostConfig = {
host: process.env.HOST,
port: process.env.PORT || 22,
username: process.env.USER,
privateKey: process.env.KEY,
hostHash: 'md5',
hostVerifier: (keyHash) => serverHash === keyHash,
};
const serverHash = hostHash(fingerprint, 'md5');
async function main() {
try {
let client = new Client();
await client.connect(hostConfig)
console.log('Connected to', hostConfig.host);
const dir = '/sftpuser';
const files = await client.list(dir);
const downloadList = files.filter(f => f.name.endsWith('.txt')).map(f => `${dir}/${f.name}`);
await downloadFiles(client, downloadList);
await client.end();
console.log('Connection closed');
} catch (error) {
console.log(error, 'catch error');
}
}
function hostHash(fingerprint, algorithm) {
const key = Buffer.from(fingerprint, 'base64');
var hasher = crypto.createHash(algorithm);
hasher.update(key);
return hasher.digest('hex');
}
async function downloadFiles(client, downloadList) {
const downloadFileAsync = async (f) => {
try {
process.stdout.write(`Downloading ${f}...`);
const buffer = await retry(client.get(f));
fs.writeFileSync(`T:/${path.basename(f)}`, buffer);
console.log('Done');
process.stdout.write(`Writing acknowledgement for ${f}...`);
const ackFile = `${path.dirname(f)}/${path.basename(f, '.txt')}.ack`;
await retry(client.put(Buffer.from('OK\n', 'utf-8'), ackFile));
console.log('Done');
process.stdout.write(`Deleting ${f}...`);
await retry(client.delete(f));
console.log('Done');
} catch (error) {
console.error(`Failed to process ${f}`, error);
}
}
return downloadList.reduce(async (prevPromise, nextFile) => {
await prevPromise;
return downloadFileAsync(nextFile);
}, Promise.resolve());
}
function retry(promise, retries=3, err=null) {
if (!retries) {
return Promise.reject(err);
}
return promise.catch(err => {
console.error(err);
console.log('Error occurred. Retrying...');
return retry(promise, (retries - 1), err);
});
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment