// Copyright (C) 2019 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import {_TextDecoder, _TextEncoder} from 'custom_utils';

import {assertExists} from '../base/logging';

import {Adb, AdbMsg, AdbStream, CmdType} from './adb_interfaces';

const textEncoder = new _TextEncoder();
const textDecoder = new _TextDecoder();

export const VERSION_WITH_CHECKSUM = 0x01000000;
export const VERSION_NO_CHECKSUM = 0x01000001;
export const DEFAULT_MAX_PAYLOAD_BYTES = 256 * 1024;

export enum AdbState {
  DISCONNECTED = 0,
  // Authentication steps, see AdbOverWebUsb's handleAuthentication().
  AUTH_STEP1 = 1,
  AUTH_STEP2 = 2,
  AUTH_STEP3 = 3,

  CONNECTED = 2,
}

enum AuthCmd {
  TOKEN = 1,
  SIGNATURE = 2,
  RSAPUBLICKEY = 3,
}

const DEVICE_NOT_SET_ERROR = 'Device not set.';

// This class is a basic TypeScript implementation of adb that only supports
// shell commands. It is used to send the start tracing command to the connected
// android device, and to automatically pull the trace after the end of the
// recording. It works through the webUSB API. A brief description of how it
// works is the following:
// - The connection with the device is initiated by findAndConnect, which shows
//   a dialog with a list of connected devices. Once one is selected the
//   authentication begins. The authentication has to pass different steps, as
//   described in the "handeAuthentication" method.
// - AdbOverWebUsb tracks the state of the authentication via a state machine
//   (see AdbState).
// - A Message handler loop is executed to keep receiving the messages.
// - All the messages received from the device are passed to "onMessage" that is
//   implemented as a state machine.
// - When a new shell is established, it becomes an AdbStream, and is kept in
//   the "streams" map. Each time a message from the device is for a specific
//   previously opened stream, the "onMessage" function will forward it to the
//   stream (identified by a number).
export class AdbOverWebUsb implements Adb {
  state: AdbState = AdbState.DISCONNECTED;
  streams = new Map<number, AdbStream>();
  devProps = '';
  maxPayload = DEFAULT_MAX_PAYLOAD_BYTES;
  key?: CryptoKeyPair;
  onConnected = () => {};

  // Devices after Dec 2017 don't use checksum. This will be auto-detected
  // during the connection.
  useChecksum = true;

  private lastStreamId = 0;
  private dev?: USBDevice;
  private usbInterfaceNumber?: number;
  private usbReadEndpoint = -1;
  private usbWriteEpEndpoint = -1;
  private filter = {
    classCode: 255,    // USB vendor specific code
    subclassCode: 66,  // Android vendor specific subclass
    protocolCode: 1,   // Adb protocol
  };

  async findDevice() {
    if (!('usb' in navigator)) {
      throw new Error('WebUSB not supported by the browser (requires HTTPS)');
    }
    return navigator.usb.requestDevice({filters: [this.filter]});
  }

  async getPairedDevices() {
    try {
      return await navigator.usb.getDevices();
    } catch (e) {  // WebUSB not available.
      return Promise.resolve([]);
    }
  }

  async connect(device: USBDevice): Promise<void> {
    // If we are already connected, we are also already authenticated, so we can
    // skip doing the authentication again.
    if (this.state === AdbState.CONNECTED) {
      if (this.dev === device && device.opened) {
        this.onConnected();
        this.onConnected = () => {};
        return;
      }
      // Another device was connected.
      await this.disconnect();
    }

    this.dev = device;
    this.useChecksum = true;
    this.key = await AdbOverWebUsb.initKey();

    await this.dev.open();

    const {configValue, usbInterfaceNumber, endpoints} =
        this.findInterfaceAndEndpoint();
    this.usbInterfaceNumber = usbInterfaceNumber;

    this.usbReadEndpoint = this.findEndpointNumber(endpoints, 'in');
    this.usbWriteEpEndpoint = this.findEndpointNumber(endpoints, 'out');

    console.assert(this.usbReadEndpoint >= 0 && this.usbWriteEpEndpoint >= 0);

    await this.dev.selectConfiguration(configValue);
    await this.dev.claimInterface(usbInterfaceNumber);

    await this.startAuthentication();

    // This will start a message handler loop.
    this.receiveDeviceMessages();
    // The promise will be resolved after the handshake.
    return new Promise<void>((resolve, _) => this.onConnected = resolve);
  }

