fa-mcp-sdk 0.2.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/LICENSE +21 -0
- package/README.md +283 -0
- package/dist/core/_types_/types.d.ts +67 -0
- package/dist/core/_types_/types.d.ts.map +1 -0
- package/dist/core/_types_/types.js +2 -0
- package/dist/core/_types_/types.js.map +1 -0
- package/dist/core/bootstrap/dotenv.d.ts +3 -0
- package/dist/core/bootstrap/dotenv.d.ts.map +1 -0
- package/dist/core/bootstrap/dotenv.js +3 -0
- package/dist/core/bootstrap/dotenv.js.map +1 -0
- package/dist/core/bootstrap/init-config.d.ts +11 -0
- package/dist/core/bootstrap/init-config.d.ts.map +1 -0
- package/dist/core/bootstrap/init-config.js +52 -0
- package/dist/core/bootstrap/init-config.js.map +1 -0
- package/dist/core/bootstrap/startup-info.d.ts +6 -0
- package/dist/core/bootstrap/startup-info.d.ts.map +1 -0
- package/dist/core/bootstrap/startup-info.js +43 -0
- package/dist/core/bootstrap/startup-info.js.map +1 -0
- package/dist/core/constants.d.ts +2 -0
- package/dist/core/constants.d.ts.map +1 -0
- package/dist/core/constants.js +2 -0
- package/dist/core/constants.js.map +1 -0
- package/dist/core/consul/access-points-updater.d.ts +5 -0
- package/dist/core/consul/access-points-updater.d.ts.map +1 -0
- package/dist/core/consul/access-points-updater.js +11 -0
- package/dist/core/consul/access-points-updater.js.map +1 -0
- package/dist/core/consul/deregister.d.ts +2 -0
- package/dist/core/consul/deregister.d.ts.map +1 -0
- package/dist/core/consul/deregister.js +21 -0
- package/dist/core/consul/deregister.js.map +1 -0
- package/dist/core/consul/get-consul-api.d.ts +2 -0
- package/dist/core/consul/get-consul-api.d.ts.map +1 -0
- package/dist/core/consul/get-consul-api.js +18 -0
- package/dist/core/consul/get-consul-api.js.map +1 -0
- package/dist/core/consul/register.d.ts +2 -0
- package/dist/core/consul/register.d.ts.map +1 -0
- package/dist/core/consul/register.js +6 -0
- package/dist/core/consul/register.js.map +1 -0
- package/dist/core/db/pg-db.d.ts +50 -0
- package/dist/core/db/pg-db.d.ts.map +1 -0
- package/dist/core/db/pg-db.js +89 -0
- package/dist/core/db/pg-db.js.map +1 -0
- package/dist/core/debug.d.ts +5 -0
- package/dist/core/debug.d.ts.map +1 -0
- package/dist/core/debug.js +32 -0
- package/dist/core/debug.js.map +1 -0
- package/dist/core/ee.d.ts +3 -0
- package/dist/core/ee.d.ts.map +1 -0
- package/dist/core/ee.js +4 -0
- package/dist/core/ee.js.map +1 -0
- package/dist/core/errors/BaseMcpError.d.ts +19 -0
- package/dist/core/errors/BaseMcpError.d.ts.map +1 -0
- package/dist/core/errors/BaseMcpError.js +47 -0
- package/dist/core/errors/BaseMcpError.js.map +1 -0
- package/dist/core/errors/ValidationError.d.ts +5 -0
- package/dist/core/errors/ValidationError.d.ts.map +1 -0
- package/dist/core/errors/ValidationError.js +7 -0
- package/dist/core/errors/ValidationError.js.map +1 -0
- package/dist/core/errors/errors.d.ts +24 -0
- package/dist/core/errors/errors.d.ts.map +1 -0
- package/dist/core/errors/errors.js +49 -0
- package/dist/core/errors/errors.js.map +1 -0
- package/dist/core/index.d.ts +19 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +16 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/init-mcp-server.d.ts +8 -0
- package/dist/core/init-mcp-server.d.ts.map +1 -0
- package/dist/core/init-mcp-server.js +101 -0
- package/dist/core/init-mcp-server.js.map +1 -0
- package/dist/core/logger.d.ts +6 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +53 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/mcp/create-mcp-server.d.ts +6 -0
- package/dist/core/mcp/create-mcp-server.d.ts.map +1 -0
- package/dist/core/mcp/create-mcp-server.js +44 -0
- package/dist/core/mcp/create-mcp-server.js.map +1 -0
- package/dist/core/mcp/prompts.d.ts +10 -0
- package/dist/core/mcp/prompts.d.ts.map +1 -0
- package/dist/core/mcp/prompts.js +56 -0
- package/dist/core/mcp/prompts.js.map +1 -0
- package/dist/core/mcp/resources.d.ts +14 -0
- package/dist/core/mcp/resources.d.ts.map +1 -0
- package/dist/core/mcp/resources.js +72 -0
- package/dist/core/mcp/resources.js.map +1 -0
- package/dist/core/mcp/server-stdio.d.ts +5 -0
- package/dist/core/mcp/server-stdio.d.ts.map +1 -0
- package/dist/core/mcp/server-stdio.js +13 -0
- package/dist/core/mcp/server-stdio.js.map +1 -0
- package/dist/core/token/gen-token-app/gen-token-server.d.ts +2 -0
- package/dist/core/token/gen-token-app/gen-token-server.d.ts.map +1 -0
- package/dist/core/token/gen-token-app/gen-token-server.js +115 -0
- package/dist/core/token/gen-token-app/gen-token-server.js.map +1 -0
- package/dist/core/token/gen-token-app/html.d.ts +2 -0
- package/dist/core/token/gen-token-app/html.d.ts.map +1 -0
- package/dist/core/token/gen-token-app/html.js +500 -0
- package/dist/core/token/gen-token-app/html.js.map +1 -0
- package/dist/core/token/i-token.d.ts +13 -0
- package/dist/core/token/i-token.d.ts.map +1 -0
- package/dist/core/token/i-token.js +2 -0
- package/dist/core/token/i-token.js.map +1 -0
- package/dist/core/token/token-core.d.ts +24 -0
- package/dist/core/token/token-core.d.ts.map +1 -0
- package/dist/core/token/token-core.js +130 -0
- package/dist/core/token/token-core.js.map +1 -0
- package/dist/core/token/token.d.ts +17 -0
- package/dist/core/token/token.d.ts.map +1 -0
- package/dist/core/token/token.js +62 -0
- package/dist/core/token/token.js.map +1 -0
- package/dist/core/utils/formatToolResult.d.ts +7 -0
- package/dist/core/utils/formatToolResult.d.ts.map +1 -0
- package/dist/core/utils/formatToolResult.js +68 -0
- package/dist/core/utils/formatToolResult.js.map +1 -0
- package/dist/core/utils/rate-limit.d.ts +17 -0
- package/dist/core/utils/rate-limit.d.ts.map +1 -0
- package/dist/core/utils/rate-limit.js +56 -0
- package/dist/core/utils/rate-limit.js.map +1 -0
- package/dist/core/utils/utils.d.ts +6 -0
- package/dist/core/utils/utils.d.ts.map +1 -0
- package/dist/core/utils/utils.js +12 -0
- package/dist/core/utils/utils.js.map +1 -0
- package/dist/core/web/about-page/css.d.ts +2 -0
- package/dist/core/web/about-page/css.d.ts.map +1 -0
- package/dist/core/web/about-page/css.js +534 -0
- package/dist/core/web/about-page/css.js.map +1 -0
- package/dist/core/web/about-page/render.d.ts +2 -0
- package/dist/core/web/about-page/render.d.ts.map +1 -0
- package/dist/core/web/about-page/render.js +679 -0
- package/dist/core/web/about-page/render.js.map +1 -0
- package/dist/core/web/cors.d.ts +5 -0
- package/dist/core/web/cors.d.ts.map +1 -0
- package/dist/core/web/cors.js +22 -0
- package/dist/core/web/cors.js.map +1 -0
- package/dist/core/web/favicon-svg.d.ts +7 -0
- package/dist/core/web/favicon-svg.d.ts.map +1 -0
- package/dist/core/web/favicon-svg.js +44 -0
- package/dist/core/web/favicon-svg.js.map +1 -0
- package/dist/core/web/server-http.d.ts +5 -0
- package/dist/core/web/server-http.d.ts.map +1 -0
- package/dist/core/web/server-http.js +275 -0
- package/dist/core/web/server-http.js.map +1 -0
- package/package.json +88 -0
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
export const getHTMLPage = () => `<!DOCTYPE html>
|
|
2
|
+
<html lang='ru'>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset='UTF-8'>
|
|
5
|
+
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
|
|
6
|
+
<title>Token Generator & Validator</title>
|
|
7
|
+
<style>
|
|
8
|
+
* {
|
|
9
|
+
box-sizing: border-box;
|
|
10
|
+
margin: 0;
|
|
11
|
+
padding: 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
body {
|
|
15
|
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
16
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
17
|
+
min-height: 100vh;
|
|
18
|
+
display: flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
justify-content: center;
|
|
21
|
+
padding: 20px;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.container {
|
|
25
|
+
background: white;
|
|
26
|
+
border-radius: 20px;
|
|
27
|
+
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
|
|
28
|
+
padding: 30px;
|
|
29
|
+
width: 100%;
|
|
30
|
+
max-width: 800px;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.tab-container {
|
|
34
|
+
margin-bottom: 30px;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.tabs {
|
|
38
|
+
display: flex;
|
|
39
|
+
border-bottom: 2px solid #f0f0f0;
|
|
40
|
+
margin-bottom: 20px;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.tab {
|
|
44
|
+
background: none;
|
|
45
|
+
border: none;
|
|
46
|
+
padding: 15px 25px;
|
|
47
|
+
cursor: pointer;
|
|
48
|
+
font-size: 16px;
|
|
49
|
+
font-weight: 500;
|
|
50
|
+
color: #666;
|
|
51
|
+
border-bottom: 2px solid transparent;
|
|
52
|
+
transition: all 0.3s ease;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.tab.active {
|
|
56
|
+
color: #667eea;
|
|
57
|
+
border-bottom-color: #667eea;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.tab:hover {
|
|
61
|
+
background: #f9f9f9;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.tab-content {
|
|
65
|
+
display: none;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.tab-content.active {
|
|
69
|
+
display: block;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.form-group {
|
|
73
|
+
margin-bottom: 20px;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.form-row {
|
|
77
|
+
display: flex;
|
|
78
|
+
gap: 10px;
|
|
79
|
+
align-items: center;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
label {
|
|
83
|
+
display: block;
|
|
84
|
+
margin-bottom: 5px;
|
|
85
|
+
font-weight: 500;
|
|
86
|
+
color: #333;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
input, select, textarea {
|
|
90
|
+
width: 100%;
|
|
91
|
+
padding: 12px;
|
|
92
|
+
border: 2px solid #e0e0e0;
|
|
93
|
+
border-radius: 8px;
|
|
94
|
+
font-size: 14px;
|
|
95
|
+
transition: border-color 0.3s ease;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
input:focus, select:focus, textarea:focus {
|
|
99
|
+
outline: none;
|
|
100
|
+
border-color: #667eea;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.time-input {
|
|
104
|
+
flex: 1;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.time-unit {
|
|
108
|
+
flex: 0 0 120px;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.key-value-pair {
|
|
112
|
+
display: flex;
|
|
113
|
+
gap: 10px;
|
|
114
|
+
margin-bottom: 10px;
|
|
115
|
+
align-items: center;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.key-value-pair input {
|
|
119
|
+
margin-bottom: 0;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.key-value-pair input[name="keys"] {
|
|
123
|
+
width: 180px;
|
|
124
|
+
flex-shrink: 0;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.key-value-pair input[name="values"] {
|
|
128
|
+
flex: 1;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.remove-btn {
|
|
132
|
+
background: #ffffff;
|
|
133
|
+
color: #ff0000;
|
|
134
|
+
border: 1px solid #ffb7b7;
|
|
135
|
+
border-radius: 50%;
|
|
136
|
+
width: 36px;
|
|
137
|
+
height: 36px;
|
|
138
|
+
cursor: pointer;
|
|
139
|
+
font-size: 24px;
|
|
140
|
+
display: flex;
|
|
141
|
+
align-items: center;
|
|
142
|
+
justify-content: center;
|
|
143
|
+
transition: background 0.3s ease;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.remove-btn:hover {
|
|
147
|
+
background: #ff3838;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.add-btn {
|
|
151
|
+
background: #2ed573;
|
|
152
|
+
color: white;
|
|
153
|
+
border: none;
|
|
154
|
+
border-radius: 50%;
|
|
155
|
+
width: 40px;
|
|
156
|
+
height: 40px;
|
|
157
|
+
cursor: pointer;
|
|
158
|
+
font-size: 20px;
|
|
159
|
+
display: flex;
|
|
160
|
+
align-items: center;
|
|
161
|
+
justify-content: center;
|
|
162
|
+
margin: 10px auto;
|
|
163
|
+
transition: background 0.3s ease;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.add-btn:hover {
|
|
167
|
+
background: #26d068;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.btn {
|
|
171
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
172
|
+
color: white;
|
|
173
|
+
border: none;
|
|
174
|
+
padding: 15px 30px;
|
|
175
|
+
border-radius: 10px;
|
|
176
|
+
font-size: 16px;
|
|
177
|
+
font-weight: 500;
|
|
178
|
+
cursor: pointer;
|
|
179
|
+
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
|
180
|
+
width: 100%;
|
|
181
|
+
margin-bottom: 20px;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.btn:hover {
|
|
185
|
+
transform: translateY(-2px);
|
|
186
|
+
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.btn:active {
|
|
190
|
+
transform: translateY(0);
|
|
191
|
+
}
|
|
192
|
+
|
|
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
|
+
|
|
201
|
+
.result {
|
|
202
|
+
margin-top: 20px;
|
|
203
|
+
padding: 20px;
|
|
204
|
+
border-radius: 10px;
|
|
205
|
+
font-family: 'Courier New', monospace;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.result.success {
|
|
209
|
+
background: #d4edda;
|
|
210
|
+
color: #155724;
|
|
211
|
+
border: 1px solid #c3e6cb;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.result.error {
|
|
215
|
+
background: #f8d7da;
|
|
216
|
+
color: #721c24;
|
|
217
|
+
border: 1px solid #f5c6cb;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.token-output {
|
|
221
|
+
background: #f8f9fa;
|
|
222
|
+
border: 2px solid #e9ecef;
|
|
223
|
+
border-radius: 8px;
|
|
224
|
+
padding: 15px;
|
|
225
|
+
font-family: 'Courier New', monospace;
|
|
226
|
+
font-size: 12px;
|
|
227
|
+
line-height: 1.4;
|
|
228
|
+
word-break: break-all;
|
|
229
|
+
min-height: 100px;
|
|
230
|
+
resize: vertical;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.token-info {
|
|
234
|
+
background: #e8f5e8;
|
|
235
|
+
border: 1px solid #d4edda;
|
|
236
|
+
border-radius: 8px;
|
|
237
|
+
padding: 15px;
|
|
238
|
+
margin-top: 15px;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.token-info h4 {
|
|
242
|
+
margin-bottom: 10px;
|
|
243
|
+
color: #155724;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.token-info p {
|
|
247
|
+
margin: 5px 0;
|
|
248
|
+
font-family: 'Courier New', monospace;
|
|
249
|
+
font-size: 14px;
|
|
250
|
+
}
|
|
251
|
+
</style>
|
|
252
|
+
</head>
|
|
253
|
+
<body>
|
|
254
|
+
<div class="container">
|
|
255
|
+
<div class="tab-container">
|
|
256
|
+
<div class="tabs">
|
|
257
|
+
<button class="tab active" onclick="switchTab('generate')">Token generation</button>
|
|
258
|
+
<button class="tab" onclick="switchTab('validate')">Token validation</button>
|
|
259
|
+
</div>
|
|
260
|
+
|
|
261
|
+
<!-- Token generation -->
|
|
262
|
+
<div id="generate" class="tab-content active">
|
|
263
|
+
<form id="generateForm">
|
|
264
|
+
<div class="form-group">
|
|
265
|
+
<div class="form-row" style="gap: 20px;">
|
|
266
|
+
<div style="flex: 1;">
|
|
267
|
+
<label for="tokenUser">Who is the token issued to:</label>
|
|
268
|
+
<input type="text" id="tokenUser" name="user" required>
|
|
269
|
+
</div>
|
|
270
|
+
<div style="flex: 1;">
|
|
271
|
+
<label>For how long:</label>
|
|
272
|
+
<div class="form-row">
|
|
273
|
+
<input type="number" id="timeValue" name="timeValue" class="time-input" min="1" required>
|
|
274
|
+
<select id="timeUnit" name="timeUnit" class="time-unit">
|
|
275
|
+
<option value="minutes">minutes</option>
|
|
276
|
+
<option value="hours">hours</option>
|
|
277
|
+
<option value="days" selected>days</option>
|
|
278
|
+
<option value="months">months</option>
|
|
279
|
+
<option value="years">years</option>
|
|
280
|
+
</select>
|
|
281
|
+
</div>
|
|
282
|
+
</div>
|
|
283
|
+
</div>
|
|
284
|
+
</div>
|
|
285
|
+
<div class="form-group">
|
|
286
|
+
<label>Additional data (key-value):</label>
|
|
287
|
+
<div id="keyValuePairs"></div>
|
|
288
|
+
<button type="button" class="add-btn" onclick="addKeyValuePair()">+</button>
|
|
289
|
+
</div>
|
|
290
|
+
<button type="submit" class="btn">Generate a token</button>
|
|
291
|
+
</form>
|
|
292
|
+
<div id="generateResult"></div>
|
|
293
|
+
</div>
|
|
294
|
+
|
|
295
|
+
<!-- Token validation -->
|
|
296
|
+
<div id="validate" class="tab-content">
|
|
297
|
+
<form id="validateForm">
|
|
298
|
+
<div class="form-group">
|
|
299
|
+
<label for="tokenInput">Enter the token for verification:</label>
|
|
300
|
+
<textarea id="tokenInput" name="token" rows="4" required></textarea>
|
|
301
|
+
</div>
|
|
302
|
+
<button type="submit" class="btn">Check Token</button>
|
|
303
|
+
</form>
|
|
304
|
+
<div id="validateResult"></div>
|
|
305
|
+
</div>
|
|
306
|
+
</div>
|
|
307
|
+
</div>
|
|
308
|
+
|
|
309
|
+
<script>
|
|
310
|
+
let keyValuePairCount = 0;
|
|
311
|
+
|
|
312
|
+
function switchTab (tabName) {
|
|
313
|
+
document.querySelectorAll('.tab-content').forEach(content => {
|
|
314
|
+
content.classList.remove('active');
|
|
315
|
+
});
|
|
316
|
+
document.querySelectorAll('.tab').forEach(tab => {
|
|
317
|
+
tab.classList.remove('active');
|
|
318
|
+
});
|
|
319
|
+
document.getElementById(tabName).classList.add('active');
|
|
320
|
+
event.target.classList.add('active');
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function addKeyValuePair (key = '', value = '', readonly = false, placeholder = 'Value') {
|
|
324
|
+
if (keyValuePairCount >= 15) {
|
|
325
|
+
alert('Maximum of 15 key-value pairs');
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
const container = document.getElementById('keyValuePairs');
|
|
329
|
+
const pairDiv = document.createElement('div');
|
|
330
|
+
pairDiv.className = 'key-value-pair';
|
|
331
|
+
|
|
332
|
+
const keyInput = readonly ?
|
|
333
|
+
'<input type="text" placeholder="Key" name="keys" value="' + key + '" readonly style="background-color: #f8f9fa;">' :
|
|
334
|
+
'<input type="text" placeholder="Key" name="keys" value="' + key + '">';
|
|
335
|
+
|
|
336
|
+
const valueInput = '<input type="text" placeholder="' + placeholder + '" name="values" value="' + value + '">';
|
|
337
|
+
|
|
338
|
+
pairDiv.innerHTML = keyInput + valueInput +
|
|
339
|
+
'<button type="button" class="remove-btn" onclick="removeKeyValuePair(this)">×</button>';
|
|
340
|
+
container.appendChild(pairDiv);
|
|
341
|
+
keyValuePairCount++;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
function removeKeyValuePair (button) {
|
|
345
|
+
button.parentElement.remove();
|
|
346
|
+
keyValuePairCount--;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
function copyToClipboard (text) {
|
|
350
|
+
navigator.clipboard.writeText(text).then(() => {
|
|
351
|
+
alert('Token copied to clipboard!');
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function formatTime (ms) {
|
|
356
|
+
const seconds = Math.floor(ms / 1000);
|
|
357
|
+
const minutes = Math.floor(seconds / 60);
|
|
358
|
+
const hours = Math.floor(minutes / 60);
|
|
359
|
+
const days = Math.floor(hours / 24);
|
|
360
|
+
|
|
361
|
+
if (days > 0) return days + ' d. ' + (hours % 24) + ' h.';
|
|
362
|
+
if (hours > 0) return hours + ' h. ' + (minutes % 60) + ' min.';
|
|
363
|
+
if (minutes > 0) return minutes + ' min.';
|
|
364
|
+
return seconds + ' s.';
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Processing the Generation Form
|
|
368
|
+
document.getElementById('generateForm').addEventListener('submit', async (e) => {
|
|
369
|
+
e.preventDefault();
|
|
370
|
+
|
|
371
|
+
const formData = new FormData(e.target);
|
|
372
|
+
const keys = formData.getAll('keys').filter(k => k.trim());
|
|
373
|
+
const values = formData.getAll('values').filter(v => v.trim());
|
|
374
|
+
|
|
375
|
+
const payload = {};
|
|
376
|
+
for (let i = 0; i < keys.length; i++) {
|
|
377
|
+
if (keys[i] && values[i]) {
|
|
378
|
+
payload[keys[i]] = values[i];
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const requestData = {
|
|
383
|
+
user: formData.get('user'),
|
|
384
|
+
timeValue: parseInt(formData.get('timeValue')),
|
|
385
|
+
timeUnit: formData.get('timeUnit'),
|
|
386
|
+
payload: payload,
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
try {
|
|
390
|
+
const response = await fetch('/api/generate-token', {
|
|
391
|
+
method: 'POST',
|
|
392
|
+
headers: { 'Content-Type': 'application/json' },
|
|
393
|
+
body: JSON.stringify(requestData),
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
const result = await response.json();
|
|
397
|
+
const resultDiv = document.getElementById('generateResult');
|
|
398
|
+
|
|
399
|
+
if (result.success) {
|
|
400
|
+
resultDiv.innerHTML =
|
|
401
|
+
'<div class="result success">' +
|
|
402
|
+
'<strong>The token has been successfully created!</strong><br>' +
|
|
403
|
+
'<div class="token-output">' + result.token + '</div>' +
|
|
404
|
+
'<button class="copy-btn" onclick="copyToClipboard(\\'' + result.token + '\\')">Copy Token</button>' +
|
|
405
|
+
'</div>';
|
|
406
|
+
} else {
|
|
407
|
+
resultDiv.innerHTML =
|
|
408
|
+
'<div class="result error">' +
|
|
409
|
+
'<strong>Error:</strong> ' + result.error +
|
|
410
|
+
'</div>';
|
|
411
|
+
}
|
|
412
|
+
} catch (error) {
|
|
413
|
+
document.getElementById('generateResult').innerHTML =
|
|
414
|
+
'<div class="result error">' +
|
|
415
|
+
'<strong>Error:</strong> ' + error.message +
|
|
416
|
+
'</div>';
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
// Processing the Verification Form
|
|
421
|
+
document.getElementById('validateForm').addEventListener('submit', async (e) => {
|
|
422
|
+
e.preventDefault();
|
|
423
|
+
|
|
424
|
+
const formData = new FormData(e.target);
|
|
425
|
+
const token = formData.get('token').trim();
|
|
426
|
+
|
|
427
|
+
try {
|
|
428
|
+
const response = await fetch('/api/validate-token', {
|
|
429
|
+
method: 'POST',
|
|
430
|
+
headers: { 'Content-Type': 'application/json' },
|
|
431
|
+
body: JSON.stringify({ token }),
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
const result = await response.json();
|
|
435
|
+
const resultDiv = document.getElementById('validateResult');
|
|
436
|
+
|
|
437
|
+
if (result.success) {
|
|
438
|
+
const remainingTime = result.payload.expire - Date.now();
|
|
439
|
+
const payloadKeys = Object.keys(result.payload).filter(k => k !== 'user' && k !== 'expire');
|
|
440
|
+
|
|
441
|
+
let payloadHtml = '';
|
|
442
|
+
if (payloadKeys.length > 0) {
|
|
443
|
+
payloadHtml = '<h4>Additional data:</h4>';
|
|
444
|
+
payloadKeys.forEach(key => {
|
|
445
|
+
payloadHtml += '<p><strong>' + key + ':</strong> ' + result.payload[key] + '</p>';
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
resultDiv.innerHTML =
|
|
450
|
+
'<div class="result success">' +
|
|
451
|
+
'<strong>The token is valid!</strong>' +
|
|
452
|
+
'<div class="token-info">' +
|
|
453
|
+
'<h4>Token Information:</h4>' +
|
|
454
|
+
'<p><strong>User:</strong> ' + result.payload.user + '</p>' +
|
|
455
|
+
'<p><strong>Time remaining:</strong> ' + formatTime(remainingTime) + '</p>' +
|
|
456
|
+
'<p><strong>Expires:</strong> ' + new Date(result.payload.expire).toLocaleString('ru-RU') + '</p>' +
|
|
457
|
+
payloadHtml +
|
|
458
|
+
'</div>' +
|
|
459
|
+
'</div>';
|
|
460
|
+
} else {
|
|
461
|
+
resultDiv.innerHTML =
|
|
462
|
+
'<div class="result error">' +
|
|
463
|
+
'<strong>Token invalid!</strong><br>' +
|
|
464
|
+
'Reason: ' + result.error +
|
|
465
|
+
'</div>';
|
|
466
|
+
}
|
|
467
|
+
} catch (error) {
|
|
468
|
+
document.getElementById('validateResult').innerHTML =
|
|
469
|
+
'<div class="result error">' +
|
|
470
|
+
'<strong>Error:</strong> ' + error.message +
|
|
471
|
+
'</div>';
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
// Function to initialize the form
|
|
476
|
+
async function initializeForm () {
|
|
477
|
+
try {
|
|
478
|
+
// Getting information about the service
|
|
479
|
+
const response = await fetch('/api/service-info');
|
|
480
|
+
const data = await response.json();
|
|
481
|
+
const serviceName = data.serviceName;
|
|
482
|
+
|
|
483
|
+
// Adding a pre-filled pair serviceName
|
|
484
|
+
addKeyValuePair('service', serviceName, true);
|
|
485
|
+
addKeyValuePair('issue', '', true, 'Reqoest for the issuance of a token');
|
|
486
|
+
|
|
487
|
+
} catch (error) {
|
|
488
|
+
console.error('Error loading service info:', error);
|
|
489
|
+
}
|
|
490
|
+
// Add one empty pair for the user
|
|
491
|
+
addKeyValuePair();
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Initialization on page load
|
|
495
|
+
initializeForm();
|
|
496
|
+
</script>
|
|
497
|
+
</body>
|
|
498
|
+
</html>
|
|
499
|
+
`;
|
|
500
|
+
//# sourceMappingURL=html.js.map
|
|
@@ -0,0 +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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkfxC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type TTokenType = 'permanent' | 'JWT';
|
|
2
|
+
export interface ITokenPayload {
|
|
3
|
+
user: string;
|
|
4
|
+
expire: number;
|
|
5
|
+
[key: string]: any;
|
|
6
|
+
}
|
|
7
|
+
export interface ICheckTokenResult {
|
|
8
|
+
inTokenType?: TTokenType;
|
|
9
|
+
payload?: ITokenPayload;
|
|
10
|
+
errorReason?: string;
|
|
11
|
+
isTokenDecrypted?: boolean;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=i-token.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i-token.d.ts","sourceRoot":"","sources":["../../../src/core/token/i-token.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG,KAAK,CAAC;AAE7C,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,CAAC,EAAE,UAAU,CAAA;IACxB,OAAO,CAAC,EAAE,aAAa,CAAC;IAExB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i-token.js","sourceRoot":"","sources":["../../../src/core/token/i-token.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ICheckTokenResult } from './i-token.js';
|
|
2
|
+
export declare const tokenRE: RegExp;
|
|
3
|
+
/**
|
|
4
|
+
* Encrypts the transmitted text with a symmetric key taken from the config
|
|
5
|
+
*/
|
|
6
|
+
export declare const encrypt: (text: string) => string;
|
|
7
|
+
/**
|
|
8
|
+
* Decrypts the transmitted text with a symmetric key taken from the config
|
|
9
|
+
*/
|
|
10
|
+
export declare const decrypt: (encryptedStr: string) => string;
|
|
11
|
+
/**
|
|
12
|
+
* Creates a token by encrypting the username and expiration time.
|
|
13
|
+
* To determine the expiration time in the JB form script, at the beginning of the token
|
|
14
|
+
* deprecation timestamp is added
|
|
15
|
+
*/
|
|
16
|
+
export declare const generateToken: (user: string, liveTimeSec: number, payload?: any) => string;
|
|
17
|
+
/**
|
|
18
|
+
* Checks the validity of the token:
|
|
19
|
+
* - Token to be decrypted
|
|
20
|
+
* - the obsolescence time must not be expired
|
|
21
|
+
* - If a user is transferred, it must match
|
|
22
|
+
*/
|
|
23
|
+
export declare const checkToken: (token: string, expectedUser?: string) => ICheckTokenResult;
|
|
24
|
+
//# sourceMappingURL=token-core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-core.d.ts","sourceRoot":"","sources":["../../../src/core/token/token-core.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAiB,MAAM,cAAc,CAAC;AAkBhE,eAAO,MAAM,OAAO,QAAmC,CAAC;AAExD;;GAEG;AACH,eAAO,MAAM,OAAO,GAAI,MAAM,MAAM,KAAG,MAStC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,OAAO,GAAI,cAAc,MAAM,WAW3C,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,EAAE,aAAa,MAAM,EAAE,UAAU,GAAG,KAAG,MAYhF,CAAC;AAGF;;;;;GAKG;AACH,eAAO,MAAM,UAAU,GAAI,OAAO,MAAM,EAAE,eAAe,MAAM,KAAG,iBAiEjE,CAAC"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// noinspection UnnecessaryLocalVariableJS
|
|
2
|
+
import crypto from 'crypto';
|
|
3
|
+
import { appConfig } from '../bootstrap/init-config.js';
|
|
4
|
+
import { logger as lgr } from '../logger.js';
|
|
5
|
+
import { isObject, trim } from '../utils/utils.js';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
const logger = lgr.getSubLogger({ name: chalk.cyan('token-auth') });
|
|
8
|
+
const { permanentServerTokens: pt, tokenEncryptKey } = appConfig.webServer.auth;
|
|
9
|
+
const permanentServerTokensSet = new Set(Array.isArray(pt) ? pt : [pt]);
|
|
10
|
+
const ALGORITHM = 'aes-256-ctr';
|
|
11
|
+
const KEY = crypto
|
|
12
|
+
.createHash('sha256')
|
|
13
|
+
.update(String(tokenEncryptKey))
|
|
14
|
+
.digest('base64')
|
|
15
|
+
.substring(0, 32);
|
|
16
|
+
export const tokenRE = /^(\d{13,})\.([\da-fA-F]{32,})$/;
|
|
17
|
+
/**
|
|
18
|
+
* Encrypts the transmitted text with a symmetric key taken from the config
|
|
19
|
+
*/
|
|
20
|
+
export const encrypt = (text) => {
|
|
21
|
+
const buffer = Buffer.from(text);
|
|
22
|
+
// Create an initialization vector
|
|
23
|
+
const iv = crypto.randomBytes(16);
|
|
24
|
+
// Create a new cipher using the algorithm, key, and iv
|
|
25
|
+
const cipher = crypto.createCipheriv(ALGORITHM, KEY, iv);
|
|
26
|
+
// Create the new (encrypted) buffer
|
|
27
|
+
const encryptedBuf = Buffer.concat([iv, cipher.update(buffer), cipher.final()]);
|
|
28
|
+
return encryptedBuf.toString('hex');
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Decrypts the transmitted text with a symmetric key taken from the config
|
|
32
|
+
*/
|
|
33
|
+
export const decrypt = (encryptedStr) => {
|
|
34
|
+
const encryptedByf = Buffer.from(encryptedStr, 'hex');
|
|
35
|
+
// Get the iv: the first 16 bytes
|
|
36
|
+
const iv2 = encryptedByf.subarray(0, 16);
|
|
37
|
+
// Get the rest
|
|
38
|
+
const restBuf = encryptedByf.subarray(16);
|
|
39
|
+
// Create decipher
|
|
40
|
+
const decipher = crypto.createDecipheriv(ALGORITHM, KEY, iv2);
|
|
41
|
+
// Actually decrypt it
|
|
42
|
+
const decryptedBuf = Buffer.concat([decipher.update(restBuf), decipher.final()]);
|
|
43
|
+
return decryptedBuf.toString();
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Creates a token by encrypting the username and expiration time.
|
|
47
|
+
* To determine the expiration time in the JB form script, at the beginning of the token
|
|
48
|
+
* deprecation timestamp is added
|
|
49
|
+
*/
|
|
50
|
+
export const generateToken = (user, liveTimeSec, payload) => {
|
|
51
|
+
user = trim(user).toLowerCase();
|
|
52
|
+
if (!user) {
|
|
53
|
+
throw new Error('generateToken: Username is empty');
|
|
54
|
+
}
|
|
55
|
+
const expire = Date.now() + (liveTimeSec * 1000);
|
|
56
|
+
payload = isObject(payload) ? payload : {};
|
|
57
|
+
payload.user = user;
|
|
58
|
+
payload.expire = expire;
|
|
59
|
+
// Add the required serviceName parameter from appConfig
|
|
60
|
+
payload.serviceName = appConfig.name;
|
|
61
|
+
return `${expire}.${encrypt(JSON.stringify(payload))}`;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Checks the validity of the token:
|
|
65
|
+
* - Token to be decrypted
|
|
66
|
+
* - the obsolescence time must not be expired
|
|
67
|
+
* - If a user is transferred, it must match
|
|
68
|
+
*/
|
|
69
|
+
export const checkToken = (token, expectedUser) => {
|
|
70
|
+
token = (token || '').trim();
|
|
71
|
+
if (!token) {
|
|
72
|
+
return {
|
|
73
|
+
errorReason: 'Token not passed',
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
if (permanentServerTokensSet.has(token)) {
|
|
77
|
+
return {
|
|
78
|
+
inTokenType: 'permanent',
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const [, expirePartStr, encryptedPayload] = tokenRE.exec(token) || [];
|
|
82
|
+
if (!expirePartStr || !encryptedPayload) {
|
|
83
|
+
return {
|
|
84
|
+
inTokenType: 'permanent',
|
|
85
|
+
errorReason: 'The token is not a JWT and is not on the list of registered server tokens',
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
let payloadStr = '';
|
|
89
|
+
try {
|
|
90
|
+
payloadStr = decrypt(encryptedPayload);
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
logger.error(err);
|
|
94
|
+
return {
|
|
95
|
+
errorReason: `Error decrypting JWT token :: ${err.message}`,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
let payload;
|
|
99
|
+
try {
|
|
100
|
+
payload = JSON.parse(payloadStr);
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
logger.error(err);
|
|
104
|
+
return {
|
|
105
|
+
inTokenType: 'JWT',
|
|
106
|
+
errorReason: `Error deserializing payload of JWT token :: ${err.message}`,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
expectedUser = trim(expectedUser).toLowerCase();
|
|
110
|
+
if (expectedUser && payload.user !== expectedUser) {
|
|
111
|
+
return {
|
|
112
|
+
isTokenDecrypted: true,
|
|
113
|
+
inTokenType: 'JWT',
|
|
114
|
+
errorReason: `JWT Token: user not match :: Expected '${expectedUser}' / obtained from the token: '${payload.user}'`,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
let expire = Number(expirePartStr) || 0;
|
|
118
|
+
const expiredOn = Date.now() - expire;
|
|
119
|
+
if (expiredOn > 0) {
|
|
120
|
+
// Token deprecated
|
|
121
|
+
return {
|
|
122
|
+
isTokenDecrypted: true,
|
|
123
|
+
inTokenType: 'JWT',
|
|
124
|
+
errorReason: `JWT Token expired :: on ${expiredOn} mc`,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
// OK!
|
|
128
|
+
return { inTokenType: 'JWT', payload };
|
|
129
|
+
};
|
|
130
|
+
//# sourceMappingURL=token-core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-core.js","sourceRoot":"","sources":["../../../src/core/token/token-core.ts"],"names":[],"mappings":"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"}
|