UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

207 lines (203 loc) 7.75 kB
import * as i0 from '@angular/core'; import { inject, Injectable } from '@angular/core'; import * as i1 from '@c8y/client'; import * as i2 from '@c8y/ngx-components'; import { Permissions, ContextRouteService, ViewContext } from '@c8y/ngx-components'; import { gettext } from '@c8y/ngx-components/gettext'; import { defer, shareReplay } from 'rxjs'; const CREDENTIALS_TYPES = { NONE: { name: 'NONE', value: 'NONE', label: gettext('No password') }, USER_PASS: { name: 'USER_PASS', value: 'USER_PASS', label: gettext('Username and password') }, PASS_ONLY: { name: 'PASS_ONLY', value: 'PASS_ONLY', label: gettext('Password only') }, KEY_PAIR: { name: 'KEY_PAIR', value: 'KEY_PAIR', label: gettext('Public/private keys') }, CERTIFICATE: { name: 'CERTIFICATE', value: 'CERTIFICATE', label: gettext('Certificate') } }; const canActivateRemoteAccess = (route) => { const permissions = inject(Permissions); const remoteAccessService = inject(RemoteAccessService); const contextRouteService = inject(ContextRouteService); if (!permissions.hasRole(Permissions.ROLE_REMOTE_ACCESS_ADMIN)) { return false; } const contextDetails = contextRouteService.getContextData(route); if (contextDetails.context !== ViewContext.Device) { return false; } const device = contextDetails.contextData; if (!device || !Array.isArray(device.c8y_SupportedOperations)) { return false; } const supportedOperations = device.c8y_SupportedOperations; if (!supportedOperations.includes('c8y_RemoteAccessConnect')) { return false; } return remoteAccessService.isAvailable$(); }; class RemoteAccessService { constructor(fetchClient, serviceRegistry) { this.fetchClient = fetchClient; this.serviceRegistry = serviceRegistry; this.baseUrl = '/service/remoteaccess'; } /** * Verifies if the remote access service is available by sending a HEAD request to is's health endpoint. * @returns cached Observable that emits true if the service is available, false otherwise. */ isAvailable$() { if (!this.cachedIsAvailable$) { this.cachedIsAvailable$ = defer(() => this.healthEndpointAvailable()).pipe(shareReplay(1)); } return this.cachedIsAvailable$; } /** * misses the leading ? for the query params */ getAuthQueryParamsForWebsocketConnection() { const { headers } = this.fetchClient.getFetchOptions(); const params = new URLSearchParams(); if (headers) { const xsrfToken = headers['X-XSRF-TOKEN']; const auth = headers['Authorization']; if (xsrfToken) { params.append('XSRF-TOKEN', xsrfToken); } if (auth) { params.append('token', auth.replace('Bearer ', '').replace('Basic ', '')); } } const paramsString = params.toString(); return paramsString; } /** * Returns the URI for the websocket connection to the remote access service. */ getWebSocketUri(deviceId, configurationId) { const authQueryParams = this.getAuthQueryParamsForWebsocketConnection(); const protocol = window.location.protocol === 'http:' ? 'ws' : 'wss'; const pathName = `${protocol}://${window.location.host}${this.baseUrl}/client/${deviceId}/configurations/${configurationId}`; return authQueryParams ? `${pathName}?${authQueryParams}` : pathName; } /** * Retrieves all configurations for a given device. */ async listConfigurations(deviceId) { const response = await this.fetchClient.fetch(`${this.baseUrl}/devices/${deviceId}/configurations`); if (response.ok) { return response.json(); } throw new Error(`Failed to fetch configurations for device ${deviceId}`); } /** * Deletes a configuration for a given device. */ async deleteConfiguration(deviceId, configurationId) { const response = await this.fetchClient.fetch(`${this.baseUrl}/devices/${deviceId}/configurations/${configurationId}`, { method: 'DELETE' }); if (response.ok) { return; } throw new Error(`Failed to delete configuration for device ${deviceId}`); } /** * Retrieves all available remote access protocol providers. */ getProtocolProviders() { return this.serviceRegistry.get('remoteAccessProtocolHook'); } /** * Creates a new configuration for a given device. */ async addConfiguration(deviceId, configuration) { const response = await this.fetchClient.fetch(`${this.baseUrl}/devices/${deviceId}/configurations`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(configuration) }); if (response.ok) { return response.json(); } throw new Error(`Failed to add configuration for device ${configuration.attrs.deviceId}`); } /** * Updates a configuration for a given device. */ async updateConfiguration(deviceId, configuration) { const response = await this.fetchClient.fetch(`${this.baseUrl}/devices/${deviceId}/configurations/${configuration.id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(configuration) }); if (response.ok) { return response.json(); } throw new Error(`Failed to update configuration for device ${configuration.attrs.deviceId}`); } /** * Generates a SSH key pair for a given hostname. */ async generateKeyPair(hostname) { const response = await this.fetchClient.fetch(`${this.baseUrl}/keypair/generate`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ hostname }) }); if (response.ok) { return response.json(); } throw new Error(`Failed to generate key pair for ${hostname}`); } async healthEndpointAvailable() { try { const response = await this.fetchClient.fetch(`${this.baseUrl}/health`, { method: 'HEAD', headers: { 'Content-Type': 'application/json' } }); if (response.ok) { return !!response.ok; } } catch (e) { return false; } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RemoteAccessService, deps: [{ token: i1.FetchClient }, { token: i2.ServiceRegistry }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RemoteAccessService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RemoteAccessService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [{ type: i1.FetchClient }, { type: i2.ServiceRegistry }] }); /** * Generated bundle index. Do not edit. */ export { CREDENTIALS_TYPES, RemoteAccessService, canActivateRemoteAccess }; //# sourceMappingURL=c8y-ngx-components-remote-access-data.mjs.map