  async disconnect(): Promise<void> {
    if (this.state === AdbState.DISCONNECTED) {
      return;
    }
    this.state = AdbState.DISCONNECTED;

    if (!this.dev) return;

    new Map(this.streams).forEach((stream, _id) => stream.setClosed());
    console.assert(this.streams.size === 0);

    await this.dev.releaseInterface(assertExists(this.usbInterfaceNumber));
    this.dev = undefined;
    this.usbInterfaceNumber = undefined;
  }

  async startAuthentication() {
    // USB connected, now let's authenticate.
    const VERSION =
        this.useChecksum ? VERSION_WITH_CHECKSUM : VERSION_NO_CHECKSUM;
    this.state = AdbState.AUTH_STEP1;
    await this.send('CNXN', VERSION, this.maxPayload, 'host:1:UsbADB');
  }

  findInterfaceAndEndpoint() {
    if (!this.dev) throw Error(DEVICE_NOT_SET_ERROR);
    for (const config of this.dev.configurations) {
      for (const interface_ of config.interfaces) {
        for (const alt of interface_.alternates) {
          if (alt.interfaceClass === this.filter.classCode &&
              alt.interfaceSubclass === this.filter.subclassCode &&
              alt.interfaceProtocol === this.filter.protocolCode) {
            return {
              configValue: config.configurationValue,
              usbInterfaceNumber: interface_.interfaceNumber,
              endpoints: alt.endpoints,
            };
          }  // if (alternate)
        }    // for (interface.alternates)
      }      // for (configuration.interfaces)
    }        // for (configurations)

    throw Error('Cannot find interfaces and endpoints');
  }

  findEndpointNumber(
      endpoints: USBEndpoint[], direction: 'out'|'in', type = 'bulk'): number {
    const ep =
        endpoints.find((ep) => ep.type === type && ep.direction === direction);

    if (ep) return ep.endpointNumber;

    throw Error(`Cannot find ${direction} endpoint`);
  }

  receiveDeviceMessages() {
    this.recv()
        .then((msg) => {
          this.onMessage(msg);
          this.receiveDeviceMessages();
        })
        .catch((e) => {
          // Ignore error with "DEVICE_NOT_SET_ERROR" message since it is always
          // thrown after the device disconnects.
          if (e.message !== DEVICE_NOT_SET_ERROR) {
            console.error(`Exception in recv: ${e.name}. error: ${e.message}`);
          }
          this.disconnect();
        });
  }

  async onMessage(msg: AdbMsg) {
    if (!this.key) throw Error('ADB key not initialized');

    if (msg.cmd === 'AUTH' && msg.arg0 === AuthCmd.TOKEN) {
      this.handleAuthentication(msg);
    } else if (msg.cmd === 'CNXN') {
      console.assert(
          [AdbState.AUTH_STEP2, AdbState.AUTH_STEP3].includes(this.state));
      this.state = AdbState.CONNECTED;
      this.handleConnectedMessage(msg);
    } else if (this.state === AdbState.CONNECTED && [
                 'OKAY',
                 'WRTE',
                 'CLSE',
               ].indexOf(msg.cmd) >= 0) {
      const stream = this.streams.get(msg.arg1);
      if (!stream) {
        console.warn(`Received message ${msg} for unknown stream ${msg.arg1}`);
        return;
      }
      stream.onMessage(msg);
    } else {
      console.error(`Unexpected message `, msg, ` in state ${this.state}`);
    }
  }

