Skip to content

Commit 9360cfe

Browse files
authored
[items] Metadata: Don't allow objects as configuration value (openhab#495)
See https://community.openhab.org/t/main-ui-javascript-rule-reload-causing-rest-items-failure/167141/10?u=florian-h05 for motivation. Signed-off-by: Florian Hotze <[email protected]>
1 parent ae59b3e commit 9360cfe

File tree

3 files changed

+41
-10
lines changed

3 files changed

+41
-10
lines changed

src/items/metadata.js

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,45 @@ function _getSingleItemMetadata (itemName, namespace) {
111111
* @memberOf items.metadata
112112
* @param {Item|string} itemOrName {@link Item} or the name of the Item
113113
* @param {string} [namespace] name of the metadata: if provided, only metadata of this namespace is returned, else all metadata is returned
114-
* @returns {{ namespace: ItemMetadata }|ItemMetadata|null} all metadata as an object with the namespaces as properties OR metadata of a single namespace or `null` if that namespace doesn't exist; the metadata itself is of type {@link ItemMetadata}
114+
* @returns {{ namespace: ItemMetadata }|ItemMetadata|null} all metadata as an object with the namespaces as properties OR metadata of a single
115+
* namespace or `null` if that namespace doesn't exist; the metadata itself is of type {@link ItemMetadata}
115116
*/
116117
function getMetadata (itemOrName, namespace) {
117118
const itemName = _getItemName(itemOrName);
118119
if (namespace !== undefined) return _getSingleItemMetadata(itemName, namespace);
119120
return _getAllItemMetadata(itemName);
120121
}
121122

123+
/**
124+
* Creates a {@link https://www.openhab.org/javadoc/latest/org/openhab/core/items/metadata org.openhab.core.items.Metadata}.
125+
*
126+
* @private
127+
* @param {string} itemName
128+
* @param {string} namespace
129+
* @param {string} value
130+
* @param {object} configuration
131+
* @return {*} an instance of {@link https://www.openhab.org/javadoc/latest/org/openhab/core/items/metadata org.openhab.core.items.Metadata}
132+
*/
133+
function _createMetadata (itemName, namespace, value, configuration) {
134+
const configurationClone = Object.assign({}, configuration);
135+
for (const key in configurationClone) {
136+
const value = configurationClone[key];
137+
if (typeof value === 'object') {
138+
/*
139+
* Some reasoning for this:
140+
* Generally, storing objects in metadata is not the best idea, as they are not necessarily serializable and therefore JSONDB will not be able to store them.
141+
* Wrt to JavaScript objects specifically, they are passed by reference (as all objects), and that reference becomes invalid if the script that created the
142+
* object is reloaded, causing various issues failure of related REST API endpoints.
143+
* */
144+
console.warn(`Metadata configuration values must be primitive types, not objects. Ignoring configuration for key '${key}' of metadata '${namespace}' for Item '${itemName}'`);
145+
delete configurationClone[key];
146+
}
147+
}
148+
149+
const key = new MetadataKey(namespace, itemName);
150+
return new Metadata(key, value, configurationClone);
151+
}
152+
122153
/**
123154
* Adds metadata of a single namespace to an Item.
124155
*
@@ -137,8 +168,7 @@ function getMetadata (itemOrName, namespace) {
137168
*/
138169
function addMetadata (itemOrName, namespace, value, configuration, persist = false) {
139170
const itemName = _getItemName(itemOrName);
140-
const key = new MetadataKey(namespace, itemName);
141-
const newMetadata = new Metadata(key, value, configuration);
171+
const newMetadata = _createMetadata(itemName, namespace, value, configuration);
142172
try {
143173
const meta = (persist && environment.useProviderRegistries()) ? metadataRegistry.addPermanent(newMetadata) : metadataRegistry.add(newMetadata);
144174
return new ItemMetadata(meta);
@@ -168,11 +198,11 @@ function addMetadata (itemOrName, namespace, value, configuration, persist = fal
168198
function replaceMetadata (itemOrName, namespace, value, configuration) {
169199
const itemName = _getItemName(itemOrName);
170200
const key = new MetadataKey(namespace, itemName);
171-
const newMetadata = new Metadata(key, value, configuration);
172-
let meta = metadataRegistry.get(key);
173-
meta = (meta === null) ? metadataRegistry.add(newMetadata) : metadataRegistry.update(newMetadata);
174-
if (meta === null) return null;
175-
return new ItemMetadata(meta);
201+
const newMetadata = _createMetadata(itemName, namespace, value, configuration);
202+
let metadata = metadataRegistry.get(key);
203+
metadata = (metadata === null) ? metadataRegistry.add(newMetadata) : metadataRegistry.update(newMetadata);
204+
if (metadata === null) return null;
205+
return new ItemMetadata(metadata);
176206
}
177207

178208
/**

types/items/metadata.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ export type Item = {
5757
* @memberOf items.metadata
5858
* @param {Item|string} itemOrName {@link Item} or the name of the Item
5959
* @param {string} [namespace] name of the metadata: if provided, only metadata of this namespace is returned, else all metadata is returned
60-
* @returns {{ namespace: ItemMetadata }|ItemMetadata|null} all metadata as an object with the namespaces as properties OR metadata of a single namespace or `null` if that namespace doesn't exist; the metadata itself is of type {@link ItemMetadata}
60+
* @returns {{ namespace: ItemMetadata }|ItemMetadata|null} all metadata as an object with the namespaces as properties OR metadata of a single
61+
* namespace or `null` if that namespace doesn't exist; the metadata itself is of type {@link ItemMetadata}
6162
*/
6263
export function getMetadata(itemOrName: Item | string, namespace?: string): {
6364
namespace: ItemMetadata;

types/items/metadata.d.ts.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)