n8n-nodes-antony-cloud-office 0.1.3
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 +151 -0
- package/dist/credentials/AntonyApi.credentials.d.ts +21 -0
- package/dist/credentials/AntonyApi.credentials.js +99 -0
- package/dist/credentials/AntonyApi.credentials.js.map +1 -0
- package/dist/credentials/NextcloudApi.credentials.d.ts +23 -0
- package/dist/credentials/NextcloudApi.credentials.js +198 -0
- package/dist/credentials/NextcloudApi.credentials.js.map +1 -0
- package/dist/nodes/AntonyGraphql/AntonyGraphql.node.d.ts +5 -0
- package/dist/nodes/AntonyGraphql/AntonyGraphql.node.js +279 -0
- package/dist/nodes/AntonyGraphql/AntonyGraphql.node.js.map +1 -0
- package/dist/nodes/AntonyGraphql/antony.svg +58 -0
- package/dist/nodes/AntonyNextcloudNode/NextcloudNode.node.d.ts +6 -0
- package/dist/nodes/AntonyNextcloudNode/NextcloudNode.node.js +1048 -0
- package/dist/nodes/AntonyNextcloudNode/NextcloudNode.node.js.map +1 -0
- package/dist/nodes/AntonyNextcloudNode/antony.svg +58 -0
- package/dist/nodes/AntonyRest/AntonyRest.node.d.ts +10 -0
- package/dist/nodes/AntonyRest/AntonyRest.node.js +168 -0
- package/dist/nodes/AntonyRest/AntonyRest.node.js.map +1 -0
- package/dist/nodes/AntonyRest/antony.svg +58 -0
- package/dist/nodes/shared/restOperations.d.ts +34 -0
- package/dist/nodes/shared/restOperations.js +365 -0
- package/dist/nodes/shared/restOperations.js.map +1 -0
- package/dist/nodes/shared/transport.d.ts +4 -0
- package/dist/nodes/shared/transport.js +38 -0
- package/dist/nodes/shared/transport.js.map +1 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# antony-cloud-office-n8n-nodes
|
|
2
|
+
|
|
3
|
+
Community node package for [Antony Cloud Office](https://www.die-groupware.de).
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## English
|
|
8
|
+
|
|
9
|
+
### Nodes
|
|
10
|
+
|
|
11
|
+
- **Antony REST** — typed operations for known REST endpoints, with form and JSON body modes.
|
|
12
|
+
- **Antony GraphQL** — raw GraphQL execution with schema introspection support.
|
|
13
|
+
- **Antony Nextcloud** — Nextcloud operations not covered by the built-in n8n Nextcloud node.
|
|
14
|
+
|
|
15
|
+
Authentication uses Keycloak username/password. The credential fetches a Bearer token and sends it with every API call.
|
|
16
|
+
|
|
17
|
+
### Build
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install
|
|
21
|
+
npm run build
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Install locally (development)
|
|
25
|
+
|
|
26
|
+
**Option A — pack and install:**
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm run build && npm pack
|
|
30
|
+
cd ~/.n8n
|
|
31
|
+
npm install /path/to/antony-cloud-office-n8n-nodes-0.1.0.tgz
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Restart n8n afterwards.
|
|
35
|
+
|
|
36
|
+
**Option B — npm link (live rebuild):**
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm run build
|
|
40
|
+
npm link
|
|
41
|
+
|
|
42
|
+
mkdir -p ~/.n8n/custom && cd ~/.n8n/custom
|
|
43
|
+
npm init -y
|
|
44
|
+
npm link --save antony-cloud-office-n8n-nodes
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
After each code change run `npm run build` and restart n8n.
|
|
48
|
+
|
|
49
|
+
**Docker with npm link** — the linked project directory must also be mounted into the container:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
docker run -d --rm \
|
|
53
|
+
--name n8n \
|
|
54
|
+
-p 5678:5678 \
|
|
55
|
+
-v ~/.n8n:/home/node/.n8n \
|
|
56
|
+
-v /path/to/n8nnodes:/home/node/n8nnodes \
|
|
57
|
+
-e N8N_COMMUNITY_PACKAGES_ENABLED=true \
|
|
58
|
+
-e N8N_CUSTOM_EXTENSIONS=/home/node/.n8n/custom \
|
|
59
|
+
n8nio/n8n
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Configure credentials
|
|
63
|
+
|
|
64
|
+
Create a credential of type **Antony API** and fill in:
|
|
65
|
+
|
|
66
|
+
| Field | Example |
|
|
67
|
+
|---|---|
|
|
68
|
+
| Base URL | `https://your-antony-instance` |
|
|
69
|
+
| Keycloak Realm | `antony` |
|
|
70
|
+
| Keycloak Client ID | `antonyfe` |
|
|
71
|
+
| Username / Password | your credentials |
|
|
72
|
+
|
|
73
|
+
### Troubleshooting
|
|
74
|
+
|
|
75
|
+
- Nodes not showing: run `npm run build`, restart n8n, check `N8N_COMMUNITY_PACKAGES_ENABLED=true`.
|
|
76
|
+
- Login fails: no trailing slash in Base URL, verify realm/client ID and that password grant is allowed.
|
|
77
|
+
- GraphQL introspection fails: test the credential, check that the user has introspection access on `/api/v2/graphql`.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Deutsch
|
|
82
|
+
|
|
83
|
+
### Nodes
|
|
84
|
+
|
|
85
|
+
- **Antony REST** — typisierte Operationen für bekannte REST-Endpunkte, mit Formular- und JSON-Body-Modus.
|
|
86
|
+
- **Antony GraphQL** — direkte GraphQL-Ausführung mit Schema-Introspection.
|
|
87
|
+
- **Antony Nextcloud** — Nextcloud-Operationen, die der eingebaute n8n-Nextcloud-Node nicht abdeckt.
|
|
88
|
+
|
|
89
|
+
Die Authentifizierung läuft über Keycloak (Benutzername/Passwort). Der Credential holt sich einen Bearer Token und sendet ihn bei jedem API-Aufruf mit.
|
|
90
|
+
|
|
91
|
+
### Build
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
npm install
|
|
95
|
+
npm run build
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Lokal installieren (Entwicklung)
|
|
99
|
+
|
|
100
|
+
**Variante A — Pack und Install:**
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
npm run build && npm pack
|
|
104
|
+
cd ~/.n8n
|
|
105
|
+
npm install /pfad/zu/antony-cloud-office-n8n-nodes-0.1.0.tgz
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Danach n8n neu starten.
|
|
109
|
+
|
|
110
|
+
**Variante B — npm link (Live-Rebuild):**
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
npm run build
|
|
114
|
+
npm link
|
|
115
|
+
|
|
116
|
+
mkdir -p ~/.n8n/custom && cd ~/.n8n/custom
|
|
117
|
+
npm init -y
|
|
118
|
+
npm link --save antony-cloud-office-n8n-nodes
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Nach jeder Code-Änderung `npm run build` ausführen und n8n neu starten.
|
|
122
|
+
|
|
123
|
+
**Docker mit npm link** — das verlinkte Projektverzeichnis muss zusätzlich in den Container gemountet werden:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
docker run -d --rm \
|
|
127
|
+
--name n8n \
|
|
128
|
+
-p 5678:5678 \
|
|
129
|
+
-v ~/.n8n:/home/node/.n8n \
|
|
130
|
+
-v /pfad/zu/n8nnodes:/home/node/n8nnodes \
|
|
131
|
+
-e N8N_COMMUNITY_PACKAGES_ENABLED=true \
|
|
132
|
+
-e N8N_CUSTOM_EXTENSIONS=/home/node/.n8n/custom \
|
|
133
|
+
n8nio/n8n
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Credentials konfigurieren
|
|
137
|
+
|
|
138
|
+
Credential vom Typ **Antony API** anlegen und ausfüllen:
|
|
139
|
+
|
|
140
|
+
| Feld | Beispiel |
|
|
141
|
+
|---|---|
|
|
142
|
+
| Base URL | `https://deine-antony-instanz` |
|
|
143
|
+
| Keycloak Realm | `antony` |
|
|
144
|
+
| Keycloak Client ID | `antonyfe` |
|
|
145
|
+
| Benutzername / Passwort | deine Zugangsdaten |
|
|
146
|
+
|
|
147
|
+
### Fehlerbehebung
|
|
148
|
+
|
|
149
|
+
- Nodes erscheinen nicht: `npm run build` ausführen, n8n neu starten, `N8N_COMMUNITY_PACKAGES_ENABLED=true` prüfen.
|
|
150
|
+
- Login schlägt fehl: Base URL ohne Slash am Ende, Realm und Client ID prüfen, Password Grant im Keycloak-Client aktivieren.
|
|
151
|
+
- GraphQL-Introspection schlägt fehl: Credential testen, prüfen ob der Benutzer Introspection-Zugriff auf `/api/v2/graphql` hat.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ICredentialDataDecryptedObject, ICredentialTestRequest, ICredentialType, IHttpRequestOptions, INodeProperties } from 'n8n-workflow';
|
|
2
|
+
export declare class AntonyApi implements ICredentialType {
|
|
3
|
+
name: string;
|
|
4
|
+
displayName: string;
|
|
5
|
+
documentationUrl: string;
|
|
6
|
+
properties: INodeProperties[];
|
|
7
|
+
preAuthentication(this: {
|
|
8
|
+
helpers: {
|
|
9
|
+
httpRequest(options: IHttpRequestOptions): Promise<unknown>;
|
|
10
|
+
};
|
|
11
|
+
}, credentials: ICredentialDataDecryptedObject): Promise<ICredentialDataDecryptedObject>;
|
|
12
|
+
authenticate: {
|
|
13
|
+
type: "generic";
|
|
14
|
+
properties: {
|
|
15
|
+
headers: {
|
|
16
|
+
Authorization: string;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
test: ICredentialTestRequest;
|
|
21
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AntonyApi = void 0;
|
|
4
|
+
class AntonyApi {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.name = 'antonyApi';
|
|
7
|
+
this.displayName = 'Antony API';
|
|
8
|
+
this.documentationUrl = 'https://antonyoffice.cloud';
|
|
9
|
+
this.properties = [
|
|
10
|
+
{
|
|
11
|
+
displayName: 'Base URL',
|
|
12
|
+
name: 'baseUrl',
|
|
13
|
+
type: 'string',
|
|
14
|
+
default: '',
|
|
15
|
+
placeholder: 'https://<ANTONY_BASE_URL>',
|
|
16
|
+
required: true,
|
|
17
|
+
description: 'Antony base URL without trailing slash',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
displayName: 'Keycloak Realm',
|
|
21
|
+
name: 'realm',
|
|
22
|
+
type: 'string',
|
|
23
|
+
default: 'antony',
|
|
24
|
+
required: true,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
displayName: 'Keycloak Client ID',
|
|
28
|
+
name: 'clientId',
|
|
29
|
+
type: 'string',
|
|
30
|
+
default: 'antonyfe',
|
|
31
|
+
required: true,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
displayName: 'Username',
|
|
35
|
+
name: 'username',
|
|
36
|
+
type: 'string',
|
|
37
|
+
default: '',
|
|
38
|
+
required: true,
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
displayName: 'Password',
|
|
42
|
+
name: 'password',
|
|
43
|
+
type: 'string',
|
|
44
|
+
typeOptions: { password: true },
|
|
45
|
+
default: '',
|
|
46
|
+
required: true,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
displayName: 'Access Token',
|
|
50
|
+
name: 'accessToken',
|
|
51
|
+
type: 'hidden',
|
|
52
|
+
typeOptions: { expirable: true },
|
|
53
|
+
default: '',
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
this.authenticate = {
|
|
57
|
+
type: 'generic',
|
|
58
|
+
properties: {
|
|
59
|
+
headers: {
|
|
60
|
+
Authorization: '=Bearer {{$credentials.accessToken}}',
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
this.test = {
|
|
65
|
+
request: {
|
|
66
|
+
baseURL: '={{$credentials.baseUrl.replace(/\\/$/, "")}}',
|
|
67
|
+
url: '/api/v2/modules',
|
|
68
|
+
method: 'GET',
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
async preAuthentication(credentials) {
|
|
73
|
+
const baseUrl = String(credentials.baseUrl).replace(/\/$/, '');
|
|
74
|
+
const realm = encodeURIComponent(String(credentials.realm));
|
|
75
|
+
const tokenUrl = `${baseUrl}/kc/realms/${realm}/protocol/openid-connect/token`;
|
|
76
|
+
const response = (await this.helpers.httpRequest({
|
|
77
|
+
method: 'POST',
|
|
78
|
+
url: tokenUrl,
|
|
79
|
+
headers: {
|
|
80
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
81
|
+
},
|
|
82
|
+
body: new URLSearchParams({
|
|
83
|
+
grant_type: 'password',
|
|
84
|
+
client_id: String(credentials.clientId),
|
|
85
|
+
username: String(credentials.username),
|
|
86
|
+
password: String(credentials.password),
|
|
87
|
+
}).toString(),
|
|
88
|
+
json: true,
|
|
89
|
+
}));
|
|
90
|
+
if (!response.access_token) {
|
|
91
|
+
throw new Error('Keycloak did not return an access_token.');
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
accessToken: response.access_token,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
exports.AntonyApi = AntonyApi;
|
|
99
|
+
//# sourceMappingURL=AntonyApi.credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AntonyApi.credentials.js","sourceRoot":"","sources":["../../credentials/AntonyApi.credentials.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ICredentialDataDecryptedObject, ICredentialTestRequest, ICredentialType, IHttpRequestOptions, INodeProperties } from 'n8n-workflow';
|
|
2
|
+
export declare class NextcloudApi implements ICredentialType {
|
|
3
|
+
name: string;
|
|
4
|
+
displayName: string;
|
|
5
|
+
documentationUrl: string;
|
|
6
|
+
properties: INodeProperties[];
|
|
7
|
+
preAuthentication(this: {
|
|
8
|
+
helpers: {
|
|
9
|
+
httpRequest(options: IHttpRequestOptions): Promise<unknown>;
|
|
10
|
+
};
|
|
11
|
+
}, credentials: ICredentialDataDecryptedObject): Promise<ICredentialDataDecryptedObject>;
|
|
12
|
+
authenticate: {
|
|
13
|
+
type: "generic";
|
|
14
|
+
properties: {
|
|
15
|
+
headers: {
|
|
16
|
+
Authorization: string;
|
|
17
|
+
'OCS-APIRequest': string;
|
|
18
|
+
Accept: string;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
test: ICredentialTestRequest;
|
|
23
|
+
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NextcloudApi = void 0;
|
|
4
|
+
function getEnvironmentBaseUrl(baseUrl) {
|
|
5
|
+
return baseUrl
|
|
6
|
+
.trim()
|
|
7
|
+
.replace(/\/+$/, '')
|
|
8
|
+
.replace(/\/(?:nc|kc)$/i, '');
|
|
9
|
+
}
|
|
10
|
+
class NextcloudApi {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.name = 'nextcloudApi';
|
|
13
|
+
this.displayName = 'Nextcloud API';
|
|
14
|
+
this.documentationUrl = 'https://docs.nextcloud.com/server/latest/developer_manual/client_apis/';
|
|
15
|
+
this.properties = [
|
|
16
|
+
{
|
|
17
|
+
displayName: 'Base URL',
|
|
18
|
+
name: 'baseUrl',
|
|
19
|
+
type: 'string',
|
|
20
|
+
default: '',
|
|
21
|
+
placeholder: 'https://<NEXTCLOUD_BASE_URL>',
|
|
22
|
+
required: true,
|
|
23
|
+
description: 'Base URL der Umgebung ohne /nc oder /kc. Falls /nc oder /kc angegeben wird, wird es automatisch normalisiert.',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
displayName: 'Authentication Method',
|
|
27
|
+
name: 'authMethod',
|
|
28
|
+
type: 'options',
|
|
29
|
+
options: [
|
|
30
|
+
{
|
|
31
|
+
name: 'Basic Auth – App Password (Recommended)',
|
|
32
|
+
value: 'appPassword',
|
|
33
|
+
description: 'Generate an App Password in Nextcloud → Settings → Security → App passwords',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: 'OIDC / Keycloak – Bearer Token',
|
|
37
|
+
value: 'oidc',
|
|
38
|
+
description: 'Requires user_oidc app with token introspection configured in Nextcloud',
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
default: 'appPassword',
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
displayName: 'Username',
|
|
45
|
+
name: 'username',
|
|
46
|
+
type: 'string',
|
|
47
|
+
default: '',
|
|
48
|
+
required: true,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
displayName: 'App Password',
|
|
52
|
+
name: 'appPassword',
|
|
53
|
+
type: 'string',
|
|
54
|
+
typeOptions: { password: true },
|
|
55
|
+
default: '',
|
|
56
|
+
description: 'App-specific password generated in Nextcloud → Settings → Security → App passwords',
|
|
57
|
+
displayOptions: { show: { authMethod: ['appPassword'] } },
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
displayName: 'Password',
|
|
61
|
+
name: 'password',
|
|
62
|
+
type: 'string',
|
|
63
|
+
typeOptions: { password: true },
|
|
64
|
+
default: '',
|
|
65
|
+
displayOptions: { show: { authMethod: ['oidc'] } },
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
displayName: 'Keycloak Realm',
|
|
69
|
+
name: 'realm',
|
|
70
|
+
type: 'string',
|
|
71
|
+
default: '',
|
|
72
|
+
displayOptions: { show: { authMethod: ['oidc'] } },
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
displayName: 'Keycloak Client ID',
|
|
76
|
+
name: 'clientId',
|
|
77
|
+
type: 'string',
|
|
78
|
+
default: '',
|
|
79
|
+
description: 'Must have "Direct Access Grants" enabled in Keycloak',
|
|
80
|
+
displayOptions: { show: { authMethod: ['oidc'] } },
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
displayName: 'Bearer Token Type',
|
|
84
|
+
name: 'bearerTokenType',
|
|
85
|
+
type: 'options',
|
|
86
|
+
options: [
|
|
87
|
+
{
|
|
88
|
+
name: 'Access Token',
|
|
89
|
+
value: 'access_token',
|
|
90
|
+
description: 'Use Keycloak access_token as Bearer token',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: 'ID Token',
|
|
94
|
+
value: 'id_token',
|
|
95
|
+
description: 'Use Keycloak id_token as Bearer token; useful for some Nextcloud user_oidc setups',
|
|
96
|
+
},
|
|
97
|
+
],
|
|
98
|
+
default: 'access_token',
|
|
99
|
+
displayOptions: { show: { authMethod: ['oidc'] } },
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
displayName: 'Authorization',
|
|
103
|
+
name: 'accessToken',
|
|
104
|
+
type: 'hidden',
|
|
105
|
+
typeOptions: { expirable: true },
|
|
106
|
+
default: '',
|
|
107
|
+
},
|
|
108
|
+
];
|
|
109
|
+
this.authenticate = {
|
|
110
|
+
type: 'generic',
|
|
111
|
+
properties: {
|
|
112
|
+
headers: {
|
|
113
|
+
Authorization: '={{$credentials.accessToken}}',
|
|
114
|
+
'OCS-APIRequest': 'true',
|
|
115
|
+
Accept: 'application/json',
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
this.test = {
|
|
120
|
+
request: {
|
|
121
|
+
baseURL: '={{$credentials.baseUrl.trim().replace(/\\/+$/, "").replace(/\\/(nc|kc)$/i, "") + "/nc"}}',
|
|
122
|
+
url: '/ocs/v2.php/cloud/user?format=json',
|
|
123
|
+
method: 'GET',
|
|
124
|
+
headers: {
|
|
125
|
+
'OCS-APIRequest': 'true',
|
|
126
|
+
Accept: 'application/json',
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
rules: [
|
|
130
|
+
{
|
|
131
|
+
type: 'responseCode',
|
|
132
|
+
properties: {
|
|
133
|
+
value: 401,
|
|
134
|
+
message: 'Nextcloud HTTP 401: Username/App-Passwort falsch, oder ein Keycloak-Bearer-Token wird von Nextcloud nicht fuer OCS akzeptiert.',
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
type: 'responseCode',
|
|
139
|
+
properties: {
|
|
140
|
+
value: 404,
|
|
141
|
+
message: 'Nextcloud HTTP 404: Base URL pruefen. Erwartet wird die Umgebung ohne /nc oder /kc; der Test ruft automatisch /nc/ocs/v2.php/cloud/user auf.',
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
],
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
async preAuthentication(credentials) {
|
|
148
|
+
const authMethod = String(credentials.authMethod || 'appPassword');
|
|
149
|
+
if (authMethod === 'appPassword') {
|
|
150
|
+
const username = String(credentials.username);
|
|
151
|
+
const appPassword = String(credentials.appPassword);
|
|
152
|
+
const encoded = Buffer.from(`${username}:${appPassword}`).toString('base64');
|
|
153
|
+
return { accessToken: `Basic ${encoded}` };
|
|
154
|
+
}
|
|
155
|
+
// OIDC / Keycloak – URL aus baseUrl ableiten
|
|
156
|
+
const base = getEnvironmentBaseUrl(String(credentials.baseUrl));
|
|
157
|
+
const keycloakUrl = `${base}/kc`;
|
|
158
|
+
const realm = encodeURIComponent(String(credentials.realm));
|
|
159
|
+
const tokenUrl = `${keycloakUrl}/realms/${realm}/protocol/openid-connect/token`;
|
|
160
|
+
let tokenResponse;
|
|
161
|
+
const bearerTokenType = String(credentials.bearerTokenType || 'access_token');
|
|
162
|
+
try {
|
|
163
|
+
tokenResponse = (await this.helpers.httpRequest({
|
|
164
|
+
method: 'POST',
|
|
165
|
+
url: tokenUrl,
|
|
166
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
167
|
+
body: new URLSearchParams({
|
|
168
|
+
grant_type: 'password',
|
|
169
|
+
client_id: String(credentials.clientId),
|
|
170
|
+
username: String(credentials.username),
|
|
171
|
+
password: String(credentials.password),
|
|
172
|
+
scope: 'openid',
|
|
173
|
+
}).toString(),
|
|
174
|
+
json: true,
|
|
175
|
+
}));
|
|
176
|
+
}
|
|
177
|
+
catch (err) {
|
|
178
|
+
// httpRequest wirft bei 4xx/5xx – Keycloak-Fehlerbody extrahieren
|
|
179
|
+
const body = err?.response?.body ?? err?.response?.data;
|
|
180
|
+
const detail = typeof body === 'object'
|
|
181
|
+
? (body?.error_description ?? body?.error ?? JSON.stringify(body))
|
|
182
|
+
: String(body ?? err.message);
|
|
183
|
+
throw new Error(`Keycloak token request failed (${tokenUrl}): ${detail}`);
|
|
184
|
+
}
|
|
185
|
+
if (tokenResponse.error) {
|
|
186
|
+
throw new Error(`Keycloak error: ${tokenResponse.error}` +
|
|
187
|
+
(tokenResponse.error_description ? ` – ${tokenResponse.error_description}` : ''));
|
|
188
|
+
}
|
|
189
|
+
const bearerToken = tokenResponse[bearerTokenType];
|
|
190
|
+
if (!bearerToken) {
|
|
191
|
+
throw new Error(`Keycloak returned no ${bearerTokenType}. ` +
|
|
192
|
+
`Check: realm="${String(credentials.realm)}", clientId, Direct Access Grants enabled, username/password.`);
|
|
193
|
+
}
|
|
194
|
+
return { accessToken: `Bearer ${bearerToken}` };
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
exports.NextcloudApi = NextcloudApi;
|
|
198
|
+
//# sourceMappingURL=NextcloudApi.credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NextcloudApi.credentials.js","sourceRoot":"","sources":["../../credentials/NextcloudApi.credentials.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
|
|
2
|
+
export declare class AntonyGraphql implements INodeType {
|
|
3
|
+
description: INodeTypeDescription;
|
|
4
|
+
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
5
|
+
}
|