  async handleAuthentication(msg: AdbMsg) {
    if (!this.key) throw Error('ADB key not initialized');

    console.assert(msg.cmd === 'AUTH' && msg.arg0 === AuthCmd.TOKEN);
    const token = msg.data;

    if (this.state === AdbState.AUTH_STEP1) {
      // During this step, we send back the token received signed with our
      // private key. If the device has previously received our public key, the
      // dialog will not be displayed. Otherwise we will receive another message
      // ending up in AUTH_STEP3.
      this.state = AdbState.AUTH_STEP2;

      const signedToken =
          await signAdbTokenWithPrivateKey(this.key.privateKey, token);
      this.send('AUTH', AuthCmd.SIGNATURE, 0, new Uint8Array(signedToken));
      return;
    }

    console.assert(this.state === AdbState.AUTH_STEP2);

    // During this step, we send our public key. The dialog will appear, and
    // if the user chooses to remember our public key, it will be
    // saved, so that the next time we will only pass through AUTH_STEP1.
    this.state = AdbState.AUTH_STEP3;
    const encodedPubKey = await encodePubKey(this.key.publicKey);
    this.send('AUTH', AuthCmd.RSAPUBLICKEY, 0, encodedPubKey);
  }

  private handleConnectedMessage(msg: AdbMsg) {
    console.assert(msg.cmd === 'CNXN');

    this.maxPayload = msg.arg1;
    this.devProps = textDecoder.decode(msg.data);

    const deviceVersion = msg.arg0;

    if (![VERSION_WITH_CHECKSUM, VERSION_NO_CHECKSUM].includes(deviceVersion)) {
      console.error('Version ', msg.arg0, ' not really supported!');
    }
    this.useChecksum = deviceVersion === VERSION_WITH_CHECKSUM;
    this.state = AdbState.CONNECTED;

    // This will resolve the promise returned by "onConnect"
    this.onConnected();
    this.onConnected = () => {};
  }

  shell(cmd: string): Promise<AdbStream> {
    return this.openStream('shell:' + cmd);
  }

  socket(path: string): Promise<AdbStream> {
    return this.openStream('localfilesystem:' + path);
  }

  openStream(svc: string): Promise<AdbStream> {
    const stream = new AdbStreamImpl(this, ++this.lastStreamId);
    this.streams.set(stream.localStreamId, stream);
    this.send('OPEN', stream.localStreamId, 0, svc);

    //  The stream will resolve this promise once it receives the
    //  acknowledgement message from the device.
    return new Promise<AdbStream>((resolve, reject) => {
      stream.onConnect = () => {
        stream.onClose = () => {};
        resolve(stream);
      };
      stream.onClose = () =>
          reject(new Error(`Failed to openStream svc=${svc}`));
    });
  }

  async shellOutputAsString(cmd: string): Promise<string> {
    const shell = await this.shell(cmd);

    return new Promise<string>((resolve, _) => {
      const output: string[] = [];
      shell.onData = (raw) => output.push(textDecoder.decode(raw));
      shell.onClose = () => resolve(output.join());
    });
  }

  async send(
      cmd: CmdType, arg0: number, arg1: number, data?: Uint8Array|string) {
    await this.sendMsg(AdbMsgImpl.create(
        {cmd, arg0, arg1, data, useChecksum: this.useChecksum}));
  }

  //  The header and the message data must be sent consecutively. Using 2 awaits
  //  Another message can interleave after the first header has been sent,
  //  resulting in something like [header1] [header2] [data1] [data2];
  //  In this way we are waiting both promises to be resolved before continuing.
  async sendMsg(msg: AdbMsgImpl) {
    const sendPromises = [this.sendRaw(msg.encodeHeader())];
    if (msg.data.length > 0) sendPromises.push(this.sendRaw(msg.data));
    await Promise.all(sendPromises);
  }

  async recv(): Promise<AdbMsg> {
    const res = await this.recvRaw(ADB_MSG_SIZE);
    console.assert(res.status === 'ok');
    const msg = AdbMsgImpl.decodeHeader(res.data!);

    if (msg.dataLen > 0) {
      const resp = await this.recvRaw(msg.dataLen);
      msg.data = new Uint8Array(
          resp.data!.buffer, resp.data!.byteOffset, resp.data!.byteLength);
    }
    if (this.useChecksum) {
      console.assert(AdbOverWebUsb.checksum(msg.data) === msg.dataChecksum);
    }
    return msg;
  }

