繁体   English   中英

SFTP 通过 HTTP 代理使用 Node.js 中的 ssh2-sftp-client 库

[英]SFTP through HTTP proxy using ssh2-sftp-client library in Node.js

我需要使用 Node.js 库ssh2-sftp-client传输文件。 我的问题是我需要通过 HTTP 代理连接。 该文档有一个 SOCKS 代理的步骤。 我想知道如何使用 HTTP 代理来实现这一点。

我的版本基于您链接中的解决方案。 所有学分 go 到https://github.com/lmdc45

import {Injectable, Logger} from '@nestjs/common';
import * as Client from 'ssh2-sftp-client'
import * as fs from "fs";
import {ConfigService} from "@nestjs/config";
import * as http from "http";
import {SocksClient} from "socks";
import {Socket} from "net";
import {SocksClientOptions} from "socks/typings/common/constants";

export type SftpProxyConfig = { targetHost: string, targetPort: number, proxyType: 'http' | 'socks4' | 'socks5', proxyHost: string, proxyPort: number }

@Injectable()
export class SftpService {

  private readonly logger = new Logger(SftpService.name);

  constructor(
    private readonly configService: ConfigService
  ) {}


  async doSftpAction(
    connectionOptions?: Client.ConnectOptions
  ) {
    const sftp = new Client();
    const connectionInfo = connectionOptions ? connectionOptions : await this.getSFTPConnectionInfo();

    let sftpWrapper;
    try {
      sftpWrapper = await sftp.connect(connectionInfo);
      
      // Here comes your code
    } catch (error) {
      this.logger.error(error.message, error);
      throw new Error(error.message);
    } finally {
      if (sftpWrapper) {
        await sftp.end();
      }
    }
  }

  private async getSFTPConnectionInfo(): Promise<Client.ConnectOptions> {
    const host = this.configService.get<string>('SFTP_HOST');
    const port = this.configService.get<number>('SFTP_PORT');
    const connectionOptions: Client.ConnectOptions = {host, port};

    const username = this.configService.get<string>('SFTP_USER');
    const password = this.configService.get<string>('SFTP_PASSWORD');
    const privateKey = this.configService.get<string>('SFTP_SSH_KEY');
    const passphrase = this.configService.get<string>('SFTP_SSH_PASSPHRASE');
    const proxyHost = this.configService.get<string>('SFTP_PROXY_HOST');
    const proxyPort = this.configService.get<number>('SFTP_PROXY_PORT');
    const proxyType = this.configService.get<'http' | 'socks4' | 'socks5'>('SFTP_PROXY_TYPE')
    const debug = this.configService.get('SFTP_DEBUG_LOG') || false;

    if (username)
      connectionOptions.username = username;
    if (password)
      connectionOptions.password = password;
    else if (privateKey) {
      connectionOptions.privateKey = fs.readFileSync(this.configService.get<string>('SFTP_SSH_KEY'));
      if (passphrase)
        connectionOptions.passphrase = passphrase;
    }
    if (proxyHost && proxyPort && proxyType)
      connectionOptions.sock = await this.getProxy({
        targetHost: host,
        targetPort: port,
        proxyHost,
        proxyPort,
        proxyType
      });
    connectionOptions.debug = JSON.parse(debug) ? information => this.logger.log(information) : undefined;
    return connectionOptions;
  }

  public async getProxy(config: SftpProxyConfig): Promise<NodeJS.ReadableStream> {
    return (config.proxyType === 'http' ?
      await this.getHttpProxy(config) :
      await this.getSocksProxy(config)) as NodeJS.ReadableStream;
  }

  private async getHttpProxy(config: SftpProxyConfig):Promise<Socket>{
    // Make a request to a tunneling proxy
    const res = new Promise<Socket>((resolve, reject) => {

      const options = {
        port: config.proxyPort,
        host: config.proxyHost,
        method: 'CONNECT',
        path: `${config.targetHost}:${config.targetPort}`
      };

      const req = http.request(options);
      req.end();

      req.on('connect', (res, socket, head) => {
        this.logger.log(`Status Code: ${res.statusCode}`);
        resolve(socket);
      });
    });
    return res;
  }

  private async getSocksProxy(config: SftpProxyConfig): Promise<Socket> { 
    const options = {
      proxy: {
        host: config.proxyHost, // ipv4 or ipv6 or hostname
        port: config.proxyPort,
        type: config.proxyType === 'socks4' ? 4 : 5 // Proxy version (4 or 5)
      },

      command: 'connect', // SOCKS command (createConnection factory function only supports the connect command)

      destination: {
        host: config.targetHost,
        port: config.targetPort
      }
    };

    const info = await SocksClient.createConnection(options as SocksClientOptions);
    return info.socket;
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM