iobroker.javascript 10.1.0 → 10.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -9
- package/admin/assets/AiChatPanel-D3eFcu56.js +242 -0
- package/admin/assets/AiDiffView-DtbcD6Yx.js +1 -0
- package/admin/assets/{Debugger-DCMWjeGm.js → Debugger-DsoSdux9.js} +4 -4
- package/admin/assets/Error-1oeF0cix.js +1 -0
- package/admin/assets/Import-BH2X_ziv.js +1 -0
- package/admin/assets/RulesEditor-BcGsf9n4.css +1 -0
- package/admin/assets/RulesEditor-CJ9TvZtR.js +1 -0
- package/admin/assets/{ScriptEditor-CMYUt5S4.js → ScriptEditor-DNcGhbcU.js} +2 -2
- package/admin/assets/ScriptEditorVanillaMonaco-BBoOLFln.js +3 -0
- package/admin/assets/{_virtual_mf-localSharedImportMap___mfe_internal__iobroker_javascript__mf_owner__1-7EPUlgCk.js → _virtual_mf-localSharedImportMap___mfe_internal__iobroker_javascript__mf_owner__1-BK6m6sZx.js} +1 -1
- package/admin/assets/_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__1__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-DezK0U6r.js +1243 -0
- package/admin/assets/_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__1__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-_q6w9ugW.js +9 -0
- package/admin/assets/aiPromptBuilder-DSYziAVr.js +1 -0
- package/admin/assets/{blockly-C4zJerWL.js → blockly-DBw-ytY1.js} +11 -11
- package/admin/assets/{blocks_action-CvnOHXwt.js → blocks_action-Bpe-Zvqj.js} +1 -1
- package/admin/assets/{blocks_convert-BZlKcd02.js → blocks_convert-DS1wCMO_.js} +3 -3
- package/admin/assets/blocks_logic-DQaroQTu.js +1 -0
- package/admin/assets/blocks_number-C998FOz6.js +1 -0
- package/admin/assets/{blocks_object-B64vSfel.js → blocks_object-BGYvC_4Y.js} +1 -1
- package/admin/assets/blocks_procedures-BZFhrnZ3.js +3 -0
- package/admin/assets/blocks_sendto-BoOZkX-e.js +5 -0
- package/admin/assets/{blocks_switch-DViYCmQd.js → blocks_switch-CfjY75wV.js} +2 -2
- package/admin/assets/blocks_system-C69gZMAz.js +1 -0
- package/admin/assets/{blocks_text-BOvtHN2r.js → blocks_text-Dp6RaJ_p.js} +1 -1
- package/admin/assets/{blocks_time-BH2F-ylT.js → blocks_time-CmECitUh.js} +1 -1
- package/admin/assets/blocks_timeout-BI8OyiNa.js +1 -0
- package/admin/assets/blocks_trigger-X7O3INGz.js +2 -0
- package/admin/assets/blocks_words-BhHIf_1o.js +1 -0
- package/admin/assets/{cronHoverProvider-DjY3jLvQ.js → cronHoverProvider-BhX-SvkB.js} +1 -1
- package/admin/assets/{dist-D6o4h8Pd.js → dist-CaOsN0XW.js} +1 -1
- package/admin/assets/{field_cron-BMQWPb61.js → field_cron-BJLkgNzf.js} +1 -1
- package/admin/assets/{field_oid-BGIMv9gw.js → field_oid-CJZIeruf.js} +1 -1
- package/admin/assets/{field_script-CdzYBCe6.js → field_script-4IGidWJ7.js} +1 -1
- package/admin/assets/helpers-DaSC8t53.js +1 -0
- package/admin/assets/{hostInit-DBlZi_Kt.js → hostInit-B3IjMQKW.js} +1 -1
- package/admin/assets/index-DKhQ45Yn.js +871 -0
- package/admin/assets/index-Z8Hkv58g.css +1 -0
- package/admin/assets/{inlineChatWidget-SDoyVtOR.js → inlineChatWidget-CBVgT6FZ.js} +1 -1
- package/admin/assets/{inlineDiffController-CnHE3Rwd.js → inlineDiffController-DianrKl1.js} +1 -1
- package/admin/assets/{mf-entry-bootstrap-0-a03ecebd.js → mf-entry-bootstrap-0-a65094d3.js} +3 -2
- package/admin/assets/stateHoverProvider-CIFNrLee.js +9 -0
- package/admin/assets/virtual_mf-REMOTE_ENTRY_ID___mfe_internal__iobroker_javascript__remoteEntry_js-BO-WKj5V.js +1 -0
- package/admin/custom/assets/Components-BCQTjBgm.js +1 -0
- package/admin/custom/assets/{_virtual_mf-localSharedImportMap___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1-DljJyQQg.js → _virtual_mf-localSharedImportMap___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1-BuAc8OyX.js} +1 -1
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__loadShare___mf_0_emotion_mf_1_react__loadShare__.js-BGJv4zZP.js +1 -0
- package/admin/custom/assets/{_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__loadShare___mf_0_emotion_mf_1_styled__loadShare__.js-BD2OkSge.js → _virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__loadShare___mf_0_emotion_mf_1_styled__loadShare__.js-B4E6MFJ4.js} +1 -1
- package/admin/custom/assets/{_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-pM642JFd.js → _virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-aRlxyEhq.js} +86 -86
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__loadShare___mf_0_iobroker_mf_1_json_mf_2_config__loadShare__.js-DQwzYx75.js +1494 -0
- package/admin/custom/assets/{_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__loadShare__leaflet__loadShare__.js-h-rCw3iz.js → _virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__loadShare__leaflet__loadShare__.js-n2zIPi0L.js} +1 -1
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-xxszBNje.js +9 -0
- package/admin/custom/assets/{_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__prebuild__date_mf_2_fns__prebuild__-D5hqXJXI.js → _virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__prebuild__date_mf_2_fns__prebuild__-Tq7tesSS.js} +1 -1
- package/admin/custom/assets/{_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__prebuild__leaflet__prebuild__-DARUoA03.js → _virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__prebuild__leaflet__prebuild__-BeF0jEWM.js} +1 -1
- package/admin/custom/assets/{hostInit-0DGPuZTB.js → hostInit-CHwrowP4.js} +1 -1
- package/admin/custom/assets/{index-DcFI5r-g.js → index-Cm6xl9K4.js} +1 -1
- package/admin/custom/assets/{lib-BlUjuGH7.js → lib-bhrFL6jR.js} +1 -1
- package/admin/custom/assets/{mf-entry-bootstrap-0-efd847a6.js → mf-entry-bootstrap-0-f08941e2.js} +3 -2
- package/admin/custom/assets/{setYear-BaCcPbbI.js → setYear-DzTZ2h9A.js} +1 -1
- package/admin/custom/assets/virtualExposes-B5LJmnfO.js +1 -0
- package/admin/custom/assets/virtual_mf-REMOTE_ENTRY_ID___mfe_internal__ConfigCustomJavascriptSet__customComponents_js-ML-chjs6.js +1 -0
- package/admin/custom/assets/{virtual_mf-exposes___mfe_internal__ConfigCustomJavascriptSet__customComponents_js-DPck7zEs.js → virtual_mf-exposes___mfe_internal__ConfigCustomJavascriptSet__customComponents_js-C3ImybiM.js} +2 -2
- package/admin/custom/customComponents.js +12 -1
- package/admin/custom/i18n/de.json +11 -1
- package/admin/custom/i18n/en.json +11 -1
- package/admin/custom/i18n/es.json +11 -1
- package/admin/custom/i18n/fr.json +11 -1
- package/admin/custom/i18n/it.json +11 -1
- package/admin/custom/i18n/nl.json +11 -1
- package/admin/custom/i18n/pl.json +11 -1
- package/admin/custom/i18n/pt.json +11 -1
- package/admin/custom/i18n/ru.json +11 -1
- package/admin/custom/i18n/uk.json +11 -1
- package/admin/custom/i18n/zh-cn.json +11 -1
- package/admin/i18n/de.json +3 -0
- package/admin/i18n/en.json +3 -0
- package/admin/i18n/es.json +3 -0
- package/admin/i18n/fr.json +3 -0
- package/admin/i18n/it.json +3 -0
- package/admin/i18n/nl.json +3 -0
- package/admin/i18n/pl.json +3 -0
- package/admin/i18n/pt.json +3 -0
- package/admin/i18n/ru.json +3 -0
- package/admin/i18n/uk.json +3 -0
- package/admin/i18n/zh-cn.json +3 -0
- package/admin/jsonConfig.json +31 -0
- package/admin/mf-manifest.json +1 -1
- package/admin/mf-stats.json +1 -1
- package/admin/remoteEntry.js +12 -1
- package/admin/tab.html +6 -15
- package/build/lib/javascript.d.ts +48 -0
- package/build/lib/sandbox.js +2 -0
- package/build/lib/sandbox.js.map +1 -1
- package/build/lib/secrets.js +220 -0
- package/build/lib/secrets.js.map +1 -0
- package/build/main.js +51 -0
- package/build/main.js.map +1 -1
- package/build/types.d.ts +7 -0
- package/docs/en/blockly.md +29 -0
- package/docs/en/javascript.md +56 -0
- package/io-package.json +28 -27
- package/package.json +2 -2
- package/admin/assets/AiChatPanel-C4kuqP2U.js +0 -237
- package/admin/assets/AiDiffView-zJTEnv05.js +0 -1
- package/admin/assets/AiScriptAnalyzer--BHML2rN.js +0 -9
- package/admin/assets/BlocklyEditor-BB77aFJI.js +0 -84
- package/admin/assets/ContextWrapper-C2yvd2Tn.css +0 -1
- package/admin/assets/ContextWrapper-W2H0z6zD.js +0 -136
- package/admin/assets/Error-CBC2oZzb.js +0 -1
- package/admin/assets/Import-B-F9IhZ-.js +0 -1
- package/admin/assets/RulesEditor-ByjgEaVo.js +0 -1
- package/admin/assets/RulesEditor-k-DMHotH.css +0 -1
- package/admin/assets/ScriptEditorVanillaMonaco-v12-gORS.js +0 -3
- package/admin/assets/Send-CChqR5Oy.js +0 -1
- package/admin/assets/_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__1__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-DuplUOZN.js +0 -1243
- package/admin/assets/_virtual_mf___mfe_internal__iobroker_javascript__mf_owner__1__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-JkwfVf8d.js +0 -9
- package/admin/assets/aiCodeLensProvider-BGvIu6hH.js +0 -4
- package/admin/assets/aiPromptBuilder-Bs27qOHT.js +0 -7
- package/admin/assets/back-CXiqI7Po.jpg +0 -0
- package/admin/assets/blocklyDarkTheme-DEiAX5DT.js +0 -1
- package/admin/assets/blocks_logic-B33Pypxr.js +0 -1
- package/admin/assets/blocks_number-k2IjE7OH.js +0 -1
- package/admin/assets/blocks_procedures-BpvNI5dO.js +0 -3
- package/admin/assets/blocks_sendto-pwZchfe0.js +0 -5
- package/admin/assets/blocks_system-BZZcGqTJ.js +0 -1
- package/admin/assets/blocks_timeout-C3BoW4XJ.js +0 -1
- package/admin/assets/blocks_trigger-gwXvuAHV.js +0 -2
- package/admin/assets/blocks_words-D8PL_nSE.js +0 -1
- package/admin/assets/helpers-Crmcgphg.js +0 -1
- package/admin/assets/index-BHhhebRG.css +0 -1
- package/admin/assets/index-BvPVHv3P.js +0 -192
- package/admin/assets/javascript-DVIhlTDr.js +0 -218
- package/admin/assets/mjs-Bh7xFIpd.js +0 -90
- package/admin/assets/stateHoverProvider-D0iXo6YF.js +0 -9
- package/admin/assets/virtual_mf-REMOTE_ENTRY_ID___mfe_internal__iobroker_javascript__remoteEntry_js-DYEYnOkt.js +0 -1
- package/admin/custom/assets/Components-CuFt9lAY.js +0 -1
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__loadShare___mf_0_emotion_mf_1_react__loadShare__.js-D0M1SjIE.js +0 -1
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__loadShare___mf_0_iobroker_mf_1_json_mf_2_config__loadShare__.js-BLelmJ7Y.js +0 -1494
- package/admin/custom/assets/_virtual_mf___mfe_internal__ConfigCustomJavascriptSet__mf_owner__1__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-BGiB1l5e.js +0 -9
- package/admin/custom/assets/virtualExposes-DGxNcyb6.js +0 -1
- package/admin/custom/assets/virtual_mf-REMOTE_ENTRY_ID___mfe_internal__ConfigCustomJavascriptSet__customComponents_js-DVNwFcUr.js +0 -1
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.SecretsManager = exports.SECRETS_PREFIX = void 0;
|
|
37
|
+
exports.isSecretId = isSecretId;
|
|
38
|
+
exports.getSecretName = getSecretName;
|
|
39
|
+
/**
|
|
40
|
+
* Access to the central ioBroker credential store (`system.credentials.*`) from scripts.
|
|
41
|
+
*
|
|
42
|
+
* The admin UI manages the credentials under "Basic settings" → "Credentials". Every credential
|
|
43
|
+
* has an ID like `system.credentials.CameraPassword` and holds either a single `key` (API keys)
|
|
44
|
+
* or a `login`/`password` pair. The secret fields are stored encrypted with the system secret.
|
|
45
|
+
*
|
|
46
|
+
* This manager keeps all credentials decrypted in memory and exposes them to the scripts as the
|
|
47
|
+
* global `SECRETS` object, so a script can simply write:
|
|
48
|
+
*
|
|
49
|
+
* ```js
|
|
50
|
+
* const password = SECRETS.CameraPassword.key;
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
* The cache is kept up to date while the adapter is running, so editing a credential in the admin
|
|
54
|
+
* UI takes effect immediately - without restarting the adapter or the scripts.
|
|
55
|
+
*/
|
|
56
|
+
// Imported from its own entry point on purpose: the package index of `@iobroker/adapter-core`
|
|
57
|
+
// looks for js-controller while it is being loaded and terminates the process with exit code 10
|
|
58
|
+
// when it is missing. This module is required by the unit tests, which run without a controller,
|
|
59
|
+
// so it must stay clear of that side effect. `@iobroker/adapter-core/credentials` is free of it -
|
|
60
|
+
// it is written to be usable in browser builds as well.
|
|
61
|
+
const Credentials = __importStar(require("@iobroker/adapter-core/credentials"));
|
|
62
|
+
/** Prefix of all credential object IDs */
|
|
63
|
+
exports.SECRETS_PREFIX = 'system.credentials.';
|
|
64
|
+
/**
|
|
65
|
+
* Checks if the given object ID belongs to the central credential store.
|
|
66
|
+
*
|
|
67
|
+
* @param id Object ID, e.g. `system.credentials.CameraPassword`
|
|
68
|
+
*/
|
|
69
|
+
function isSecretId(id) {
|
|
70
|
+
return id.startsWith(exports.SECRETS_PREFIX) && id.length > exports.SECRETS_PREFIX.length;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Extracts the name a credential is exposed under in `SECRETS`.
|
|
74
|
+
*
|
|
75
|
+
* @param id Object ID, e.g. `system.credentials.CameraPassword`
|
|
76
|
+
*/
|
|
77
|
+
function getSecretName(id) {
|
|
78
|
+
return id.substring(exports.SECRETS_PREFIX.length);
|
|
79
|
+
}
|
|
80
|
+
class SecretsManager {
|
|
81
|
+
adapter;
|
|
82
|
+
/** Decrypted credentials, keyed by name (the credential ID without the `system.credentials.` prefix) */
|
|
83
|
+
cache = new Map();
|
|
84
|
+
/** If the scripts may read the credentials at all (adapter option `enableSecrets`) */
|
|
85
|
+
enabled = false;
|
|
86
|
+
/** Warn only once per script run that the feature is disabled */
|
|
87
|
+
disabledWarningShown = false;
|
|
88
|
+
/**
|
|
89
|
+
* The object handed to the scripts as the global `SECRETS`.
|
|
90
|
+
*
|
|
91
|
+
* It is a read-only view on the cache, so the values stay up to date without the scripts
|
|
92
|
+
* having to re-read anything, and a script cannot modify the credentials of another script.
|
|
93
|
+
*/
|
|
94
|
+
secrets;
|
|
95
|
+
constructor(adapter) {
|
|
96
|
+
this.adapter = adapter;
|
|
97
|
+
this.secrets = new Proxy(Object.create(null), {
|
|
98
|
+
get: (_target, prop) => typeof prop === 'string' ? this.get(prop) : undefined,
|
|
99
|
+
has: (_target, prop) => typeof prop === 'string' && this.cache.has(prop),
|
|
100
|
+
ownKeys: () => (this.enabled ? Array.from(this.cache.keys()) : []),
|
|
101
|
+
getOwnPropertyDescriptor: (_target, prop) => {
|
|
102
|
+
const value = typeof prop === 'string' ? this.get(prop) : undefined;
|
|
103
|
+
return value === undefined
|
|
104
|
+
? undefined
|
|
105
|
+
: { value, enumerable: true, configurable: true, writable: false };
|
|
106
|
+
},
|
|
107
|
+
// The credentials belong to the system - scripts may read them, but never change them
|
|
108
|
+
set: () => false,
|
|
109
|
+
defineProperty: () => false,
|
|
110
|
+
deleteProperty: () => false,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
/** Reads one credential from the cache and warns if the whole feature is switched off */
|
|
114
|
+
get(name) {
|
|
115
|
+
if (!this.enabled) {
|
|
116
|
+
if (!this.disabledWarningShown) {
|
|
117
|
+
this.disabledWarningShown = true;
|
|
118
|
+
this.adapter.log.warn(`A script tried to read the secret "${name}", but the access to the credentials is disabled. Enable "Allow scripts to read the credentials" in the instance settings.`);
|
|
119
|
+
}
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
return this.cache.get(name);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Reads all credentials of the central store and decrypts them.
|
|
126
|
+
*
|
|
127
|
+
* @param enabled Value of the adapter option `enableSecrets`
|
|
128
|
+
*/
|
|
129
|
+
async load(enabled) {
|
|
130
|
+
this.cache.clear();
|
|
131
|
+
this.disabledWarningShown = false;
|
|
132
|
+
this.enabled = enabled;
|
|
133
|
+
if (!enabled) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
if (!Credentials?.listCredentials) {
|
|
137
|
+
this.adapter.log.warn('Cannot read the credentials for "SECRETS": the credentials API is only available with js-controller 7.2 or newer');
|
|
138
|
+
this.enabled = false;
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
try {
|
|
142
|
+
const list = await Credentials.listCredentials(this.adapter);
|
|
143
|
+
for (const entry of list) {
|
|
144
|
+
await this.update(entry.id);
|
|
145
|
+
}
|
|
146
|
+
this.adapter.log.debug(`${this.cache.size} secret(s) available in the scripts as "SECRETS"`);
|
|
147
|
+
}
|
|
148
|
+
catch (e) {
|
|
149
|
+
this.adapter.log.warn(`Cannot read the credentials: ${e instanceof Error ? e.message : String(e)}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Reads one credential and decrypts it. Called for every change of a `system.credentials.*`
|
|
154
|
+
* object, so edits in the admin UI are visible in the scripts immediately.
|
|
155
|
+
*
|
|
156
|
+
* @param id Object ID, e.g. `system.credentials.CameraPassword`
|
|
157
|
+
*/
|
|
158
|
+
async update(id) {
|
|
159
|
+
if (!this.enabled || !isSecretId(id)) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const name = getSecretName(id);
|
|
163
|
+
try {
|
|
164
|
+
const credentials = await Credentials.getCredentials(this.adapter, id);
|
|
165
|
+
this.cache.set(name, Object.freeze({ ...credentials.values }));
|
|
166
|
+
}
|
|
167
|
+
catch (e) {
|
|
168
|
+
this.cache.delete(name);
|
|
169
|
+
this.adapter.log.warn(`Cannot read the secret "${name}": ${e instanceof Error ? e.message : String(e)}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Forgets one credential because its object was deleted.
|
|
174
|
+
*
|
|
175
|
+
* @param id Object ID, e.g. `system.credentials.CameraPassword`
|
|
176
|
+
*/
|
|
177
|
+
remove(id) {
|
|
178
|
+
if (isSecretId(id) && this.cache.delete(getSecretName(id))) {
|
|
179
|
+
this.adapter.log.debug(`Secret "${getSecretName(id)}" was deleted`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* The structure of the credential store without any secret value: which credentials exist and
|
|
184
|
+
* which fields each of them has. Used by the instance settings and the Blockly editor to show
|
|
185
|
+
* the user what `SECRETS.<name>.<field>` expressions are available.
|
|
186
|
+
*/
|
|
187
|
+
getStructure() {
|
|
188
|
+
return Array.from(this.cache.entries())
|
|
189
|
+
.map(([name, values]) => ({ name, fields: Object.keys(values).sort() }))
|
|
190
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Builds the ambient TypeScript declarations for the credentials that currently exist, so the
|
|
194
|
+
* editor can suggest their names after typing `SECRETS.` and their fields after the next dot.
|
|
195
|
+
* The names are merged into the `iobJS.Secrets` interface, which has an index signature for
|
|
196
|
+
* all other names.
|
|
197
|
+
*/
|
|
198
|
+
getDeclarations() {
|
|
199
|
+
const lines = [
|
|
200
|
+
'// Generated by ioBroker.javascript from the central credential store - do not edit',
|
|
201
|
+
'declare namespace iobJS {',
|
|
202
|
+
' interface Secrets {',
|
|
203
|
+
];
|
|
204
|
+
for (const { name, fields } of this.getStructure()) {
|
|
205
|
+
const values = this.cache.get(name);
|
|
206
|
+
// Declare the fields this credential really has, so the editor suggests exactly those
|
|
207
|
+
const members = fields.map(field => `${JSON.stringify(field)}: ${typeof values[field]}`).join('; ');
|
|
208
|
+
lines.push(` ${JSON.stringify(name)}: { ${members} };`);
|
|
209
|
+
}
|
|
210
|
+
lines.push(' }', '}', '');
|
|
211
|
+
return lines.join('\n');
|
|
212
|
+
}
|
|
213
|
+
/** Forgets all decrypted credentials */
|
|
214
|
+
destroy() {
|
|
215
|
+
this.cache.clear();
|
|
216
|
+
this.enabled = false;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
exports.SecretsManager = SecretsManager;
|
|
220
|
+
//# sourceMappingURL=secrets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../src/lib/secrets.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Access to the central ioBroker credential store (`system.credentials.*`) from scripts.\n *\n * The admin UI manages the credentials under \"Basic settings\" → \"Credentials\". Every credential\n * has an ID like `system.credentials.CameraPassword` and holds either a single `key` (API keys)\n * or a `login`/`password` pair. The secret fields are stored encrypted with the system secret.\n *\n * This manager keeps all credentials decrypted in memory and exposes them to the scripts as the\n * global `SECRETS` object, so a script can simply write:\n *\n * ```js\n * const password = SECRETS.CameraPassword.key;\n * ```\n *\n * The cache is kept up to date while the adapter is running, so editing a credential in the admin\n * UI takes effect immediately - without restarting the adapter or the scripts.\n */\n// Imported from its own entry point on purpose: the package index of `@iobroker/adapter-core`\n// looks for js-controller while it is being loaded and terminates the process with exit code 10\n// when it is missing. This module is required by the unit tests, which run without a controller,\n// so it must stay clear of that side effect. `@iobroker/adapter-core/credentials` is free of it -\n// it is written to be usable in browser builds as well.\nimport * as Credentials from '@iobroker/adapter-core/credentials';\n\n/** Prefix of all credential object IDs */\nexport const SECRETS_PREFIX = 'system.credentials.';\n\n/** Decrypted fields of one credential, e.g. `{ key: 'abc' }` or `{ login: 'user', password: 'pass' }` */\nexport type SecretValues = Record<string, string | number | boolean>;\n\n/** The global `SECRETS` object: credential name (ID without the prefix) => decrypted fields */\nexport type Secrets = Record<string, SecretValues>;\n\n/** One credential without its values: only the name and the names of its fields */\nexport interface SecretStructure {\n /** Credential name, i.e. the object ID without the `system.credentials.` prefix */\n name: string;\n /** Names of the fields this credential has, e.g. `['key']` or `['login', 'password']` */\n fields: string[];\n}\n\n/**\n * Checks if the given object ID belongs to the central credential store.\n *\n * @param id Object ID, e.g. `system.credentials.CameraPassword`\n */\nexport function isSecretId(id: string): boolean {\n return id.startsWith(SECRETS_PREFIX) && id.length > SECRETS_PREFIX.length;\n}\n\n/**\n * Extracts the name a credential is exposed under in `SECRETS`.\n *\n * @param id Object ID, e.g. `system.credentials.CameraPassword`\n */\nexport function getSecretName(id: string): string {\n return id.substring(SECRETS_PREFIX.length);\n}\n\nexport class SecretsManager {\n private readonly adapter: ioBroker.Adapter;\n\n /** Decrypted credentials, keyed by name (the credential ID without the `system.credentials.` prefix) */\n private readonly cache: Map<string, Readonly<SecretValues>> = new Map();\n\n /** If the scripts may read the credentials at all (adapter option `enableSecrets`) */\n private enabled = false;\n\n /** Warn only once per script run that the feature is disabled */\n private disabledWarningShown = false;\n\n /**\n * The object handed to the scripts as the global `SECRETS`.\n *\n * It is a read-only view on the cache, so the values stay up to date without the scripts\n * having to re-read anything, and a script cannot modify the credentials of another script.\n */\n public readonly secrets: Secrets;\n\n constructor(adapter: ioBroker.Adapter) {\n this.adapter = adapter;\n\n this.secrets = new Proxy(Object.create(null) as Secrets, {\n get: (_target: Secrets, prop: string | symbol): SecretValues | undefined =>\n typeof prop === 'string' ? this.get(prop) : undefined,\n has: (_target: Secrets, prop: string | symbol): boolean => typeof prop === 'string' && this.cache.has(prop),\n ownKeys: (): string[] => (this.enabled ? Array.from(this.cache.keys()) : []),\n getOwnPropertyDescriptor: (_target: Secrets, prop: string | symbol): PropertyDescriptor | undefined => {\n const value = typeof prop === 'string' ? this.get(prop) : undefined;\n return value === undefined\n ? undefined\n : { value, enumerable: true, configurable: true, writable: false };\n },\n // The credentials belong to the system - scripts may read them, but never change them\n set: (): boolean => false,\n defineProperty: (): boolean => false,\n deleteProperty: (): boolean => false,\n });\n }\n\n /** Reads one credential from the cache and warns if the whole feature is switched off */\n private get(name: string): SecretValues | undefined {\n if (!this.enabled) {\n if (!this.disabledWarningShown) {\n this.disabledWarningShown = true;\n this.adapter.log.warn(\n `A script tried to read the secret \"${name}\", but the access to the credentials is disabled. Enable \"Allow scripts to read the credentials\" in the instance settings.`,\n );\n }\n return undefined;\n }\n return this.cache.get(name);\n }\n\n /**\n * Reads all credentials of the central store and decrypts them.\n *\n * @param enabled Value of the adapter option `enableSecrets`\n */\n async load(enabled: boolean): Promise<void> {\n this.cache.clear();\n this.disabledWarningShown = false;\n this.enabled = enabled;\n\n if (!enabled) {\n return;\n }\n\n if (!Credentials?.listCredentials) {\n this.adapter.log.warn(\n 'Cannot read the credentials for \"SECRETS\": the credentials API is only available with js-controller 7.2 or newer',\n );\n this.enabled = false;\n return;\n }\n\n try {\n const list = await Credentials.listCredentials(this.adapter);\n for (const entry of list) {\n await this.update(entry.id);\n }\n this.adapter.log.debug(`${this.cache.size} secret(s) available in the scripts as \"SECRETS\"`);\n } catch (e: unknown) {\n this.adapter.log.warn(`Cannot read the credentials: ${e instanceof Error ? e.message : String(e)}`);\n }\n }\n\n /**\n * Reads one credential and decrypts it. Called for every change of a `system.credentials.*`\n * object, so edits in the admin UI are visible in the scripts immediately.\n *\n * @param id Object ID, e.g. `system.credentials.CameraPassword`\n */\n async update(id: string): Promise<void> {\n if (!this.enabled || !isSecretId(id)) {\n return;\n }\n const name = getSecretName(id);\n\n try {\n const credentials = await Credentials.getCredentials(this.adapter, id);\n this.cache.set(name, Object.freeze({ ...credentials.values }));\n } catch (e: unknown) {\n this.cache.delete(name);\n this.adapter.log.warn(`Cannot read the secret \"${name}\": ${e instanceof Error ? e.message : String(e)}`);\n }\n }\n\n /**\n * Forgets one credential because its object was deleted.\n *\n * @param id Object ID, e.g. `system.credentials.CameraPassword`\n */\n remove(id: string): void {\n if (isSecretId(id) && this.cache.delete(getSecretName(id))) {\n this.adapter.log.debug(`Secret \"${getSecretName(id)}\" was deleted`);\n }\n }\n\n /**\n * The structure of the credential store without any secret value: which credentials exist and\n * which fields each of them has. Used by the instance settings and the Blockly editor to show\n * the user what `SECRETS.<name>.<field>` expressions are available.\n */\n getStructure(): SecretStructure[] {\n return Array.from(this.cache.entries())\n .map(([name, values]) => ({ name, fields: Object.keys(values).sort() }))\n .sort((a, b) => a.name.localeCompare(b.name));\n }\n\n /**\n * Builds the ambient TypeScript declarations for the credentials that currently exist, so the\n * editor can suggest their names after typing `SECRETS.` and their fields after the next dot.\n * The names are merged into the `iobJS.Secrets` interface, which has an index signature for\n * all other names.\n */\n getDeclarations(): string {\n const lines = [\n '// Generated by ioBroker.javascript from the central credential store - do not edit',\n 'declare namespace iobJS {',\n ' interface Secrets {',\n ];\n for (const { name, fields } of this.getStructure()) {\n const values = this.cache.get(name)!;\n // Declare the fields this credential really has, so the editor suggests exactly those\n const members = fields.map(field => `${JSON.stringify(field)}: ${typeof values[field]}`).join('; ');\n lines.push(` ${JSON.stringify(name)}: { ${members} };`);\n }\n lines.push(' }', '}', '');\n return lines.join('\\n');\n }\n\n /** Forgets all decrypted credentials */\n destroy(): void {\n this.cache.clear();\n this.enabled = false;\n }\n}\n"]}
|
package/build/main.js
CHANGED
|
@@ -78,6 +78,7 @@ const protectFs_1 = __importDefault(require("./lib/protectFs"));
|
|
|
78
78
|
const words_1 = require("./lib/words");
|
|
79
79
|
const sandbox_1 = require("./lib/sandbox");
|
|
80
80
|
const nodeModulesManagement_1 = require("./lib/nodeModulesManagement");
|
|
81
|
+
const secrets_1 = require("./lib/secrets");
|
|
81
82
|
const aiProviderResolver_1 = require("./lib/aiProviderResolver");
|
|
82
83
|
const anthropicAdapter_1 = require("./lib/anthropicAdapter");
|
|
83
84
|
const eventObj_1 = require("./lib/eventObj");
|
|
@@ -328,6 +329,11 @@ class JavaScript extends adapter_core_1.Adapter {
|
|
|
328
329
|
aiCredentialCache = new Map();
|
|
329
330
|
/** Unsubscribe callbacks for the AI credential subscriptions (manager mode). */
|
|
330
331
|
aiCredentialUnsubscribers = [];
|
|
332
|
+
/**
|
|
333
|
+
* Decrypted credentials of the central ioBroker credential store (`system.credentials.*`),
|
|
334
|
+
* exposed to the scripts as the global `SECRETS` object. Kept up to date by `onObjectChange`.
|
|
335
|
+
*/
|
|
336
|
+
secretsManager = new secrets_1.SecretsManager(this);
|
|
331
337
|
globalScript = '';
|
|
332
338
|
/** Generated declarations for global TypeScripts */
|
|
333
339
|
globalDeclarations = '';
|
|
@@ -479,6 +485,7 @@ class JavaScript extends adapter_core_1.Adapter {
|
|
|
479
485
|
adapter: this,
|
|
480
486
|
logError: this.logError.bind(this),
|
|
481
487
|
allowSelfSignedCerts: false,
|
|
488
|
+
secrets: this.secretsManager.secrets,
|
|
482
489
|
};
|
|
483
490
|
this.tsServer = new virtual_tsc_1.Server(typescriptSettings_1.tsCompilerOptions, this.tsLog);
|
|
484
491
|
}
|
|
@@ -509,6 +516,16 @@ class JavaScript extends adapter_core_1.Adapter {
|
|
|
509
516
|
this._enums.delete(id);
|
|
510
517
|
}
|
|
511
518
|
}
|
|
519
|
+
// Keep the decrypted credentials (global `SECRETS`) in sync with the central credential store
|
|
520
|
+
if ((0, secrets_1.isSecretId)(id)) {
|
|
521
|
+
if (obj) {
|
|
522
|
+
await this.secretsManager.update(id);
|
|
523
|
+
}
|
|
524
|
+
else {
|
|
525
|
+
this.secretsManager.remove(id);
|
|
526
|
+
}
|
|
527
|
+
this.updateSecretsDeclarations();
|
|
528
|
+
}
|
|
512
529
|
// IO-9: Invalidate sendTo instance-cache when adapter instances change
|
|
513
530
|
if (id.startsWith('system.adapter.')) {
|
|
514
531
|
const parts = id.split('.');
|
|
@@ -777,6 +794,7 @@ class JavaScript extends adapter_core_1.Adapter {
|
|
|
777
794
|
this.setStateCountCheckInterval = null;
|
|
778
795
|
}
|
|
779
796
|
await this.unsubscribeAiCredentials();
|
|
797
|
+
this.secretsManager.destroy();
|
|
780
798
|
await this.stopAllScripts();
|
|
781
799
|
}
|
|
782
800
|
catch (err) {
|
|
@@ -1401,6 +1419,18 @@ class JavaScript extends adapter_core_1.Adapter {
|
|
|
1401
1419
|
}
|
|
1402
1420
|
break;
|
|
1403
1421
|
}
|
|
1422
|
+
case 'getSecrets': {
|
|
1423
|
+
// Reports which credentials exist and which fields they have, so the instance
|
|
1424
|
+
// settings and the Blockly editor can show the available `SECRETS.<name>.<field>`
|
|
1425
|
+
// expressions. The decrypted values never leave the backend.
|
|
1426
|
+
if (obj.callback) {
|
|
1427
|
+
this.sendTo(obj.from, obj.command, {
|
|
1428
|
+
enabled: this.config.enableSecrets !== false,
|
|
1429
|
+
secrets: this.secretsManager.getStructure(),
|
|
1430
|
+
}, obj.callback);
|
|
1431
|
+
}
|
|
1432
|
+
break;
|
|
1433
|
+
}
|
|
1404
1434
|
case 'prettier': {
|
|
1405
1435
|
// Format the code with Prettier
|
|
1406
1436
|
if (obj.message && typeof obj.message.code === 'string') {
|
|
@@ -1588,6 +1618,10 @@ class JavaScript extends adapter_core_1.Adapter {
|
|
|
1588
1618
|
// In `manager` credential mode, subscribe to the configured AI credentials so changes in the
|
|
1589
1619
|
// central credential store are picked up live (the keys are cached for the AI sendTo handlers).
|
|
1590
1620
|
await this.subscribeAiCredentials();
|
|
1621
|
+
// Read the central credential store, so the scripts can use `SECRETS.<name>.<field>`.
|
|
1622
|
+
// Later changes are picked up in `onObjectChange`.
|
|
1623
|
+
await this.secretsManager.load(this.config.enableSecrets !== false);
|
|
1624
|
+
this.updateSecretsDeclarations();
|
|
1591
1625
|
const doc = await this.getObjectViewAsync('script', 'javascript', {});
|
|
1592
1626
|
if (doc?.rows?.length) {
|
|
1593
1627
|
// sort global scripts if configured
|
|
@@ -1759,6 +1793,23 @@ class JavaScript extends adapter_core_1.Adapter {
|
|
|
1759
1793
|
}
|
|
1760
1794
|
}, 60_000).unref();
|
|
1761
1795
|
}
|
|
1796
|
+
/**
|
|
1797
|
+
* Publishes the names of the existing credentials as ambient declarations, so the editor can
|
|
1798
|
+
* suggest them after typing `SECRETS.` and the TypeScript compiler knows them.
|
|
1799
|
+
*/
|
|
1800
|
+
updateSecretsDeclarations() {
|
|
1801
|
+
if (!tsAmbient) {
|
|
1802
|
+
return;
|
|
1803
|
+
}
|
|
1804
|
+
const declarationPath = 'secrets.d.ts';
|
|
1805
|
+
const declarations = this.secretsManager.getDeclarations();
|
|
1806
|
+
if (tsAmbient[declarationPath] === declarations) {
|
|
1807
|
+
return;
|
|
1808
|
+
}
|
|
1809
|
+
tsAmbient[declarationPath] = declarations;
|
|
1810
|
+
this.tsServer.provideAmbientDeclarations({ [declarationPath]: declarations });
|
|
1811
|
+
jsDeclarationServer.provideAmbientDeclarations({ [declarationPath]: declarations });
|
|
1812
|
+
}
|
|
1762
1813
|
loadTypeScriptDeclarations() {
|
|
1763
1814
|
// try to load the typings on disk for all 3rd party modules
|
|
1764
1815
|
const packages = [
|