  static async initKey(): Promise<CryptoKeyPair> {
    const KEY_SIZE = 2048;

    const keySpec = {
      name: 'RSASSA-PKCS1-v1_5',
      modulusLength: KEY_SIZE,
      publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
      hash: {name: 'SHA-1'},
    };

    const key = await crypto.subtle.generateKey(
        keySpec, /* extractable=*/ true, ['sign', 'verify']);
    return key;
  }

  static checksum(data: Uint8Array): number {
    let res = 0;
    for (let i = 0; i < data.byteLength; i++) res += data[i];
    return res & 0xFFFFFFFF;
  }

  sendRaw(buf: Uint8Array): Promise<USBOutTransferResult> {
    console.assert(buf.length <= this.maxPayload);
    if (!this.dev) throw Error(DEVICE_NOT_SET_ERROR);
    return this.dev.transferOut(this.usbWriteEpEndpoint, buf.buffer);
  }

  recvRaw(dataLen: number): Promise<USBInTransferResult> {
    if (!this.dev) throw Error(DEVICE_NOT_SET_ERROR);
    return this.dev.transferIn(this.usbReadEndpoint, dataLen);
  }
}

enum AdbStreamState {
  WAITING_INITIAL_OKAY = 0,
  CONNECTED = 1,
  CLOSED = 2
}


// An AdbStream is instantiated after the creation of a shell to the device.
// Thanks to this, we can send commands and receive their output. Messages are
// received in the main adb class, and are forwarded to an instance of this
// class based on a stream id match. Also streams have an initialization flow:
//   1. WAITING_INITIAL_OKAY: waiting for first "OKAY" message. Once received,
//      the next state will be "CONNECTED".
//   2. CONNECTED: ready to receive or send messages.
//   3. WRITING: this is needed because we must receive an ack after sending
//      each message (so, before sending the next one). For this reason, many
//      subsequent "write" calls will result in different messages in the
//      writeQueue. After each new acknowledgement ('OKAY') a new one will be
//      sent. When the queue is empty, the state will return to CONNECTED.
//   4. CLOSED: entered when the device closes the stream or close() is called.
//      For shell commands, the stream is closed after the command completed.
export class AdbStreamImpl implements AdbStream {
  private adb: AdbOverWebUsb;
  localStreamId: number;
  private remoteStreamId = -1;
  private state: AdbStreamState = AdbStreamState.WAITING_INITIAL_OKAY;
  private writeQueue: Uint8Array[] = [];

  private sendInProgress = false;

  onData: AdbStreamReadCallback = (_) => {};
  onConnect = () => {};
  onClose = () => {};

  constructor(adb: AdbOverWebUsb, localStreamId: number) {
    this.adb = adb;
    this.localStreamId = localStreamId;
  }

  close() {
    console.assert(this.state === AdbStreamState.CONNECTED);

    if (this.writeQueue.length > 0) {
      console.error(`Dropping ${
          this.writeQueue.length} queued messages due to stream closing.`);
      this.writeQueue = [];
    }

    this.adb.send('CLSE', this.localStreamId, this.remoteStreamId);
  }

  async write(msg: string|Uint8Array) {
    const raw = (typeof msg === 'string') ? textEncoder.encode(msg) : msg;
    if (this.sendInProgress ||
        this.state === AdbStreamState.WAITING_INITIAL_OKAY) {
      this.writeQueue.push(raw);
      return;
    }
    console.assert(this.state === AdbStreamState.CONNECTED);
    this.sendInProgress = true;
    await this.adb.send('WRTE', this.localStreamId, this.remoteStreamId, raw);
  }

  setClosed() {
    this.state = AdbStreamState.CLOSED;
    this.adb.streams.delete(this.localStreamId);
    this.onClose();
  }

