chromium/chrome/browser/resources/ash/settings/internet_page/hotspot_config_dialog.ts

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

/**
 * @fileoverview Polymer element to set hotspot configuration
 */

import 'chrome://resources/ash/common/cr_elements/cr_button/cr_button.js';
import 'chrome://resources/ash/common/cr_elements/cr_dialog/cr_dialog.js';
import './internet_shared.css.js';

import {getHotspotConfig} from 'chrome://resources/ash/common/hotspot/cros_hotspot_config.js';
import {HotspotConfig, HotspotInfo, SetHotspotConfigResult, WiFiBand, WiFiSecurityMode} from 'chrome://resources/ash/common/hotspot/cros_hotspot_config.mojom-webui.js';
import {CrDialogElement} from 'chrome://resources/ash/common/cr_elements/cr_dialog/cr_dialog.js';
import {I18nMixin} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js';
import {assertNotReached} from 'chrome://resources/js/assert.js';
import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';

import {castExists} from '../assert_extras.js';

import {getTemplate} from './hotspot_config_dialog.html.js';

export enum WiFiSecurityType {
  WPA2 = 'WPA2',
  WPA3 = 'WPA3',
  WPA2WPA3 = 'WPA2WPA3',
}

const MIN_WIFI_PASSWORD_LENGTH = 8;
const MAX_WIFI_PASSWORD_LENGTH = 63;
const MAX_HOTSPOT_SSID_LENGTH = 32;

export interface HotspotConfigDialogElement {
  $: {
    dialog: CrDialogElement,
  };
}

const HotspotConfigDialogElementBase = I18nMixin(PolymerElement);

export class HotspotConfigDialogElement extends HotspotConfigDialogElementBase {
  static get is() {
    return 'hotspot-config-dialog' as const;
  }

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

  static get properties() {
    return {
      hotspotInfo: {
        type: Object,
      },

      hotspotSsid_: {
        type: String,
        value: '',
        observer: 'onSsidChanged_',
      },

      isSsidInvalid_: {
        type: Boolean,
        value: false,
      },

      hotspotPassword_: {
        type: String,
        value: '',
        observer: 'onPasswordChanged_',
      },

      isPasswordInvalid_: {
        type: Boolean,
        value: false,
      },

      securityType_: {
        type: String,
        value: '',
      },

      isRandomizeBssidToggleOn_: {
        type: Boolean,
        value: true,
      },

      isExtendCompatibilityToggleOn_: {
        type: Boolean,
        value: false,
      },

      error_: {
        type: String,
        value: '',
      },
    };
  }

  hotspotInfo: HotspotInfo;
  private hotspotSsid_: string;
  private isSsidInvalid_: boolean;
  private hotspotPassword_: string;
  private isPasswordInvalid_: boolean;
  private securityType_: string;
  private isRandomizeBssidToggleOn_: boolean;
  private isExtendCompatibilityToggleOn_: boolean;
  private error_: string;

  override connectedCallback(): void {
    super.connectedCallback();

    this.init_();
  }

  private init_(): void {
    this.hotspotSsid_ = castExists(this.hotspotInfo.config!.ssid);
    this.hotspotPassword_ = castExists(this.hotspotInfo.config!.passphrase);
    this.isRandomizeBssidToggleOn_ =
        castExists(this.hotspotInfo.config!.bssidRandomization);
    this.isExtendCompatibilityToggleOn_ =
        this.hotspotInfo.config!.band === WiFiBand.k2_4GHz;
    this.securityType_ = this.getWifiSecurityTypeString_(
        castExists(this.hotspotInfo.config!.security));
  }

  private onSsidChanged_(): void {
    this.isSsidInvalid_ = this.hotspotSsid_.length === 0 ||
        this.hotspotSsid_.length > MAX_HOTSPOT_SSID_LENGTH;
  }

  private onPasswordChanged_(): void {
    this.isPasswordInvalid_ =
        this.hotspotPassword_.length < MIN_WIFI_PASSWORD_LENGTH ||
        this.hotspotPassword_.length > MAX_WIFI_PASSWORD_LENGTH;
  }

  private getWifiSecurityTypeString_(security: WiFiSecurityMode): string {
    if (security === WiFiSecurityMode.kWpa2) {
      return WiFiSecurityType.WPA2;
    }
    if (security === WiFiSecurityMode.kWpa3) {
      return WiFiSecurityType.WPA3;
    }
    if (security === WiFiSecurityMode.kWpa2Wpa3) {
      return WiFiSecurityType.WPA2WPA3;
    }
    assertNotReached();
  }

  private getSecurityModeFromString_(security: string): WiFiSecurityMode {
    if (security === WiFiSecurityType.WPA2) {
      return WiFiSecurityMode.kWpa2;
    }
    if (security === WiFiSecurityType.WPA3) {
      return WiFiSecurityMode.kWpa3;
    }
    if (security === WiFiSecurityType.WPA2WPA3) {
      return WiFiSecurityMode.kWpa2Wpa3;
    }
    assertNotReached();
  }

  private getSecurityItems_(): string[] {
    return this.hotspotInfo!.allowedWifiSecurityModes.map(security => {
      return this.getWifiSecurityTypeString_(security);
    });
  }

  private getSsidInputInfoClass_(): string {
    if (!this.isSsidInvalid_) {
      return 'input-info';
    }
    return 'input-info error';
  }

  private getSsidInputInfo_(): string {
    if (this.hotspotSsid_.length === 0) {
      return this.i18n('hotspotConfigNameEmptyInfo');
    }
    if (this.hotspotSsid_.length > MAX_HOTSPOT_SSID_LENGTH) {
      return this.i18n('hotspotConfigNameTooLongInfo');
    }
    return this.i18n('hotspotConfigNameInfo');
  }

  private getPasswordInputInfoClass_(): string {
    if (!this.isPasswordInvalid_) {
      return 'input-info';
    }
    return 'input-info error';
  }

  private isSaveButtonDisabled_(): boolean {
    return this.isSsidInvalid_ || this.isPasswordInvalid_;
  }

  private onCancelClick_(): void {
    this.$.dialog.close();
  }

  private async onSaveClick_(): Promise<void> {
    const configToSet: HotspotConfig = {
      ssid: this.hotspotSsid_,
      passphrase: this.hotspotPassword_,
      security: this.getSecurityModeFromString_(this.securityType_),
      band: this.isExtendCompatibilityToggleOn_ ? WiFiBand.k2_4GHz :
                                                  WiFiBand.kAutoChoose,
      bssidRandomization: this.isRandomizeBssidToggleOn_,
      autoDisable: castExists(this.hotspotInfo.config!.autoDisable),
    };
    const response = await getHotspotConfig().setHotspotConfig(configToSet);
    if (response.result === SetHotspotConfigResult.kSuccess) {
      this.$.dialog.close();
      return;
    }
    if (response.result ===
        SetHotspotConfigResult.kFailedInvalidConfiguration) {
      this.error_ = this.i18n('hotspotConfigInvalidConfigurationErrorMessage');
    } else if (response.result === SetHotspotConfigResult.kFailedNotLogin) {
      this.error_ = this.i18n('hotspotConfigNotLoginErrorMessage');
    } else {
      this.error_ = this.i18n('hotspotConfigGeneralErrorMessage');
    }
  }
}

declare global {
  interface HTMLElementTagNameMap {
    [HotspotConfigDialogElement.is]: HotspotConfigDialogElement;
  }
}

customElements.define(
    HotspotConfigDialogElement.is, HotspotConfigDialogElement);