123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 |
- var crypto = require('crypto');
- var constants = require('constants');
- var fs = require('fs');
- var ssh2 = require('ssh2');
- var OPEN_MODE = ssh2.SFTP_OPEN_MODE;
- var STATUS_CODE = ssh2.SFTP_STATUS_CODE;
- var allowedUser = Buffer.from('foo');
- var allowedPassword = Buffer.from('bar');
- new ssh2.Server({
- hostKeys: [fs.readFileSync('host.key')]
- }, function(client) {
- console.log('Client connected!');
- client.on('authentication', function(ctx) {
- var user = Buffer.from(ctx.username);
- if (user.length !== allowedUser.length
- || !crypto.timingSafeEqual(user, allowedUser)) {
- return ctx.reject(['password']);
- }
- switch (ctx.method) {
- case 'password':
- var password = Buffer.from(ctx.password);
- if (password.length !== allowedPassword.length
- || !crypto.timingSafeEqual(password, allowedPassword)) {
- return ctx.reject(['password']);
- }
- break;
- default:
- return ctx.reject(['password']);
- }
- ctx.accept();
- }).on('ready', function() {
- console.log('Client authenticated!');
- client.on('session', function(accept, reject) {
- var session = accept();
- session.on('sftp', function(accept, reject) {
- console.log('Client SFTP session');
- var openFiles = {};
- var handleCount = 0;
- // `sftpStream` is an `SFTPStream` instance in server mode
- // see: https://github.com/mscdex/ssh2-streams/blob/master/SFTPStream.md
- var sftpStream = accept();
- sftpStream.on('OPEN', function(reqid, filename, flags, attrs) {
- console.log('OPEN', filename);
- // only allow opening /tmp/foo.txt for writing
- if (filename !== '/tmp/foo.txt' || !(flags & OPEN_MODE.READ))
- return sftpStream.status(reqid, STATUS_CODE.FAILURE);
- // create a fake handle to return to the client, this could easily
- // be a real file descriptor number for example if actually opening
- // the file on the disk
- var handle = new Buffer(4);
- openFiles[handleCount] = { read: false };
- handle.writeUInt32BE(handleCount++, 0, true);
- sftpStream.handle(reqid, handle);
- console.log('Opening file for read')
- }).on('READ', function(reqid, handle, offset, length) {
- if (handle.length !== 4 || !openFiles[handle.readUInt32BE(0, true)])
- return sftpStream.status(reqid, STATUS_CODE.FAILURE);
- // fake the read
- var state = openFiles[handle.readUInt32BE(0, true)];
- if (state.read)
- sftpStream.status(reqid, STATUS_CODE.EOF);
- else {
- state.read = true;
- sftpStream.data(reqid, 'bar');
- console.log('Read from file at offset %d, length %d', offset, length);
- }
- }).on('CLOSE', function(reqid, handle) {
- var fnum;
- if (handle.length !== 4 || !openFiles[(fnum = handle.readUInt32BE(0, true))])
- return sftpStream.status(reqid, STATUS_CODE.FAILURE);
- delete openFiles[fnum];
- sftpStream.status(reqid, STATUS_CODE.OK);
- console.log('Closing file');
- }).on('REALPATH', function(reqid, path) {
- var name = [{
- filename: '/tmp/foo.txt',
- longname: '-rwxrwxrwx 1 foo foo 3 Dec 8 2009 foo.txt',
- attrs: {}
- }];
- sftpStream.name(reqid, name);
- }).on('STAT', onSTAT)
- .on('LSTAT', onSTAT);
- function onSTAT(reqid, path) {
- if (path !== '/tmp/foo.txt')
- return sftpStream.status(reqid, STATUS_CODE.FAILURE);
- var mode = constants.S_IFREG; // Regular file
- mode |= constants.S_IRWXU; // read, write, execute for user
- mode |= constants.S_IRWXG; // read, write, execute for group
- mode |= constants.S_IRWXO; // read, write, execute for other
- sftpStream.attrs(reqid, {
- mode: mode,
- uid: 0,
- gid: 0,
- size: 3,
- atime: Date.now(),
- mtime: Date.now()
- });
- }
- });
- });
- }).on('end', function() {
- console.log('Client disconnected');
- });
- }).listen(0, '127.0.0.1', function() {
- console.log('Listening on port ' + this.address().port);
- });
|