  onMessage(msg: AdbMsgImpl) {
    console.assert(msg.arg1 === this.localStreamId);

    if (this.state === AdbStreamState.WAITING_INITIAL_OKAY &&
        msg.cmd === 'OKAY') {
      this.remoteStreamId = msg.arg0;
      this.state = AdbStreamState.CONNECTED;
      this.onConnect();
      return;
    }

    if (msg.cmd === 'WRTE') {
      this.adb.send('OKAY', this.localStreamId, this.remoteStreamId);
      this.onData(msg.data);
      return;
    }

    if (msg.cmd === 'OKAY') {
      console.assert(this.sendInProgress);
      this.sendInProgress = false;
      const queuedMsg = this.writeQueue.shift();
      if (queuedMsg !== undefined) this.write(queuedMsg);
      return;
    }

    if (msg.cmd === 'CLSE') {
      this.setClosed();
      return;
    }
    console.error(
        `Unexpected stream msg ${msg.toString()} in state ${this.state}`);
  }
}

interface AdbStreamReadCallback {
  (raw: Uint8Array): void;
}

const ADB_MSG_SIZE = 6 * 4;  // 6 * int32.

export class AdbMsgImpl implements AdbMsg {
  cmd: CmdType;
  arg0: number;
  arg1: number;
  data: Uint8Array;
  dataLen: number;
  dataChecksum: number;

  useChecksum: boolean;

  constructor(
      cmd: CmdType, arg0: number, arg1: number, dataLen: number,
      dataChecksum: number, useChecksum = false) {
    console.assert(cmd.length === 4);
    this.cmd = cmd;
    this.arg0 = arg0;
    this.arg1 = arg1;
    this.dataLen = dataLen;
    this.data = new Uint8Array(dataLen);
    this.dataChecksum = dataChecksum;
    this.useChecksum = useChecksum;
  }


  static create({cmd, arg0, arg1, data, useChecksum = true}: {
    cmd: CmdType; arg0: number; arg1: number;
    data?: Uint8Array | string;
    useChecksum?: boolean;
  }): AdbMsgImpl {
    const encodedData = this.encodeData(data);
    const msg =
        new AdbMsgImpl(cmd, arg0, arg1, encodedData.length, 0, useChecksum);
    msg.data = encodedData;
    return msg;
  }

  get dataStr() {
    return textDecoder.decode(this.data);
  }

  toString() {
    return `${this.cmd} [${this.arg0},${this.arg1}] ${this.dataStr}`;
  }

  // A brief description of the message can be found here:
  // https://android.googlesource.com/platform/system/core/+/main/adb/protocol.txt
  //
  // struct amessage {
  //     uint32_t command;    // command identifier constant
  //     uint32_t arg0;       // first argument
  //     uint32_t arg1;       // second argument
  //     uint32_t data_length;// length of payload (0 is allowed)
  //     uint32_t data_check; // checksum of data payload
  //     uint32_t magic;      // command ^ 0xffffffff
  // };
  static decodeHeader(dv: DataView): AdbMsgImpl {
    console.assert(dv.byteLength === ADB_MSG_SIZE);
    const cmd = textDecoder.decode(dv.buffer.slice(0, 4)) as CmdType;
    const cmdNum = dv.getUint32(0, true);
    const arg0 = dv.getUint32(4, true);
    const arg1 = dv.getUint32(8, true);
    const dataLen = dv.getUint32(12, true);
    const dataChecksum = dv.getUint32(16, true);
    const cmdChecksum = dv.getUint32(20, true);
    console.assert(cmdNum === (cmdChecksum ^ 0xFFFFFFFF));
    return new AdbMsgImpl(cmd, arg0, arg1, dataLen, dataChecksum);
  }

  encodeHeader(): Uint8Array {
    const buf = new Uint8Array(ADB_MSG_SIZE);
    const dv = new DataView(buf.buffer);
    const cmdBytes: Uint8Array = textEncoder.encode(this.cmd);
    const rawMsg = AdbMsgImpl.encodeData(this.data);
    const checksum = this.useChecksum ? AdbOverWebUsb.checksum(rawMsg) : 0;
    for (let i = 0; i < 4; i++) dv.setUint8(i, cmdBytes[i]);

    dv.setUint32(4, this.arg0, true);
    dv.setUint32(8, this.arg1, true);
    dv.setUint32(12, rawMsg.byteLength, true);
    dv.setUint32(16, checksum, true);
    dv.setUint32(20, dv.getUint32(0, true) ^ 0xFFFFFFFF, true);

    return buf;
  }

