Skip to content

Commit

Permalink
Allow storing thread credentials in phone keychain
Browse files Browse the repository at this point in the history
  • Loading branch information
bramkragten committed May 6, 2024
1 parent 43a422c commit aa34f22
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 30 deletions.
13 changes: 12 additions & 1 deletion src/external_app/external_messaging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,15 @@ interface EMOutgoingMessageAssistShow extends EMMessage {
};
}

interface EMOutgoingMessageThreadStoreInPlatformKeychain extends EMMessage {
type: "thread/store_in_platform_keychain";
payload: {
mac_extended_address: string;
border_agent_id: string | null;
active_operational_dataset: string;
};
}

type EMOutgoingMessageWithoutAnswer =
| EMMessageResultError
| EMMessageResultSuccess
Expand All @@ -146,7 +155,8 @@ type EMOutgoingMessageWithoutAnswer =
| EMOutgoingMessageMatterCommission
| EMOutgoingMessageSidebarShow
| EMOutgoingMessageTagWrite
| EMOutgoingMessageThemeUpdate;
| EMOutgoingMessageThemeUpdate
| EMOutgoingMessageThreadStoreInPlatformKeychain;

interface EMIncomingMessageRestart {
id: number;
Expand Down Expand Up @@ -239,6 +249,7 @@ export interface ExternalConfig {
hasExoPlayer: boolean;
canCommissionMatter: boolean;
canImportThreadCredentials: boolean;
canTransferThreadCredentialsToKeychain: boolean;
hasAssist: boolean;
hasBarCodeScanner: number;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { LitElement, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../../../../common/dom/fire_event";
import { HassDialog } from "../../../../../dialogs/make-dialog-manager";
import { HomeAssistant } from "../../../../../types";
import { DialogThreadDatasetParams } from "./show-dialog-thread-dataset";
import { createCloseHeading } from "../../../../../components/ha-dialog";

@customElement("ha-dialog-thread-dataset")
class DialogThreadDataset extends LitElement implements HassDialog {
@property({ attribute: false }) public hass!: HomeAssistant;

@state() private _params?: DialogThreadDatasetParams;

public async showDialog(
params: DialogThreadDatasetParams
): Promise<Promise<void>> {
this._params = params;
}

public closeDialog(): void {
this._params = undefined;
fireEvent(this, "dialog-closed", { dialog: this.localName });
}

protected render() {
if (!this._params) {
return nothing;
}
const network = this._params.network;
const dataset = network.dataset!;
const otbrInfo = this._params.otbrInfo;

const hasOTBR =
otbrInfo &&
dataset.extended_pan_id &&
otbrInfo.active_dataset_tlvs?.includes(dataset.extended_pan_id);

const canImportKeychain =
hasOTBR &&
!this.hass.auth.external?.config.canTransferThreadCredentialsToKeychain &&
network.routers?.length;

return html`<ha-dialog
open
.hideActions=${!canImportKeychain}
@closed=${this.closeDialog}
.heading=${createCloseHeading(this.hass, network.name)}
>
<div>
Network name: ${dataset.network_name}<br />
Channel: ${dataset.channel}<br />
Dataset id: ${dataset.dataset_id}<br />
Pan id: ${dataset.pan_id}<br />
Extended Pan id: ${dataset.extended_pan_id}<br />
${hasOTBR
? html`OTBR URL: ${otbrInfo.url}<br />
Active dataset TLVs: ${otbrInfo.active_dataset_tlvs}`
: nothing}
</div>
${canImportKeychain
? html`<ha-button slot="primary-action" @click=${this._sendCredentials}
>Send credentials to phone</ha-button
>`
: nothing}
</ha-dialog>`;
}

private _sendCredentials() {
this.hass.auth.external!.fireMessage({
type: "thread/store_in_platform_keychain",
payload: {
mac_extended_address:
this._params!.network.routers![0]!.extended_pan_id,
border_agent_id: this._params!.network.routers![0]!.border_agent_id,
active_operational_dataset: this._params!.otbrInfo!.active_dataset_tlvs,
},
});
}
}

declare global {
interface HTMLElementTagNameMap {
"ha-dialog-thread-dataset": DialogThreadDataset;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { fireEvent } from "../../../../../common/dom/fire_event";
import { OTBRInfo } from "../../../../../data/otbr";
import { ThreadNetwork } from "./thread-config-panel";

export interface DialogThreadDatasetParams {
network: ThreadNetwork;
otbrInfo?: OTBRInfo;
}

export const showThreadDatasetDialog = (
element: HTMLElement,
dialogParams: DialogThreadDatasetParams
): void => {
fireEvent(element, "show-dialog", {
dialogTag: "ha-dialog-thread-dataset",
dialogImport: () => import("./dialog-thread-dataset"),
dialogParams,
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,9 @@ import { HomeAssistant } from "../../../../../types";
import { brandsUrl } from "../../../../../util/brands-url";
import { fileDownload } from "../../../../../util/file_download";
import { documentationUrl } from "../../../../../util/documentation-url";
import { showThreadDatasetDialog } from "./show-dialog-thread-dataset";

interface ThreadNetwork {
export interface ThreadNetwork {
name: string;
dataset?: ThreadDataSet;
routers?: ThreadRouter[];
Expand Down Expand Up @@ -164,7 +165,7 @@ export class ThreadConfigPanel extends SubscribeMixin(LitElement) {
${network.name}${network.dataset
? html`<div>
<ha-icon-button
.networkDataset=${network.dataset}
.network=${network}
.path=${mdiInformationOutline}
@click=${this._showDatasetInfo}
></ha-icon-button
Expand Down Expand Up @@ -306,33 +307,8 @@ export class ThreadConfigPanel extends SubscribeMixin(LitElement) {
}

private async _showDatasetInfo(ev: Event) {
const dataset = (ev.currentTarget as any).networkDataset as ThreadDataSet;
if (this._otbrInfo) {
if (
dataset.extended_pan_id &&
this._otbrInfo.active_dataset_tlvs?.includes(dataset.extended_pan_id)
) {
showAlertDialog(this, {
title: dataset.network_name,
text: html`Network name: ${dataset.network_name}<br />
Channel: ${dataset.channel}<br />
Dataset id: ${dataset.dataset_id}<br />
Pan id: ${dataset.pan_id}<br />
Extended Pan id: ${dataset.extended_pan_id}<br />
OTBR URL: ${this._otbrInfo.url}<br />
Active dataset TLVs: ${this._otbrInfo.active_dataset_tlvs}`,
});
return;
}
}
showAlertDialog(this, {
title: dataset.network_name,
text: html`Network name: ${dataset.network_name}<br />
Channel: ${dataset.channel}<br />
Dataset id: ${dataset.dataset_id}<br />
Pan id: ${dataset.pan_id}<br />
Extended Pan id: ${dataset.extended_pan_id}`,
});
const network = (ev.currentTarget as any).network as ThreadNetwork;
showThreadDatasetDialog(this, { network, otbrInfo: this._otbrInfo });
}

private _importExternalThreadCredentials() {
Expand Down

0 comments on commit aa34f22

Please sign in to comment.