@cnc_cbz/usefultools-plugin-official 1.0.1
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 +56 -0
- package/dist/base-converter.mjs +333 -0
- package/dist/case-converter.mjs +142 -0
- package/dist/chmod-calculator.mjs +286 -0
- package/dist/color-converter.mjs +211 -0
- package/dist/cron-expression.mjs +487 -0
- package/dist/cyber-chef.mjs +24885 -0
- package/dist/hash-generator.mjs +239 -0
- package/dist/html-entity.mjs +187 -0
- package/dist/image-compressor.mjs +337 -0
- package/dist/ip-subnet.mjs +222 -0
- package/dist/js-runner.mjs +39973 -0
- package/dist/json-diff.mjs +704 -0
- package/dist/json-formatter.mjs +1138 -0
- package/dist/json-yaml.mjs +256 -0
- package/dist/jwt-parser.mjs +405 -0
- package/dist/lorem-ipsum.mjs +246 -0
- package/dist/markdown-preview.mjs +184 -0
- package/dist/password-generator.mjs +254 -0
- package/dist/qr-generator.mjs +238 -0
- package/dist/regex-tester.mjs +424 -0
- package/dist/sql-formatter.mjs +242 -0
- package/dist/text-diff.mjs +940 -0
- package/dist/text-stats.mjs +205 -0
- package/dist/timestamp-converter.mjs +339 -0
- package/dist/translator.mjs +667 -0
- package/dist/url-codec.mjs +179 -0
- package/dist/uuid-generator.mjs +165 -0
- package/package.json +56 -0
- package/plugin.json +31 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { defineComponent, ref, openBlock, createElementBlock, createElementVNode, Fragment, renderList, normalizeClass, toDisplayString, createTextVNode, createCommentVNode, withDirectives, vModelText } from "vue";
|
|
2
|
+
const _hoisted_1 = { class: "flex flex-col h-full gap-4" };
|
|
3
|
+
const _hoisted_2 = { class: "flex items-center justify-between" };
|
|
4
|
+
const _hoisted_3 = { class: "flex gap-2" };
|
|
5
|
+
const _hoisted_4 = ["onClick"];
|
|
6
|
+
const _hoisted_5 = {
|
|
7
|
+
key: 0,
|
|
8
|
+
class: "px-4 py-2 bg-coral-red/20 border-2 border-coral-red rounded flex items-center gap-2 text-coral-red font-bold text-sm"
|
|
9
|
+
};
|
|
10
|
+
const _hoisted_6 = { class: "flex-1 grid grid-cols-2 gap-4 min-h-0" };
|
|
11
|
+
const _hoisted_7 = { class: "bg-deep-charcoal border-4 border-black rounded-xl shadow-hard overflow-hidden flex flex-col" };
|
|
12
|
+
const _hoisted_8 = { class: "px-3 py-2 border-b-2 border-black text-xs font-bold text-gray-500 uppercase" };
|
|
13
|
+
const _hoisted_9 = ["placeholder"];
|
|
14
|
+
const _hoisted_10 = { class: "bg-deep-charcoal border-4 border-black rounded-xl shadow-hard overflow-hidden flex flex-col" };
|
|
15
|
+
const _hoisted_11 = { class: "flex items-center justify-between px-3 py-2 border-b-2 border-black" };
|
|
16
|
+
const _hoisted_12 = { class: "text-xs font-bold text-gray-500 uppercase" };
|
|
17
|
+
const _hoisted_13 = { class: "material-icons text-sm" };
|
|
18
|
+
const _hoisted_14 = { class: "flex-1 overflow-auto px-4 py-3 font-mono text-sm text-gray-100 whitespace-pre-wrap" };
|
|
19
|
+
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
20
|
+
__name: "index",
|
|
21
|
+
setup(__props) {
|
|
22
|
+
const input = ref("");
|
|
23
|
+
const output = ref("");
|
|
24
|
+
const mode = ref("json2yaml");
|
|
25
|
+
const errorMsg = ref("");
|
|
26
|
+
const copyField = ref("");
|
|
27
|
+
function jsonToYaml(obj, indent = 0) {
|
|
28
|
+
const pad = " ".repeat(indent);
|
|
29
|
+
if (obj === null) return "null";
|
|
30
|
+
if (typeof obj === "boolean") return String(obj);
|
|
31
|
+
if (typeof obj === "number") return String(obj);
|
|
32
|
+
if (typeof obj === "string") {
|
|
33
|
+
if (obj.includes("\n") || obj.includes(":") || obj.includes("#") || obj.includes('"') || obj.includes("'") || obj.trim() !== obj)
|
|
34
|
+
return `"${obj.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n")}"`;
|
|
35
|
+
return obj;
|
|
36
|
+
}
|
|
37
|
+
if (Array.isArray(obj)) {
|
|
38
|
+
if (obj.length === 0) return "[]";
|
|
39
|
+
return obj.map((item) => {
|
|
40
|
+
const val = jsonToYaml(item, indent + 1);
|
|
41
|
+
if (typeof item === "object" && item !== null) {
|
|
42
|
+
const lines = val.split("\n");
|
|
43
|
+
return `${pad}- ${lines[0]}
|
|
44
|
+
${lines.slice(1).map((l) => `${pad} ${l}`).join("\n")}`.trimEnd();
|
|
45
|
+
}
|
|
46
|
+
return `${pad}- ${val}`;
|
|
47
|
+
}).join("\n");
|
|
48
|
+
}
|
|
49
|
+
if (typeof obj === "object") {
|
|
50
|
+
const entries = Object.entries(obj);
|
|
51
|
+
if (entries.length === 0) return "{}";
|
|
52
|
+
return entries.map(([key, val]) => {
|
|
53
|
+
const yamlVal = jsonToYaml(val, indent + 1);
|
|
54
|
+
if (typeof val === "object" && val !== null && !Array.isArray(val) && Object.keys(val).length > 0) {
|
|
55
|
+
return `${pad}${key}:
|
|
56
|
+
${yamlVal}`;
|
|
57
|
+
}
|
|
58
|
+
if (Array.isArray(val) && val.length > 0) {
|
|
59
|
+
return `${pad}${key}:
|
|
60
|
+
${yamlVal}`;
|
|
61
|
+
}
|
|
62
|
+
return `${pad}${key}: ${yamlVal}`;
|
|
63
|
+
}).join("\n");
|
|
64
|
+
}
|
|
65
|
+
return String(obj);
|
|
66
|
+
}
|
|
67
|
+
function yamlToJson(yaml) {
|
|
68
|
+
const lines = yaml.split("\n");
|
|
69
|
+
return parseYamlLines(lines, 0).value;
|
|
70
|
+
}
|
|
71
|
+
function parseYamlLines(lines, startIndent) {
|
|
72
|
+
const result = {};
|
|
73
|
+
let isArray = false;
|
|
74
|
+
const arr = [];
|
|
75
|
+
let i = 0;
|
|
76
|
+
while (i < lines.length) {
|
|
77
|
+
const line = lines[i];
|
|
78
|
+
if (line.trim() === "" || line.trim().startsWith("#")) {
|
|
79
|
+
i++;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const indent = line.search(/\S/);
|
|
83
|
+
if (indent < startIndent) break;
|
|
84
|
+
const trimmed = line.trim();
|
|
85
|
+
if (trimmed.startsWith("- ")) {
|
|
86
|
+
isArray = true;
|
|
87
|
+
const val = trimmed.slice(2).trim();
|
|
88
|
+
if (val.includes(":") && !val.startsWith('"') && !val.startsWith("'")) {
|
|
89
|
+
const subLines = [val, ...lines.slice(i + 1)];
|
|
90
|
+
const sub = parseYamlLines(subLines, indent + 2);
|
|
91
|
+
arr.push(sub.value);
|
|
92
|
+
i += sub.consumed;
|
|
93
|
+
} else {
|
|
94
|
+
arr.push(parseYamlValue(val));
|
|
95
|
+
i++;
|
|
96
|
+
}
|
|
97
|
+
} else if (trimmed.includes(":")) {
|
|
98
|
+
const colonIdx = trimmed.indexOf(":");
|
|
99
|
+
const key = trimmed.slice(0, colonIdx).trim();
|
|
100
|
+
const val = trimmed.slice(colonIdx + 1).trim();
|
|
101
|
+
if (val === "" || val === "|" || val === ">") {
|
|
102
|
+
const sub = parseYamlLines(lines.slice(i + 1), indent + 2);
|
|
103
|
+
result[key] = sub.value;
|
|
104
|
+
i += 1 + sub.consumed;
|
|
105
|
+
} else {
|
|
106
|
+
result[key] = parseYamlValue(val);
|
|
107
|
+
i++;
|
|
108
|
+
}
|
|
109
|
+
} else {
|
|
110
|
+
i++;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return { value: isArray ? arr : result, consumed: i };
|
|
114
|
+
}
|
|
115
|
+
function parseYamlValue(val) {
|
|
116
|
+
if (val === "null" || val === "~") return null;
|
|
117
|
+
if (val === "true") return true;
|
|
118
|
+
if (val === "false") return false;
|
|
119
|
+
if (/^-?\d+$/.test(val)) return parseInt(val);
|
|
120
|
+
if (/^-?\d+\.\d+$/.test(val)) return parseFloat(val);
|
|
121
|
+
if (val.startsWith('"') && val.endsWith('"') || val.startsWith("'") && val.endsWith("'"))
|
|
122
|
+
return val.slice(1, -1).replace(/\\n/g, "\n").replace(/\\"/g, '"');
|
|
123
|
+
if (val === "[]") return [];
|
|
124
|
+
if (val === "{}") return {};
|
|
125
|
+
return val;
|
|
126
|
+
}
|
|
127
|
+
function convert() {
|
|
128
|
+
errorMsg.value = "";
|
|
129
|
+
if (!input.value.trim()) {
|
|
130
|
+
output.value = "";
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
try {
|
|
134
|
+
if (mode.value === "json2yaml") {
|
|
135
|
+
const obj = JSON.parse(input.value);
|
|
136
|
+
output.value = jsonToYaml(obj);
|
|
137
|
+
} else {
|
|
138
|
+
const obj = yamlToJson(input.value);
|
|
139
|
+
output.value = JSON.stringify(obj, null, 2);
|
|
140
|
+
}
|
|
141
|
+
} catch (e) {
|
|
142
|
+
errorMsg.value = `转换失败: ${e.message || "格式无效"}`;
|
|
143
|
+
output.value = "";
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
async function copy(text, field) {
|
|
147
|
+
await navigator.clipboard.writeText(text);
|
|
148
|
+
copyField.value = field;
|
|
149
|
+
setTimeout(() => {
|
|
150
|
+
copyField.value = "";
|
|
151
|
+
}, 1200);
|
|
152
|
+
}
|
|
153
|
+
return (_ctx, _cache) => {
|
|
154
|
+
return openBlock(), createElementBlock("div", _hoisted_1, [
|
|
155
|
+
createElementVNode("div", _hoisted_2, [
|
|
156
|
+
_cache[2] || (_cache[2] = createElementVNode(
|
|
157
|
+
"div",
|
|
158
|
+
{ class: "flex items-center gap-2" },
|
|
159
|
+
[
|
|
160
|
+
createElementVNode("span", { class: "material-icons text-primary text-lg" }, "sync_alt"),
|
|
161
|
+
createElementVNode("span", { class: "text-sm font-bold text-gray-400 uppercase tracking-wider" }, "JSON ↔ YAML")
|
|
162
|
+
],
|
|
163
|
+
-1
|
|
164
|
+
/* CACHED */
|
|
165
|
+
)),
|
|
166
|
+
createElementVNode("div", _hoisted_3, [
|
|
167
|
+
(openBlock(), createElementBlock(
|
|
168
|
+
Fragment,
|
|
169
|
+
null,
|
|
170
|
+
renderList(["json2yaml", "yaml2json"], (m) => {
|
|
171
|
+
return createElementVNode("button", {
|
|
172
|
+
key: m,
|
|
173
|
+
onClick: ($event) => mode.value = m,
|
|
174
|
+
class: normalizeClass(["h-8 px-3 font-bold border-2 border-black rounded text-xs transition-all", mode.value === m ? "bg-primary text-black shadow-none translate-x-0.5 translate-y-0.5" : "bg-bg-dark text-gray-400 shadow-hard-sm hover:shadow-none hover:translate-x-0.5 hover:translate-y-0.5"])
|
|
175
|
+
}, toDisplayString(m === "json2yaml" ? "JSON → YAML" : "YAML → JSON"), 11, _hoisted_4);
|
|
176
|
+
}),
|
|
177
|
+
64
|
|
178
|
+
/* STABLE_FRAGMENT */
|
|
179
|
+
)),
|
|
180
|
+
createElementVNode("button", {
|
|
181
|
+
onClick: convert,
|
|
182
|
+
class: "h-8 px-4 bg-primary text-black font-bold border-2 border-black rounded shadow-hard-sm hover:shadow-none hover:translate-x-0.5 hover:translate-y-0.5 transition-all text-xs"
|
|
183
|
+
}, " 转换 ")
|
|
184
|
+
])
|
|
185
|
+
]),
|
|
186
|
+
errorMsg.value ? (openBlock(), createElementBlock("div", _hoisted_5, [
|
|
187
|
+
_cache[3] || (_cache[3] = createElementVNode(
|
|
188
|
+
"span",
|
|
189
|
+
{ class: "material-icons text-lg" },
|
|
190
|
+
"error_outline",
|
|
191
|
+
-1
|
|
192
|
+
/* CACHED */
|
|
193
|
+
)),
|
|
194
|
+
createTextVNode(
|
|
195
|
+
" " + toDisplayString(errorMsg.value),
|
|
196
|
+
1
|
|
197
|
+
/* TEXT */
|
|
198
|
+
)
|
|
199
|
+
])) : createCommentVNode("v-if", true),
|
|
200
|
+
createElementVNode("div", _hoisted_6, [
|
|
201
|
+
createElementVNode("div", _hoisted_7, [
|
|
202
|
+
createElementVNode(
|
|
203
|
+
"div",
|
|
204
|
+
_hoisted_8,
|
|
205
|
+
toDisplayString(mode.value === "json2yaml" ? "JSON" : "YAML"),
|
|
206
|
+
1
|
|
207
|
+
/* TEXT */
|
|
208
|
+
),
|
|
209
|
+
withDirectives(createElementVNode("textarea", {
|
|
210
|
+
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => input.value = $event),
|
|
211
|
+
onInput: convert,
|
|
212
|
+
class: "flex-1 w-full bg-transparent text-gray-100 px-4 py-3 font-mono text-sm outline-none resize-none placeholder-gray-600",
|
|
213
|
+
placeholder: mode.value === "json2yaml" ? "输入 JSON..." : "输入 YAML..."
|
|
214
|
+
}, null, 40, _hoisted_9), [
|
|
215
|
+
[vModelText, input.value]
|
|
216
|
+
])
|
|
217
|
+
]),
|
|
218
|
+
createElementVNode("div", _hoisted_10, [
|
|
219
|
+
createElementVNode("div", _hoisted_11, [
|
|
220
|
+
createElementVNode(
|
|
221
|
+
"span",
|
|
222
|
+
_hoisted_12,
|
|
223
|
+
toDisplayString(mode.value === "json2yaml" ? "YAML" : "JSON"),
|
|
224
|
+
1
|
|
225
|
+
/* TEXT */
|
|
226
|
+
),
|
|
227
|
+
output.value ? (openBlock(), createElementBlock("button", {
|
|
228
|
+
key: 0,
|
|
229
|
+
onClick: _cache[1] || (_cache[1] = ($event) => copy(output.value, "output")),
|
|
230
|
+
class: "flex items-center gap-1 text-xs text-gray-500 hover:text-primary transition-colors"
|
|
231
|
+
}, [
|
|
232
|
+
createElementVNode(
|
|
233
|
+
"span",
|
|
234
|
+
_hoisted_13,
|
|
235
|
+
toDisplayString(copyField.value === "output" ? "check" : "content_copy"),
|
|
236
|
+
1
|
|
237
|
+
/* TEXT */
|
|
238
|
+
)
|
|
239
|
+
])) : createCommentVNode("v-if", true)
|
|
240
|
+
]),
|
|
241
|
+
createElementVNode(
|
|
242
|
+
"pre",
|
|
243
|
+
_hoisted_14,
|
|
244
|
+
toDisplayString(output.value),
|
|
245
|
+
1
|
|
246
|
+
/* TEXT */
|
|
247
|
+
)
|
|
248
|
+
])
|
|
249
|
+
])
|
|
250
|
+
]);
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
export {
|
|
255
|
+
_sfc_main as default
|
|
256
|
+
};
|
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
import { defineComponent, ref, computed, openBlock, createElementBlock, createCommentVNode, createElementVNode, withDirectives, vModelText, createTextVNode, toDisplayString, normalizeClass, Fragment, renderList } from "vue";
|
|
2
|
+
const _hoisted_1 = { class: "flex flex-col h-full gap-5" };
|
|
3
|
+
const _hoisted_2 = { class: "bg-deep-charcoal border-4 border-black rounded-xl p-4 shadow-hard" };
|
|
4
|
+
const _hoisted_3 = {
|
|
5
|
+
key: 0,
|
|
6
|
+
class: "px-4 py-2 bg-coral-red/20 border-2 border-coral-red rounded flex items-center gap-2 text-coral-red font-bold text-sm"
|
|
7
|
+
};
|
|
8
|
+
const _hoisted_4 = {
|
|
9
|
+
key: 1,
|
|
10
|
+
class: "flex-1 grid grid-cols-1 lg:grid-cols-2 gap-4 min-h-0 overflow-auto"
|
|
11
|
+
};
|
|
12
|
+
const _hoisted_5 = { class: "flex flex-col gap-4" };
|
|
13
|
+
const _hoisted_6 = { class: "bg-deep-charcoal border-4 border-black rounded-xl p-4 shadow-hard" };
|
|
14
|
+
const _hoisted_7 = { class: "flex items-center justify-between mb-3" };
|
|
15
|
+
const _hoisted_8 = { class: "flex items-center gap-2" };
|
|
16
|
+
const _hoisted_9 = {
|
|
17
|
+
key: 0,
|
|
18
|
+
class: "ml-2 px-2 py-0.5 bg-electric-blue/20 text-electric-blue text-xs font-bold rounded border border-electric-blue/40"
|
|
19
|
+
};
|
|
20
|
+
const _hoisted_10 = { class: "material-icons text-sm" };
|
|
21
|
+
const _hoisted_11 = { class: "font-mono text-sm text-gray-100 bg-bg-dark rounded-lg p-3 border-2 border-black overflow-auto max-h-40" };
|
|
22
|
+
const _hoisted_12 = { class: "bg-deep-charcoal border-4 border-black rounded-xl p-4 shadow-hard" };
|
|
23
|
+
const _hoisted_13 = { class: "flex items-center justify-between mb-3" };
|
|
24
|
+
const _hoisted_14 = { class: "material-icons text-sm" };
|
|
25
|
+
const _hoisted_15 = { class: "font-mono text-sm text-gray-400 bg-bg-dark rounded-lg p-3 border-2 border-black break-all" };
|
|
26
|
+
const _hoisted_16 = { class: "flex items-center gap-3" };
|
|
27
|
+
const _hoisted_17 = { class: "text-xs text-gray-400" };
|
|
28
|
+
const _hoisted_18 = { class: "flex flex-col gap-4" };
|
|
29
|
+
const _hoisted_19 = {
|
|
30
|
+
key: 0,
|
|
31
|
+
class: "bg-deep-charcoal border-4 border-black rounded-xl p-4 shadow-hard"
|
|
32
|
+
};
|
|
33
|
+
const _hoisted_20 = { class: "space-y-1" };
|
|
34
|
+
const _hoisted_21 = ["onClick"];
|
|
35
|
+
const _hoisted_22 = { class: "text-xs text-gray-500 shrink-0 w-32" };
|
|
36
|
+
const _hoisted_23 = { class: "bg-deep-charcoal border-4 border-black rounded-xl p-4 shadow-hard" };
|
|
37
|
+
const _hoisted_24 = { class: "flex items-center justify-between mb-3" };
|
|
38
|
+
const _hoisted_25 = { class: "material-icons text-sm" };
|
|
39
|
+
const _hoisted_26 = { class: "font-mono text-sm text-gray-100 bg-bg-dark rounded-lg p-3 border-2 border-black overflow-auto max-h-60" };
|
|
40
|
+
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
41
|
+
__name: "index",
|
|
42
|
+
setup(__props) {
|
|
43
|
+
const jwtInput = ref("");
|
|
44
|
+
const copyField = ref("");
|
|
45
|
+
function base64UrlDecode(str) {
|
|
46
|
+
let base64 = str.replace(/-/g, "+").replace(/_/g, "/");
|
|
47
|
+
while (base64.length % 4) base64 += "=";
|
|
48
|
+
return decodeURIComponent(
|
|
49
|
+
atob(base64).split("").map((c) => "%" + c.charCodeAt(0).toString(16).padStart(2, "0")).join("")
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
const parsed = computed(() => {
|
|
53
|
+
const raw = jwtInput.value.trim();
|
|
54
|
+
if (!raw) return null;
|
|
55
|
+
const parts = raw.split(".");
|
|
56
|
+
if (parts.length !== 3) return { error: "JWT 格式无效,应包含 3 个部分(header.payload.signature)" };
|
|
57
|
+
try {
|
|
58
|
+
const header = JSON.parse(base64UrlDecode(parts[0]));
|
|
59
|
+
const payload = JSON.parse(base64UrlDecode(parts[1]));
|
|
60
|
+
return { header, payload, signature: parts[2], error: "" };
|
|
61
|
+
} catch {
|
|
62
|
+
return { error: "解码失败,请检查 JWT 是否完整" };
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
const claims = computed(() => {
|
|
66
|
+
if (!parsed.value || parsed.value.error || !parsed.value.payload) return [];
|
|
67
|
+
const p = parsed.value.payload;
|
|
68
|
+
const items = [];
|
|
69
|
+
if (p.iss != null) items.push({ label: "签发者 (iss)", key: "iss", value: String(p.iss), color: "text-electric-blue" });
|
|
70
|
+
if (p.sub != null) items.push({ label: "主题 (sub)", key: "sub", value: String(p.sub), color: "text-vibrant-purple" });
|
|
71
|
+
if (p.aud != null) items.push({ label: "受众 (aud)", key: "aud", value: String(p.aud), color: "text-neon-green" });
|
|
72
|
+
if (p.iat != null) items.push({ label: "签发时间 (iat)", key: "iat", value: formatTs(p.iat), color: "text-gray-300" });
|
|
73
|
+
if (p.nbf != null) items.push({ label: "生效时间 (nbf)", key: "nbf", value: formatTs(p.nbf), color: "text-gray-300" });
|
|
74
|
+
if (p.exp != null) items.push({ label: "过期时间 (exp)", key: "exp", value: formatTs(p.exp), color: isExpired.value ? "text-coral-red" : "text-neon-green" });
|
|
75
|
+
if (p.jti != null) items.push({ label: "JWT ID (jti)", key: "jti", value: String(p.jti), color: "text-gray-300" });
|
|
76
|
+
return items;
|
|
77
|
+
});
|
|
78
|
+
const isExpired = computed(() => {
|
|
79
|
+
var _a;
|
|
80
|
+
if (!parsed.value || parsed.value.error || !((_a = parsed.value.payload) == null ? void 0 : _a.exp)) return false;
|
|
81
|
+
return parsed.value.payload.exp * 1e3 < Date.now();
|
|
82
|
+
});
|
|
83
|
+
const expiresIn = computed(() => {
|
|
84
|
+
var _a;
|
|
85
|
+
if (!parsed.value || parsed.value.error || !((_a = parsed.value.payload) == null ? void 0 : _a.exp)) return "";
|
|
86
|
+
const diff = parsed.value.payload.exp * 1e3 - Date.now();
|
|
87
|
+
const abs = Math.abs(diff);
|
|
88
|
+
const suffix = diff > 0 ? "后过期" : "前已过期";
|
|
89
|
+
if (abs < 6e4) return `${Math.floor(abs / 1e3)} 秒${suffix}`;
|
|
90
|
+
if (abs < 36e5) return `${Math.floor(abs / 6e4)} 分钟${suffix}`;
|
|
91
|
+
if (abs < 864e5) return `${Math.floor(abs / 36e5)} 小时${suffix}`;
|
|
92
|
+
return `${Math.floor(abs / 864e5)} 天${suffix}`;
|
|
93
|
+
});
|
|
94
|
+
function formatTs(ts) {
|
|
95
|
+
const d = new Date(ts * 1e3);
|
|
96
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
97
|
+
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
|
|
98
|
+
}
|
|
99
|
+
function formatJson(obj) {
|
|
100
|
+
return JSON.stringify(obj, null, 2);
|
|
101
|
+
}
|
|
102
|
+
async function copy(text, field) {
|
|
103
|
+
await navigator.clipboard.writeText(text);
|
|
104
|
+
copyField.value = field;
|
|
105
|
+
setTimeout(() => {
|
|
106
|
+
copyField.value = "";
|
|
107
|
+
}, 1200);
|
|
108
|
+
}
|
|
109
|
+
function loadSample() {
|
|
110
|
+
const h = btoa(JSON.stringify({ alg: "HS256", typ: "JWT" })).replace(/=/g, "");
|
|
111
|
+
const p = btoa(JSON.stringify({ sub: "1234567890", name: "John Doe", iat: 1516239022, exp: Math.floor(Date.now() / 1e3) + 3600 })).replace(/=/g, "");
|
|
112
|
+
jwtInput.value = `${h}.${p}.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c`;
|
|
113
|
+
}
|
|
114
|
+
return (_ctx, _cache) => {
|
|
115
|
+
var _a, _b, _c;
|
|
116
|
+
return openBlock(), createElementBlock("div", _hoisted_1, [
|
|
117
|
+
createCommentVNode(" 输入区 "),
|
|
118
|
+
createElementVNode("div", _hoisted_2, [
|
|
119
|
+
createElementVNode("div", { class: "flex items-center justify-between mb-3" }, [
|
|
120
|
+
_cache[4] || (_cache[4] = createElementVNode(
|
|
121
|
+
"div",
|
|
122
|
+
{ class: "flex items-center gap-2" },
|
|
123
|
+
[
|
|
124
|
+
createElementVNode("span", { class: "material-icons text-primary text-lg" }, "vpn_key"),
|
|
125
|
+
createElementVNode("span", { class: "text-sm font-bold text-gray-400 uppercase tracking-wider" }, "JWT Token")
|
|
126
|
+
],
|
|
127
|
+
-1
|
|
128
|
+
/* CACHED */
|
|
129
|
+
)),
|
|
130
|
+
createElementVNode("button", {
|
|
131
|
+
onClick: loadSample,
|
|
132
|
+
class: "h-8 px-3 bg-primary text-black font-bold border-2 border-black rounded shadow-hard-sm hover:shadow-none hover:translate-x-0.5 hover:translate-y-0.5 transition-all text-xs"
|
|
133
|
+
}, " 加载示例 ")
|
|
134
|
+
]),
|
|
135
|
+
withDirectives(createElementVNode(
|
|
136
|
+
"textarea",
|
|
137
|
+
{
|
|
138
|
+
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => jwtInput.value = $event),
|
|
139
|
+
rows: "4",
|
|
140
|
+
placeholder: "粘贴 JWT Token(eyJhbGciOi...)",
|
|
141
|
+
class: "w-full bg-bg-dark text-gray-100 border-4 border-black rounded-lg px-4 py-3 font-mono text-sm shadow-hard focus:border-primary focus:shadow-none focus:translate-x-[4px] focus:translate-y-[4px] transition-all outline-none placeholder-gray-600 resize-none"
|
|
142
|
+
},
|
|
143
|
+
null,
|
|
144
|
+
512
|
|
145
|
+
/* NEED_PATCH */
|
|
146
|
+
), [
|
|
147
|
+
[vModelText, jwtInput.value]
|
|
148
|
+
])
|
|
149
|
+
]),
|
|
150
|
+
createCommentVNode(" 错误提示 "),
|
|
151
|
+
((_a = parsed.value) == null ? void 0 : _a.error) ? (openBlock(), createElementBlock("div", _hoisted_3, [
|
|
152
|
+
_cache[5] || (_cache[5] = createElementVNode(
|
|
153
|
+
"span",
|
|
154
|
+
{ class: "material-icons text-lg" },
|
|
155
|
+
"error_outline",
|
|
156
|
+
-1
|
|
157
|
+
/* CACHED */
|
|
158
|
+
)),
|
|
159
|
+
createTextVNode(
|
|
160
|
+
" " + toDisplayString(parsed.value.error),
|
|
161
|
+
1
|
|
162
|
+
/* TEXT */
|
|
163
|
+
)
|
|
164
|
+
])) : createCommentVNode("v-if", true),
|
|
165
|
+
createCommentVNode(" 解析结果 "),
|
|
166
|
+
parsed.value && !parsed.value.error ? (openBlock(), createElementBlock("div", _hoisted_4, [
|
|
167
|
+
createCommentVNode(" 左列:Header + Signature "),
|
|
168
|
+
createElementVNode("div", _hoisted_5, [
|
|
169
|
+
createCommentVNode(" Header "),
|
|
170
|
+
createElementVNode("div", _hoisted_6, [
|
|
171
|
+
createElementVNode("div", _hoisted_7, [
|
|
172
|
+
createElementVNode("div", _hoisted_8, [
|
|
173
|
+
_cache[6] || (_cache[6] = createElementVNode(
|
|
174
|
+
"span",
|
|
175
|
+
{ class: "material-icons text-electric-blue text-lg" },
|
|
176
|
+
"code",
|
|
177
|
+
-1
|
|
178
|
+
/* CACHED */
|
|
179
|
+
)),
|
|
180
|
+
_cache[7] || (_cache[7] = createElementVNode(
|
|
181
|
+
"span",
|
|
182
|
+
{ class: "text-sm font-bold text-gray-400 uppercase tracking-wider" },
|
|
183
|
+
"Header",
|
|
184
|
+
-1
|
|
185
|
+
/* CACHED */
|
|
186
|
+
)),
|
|
187
|
+
((_b = parsed.value.header) == null ? void 0 : _b.alg) ? (openBlock(), createElementBlock(
|
|
188
|
+
"span",
|
|
189
|
+
_hoisted_9,
|
|
190
|
+
toDisplayString(parsed.value.header.alg),
|
|
191
|
+
1
|
|
192
|
+
/* TEXT */
|
|
193
|
+
)) : createCommentVNode("v-if", true)
|
|
194
|
+
]),
|
|
195
|
+
createElementVNode("button", {
|
|
196
|
+
onClick: _cache[1] || (_cache[1] = ($event) => copy(formatJson(parsed.value.header), "header")),
|
|
197
|
+
class: "flex items-center gap-1 text-xs text-gray-500 hover:text-primary transition-colors"
|
|
198
|
+
}, [
|
|
199
|
+
createElementVNode(
|
|
200
|
+
"span",
|
|
201
|
+
_hoisted_10,
|
|
202
|
+
toDisplayString(copyField.value === "header" ? "check" : "content_copy"),
|
|
203
|
+
1
|
|
204
|
+
/* TEXT */
|
|
205
|
+
),
|
|
206
|
+
createTextVNode(
|
|
207
|
+
" " + toDisplayString(copyField.value === "header" ? "已复制" : "复制"),
|
|
208
|
+
1
|
|
209
|
+
/* TEXT */
|
|
210
|
+
)
|
|
211
|
+
])
|
|
212
|
+
]),
|
|
213
|
+
createElementVNode(
|
|
214
|
+
"pre",
|
|
215
|
+
_hoisted_11,
|
|
216
|
+
toDisplayString(formatJson(parsed.value.header)),
|
|
217
|
+
1
|
|
218
|
+
/* TEXT */
|
|
219
|
+
)
|
|
220
|
+
]),
|
|
221
|
+
createCommentVNode(" Signature "),
|
|
222
|
+
createElementVNode("div", _hoisted_12, [
|
|
223
|
+
createElementVNode("div", _hoisted_13, [
|
|
224
|
+
_cache[8] || (_cache[8] = createElementVNode(
|
|
225
|
+
"div",
|
|
226
|
+
{ class: "flex items-center gap-2" },
|
|
227
|
+
[
|
|
228
|
+
createElementVNode("span", { class: "material-icons text-hot-pink text-lg" }, "fingerprint"),
|
|
229
|
+
createElementVNode("span", { class: "text-sm font-bold text-gray-400 uppercase tracking-wider" }, "Signature")
|
|
230
|
+
],
|
|
231
|
+
-1
|
|
232
|
+
/* CACHED */
|
|
233
|
+
)),
|
|
234
|
+
createElementVNode("button", {
|
|
235
|
+
onClick: _cache[2] || (_cache[2] = ($event) => copy(parsed.value.signature ?? "", "sig")),
|
|
236
|
+
class: "flex items-center gap-1 text-xs text-gray-500 hover:text-primary transition-colors"
|
|
237
|
+
}, [
|
|
238
|
+
createElementVNode(
|
|
239
|
+
"span",
|
|
240
|
+
_hoisted_14,
|
|
241
|
+
toDisplayString(copyField.value === "sig" ? "check" : "content_copy"),
|
|
242
|
+
1
|
|
243
|
+
/* TEXT */
|
|
244
|
+
),
|
|
245
|
+
createTextVNode(
|
|
246
|
+
" " + toDisplayString(copyField.value === "sig" ? "已复制" : "复制"),
|
|
247
|
+
1
|
|
248
|
+
/* TEXT */
|
|
249
|
+
)
|
|
250
|
+
])
|
|
251
|
+
]),
|
|
252
|
+
createElementVNode(
|
|
253
|
+
"div",
|
|
254
|
+
_hoisted_15,
|
|
255
|
+
toDisplayString(parsed.value.signature),
|
|
256
|
+
1
|
|
257
|
+
/* TEXT */
|
|
258
|
+
)
|
|
259
|
+
]),
|
|
260
|
+
createCommentVNode(" 过期状态 "),
|
|
261
|
+
((_c = parsed.value.payload) == null ? void 0 : _c.exp) ? (openBlock(), createElementBlock(
|
|
262
|
+
"div",
|
|
263
|
+
{
|
|
264
|
+
key: 0,
|
|
265
|
+
class: normalizeClass(["border-4 border-black rounded-xl p-4 shadow-hard", isExpired.value ? "bg-coral-red/10 border-coral-red" : "bg-neon-green/10 border-neon-green"])
|
|
266
|
+
},
|
|
267
|
+
[
|
|
268
|
+
createElementVNode("div", _hoisted_16, [
|
|
269
|
+
createElementVNode(
|
|
270
|
+
"span",
|
|
271
|
+
{
|
|
272
|
+
class: normalizeClass(["material-icons text-2xl", isExpired.value ? "text-coral-red" : "text-neon-green"])
|
|
273
|
+
},
|
|
274
|
+
toDisplayString(isExpired.value ? "timer_off" : "verified"),
|
|
275
|
+
3
|
|
276
|
+
/* TEXT, CLASS */
|
|
277
|
+
),
|
|
278
|
+
createElementVNode("div", null, [
|
|
279
|
+
createElementVNode(
|
|
280
|
+
"div",
|
|
281
|
+
{
|
|
282
|
+
class: normalizeClass(["font-bold text-sm", isExpired.value ? "text-coral-red" : "text-neon-green"])
|
|
283
|
+
},
|
|
284
|
+
toDisplayString(isExpired.value ? "已过期" : "有效"),
|
|
285
|
+
3
|
|
286
|
+
/* TEXT, CLASS */
|
|
287
|
+
),
|
|
288
|
+
createElementVNode(
|
|
289
|
+
"div",
|
|
290
|
+
_hoisted_17,
|
|
291
|
+
toDisplayString(expiresIn.value),
|
|
292
|
+
1
|
|
293
|
+
/* TEXT */
|
|
294
|
+
)
|
|
295
|
+
])
|
|
296
|
+
])
|
|
297
|
+
],
|
|
298
|
+
2
|
|
299
|
+
/* CLASS */
|
|
300
|
+
)) : createCommentVNode("v-if", true)
|
|
301
|
+
]),
|
|
302
|
+
createCommentVNode(" 右列:Payload + Claims "),
|
|
303
|
+
createElementVNode("div", _hoisted_18, [
|
|
304
|
+
createCommentVNode(" 标准 Claims "),
|
|
305
|
+
claims.value.length ? (openBlock(), createElementBlock("div", _hoisted_19, [
|
|
306
|
+
_cache[9] || (_cache[9] = createElementVNode(
|
|
307
|
+
"div",
|
|
308
|
+
{ class: "flex items-center gap-2 mb-3" },
|
|
309
|
+
[
|
|
310
|
+
createElementVNode("span", { class: "material-icons text-primary text-lg" }, "badge"),
|
|
311
|
+
createElementVNode("span", { class: "text-sm font-bold text-gray-400 uppercase tracking-wider" }, "标准声明")
|
|
312
|
+
],
|
|
313
|
+
-1
|
|
314
|
+
/* CACHED */
|
|
315
|
+
)),
|
|
316
|
+
createElementVNode("div", _hoisted_20, [
|
|
317
|
+
(openBlock(true), createElementBlock(
|
|
318
|
+
Fragment,
|
|
319
|
+
null,
|
|
320
|
+
renderList(claims.value, (c) => {
|
|
321
|
+
return openBlock(), createElementBlock("div", {
|
|
322
|
+
key: c.key,
|
|
323
|
+
class: "flex items-center justify-between py-1.5 px-2 rounded hover:bg-white/5 cursor-pointer group",
|
|
324
|
+
onClick: ($event) => copy(c.value, c.key)
|
|
325
|
+
}, [
|
|
326
|
+
createElementVNode(
|
|
327
|
+
"span",
|
|
328
|
+
_hoisted_22,
|
|
329
|
+
toDisplayString(c.label),
|
|
330
|
+
1
|
|
331
|
+
/* TEXT */
|
|
332
|
+
),
|
|
333
|
+
createElementVNode(
|
|
334
|
+
"span",
|
|
335
|
+
{
|
|
336
|
+
class: normalizeClass(["font-mono text-sm flex-1 text-right", c.color])
|
|
337
|
+
},
|
|
338
|
+
toDisplayString(c.value),
|
|
339
|
+
3
|
|
340
|
+
/* TEXT, CLASS */
|
|
341
|
+
),
|
|
342
|
+
createElementVNode(
|
|
343
|
+
"span",
|
|
344
|
+
{
|
|
345
|
+
class: normalizeClass(["material-icons text-sm ml-2 opacity-0 group-hover:opacity-100 transition-opacity", copyField.value === c.key ? "text-neon-green" : "text-gray-500"])
|
|
346
|
+
},
|
|
347
|
+
toDisplayString(copyField.value === c.key ? "check" : "content_copy"),
|
|
348
|
+
3
|
|
349
|
+
/* TEXT, CLASS */
|
|
350
|
+
)
|
|
351
|
+
], 8, _hoisted_21);
|
|
352
|
+
}),
|
|
353
|
+
128
|
|
354
|
+
/* KEYED_FRAGMENT */
|
|
355
|
+
))
|
|
356
|
+
])
|
|
357
|
+
])) : createCommentVNode("v-if", true),
|
|
358
|
+
createCommentVNode(" 完整 Payload "),
|
|
359
|
+
createElementVNode("div", _hoisted_23, [
|
|
360
|
+
createElementVNode("div", _hoisted_24, [
|
|
361
|
+
_cache[10] || (_cache[10] = createElementVNode(
|
|
362
|
+
"div",
|
|
363
|
+
{ class: "flex items-center gap-2" },
|
|
364
|
+
[
|
|
365
|
+
createElementVNode("span", { class: "material-icons text-vibrant-purple text-lg" }, "description"),
|
|
366
|
+
createElementVNode("span", { class: "text-sm font-bold text-gray-400 uppercase tracking-wider" }, "Payload")
|
|
367
|
+
],
|
|
368
|
+
-1
|
|
369
|
+
/* CACHED */
|
|
370
|
+
)),
|
|
371
|
+
createElementVNode("button", {
|
|
372
|
+
onClick: _cache[3] || (_cache[3] = ($event) => copy(formatJson(parsed.value.payload), "payload")),
|
|
373
|
+
class: "flex items-center gap-1 text-xs text-gray-500 hover:text-primary transition-colors"
|
|
374
|
+
}, [
|
|
375
|
+
createElementVNode(
|
|
376
|
+
"span",
|
|
377
|
+
_hoisted_25,
|
|
378
|
+
toDisplayString(copyField.value === "payload" ? "check" : "content_copy"),
|
|
379
|
+
1
|
|
380
|
+
/* TEXT */
|
|
381
|
+
),
|
|
382
|
+
createTextVNode(
|
|
383
|
+
" " + toDisplayString(copyField.value === "payload" ? "已复制" : "复制"),
|
|
384
|
+
1
|
|
385
|
+
/* TEXT */
|
|
386
|
+
)
|
|
387
|
+
])
|
|
388
|
+
]),
|
|
389
|
+
createElementVNode(
|
|
390
|
+
"pre",
|
|
391
|
+
_hoisted_26,
|
|
392
|
+
toDisplayString(formatJson(parsed.value.payload)),
|
|
393
|
+
1
|
|
394
|
+
/* TEXT */
|
|
395
|
+
)
|
|
396
|
+
])
|
|
397
|
+
])
|
|
398
|
+
])) : createCommentVNode("v-if", true)
|
|
399
|
+
]);
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
});
|
|
403
|
+
export {
|
|
404
|
+
_sfc_main as default
|
|
405
|
+
};
|