  static encodeData(data?: Uint8Array|string): Uint8Array {
    if (data === undefined) return new Uint8Array([]);
    if (typeof data === 'string') return textEncoder.encode(data + '\0');
    return data;
  }
}


function base64StringToArray(s: string) {
  const decoded = atob(s.replaceAll('-', '+').replaceAll('_', '/'));
  return [...decoded].map((char) => char.charCodeAt(0));
}

const ANDROID_PUBKEY_MODULUS_SIZE = 2048;
const MODULUS_SIZE_BYTES = ANDROID_PUBKEY_MODULUS_SIZE / 8;

// RSA Public keys are encoded in a rather unique way. It's a base64 encoded
// struct of 524 bytes in total as follows (see
// libcrypto_utils/android_pubkey.c):
//
// typedef struct RSAPublicKey {
//   // Modulus length. This must be ANDROID_PUBKEY_MODULUS_SIZE.
//   uint32_t modulus_size_words;
//
//   // Precomputed montgomery parameter: -1 / n[0] mod 2^32
//   uint32_t n0inv;
//
//   // RSA modulus as a little-endian array.
//   uint8_t modulus[ANDROID_PUBKEY_MODULUS_SIZE];
//
//   // Montgomery parameter R^2 as a little-endian array of little-endian
//   words. uint8_t rr[ANDROID_PUBKEY_MODULUS_SIZE];
//
//   // RSA modulus: 3 or 65537
//   uint32_t exponent;
// } RSAPublicKey;
//
// However, the Montgomery params (n0inv and rr) are not really used, see
// comment in android_pubkey_decode() ("Note that we don't extract the
// montgomery parameters...")
async function encodePubKey(key: CryptoKey) {
  const expPubKey = await crypto.subtle.exportKey('jwk', key);
  const nArr = base64StringToArray(expPubKey.n as string).reverse();
  const eArr = base64StringToArray(expPubKey.e as string).reverse();

  const arr = new Uint8Array(3 * 4 + 2 * MODULUS_SIZE_BYTES);
  const dv = new DataView(arr.buffer);
  dv.setUint32(0, MODULUS_SIZE_BYTES / 4, true);

  // The Mongomery params (n0inv and rr) are not computed.
  dv.setUint32(4, 0 /* n0inv*/, true);
  // Modulus
  for (let i = 0; i < MODULUS_SIZE_BYTES; i++) dv.setUint8(8 + i, nArr[i]);

  // rr:
  for (let i = 0; i < MODULUS_SIZE_BYTES; i++) {
    dv.setUint8(8 + MODULUS_SIZE_BYTES + i, 0 /* rr*/);
  }
  // Exponent
  for (let i = 0; i < 4; i++) {
    dv.setUint8(8 + (2 * MODULUS_SIZE_BYTES) + i, eArr[i]);
  }
  return btoa(String.fromCharCode(...new Uint8Array(dv.buffer))) +
      ' perfetto@webusb';
}

// TODO(nicomazz): This token signature will be useful only when we save the
// generated keys. So far, we are not doing so. As a consequence, a dialog is
// displayed every time a tracing session is started.
// The reason why it has not already been implemented is that the standard
// crypto.subtle.sign function assumes that the input needs hashing, which is
// not the case for ADB, where the 20 bytes token is already hashed.
// A solution to this is implementing a custom private key signature with a js
// implementation of big integers. Maybe, wrapping the key like in the following
// CL can work:
// https://android-review.googlesource.com/c/platform/external/perfetto/+/1105354/18
async function signAdbTokenWithPrivateKey(
    _privateKey: CryptoKey, token: Uint8Array): Promise<ArrayBuffer> {
  // This function is not implemented.
  return token.buffer;
}
