fix: contain malformed metadata and stale discovery
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
const { validateDeviceId } = require('./proxy-launch');
|
||||
const { toWellFormedString } = require('../well-formed-string');
|
||||
|
||||
const MAX_PROJECTED_PAYLOAD_BYTES = 8 * 1024 * 1024;
|
||||
|
||||
@@ -11,11 +12,11 @@ function projectionError(code, message) {
|
||||
}
|
||||
|
||||
function nullableString(value) {
|
||||
return typeof value === 'string' ? value : null;
|
||||
return typeof value === 'string' ? toWellFormedString(value) : null;
|
||||
}
|
||||
|
||||
function nullableId(value) {
|
||||
return typeof value === 'string' && value.length > 0 ? value : null;
|
||||
return typeof value === 'string' && value.length > 0 ? toWellFormedString(value) : null;
|
||||
}
|
||||
|
||||
function nullableBoolean(value) {
|
||||
@@ -78,7 +79,9 @@ function projectArray(values, projector) {
|
||||
}
|
||||
|
||||
function safeMetadataError(value) {
|
||||
return typeof value === 'string' && value.length > 0 ? value.slice(0, 512) : null;
|
||||
return typeof value === 'string' && value.length > 0
|
||||
? Array.from(toWellFormedString(value)).slice(0, 512).join('')
|
||||
: null;
|
||||
}
|
||||
|
||||
function projectDeviceHierarchy({ devices = [], sites = [], groups = [], metadataErrors = {} } = {}) {
|
||||
|
||||
+50
-4
@@ -214,6 +214,8 @@ class AppRuntime {
|
||||
this.openExternal = openExternal;
|
||||
this.discoveryTimeoutMs = discoveryTimeoutMs;
|
||||
this.allowedDeviceIds = new Set();
|
||||
this.allowedDeviceDiscovery = null;
|
||||
this.discoveryGeneration = 0;
|
||||
this.proxyByDevice = new Map();
|
||||
}
|
||||
|
||||
@@ -233,16 +235,55 @@ class AppRuntime {
|
||||
return tracked.filter((proxy) => this.proxyByDevice.get(proxy.deviceId) === proxy.processId);
|
||||
}
|
||||
|
||||
_setAllowedDevices(devices) {
|
||||
_setAllowedDevices(devices, discovery) {
|
||||
this.allowedDeviceIds = new Set(devices.map((device) => device.id));
|
||||
this.allowedDeviceDiscovery = discovery;
|
||||
}
|
||||
|
||||
_beginDiscovery() {
|
||||
const state = this.sessionStore.describe();
|
||||
this.allowedDeviceIds.clear();
|
||||
this.allowedDeviceDiscovery = null;
|
||||
return Object.freeze({
|
||||
generation: ++this.discoveryGeneration,
|
||||
connected: state.connected,
|
||||
origin: state.origin,
|
||||
});
|
||||
}
|
||||
|
||||
_isCurrentDiscovery(discovery) {
|
||||
const state = this.sessionStore.describe();
|
||||
return discovery.generation === this.discoveryGeneration &&
|
||||
discovery.connected === state.connected && discovery.origin === state.origin;
|
||||
}
|
||||
|
||||
_staleDiscoveryResult() {
|
||||
return {
|
||||
success: false,
|
||||
stale: true,
|
||||
hierarchy: { devices: [], sites: [], groups: [] },
|
||||
message: 'Alta device discovery result is stale',
|
||||
};
|
||||
}
|
||||
|
||||
invalidateDiscovery() {
|
||||
this.discoveryGeneration += 1;
|
||||
this.allowedDeviceIds.clear();
|
||||
this.allowedDeviceDiscovery = null;
|
||||
}
|
||||
|
||||
onSessionChanged() {
|
||||
this.invalidateDiscovery();
|
||||
}
|
||||
|
||||
async getDevices() {
|
||||
const discovery = this._beginDiscovery();
|
||||
try {
|
||||
const hierarchy = projectDeviceHierarchy({
|
||||
devices: await this.altaClient.getDevices(), sites: [], groups: [],
|
||||
});
|
||||
this._setAllowedDevices(hierarchy.devices);
|
||||
if (!this._isCurrentDiscovery(discovery)) return this._staleDiscoveryResult();
|
||||
this._setAllowedDevices(hierarchy.devices, discovery);
|
||||
return { success: true, devices: hierarchy.devices };
|
||||
} catch (error) {
|
||||
return { success: false, devices: [], message: safeErrorMessage(error, 'Failed to get devices') };
|
||||
@@ -268,6 +309,7 @@ class AppRuntime {
|
||||
}
|
||||
|
||||
async getDeviceHierarchy() {
|
||||
const discoveryState = this._beginDiscovery();
|
||||
let timer;
|
||||
try {
|
||||
const discovery = Promise.allSettled([
|
||||
@@ -298,9 +340,11 @@ class AppRuntime {
|
||||
groups: groupResult.status === 'fulfilled' ? groupResult.value : [],
|
||||
metadataErrors,
|
||||
});
|
||||
this._setAllowedDevices(hierarchy.devices);
|
||||
if (!this._isCurrentDiscovery(discoveryState)) return this._staleDiscoveryResult();
|
||||
this._setAllowedDevices(hierarchy.devices, discoveryState);
|
||||
return { success: true, hierarchy };
|
||||
} catch (error) {
|
||||
if (!this._isCurrentDiscovery(discoveryState)) return this._staleDiscoveryResult();
|
||||
this.allowedDeviceIds.clear();
|
||||
const message = error && error.code === 'DISCOVERY_TIMEOUT'
|
||||
? 'Alta device discovery timed out'
|
||||
@@ -324,7 +368,8 @@ class AppRuntime {
|
||||
const validatedId = validateDeviceId(deviceId);
|
||||
const validatedUsername = validateUsername(username);
|
||||
this._reconcileProxies();
|
||||
if (!this.allowedDeviceIds.has(validatedId)) {
|
||||
if (!this.allowedDeviceDiscovery || !this._isCurrentDiscovery(this.allowedDeviceDiscovery) ||
|
||||
!this.allowedDeviceIds.has(validatedId)) {
|
||||
return { success: false, message: 'Select a device from the current Alta device list.' };
|
||||
}
|
||||
if (this.proxyByDevice.has(validatedId)) {
|
||||
@@ -364,6 +409,7 @@ class AppRuntime {
|
||||
}
|
||||
|
||||
async disconnect() {
|
||||
this.invalidateDiscovery();
|
||||
const tracked = this._reconcileProxies();
|
||||
await Promise.all(tracked.map(async (proxy) => {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user