From a2f8534823c0bbd25e2c51586ed2efcea7680f98 Mon Sep 17 00:00:00 2001 From: Jakub Jirutka Date: Sun, 13 Nov 2022 15:17:59 +0100 Subject: [PATCH] Allow to specify full file name in value reference '!' (#14955) * Extract parsing of value reference '!' in settings into a function * Allow to specify full file name in value reference '!' This `network_key: '!secret network_key'` is really confusing because it looks like a YAML tag named 'secret' and a value "network_key". When we write `network_key: '!secret.yaml network_key'` instead, it's a little clearer what's going on. Also, it's more consistent with file references in 'devices' and 'groups'. --- lib/util/settings.ts | 29 ++++++++++++++++++++--------- test/settings.test.js | 2 +- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/lib/util/settings.ts b/lib/util/settings.ts index 98346b8d..aabbf5af 100644 --- a/lib/util/settings.ts +++ b/lib/util/settings.ts @@ -187,6 +187,20 @@ function loadSettingsWithDefaults(): void { _settingsWithDefaults.whitelist && _settingsWithDefaults.passlist.push(..._settingsWithDefaults.whitelist); } +function parseValueRef(text: string): {filename: string, key: string} | null { + const match = /!(.*) (.*)/g.exec(text); + if (match) { + let filename = match[1]; + // This is mainly for backward compatibility. + if (!filename.endsWith('.yaml') && !filename.endsWith('.yml')) { + filename += '.yaml'; + } + return {filename, key: match[2]}; + } else { + return null; + } +} + function write(): void { const settings = getInternalSettings(); const toWrite: KeyValue = objectAssignDeep({}, settings); @@ -203,9 +217,9 @@ function write(): void { ['frontend', 'auth_token'], ]) { if (actual[path[0]] && actual[path[0]][path[1]]) { - const match = /!(.*) (.*)/g.exec(actual[path[0]][path[1]]); - if (match) { - yaml.updateIfChanged(data.joinPath(`${match[1]}.yaml`), match[2], toWrite[path[0]][path[1]]); + const ref = parseValueRef(actual[path[0]][path[1]]); + if (ref) { + yaml.updateIfChanged(data.joinPath(ref.filename), ref.key, toWrite[path[0]][path[1]]); toWrite[path[0]][path[1]] = actual[path[0]][path[1]]; } } @@ -314,12 +328,9 @@ function read(): Settings { // Read !secret MQTT username and password if set // eslint-disable-next-line const interpetValue = (value: any): any => { - const re = /!(.*) (.*)/g; - const match = re.exec(value); - if (match) { - const file = data.joinPath(`${match[1]}.yaml`); - const key = match[2]; - return yaml.read(file)[key]; + const ref = parseValueRef(value); + if (ref) { + return yaml.read(data.joinPath(ref.filename))[ref.key]; } else { return value; } diff --git a/test/settings.test.js b/test/settings.test.js index e7dbaffb..68a05e1f 100644 --- a/test/settings.test.js +++ b/test/settings.test.js @@ -199,7 +199,7 @@ describe('Settings', () => { mqtt: { server: '!secret server', user: '!secret username', - password: '!secret password', + password: '!secret.yaml password', }, advanced: { network_key: '!secret network_key',