chromium/chrome/browser/resources/settings/privacy_page/security_keys_phones_subpage.ts

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * @fileoverview A settings subpage that allows the user to see and manage the
    set of phones that are usable as security keys.
 */
import '../settings_shared.css.js';

import {assert} from 'chrome://resources/js/assert.js';
import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';

import type {SecurityKeysPhone, SecurityKeysPhonesBrowserProxy, SecurityKeysPhonesList} from './security_keys_browser_proxy.js';
import {SecurityKeysPhonesBrowserProxyImpl} from './security_keys_browser_proxy.js';
import {getTemplate} from './security_keys_phones_subpage.html.js';

declare global {
  interface HTMLElementEventMap {
    'edit-security-key-phone': CustomEvent<string>;
    'delete-security-key-phone': CustomEvent<string>;
  }
}

export class SecurityKeysPhonesSubpageElement extends PolymerElement {
  static get is() {
    return 'security-keys-phones-subpage';
  }

  static get template() {
    return getTemplate();
  }

  private syncedPhones_: SecurityKeysPhone[];
  private linkedPhones_: SecurityKeysPhone[];
  private showDialog_: boolean;
  private dialogName_: string;
  private dialogPublicKey_: string;
  private browserProxy_: SecurityKeysPhonesBrowserProxy =
      SecurityKeysPhonesBrowserProxyImpl.getInstance();

  override ready() {
    super.ready();

    this.addEventListener(
        'edit-security-key-phone', this.editPhone_.bind(this));
    this.addEventListener(
        'delete-security-key-phone', this.deletePhone_.bind(this));

    this.browserProxy_.enumerate().then(this.onEnumerateComplete_.bind(this));
  }

  /**
   * Called when the browser has a new set of phone details.
   */
  private onEnumerateComplete_([syncedPhones, linkedPhones]:
                                   SecurityKeysPhonesList) {
    this.syncedPhones_ = syncedPhones;
    this.linkedPhones_ = linkedPhones;
  }

  /**
   * Called when the user clicks "Edit" in a drop-down menu to open the dialog.
   */
  private editPhone_(e: CustomEvent<string>) {
    this.dialogPublicKey_ = e.detail;
    this.dialogName_ = this.nameFromPublicKey_(e.detail);
    this.showDialog_ = true;
  }

  /**
   * Called when an edit dialog as closed (whether successful or not).
   */
  private onDialogClose_() {
    this.showDialog_ = false;
    // The dialog may have renamed a phone so refresh the lists.
    this.browserProxy_.enumerate().then(this.onEnumerateComplete_.bind(this));
  }

  /**
   * Called when the user clicks "Delete" in a drop-down menu to delete a linked
   * phone.
   */
  private deletePhone_(e: CustomEvent<string>) {
    this.browserProxy_.delete(e.detail).then(
        this.onEnumerateComplete_.bind(this));
  }

  /**
   * Returns the name of a linked phone given its public key.
   */
  private nameFromPublicKey_(publicKey: string): string {
    const matchingPhones =
        this.linkedPhones_.filter(phone => phone.publicKey === publicKey);
    assert(matchingPhones.length !== 0);
    return matchingPhones[0].name;
  }
}

declare global {
  interface HTMLElementTagNameMap {
    'security-keys-phones-subpage': SecurityKeysPhonesSubpageElement;
  }
}

customElements.define(
    SecurityKeysPhonesSubpageElement.is, SecurityKeysPhonesSubpageElement);