fa-mcp-sdk 0.2.31 → 0.2.38
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/dist/core/_types_/types.d.ts +3 -2
- package/dist/core/_types_/types.d.ts.map +1 -1
- package/dist/core/mcp/resources.d.ts.map +1 -1
- package/dist/core/mcp/resources.js +25 -6
- package/dist/core/mcp/resources.js.map +1 -1
- package/dist/core/token/gen-token-app/html.d.ts.map +1 -1
- package/dist/core/token/gen-token-app/html.js +371 -105
- package/dist/core/token/gen-token-app/html.js.map +1 -1
- package/dist/core/token/token-core.js +2 -2
- package/dist/core/token/token-core.js.map +1 -1
- package/dist/core/utils/utils.d.ts +1 -0
- package/dist/core/utils/utils.d.ts.map +1 -1
- package/dist/core/utils/utils.js +6 -0
- package/dist/core/utils/utils.js.map +1 -1
- package/dist/core/web/about-page/css.d.ts.map +1 -1
- package/dist/core/web/about-page/css.js +88 -151
- package/dist/core/web/about-page/css.js.map +1 -1
- package/dist/core/web/about-page/render.d.ts.map +1 -1
- package/dist/core/web/about-page/render.js +11 -7
- package/dist/core/web/about-page/render.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
import { encodeSvgForDataUri } from '../../utils/utils.js';
|
|
2
|
+
const jwtSvg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="#0052cc" d="M10.2 0v6.5L12 8.9l1.8-2.4V0Zm3.6 6.5v3l3-1 3.7-5.1-2.9-2.2zm3 2-1.9 2.6 3 1 6.1-2-1.1-3.5Zm1 3.5L15 13l1.8 2.5 6.2 2 1-3.5Zm-1 3.5-3-1v3l3.8 5.3 3-2.1zm-3 2L12 15.2l-1.8 2.5V24h3.6zm-3.6 0v-3l-3 1-3.7 5.2 2.9 2.1zm-3-2 2-2.5-3-1L0 14l1.1 3.5Zm-1-3.5L9 11 7.3 8.7 1 6.6 0 10Zm1-3.4 3 1V6.4L6.4 1.2l-3 2.2Z"/></svg>';
|
|
3
|
+
const iconEncoded = encodeSvgForDataUri(jwtSvg);
|
|
1
4
|
export const getHTMLPage = () => `<!DOCTYPE html>
|
|
2
5
|
<html lang='ru'>
|
|
3
6
|
<head>
|
|
4
7
|
<meta charset='UTF-8'>
|
|
5
8
|
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
|
|
9
|
+
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,${iconEncoded}">
|
|
6
10
|
<title>Token Generator & Validator</title>
|
|
11
|
+
|
|
7
12
|
<style>
|
|
8
13
|
* {
|
|
9
14
|
box-sizing: border-box;
|
|
@@ -11,54 +16,90 @@ export const getHTMLPage = () => `<!DOCTYPE html>
|
|
|
11
16
|
padding: 0;
|
|
12
17
|
}
|
|
13
18
|
|
|
19
|
+
html, body {
|
|
20
|
+
height: 100%;
|
|
21
|
+
}
|
|
22
|
+
|
|
14
23
|
body {
|
|
15
|
-
font-family: 'Segoe UI',
|
|
16
|
-
|
|
24
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
|
25
|
+
font-size: 14px;
|
|
26
|
+
line-height: 1.5;
|
|
27
|
+
color: #253858;
|
|
28
|
+
background: white;
|
|
29
|
+
margin: 0;
|
|
30
|
+
padding: 24px;
|
|
31
|
+
-webkit-font-smoothing: antialiased;
|
|
32
|
+
-moz-osx-font-smoothing: grayscale;
|
|
17
33
|
min-height: 100vh;
|
|
18
34
|
display: flex;
|
|
19
|
-
align-items:
|
|
35
|
+
align-items: flex-start;
|
|
20
36
|
justify-content: center;
|
|
21
|
-
padding: 20px;
|
|
22
37
|
}
|
|
23
38
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
border-radius: 20px;
|
|
27
|
-
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
|
|
28
|
-
padding: 30px;
|
|
39
|
+
/* Simple Layout */
|
|
40
|
+
.simple-container {
|
|
29
41
|
width: 100%;
|
|
30
|
-
max-width:
|
|
42
|
+
max-width: 670px;
|
|
43
|
+
background: white;
|
|
44
|
+
border: 1px solid #c1c7d0;
|
|
45
|
+
border-radius: 6px;
|
|
46
|
+
box-shadow: 0 1px 3px rgba(9, 30, 66, 0.25), 0 0 1px rgba(9, 30, 66, 0.31);
|
|
47
|
+
margin-top: 40px;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* Simple Header */
|
|
51
|
+
.simple-header {
|
|
52
|
+
padding: 16px 24px 12px;
|
|
53
|
+
border-bottom: 1px solid #c1c7d0;
|
|
54
|
+
background: #fafbfc;
|
|
55
|
+
border-radius: 6px 6px 0 0;
|
|
56
|
+
display: flex;
|
|
57
|
+
align-items: center;
|
|
58
|
+
gap: 16px;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.simple-header h1 {
|
|
62
|
+
font-size: 24px;
|
|
63
|
+
font-weight: 600;
|
|
64
|
+
margin: 0;
|
|
65
|
+
color: #0052cc;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* Simple Main Content */
|
|
69
|
+
.simple-main {
|
|
70
|
+
padding: 24px 24px;
|
|
31
71
|
}
|
|
32
72
|
|
|
33
73
|
.tab-container {
|
|
34
|
-
margin-bottom:
|
|
74
|
+
margin-bottom: 0;
|
|
35
75
|
}
|
|
36
76
|
|
|
37
77
|
.tabs {
|
|
38
78
|
display: flex;
|
|
39
|
-
border-bottom:
|
|
40
|
-
margin-bottom:
|
|
79
|
+
border-bottom: 1px solid #c1c7d0;
|
|
80
|
+
margin-bottom: 24px;
|
|
41
81
|
}
|
|
42
82
|
|
|
43
83
|
.tab {
|
|
44
84
|
background: none;
|
|
45
85
|
border: none;
|
|
46
|
-
padding:
|
|
86
|
+
padding: 12px 16px;
|
|
47
87
|
cursor: pointer;
|
|
48
|
-
font-size:
|
|
88
|
+
font-size: 14px;
|
|
49
89
|
font-weight: 500;
|
|
50
|
-
color: #
|
|
90
|
+
color: #505f79;
|
|
51
91
|
border-bottom: 2px solid transparent;
|
|
52
|
-
transition: all 0.
|
|
92
|
+
transition: all 0.2s ease;
|
|
53
93
|
}
|
|
54
94
|
|
|
55
95
|
.tab.active {
|
|
56
|
-
color: #
|
|
57
|
-
border-bottom-color: #
|
|
96
|
+
color: #0052cc;
|
|
97
|
+
border-bottom-color: #0052cc;
|
|
58
98
|
}
|
|
59
99
|
|
|
60
100
|
.tab:hover {
|
|
61
|
-
|
|
101
|
+
color: #253858;
|
|
102
|
+
background: #fafbfc;
|
|
62
103
|
}
|
|
63
104
|
|
|
64
105
|
.tab-content {
|
|
@@ -70,34 +111,46 @@ body {
|
|
|
70
111
|
}
|
|
71
112
|
|
|
72
113
|
.form-group {
|
|
73
|
-
margin-bottom:
|
|
114
|
+
margin-bottom: 12px;
|
|
74
115
|
}
|
|
75
116
|
|
|
76
117
|
.form-row {
|
|
77
118
|
display: flex;
|
|
78
|
-
gap:
|
|
119
|
+
gap: 12px;
|
|
79
120
|
align-items: center;
|
|
80
121
|
}
|
|
81
122
|
|
|
82
123
|
label {
|
|
83
124
|
display: block;
|
|
84
|
-
margin-bottom:
|
|
125
|
+
margin-bottom: 4px;
|
|
85
126
|
font-weight: 500;
|
|
86
|
-
color: #
|
|
127
|
+
color: #42526e;
|
|
128
|
+
font-size: 14px;
|
|
87
129
|
}
|
|
88
130
|
|
|
89
131
|
input, select, textarea {
|
|
90
132
|
width: 100%;
|
|
91
|
-
padding:
|
|
92
|
-
border:
|
|
93
|
-
border-radius:
|
|
133
|
+
padding: 4px 6px;
|
|
134
|
+
border: 1px solid #c1c7d0;
|
|
135
|
+
border-radius: 3px;
|
|
94
136
|
font-size: 14px;
|
|
95
|
-
|
|
137
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
|
138
|
+
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
|
139
|
+
background: white;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
select {
|
|
143
|
+
padding: 3px 6px;
|
|
96
144
|
}
|
|
97
145
|
|
|
98
146
|
input:focus, select:focus, textarea:focus {
|
|
99
147
|
outline: none;
|
|
100
|
-
border-color: #
|
|
148
|
+
border-color: #0065ff;
|
|
149
|
+
box-shadow: 0 0 0 2px rgba(0, 101, 255, 0.1);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
input::placeholder, textarea::placeholder {
|
|
153
|
+
color: #505f79;
|
|
101
154
|
}
|
|
102
155
|
|
|
103
156
|
.time-input {
|
|
@@ -110,8 +163,8 @@ input:focus, select:focus, textarea:focus {
|
|
|
110
163
|
|
|
111
164
|
.key-value-pair {
|
|
112
165
|
display: flex;
|
|
113
|
-
gap:
|
|
114
|
-
margin-bottom:
|
|
166
|
+
gap: 8px;
|
|
167
|
+
margin-bottom: 12px;
|
|
115
168
|
align-items: center;
|
|
116
169
|
}
|
|
117
170
|
|
|
@@ -129,134 +182,243 @@ input:focus, select:focus, textarea:focus {
|
|
|
129
182
|
}
|
|
130
183
|
|
|
131
184
|
.remove-btn {
|
|
132
|
-
background:
|
|
133
|
-
color: #
|
|
134
|
-
border:
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
height: 36px;
|
|
185
|
+
background: white;
|
|
186
|
+
color: #bf2600;
|
|
187
|
+
border: 0px;
|
|
188
|
+
width: 28px;
|
|
189
|
+
height: 28px;
|
|
138
190
|
cursor: pointer;
|
|
139
|
-
font-size:
|
|
191
|
+
font-size: 22px;
|
|
140
192
|
display: flex;
|
|
141
193
|
align-items: center;
|
|
142
194
|
justify-content: center;
|
|
143
|
-
|
|
195
|
+
flex-shrink: 0;
|
|
144
196
|
}
|
|
145
197
|
|
|
146
198
|
.remove-btn:hover {
|
|
147
|
-
background: #
|
|
199
|
+
background: #bf2600;
|
|
200
|
+
color: white;
|
|
201
|
+
border-color: #bf2600;
|
|
148
202
|
}
|
|
149
203
|
|
|
150
204
|
.add-btn {
|
|
151
|
-
background: #
|
|
152
|
-
color:
|
|
205
|
+
background: #d7ffd4;
|
|
206
|
+
color: #089300;
|
|
153
207
|
border: none;
|
|
154
|
-
border-radius:
|
|
155
|
-
width:
|
|
156
|
-
height:
|
|
208
|
+
border-radius: 14px;
|
|
209
|
+
width: 28px;
|
|
210
|
+
height: 28px;
|
|
157
211
|
cursor: pointer;
|
|
158
|
-
font-size:
|
|
159
|
-
|
|
212
|
+
font-size: 24px;
|
|
213
|
+
font-weight: 500;
|
|
160
214
|
align-items: center;
|
|
161
|
-
|
|
162
|
-
margin: 10px auto;
|
|
163
|
-
transition: background 0.3s ease;
|
|
215
|
+
transition: background 0.2s ease;
|
|
164
216
|
}
|
|
165
217
|
|
|
166
218
|
.add-btn:hover {
|
|
167
|
-
background: #
|
|
219
|
+
background: #c9ffc4;
|
|
168
220
|
}
|
|
169
221
|
|
|
170
222
|
.btn {
|
|
171
|
-
background:
|
|
223
|
+
background: #0052cc;
|
|
172
224
|
color: white;
|
|
173
225
|
border: none;
|
|
174
|
-
padding:
|
|
175
|
-
border-radius:
|
|
176
|
-
font-size:
|
|
226
|
+
padding: 12px 24px;
|
|
227
|
+
border-radius: 3px;
|
|
228
|
+
font-size: 14px;
|
|
177
229
|
font-weight: 500;
|
|
178
230
|
cursor: pointer;
|
|
179
|
-
transition:
|
|
231
|
+
transition: all 0.2s ease;
|
|
180
232
|
width: 100%;
|
|
181
|
-
margin-bottom:
|
|
233
|
+
margin-bottom: 16px;
|
|
182
234
|
}
|
|
183
235
|
|
|
184
236
|
.btn:hover {
|
|
185
|
-
|
|
186
|
-
box-shadow: 0
|
|
237
|
+
background: #0065ff;
|
|
238
|
+
box-shadow: 0 1px 1px rgba(9, 30, 66, 0.25), 0 0 1px rgba(9, 30, 66, 0.31);
|
|
187
239
|
}
|
|
188
240
|
|
|
189
241
|
.btn:active {
|
|
190
|
-
transform: translateY(
|
|
242
|
+
transform: translateY(1px);
|
|
243
|
+
box-shadow: none;
|
|
191
244
|
}
|
|
192
245
|
|
|
193
|
-
.copy-btn {
|
|
194
|
-
background: #5352ed;
|
|
195
|
-
padding: 10px 20px;
|
|
196
|
-
font-size: 14px;
|
|
197
|
-
width: auto;
|
|
198
|
-
margin: 10px 0 0 0;
|
|
199
|
-
}
|
|
200
246
|
|
|
201
247
|
.result {
|
|
202
|
-
margin-top:
|
|
203
|
-
padding:
|
|
204
|
-
border-radius:
|
|
205
|
-
font-family: '
|
|
248
|
+
margin-top: 24px;
|
|
249
|
+
padding: 24px;
|
|
250
|
+
border-radius: 3px;
|
|
251
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
|
206
252
|
}
|
|
207
253
|
|
|
208
254
|
.result.success {
|
|
209
|
-
background:
|
|
210
|
-
color: #
|
|
211
|
-
border: 1px solid
|
|
255
|
+
background: rgba(0, 102, 68, 0.1);
|
|
256
|
+
color: #006644;
|
|
257
|
+
border: 1px solid rgba(0, 102, 68, 0.2);
|
|
212
258
|
}
|
|
213
259
|
|
|
214
260
|
.result.error {
|
|
215
|
-
background:
|
|
216
|
-
color: #
|
|
217
|
-
border: 1px solid
|
|
261
|
+
background: rgba(191, 38, 0, 0.1);
|
|
262
|
+
color: #bf2600;
|
|
263
|
+
border: 1px solid rgba(255, 86, 48, 0.2);
|
|
218
264
|
}
|
|
219
265
|
|
|
220
266
|
.token-output {
|
|
221
|
-
background: #
|
|
222
|
-
border:
|
|
223
|
-
border-radius:
|
|
224
|
-
padding:
|
|
225
|
-
font-family: '
|
|
267
|
+
background: #ebecf0;
|
|
268
|
+
border: 1px solid #c1c7d0;
|
|
269
|
+
border-radius: 3px;
|
|
270
|
+
padding: 16px;
|
|
271
|
+
font-family: ui-monospace, 'SF Mono', 'Consolas', 'Roboto Mono', 'Ubuntu Mono', monospace;
|
|
226
272
|
font-size: 12px;
|
|
227
273
|
line-height: 1.4;
|
|
228
274
|
word-break: break-all;
|
|
229
275
|
min-height: 100px;
|
|
230
276
|
resize: vertical;
|
|
277
|
+
color: #172b4d;
|
|
278
|
+
position: relative;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.copy-button, .validate-token-button {
|
|
282
|
+
position: absolute;
|
|
283
|
+
bottom: 5px;
|
|
284
|
+
right: 35px;
|
|
285
|
+
background: #ffffff73;
|
|
286
|
+
border-radius: 4px;
|
|
287
|
+
width: 28px;
|
|
288
|
+
height: 28px;
|
|
289
|
+
cursor: pointer;
|
|
290
|
+
font-size: 12px;
|
|
291
|
+
display: flex;
|
|
292
|
+
align-items: center;
|
|
293
|
+
justify-content: center;
|
|
294
|
+
border: none;
|
|
295
|
+
transition: all 0.2s ease;
|
|
296
|
+
z-index: 10;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.validate-token-button {
|
|
300
|
+
right: 5px;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.copy-button:hover, .validate-token-button:hover {
|
|
304
|
+
background: #ffffff;
|
|
305
|
+
transform: scale(1.05);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.copy-notification {
|
|
309
|
+
position: absolute;
|
|
310
|
+
top: 8px;
|
|
311
|
+
right: 42px;
|
|
312
|
+
background: #006644;
|
|
313
|
+
color: white;
|
|
314
|
+
padding: 4px 8px;
|
|
315
|
+
border-radius: 4px;
|
|
316
|
+
font-size: 12px;
|
|
317
|
+
font-weight: 500;
|
|
318
|
+
opacity: 0;
|
|
319
|
+
transform: translateY(-10px);
|
|
320
|
+
transition: all 0.3s ease;
|
|
321
|
+
z-index: 11;
|
|
322
|
+
white-space: nowrap;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.copy-notification.show {
|
|
326
|
+
opacity: 1;
|
|
327
|
+
transform: translateY(0);
|
|
231
328
|
}
|
|
232
329
|
|
|
233
330
|
.token-info {
|
|
234
|
-
background:
|
|
235
|
-
border: 1px solid
|
|
236
|
-
border-radius:
|
|
237
|
-
padding:
|
|
238
|
-
margin-top:
|
|
331
|
+
background: rgba(0, 102, 68, 0.05);
|
|
332
|
+
border: 1px solid rgba(0, 102, 68, 0.1);
|
|
333
|
+
border-radius: 3px;
|
|
334
|
+
padding: 16px;
|
|
335
|
+
margin-top: 12px;
|
|
239
336
|
}
|
|
240
337
|
|
|
241
338
|
.token-info h4 {
|
|
242
|
-
margin-bottom:
|
|
243
|
-
color: #
|
|
339
|
+
margin-bottom: 8px;
|
|
340
|
+
color: #006644;
|
|
341
|
+
font-weight: 600;
|
|
342
|
+
font-size: 14px;
|
|
244
343
|
}
|
|
245
344
|
|
|
246
345
|
.token-info p {
|
|
247
|
-
margin:
|
|
248
|
-
font-family: '
|
|
346
|
+
margin: 4px 0;
|
|
347
|
+
font-family: ui-monospace, 'SF Mono', 'Consolas', 'Roboto Mono', 'Ubuntu Mono', monospace;
|
|
249
348
|
font-size: 14px;
|
|
349
|
+
color: #172b4d;
|
|
350
|
+
}
|
|
351
|
+
.service-icon {
|
|
352
|
+
width: 26px;
|
|
353
|
+
height: 26px;
|
|
354
|
+
display: flex;
|
|
355
|
+
align-items: center;
|
|
356
|
+
justify-content: center;
|
|
357
|
+
}
|
|
358
|
+
.service-icon svg {
|
|
359
|
+
width: 100%;
|
|
360
|
+
height: 100%;
|
|
361
|
+
}
|
|
362
|
+
/* Responsive Design */
|
|
363
|
+
@media (max-width: 640px) {
|
|
364
|
+
body {
|
|
365
|
+
padding: 16px;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
.simple-container {
|
|
369
|
+
margin-top: 24px;
|
|
370
|
+
max-width: 100%;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
.simple-header {
|
|
374
|
+
padding: 16px 20px 12px;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.simple-header h1 {
|
|
378
|
+
font-size: 20px;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
.simple-main {
|
|
382
|
+
padding: 20px 20px;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
.form-row {
|
|
386
|
+
flex-direction: column;
|
|
387
|
+
gap: 8px;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
.key-value-pair {
|
|
391
|
+
flex-direction: column;
|
|
392
|
+
align-items: stretch;
|
|
393
|
+
gap: 8px;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
.key-value-pair input[name="keys"] {
|
|
397
|
+
width: 100%;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
.remove-btn {
|
|
401
|
+
width: 100%;
|
|
402
|
+
margin-top: 8px;
|
|
403
|
+
}
|
|
250
404
|
}
|
|
251
405
|
</style>
|
|
252
406
|
</head>
|
|
253
407
|
<body>
|
|
254
|
-
<div class="container">
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
408
|
+
<div class="simple-container">
|
|
409
|
+
<!-- Header -->
|
|
410
|
+
<header class="simple-header">
|
|
411
|
+
<div class="service-icon">${jwtSvg}</div>
|
|
412
|
+
<h1>Token Generator & Validator</h1>
|
|
413
|
+
</header>
|
|
414
|
+
|
|
415
|
+
<!-- Main Content -->
|
|
416
|
+
<main class="simple-main">
|
|
417
|
+
<div class="tab-container">
|
|
418
|
+
<div class="tabs">
|
|
419
|
+
<button class="tab active" onclick="switchTab('generate')">Token generation</button>
|
|
420
|
+
<button class="tab" onclick="switchTab('validate')">Token validation</button>
|
|
421
|
+
</div>
|
|
260
422
|
|
|
261
423
|
<!-- Token generation -->
|
|
262
424
|
<div id="generate" class="tab-content active">
|
|
@@ -303,7 +465,8 @@ input:focus, select:focus, textarea:focus {
|
|
|
303
465
|
</form>
|
|
304
466
|
<div id="validateResult"></div>
|
|
305
467
|
</div>
|
|
306
|
-
|
|
468
|
+
</div>
|
|
469
|
+
</main>
|
|
307
470
|
</div>
|
|
308
471
|
|
|
309
472
|
<script>
|
|
@@ -317,7 +480,15 @@ function switchTab (tabName) {
|
|
|
317
480
|
tab.classList.remove('active');
|
|
318
481
|
});
|
|
319
482
|
document.getElementById(tabName).classList.add('active');
|
|
320
|
-
|
|
483
|
+
|
|
484
|
+
// Activate the corresponding tab button
|
|
485
|
+
const tabs = document.querySelectorAll('.tab');
|
|
486
|
+
tabs.forEach(tab => {
|
|
487
|
+
const onclick = tab.getAttribute('onclick');
|
|
488
|
+
if (onclick && onclick.includes("switchTab('" + tabName + "')")) {
|
|
489
|
+
tab.classList.add('active');
|
|
490
|
+
}
|
|
491
|
+
});
|
|
321
492
|
}
|
|
322
493
|
|
|
323
494
|
function addKeyValuePair (key = '', value = '', readonly = false, placeholder = 'Value') {
|
|
@@ -346,9 +517,88 @@ function removeKeyValuePair (button) {
|
|
|
346
517
|
keyValuePairCount--;
|
|
347
518
|
}
|
|
348
519
|
|
|
349
|
-
function
|
|
350
|
-
|
|
351
|
-
|
|
520
|
+
function addCopyButtonToTokenOutput(tokenOutput, token) {
|
|
521
|
+
if (!tokenOutput || tokenOutput.hasAttribute('data-copy-added')) {
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
tokenOutput.setAttribute('data-copy-added', 'true');
|
|
526
|
+
|
|
527
|
+
const copyButton = document.createElement('button');
|
|
528
|
+
copyButton.className = 'copy-button';
|
|
529
|
+
copyButton.innerHTML = '📋';
|
|
530
|
+
copyButton.title = 'Copy to clipboard';
|
|
531
|
+
copyButton.setAttribute('aria-label', 'Copy to clipboard');
|
|
532
|
+
|
|
533
|
+
const validateButton = document.createElement('button');
|
|
534
|
+
validateButton.className = 'validate-token-button';
|
|
535
|
+
validateButton.innerHTML = '✓';
|
|
536
|
+
validateButton.title = 'Validate token';
|
|
537
|
+
validateButton.setAttribute('aria-label', 'Validate token');
|
|
538
|
+
|
|
539
|
+
const notification = document.createElement('div');
|
|
540
|
+
notification.className = 'copy-notification';
|
|
541
|
+
notification.textContent = 'Copied';
|
|
542
|
+
|
|
543
|
+
tokenOutput.appendChild(copyButton);
|
|
544
|
+
tokenOutput.appendChild(validateButton);
|
|
545
|
+
tokenOutput.appendChild(notification);
|
|
546
|
+
|
|
547
|
+
copyButton.addEventListener('click', async function() {
|
|
548
|
+
try {
|
|
549
|
+
await navigator.clipboard.writeText(token);
|
|
550
|
+
|
|
551
|
+
// Show notification
|
|
552
|
+
notification.classList.add('show');
|
|
553
|
+
|
|
554
|
+
// Hide notification after 1 second
|
|
555
|
+
setTimeout(() => {
|
|
556
|
+
notification.classList.remove('show');
|
|
557
|
+
}, 1000);
|
|
558
|
+
|
|
559
|
+
} catch (err) {
|
|
560
|
+
// Fallback for browsers that don't support clipboard API
|
|
561
|
+
const textArea = document.createElement('textarea');
|
|
562
|
+
textArea.value = token;
|
|
563
|
+
textArea.style.position = 'fixed';
|
|
564
|
+
textArea.style.opacity = '0';
|
|
565
|
+
document.body.appendChild(textArea);
|
|
566
|
+
textArea.focus();
|
|
567
|
+
textArea.select();
|
|
568
|
+
|
|
569
|
+
try {
|
|
570
|
+
document.execCommand('copy');
|
|
571
|
+
|
|
572
|
+
// Show notification
|
|
573
|
+
notification.classList.add('show');
|
|
574
|
+
|
|
575
|
+
// Hide notification after 1 second
|
|
576
|
+
setTimeout(() => {
|
|
577
|
+
notification.classList.remove('show');
|
|
578
|
+
}, 1000);
|
|
579
|
+
} catch (fallbackErr) {
|
|
580
|
+
console.error('Failed to copy text:', fallbackErr);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
document.body.removeChild(textArea);
|
|
584
|
+
}
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
validateButton.addEventListener('click', function() {
|
|
588
|
+
// Switch to validation tab
|
|
589
|
+
switchTab('validate');
|
|
590
|
+
|
|
591
|
+
// Set the token in the validation textarea
|
|
592
|
+
const tokenTextarea = document.getElementById('tokenInput');
|
|
593
|
+
if (tokenTextarea) {
|
|
594
|
+
tokenTextarea.value = token;
|
|
595
|
+
|
|
596
|
+
// Trigger validation form submit
|
|
597
|
+
const validateForm = document.getElementById('validateForm');
|
|
598
|
+
if (validateForm) {
|
|
599
|
+
validateForm.dispatchEvent(new Event('submit'));
|
|
600
|
+
}
|
|
601
|
+
}
|
|
352
602
|
});
|
|
353
603
|
}
|
|
354
604
|
|
|
@@ -401,8 +651,19 @@ document.getElementById('generateForm').addEventListener('submit', async (e) =>
|
|
|
401
651
|
'<div class="result success">' +
|
|
402
652
|
'<strong>The token has been successfully created!</strong><br>' +
|
|
403
653
|
'<div class="token-output">' + result.token + '</div>' +
|
|
404
|
-
'<button class="copy-btn" onclick="copyToClipboard(\\'' + result.token + '\\')">Copy Token</button>' +
|
|
405
654
|
'</div>';
|
|
655
|
+
|
|
656
|
+
// Add floating copy button to the token output
|
|
657
|
+
const tokenOutput = resultDiv.querySelector('.token-output');
|
|
658
|
+
if (tokenOutput) {
|
|
659
|
+
addCopyButtonToTokenOutput(tokenOutput, result.token);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
// Automatically populate the validation field with the generated token
|
|
663
|
+
const tokenTextarea = document.getElementById('tokenInput');
|
|
664
|
+
if (tokenTextarea) {
|
|
665
|
+
tokenTextarea.value = result.token;
|
|
666
|
+
}
|
|
406
667
|
} else {
|
|
407
668
|
resultDiv.innerHTML =
|
|
408
669
|
'<div class="result error">' +
|
|
@@ -436,7 +697,7 @@ document.getElementById('validateForm').addEventListener('submit', async (e) =>
|
|
|
436
697
|
|
|
437
698
|
if (result.success) {
|
|
438
699
|
const remainingTime = result.payload.expire - Date.now();
|
|
439
|
-
const payloadKeys = Object.keys(result.payload).filter(k =>
|
|
700
|
+
const payloadKeys = Object.keys(result.payload).filter((k) => !/^(user|expire|iat|service)$/.test(k));
|
|
440
701
|
|
|
441
702
|
let payloadHtml = '';
|
|
442
703
|
if (payloadKeys.length > 0) {
|
|
@@ -446,12 +707,17 @@ document.getElementById('validateForm').addEventListener('submit', async (e) =>
|
|
|
446
707
|
});
|
|
447
708
|
}
|
|
448
709
|
|
|
710
|
+
// Format issued at time
|
|
711
|
+
const issuedAtTime = result.payload.iat ? new Date(result.payload.iat).toLocaleString('ru-RU') : 'N/A';
|
|
712
|
+
|
|
449
713
|
resultDiv.innerHTML =
|
|
450
714
|
'<div class="result success">' +
|
|
451
715
|
'<strong>The token is valid!</strong>' +
|
|
452
716
|
'<div class="token-info">' +
|
|
453
717
|
'<h4>Token Information:</h4>' +
|
|
454
718
|
'<p><strong>User:</strong> ' + result.payload.user + '</p>' +
|
|
719
|
+
( result.payload.service ? '<p><strong>Service:</strong> ' + result.payload.service + '</p>' : '') +
|
|
720
|
+
'<p><strong>Issued at:</strong> ' + issuedAtTime + '</p>' +
|
|
455
721
|
'<p><strong>Time remaining:</strong> ' + formatTime(remainingTime) + '</p>' +
|
|
456
722
|
'<p><strong>Expires:</strong> ' + new Date(result.payload.expire).toLocaleString('ru-RU') + '</p>' +
|
|
457
723
|
payloadHtml +
|
|
@@ -482,7 +748,7 @@ async function initializeForm () {
|
|
|
482
748
|
|
|
483
749
|
// Adding a pre-filled pair serviceName
|
|
484
750
|
addKeyValuePair('service', serviceName, true);
|
|
485
|
-
addKeyValuePair('issue', '', true, '
|
|
751
|
+
addKeyValuePair('issue', '', true, 'URL of request for the issuance of a token in JIRA');
|
|
486
752
|
|
|
487
753
|
} catch (error) {
|
|
488
754
|
console.error('Error loading service info:', error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html.js","sourceRoot":"","sources":["../../../../src/core/token/gen-token-app/html.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG,GAAW,EAAE,CAAC
|
|
1
|
+
{"version":3,"file":"html.js","sourceRoot":"","sources":["../../../../src/core/token/gen-token-app/html.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,MAAM,MAAM,GAAG,gZAAgZ,CAAC;AACha,MAAM,WAAW,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;AAEhD,MAAM,CAAC,MAAM,WAAW,GAAG,GAAW,EAAE,CAAC;;;;;mEAK0B,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCAkZ9C,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkWrC,CAAC"}
|
|
@@ -53,11 +53,11 @@ export const generateToken = (user, liveTimeSec, payload) => {
|
|
|
53
53
|
throw new Error('generateToken: Username is empty');
|
|
54
54
|
}
|
|
55
55
|
const expire = Date.now() + (liveTimeSec * 1000);
|
|
56
|
+
const issuedAt = new Date().toISOString();
|
|
56
57
|
payload = isObject(payload) ? payload : {};
|
|
57
58
|
payload.user = user;
|
|
58
59
|
payload.expire = expire;
|
|
59
|
-
|
|
60
|
-
payload.serviceName = appConfig.name;
|
|
60
|
+
payload.iat = issuedAt;
|
|
61
61
|
return `${expire}.${encrypt(JSON.stringify(payload))}`;
|
|
62
62
|
};
|
|
63
63
|
/**
|