@t0mer/n8n-nodes-ssllabs 2026.9.0

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.
Files changed (62) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +234 -0
  3. package/dist/assets/demo/ssllabs-demo.png +0 -0
  4. package/dist/credentials/SslLabsApi.credentials.d.ts +10 -0
  5. package/dist/credentials/SslLabsApi.credentials.js +46 -0
  6. package/dist/credentials/SslLabsApi.credentials.js.map +1 -0
  7. package/dist/credentials/sslLabs.dark.svg +9 -0
  8. package/dist/credentials/sslLabs.svg +9 -0
  9. package/dist/nodes/SslLabs/SslLabs.node.d.ts +5 -0
  10. package/dist/nodes/SslLabs/SslLabs.node.js +91 -0
  11. package/dist/nodes/SslLabs/SslLabs.node.js.map +1 -0
  12. package/dist/nodes/SslLabs/SslLabs.node.json +18 -0
  13. package/dist/nodes/SslLabs/resources/assessment.d.ts +11 -0
  14. package/dist/nodes/SslLabs/resources/assessment.js +258 -0
  15. package/dist/nodes/SslLabs/resources/assessment.js.map +1 -0
  16. package/dist/nodes/SslLabs/resources/endpoint.d.ts +2 -0
  17. package/dist/nodes/SslLabs/resources/endpoint.js +77 -0
  18. package/dist/nodes/SslLabs/resources/endpoint.js.map +1 -0
  19. package/dist/nodes/SslLabs/resources/registration.d.ts +2 -0
  20. package/dist/nodes/SslLabs/resources/registration.js +71 -0
  21. package/dist/nodes/SslLabs/resources/registration.js.map +1 -0
  22. package/dist/nodes/SslLabs/resources/service.d.ts +3 -0
  23. package/dist/nodes/SslLabs/resources/service.js +86 -0
  24. package/dist/nodes/SslLabs/resources/service.js.map +1 -0
  25. package/dist/nodes/SslLabs/shared.d.ts +11 -0
  26. package/dist/nodes/SslLabs/shared.js +26 -0
  27. package/dist/nodes/SslLabs/shared.js.map +1 -0
  28. package/dist/nodes/SslLabs/sslLabs.dark.svg +9 -0
  29. package/dist/nodes/SslLabs/sslLabs.svg +9 -0
  30. package/dist/nodes/SslLabsTrigger/SslLabsTrigger.node.d.ts +5 -0
  31. package/dist/nodes/SslLabsTrigger/SslLabsTrigger.node.js +237 -0
  32. package/dist/nodes/SslLabsTrigger/SslLabsTrigger.node.js.map +1 -0
  33. package/dist/nodes/SslLabsTrigger/SslLabsTrigger.node.json +18 -0
  34. package/dist/nodes/SslLabsTrigger/sslLabs.dark.svg +9 -0
  35. package/dist/nodes/SslLabsTrigger/sslLabs.svg +9 -0
  36. package/dist/nodes/SslLabsTrigger/state.d.ts +35 -0
  37. package/dist/nodes/SslLabsTrigger/state.js +122 -0
  38. package/dist/nodes/SslLabsTrigger/state.js.map +1 -0
  39. package/dist/package.json +73 -0
  40. package/dist/shared/batch.d.ts +24 -0
  41. package/dist/shared/batch.js +66 -0
  42. package/dist/shared/batch.js.map +1 -0
  43. package/dist/shared/grades.d.ts +8 -0
  44. package/dist/shared/grades.js +38 -0
  45. package/dist/shared/grades.js.map +1 -0
  46. package/dist/shared/host.d.ts +2 -0
  47. package/dist/shared/host.js +38 -0
  48. package/dist/shared/host.js.map +1 -0
  49. package/dist/shared/poll.d.ts +29 -0
  50. package/dist/shared/poll.js +81 -0
  51. package/dist/shared/poll.js.map +1 -0
  52. package/dist/shared/summary.d.ts +8 -0
  53. package/dist/shared/summary.js +87 -0
  54. package/dist/shared/summary.js.map +1 -0
  55. package/dist/shared/transport.d.ts +37 -0
  56. package/dist/shared/transport.js +161 -0
  57. package/dist/shared/transport.js.map +1 -0
  58. package/dist/shared/types.d.ts +88 -0
  59. package/dist/shared/types.js +3 -0
  60. package/dist/shared/types.js.map +1 -0
  61. package/dist/tsconfig.tsbuildinfo +1 -0
  62. package/package.json +73 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 t0mer
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,234 @@
1
+ # @t0mer/n8n-nodes-ssllabs
2
+
3
+ An [n8n](https://n8n.io/) community node for the [Qualys SSL Labs API v4](https://github.com/ssllabs/ssllabs-scan/blob/master/ssllabs-api-docs-v4.md). It runs SSL/TLS server assessments, returns grades, endpoint details and certificate data, and watches your hosts for grade or certificate changes.
4
+
5
+ It ships two nodes and one credential:
6
+
7
+ | | |
8
+ |---|---|
9
+ | **SSL Labs** | Action node: run assessments, read endpoint details, get service info, and register your email |
10
+ | **SSL Labs Trigger** | Polling trigger: grade changed, grade below a threshold, or certificate expiring |
11
+ | **SSL Labs API** | Credential: your registered email address and the API base URL |
12
+
13
+ > **Not affiliated with Qualys.** This is an unofficial, community-maintained node. SSL Labs is a free service provided by Qualys; use it according to the [SSL Labs terms](https://www.ssllabs.com/about/terms.html). **Only assess hosts you own or are authorized to test.**
14
+
15
+ - [Demo](#demo)
16
+ - [Installation](#installation)
17
+ - [Registration](#registration)
18
+ - [Credentials](#credentials)
19
+ - [SSL Labs node](#ssl-labs-node)
20
+ - [SSL Labs Trigger](#ssl-labs-trigger)
21
+ - [Rate limits and timing](#rate-limits-and-timing)
22
+ - [Compatibility](#compatibility)
23
+ - [Resources](#resources)
24
+
25
+ ## Demo
26
+
27
+ [![SSL Labs for n8n demo: credential, registration, Analyze and the trigger's test event](https://raw.githubusercontent.com/t0mer/n8n-nodes-ssllabs/main/assets/demo/ssllabs-demo.png)](https://github.com/t0mer/n8n-nodes-ssllabs/raw/main/assets/demo/ssllabs-demo.mp4)
28
+
29
+ ▶️ [Watch the demo video](https://github.com/t0mer/n8n-nodes-ssllabs/raw/main/assets/demo/ssllabs-demo.mp4) (2½ min). It shows:
30
+ - the credential
31
+ - a free-mailbox registration being rejected (email addresses are blurred)
32
+ - Get Info, then Analyze of `www.ssllabs.com`, with cache on and publish off
33
+ - the trigger's Fetch Test Event
34
+
35
+ ## Installation
36
+
37
+ **From the n8n UI** (self-hosted): go to **Settings → Community Nodes → Install**, enter `@t0mer/n8n-nodes-ssllabs`, and confirm.
38
+
39
+ **From npm**, in your n8n custom nodes folder (usually `~/.n8n/nodes`):
40
+
41
+ ```bash
42
+ npm install @t0mer/n8n-nodes-ssllabs
43
+ ```
44
+
45
+ Then restart n8n. See the [community nodes installation guide](https://docs.n8n.io/integrations/community-nodes/installation/) for details.
46
+
47
+ ## Registration
48
+
49
+ API v4 requires every caller to register an email address once. Qualys rejects free mailbox domains such as Gmail, Yahoo or Hotmail, so use an organization address.
50
+
51
+ You can register in either of two ways:
52
+
53
+ - **With this node:** add an **SSL Labs** node and choose **Resource: Registration → Register**. Fill in first name, last name, email and organization, then run it. This operation does not need a credential; if you attach one, its base URL is used. Any rejection message from SSL Labs is shown as-is.
54
+ - **With the official CLI:** build and run `ssllabs-scan-v4-register` from the [ssllabs-scan](https://github.com/ssllabs/ssllabs-scan) repository. Its README lists the flags it takes.
55
+
56
+ You only register once per email address.
57
+
58
+ ## Credentials
59
+
60
+ Create an **SSL Labs API** credential:
61
+
62
+ | Field | Description |
63
+ |---|---|
64
+ | **Email** | The address you registered. It is sent as the `email` header on every call. |
65
+ | **Base URL** | Defaults to `https://api.ssllabs.com/api/v4`. Use `https://api.dev.ssllabs.com/api/v4` for the development server, which has lower limits and no availability guarantee. |
66
+
67
+ The credential test calls `/info`, so it only proves that the API is reachable. An unregistered email fails on the first assessment with *"Email is not registered with SSL Labs v4 — use the Register operation first"*.
68
+
69
+ ## SSL Labs node
70
+
71
+ ### Assessment → Analyze
72
+
73
+ This operation assesses a host. The **Host** field takes a bare hostname; if you paste a URL such as `https://Example.com:443/path`, it is reduced to `example.com`.
74
+
75
+ | Mode | What it does |
76
+ |---|---|
77
+ | **Wait for Result** (default) | Starts an assessment (or reuses a cached one) and polls until it is READY or ERROR, or the timeout passes. |
78
+ | **Start Only** | Starts the assessment and returns right away with its current status. Use it for long batches that you split across workflow runs. |
79
+ | **Get Status** | Makes a single call without forcing a new scan and returns the current state. Note that SSL Labs itself starts an assessment when nothing fresh enough is cached. |
80
+
81
+ **Parameters**
82
+
83
+ | Parameter | Default | Notes |
84
+ |---|---|---|
85
+ | Use Cache | on | Accept a cached report (`fromCache=on`). |
86
+ | Max Cache Age (Hours) | 24 | Only accept cached reports up to this old. `0` accepts any age. |
87
+ | Force New Scan | off | Only shown when Use Cache is off. Sends `startNew=on`. SSL Labs does not allow both flags at once, and the node rejects that combination too. |
88
+
89
+ **Options**
90
+
91
+ | Option | Default | Notes |
92
+ |---|---|---|
93
+ | Batch Concurrency | 3 | Maximum parallel assessments when there are several input items (max 10). |
94
+ | Detail Level | Summary | **Summary** returns the compact shape below. **Full** returns the raw SSL Labs `Host` object plus `reportUrl`. |
95
+ | Fail on Assessment Error | on | When off, an assessment that ends in ERROR is returned as an item instead of failing the node. |
96
+ | Ignore Certificate Mismatch | off | Continue even when the certificate does not match the hostname. |
97
+ | Initial Poll Interval (Seconds) | 5 | How often to poll while the status is `DNS` (minimum 5). |
98
+ | Poll Interval (Seconds) | 10 | How often to poll once the status is `IN_PROGRESS` (minimum 5). |
99
+ | Publish Results | **off** | ⚠️ **Published results appear on the public SSL Labs boards.** Leave this off unless you really want that. |
100
+ | Timeout (Minutes) | 15 | How long Wait for Result keeps polling before it fails. |
101
+
102
+ **Summary output** (one item per host):
103
+
104
+ ```json
105
+ {
106
+ "host": "example.com",
107
+ "status": "READY",
108
+ "statusMessage": "Ready",
109
+ "grade": "B",
110
+ "worstGrade": "B",
111
+ "bestGrade": "A+",
112
+ "hasWarnings": true,
113
+ "endpoints": [
114
+ { "ipAddress": "93.184.216.34", "serverName": "example.com", "grade": "A", "gradeTrustIgnored": "A",
115
+ "hasWarnings": false, "isExceptional": false, "statusMessage": "Ready" }
116
+ ],
117
+ "certificate": {
118
+ "subject": "CN=example.com", "issuer": "CN=R11, O=Let's Encrypt, C=US",
119
+ "notBefore": "2026-08-27T00:00:00.000Z", "notAfter": "2026-11-26T01:00:00.000Z",
120
+ "daysUntilExpiry": 61, "serialNumber": "04a1b2c3", "fingerprint": "…sha256…"
121
+ },
122
+ "testTime": "2026-09-25T23:59:50.000Z",
123
+ "engineVersion": "2.3.1",
124
+ "criteriaVersion": "2009q",
125
+ "reportUrl": "https://www.ssllabs.com/ssltest/analyze.html?d=example.com"
126
+ }
127
+ ```
128
+
129
+ A few details about these fields:
130
+
131
+ - `grade` is the **worst** grade across all endpoints that have one. That makes it the conservative value to alert on. Endpoints that could not be tested have no grade and are ignored.
132
+ - Grades rank from best to worst as `A+ > A > A- > B > C > D > E > F > T > M`. `T` (trust issues) and `M` (certificate name mismatch) rank below `F`.
133
+ - All timestamps are ISO-8601 strings.
134
+
135
+ **Several input items:** the node reads `/info` once, then runs at most `min(Batch Concurrency, maxAssessments − currentAssessments)` assessments at a time, and never fewer than 1. It spaces new assessments by SSL Labs' `newAssessmentCoolOff`.
136
+
137
+ - With **Continue On Fail**, a failed item becomes `{ "error": "…", "host": "…" }` and the other items keep going.
138
+ - Without it, the first failure cancels the rest of the batch.
139
+
140
+ Example: check your own hosts and alert if the grade is below A.
141
+
142
+ 1. **Schedule Trigger**
143
+ 2. **SSL Labs** (Assessment → Analyze, Host `{{ $json.host }}`)
144
+ 3. **IF** `{{ $json.grade }}` is not `A+`/`A`
145
+ 4. **Slack**
146
+
147
+ ### Endpoint → Get
148
+
149
+ This operation returns the full SSL Labs `Endpoint` object for one IP address of an assessed host (`getEndpointData`). Set **Host** and **IP Address**; the IP address is listed in the `endpoints` of an Analyze result. **Use Cache** (default on) returns the cached data. This operation never starts a new assessment.
150
+
151
+ ### Service
152
+
153
+ | Operation | Returns |
154
+ |---|---|
155
+ | **Get Info** | Availability, engine and criteria versions, `maxAssessments`, `currentAssessments`, `newAssessmentCoolOff`, and messages |
156
+ | **Get Status Codes** | The `statusDetails` code → English message map |
157
+ | **Get Root Certificates** | `{ trustStoreId, trustStore, certificates }` where `certificates` is the raw PEM text. Trust stores: 1 Mozilla, 2 Apple MacOS, 3 Android, 4 Java, 5 Windows. |
158
+
159
+ ### Registration → Register
160
+
161
+ See [Registration](#registration).
162
+
163
+ ## SSL Labs Trigger
164
+
165
+ The trigger polls SSL Labs on the schedule you set in n8n. It **never waits for a scan during a poll**: it reads cached results (`fromCache=on`, `maxAge=<Max Result Age>`) and picks up assessments that are still running on the next poll.
166
+
167
+ | Parameter | Default | Notes |
168
+ |---|---|---|
169
+ | Hosts | — | The hostnames to watch. Add one per value; comma-separated values also work. |
170
+ | Event | Grade Changed | See the table below. |
171
+ | Threshold Grade | A | For **Grade Below Threshold**. |
172
+ | Days Before Expiry | 21 | For **Certificate Expiring**. |
173
+ | Max Result Age (Hours) | 24 | Cached results up to this old are reused, so each host is re-assessed at most this often. |
174
+ | Emit Errors (option) | off | Emit an `assessmentError` item when a host's assessment ends in ERROR. |
175
+
176
+ | Event | Fires when |
177
+ |---|---|
178
+ | **Grade Changed** | A host's grade differs from the last grade seen. The output includes `previousGrade`. |
179
+ | **Grade Below Threshold** | The grade becomes worse than the threshold. It fires **once** when the grade crosses the threshold, and re-arms when the grade recovers. The output includes `previousGrade` and `thresholdGrade`. |
180
+ | **Certificate Expiring** | `daysUntilExpiry` is at or below the limit. It fires **once per certificate**, keyed on its fingerprint, and a renewed certificate re-arms it. The output includes `previousCertificate` when the certificate changed. |
181
+
182
+ Output items use the same Summary shape as the action node, plus an `event` field.
183
+
184
+ How the trigger behaves:
185
+
186
+ - **First run is a baseline.** The first result for each host is stored and nothing is emitted.
187
+ - A certificate that is already expiring at the baseline alerts on the **next** poll.
188
+ - A host that is already below the threshold does not alert, because it never crossed it. It alerts the next time it crosses after recovering.
189
+ - Grade Below Threshold starts tracking at the first graded result after the event or threshold is selected, so it also begins with a silent baseline.
190
+ - Grade Changed compares against the last grade seen, whichever event was selected at the time.
191
+ - Certificate Expiring alerts on the next poll for a certificate already inside the window, even right after you switch to this event.
192
+ - **Fetch Test Event** (manual mode) returns the current summary of each host with `event: "test"`, so you can map fields. It does not change the stored state.
193
+ - Hosts whose assessment is still running are marked as pending and checked again on the next poll.
194
+ - Days until expiry are recomputed on every poll from the certificate's `notAfter` date.
195
+ - How the trigger handles errors:
196
+ - **SSL Labs busy (429, 503 or 529):** the poll stops quietly. The remaining hosts are checked first on the next poll.
197
+ - **Server error or network trouble:** that host is skipped until the next poll.
198
+ - **400 for a host:** recorded as that host's error.
199
+ - **Configuration problems** (unregistered email, a non-https base URL, 401/403/404): the trigger fails, so you see the problem.
200
+ - After a call that starts a new assessment, the trigger waits SSL Labs' `newAssessmentCoolOff` before checking the next host.
201
+ - The stored state is versioned (`stateVersion: 1`).
202
+
203
+ ## Rate limits and timing
204
+
205
+ - An assessment usually takes **1–5 minutes per IP address**, and some hosts have several. That is why **Wait for Result** can run for minutes. Raise **Timeout (Minutes)**, or use **Start Only** and later **Get Status**.
206
+ - SSL Labs limits how many assessments you may run at once (`maxAssessments`) and how quickly you may start new ones (`newAssessmentCoolOff`). The node respects both.
207
+ - How the node handles errors:
208
+
209
+ | Status | Meaning | What the node does |
210
+ |---|---|---|
211
+ | **429** | Too many assessments | Waits and retries up to 3 times |
212
+ | **503** | Maintenance | Waits a minute and retries twice, then fails with a clear message. SSL Labs recommends waiting 15–30 minutes before trying again. |
213
+ | **529** | Overloaded | Same as 503 |
214
+ | **500** | Server error | Retried once |
215
+ | **400** | Invalid parameters | Not retried |
216
+
217
+ - Prefer **Use Cache** unless you really need a fresh scan. Cached reports are fast and don't use up assessment slots.
218
+
219
+ ## Compatibility
220
+
221
+ - n8n 2.x, built and tested against `n8n-workflow` 2.40
222
+ - Node.js 24
223
+ - No runtime dependencies
224
+
225
+ ## Resources
226
+
227
+ - [SSL Labs API v4 documentation](https://github.com/ssllabs/ssllabs-scan/blob/master/ssllabs-api-docs-v4.md)
228
+ - [SSL Labs API v4 announcement](https://notifications.qualys.com/api/2023/09/28/introduction-of-api-v4-for-qualys-ssllabs-and-deprecation-of-api-v3)
229
+ - [SSL Labs Server Test](https://www.ssllabs.com/ssltest/)
230
+ - [n8n community nodes documentation](https://docs.n8n.io/integrations/#community-nodes)
231
+
232
+ ## License
233
+
234
+ [MIT](LICENSE)
@@ -0,0 +1,10 @@
1
+ import type { IAuthenticateGeneric, Icon, ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
2
+ export declare class SslLabsApi implements ICredentialType {
3
+ name: string;
4
+ displayName: string;
5
+ icon: Icon;
6
+ documentationUrl: string;
7
+ properties: INodeProperties[];
8
+ authenticate: IAuthenticateGeneric;
9
+ test: ICredentialTestRequest;
10
+ }
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SslLabsApi = void 0;
4
+ class SslLabsApi {
5
+ constructor() {
6
+ this.name = 'sslLabsApi';
7
+ this.displayName = 'SSL Labs API';
8
+ this.icon = { light: 'file:sslLabs.svg', dark: 'file:sslLabs.dark.svg' };
9
+ this.documentationUrl = 'https://github.com/t0mer/n8n-nodes-ssllabs#credentials';
10
+ this.properties = [
11
+ {
12
+ displayName: 'Email',
13
+ name: 'email',
14
+ type: 'string',
15
+ placeholder: 'name@example.com',
16
+ default: '',
17
+ required: true,
18
+ description: 'The email address registered with the SSL Labs API v4. It is sent as the "email" header on every call. The credential test only confirms the API is reachable: an unregistered email fails on the first assessment, so use the Register operation first.',
19
+ },
20
+ {
21
+ displayName: 'Base URL',
22
+ name: 'baseUrl',
23
+ type: 'string',
24
+ default: 'https://api.ssllabs.com/api/v4',
25
+ description: 'API entry point (HTTPS only). Use https://api.dev.ssllabs.com/api/v4 for the development server (lower limits, no availability guarantee).',
26
+ },
27
+ ];
28
+ this.authenticate = {
29
+ type: 'generic',
30
+ properties: {
31
+ headers: {
32
+ email: '={{$credentials.email}}',
33
+ },
34
+ },
35
+ };
36
+ this.test = {
37
+ request: {
38
+ baseURL: '={{($credentials.baseUrl || "https://api.ssllabs.com/api/v4").trim().replace(/\\/+$/, "")}}',
39
+ url: '/info',
40
+ method: 'GET',
41
+ },
42
+ };
43
+ }
44
+ }
45
+ exports.SslLabsApi = SslLabsApi;
46
+ //# sourceMappingURL=SslLabsApi.credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SslLabsApi.credentials.js","sourceRoot":"","sources":["../../credentials/SslLabsApi.credentials.ts"],"names":[],"mappings":";;;AAQA,MAAa,UAAU;IAAvB;QACC,SAAI,GAAG,YAAY,CAAC;QAEpB,gBAAW,GAAG,cAAc,CAAC;QAE7B,SAAI,GAAS,EAAE,KAAK,EAAE,kBAAkB,EAAE,IAAI,EAAE,uBAAuB,EAAE,CAAC;QAE1E,qBAAgB,GAAG,wDAAwD,CAAC;QAE5E,eAAU,GAAsB;YAC/B;gBACC,WAAW,EAAE,OAAO;gBACpB,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,kBAAkB;gBAC/B,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;gBACd,WAAW,EACV,0PAA0P;aAC3P;YACD;gBACC,WAAW,EAAE,UAAU;gBACvB,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,gCAAgC;gBACzC,WAAW,EACV,4IAA4I;aAC7I;SACD,CAAC;QAEF,iBAAY,GAAyB;YACpC,IAAI,EAAE,SAAS;YACf,UAAU,EAAE;gBACX,OAAO,EAAE;oBACR,KAAK,EAAE,yBAAyB;iBAChC;aACD;SACD,CAAC;QAEF,SAAI,GAA2B;YAC9B,OAAO,EAAE;gBACR,OAAO,EACN,6FAA6F;gBAC9F,GAAG,EAAE,OAAO;gBACZ,MAAM,EAAE,KAAK;aACb;SACD,CAAC;IACH,CAAC;CAAA;AA/CD,gCA+CC"}
@@ -0,0 +1,9 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64">
2
+ <path d="M20 28v-7a12 12 0 0 1 24 0v7" fill="none" stroke="#58a6ff" stroke-width="5" stroke-linecap="round"/>
3
+ <rect x="10" y="27" width="44" height="31" rx="6" fill="#58a6ff"/>
4
+ <path d="M19 51a13 13 0 0 1 26 0" fill="none" stroke="#0d1117" stroke-width="3" stroke-linecap="round"/>
5
+ <path d="M19 51a13 13 0 0 1 6.5-11.26" fill="none" stroke="#e5534b" stroke-width="3" stroke-linecap="round"/>
6
+ <path d="M38.5 39.74A13 13 0 0 1 45 51" fill="none" stroke="#3fb950" stroke-width="3" stroke-linecap="round"/>
7
+ <line x1="32" y1="51" x2="39" y2="42" stroke="#0d1117" stroke-width="3" stroke-linecap="round"/>
8
+ <circle cx="32" cy="51" r="3" fill="#0d1117"/>
9
+ </svg>
@@ -0,0 +1,9 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64">
2
+ <path d="M20 28v-7a12 12 0 0 1 24 0v7" fill="none" stroke="#1f5f8b" stroke-width="5" stroke-linecap="round"/>
3
+ <rect x="10" y="27" width="44" height="31" rx="6" fill="#1f5f8b"/>
4
+ <path d="M19 51a13 13 0 0 1 26 0" fill="none" stroke="#ffffff" stroke-width="3" stroke-linecap="round"/>
5
+ <path d="M19 51a13 13 0 0 1 6.5-11.26" fill="none" stroke="#e5534b" stroke-width="3" stroke-linecap="round"/>
6
+ <path d="M38.5 39.74A13 13 0 0 1 45 51" fill="none" stroke="#3fb950" stroke-width="3" stroke-linecap="round"/>
7
+ <line x1="32" y1="51" x2="39" y2="42" stroke="#ffffff" stroke-width="3" stroke-linecap="round"/>
8
+ <circle cx="32" cy="51" r="3" fill="#ffffff"/>
9
+ </svg>
@@ -0,0 +1,5 @@
1
+ import type { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
2
+ export declare class SslLabs implements INodeType {
3
+ description: INodeTypeDescription;
4
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
5
+ }
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SslLabs = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
5
+ const assessment_1 = require("./resources/assessment");
6
+ const endpoint_1 = require("./resources/endpoint");
7
+ const registration_1 = require("./resources/registration");
8
+ const service_1 = require("./resources/service");
9
+ const shared_1 = require("./shared");
10
+ const resources = { assessment: assessment_1.assessment, endpoint: endpoint_1.endpoint, registration: registration_1.registration, service: service_1.service };
11
+ class SslLabs {
12
+ constructor() {
13
+ this.description = {
14
+ displayName: 'SSL Labs',
15
+ name: 'sslLabs',
16
+ icon: { light: 'file:sslLabs.svg', dark: 'file:sslLabs.dark.svg' },
17
+ group: ['transform'],
18
+ version: 1,
19
+ subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
20
+ description: 'Run SSL/TLS server assessments with the Qualys SSL Labs API v4',
21
+ defaults: { name: 'SSL Labs' },
22
+ usableAsTool: true,
23
+ inputs: [n8n_workflow_1.NodeConnectionTypes.Main],
24
+ outputs: [n8n_workflow_1.NodeConnectionTypes.Main],
25
+ credentials: [
26
+ {
27
+ name: 'sslLabsApi',
28
+ required: true,
29
+ displayOptions: { hide: { resource: ['registration'] } },
30
+ },
31
+ {
32
+ name: 'sslLabsApi',
33
+ required: false,
34
+ displayOptions: { show: { resource: ['registration'] } },
35
+ },
36
+ ],
37
+ properties: [
38
+ {
39
+ displayName: 'Resource',
40
+ name: 'resource',
41
+ type: 'options',
42
+ noDataExpression: true,
43
+ options: [
44
+ { name: 'Assessment', value: 'assessment' },
45
+ { name: 'Endpoint', value: 'endpoint' },
46
+ { name: 'Registration', value: 'registration' },
47
+ { name: 'Service', value: 'service' },
48
+ ],
49
+ default: 'assessment',
50
+ },
51
+ ...Object.values(resources).flatMap((r) => r.properties),
52
+ ],
53
+ };
54
+ }
55
+ async execute() {
56
+ var _a;
57
+ const resource = this.getNodeParameter('resource', 0);
58
+ const operation = this.getNodeParameter('operation', 0);
59
+ const module = resources[resource];
60
+ const batch = (_a = module === null || module === void 0 ? void 0 : module.batchHandlers) === null || _a === void 0 ? void 0 : _a[operation];
61
+ if (batch)
62
+ return [await batch(this)];
63
+ const handler = module === null || module === void 0 ? void 0 : module.handlers[operation];
64
+ if (!handler) {
65
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Unsupported operation "${resource}: ${operation}"`);
66
+ }
67
+ const items = this.getInputData();
68
+ const returnData = [];
69
+ for (let i = 0; i < items.length; i++) {
70
+ let failure;
71
+ try {
72
+ const result = await handler(this, i);
73
+ for (const json of Array.isArray(result) ? result : [result]) {
74
+ returnData.push({ json, pairedItem: { item: i } });
75
+ }
76
+ }
77
+ catch (error) {
78
+ if (this.continueOnFail()) {
79
+ returnData.push((0, shared_1.errorItem)(this, error, i));
80
+ continue;
81
+ }
82
+ failure = error;
83
+ }
84
+ if (failure)
85
+ throw (0, shared_1.toNodeError)(this, failure, i);
86
+ }
87
+ return [returnData];
88
+ }
89
+ }
90
+ exports.SslLabs = SslLabs;
91
+ //# sourceMappingURL=SslLabs.node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SslLabs.node.js","sourceRoot":"","sources":["../../../nodes/SslLabs/SslLabs.node.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ {
2
+ "node": "@t0mer/n8n-nodes-ssllabs.sslLabs",
3
+ "nodeVersion": "1.0",
4
+ "codexVersion": "1.0",
5
+ "categories": ["Development", "Developer Tools"],
6
+ "resources": {
7
+ "credentialDocumentation": [
8
+ {
9
+ "url": "https://github.com/t0mer/n8n-nodes-ssllabs#credentials"
10
+ }
11
+ ],
12
+ "primaryDocumentation": [
13
+ {
14
+ "url": "https://github.com/t0mer/n8n-nodes-ssllabs#readme"
15
+ }
16
+ ]
17
+ }
18
+ }
@@ -0,0 +1,11 @@
1
+ import type { IDataObject, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
2
+ import { type ResourceModule } from '../shared';
3
+ export interface AnalyzeHooks {
4
+ abortSignal?: AbortSignal;
5
+ beforeStart?: () => Promise<void>;
6
+ }
7
+ export type AnalyzeMode = 'waitForResult' | 'startOnly' | 'getStatus';
8
+ export declare function readMode(ctx: IExecuteFunctions, i: number): AnalyzeMode;
9
+ export declare function analyzeItem(ctx: IExecuteFunctions, i: number, hooks?: AnalyzeHooks): Promise<IDataObject>;
10
+ export declare function executeAnalyze(ctx: IExecuteFunctions): Promise<INodeExecutionData[]>;
11
+ export declare const assessment: ResourceModule;