@kodelyth/nextcloud-talk 2026.5.39 → 2026.5.42
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/api.ts +1 -0
- package/channel-plugin-api.ts +1 -0
- package/contract-api.ts +4 -0
- package/dist/api.js +2 -0
- package/dist/channel-ej3z6XJ5.js +2094 -0
- package/dist/channel-plugin-api.js +2 -0
- package/dist/contract-api.js +2 -0
- package/dist/doctor-contract-Dia7keG4.js +7 -0
- package/dist/doctor-contract-api.js +2 -0
- package/dist/index.js +22 -0
- package/dist/runtime-api-DCIDXlUd.js +14 -0
- package/dist/runtime-api.js +2 -0
- package/dist/secret-contract-DQ2wQ4m1.js +86 -0
- package/dist/secret-contract-api.js +2 -0
- package/dist/setup-entry.js +15 -0
- package/doctor-contract-api.ts +1 -0
- package/index.ts +20 -0
- package/klaw.plugin.json +2 -799
- package/package.json +4 -4
- package/runtime-api.ts +29 -0
- package/secret-contract-api.ts +5 -0
- package/setup-entry.ts +13 -0
- package/src/accounts.test.ts +31 -0
- package/src/accounts.ts +149 -0
- package/src/api-credentials.ts +31 -0
- package/src/approval-auth.test.ts +17 -0
- package/src/approval-auth.ts +27 -0
- package/src/bot-preflight.test.ts +135 -0
- package/src/bot-preflight.ts +183 -0
- package/src/channel-api.ts +5 -0
- package/src/channel.adapters.ts +52 -0
- package/src/channel.core.test.ts +75 -0
- package/src/channel.lifecycle.test.ts +91 -0
- package/src/channel.status.test.ts +28 -0
- package/src/channel.ts +225 -0
- package/src/config-schema.ts +79 -0
- package/src/core.test.ts +325 -0
- package/src/doctor-contract.ts +9 -0
- package/src/doctor.test.ts +87 -0
- package/src/doctor.ts +40 -0
- package/src/gateway.ts +109 -0
- package/src/inbound.authz.test.ts +146 -0
- package/src/inbound.behavior.test.ts +309 -0
- package/src/inbound.ts +392 -0
- package/src/message-actions.test.ts +270 -0
- package/src/message-actions.ts +82 -0
- package/src/message-adapter.ts +28 -0
- package/src/monitor-runtime.ts +138 -0
- package/src/monitor.replay.test.ts +276 -0
- package/src/monitor.test-fixtures.ts +30 -0
- package/src/monitor.test-harness.ts +59 -0
- package/src/monitor.ts +385 -0
- package/src/normalize.ts +44 -0
- package/src/policy.ts +111 -0
- package/src/replay-guard.ts +128 -0
- package/src/room-info.test.ts +160 -0
- package/src/room-info.ts +130 -0
- package/src/runtime.ts +9 -0
- package/src/secret-contract.ts +103 -0
- package/src/secret-input.ts +4 -0
- package/src/send.cfg-threading.test.ts +359 -0
- package/src/send.runtime.ts +8 -0
- package/src/send.ts +269 -0
- package/src/session-route.ts +40 -0
- package/src/setup-core.ts +250 -0
- package/src/setup-surface.ts +195 -0
- package/src/setup.test.ts +445 -0
- package/src/signature.ts +82 -0
- package/src/types.ts +195 -0
- package/tsconfig.json +16 -0
- package/api.js +0 -7
- package/channel-plugin-api.js +0 -7
- package/contract-api.js +0 -7
- package/doctor-contract-api.js +0 -7
- package/index.js +0 -7
- package/runtime-api.js +0 -7
- package/secret-contract-api.js +0 -7
- package/setup-entry.js +0 -7
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import type { ChannelSetupAdapter, ChannelSetupInput } from "klaw/plugin-sdk/channel-setup";
|
|
2
|
+
import type { KlawConfig } from "klaw/plugin-sdk/config-contracts";
|
|
3
|
+
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "klaw/plugin-sdk/routing";
|
|
4
|
+
import { applyAccountNameToChannelSection, patchScopedAccountConfig } from "klaw/plugin-sdk/setup";
|
|
5
|
+
import {
|
|
6
|
+
createSetupInputPresenceValidator,
|
|
7
|
+
mergeAllowFromEntries,
|
|
8
|
+
promptParsedAllowFromForAccount,
|
|
9
|
+
resolveSetupAccountId,
|
|
10
|
+
createSetupTranslator,
|
|
11
|
+
type ChannelSetupDmPolicy,
|
|
12
|
+
type WizardPrompter,
|
|
13
|
+
} from "klaw/plugin-sdk/setup-runtime";
|
|
14
|
+
import { formatDocsLink } from "klaw/plugin-sdk/setup-tools";
|
|
15
|
+
import { normalizeLowercaseStringOrEmpty } from "klaw/plugin-sdk/string-coerce-runtime";
|
|
16
|
+
import { resolveDefaultNextcloudTalkAccountId, resolveNextcloudTalkAccount } from "./accounts.js";
|
|
17
|
+
import type { CoreConfig } from "./types.js";
|
|
18
|
+
|
|
19
|
+
const t = createSetupTranslator();
|
|
20
|
+
|
|
21
|
+
const channel = "nextcloud-talk" as const;
|
|
22
|
+
|
|
23
|
+
type NextcloudSetupInput = ChannelSetupInput & {
|
|
24
|
+
baseUrl?: string;
|
|
25
|
+
secret?: string;
|
|
26
|
+
secretFile?: string;
|
|
27
|
+
};
|
|
28
|
+
type NextcloudTalkSection = NonNullable<CoreConfig["channels"]>["nextcloud-talk"];
|
|
29
|
+
|
|
30
|
+
function addWildcardAllowFrom(allowFrom?: Array<string | number> | null): string[] {
|
|
31
|
+
return mergeAllowFromEntries(allowFrom, ["*"]);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function normalizeNextcloudTalkBaseUrl(value: string | undefined): string {
|
|
35
|
+
return value?.trim().replace(/\/+$/, "") ?? "";
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function validateNextcloudTalkBaseUrl(value: string): string | undefined {
|
|
39
|
+
if (!value) {
|
|
40
|
+
return "Required";
|
|
41
|
+
}
|
|
42
|
+
if (!value.startsWith("http://") && !value.startsWith("https://")) {
|
|
43
|
+
return "URL must start with http:// or https://";
|
|
44
|
+
}
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function setNextcloudTalkAccountConfig(
|
|
49
|
+
cfg: CoreConfig,
|
|
50
|
+
accountId: string,
|
|
51
|
+
updates: Record<string, unknown>,
|
|
52
|
+
): CoreConfig {
|
|
53
|
+
return patchScopedAccountConfig({
|
|
54
|
+
cfg,
|
|
55
|
+
channelKey: channel,
|
|
56
|
+
accountId,
|
|
57
|
+
patch: updates,
|
|
58
|
+
}) as CoreConfig;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function clearNextcloudTalkAccountFields(
|
|
62
|
+
cfg: CoreConfig,
|
|
63
|
+
accountId: string,
|
|
64
|
+
fields: string[],
|
|
65
|
+
): CoreConfig {
|
|
66
|
+
const section = cfg.channels?.["nextcloud-talk"];
|
|
67
|
+
if (!section) {
|
|
68
|
+
return cfg;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (accountId === DEFAULT_ACCOUNT_ID) {
|
|
72
|
+
const nextSection = { ...section } as Record<string, unknown>;
|
|
73
|
+
for (const field of fields) {
|
|
74
|
+
delete nextSection[field];
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
...cfg,
|
|
78
|
+
channels: {
|
|
79
|
+
...cfg.channels,
|
|
80
|
+
"nextcloud-talk": nextSection as NextcloudTalkSection,
|
|
81
|
+
},
|
|
82
|
+
} as CoreConfig;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const currentAccount = section.accounts?.[accountId];
|
|
86
|
+
if (!currentAccount) {
|
|
87
|
+
return cfg;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const nextAccount = { ...currentAccount } as Record<string, unknown>;
|
|
91
|
+
for (const field of fields) {
|
|
92
|
+
delete nextAccount[field];
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
...cfg,
|
|
96
|
+
channels: {
|
|
97
|
+
...cfg.channels,
|
|
98
|
+
"nextcloud-talk": {
|
|
99
|
+
...section,
|
|
100
|
+
accounts: {
|
|
101
|
+
...section.accounts,
|
|
102
|
+
[accountId]: nextAccount as NonNullable<typeof section.accounts>[string],
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
} as CoreConfig;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function promptNextcloudTalkAllowFrom(params: {
|
|
110
|
+
cfg: CoreConfig;
|
|
111
|
+
prompter: WizardPrompter;
|
|
112
|
+
accountId: string;
|
|
113
|
+
}): Promise<CoreConfig> {
|
|
114
|
+
return await promptParsedAllowFromForAccount({
|
|
115
|
+
cfg: params.cfg,
|
|
116
|
+
accountId: params.accountId,
|
|
117
|
+
defaultAccountId: params.accountId,
|
|
118
|
+
prompter: params.prompter,
|
|
119
|
+
noteTitle: t("wizard.nextcloudTalk.userIdTitle"),
|
|
120
|
+
noteLines: [
|
|
121
|
+
t("wizard.nextcloudTalk.userIdHelpAdmin"),
|
|
122
|
+
t("wizard.nextcloudTalk.userIdHelpLogs"),
|
|
123
|
+
t("wizard.nextcloudTalk.userIdHelpLowercase"),
|
|
124
|
+
t("wizard.channels.docs", {
|
|
125
|
+
link: formatDocsLink("/channels/nextcloud-talk", "nextcloud-talk"),
|
|
126
|
+
}),
|
|
127
|
+
],
|
|
128
|
+
message: t("wizard.nextcloudTalk.allowFromPrompt"),
|
|
129
|
+
placeholder: "username",
|
|
130
|
+
parseEntries: (raw) => ({
|
|
131
|
+
entries: raw
|
|
132
|
+
.split(/[\n,;]+/g)
|
|
133
|
+
.map(normalizeLowercaseStringOrEmpty)
|
|
134
|
+
.filter(Boolean),
|
|
135
|
+
}),
|
|
136
|
+
getExistingAllowFrom: ({ cfg, accountId }) =>
|
|
137
|
+
resolveNextcloudTalkAccount({ cfg, accountId }).config.allowFrom ?? [],
|
|
138
|
+
mergeEntries: ({ existing, parsed }) =>
|
|
139
|
+
mergeAllowFromEntries(
|
|
140
|
+
existing.map((value) => normalizeLowercaseStringOrEmpty(String(value))),
|
|
141
|
+
parsed,
|
|
142
|
+
),
|
|
143
|
+
applyAllowFrom: ({ cfg, accountId, allowFrom }) =>
|
|
144
|
+
setNextcloudTalkAccountConfig(cfg, accountId, {
|
|
145
|
+
dmPolicy: "allowlist",
|
|
146
|
+
allowFrom,
|
|
147
|
+
}),
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async function promptNextcloudTalkAllowFromForAccount(params: {
|
|
152
|
+
cfg: KlawConfig;
|
|
153
|
+
prompter: WizardPrompter;
|
|
154
|
+
accountId?: string;
|
|
155
|
+
}): Promise<KlawConfig> {
|
|
156
|
+
const accountId = resolveSetupAccountId({
|
|
157
|
+
accountId: params.accountId,
|
|
158
|
+
defaultAccountId: resolveDefaultNextcloudTalkAccountId(params.cfg as CoreConfig),
|
|
159
|
+
});
|
|
160
|
+
return await promptNextcloudTalkAllowFrom({
|
|
161
|
+
cfg: params.cfg as CoreConfig,
|
|
162
|
+
prompter: params.prompter,
|
|
163
|
+
accountId,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export const nextcloudTalkDmPolicy: ChannelSetupDmPolicy = {
|
|
168
|
+
label: "Nextcloud Talk",
|
|
169
|
+
channel,
|
|
170
|
+
policyKey: "channels.nextcloud-talk.dmPolicy",
|
|
171
|
+
allowFromKey: "channels.nextcloud-talk.allowFrom",
|
|
172
|
+
resolveConfigKeys: (cfg, accountId) =>
|
|
173
|
+
(accountId ?? resolveDefaultNextcloudTalkAccountId(cfg as CoreConfig)) !== DEFAULT_ACCOUNT_ID
|
|
174
|
+
? {
|
|
175
|
+
policyKey: `channels.nextcloud-talk.accounts.${accountId ?? resolveDefaultNextcloudTalkAccountId(cfg as CoreConfig)}.dmPolicy`,
|
|
176
|
+
allowFromKey: `channels.nextcloud-talk.accounts.${accountId ?? resolveDefaultNextcloudTalkAccountId(cfg as CoreConfig)}.allowFrom`,
|
|
177
|
+
}
|
|
178
|
+
: {
|
|
179
|
+
policyKey: "channels.nextcloud-talk.dmPolicy",
|
|
180
|
+
allowFromKey: "channels.nextcloud-talk.allowFrom",
|
|
181
|
+
},
|
|
182
|
+
getCurrent: (cfg, accountId) =>
|
|
183
|
+
resolveNextcloudTalkAccount({
|
|
184
|
+
cfg: cfg as CoreConfig,
|
|
185
|
+
accountId: accountId ?? resolveDefaultNextcloudTalkAccountId(cfg as CoreConfig),
|
|
186
|
+
}).config.dmPolicy ?? "pairing",
|
|
187
|
+
setPolicy: (cfg, policy, accountId) => {
|
|
188
|
+
const resolvedAccountId = accountId ?? resolveDefaultNextcloudTalkAccountId(cfg as CoreConfig);
|
|
189
|
+
const resolved = resolveNextcloudTalkAccount({
|
|
190
|
+
cfg: cfg as CoreConfig,
|
|
191
|
+
accountId: resolvedAccountId,
|
|
192
|
+
});
|
|
193
|
+
return setNextcloudTalkAccountConfig(cfg as CoreConfig, resolvedAccountId, {
|
|
194
|
+
dmPolicy: policy,
|
|
195
|
+
...(policy === "open" ? { allowFrom: addWildcardAllowFrom(resolved.config.allowFrom) } : {}),
|
|
196
|
+
});
|
|
197
|
+
},
|
|
198
|
+
promptAllowFrom: promptNextcloudTalkAllowFromForAccount,
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
export const nextcloudTalkSetupAdapter: ChannelSetupAdapter = {
|
|
202
|
+
resolveAccountId: ({ accountId }) => normalizeAccountId(accountId),
|
|
203
|
+
applyAccountName: ({ cfg, accountId, name }) =>
|
|
204
|
+
applyAccountNameToChannelSection({
|
|
205
|
+
cfg,
|
|
206
|
+
channelKey: channel,
|
|
207
|
+
accountId,
|
|
208
|
+
name,
|
|
209
|
+
}),
|
|
210
|
+
validateInput: createSetupInputPresenceValidator({
|
|
211
|
+
defaultAccountOnlyEnvError:
|
|
212
|
+
"NEXTCLOUD_TALK_BOT_SECRET can only be used for the default account.",
|
|
213
|
+
validate: ({ input }) => {
|
|
214
|
+
const setupInput = input as NextcloudSetupInput;
|
|
215
|
+
if (!setupInput.useEnv && !setupInput.secret && !setupInput.secretFile) {
|
|
216
|
+
return "Nextcloud Talk requires bot secret or --secret-file (or --use-env).";
|
|
217
|
+
}
|
|
218
|
+
if (!setupInput.baseUrl) {
|
|
219
|
+
return "Nextcloud Talk requires --base-url.";
|
|
220
|
+
}
|
|
221
|
+
return null;
|
|
222
|
+
},
|
|
223
|
+
}),
|
|
224
|
+
applyAccountConfig: ({ cfg, accountId, input }) => {
|
|
225
|
+
const setupInput = input as NextcloudSetupInput;
|
|
226
|
+
const namedConfig = applyAccountNameToChannelSection({
|
|
227
|
+
cfg,
|
|
228
|
+
channelKey: channel,
|
|
229
|
+
accountId,
|
|
230
|
+
name: setupInput.name,
|
|
231
|
+
});
|
|
232
|
+
const next = setupInput.useEnv
|
|
233
|
+
? clearNextcloudTalkAccountFields(namedConfig as CoreConfig, accountId, [
|
|
234
|
+
"botSecret",
|
|
235
|
+
"botSecretFile",
|
|
236
|
+
])
|
|
237
|
+
: namedConfig;
|
|
238
|
+
const patch = {
|
|
239
|
+
baseUrl: normalizeNextcloudTalkBaseUrl(setupInput.baseUrl),
|
|
240
|
+
...(setupInput.useEnv
|
|
241
|
+
? {}
|
|
242
|
+
: setupInput.secretFile
|
|
243
|
+
? { botSecretFile: setupInput.secretFile }
|
|
244
|
+
: setupInput.secret
|
|
245
|
+
? { botSecret: setupInput.secret }
|
|
246
|
+
: {}),
|
|
247
|
+
};
|
|
248
|
+
return setNextcloudTalkAccountConfig(next as CoreConfig, accountId, patch);
|
|
249
|
+
},
|
|
250
|
+
};
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { DEFAULT_ACCOUNT_ID } from "klaw/plugin-sdk/routing";
|
|
2
|
+
import { hasConfiguredSecretInput } from "klaw/plugin-sdk/secret-input";
|
|
3
|
+
import {
|
|
4
|
+
createStandardChannelSetupStatus,
|
|
5
|
+
formatDocsLink,
|
|
6
|
+
setSetupChannelEnabled,
|
|
7
|
+
createSetupTranslator,
|
|
8
|
+
type ChannelSetupWizard,
|
|
9
|
+
} from "klaw/plugin-sdk/setup";
|
|
10
|
+
import { normalizeOptionalString } from "klaw/plugin-sdk/string-coerce-runtime";
|
|
11
|
+
import { resolveNextcloudTalkAccount } from "./accounts.js";
|
|
12
|
+
import {
|
|
13
|
+
clearNextcloudTalkAccountFields,
|
|
14
|
+
nextcloudTalkDmPolicy,
|
|
15
|
+
normalizeNextcloudTalkBaseUrl,
|
|
16
|
+
setNextcloudTalkAccountConfig,
|
|
17
|
+
validateNextcloudTalkBaseUrl,
|
|
18
|
+
} from "./setup-core.js";
|
|
19
|
+
import type { CoreConfig } from "./types.js";
|
|
20
|
+
|
|
21
|
+
const t = createSetupTranslator();
|
|
22
|
+
|
|
23
|
+
const channel = "nextcloud-talk" as const;
|
|
24
|
+
const CONFIGURE_API_FLAG = "__nextcloudTalkConfigureApiCredentials";
|
|
25
|
+
|
|
26
|
+
export const nextcloudTalkSetupWizard: ChannelSetupWizard = {
|
|
27
|
+
channel,
|
|
28
|
+
stepOrder: "text-first",
|
|
29
|
+
status: createStandardChannelSetupStatus({
|
|
30
|
+
channelLabel: "Nextcloud Talk",
|
|
31
|
+
configuredLabel: t("wizard.channels.statusConfigured"),
|
|
32
|
+
unconfiguredLabel: t("wizard.channels.statusNeedsSetup"),
|
|
33
|
+
configuredHint: t("wizard.channels.statusConfigured"),
|
|
34
|
+
unconfiguredHint: t("wizard.channels.statusSelfHostedChat"),
|
|
35
|
+
configuredScore: 1,
|
|
36
|
+
unconfiguredScore: 5,
|
|
37
|
+
resolveConfigured: ({ cfg, accountId }) => {
|
|
38
|
+
const account = resolveNextcloudTalkAccount({ cfg: cfg as CoreConfig, accountId });
|
|
39
|
+
return Boolean(account.secret && account.baseUrl);
|
|
40
|
+
},
|
|
41
|
+
}),
|
|
42
|
+
introNote: {
|
|
43
|
+
title: t("wizard.nextcloudTalk.setupTitle"),
|
|
44
|
+
lines: [
|
|
45
|
+
t("wizard.nextcloudTalk.helpSsh"),
|
|
46
|
+
t("wizard.nextcloudTalk.helpInstallCommand"),
|
|
47
|
+
t("wizard.nextcloudTalk.helpCopySecret"),
|
|
48
|
+
t("wizard.nextcloudTalk.helpEnableRoom"),
|
|
49
|
+
t("wizard.nextcloudTalk.helpEnvTip"),
|
|
50
|
+
t("wizard.channels.docs", {
|
|
51
|
+
link: formatDocsLink("/channels/nextcloud-talk", "channels/nextcloud-talk"),
|
|
52
|
+
}),
|
|
53
|
+
],
|
|
54
|
+
shouldShow: ({ cfg, accountId }) => {
|
|
55
|
+
const account = resolveNextcloudTalkAccount({ cfg: cfg as CoreConfig, accountId });
|
|
56
|
+
return !account.secret || !account.baseUrl;
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
prepare: async ({ cfg, accountId, credentialValues, prompter }) => {
|
|
60
|
+
const resolvedAccount = resolveNextcloudTalkAccount({ cfg: cfg as CoreConfig, accountId });
|
|
61
|
+
const hasApiCredentials = Boolean(
|
|
62
|
+
resolvedAccount.config.apiUser?.trim() &&
|
|
63
|
+
(hasConfiguredSecretInput(resolvedAccount.config.apiPassword) ||
|
|
64
|
+
resolvedAccount.config.apiPasswordFile),
|
|
65
|
+
);
|
|
66
|
+
const configureApiCredentials = await prompter.confirm({
|
|
67
|
+
message: t("wizard.nextcloudTalk.configureApiCredentials"),
|
|
68
|
+
initialValue: hasApiCredentials,
|
|
69
|
+
});
|
|
70
|
+
if (!configureApiCredentials) {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
credentialValues: {
|
|
75
|
+
...credentialValues,
|
|
76
|
+
[CONFIGURE_API_FLAG]: "1",
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
},
|
|
80
|
+
credentials: [
|
|
81
|
+
{
|
|
82
|
+
inputKey: "token",
|
|
83
|
+
providerHint: channel,
|
|
84
|
+
credentialLabel: t("wizard.nextcloudTalk.botSecret"),
|
|
85
|
+
preferredEnvVar: "NEXTCLOUD_TALK_BOT_SECRET",
|
|
86
|
+
envPrompt: t("wizard.nextcloudTalk.botSecretEnvPrompt"),
|
|
87
|
+
keepPrompt: t("wizard.nextcloudTalk.botSecretKeep"),
|
|
88
|
+
inputPrompt: t("wizard.nextcloudTalk.botSecretInput"),
|
|
89
|
+
allowEnv: ({ accountId }) => accountId === DEFAULT_ACCOUNT_ID,
|
|
90
|
+
inspect: ({ cfg, accountId }) => {
|
|
91
|
+
const resolvedAccount = resolveNextcloudTalkAccount({ cfg: cfg as CoreConfig, accountId });
|
|
92
|
+
return {
|
|
93
|
+
accountConfigured: Boolean(resolvedAccount.secret && resolvedAccount.baseUrl),
|
|
94
|
+
hasConfiguredValue: Boolean(
|
|
95
|
+
hasConfiguredSecretInput(resolvedAccount.config.botSecret) ||
|
|
96
|
+
resolvedAccount.config.botSecretFile,
|
|
97
|
+
),
|
|
98
|
+
resolvedValue: resolvedAccount.secret || undefined,
|
|
99
|
+
envValue:
|
|
100
|
+
accountId === DEFAULT_ACCOUNT_ID
|
|
101
|
+
? normalizeOptionalString(process.env.NEXTCLOUD_TALK_BOT_SECRET)
|
|
102
|
+
: undefined,
|
|
103
|
+
};
|
|
104
|
+
},
|
|
105
|
+
applyUseEnv: async (params) => {
|
|
106
|
+
const resolvedAccount = resolveNextcloudTalkAccount({
|
|
107
|
+
cfg: params.cfg as CoreConfig,
|
|
108
|
+
accountId: params.accountId,
|
|
109
|
+
});
|
|
110
|
+
const cleared = clearNextcloudTalkAccountFields(
|
|
111
|
+
params.cfg as CoreConfig,
|
|
112
|
+
params.accountId,
|
|
113
|
+
["botSecret", "botSecretFile"],
|
|
114
|
+
);
|
|
115
|
+
return setNextcloudTalkAccountConfig(cleared, params.accountId, {
|
|
116
|
+
baseUrl: resolvedAccount.baseUrl,
|
|
117
|
+
});
|
|
118
|
+
},
|
|
119
|
+
applySet: async (params) =>
|
|
120
|
+
setNextcloudTalkAccountConfig(
|
|
121
|
+
clearNextcloudTalkAccountFields(params.cfg as CoreConfig, params.accountId, [
|
|
122
|
+
"botSecret",
|
|
123
|
+
"botSecretFile",
|
|
124
|
+
]),
|
|
125
|
+
params.accountId,
|
|
126
|
+
{
|
|
127
|
+
botSecret: params.value,
|
|
128
|
+
},
|
|
129
|
+
),
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
inputKey: "password",
|
|
133
|
+
providerHint: "nextcloud-talk-api",
|
|
134
|
+
credentialLabel: t("wizard.nextcloudTalk.apiPassword"),
|
|
135
|
+
preferredEnvVar: "NEXTCLOUD_TALK_API_PASSWORD",
|
|
136
|
+
envPrompt: "",
|
|
137
|
+
keepPrompt: t("wizard.nextcloudTalk.apiPasswordKeep"),
|
|
138
|
+
inputPrompt: t("wizard.nextcloudTalk.apiPasswordInput"),
|
|
139
|
+
inspect: ({ cfg, accountId }) => {
|
|
140
|
+
const resolvedAccount = resolveNextcloudTalkAccount({ cfg: cfg as CoreConfig, accountId });
|
|
141
|
+
const apiUser = resolvedAccount.config.apiUser?.trim();
|
|
142
|
+
const apiPasswordConfigured = Boolean(
|
|
143
|
+
hasConfiguredSecretInput(resolvedAccount.config.apiPassword) ||
|
|
144
|
+
resolvedAccount.config.apiPasswordFile,
|
|
145
|
+
);
|
|
146
|
+
return {
|
|
147
|
+
accountConfigured: Boolean(apiUser && apiPasswordConfigured),
|
|
148
|
+
hasConfiguredValue: apiPasswordConfigured,
|
|
149
|
+
};
|
|
150
|
+
},
|
|
151
|
+
shouldPrompt: ({ credentialValues }) => credentialValues[CONFIGURE_API_FLAG] === "1",
|
|
152
|
+
applySet: async (params) =>
|
|
153
|
+
setNextcloudTalkAccountConfig(
|
|
154
|
+
clearNextcloudTalkAccountFields(params.cfg as CoreConfig, params.accountId, [
|
|
155
|
+
"apiPassword",
|
|
156
|
+
"apiPasswordFile",
|
|
157
|
+
]),
|
|
158
|
+
params.accountId,
|
|
159
|
+
{
|
|
160
|
+
apiPassword: params.value,
|
|
161
|
+
},
|
|
162
|
+
),
|
|
163
|
+
},
|
|
164
|
+
],
|
|
165
|
+
textInputs: [
|
|
166
|
+
{
|
|
167
|
+
inputKey: "httpUrl",
|
|
168
|
+
message: t("wizard.nextcloudTalk.instanceUrlPrompt"),
|
|
169
|
+
currentValue: ({ cfg, accountId }) =>
|
|
170
|
+
resolveNextcloudTalkAccount({ cfg: cfg as CoreConfig, accountId }).baseUrl || undefined,
|
|
171
|
+
shouldPrompt: ({ currentValue }) => !currentValue,
|
|
172
|
+
validate: ({ value }) => validateNextcloudTalkBaseUrl(value),
|
|
173
|
+
normalizeValue: ({ value }) => normalizeNextcloudTalkBaseUrl(value),
|
|
174
|
+
applySet: async (params) =>
|
|
175
|
+
setNextcloudTalkAccountConfig(params.cfg as CoreConfig, params.accountId, {
|
|
176
|
+
baseUrl: params.value,
|
|
177
|
+
}),
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
inputKey: "userId",
|
|
181
|
+
message: t("wizard.nextcloudTalk.apiUserPrompt"),
|
|
182
|
+
currentValue: ({ cfg, accountId }) =>
|
|
183
|
+
resolveNextcloudTalkAccount({ cfg: cfg as CoreConfig, accountId }).config.apiUser?.trim() ||
|
|
184
|
+
undefined,
|
|
185
|
+
shouldPrompt: ({ credentialValues }) => credentialValues[CONFIGURE_API_FLAG] === "1",
|
|
186
|
+
validate: ({ value }) => (value ? undefined : t("common.required")),
|
|
187
|
+
applySet: async (params) =>
|
|
188
|
+
setNextcloudTalkAccountConfig(params.cfg as CoreConfig, params.accountId, {
|
|
189
|
+
apiUser: params.value,
|
|
190
|
+
}),
|
|
191
|
+
},
|
|
192
|
+
],
|
|
193
|
+
dmPolicy: nextcloudTalkDmPolicy,
|
|
194
|
+
disable: (cfg) => setSetupChannelEnabled(cfg, channel, false),
|
|
195
|
+
};
|