mirror of
				https://github.com/Ylianst/MeshCentral.git
				synced 2025-03-09 15:40:18 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			327 lines
		
	
	
	
		
			8.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			327 lines
		
	
	
	
		
			8.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
const type = require('../../core').type;
 | 
						|
const EventEmitter = require('events').EventEmitter;
 | 
						|
const caps = require('./caps');
 | 
						|
const log = require('../../core').log;
 | 
						|
const data = require('./data');
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * Cliprdr channel for all clipboard
 | 
						|
 * capabilities exchange
 | 
						|
 */
 | 
						|
class Cliprdr extends EventEmitter {
 | 
						|
 | 
						|
  constructor(transport) {
 | 
						|
    super();
 | 
						|
    this.transport = transport;
 | 
						|
    // must be init via connect event
 | 
						|
    this.userId = 0;
 | 
						|
    this.serverCapabilities = [];
 | 
						|
    this.clientCapabilities = [];
 | 
						|
  }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * Client side of Cliprdr channel automata
 | 
						|
 * @param transport
 | 
						|
 */
 | 
						|
class Client extends Cliprdr {
 | 
						|
 | 
						|
  constructor(transport, fastPathTransport) {
 | 
						|
 | 
						|
    super(transport, fastPathTransport);
 | 
						|
 | 
						|
    this.transport.once('connect', (gccCore, userId, channelId) => {
 | 
						|
      this.connect(gccCore, userId, channelId);
 | 
						|
    }).on('close', () => {
 | 
						|
      this.emit('close');
 | 
						|
    }).on('error', (err) => {
 | 
						|
      this.emit('error', err);
 | 
						|
    });
 | 
						|
 | 
						|
    this.content = '';
 | 
						|
    
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * connect function
 | 
						|
   * @param gccCore {type.Component(clientCoreData)}
 | 
						|
   */
 | 
						|
  connect(gccCore, userId, channelId) {
 | 
						|
    this.gccCore = gccCore;
 | 
						|
    this.userId = userId;
 | 
						|
    this.channelId = channelId;
 | 
						|
    this.transport.once('cliprdr', (s) => {
 | 
						|
      this.recv(s);
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  send(message) {
 | 
						|
    this.transport.send('cliprdr', new type.Component([
 | 
						|
      // Channel PDU Header
 | 
						|
      new type.UInt32Le(message.size()),
 | 
						|
      // CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST | CHANNEL_FLAG_SHOW_PROTOCOL
 | 
						|
      new type.UInt32Le(0x13),
 | 
						|
      message
 | 
						|
    ]));
 | 
						|
  };
 | 
						|
 | 
						|
  recv(s) {
 | 
						|
    s.offset = 18;
 | 
						|
    const pdu = data.clipPDU().read(s), type = data.ClipPDUMsgType;
 | 
						|
 | 
						|
    switch (pdu.obj.header.obj.msgType.value) {
 | 
						|
      case type.CB_MONITOR_READY:
 | 
						|
        this.recvMonitorReadyPDU(s);
 | 
						|
        break;
 | 
						|
      case type.CB_FORMAT_LIST:
 | 
						|
        this.recvFormatListPDU(s);
 | 
						|
        break;
 | 
						|
      case type.CB_FORMAT_LIST_RESPONSE:
 | 
						|
        this.recvFormatListResponsePDU(s);
 | 
						|
        break;
 | 
						|
      case type.CB_FORMAT_DATA_REQUEST:
 | 
						|
        this.recvFormatDataRequestPDU(s);
 | 
						|
        break;
 | 
						|
      case type.CB_FORMAT_DATA_RESPONSE:
 | 
						|
        this.recvFormatDataResponsePDU(s);
 | 
						|
        break;
 | 
						|
      case type.CB_TEMP_DIRECTORY:
 | 
						|
        break;
 | 
						|
      case type.CB_CLIP_CAPS:
 | 
						|
        this.recvClipboardCapsPDU(s);
 | 
						|
        break;
 | 
						|
      case type.CB_FILECONTENTS_REQUEST:
 | 
						|
    }
 | 
						|
 | 
						|
    this.transport.once('cliprdr', (s) => {
 | 
						|
      this.recv(s);
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Receive capabilities from server
 | 
						|
   * @param s {type.Stream}
 | 
						|
   */
 | 
						|
  recvClipboardCapsPDU(s) {
 | 
						|
    // Start at 18
 | 
						|
    s.offset = 18;
 | 
						|
    // const pdu = data.clipPDU().read(s);
 | 
						|
    // console.log('recvClipboardCapsPDU', s);
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /**
 | 
						|
   * Receive monitor ready from server
 | 
						|
   * @param s {type.Stream}
 | 
						|
   */
 | 
						|
  recvMonitorReadyPDU(s) {
 | 
						|
    s.offset = 18;
 | 
						|
    // const pdu = data.clipPDU().read(s);
 | 
						|
    // console.log('recvMonitorReadyPDU', s);
 | 
						|
 | 
						|
    this.sendClipboardCapsPDU();
 | 
						|
    // this.sendClientTemporaryDirectoryPDU();
 | 
						|
    this.sendFormatListPDU();
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /**
 | 
						|
   * Send clipboard capabilities PDU
 | 
						|
   */
 | 
						|
  sendClipboardCapsPDU() {
 | 
						|
    this.send(new type.Component({
 | 
						|
      msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_CLIP_CAPS),
 | 
						|
      msgFlags: new type.UInt16Le(0x00),
 | 
						|
      dataLen: new type.UInt32Le(0x10),
 | 
						|
      cCapabilitiesSets: new type.UInt16Le(0x01),
 | 
						|
      pad1: new type.UInt16Le(0x00),
 | 
						|
      capabilitySetType: new type.UInt16Le(0x01),
 | 
						|
      lengthCapability: new type.UInt16Le(0x0c),
 | 
						|
      version: new type.UInt32Le(0x02),
 | 
						|
      capabilityFlags: new type.UInt32Le(0x02)
 | 
						|
    }));
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /**
 | 
						|
   * Send client temporary directory PDU
 | 
						|
   */
 | 
						|
  sendClientTemporaryDirectoryPDU(path = '') {
 | 
						|
    // TODO
 | 
						|
    this.send(new type.Component({
 | 
						|
      msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_TEMP_DIRECTORY),
 | 
						|
      msgFlags: new type.UInt16Le(0x00),
 | 
						|
      dataLen: new type.UInt32Le(0x0208),
 | 
						|
      wszTempDir: new type.BinaryString(Buffer.from('D:\\Vectors' + Array(251).join('\x00'), 'ucs2'), { readLength : new type.CallableValue(520)})
 | 
						|
    }));
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /**
 | 
						|
   * Send format list PDU
 | 
						|
   */
 | 
						|
  sendFormatListPDU() {
 | 
						|
    this.send(new type.Component({
 | 
						|
      msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_FORMAT_LIST),
 | 
						|
      msgFlags: new type.UInt16Le(0x00),
 | 
						|
 | 
						|
      dataLen: new type.UInt32Le(0x24),
 | 
						|
 | 
						|
      formatId6: new type.UInt32Le(0xc004),
 | 
						|
      formatName6: new type.BinaryString(Buffer.from('Native\x00' , 'ucs2'), { readLength : new type.CallableValue(14)}),
 | 
						|
 | 
						|
      formatId8: new type.UInt32Le(0x0d),
 | 
						|
      formatName8: new type.UInt16Le(0x00),
 | 
						|
 | 
						|
      formatId9: new type.UInt32Le(0x10),
 | 
						|
      formatName9: new type.UInt16Le(0x00),
 | 
						|
 | 
						|
      formatId0: new type.UInt32Le(0x01),
 | 
						|
      formatName0: new type.UInt16Le(0x00),
 | 
						|
      
 | 
						|
      // dataLen: new type.UInt32Le(0xe0),
 | 
						|
 | 
						|
      // formatId1: new type.UInt32Le(0xc08a),
 | 
						|
      // formatName1: new type.BinaryString(Buffer.from('Rich Text Format\x00' , 'ucs2'), { readLength : new type.CallableValue(34)}),
 | 
						|
 | 
						|
      // formatId2: new type.UInt32Le(0xc145),
 | 
						|
      // formatName2: new type.BinaryString(Buffer.from('Rich Text Format Without Objects\x00' , 'ucs2'), { readLength : new type.CallableValue(66)}),
 | 
						|
 | 
						|
      // formatId3: new type.UInt32Le(0xc143),
 | 
						|
      // formatName3: new type.BinaryString(Buffer.from('RTF As Text\x00' , 'ucs2'), { readLength : new type.CallableValue(24)}),
 | 
						|
 | 
						|
      // formatId4: new type.UInt32Le(0x01),
 | 
						|
      // formatName4: new type.BinaryString(0x00),
 | 
						|
 | 
						|
      formatId5: new type.UInt32Le(0x07),
 | 
						|
      formatName5: new type.UInt16Le(0x00),
 | 
						|
 | 
						|
      // formatId6: new type.UInt32Le(0xc004),
 | 
						|
      // formatName6: new type.BinaryString(Buffer.from('Native\x00' , 'ucs2'), { readLength : new type.CallableValue(14)}),
 | 
						|
      
 | 
						|
      // formatId7: new type.UInt32Le(0xc00e),
 | 
						|
      // formatName7: new type.BinaryString(Buffer.from('Object Descriptor\x00' , 'ucs2'), { readLength : new type.CallableValue(36)}),
 | 
						|
 | 
						|
      // formatId8: new type.UInt32Le(0x03),
 | 
						|
      // formatName8: new type.UInt16Le(0x00),
 | 
						|
 | 
						|
      // formatId9: new type.UInt32Le(0x10),
 | 
						|
      // formatName9: new type.UInt16Le(0x00),
 | 
						|
 | 
						|
      // formatId0: new type.UInt32Le(0x07),
 | 
						|
      // formatName0: new type.UInt16Le(0x00),
 | 
						|
    }));
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Recvie format list PDU from server
 | 
						|
   * @param {type.Stream} s 
 | 
						|
   */
 | 
						|
  recvFormatListPDU(s) {
 | 
						|
    s.offset = 18;
 | 
						|
    // const pdu = data.clipPDU().read(s);
 | 
						|
    // console.log('recvFormatListPDU', s);
 | 
						|
    this.sendFormatListResponsePDU();
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /**
 | 
						|
   * Send format list reesponse
 | 
						|
   */
 | 
						|
   sendFormatListResponsePDU() {
 | 
						|
     this.send(new type.Component({
 | 
						|
        msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_FORMAT_LIST_RESPONSE),
 | 
						|
        msgFlags: new type.UInt16Le(0x01),
 | 
						|
        dataLen: new type.UInt32Le(0x00),
 | 
						|
     }));
 | 
						|
 | 
						|
     this.sendFormatDataRequestPDU();
 | 
						|
   }
 | 
						|
 | 
						|
 | 
						|
  /**
 | 
						|
   * Receive format list response from server
 | 
						|
   * @param s {type.Stream}
 | 
						|
   */
 | 
						|
  recvFormatListResponsePDU(s) {
 | 
						|
    s.offset = 18;
 | 
						|
    // const pdu = data.clipPDU().read(s);
 | 
						|
    // console.log('recvFormatListResponsePDU', s);
 | 
						|
    // this.sendFormatDataRequestPDU();
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /**
 | 
						|
   * Send format data request PDU
 | 
						|
   */
 | 
						|
  sendFormatDataRequestPDU(formartId = 0x0d) {
 | 
						|
    this.send(new type.Component({
 | 
						|
      msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_FORMAT_DATA_REQUEST),
 | 
						|
      msgFlags: new type.UInt16Le(0x00),
 | 
						|
      dataLen: new type.UInt32Le(0x04),
 | 
						|
      requestedFormatId: new type.UInt32Le(formartId),
 | 
						|
    }));
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /**
 | 
						|
   * Receive format data request PDU from server
 | 
						|
   * @param s {type.Stream}
 | 
						|
   */
 | 
						|
  recvFormatDataRequestPDU(s) {
 | 
						|
    s.offset = 18;
 | 
						|
    // const pdu = data.clipPDU().read(s);
 | 
						|
    // console.log('recvFormatDataRequestPDU', s);
 | 
						|
    this.sendFormatDataResponsePDU();
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /**
 | 
						|
   * Send format data reesponse PDU
 | 
						|
   */
 | 
						|
  sendFormatDataResponsePDU() {
 | 
						|
    
 | 
						|
    const bufs = Buffer.from(this.content + '\x00' , 'ucs2');
 | 
						|
 | 
						|
    this.send(new type.Component({
 | 
						|
      msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_FORMAT_DATA_RESPONSE),
 | 
						|
      msgFlags: new type.UInt16Le(0x01),
 | 
						|
      dataLen: new type.UInt32Le(bufs.length),
 | 
						|
      requestedFormatData: new type.BinaryString(bufs, { readLength : new type.CallableValue(bufs.length)})
 | 
						|
    }));
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /**
 | 
						|
   * Receive format data response PDU from server
 | 
						|
   * @param s {type.Stream}
 | 
						|
   */
 | 
						|
  recvFormatDataResponsePDU(s) {
 | 
						|
    s.offset = 18;
 | 
						|
    // const pdu = data.clipPDU().read(s);
 | 
						|
    const str = s.buffer.toString('ucs2', 26, s.buffer.length-2);
 | 
						|
    // console.log('recvFormatDataResponsePDU', str);
 | 
						|
    this.content = str;
 | 
						|
    this.emit('clipboard', str)
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
// =====================================================================================
 | 
						|
  setClipboardData(content) {
 | 
						|
    this.content = content;
 | 
						|
    this.sendFormatListPDU();
 | 
						|
  }
 | 
						|
 | 
						|
}
 | 
						|
	
 | 
						|
 | 
						|
module.exports = {
 | 
						|
  Client
 | 
						|
}
 |