Compare commits
3
Commits
2a2e9e0d6b
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce31ab2200 | ||
|
|
c6126b123a | ||
|
|
2adcf8f077 |
Generated
+278
-130
@@ -30,14 +30,14 @@
|
|||||||
"@types/react-dom": "^18.2.17",
|
"@types/react-dom": "^18.2.17",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.14.0",
|
"@typescript-eslint/eslint-plugin": "^6.14.0",
|
||||||
"@typescript-eslint/parser": "^6.14.0",
|
"@typescript-eslint/parser": "^6.14.0",
|
||||||
"@vitejs/plugin-react": "^4.2.1",
|
"@vitejs/plugin-react": "^4.7.0",
|
||||||
"eslint": "^8.55.0",
|
"eslint": "^8.55.0",
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.5",
|
"eslint-plugin-react-refresh": "^0.4.5",
|
||||||
"jest": "^30.3.0",
|
"jest": "^30.3.0",
|
||||||
"ts-jest": "^29.4.9",
|
"ts-jest": "^29.4.9",
|
||||||
"typescript": "^5.2.2",
|
"typescript": "^5.2.2",
|
||||||
"vite": "^5.0.8"
|
"vite": "^6.4.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/code-frame": {
|
"node_modules/@babel/code-frame": {
|
||||||
@@ -623,9 +623,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/aix-ppc64": {
|
"node_modules/@esbuild/aix-ppc64": {
|
||||||
"version": "0.21.5",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
|
"resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
|
||||||
"integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
|
"integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
@@ -636,13 +636,13 @@
|
|||||||
"aix"
|
"aix"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/android-arm": {
|
"node_modules/@esbuild/android-arm": {
|
||||||
"version": "0.21.5",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
|
"resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
|
||||||
"integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
|
"integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@@ -653,13 +653,13 @@
|
|||||||
"android"
|
"android"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/android-arm64": {
|
"node_modules/@esbuild/android-arm64": {
|
||||||
"version": "0.21.5",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
|
"resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
|
||||||
"integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
|
"integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -670,13 +670,13 @@
|
|||||||
"android"
|
"android"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/android-x64": {
|
"node_modules/@esbuild/android-x64": {
|
||||||
"version": "0.21.5",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
|
"resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
|
||||||
"integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
|
"integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -687,13 +687,13 @@
|
|||||||
"android"
|
"android"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/darwin-arm64": {
|
"node_modules/@esbuild/darwin-arm64": {
|
||||||
"version": "0.21.5",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
|
"resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
|
||||||
"integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
|
"integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -704,13 +704,13 @@
|
|||||||
"darwin"
|
"darwin"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/darwin-x64": {
|
"node_modules/@esbuild/darwin-x64": {
|
||||||
"version": "0.21.5",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
|
"resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
|
||||||
"integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
|
"integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -721,13 +721,13 @@
|
|||||||
"darwin"
|
"darwin"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/freebsd-arm64": {
|
"node_modules/@esbuild/freebsd-arm64": {
|
||||||
"version": "0.21.5",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
|
"resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
|
||||||
"integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
|
"integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -738,13 +738,13 @@
|
|||||||
"freebsd"
|
"freebsd"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/freebsd-x64": {
|
"node_modules/@esbuild/freebsd-x64": {
|
||||||
"version": "0.21.5",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
|
"resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
|
||||||
"integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
|
"integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -755,13 +755,13 @@
|
|||||||
"freebsd"
|
"freebsd"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-arm": {
|
"node_modules/@esbuild/linux-arm": {
|
||||||
"version": "0.21.5",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
|
"resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
|
||||||
"integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
|
"integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@@ -772,13 +772,13 @@
|
|||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-arm64": {
|
"node_modules/@esbuild/linux-arm64": {
|
||||||
"version": "0.21.5",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
|
"resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
|
||||||
"integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
|
"integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -789,13 +789,13 @@
|
|||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-ia32": {
|
"node_modules/@esbuild/linux-ia32": {
|
||||||
"version": "0.21.5",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
|
"resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
|
||||||
"integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
|
"integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
@@ -806,13 +806,13 @@
|
|||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-loong64": {
|
"node_modules/@esbuild/linux-loong64": {
|
||||||
"version": "0.21.5",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
|
"resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
|
||||||
"integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
|
"integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"loong64"
|
"loong64"
|
||||||
],
|
],
|
||||||
@@ -823,13 +823,13 @@
|
|||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-mips64el": {
|
"node_modules/@esbuild/linux-mips64el": {
|
||||||
"version": "0.21.5",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
|
"resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
|
||||||
"integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
|
"integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"mips64el"
|
"mips64el"
|
||||||
],
|
],
|
||||||
@@ -840,13 +840,13 @@
|
|||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-ppc64": {
|
"node_modules/@esbuild/linux-ppc64": {
|
||||||
"version": "0.21.5",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
|
"resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
|
||||||
"integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
|
"integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
@@ -857,13 +857,13 @@
|
|||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-riscv64": {
|
"node_modules/@esbuild/linux-riscv64": {
|
||||||
"version": "0.21.5",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
|
"resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
|
||||||
"integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
|
"integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
@@ -874,13 +874,13 @@
|
|||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-s390x": {
|
"node_modules/@esbuild/linux-s390x": {
|
||||||
"version": "0.21.5",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
|
"resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
|
||||||
"integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
|
"integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
@@ -891,13 +891,13 @@
|
|||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/linux-x64": {
|
"node_modules/@esbuild/linux-x64": {
|
||||||
"version": "0.21.5",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
|
"resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
|
||||||
"integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
|
"integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -908,13 +908,30 @@
|
|||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/netbsd-arm64": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"netbsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/netbsd-x64": {
|
"node_modules/@esbuild/netbsd-x64": {
|
||||||
"version": "0.21.5",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
|
"resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
|
||||||
"integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
|
"integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -925,13 +942,30 @@
|
|||||||
"netbsd"
|
"netbsd"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/openbsd-arm64": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"openbsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/openbsd-x64": {
|
"node_modules/@esbuild/openbsd-x64": {
|
||||||
"version": "0.21.5",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
|
"resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
|
||||||
"integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
|
"integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -942,13 +976,30 @@
|
|||||||
"openbsd"
|
"openbsd"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/openharmony-arm64": {
|
||||||
|
"version": "0.25.12",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
|
||||||
|
"integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"openharmony"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/sunos-x64": {
|
"node_modules/@esbuild/sunos-x64": {
|
||||||
"version": "0.21.5",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
|
"resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
|
||||||
"integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
|
"integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -959,13 +1010,13 @@
|
|||||||
"sunos"
|
"sunos"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/win32-arm64": {
|
"node_modules/@esbuild/win32-arm64": {
|
||||||
"version": "0.21.5",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
|
"resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
|
||||||
"integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
|
"integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -976,13 +1027,13 @@
|
|||||||
"win32"
|
"win32"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/win32-ia32": {
|
"node_modules/@esbuild/win32-ia32": {
|
||||||
"version": "0.21.5",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
|
"resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
|
||||||
"integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
|
"integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
@@ -993,13 +1044,13 @@
|
|||||||
"win32"
|
"win32"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@esbuild/win32-x64": {
|
"node_modules/@esbuild/win32-x64": {
|
||||||
"version": "0.21.5",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
|
"resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
|
||||||
"integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
|
"integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1010,7 +1061,7 @@
|
|||||||
"win32"
|
"win32"
|
||||||
],
|
],
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint-community/eslint-utils": {
|
"node_modules/@eslint-community/eslint-utils": {
|
||||||
@@ -4055,9 +4106,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/esbuild": {
|
"node_modules/esbuild": {
|
||||||
"version": "0.21.5",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.21.5.tgz",
|
"resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.25.12.tgz",
|
||||||
"integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
|
"integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -4065,32 +4116,35 @@
|
|||||||
"esbuild": "bin/esbuild"
|
"esbuild": "bin/esbuild"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=18"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@esbuild/aix-ppc64": "0.21.5",
|
"@esbuild/aix-ppc64": "0.25.12",
|
||||||
"@esbuild/android-arm": "0.21.5",
|
"@esbuild/android-arm": "0.25.12",
|
||||||
"@esbuild/android-arm64": "0.21.5",
|
"@esbuild/android-arm64": "0.25.12",
|
||||||
"@esbuild/android-x64": "0.21.5",
|
"@esbuild/android-x64": "0.25.12",
|
||||||
"@esbuild/darwin-arm64": "0.21.5",
|
"@esbuild/darwin-arm64": "0.25.12",
|
||||||
"@esbuild/darwin-x64": "0.21.5",
|
"@esbuild/darwin-x64": "0.25.12",
|
||||||
"@esbuild/freebsd-arm64": "0.21.5",
|
"@esbuild/freebsd-arm64": "0.25.12",
|
||||||
"@esbuild/freebsd-x64": "0.21.5",
|
"@esbuild/freebsd-x64": "0.25.12",
|
||||||
"@esbuild/linux-arm": "0.21.5",
|
"@esbuild/linux-arm": "0.25.12",
|
||||||
"@esbuild/linux-arm64": "0.21.5",
|
"@esbuild/linux-arm64": "0.25.12",
|
||||||
"@esbuild/linux-ia32": "0.21.5",
|
"@esbuild/linux-ia32": "0.25.12",
|
||||||
"@esbuild/linux-loong64": "0.21.5",
|
"@esbuild/linux-loong64": "0.25.12",
|
||||||
"@esbuild/linux-mips64el": "0.21.5",
|
"@esbuild/linux-mips64el": "0.25.12",
|
||||||
"@esbuild/linux-ppc64": "0.21.5",
|
"@esbuild/linux-ppc64": "0.25.12",
|
||||||
"@esbuild/linux-riscv64": "0.21.5",
|
"@esbuild/linux-riscv64": "0.25.12",
|
||||||
"@esbuild/linux-s390x": "0.21.5",
|
"@esbuild/linux-s390x": "0.25.12",
|
||||||
"@esbuild/linux-x64": "0.21.5",
|
"@esbuild/linux-x64": "0.25.12",
|
||||||
"@esbuild/netbsd-x64": "0.21.5",
|
"@esbuild/netbsd-arm64": "0.25.12",
|
||||||
"@esbuild/openbsd-x64": "0.21.5",
|
"@esbuild/netbsd-x64": "0.25.12",
|
||||||
"@esbuild/sunos-x64": "0.21.5",
|
"@esbuild/openbsd-arm64": "0.25.12",
|
||||||
"@esbuild/win32-arm64": "0.21.5",
|
"@esbuild/openbsd-x64": "0.25.12",
|
||||||
"@esbuild/win32-ia32": "0.21.5",
|
"@esbuild/openharmony-arm64": "0.25.12",
|
||||||
"@esbuild/win32-x64": "0.21.5"
|
"@esbuild/sunos-x64": "0.25.12",
|
||||||
|
"@esbuild/win32-arm64": "0.25.12",
|
||||||
|
"@esbuild/win32-ia32": "0.25.12",
|
||||||
|
"@esbuild/win32-x64": "0.25.12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/escalade": {
|
"node_modules/escalade": {
|
||||||
@@ -7599,6 +7653,54 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/tinyglobby": {
|
||||||
|
"version": "0.2.17",
|
||||||
|
"resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.17.tgz",
|
||||||
|
"integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"fdir": "^6.5.0",
|
||||||
|
"picomatch": "^4.0.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/SuperchupuDev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tinyglobby/node_modules/fdir": {
|
||||||
|
"version": "6.5.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.5.0.tgz",
|
||||||
|
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"picomatch": "^3 || ^4"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"picomatch": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tinyglobby/node_modules/picomatch": {
|
||||||
|
"version": "4.0.5",
|
||||||
|
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.5.tgz",
|
||||||
|
"integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tmpl": {
|
"node_modules/tmpl": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmmirror.com/tmpl/-/tmpl-1.0.5.tgz",
|
"resolved": "https://registry.npmmirror.com/tmpl/-/tmpl-1.0.5.tgz",
|
||||||
@@ -7912,21 +8014,24 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "5.4.21",
|
"version": "6.4.3",
|
||||||
"resolved": "https://registry.npmmirror.com/vite/-/vite-5.4.21.tgz",
|
"resolved": "https://registry.npmmirror.com/vite/-/vite-6.4.3.tgz",
|
||||||
"integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==",
|
"integrity": "sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.21.3",
|
"esbuild": "^0.25.0",
|
||||||
"postcss": "^8.4.43",
|
"fdir": "^6.4.4",
|
||||||
"rollup": "^4.20.0"
|
"picomatch": "^4.0.2",
|
||||||
|
"postcss": "^8.5.3",
|
||||||
|
"rollup": "^4.34.9",
|
||||||
|
"tinyglobby": "^0.2.13"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"vite": "bin/vite.js"
|
"vite": "bin/vite.js"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.0.0 || >=20.0.0"
|
"node": "^18.0.0 || ^20.0.0 || >=22.0.0"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/vitejs/vite?sponsor=1"
|
"url": "https://github.com/vitejs/vite?sponsor=1"
|
||||||
@@ -7935,19 +8040,25 @@
|
|||||||
"fsevents": "~2.3.3"
|
"fsevents": "~2.3.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/node": "^18.0.0 || >=20.0.0",
|
"@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
|
||||||
|
"jiti": ">=1.21.0",
|
||||||
"less": "*",
|
"less": "*",
|
||||||
"lightningcss": "^1.21.0",
|
"lightningcss": "^1.21.0",
|
||||||
"sass": "*",
|
"sass": "*",
|
||||||
"sass-embedded": "*",
|
"sass-embedded": "*",
|
||||||
"stylus": "*",
|
"stylus": "*",
|
||||||
"sugarss": "*",
|
"sugarss": "*",
|
||||||
"terser": "^5.4.0"
|
"terser": "^5.16.0",
|
||||||
|
"tsx": "^4.8.1",
|
||||||
|
"yaml": "^2.4.2"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
"jiti": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"less": {
|
"less": {
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
@@ -7968,9 +8079,46 @@
|
|||||||
},
|
},
|
||||||
"terser": {
|
"terser": {
|
||||||
"optional": true
|
"optional": true
|
||||||
|
},
|
||||||
|
"tsx": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"yaml": {
|
||||||
|
"optional": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vite/node_modules/fdir": {
|
||||||
|
"version": "6.5.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.5.0.tgz",
|
||||||
|
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"picomatch": "^3 || ^4"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"picomatch": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vite/node_modules/picomatch": {
|
||||||
|
"version": "4.0.5",
|
||||||
|
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.5.tgz",
|
||||||
|
"integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/walker": {
|
"node_modules/walker": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmmirror.com/walker/-/walker-1.0.8.tgz",
|
"resolved": "https://registry.npmmirror.com/walker/-/walker-1.0.8.tgz",
|
||||||
|
|||||||
+2
-2
@@ -33,13 +33,13 @@
|
|||||||
"@types/react-dom": "^18.2.17",
|
"@types/react-dom": "^18.2.17",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.14.0",
|
"@typescript-eslint/eslint-plugin": "^6.14.0",
|
||||||
"@typescript-eslint/parser": "^6.14.0",
|
"@typescript-eslint/parser": "^6.14.0",
|
||||||
"@vitejs/plugin-react": "^4.2.1",
|
"@vitejs/plugin-react": "^4.7.0",
|
||||||
"eslint": "^8.55.0",
|
"eslint": "^8.55.0",
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.5",
|
"eslint-plugin-react-refresh": "^0.4.5",
|
||||||
"jest": "^30.3.0",
|
"jest": "^30.3.0",
|
||||||
"ts-jest": "^29.4.9",
|
"ts-jest": "^29.4.9",
|
||||||
"typescript": "^5.2.2",
|
"typescript": "^5.2.2",
|
||||||
"vite": "^5.0.8"
|
"vite": "^6.4.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+122
-8
@@ -7,6 +7,7 @@ import { sm2GenerateKeyPair, sm2GetPublicKeyFromPrivateKey, sm2Encrypt, sm2Decry
|
|||||||
import { parseSm2Cert, parseCertFromFile, generateRootCert, generateAppCert, generateCrlFile, loadRootPrivateKeyFromCache } from './utils/algorithm/cert'
|
import { parseSm2Cert, parseCertFromFile, generateRootCert, generateAppCert, generateCrlFile, loadRootPrivateKeyFromCache } from './utils/algorithm/cert'
|
||||||
import { hexToUtf8, utf8ToHex, hexToBase64, base64ToHex } from './utils/convert'
|
import { hexToUtf8, utf8ToHex, hexToBase64, base64ToHex } from './utils/convert'
|
||||||
import { getInfoFromPKCS7, verifyPKCS7 } from './utils/crypto.js'
|
import { getInfoFromPKCS7, verifyPKCS7 } from './utils/crypto.js'
|
||||||
|
import { extractCertificate } from './utils/extract-cert'
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
// 从localStorage读取当前分类,默认sm3
|
// 从localStorage读取当前分类,默认sm3
|
||||||
@@ -189,6 +190,9 @@ function App() {
|
|||||||
const [pkcs7Info, setPkcs7Info] = useState<any>(null)
|
const [pkcs7Info, setPkcs7Info] = useState<any>(null)
|
||||||
const [originalData, setOriginalData] = useState<string>('')
|
const [originalData, setOriginalData] = useState<string>('')
|
||||||
const [verifyResult, setVerifyResult] = useState<string>('')
|
const [verifyResult, setVerifyResult] = useState<string>('')
|
||||||
|
const [extractInput, setExtractInput] = useState<string>('')
|
||||||
|
const [extractedCert, setExtractedCert] = useState<any>(null)
|
||||||
|
const [extractError, setExtractError] = useState<string>('')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -410,6 +414,36 @@ function App() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleExtractCertificate = () => {
|
||||||
|
try {
|
||||||
|
const result = extractCertificate(extractInput)
|
||||||
|
setExtractedCert(result)
|
||||||
|
setExtractError('')
|
||||||
|
} catch (error) {
|
||||||
|
setExtractError((error as Error).message)
|
||||||
|
setExtractedCert(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDownloadExtractedCert = (type: 'der' | 'pem') => {
|
||||||
|
if (!extractedCert) {
|
||||||
|
setExtractError('请先提取证书')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const content = type === 'der' ? extractedCert.der : extractedCert.pem
|
||||||
|
const blob = new Blob([content], { type: type === 'der' ? 'application/octet-stream' : 'application/x-pem-file' })
|
||||||
|
const downloadUrl = URL.createObjectURL(blob)
|
||||||
|
const link = document.createElement('a')
|
||||||
|
link.href = downloadUrl
|
||||||
|
link.download = type === 'der' ? 'extracted-cert.der' : 'extracted-cert.pem'
|
||||||
|
document.body.appendChild(link)
|
||||||
|
link.click()
|
||||||
|
document.body.removeChild(link)
|
||||||
|
URL.revokeObjectURL(downloadUrl)
|
||||||
|
setExtractError('')
|
||||||
|
}
|
||||||
|
|
||||||
// 处理 PKCS7 签名信息提取
|
// 处理 PKCS7 签名信息提取
|
||||||
const handleGetInfoFromPKCS7 = () => {
|
const handleGetInfoFromPKCS7 = () => {
|
||||||
try {
|
try {
|
||||||
@@ -1540,7 +1574,7 @@ function App() {
|
|||||||
transition: 'background 0.3s ease'
|
transition: 'background 0.3s ease'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Hex ← Base64
|
Base64 → Hex
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -1584,7 +1618,7 @@ function App() {
|
|||||||
transition: 'background 0.3s ease'
|
transition: 'background 0.3s ease'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Hex ← Base64
|
Base64 ← Hex
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1853,8 +1887,8 @@ function App() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 生成 CRL 文件 */}
|
{/* 生成 CRL 文件 */}
|
||||||
<div style={{ backgroundColor: '#2d2d2d', padding: '15px', borderRadius: '8px', marginBottom: '20px' }}>
|
<div style={{ backgroundColor: '#2d2d2d', padding: '18px', borderRadius: '8px', marginBottom: '18px' }}>
|
||||||
<h3 style={{ color: '#f59e0b', marginBottom: '15px' }}>3. 生成 CRL 文件</h3>
|
<h3 style={{ color: '#f59e0b', marginBottom: '12px', fontSize: '18px' }}>3. 生成 CRL 文件</h3>
|
||||||
<div className="form-group" style={{ marginBottom: '15px' }}>
|
<div className="form-group" style={{ marginBottom: '15px' }}>
|
||||||
<label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}>证书 id:</label>
|
<label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}>证书 id:</label>
|
||||||
<textarea
|
<textarea
|
||||||
@@ -1899,9 +1933,89 @@ function App() {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* 提取证书 */}
|
||||||
|
<div style={{ backgroundColor: '#2d2d2d', padding: '18px', borderRadius: '8px', marginBottom: '18px' }}>
|
||||||
|
<h3 style={{ color: '#f59e0b', marginBottom: '12px', fontSize: '18px' }}>4. 提取证书</h3>
|
||||||
|
<div className="form-group" style={{ marginBottom: '15px' }}>
|
||||||
|
<label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}>输入内容(DER / HEX / PEM / CMS)</label>
|
||||||
|
<textarea
|
||||||
|
value={extractInput}
|
||||||
|
onChange={(e) => setExtractInput(e.target.value)}
|
||||||
|
onContextMenu={(e) => openMenu(e, extractInput, setExtractInput, false)}
|
||||||
|
onTouchStart={(e) => {
|
||||||
|
const touchTimer = setTimeout(() => {
|
||||||
|
openMenu(e, extractInput, setExtractInput, false)
|
||||||
|
}, 500)
|
||||||
|
return () => clearTimeout(touchTimer)
|
||||||
|
}}
|
||||||
|
placeholder="可直接粘贴证书 DER/HEX/PEM 或 PKCS#7/CMS 数据"
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
padding: '10px',
|
||||||
|
border: '1px solid #333',
|
||||||
|
borderRadius: '4px',
|
||||||
|
backgroundColor: '#3d3d3d',
|
||||||
|
color: '#e0e0e0',
|
||||||
|
fontSize: '14px',
|
||||||
|
resize: 'vertical',
|
||||||
|
minHeight: '140px'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={handleExtractCertificate}
|
||||||
|
style={{
|
||||||
|
padding: '10px 20px',
|
||||||
|
border: 'none',
|
||||||
|
borderRadius: '4px',
|
||||||
|
background: '#f59e0b',
|
||||||
|
color: '#121212',
|
||||||
|
fontSize: '16px',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
cursor: 'pointer',
|
||||||
|
transition: 'background 0.3s ease'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
提取证书
|
||||||
|
</button>
|
||||||
|
{extractError && (
|
||||||
|
<div style={{ marginTop: '10px', color: '#fca5a5' }}>{extractError}</div>
|
||||||
|
)}
|
||||||
|
{extractedCert && (
|
||||||
|
<div style={{ marginTop: '15px', backgroundColor: '#3d3d3d', padding: '15px', borderRadius: '8px' }}>
|
||||||
|
<h4 style={{ color: '#f59e0b', marginBottom: '10px' }}>提取结果</h4>
|
||||||
|
<div style={{ marginBottom: '10px', color: '#e0e0e0' }}>
|
||||||
|
<span style={{ fontWeight: 'bold' }}>来源:</span> {extractedCert.via}
|
||||||
|
</div>
|
||||||
|
<div style={{ marginBottom: '10px', color: '#e0e0e0' }}>
|
||||||
|
<span style={{ fontWeight: 'bold' }}>长度:</span> {extractedCert.length} bytes
|
||||||
|
</div>
|
||||||
|
<textarea
|
||||||
|
value={extractedCert.pem}
|
||||||
|
readOnly
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
padding: '10px',
|
||||||
|
border: '1px solid #333',
|
||||||
|
borderRadius: '4px',
|
||||||
|
backgroundColor: '#2d2d2d',
|
||||||
|
color: '#e0e0e0',
|
||||||
|
fontSize: '14px',
|
||||||
|
resize: 'vertical',
|
||||||
|
minHeight: '160px'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div style={{ display: 'flex', gap: '10px', marginTop: '10px', flexWrap: 'wrap' }}>
|
||||||
|
<button onClick={() => handleDownloadExtractedCert('der')} style={{ padding: '10px 16px', border: 'none', borderRadius: '4px', background: '#f59e0b', color: '#121212', fontWeight: 'bold', cursor: 'pointer' }}>下载 DER</button>
|
||||||
|
<button onClick={() => handleDownloadExtractedCert('pem')} style={{ padding: '10px 16px', border: 'none', borderRadius: '4px', background: '#f59e0b', color: '#121212', fontWeight: 'bold', cursor: 'pointer' }}>下载 PEM</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* 证书解析 */}
|
{/* 证书解析 */}
|
||||||
<div style={{ backgroundColor: '#2d2d2d', padding: '15px', borderRadius: '8px' }}>
|
<div style={{ backgroundColor: '#2d2d2d', padding: '18px', borderRadius: '8px', marginBottom: '18px' }}>
|
||||||
<h3 style={{ color: '#f59e0b', marginBottom: '15px' }}>4. 证书解析</h3>
|
<h3 style={{ color: '#f59e0b', marginBottom: '12px', fontSize: '18px' }}>5. 证书解析</h3>
|
||||||
<div className="form-group" style={{ marginBottom: '20px' }}>
|
<div className="form-group" style={{ marginBottom: '20px' }}>
|
||||||
<label style={{ display: 'block', marginBottom: '10px', color: '#e0e0e0' }}>上传证书文件</label>
|
<label style={{ display: 'block', marginBottom: '10px', color: '#e0e0e0' }}>上传证书文件</label>
|
||||||
<div style={{ position: 'relative', display: 'inline-block', width: '100%' }}>
|
<div style={{ position: 'relative', display: 'inline-block', width: '100%' }}>
|
||||||
@@ -1999,8 +2113,8 @@ function App() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* PKCS7 签名工具 */}
|
{/* PKCS7 签名工具 */}
|
||||||
<div style={{ backgroundColor: '#2d2d2d', padding: '15px', borderRadius: '8px', marginTop: '20px' }}>
|
<div style={{ backgroundColor: '#2d2d2d', padding: '18px', borderRadius: '8px' }}>
|
||||||
<h3 style={{ color: '#f59e0b', marginBottom: '15px' }}>5. PKCS7 签名工具</h3>
|
<h3 style={{ color: '#f59e0b', marginBottom: '12px', fontSize: '18px' }}>6. PKCS7 签名工具</h3>
|
||||||
|
|
||||||
<div className="form-group" style={{ marginBottom: '15px' }}>
|
<div className="form-group" style={{ marginBottom: '15px' }}>
|
||||||
<label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}>PKCS7 签名数据</label>
|
<label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}>PKCS7 签名数据</label>
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { extractCertificate } from '../../utils/extract-cert'
|
||||||
|
|
||||||
|
describe('extractCertificate', () => {
|
||||||
|
it('extracts a DER-like certificate sequence from raw bytes', () => {
|
||||||
|
const certBody = new Uint8Array(120)
|
||||||
|
certBody[0] = 0x02
|
||||||
|
certBody[1] = 0x01
|
||||||
|
certBody[2] = 0x01
|
||||||
|
const der = new Uint8Array(130)
|
||||||
|
der[0] = 0x30
|
||||||
|
der[1] = 0x78
|
||||||
|
der[2] = 0x02
|
||||||
|
der[3] = 0x01
|
||||||
|
der[4] = 0x01
|
||||||
|
der.set(certBody, 5)
|
||||||
|
|
||||||
|
const result = extractCertificate(der)
|
||||||
|
|
||||||
|
expect(result.via).toBe('direct certificate')
|
||||||
|
expect(result.pem).toContain('BEGIN CERTIFICATE')
|
||||||
|
expect(result.der.length).toBeGreaterThan(0)
|
||||||
|
})
|
||||||
|
})
|
||||||
Vendored
+11
@@ -0,0 +1,11 @@
|
|||||||
|
export interface ExtractedCertificate {
|
||||||
|
der: Uint8Array
|
||||||
|
pem: string
|
||||||
|
hex: string
|
||||||
|
via: string
|
||||||
|
start: number
|
||||||
|
end: number
|
||||||
|
length: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export function extractCertificate(input: string | ArrayBuffer | ArrayBufferView | Uint8Array): ExtractedCertificate
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { extractCertificate, extractCertificateFromText } from './extract-cert.ts'
|
||||||
@@ -0,0 +1,237 @@
|
|||||||
|
/**
|
||||||
|
* 从 PKCS#7/CMS ContentInfo (DER) 中抽取内含的 X.509 证书。
|
||||||
|
*
|
||||||
|
* 可在浏览器和 Node 环境中使用。
|
||||||
|
* 支持输入:
|
||||||
|
* (a) CMS ContentInfo { OID, [0] EXPLICIT SEQUENCE(SignedData) }
|
||||||
|
* (b) 直接是一张 X.509 证书 DER
|
||||||
|
* (c) 其他 ASN.1 结构中嵌套证书 (fallback 全文扫描)
|
||||||
|
*/
|
||||||
|
|
||||||
|
interface TLV {
|
||||||
|
tag: number
|
||||||
|
headerLen: number
|
||||||
|
contentLen: number
|
||||||
|
totalLen: number
|
||||||
|
contentStart: number
|
||||||
|
contentEnd: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LocatedCertificate {
|
||||||
|
range: { start: number; end: number }
|
||||||
|
via: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExtractedCertificate {
|
||||||
|
der: Uint8Array
|
||||||
|
pem: string
|
||||||
|
hex: string
|
||||||
|
via: string
|
||||||
|
start: number
|
||||||
|
end: number
|
||||||
|
length: number
|
||||||
|
}
|
||||||
|
|
||||||
|
function toByteArray(input: string | ArrayBuffer | ArrayBufferView | Uint8Array | null | undefined): Uint8Array | null {
|
||||||
|
if (input == null) return null
|
||||||
|
|
||||||
|
if (input instanceof Uint8Array) return input
|
||||||
|
if (ArrayBuffer.isView(input)) return new Uint8Array(input.buffer, input.byteOffset, input.byteLength)
|
||||||
|
if (input instanceof ArrayBuffer) return new Uint8Array(input)
|
||||||
|
|
||||||
|
if (typeof input === 'string') {
|
||||||
|
const trimmed = input.trim()
|
||||||
|
if (!trimmed) return new Uint8Array(0)
|
||||||
|
|
||||||
|
if (/^-----BEGIN/.test(trimmed)) {
|
||||||
|
const base64Body = trimmed
|
||||||
|
.replace(/-----BEGIN CERTIFICATE-----/i, '')
|
||||||
|
.replace(/-----END CERTIFICATE-----/i, '')
|
||||||
|
.replace(/\s+/g, '')
|
||||||
|
return base64ToBytes(base64Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/^[0-9a-fA-F\s]+$/.test(trimmed)) {
|
||||||
|
return hexToBytes(trimmed)
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TextEncoder().encode(trimmed)
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
function base64ToBytes(value: string): Uint8Array {
|
||||||
|
if (typeof window !== 'undefined' && typeof window.atob === 'function') {
|
||||||
|
const binary = window.atob(value)
|
||||||
|
const bytes = new Uint8Array(binary.length)
|
||||||
|
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i)
|
||||||
|
return bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof Buffer !== 'undefined') {
|
||||||
|
return new Uint8Array(Buffer.from(value, 'base64'))
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Uint8Array([])
|
||||||
|
}
|
||||||
|
|
||||||
|
function hexToBytes(value: string): Uint8Array {
|
||||||
|
const cleaned = value.replace(/\s+/g, '')
|
||||||
|
const bytes = new Uint8Array(cleaned.length / 2)
|
||||||
|
for (let i = 0; i < cleaned.length; i += 2) {
|
||||||
|
const chunk = cleaned.slice(i, i + 2)
|
||||||
|
if (!chunk) continue
|
||||||
|
bytes[i / 2] = Number.parseInt(chunk, 16)
|
||||||
|
}
|
||||||
|
return bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
function bytesToHex(bytes: Uint8Array): string {
|
||||||
|
let out = ''
|
||||||
|
for (const byte of bytes) out += byte.toString(16).padStart(2, '0')
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
function readTLV(buf: Uint8Array, offset: number): TLV | null {
|
||||||
|
if (offset >= buf.length) return null
|
||||||
|
const tag = buf[offset++]
|
||||||
|
if ((tag & 0x1f) === 0x1f) return null
|
||||||
|
let len = buf[offset++]
|
||||||
|
let headerLen = 2
|
||||||
|
if (len & 0x80) {
|
||||||
|
const n = len & 0x7f
|
||||||
|
if (n === 0 || offset + n > buf.length) return null
|
||||||
|
len = 0
|
||||||
|
for (let i = 0; i < n; i++) len = (len << 8) | buf[offset++]
|
||||||
|
headerLen = 2 + n
|
||||||
|
}
|
||||||
|
if (offset + len > buf.length) return null
|
||||||
|
return { tag, headerLen, contentLen: len, totalLen: headerLen + len, contentStart: offset, contentEnd: offset + len }
|
||||||
|
}
|
||||||
|
|
||||||
|
function readChildren(buf: Uint8Array, start: number, end: number): TLV[] {
|
||||||
|
const out: TLV[] = []
|
||||||
|
let pos = start
|
||||||
|
while (pos < end) {
|
||||||
|
const tlv = readTLV(buf, pos)
|
||||||
|
if (!tlv || tlv.totalLen <= 0) break
|
||||||
|
out.push(tlv)
|
||||||
|
pos += tlv.totalLen
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
function looksLikeCertificate(buf: Uint8Array, tlv: TLV): boolean {
|
||||||
|
if (tlv.tag !== 0x30) return false
|
||||||
|
if (tlv.contentLen < 100 || tlv.contentLen > 8192) return false
|
||||||
|
const first = buf[tlv.contentStart]
|
||||||
|
if (first === 0x02) return true
|
||||||
|
if (first === 0xa0) {
|
||||||
|
const wrap = readTLV(buf, tlv.contentStart)
|
||||||
|
if (!wrap || wrap.tag !== 0xa0) return false
|
||||||
|
const inner = readTLV(buf, wrap.contentStart)
|
||||||
|
return !!(inner && inner.tag === 0x02)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
function findCertificateSEQUENCE(buf: Uint8Array): LocatedCertificate | null {
|
||||||
|
for (let i = 0; i < buf.length - 4; i++) {
|
||||||
|
if (buf[i] !== 0x30) continue
|
||||||
|
const tlv = readTLV(buf, i)
|
||||||
|
if (tlv && looksLikeCertificate(buf, tlv)) {
|
||||||
|
return { range: { start: i, end: i + tlv.totalLen }, via: 'fallback scan' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
function pickCertInCertificatesField(buf: Uint8Array, start: number, end: number): LocatedCertificate | null {
|
||||||
|
if (end - start > 4 && buf[start] === 0x30) {
|
||||||
|
const wrap = readTLV(buf, start)
|
||||||
|
if (wrap && wrap.tag === 0x30 && wrap.totalLen === (end - start)) {
|
||||||
|
const items = readChildren(buf, wrap.contentStart, wrap.contentEnd)
|
||||||
|
if (items.length > 0 && looksLikeCertificate(buf, items[0])) {
|
||||||
|
return { range: { start: items[0].contentStart - items[0].headerLen, end: items[0].contentEnd }, via: 'CMS ContentInfo' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const c of readChildren(buf, start, end)) {
|
||||||
|
if (looksLikeCertificate(buf, c)) {
|
||||||
|
return { range: { start: c.contentStart - c.headerLen, end: c.contentEnd }, via: 'CMS ContentInfo' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
function findCertViaCMS(buf: Uint8Array): LocatedCertificate | null {
|
||||||
|
const top = readTLV(buf, 0)
|
||||||
|
if (!top || top.tag !== 0x30 || top.contentLen < 8) return null
|
||||||
|
const topChildren = readChildren(buf, top.contentStart, top.contentEnd)
|
||||||
|
if (topChildren.length < 2) return null
|
||||||
|
const wrap0 = topChildren[1]
|
||||||
|
if (wrap0.tag !== 0xa0) return null
|
||||||
|
const sdTLV = readTLV(buf, wrap0.contentStart)
|
||||||
|
if (!sdTLV || sdTLV.tag !== 0x30) return null
|
||||||
|
const sdChildren = readChildren(buf, sdTLV.contentStart, sdTLV.contentEnd)
|
||||||
|
if (sdChildren.length < 4) return null
|
||||||
|
const certsField = sdChildren[3]
|
||||||
|
if (certsField.tag !== 0xa0) return null
|
||||||
|
return pickCertInCertificatesField(buf, certsField.contentStart, certsField.contentEnd)
|
||||||
|
}
|
||||||
|
|
||||||
|
function locateCertificate(buf: Uint8Array): LocatedCertificate | null {
|
||||||
|
const tlv = readTLV(buf, 0)
|
||||||
|
if (tlv && tlv.tag === 0x30 && looksLikeCertificate(buf, tlv)) {
|
||||||
|
return { range: { start: 0, end: tlv.totalLen }, via: 'direct certificate' }
|
||||||
|
}
|
||||||
|
const cms = findCertViaCMS(buf)
|
||||||
|
if (cms) return cms
|
||||||
|
return findCertificateSEQUENCE(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
function bytesToBase64(bytes: Uint8Array): string {
|
||||||
|
const binary = Array.from(bytes, (byte) => String.fromCharCode(byte)).join('')
|
||||||
|
if (typeof window !== 'undefined' && typeof window.btoa === 'function') {
|
||||||
|
return window.btoa(binary)
|
||||||
|
}
|
||||||
|
if (typeof Buffer !== 'undefined') {
|
||||||
|
return Buffer.from(bytes).toString('base64')
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function toPEM(der: Uint8Array): string {
|
||||||
|
const b64 = bytesToBase64(der)
|
||||||
|
const lines = b64.match(/.{1,64}/g)?.join('\n') || b64
|
||||||
|
return '-----BEGIN CERTIFICATE-----\n' + lines + '\n-----END CERTIFICATE-----\n'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function extractCertificate(input: string | ArrayBuffer | ArrayBufferView | Uint8Array | null | undefined): ExtractedCertificate {
|
||||||
|
const buf = toByteArray(input)
|
||||||
|
if (!buf) {
|
||||||
|
throw new Error('unsupported input type')
|
||||||
|
}
|
||||||
|
|
||||||
|
const located = locateCertificate(buf)
|
||||||
|
if (!located) {
|
||||||
|
throw new Error('no X.509 certificate SEQUENCE found')
|
||||||
|
}
|
||||||
|
|
||||||
|
const { range, via } = located
|
||||||
|
const der = buf.subarray(range.start, range.end)
|
||||||
|
return {
|
||||||
|
der,
|
||||||
|
pem: toPEM(der),
|
||||||
|
hex: bytesToHex(der),
|
||||||
|
via,
|
||||||
|
start: range.start,
|
||||||
|
end: range.end,
|
||||||
|
length: der.length,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function extractCertificateFromText(input: string | ArrayBuffer | ArrayBufferView | Uint8Array | null | undefined): ExtractedCertificate {
|
||||||
|
return extractCertificate(input)
|
||||||
|
}
|
||||||
+1
-1
@@ -1 +1 @@
|
|||||||
export const VERSION = "V1.0-20260428031400"
|
export const VERSION = "V1.0-20260824025705";
|
||||||
Reference in New Issue
Block a user