Add strict connection cloud settings (#20585)

* Add strict connection cloud settings

* Change static page to guard page

* saving files helps...

* Add create link button

* use correct service
This commit is contained in:
Bram Kragten 2024-04-24 11:06:15 +02:00 committed by GitHub
parent 62de16bb8e
commit 67c60a4aa8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 133 additions and 10 deletions

View File

@ -111,7 +111,7 @@
"fuse.js": "7.0.0", "fuse.js": "7.0.0",
"google-timezones-json": "1.2.0", "google-timezones-json": "1.2.0",
"hls.js": "patch:hls.js@npm%3A1.5.7#~/.yarn/patches/hls.js-npm-1.5.7-f5bbd3d060.patch", "hls.js": "patch:hls.js@npm%3A1.5.7#~/.yarn/patches/hls.js-npm-1.5.7-f5bbd3d060.patch",
"home-assistant-js-websocket": "9.2.1", "home-assistant-js-websocket": "9.3.0",
"idb-keyval": "6.2.1", "idb-keyval": "6.2.1",
"intl-messageformat": "10.5.11", "intl-messageformat": "10.5.11",
"js-yaml": "4.1.0", "js-yaml": "4.1.0",

View File

@ -1,6 +1,8 @@
import { EntityFilter } from "../common/entity/entity_filter"; import { EntityFilter } from "../common/entity/entity_filter";
import { HomeAssistant } from "../types"; import { HomeAssistant } from "../types";
type StrictConnectionMode = "disabled" | "guard_page" | "drop_connection";
interface CloudStatusNotLoggedIn { interface CloudStatusNotLoggedIn {
logged_in: false; logged_in: false;
cloud: "disconnected" | "connecting" | "connected"; cloud: "disconnected" | "connecting" | "connected";
@ -19,6 +21,7 @@ export interface CloudPreferences {
alexa_enabled: boolean; alexa_enabled: boolean;
remote_enabled: boolean; remote_enabled: boolean;
remote_allow_remote_enable: boolean; remote_allow_remote_enable: boolean;
strict_connection: StrictConnectionMode;
google_secure_devices_pin: string | undefined; google_secure_devices_pin: string | undefined;
cloudhooks: { [webhookId: string]: CloudWebhook }; cloudhooks: { [webhookId: string]: CloudWebhook };
alexa_report_state: boolean; alexa_report_state: boolean;
@ -141,6 +144,7 @@ export const updateCloudPref = (
google_secure_devices_pin?: CloudPreferences["google_secure_devices_pin"]; google_secure_devices_pin?: CloudPreferences["google_secure_devices_pin"];
tts_default_voice?: CloudPreferences["tts_default_voice"]; tts_default_voice?: CloudPreferences["tts_default_voice"];
remote_allow_remote_enable?: CloudPreferences["remote_allow_remote_enable"]; remote_allow_remote_enable?: CloudPreferences["remote_allow_remote_enable"];
strict_connection?: CloudPreferences["strict_connection"];
} }
) => ) =>
hass.callWS({ hass.callWS({

View File

@ -21,6 +21,7 @@ import {
import type { HomeAssistant } from "../../../../types"; import type { HomeAssistant } from "../../../../types";
import { showToast } from "../../../../util/toast"; import { showToast } from "../../../../util/toast";
import { showCloudCertificateDialog } from "../dialog-cloud-certificate/show-dialog-cloud-certificate"; import { showCloudCertificateDialog } from "../dialog-cloud-certificate/show-dialog-cloud-certificate";
import { showAlertDialog } from "../../../lovelace/custom-card-helpers";
@customElement("cloud-remote-pref") @customElement("cloud-remote-pref")
export class CloudRemotePref extends LitElement { export class CloudRemotePref extends LitElement {
@ -33,7 +34,7 @@ export class CloudRemotePref extends LitElement {
return nothing; return nothing;
} }
const { remote_enabled, remote_allow_remote_enable } = const { remote_enabled, remote_allow_remote_enable, strict_connection } =
this.cloudStatus.prefs; this.cloudStatus.prefs;
const { const {
@ -153,6 +154,61 @@ export class CloudRemotePref extends LitElement {
@change=${this._toggleAllowRemoteEnabledChanged} @change=${this._toggleAllowRemoteEnabledChanged}
></ha-switch> ></ha-switch>
</ha-settings-row> </ha-settings-row>
<ha-settings-row>
<span slot="heading"
>${this.hass.localize(
"ui.panel.config.cloud.account.remote.strict_connection"
)}</span
>
<span slot="description"
>${this.hass.localize(
"ui.panel.config.cloud.account.remote.strict_connection_secondary"
)}</span
>
<ha-select
.label=${this.hass.localize(
"ui.panel.config.cloud.account.remote.strict_connection_mode"
)}
@selected=${this._setStrictConnectionMode}
naturalMenuWidth
.value=${strict_connection}
>
<ha-list-item value="disabled">
${this.hass.localize(
"ui.panel.config.cloud.account.remote.strict_connection_modes.disabled"
)}
</ha-list-item>
<ha-list-item value="guard_page">
${this.hass.localize(
"ui.panel.config.cloud.account.remote.strict_connection_modes.guard_page"
)}
</ha-list-item>
<ha-list-item value="drop_connection">
${this.hass.localize(
"ui.panel.config.cloud.account.remote.strict_connection_modes.drop_connection"
)}
</ha-list-item>
</ha-select>
</ha-settings-row>
${strict_connection !== "disabled"
? html` <ha-settings-row>
<span slot="heading"
>${this.hass.localize(
"ui.panel.config.cloud.account.remote.strict_connection_link"
)}</span
>
<span slot="description"
>${this.hass.localize(
"ui.panel.config.cloud.account.remote.strict_connection_link_secondary"
)}</span
>
<ha-button @click=${this._createLoginUrl}
>${this.hass.localize(
"ui.panel.config.cloud.account.remote.strict_connection_create_link"
)}</ha-button
>
</ha-settings-row>`
: nothing}
<ha-settings-row> <ha-settings-row>
<span slot="heading" <span slot="heading"
>${this.hass.localize( >${this.hass.localize(
@ -223,6 +279,18 @@ export class CloudRemotePref extends LitElement {
} }
} }
private async _setStrictConnectionMode(ev) {
const mode = ev.target.value;
try {
await updateCloudPref(this.hass, {
strict_connection: mode,
});
fireEvent(this, "ha-refresh-cloud-status");
} catch (err: any) {
alert(err.message);
}
}
private async _copyURL(ev): Promise<void> { private async _copyURL(ev): Promise<void> {
const url = ev.currentTarget.url; const url = ev.currentTarget.url;
await copyToClipboard(url); await copyToClipboard(url);
@ -231,6 +299,40 @@ export class CloudRemotePref extends LitElement {
}); });
} }
private async _createLoginUrl() {
try {
const result = await this.hass.callService(
"cloud",
"create_temporary_strict_connection_url",
undefined,
undefined,
false,
true
);
showAlertDialog(this, {
title: this.hass.localize(
"ui.panel.config.cloud.account.remote.strict_connection_link"
),
text: html`${this.hass.localize(
"ui.panel.config.cloud.account.remote.strict_connection_link_created_message"
)}
<pre>${result.response.url}</pre>
<ha-button
.url=${result.response.url}
@click=${this._copyURL}
unelevated
>
<ha-svg-icon slot="icon" .path=${mdiContentCopy}></ha-svg-icon>
${this.hass.localize(
"ui.panel.config.cloud.account.remote.strict_connection_copy_link"
)}
</ha-button>`,
});
} catch (err: any) {
showAlertDialog(this, { text: err.message });
}
}
static get styles(): CSSResultGroup { static get styles(): CSSResultGroup {
return css` return css`
.preparing { .preparing {

View File

@ -83,7 +83,8 @@ export const connectionMixin = <T extends Constructor<HassBaseEl>>(
service, service,
serviceData, serviceData,
target, target,
notifyOnError = true notifyOnError = true,
returnResponse = false
) => { ) => {
if (__DEV__ || this.hass?.debugConnection) { if (__DEV__ || this.hass?.debugConnection) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
@ -101,7 +102,8 @@ export const connectionMixin = <T extends Constructor<HassBaseEl>>(
domain, domain,
service, service,
serviceData ?? {}, serviceData ?? {},
target target,
returnResponse
)) as ServiceCallResponse; )) as ServiceCallResponse;
} catch (err: any) { } catch (err: any) {
if ( if (

View File

@ -3837,6 +3837,19 @@
"advanced_options": "Advanced options", "advanced_options": "Advanced options",
"external_activation": "Allow external activation of remote control", "external_activation": "Allow external activation of remote control",
"external_activation_secondary": "Allows you to turn on remote control from your Nabu Casa account page, even if you're outside your local network", "external_activation_secondary": "Allows you to turn on remote control from your Nabu Casa account page, even if you're outside your local network",
"strict_connection": "Restrict access to logged in users",
"strict_connection_secondary": "When a user is not logged in to your Home Assistant instance, they will not be able to access your instance remotely",
"strict_connection_mode": "Mode",
"strict_connection_modes": {
"disabled": "Disabled",
"guard_page": "Guard page",
"drop_connection": "Drop connection"
},
"strict_connection_link": "Create login link",
"strict_connection_link_secondary": "You can create a link that will give temporary access to the login page.",
"strict_connection_create_link": "Create link",
"strict_connection_link_created_message": "Give this link to the person you want to give remote access to the login page of your Home Assistant instance.",
"strict_connection_copy_link": "Copy link",
"certificate_info": "Certificate info", "certificate_info": "Certificate info",
"certificate_expire": "Will be renewed at {date}", "certificate_expire": "Will be renewed at {date}",
"more_info": "More info" "more_info": "More info"

View File

@ -190,6 +190,7 @@ export interface Context {
export interface ServiceCallResponse { export interface ServiceCallResponse {
context: Context; context: Context;
response?: any;
} }
export interface ServiceCallRequest { export interface ServiceCallRequest {
@ -241,7 +242,8 @@ export interface HomeAssistant {
service: ServiceCallRequest["service"], service: ServiceCallRequest["service"],
serviceData?: ServiceCallRequest["serviceData"], serviceData?: ServiceCallRequest["serviceData"],
target?: ServiceCallRequest["target"], target?: ServiceCallRequest["target"],
notifyOnError?: boolean notifyOnError?: boolean,
returnResponse?: boolean
): Promise<ServiceCallResponse>; ): Promise<ServiceCallResponse>;
callApi<T>( callApi<T>(
method: "GET" | "POST" | "PUT" | "DELETE", method: "GET" | "POST" | "PUT" | "DELETE",

View File

@ -9703,7 +9703,7 @@ __metadata:
gulp-rename: "npm:2.0.0" gulp-rename: "npm:2.0.0"
gulp-zopfli-green: "npm:6.0.1" gulp-zopfli-green: "npm:6.0.1"
hls.js: "patch:hls.js@npm%3A1.5.7#~/.yarn/patches/hls.js-npm-1.5.7-f5bbd3d060.patch" hls.js: "patch:hls.js@npm%3A1.5.7#~/.yarn/patches/hls.js-npm-1.5.7-f5bbd3d060.patch"
home-assistant-js-websocket: "npm:9.2.1" home-assistant-js-websocket: "npm:9.3.0"
html-minifier-terser: "npm:7.2.0" html-minifier-terser: "npm:7.2.0"
husky: "npm:9.0.11" husky: "npm:9.0.11"
idb-keyval: "npm:6.2.1" idb-keyval: "npm:6.2.1"
@ -9777,10 +9777,10 @@ __metadata:
languageName: unknown languageName: unknown
linkType: soft linkType: soft
"home-assistant-js-websocket@npm:9.2.1": "home-assistant-js-websocket@npm:9.3.0":
version: 9.2.1 version: 9.3.0
resolution: "home-assistant-js-websocket@npm:9.2.1" resolution: "home-assistant-js-websocket@npm:9.3.0"
checksum: 10/0508aacb4285c805953e620968ef7ca7fc9c3cdac18fa723dd9af128dff74ef2ec65fad4079353b80363cd1daec6d2798b46d2d40a7e4ff5c0807ac71080bf58 checksum: 10/0afbe9f327c3f917187422db1b800383530846724ed8985bb076f6312a10580baeff706d45fba3d840348b76e261eab3f3f7c0b4597340d7575b9b09fc41b0c7
languageName: node languageName: node
linkType: hard linkType: hard