@pkistudio/pvkgadgets 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/core.js ADDED
@@ -0,0 +1,5 @@
1
+ import{writePkcs12Keys as O,readPkcs12Keys as T,Certificate as v,Integer as K,Time as m,CertificationRequest as M,fromBER as C,RelativeDistinguishedNames as B,BasicConstraints as V,Extension as S,AttributeTypeAndValue as H,BitString as k,PrintableString as X,IA5String as q,Utf8String as G,ObjectIdentifier as A}from"./chunks/pkcs12-lDYE488P.js";const _="0.3.0",p=[...g("RSASSA-PKCS1-v1_5","SHA-256",["sign","verify"]),...g("RSA-PSS","SHA-256",["sign","verify"]),...g("RSA-OAEP","SHA-256",["encrypt","decrypt"]),...l("ECDSA",["P-256","P-384","P-521"],["sign","verify"]),...l("ECDH",["P-256","P-384","P-521"],["deriveBits"]),...l("Ed25519",["Ed25519"],["sign","verify"]),...l("Ed448",["Ed448"],["sign","verify"]),...l("X25519",["X25519"],["deriveBits"]),...l("X448",["X448"],["deriveBits"])],b=[{id:"digitalSignature",label:"digitalSignature",bit:0},{id:"nonRepudiation",label:"nonRepudiation",bit:1},{id:"keyEncipherment",label:"keyEncipherment",bit:2},{id:"dataEncipherment",label:"dataEncipherment",bit:3},{id:"keyAgreement",label:"keyAgreement",bit:4},{id:"keyCertSign",label:"certSign",bit:5,defaultChecked:!0},{id:"cRLSign",label:"crlSign",bit:6,defaultChecked:!0},{id:"encipherOnly",label:"encipherOnly",bit:7},{id:"decipherOnly",label:"decipherOnly",bit:8}],ke={version:_,keyAlgorithms:p,certificateKeyUsages:b,getSupportedKeyAlgorithms:z,generateKeyPair:F,recognizeKeyMaterial:f,certificateMatchesKey:Z,verifyPrivateKeyMatchesPublicKey:j,createSubjectDn:oe,getCertificateSubjectDn:ce,parseSubjectDn:d,subjectDnToString:se,createCsr:te,createSelfSignedCertificate:re,readPkcs12:T,writePkcs12:O,derToPem:we,pemToDer:me,bytesEqual:L,toArrayBuffer:u};async function z(){const e=await Promise.all(p.map(async r=>({candidate:r,supported:await W(r)}))),t=new Map;for(const r of e)!r.supported||t.has(r.candidate.canonicalId)||t.set(r.candidate.canonicalId,r.candidate);return[...t.values()]}async function F(e,t={}){const{algorithm:r,usages:n}=Y(e),i=await crypto.subtle.generateKey(r,!0,n);if(!R(i))throw new Error("The browser did not return a key pair.");const[a,c]=await Promise.all([crypto.subtle.exportKey("pkcs8",i.privateKey),crypto.subtle.exportKey("spki",i.publicKey)]),o=new Uint8Array(a),y=new Uint8Array(c);return{id:t.createId?.()??Ce(),label:t.label||Ke({privateKeyDer:o,publicKeyDer:y}),privateKeyDer:o,publicKeyDer:y}}function Y(e){const t=p.find(r=>r.id===e);if(!t)throw new Error(`Unsupported algorithm: ${e||"(none selected)"}`);return t}async function W(e){try{const t=await crypto.subtle.generateKey(e.algorithm,!0,e.usages);return R(t)}catch{return!1}}function g(e,t,r){return[2048,3072,4096].map(n=>({id:`${e.toLowerCase()}-${n}`,canonicalId:`rsa-${n}`,canonicalLabel:`RSA ${n}`,algorithm:{name:e,modulusLength:n,publicExponent:new Uint8Array([1,0,1]),hash:t},usages:r}))}function l(e,t,r){return t.map(n=>({id:e===n?e.toLowerCase():`${e.toLowerCase()}-${n.toLowerCase()}`,canonicalId:e==="ECDSA"||e==="ECDH"?`ec-${n.toLowerCase()}`:e.toLowerCase(),canonicalLabel:e==="ECDSA"||e==="ECDH"?`EC ${n}`:e,algorithm:e===n?{name:e}:{name:e,namedCurve:n},usages:r}))}function R(e){return"privateKey"in e&&"publicKey"in e}function f(e){return(e.publicKeyDer?J(e.publicKeyDer):null)||(e.privateKeyDer?Q(e.privateKeyDer):s("Unknown","Unknown"))}function J(e){try{const t=w(e),r=h(t,0),{oid:n,parameters:i}=x(r);if(n==="1.2.840.113549.1.1.1"){const a=h(t,1),c=De(a);return s("RSA",c?`RSA ${c}`:"RSA")}return P(n,i)}catch{return null}}function Q(e){try{const t=w(e),r=h(t,1),{oid:n,parameters:i}=x(r);return n==="1.2.840.113549.1.1.1"?s("RSA","RSA"):P(n,i)}catch{return s("Unknown","Unknown")}}function P(e,t){if(e==="1.2.840.10045.2.1"){const r=t?ve(t):void 0;return s("EC",r?`EC ${r}`:"EC",r)}return e==="1.3.101.112"?s("Ed25519","Ed25519"):e==="1.3.101.113"?s("Ed448","Ed448"):e==="1.3.101.110"?s("X25519","X25519"):e==="1.3.101.111"?s("X448","X448"):s("Unknown",`Unknown (${e})`)}function s(e,t,r){return{family:e,label:t,canSign:e==="RSA"||e==="EC"||e==="Ed25519"||e==="Ed448",canDerive:e==="EC"||e==="X25519"||e==="X448",namedCurve:r}}async function Z(e,t){if(e.publicKeyDer)return L(e.publicKeyDer,t);if(!e.privateKeyDer)throw new Error("PrivateKey item is required before adding a certificate.");const r=f(e);if(!r.canSign)throw new Error(`${r.label} cannot be checked against a certificate.`);return j(e.privateKeyDer,t,r)}async function j(e,t,r=f({privateKeyDer:e,publicKeyDer:t})){try{const n=new TextEncoder().encode("Private Key Gadgets certificate check"),i=ee(r),[a,c]=await Promise.all([crypto.subtle.importKey("pkcs8",u(e),i.importAlgorithm,!1,["sign"]),crypto.subtle.importKey("spki",u(t),i.importAlgorithm,!1,["verify"])]),o=await crypto.subtle.sign(i.signAlgorithm,a,n);return crypto.subtle.verify(i.signAlgorithm,c,o,n)}catch{return!1}}function ee(e){if(e.family==="RSA"){const t={name:"RSASSA-PKCS1-v1_5",hash:"SHA-256"};return{importAlgorithm:t,signAlgorithm:t}}if(e.family==="EC"&&e.namedCurve)return{importAlgorithm:{name:"ECDSA",namedCurve:e.namedCurve},signAlgorithm:{name:"ECDSA",hash:"SHA-256"}};if(e.family==="Ed25519"||e.family==="Ed448"){const t={name:e.family};return{importAlgorithm:t,signAlgorithm:t}}throw new Error(`${e.label} cannot be checked against a certificate.`)}async function te(e){const t=f({privateKeyDer:e.privateKeyDer,publicKeyDer:e.publicKeyDer});if(t.family!=="RSA"&&t.family!=="EC")throw new Error(`${t.label} is not supported for CSR signing yet.`);const r=d(e.subjectBytes),[n,i]=await Promise.all([U(e.privateKeyDer,t,e.hashAlgorithm),I(e.publicKeyDer,t,e.hashAlgorithm)]),a=new M;return a.subject=r,await a.subjectPublicKeyInfo.importKey(i),a.attributes=[],await a.sign(n,e.hashAlgorithm),{subjectDn:e.subjectDn,hashAlgorithm:e.hashAlgorithm,bytes:new Uint8Array(a.toSchema(!0).toBER(!1))}}async function re(e){const t=f({privateKeyDer:e.privateKeyDer,publicKeyDer:e.publicKeyDer});if(t.family!=="RSA"&&t.family!=="EC")throw new Error(`${t.label} is not supported for certificate signing yet.`);const r=d(e.subjectBytes),n=new Date,i=new Date(n.getTime()+e.validityDays*24*60*60*1e3),[a,c]=await Promise.all([U(e.privateKeyDer,t,e.hashAlgorithm),I(e.publicKeyDer,t,e.hashAlgorithm)]),o=new v;return o.version=2,o.serialNumber=new K({valueHex:u(ae())}),o.issuer=r,o.subject=r,o.notBefore=new m({type:0,value:n}),o.notAfter=new m({type:0,value:i}),await o.subjectPublicKeyInfo.importKey(c),o.extensions=ne(e.keyUsages),await o.sign(a,e.hashAlgorithm),{subjectDn:e.subjectDn,hashAlgorithm:e.hashAlgorithm,validityDays:e.validityDays,bytes:new Uint8Array(o.toSchema(!0).toBER(!1))}}async function U(e,t,r){return crypto.subtle.importKey("pkcs8",u(e),$(t,r),!1,["sign"])}async function I(e,t,r){return crypto.subtle.importKey("spki",u(e),$(t,r),!0,["verify"])}function $(e,t){if(e.family==="RSA")return{name:"RSASSA-PKCS1-v1_5",hash:t};if(e.family==="EC"&&e.namedCurve)return{name:"ECDSA",namedCurve:e.namedCurve};throw new Error(`${e.label} is not supported for CSR signing yet.`)}function ne(e){const t=new Set(e),r=new V({cA:t.has("keyCertSign")}),n=ie(t);return[new S({extnID:"2.5.29.19",critical:t.has("keyCertSign"),extnValue:r.toSchema().toBER(!1),parsedValue:r}),new S({extnID:"2.5.29.15",critical:!0,extnValue:n.toBER(!1),parsedValue:n})]}function ie(e){const t=b.reduce((n,i)=>e.has(i.id)?Math.max(n,i.bit):n,0),r=new Uint8Array(Math.floor(t/8)+1);for(const n of b)e.has(n.id)&&(r[Math.floor(n.bit/8)]|=128>>n.bit%8);return new k({valueHex:u(r)})}function ae(){const e=new Uint8Array(16);return crypto.getRandomValues(e),e[0]&=127,e.every(t=>t===0)&&(e[15]=1),e}function oe(e){const t=new B({typesAndValues:ue(e)});return new Uint8Array(t.toSchema().toBER(!1))}function ce(e){const t=v.fromBER(u(e));return new Uint8Array(t.subject.toSchema().toBER(!1))}function d(e){const t=C(u(e));if(t.offset===-1)throw new Error("Invalid SubjectDN DER.");if(t.offset!==e.byteLength)throw new Error("SubjectDN DER has trailing data.");return new B({schema:t.result})}function se(e){const t=d(e);if(t.typesAndValues.length===0)throw new Error("SubjectDN has no attributes.");return[...t.typesAndValues].reverse().map(de).join(", ")}function ue(e){const t=le(e);if(t.length===0)throw new Error("subjectDN is required.");return[...t].reverse().map(r=>{const n=fe(r,"=");if(n<=0)throw new Error(`Invalid subjectDN part: ${r}`);const i=D(r.slice(0,n).trim()),a=D(r.slice(n+1).trim());if(!i||!a)throw new Error(`Invalid subjectDN part: ${r}`);return new H({type:ye(i),value:he(i,a)})})}function le(e){const t=e.trim();return t?t.startsWith("/")?E(t.slice(1),"/"):E(t,","):[]}function E(e,t){const r=[];let n="",i=!1;for(const a of e){if(i){n+=`\\${a}`,i=!1;continue}if(a==="\\"){i=!0;continue}if(a===t){n.trim()&&r.push(n.trim()),n="";continue}n+=a}return i&&(n+="\\"),n.trim()&&r.push(n.trim()),r}function fe(e,t){let r=!1;for(let n=0;n<e.length;n+=1){const i=e[n];if(r){r=!1;continue}if(i==="\\"){r=!0;continue}if(i===t)return n}return-1}function D(e){return e.replace(/\\([,=\\/])/g,"$1")}function ye(e){const r={C:"2.5.4.6",ST:"2.5.4.8",S:"2.5.4.8",L:"2.5.4.7",O:"2.5.4.10",OU:"2.5.4.11",CN:"2.5.4.3",DC:"0.9.2342.19200300.100.1.25",SN:"2.5.4.5",SERIALNUMBER:"2.5.4.5",EMAILADDRESS:"1.2.840.113549.1.9.1"}[e.toUpperCase()]??(/^\d+(\.\d+)+$/.test(e)?e:void 0);if(!r)throw new Error(`Unsupported subjectDN attribute: ${e}`);return r}function he(e,t){const r=e.toUpperCase();return r==="C"?new X({value:t}):r==="EMAILADDRESS"||r==="DC"?new q({value:t}):new G({value:t})}function de(e){return`${ge(e.type)}=${pe(be(e.value))}`}function ge(e){return{"2.5.4.6":"C","2.5.4.8":"ST","2.5.4.7":"L","2.5.4.10":"O","2.5.4.11":"OU","2.5.4.3":"CN","0.9.2342.19200300.100.1.25":"DC","2.5.4.5":"serialNumber","1.2.840.113549.1.9.1":"emailAddress"}[e]??e}function be(e){const t=e.valueBlock;return typeof t.value=="string"?t.value:e.toString()}function pe(e){return e.replace(/[\\,=\/]/g,t=>`\\${t}`)}function we(e,t){const n=Ae(t).match(/.{1,64}/g)??[];return`-----BEGIN ${e}-----
2
+ ${n.join(`
3
+ `)}
4
+ -----END ${e}-----
5
+ `}function me(e,t){const r=/-----BEGIN ([^-]+)-----([\s\S]*?)-----END \1-----/g,n=[];let i;for(;(i=r.exec(e))!==null;){if(t&&i[1].toUpperCase()!==t.toUpperCase())continue;const a=i[2].replace(/\s+/g,"");if(!a)throw new Error(`PEM block ${i[1]} has no base64 data.`);n.push(Se(a))}if(n.length===0)throw new Error(t?`${t} PEM was not found.`:"Could not read a PEM BEGIN/END block.");return Ee(n)}function Se(e){if(typeof atob=="function"){const t=atob(e),r=new Uint8Array(t.length);for(let n=0;n<t.length;n+=1)r[n]=t.charCodeAt(n);return r}if(typeof Buffer<"u")return new Uint8Array(Buffer.from(e,"base64"));throw new Error("Base64 decoding is not available in this runtime.")}function Ae(e){if(typeof btoa=="function"){let t="";for(let r=0;r<e.length;r+=1)t+=String.fromCharCode(e[r]);return btoa(t)}if(typeof Buffer<"u")return Buffer.from(e).toString("base64");throw new Error("Base64 encoding is not available in this runtime.")}function Ee(e){const t=e.reduce((i,a)=>i+a.length,0),r=new Uint8Array(t);let n=0;for(const i of e)r.set(i,n),n+=i.length;return r}function w(e){const t=C(u(e));if(t.offset===-1)throw new Error("Invalid DER.");if(t.offset!==e.byteLength)throw new Error("DER has trailing data.");return t.result}function h(e,t){const n=N(e)[t];if(!n)throw new Error("Missing ASN.1 sequence child.");return n}function N(e){const t=e.valueBlock;return Array.isArray(t.value)?t.value:[]}function x(e){const t=N(e),r=t[0];if(!(r instanceof A))throw new Error("Missing algorithm OID.");const n=t[1];return{oid:r.valueBlock.toString(),parameters:n instanceof A?n.valueBlock.toString():null}}function De(e){if(!(e instanceof k))return null;const r=e.valueBlock.valueHexView;if(!r||r.length===0)return null;const n=w(r),i=h(n,0),a=i.valueBlock.valueHexView;if(!(i instanceof K)||!a||a.length===0)return null;let c=0;for(;c<a.length-1&&a[c]===0;)c+=1;const o=a[c],y=o===0?0:8-Math.clz32(o)+24;return(a.length-c-1)*8+y}function ve(e){return{"1.2.840.10045.3.1.7":"P-256","1.3.132.0.34":"P-384","1.3.132.0.35":"P-521"}[e]}function Ke(e){return f({privateKeyDer:e.privateKeyDer,publicKeyDer:e.publicKeyDer}).label}function Ce(){return crypto.randomUUID?.()??String(Date.now())}function u(e){const t=new ArrayBuffer(e.byteLength);return new Uint8Array(t).set(e),t}function L(e,t){if(e.byteLength!==t.byteLength)return!1;for(let r=0;r<e.byteLength;r+=1)if(e[r]!==t[r])return!1;return!0}export{b as CERTIFICATE_KEY_USAGES,p as KEY_ALGORITHM_CANDIDATES,ke as PvkGadgetsCore};
Binary file
@@ -0,0 +1,19 @@
1
+ <!doctype html>
2
+ <html lang="ja">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <link rel="icon" href="./favicon.ico" sizes="any" />
7
+ <title>Private Key Gadgets</title>
8
+ <script type="module" crossorigin src="./main.js"></script>
9
+ <link rel="modulepreload" crossorigin href="./chunks/modulepreload-polyfill-B5Qt9EMX.js">
10
+ <link rel="modulepreload" crossorigin href="./chunks/pkcs12-lDYE488P.js">
11
+ <link rel="modulepreload" crossorigin href="./core.js">
12
+ <link rel="modulepreload" crossorigin href="./chunks/pkistudio--jw2SR0V.js">
13
+ <link rel="modulepreload" crossorigin href="./app.js">
14
+ <link rel="stylesheet" crossorigin href="./styles.css">
15
+ </head>
16
+ <body>
17
+ <div id="app"></div>
18
+ </body>
19
+ </html>
package/dist/main.js ADDED
@@ -0,0 +1 @@
1
+ import"./chunks/modulepreload-polyfill-B5Qt9EMX.js";import{initPrivateKeyGadgets as i}from"./app.js";import"./chunks/pkcs12-lDYE488P.js";import"./core.js";import"./chunks/pkistudio--jw2SR0V.js";i({mount:"#app",viewer:{newWindowUrl:"viewer.html"}});
package/dist/pkcs12.js ADDED
@@ -0,0 +1 @@
1
+ import{readPkcs12Keys as s,writePkcs12Keys as c}from"./chunks/pkcs12-lDYE488P.js";export{s as readPkcs12Keys,c as writePkcs12Keys};
@@ -0,0 +1 @@
1
+ :root{color-scheme:light dark;--bg-start: #f7f9fc;--bg: #eef1f5;--window: #f8f8f8;--chrome-start: #ffffff;--chrome: #f2f2f2;--panel: #ffffff;--panel-border: #b8c0ca;--control-border: #8f98a3;--subtle-border: #c9cdd3;--tree-line: #b9b9b9;--text: #111827;--muted: #5b6470;--accent: #2563eb;--accent-soft: #eef6ff;--hover-border: #9dbce5;--hover-bg: #eaf3ff;--selection: #cfe8ff;--selection-border: #99c7ee;--folder: #f3c14f;--folder-edge: #c69324;--folder-highlight: #ffe08a;--folder-start: #ffe28f;--leaf: #f7f7f7;--leaf-edge: #8b8b8b;--leaf-fold: #dcdcdc;--comment: #4b5563;--danger: #b91c1c;--error-border: #e7a4a4;--error-bg: #fff5f5;--field-bg: #ffffff;--dialog-overlay: rgba(15, 23, 42, .2);--shadow-strong: rgba(15, 23, 42, .18);--shadow-dialog: rgba(15, 23, 42, .22);--button-bg-start: #ffffff;--button-bg-end: #e7e9ee;--toggle-border: #7f7f7f;--toggle-text: #333333;--toggle-bg: #ffffff;--splitter: #9aa3af;--api-log-row-border: #edf0f4;--api-log-operation: #1f4f86}@media(prefers-color-scheme:dark){:root:not([data-pvkgadgets-theme=light]){color-scheme:dark;--bg-start: #202329;--bg: #171a20;--window: #202329;--chrome-start: #2b2f36;--chrome: #242830;--panel: #1b1f26;--panel-border: #4a5360;--control-border: #66707d;--subtle-border: #4c5561;--tree-line: #6d7480;--text: #e7eaf0;--muted: #a8b0bc;--accent: #7db3ff;--accent-soft: #26384d;--hover-border: #81a9dc;--hover-bg: #28384b;--selection: #21496f;--selection-border: #5d91cc;--folder: #d5a83f;--folder-edge: #a77d25;--folder-highlight: #f0c969;--folder-start: #f3d27a;--leaf: #dadde3;--leaf-edge: #8d96a3;--leaf-fold: #aeb5bf;--comment: #b6bfca;--danger: #ff9b9b;--error-border: #965f63;--error-bg: #341f24;--field-bg: #20242b;--dialog-overlay: rgba(0, 0, 0, .48);--shadow-strong: rgba(0, 0, 0, .42);--shadow-dialog: rgba(0, 0, 0, .5);--button-bg-start: #343943;--button-bg-end: #252a32;--toggle-border: #8d96a3;--toggle-text: #e7eaf0;--toggle-bg: #242830;--splitter: #7b8492;--api-log-row-border: #303640;--api-log-operation: #9fc7ff}}:root[data-pvkgadgets-theme=dark]{color-scheme:dark;--bg-start: #202329;--bg: #171a20;--window: #202329;--chrome-start: #2b2f36;--chrome: #242830;--panel: #1b1f26;--panel-border: #4a5360;--control-border: #66707d;--subtle-border: #4c5561;--tree-line: #6d7480;--text: #e7eaf0;--muted: #a8b0bc;--accent: #7db3ff;--accent-soft: #26384d;--hover-border: #81a9dc;--hover-bg: #28384b;--selection: #21496f;--selection-border: #5d91cc;--folder: #d5a83f;--folder-edge: #a77d25;--folder-highlight: #f0c969;--folder-start: #f3d27a;--leaf: #dadde3;--leaf-edge: #8d96a3;--leaf-fold: #aeb5bf;--comment: #b6bfca;--danger: #ff9b9b;--error-border: #965f63;--error-bg: #341f24;--field-bg: #20242b;--dialog-overlay: rgba(0, 0, 0, .48);--shadow-strong: rgba(0, 0, 0, .42);--shadow-dialog: rgba(0, 0, 0, .5);--button-bg-start: #343943;--button-bg-end: #252a32;--toggle-border: #8d96a3;--toggle-text: #e7eaf0;--toggle-bg: #242830;--splitter: #7b8492;--api-log-row-border: #303640;--api-log-operation: #9fc7ff}*{box-sizing:border-box}html,body{margin:0;width:100%;height:100%;min-height:0;overflow:hidden}body{color:var(--text);background:linear-gradient(var(--bg-start),var(--bg));font-family:Tahoma,MS UI Gothic,Yu Gothic UI,system-ui,sans-serif;font-size:13px}#app{width:100%;height:100dvh;min-height:0}button,input,select{font:inherit}.shell{display:flex;flex-direction:column;width:100%;height:100%;min-width:0;min-height:0;margin:0;padding:0;overflow:hidden}.toolbar{display:flex;flex-wrap:wrap;gap:2px;align-items:center;border:1px solid var(--panel-border);border-bottom:0;border-radius:0;padding:4px;background:linear-gradient(var(--chrome-start),var(--chrome))}.toolbar strong{padding:4px 8px}.toolbar button{min-height:0;border-color:transparent;padding:4px 12px;background:transparent;box-shadow:none}.toolbar button:hover,.toolbar button:focus-visible{border-color:var(--hover-border);background:var(--hover-bg);outline:none}.workspace{display:grid;flex:1 1 auto;grid-template-columns:minmax(280px,var(--key-panel-width, 360px)) 6px minmax(320px,1fr);gap:6px;min-width:0;min-height:0;overflow:hidden;border:1px solid var(--panel-border);border-radius:0;padding:8px;background:var(--window);box-shadow:none}.workspace.resizing{-webkit-user-select:none;user-select:none;cursor:col-resize}.shell.resizing-rows{-webkit-user-select:none;user-select:none;cursor:row-resize}.pane-resizer{position:relative;align-self:stretch;min-height:0;border:1px solid transparent;border-radius:3px;background:linear-gradient(90deg,transparent 0 2px,var(--splitter) 2px 3px,transparent 3px 6px);cursor:col-resize}.pane-resizer:hover,.pane-resizer:focus-visible,.workspace.resizing .pane-resizer{border-color:var(--hover-border);background-color:var(--hover-bg);outline:none}.api-log-resizer{position:relative;flex:0 0 6px;min-height:6px;border:1px solid transparent;border-radius:3px;background:linear-gradient(0deg,transparent 0 2px,var(--splitter) 2px 3px,transparent 3px 6px);cursor:row-resize}.api-log-resizer:hover,.api-log-resizer:focus-visible,.shell.resizing-rows .api-log-resizer{border-color:var(--hover-border);background-color:var(--hover-bg);outline:none}.panel{border:1px solid var(--panel-border);border-radius:3px;padding:10px;background:var(--panel)}.api-log-panel{flex:0 0 auto;margin-top:0;border:0;padding:0;background:var(--window)}.api-log-header{display:flex;align-items:center;justify-content:flex-end;border-bottom:0;border-radius:0;padding:0 0 4px;background:transparent}.api-log-header button{min-height:24px;border-color:transparent;padding:2px 8px;background:transparent;box-shadow:none}.api-log-header button:hover,.api-log-header button:focus-visible{border-color:var(--hover-border);background:var(--hover-bg);outline:none}.api-log-list{display:grid;align-content:start;height:var(--api-log-list-height, clamp(86px, 15dvh, 160px));min-height:0;overflow:auto;padding:5px 6px;background:transparent;font-family:Consolas,Courier New,monospace;font-size:12px;line-height:1.35}.api-log-entry{display:grid;grid-template-columns:174px minmax(150px,220px) minmax(0,1fr);gap:8px;align-items:baseline;min-width:0;border-bottom:1px solid var(--api-log-row-border);padding:2px 0}.api-log-entry time{color:var(--muted)}.api-log-operation{color:var(--api-log-operation);overflow-wrap:anywhere}.api-log-detail{min-width:0;overflow-wrap:anywhere}.api-log-entry.error .api-log-operation,.api-log-entry.error .api-log-detail{color:var(--danger)}.key-panel{display:flex;flex-direction:column;min-width:0;min-height:0;border:0;padding:0;background:transparent;overflow:hidden}button{min-height:28px;border:1px solid var(--control-border);border-radius:3px;padding:4px 10px;color:var(--text);background:linear-gradient(var(--button-bg-start),var(--button-bg-end));cursor:pointer}button:disabled{cursor:not-allowed;opacity:.55}.visually-hidden{display:none}.key-menu{position:relative;z-index:2;display:flex;flex:0 0 auto;flex-wrap:wrap;gap:2px;align-items:center;border:1px solid var(--panel-border);border-bottom:0;border-radius:0;padding:4px;background:linear-gradient(var(--chrome-start),var(--chrome))}.key-card{display:flex;flex:1 1 auto;flex-direction:column;align-items:stretch;gap:6px;min-height:0;border:0;border-top:1px solid var(--panel-border);border-bottom:1px solid var(--panel-border);border-radius:0;padding:6px;background:var(--window);box-shadow:none;overflow:hidden}.key-menu button{border-color:transparent;background:transparent;box-shadow:none}.key-menu button:hover,.key-menu button:focus-visible{border-color:var(--hover-border);background:var(--hover-bg);outline:none}.menu-group{position:relative}.submenu{position:absolute;top:calc(100% + 4px);left:0;z-index:20;display:grid;min-width:180px;border:1px solid var(--control-border);border-radius:3px;padding:3px;background:var(--panel);box-shadow:0 8px 20px var(--shadow-strong)}.submenu[hidden]{display:none}.submenu button{width:100%;text-align:left;white-space:nowrap}.node-context-menu{position:fixed;z-index:20;min-width:150px;border:1px solid var(--control-border);border-radius:3px;padding:3px;background:var(--panel);box-shadow:0 8px 20px var(--shadow-strong)}.node-context-menu[hidden],.node-context-menu button[hidden]{display:none}.node-context-menu button{display:block;width:100%;min-height:0;border:1px solid transparent;border-radius:2px;padding:4px 18px 4px 8px;color:var(--text);background:transparent;box-shadow:none;font:inherit;text-align:left;white-space:nowrap;cursor:pointer}.node-context-menu button:hover,.node-context-menu button:focus-visible{outline:none;border-color:var(--hover-border);background:var(--hover-bg)}.node-context-menu-group,.node-context-submenu-trigger{position:relative}.node-context-submenu-trigger:after{content:"";position:absolute;right:8px;top:50%;width:6px;height:6px;border-top:1px solid currentColor;border-right:1px solid currentColor;transform:translateY(-50%) rotate(45deg)}.node-context-submenu{position:absolute;top:-3px;left:100%;z-index:21;display:none;min-width:190px;border:1px solid var(--control-border);border-radius:3px;padding:3px;background:var(--panel);box-shadow:0 8px 20px var(--shadow-strong)}.node-context-menu-group:hover .node-context-submenu,.node-context-menu-group:focus-within .node-context-submenu{display:block}.tree{display:grid;align-content:start;gap:0;flex:1 1 auto;min-height:0;overflow:auto;border:0;border-radius:3px;padding:4px 6px;background:transparent;font-family:Consolas,Courier New,monospace;font-size:12px;line-height:1.35}.tree.empty{display:grid;grid-template-rows:minmax(0,1fr);align-content:stretch;place-items:center;color:var(--muted);font-family:Tahoma,MS UI Gothic,Yu Gothic UI,system-ui,sans-serif}.tree-node{position:relative;border:0;border-radius:0;background:transparent}.tree-node summary{position:relative;display:flex;flex-wrap:nowrap;align-items:flex-start;gap:4px;min-height:19px;padding:1px 4px 1px 0;list-style:none;cursor:default;white-space:nowrap;line-height:16px}.tree-node summary::-webkit-details-marker{display:none}.tree-node summary:after,.tree-node .tree-node:before{content:"";position:absolute}.tree-node summary:after{top:9px;left:8px;width:11px;border-top:1px dotted var(--tree-line);transform:translate(-100%)}.tree-node .tree-node{margin-left:19px}.tree-node .tree-node:before{top:-2px;bottom:8px;left:-11px;border-left:1px dotted var(--tree-line)}.tree>.tree-node>summary:after{display:none}.tree-leaf>summary .tree-toggle{border-color:transparent;background:transparent;pointer-events:none}.tree-toggle{display:inline-grid;place-items:center;position:relative;z-index:1;width:11px;height:11px;flex:0 0 auto;margin-top:2px;margin-right:2px;border:1px solid var(--toggle-border);background:var(--toggle-bg);color:var(--toggle-text);font:10px/1 Arial,sans-serif;line-height:1;-webkit-user-select:none;user-select:none}.tree-children{display:grid;gap:0;padding-left:0}.tree-row{position:relative;display:flex;align-items:flex-start;gap:4px;width:100%;min-height:19px;border:1px solid transparent;border-radius:2px;padding:1px 3px 1px 0;line-height:16px}.tree-node summary:hover,.tree-row:hover,.tree-row:focus-within{background:var(--accent-soft)}.tree-node summary.selected,.tree-row.selected{border-color:var(--selection-border);background:var(--selection)}.tree-item{display:flex;flex:1 1 auto;align-items:center;justify-content:flex-start;min-width:0;min-height:16px;border:0;border-radius:0;padding:0;color:var(--text);text-align:left;background:transparent;box-shadow:none;font:inherit}.tree-item:hover,.tree-item:focus-visible{outline:none}.tree-icon-button{display:inline-grid;flex:0 0 auto;place-items:center;width:15px;height:12px;min-height:0;margin-top:2px;margin-right:2px;border:0;border-radius:0;padding:0;background:transparent;box-shadow:none;cursor:context-menu}.tree-icon-button:hover,.tree-icon-button:focus-visible{outline:none}.tree-icon{position:relative;flex:0 0 auto;width:15px;height:12px}.tree-icon.folder:before{content:"";position:absolute;left:1px;top:1px;width:7px;height:4px;border:1px solid var(--folder-edge);border-bottom:0;background:var(--folder-highlight)}.tree-icon.folder:after{content:"";position:absolute;left:0;top:4px;width:14px;height:8px;border:1px solid var(--folder-edge);background:linear-gradient(var(--folder-start),var(--folder))}.tree-icon.leaf:before{content:"";position:absolute;left:2px;top:0;width:10px;height:12px;border:1px solid var(--leaf-edge);background:linear-gradient(135deg,transparent 0 18%,var(--leaf-fold) 19% 26%,var(--leaf) 27%)}.tree-tag{color:var(--text);font-weight:400}.key-label{border:1px solid transparent;padding:0 2px}.key-label:focus{border-color:var(--selection-border);background:var(--panel);outline:none}.notice{flex:0 0 auto;width:100%;min-height:0;margin:0;border:0;padding:0;color:var(--muted);font-size:12px;line-height:1.35}.notice.error{color:var(--danger)}.password-dialog{width:min(360px,calc(100% - 32px));border:1px solid var(--control-border);border-radius:4px;padding:0;color:var(--text);background:var(--panel);box-shadow:0 16px 32px var(--shadow-dialog)}.save-key-dialog{width:min(460px,calc(100% - 32px))}#selfSignedCertDialog{width:min(420px,calc(100% - 32px));max-height:calc(100dvh - 32px);overflow:auto}.password-dialog::backdrop{background:var(--dialog-overlay)}.about-dialog{width:min(360px,calc(100% - 32px));border:0;padding:0;color:var(--text);background:transparent}.about-dialog::backdrop{background:var(--dialog-overlay)}.about-panel{display:grid;gap:8px;border:1px solid var(--control-border);border-radius:4px;padding:14px;background:var(--panel);box-shadow:0 16px 32px var(--shadow-dialog)}.about-name{margin:0;font-weight:700;font-size:16px}.about-version,.about-detail{margin:0;color:var(--muted);font-size:12px;line-height:1.35}.password-panel{display:grid;gap:12px;padding:14px}.password-panel h2{margin:0;overflow-wrap:anywhere;font-size:15px}.password-field{display:grid;gap:4px}.password-field span{color:var(--muted);font-size:12px}.password-field input,.password-field select{width:100%;border:1px solid var(--control-border);border-radius:3px;padding:5px 7px;color:var(--text);background:var(--field-bg)}.dialog-actions{display:flex;justify-content:flex-end;gap:6px}.checkbox-list{display:grid;gap:4px;max-height:min(320px,48vh);overflow:auto;border:1px solid var(--subtle-border);border-radius:3px;padding:5px;background:var(--field-bg)}#selfSignedCertKeyUsageList{max-height:none;overflow:visible}.checkbox-list-item{display:grid;grid-template-columns:auto minmax(0,1fr);gap:8px;align-items:start;border:1px solid transparent;border-radius:3px;padding:6px}.checkbox-list-item:hover,.checkbox-list-item:focus-within{border-color:var(--hover-border);background:var(--hover-bg)}.checkbox-list-item input{margin-top:2px}.checkbox-list-item span{display:grid;gap:2px;min-width:0}.checkbox-list-item strong,.checkbox-list-item small{overflow-wrap:anywhere}.checkbox-list-item small,.checkbox-list-empty{color:var(--muted);font-size:12px}.checkbox-list-empty{margin:0;padding:8px}.dialog-error{border:1px solid var(--error-border);border-radius:3px;padding:7px;color:var(--danger);background:var(--error-bg);font-size:12px;line-height:1.35}.viewer-panel{display:flex;min-width:0;min-height:0;overflow:hidden}#viewerMount{flex:1 1 auto;min-width:0;min-height:0;height:100%}@media(max-width:820px){.shell{overflow:auto}.workspace{grid-template-columns:1fr;overflow:visible}.pane-resizer,.api-log-resizer{display:none}#viewerMount{height:min(620px,70dvh);min-height:420px}.api-log-entry{grid-template-columns:174px minmax(0,1fr)}.api-log-detail{grid-column:1 / -1}}
@@ -0,0 +1,73 @@
1
+ import './styles.css';
2
+ import { type CsrMaterial, type PvkGadgetsCoreApi, type PvkGadgetsKeyMaterial, type SubjectDnMaterial } from './core';
3
+ import type { PkiStudioApi, PkiStudioCoreApi, PkiStudioOidResolverApi } from './pkistudio-types';
4
+ type SaveFilePickerOptions = {
5
+ suggestedName?: string;
6
+ types?: Array<{
7
+ description: string;
8
+ accept: Record<string, string[]>;
9
+ }>;
10
+ };
11
+ type SaveFileHandle = {
12
+ createWritable: () => Promise<{
13
+ write: (data: Blob) => Promise<void>;
14
+ close: () => Promise<void>;
15
+ }>;
16
+ name?: string;
17
+ };
18
+ declare global {
19
+ interface Window {
20
+ PkiStudio?: PkiStudioApi;
21
+ PkiStudioCore?: PkiStudioCoreApi;
22
+ PvkGadgetsCore?: PvkGadgetsCoreApi;
23
+ showSaveFilePicker?: (options?: SaveFilePickerOptions) => Promise<SaveFileHandle>;
24
+ }
25
+ }
26
+ type KeyMaterial = Omit<PvkGadgetsKeyMaterial, 'privateKeyDer' | 'publicKeyDer'> & {
27
+ privateKeyDer?: Uint8Array;
28
+ publicKeyDer?: Uint8Array;
29
+ csrs?: CsrMaterial[];
30
+ subjectDns?: SubjectDnMaterial[];
31
+ };
32
+ type KeyNodeKind = 'keypair' | 'private' | 'public' | 'certificate' | 'csr' | 'subjectdn';
33
+ export type AppTheme = 'light' | 'dark';
34
+ type SelectedKeyNode = {
35
+ keyId: string;
36
+ kind: KeyNodeKind;
37
+ csrId?: string;
38
+ subjectDnId?: string;
39
+ };
40
+ export type PrivateKeyGadgetsSaveFileRequest = {
41
+ bytes: Uint8Array;
42
+ suggestedName: string;
43
+ types: Array<{
44
+ description: string;
45
+ accept: Record<string, string[]>;
46
+ }>;
47
+ };
48
+ export type PrivateKeyGadgetsHost = {
49
+ confirm?: (message: string) => boolean | Promise<boolean>;
50
+ saveFile?: (request: PrivateKeyGadgetsSaveFileRequest) => Promise<{
51
+ filename?: string;
52
+ } | void>;
53
+ openDerViewer?: (request: {
54
+ title: string;
55
+ bytes: Uint8Array;
56
+ }) => void | Promise<void>;
57
+ };
58
+ export type InitPrivateKeyGadgetsOptions = {
59
+ mount?: string | Element;
60
+ theme?: AppTheme;
61
+ host?: PrivateKeyGadgetsHost;
62
+ viewer?: {
63
+ oidResolver?: PkiStudioOidResolverApi | ((oid: string) => string);
64
+ newWindowUrl?: string;
65
+ };
66
+ };
67
+ export type PrivateKeyGadgetsAppInstance = {
68
+ readonly keys: readonly KeyMaterial[];
69
+ readonly selectedNode: SelectedKeyNode | null;
70
+ close: () => void;
71
+ };
72
+ export declare function initPrivateKeyGadgets(options?: InitPrivateKeyGadgetsOptions): PrivateKeyGadgetsAppInstance;
73
+ export {};
@@ -0,0 +1,97 @@
1
+ import { RelativeDistinguishedNames } from 'pkijs';
2
+ import { readPkcs12Keys, writePkcs12Keys, type Pkcs12KeyMaterial } from './pkcs12';
3
+ export type CsrMaterial = {
4
+ id: string;
5
+ label: string;
6
+ subjectDn: string;
7
+ hashAlgorithm: string;
8
+ bytes: Uint8Array;
9
+ };
10
+ export type SubjectDnMaterial = {
11
+ id: string;
12
+ label: string;
13
+ subjectDn: string;
14
+ bytes: Uint8Array;
15
+ };
16
+ export type PvkGadgetsKeyMaterial = Omit<Pkcs12KeyMaterial, 'privateKeyDer' | 'publicKeyDer'> & {
17
+ privateKeyDer?: Uint8Array;
18
+ publicKeyDer?: Uint8Array;
19
+ csrs?: CsrMaterial[];
20
+ subjectDns?: SubjectDnMaterial[];
21
+ };
22
+ export type RecognizedKeyInfo = {
23
+ family: 'RSA' | 'EC' | 'Ed25519' | 'Ed448' | 'X25519' | 'X448' | 'Unknown';
24
+ label: string;
25
+ canSign: boolean;
26
+ canDerive: boolean;
27
+ namedCurve?: string;
28
+ };
29
+ export type KeyAlgorithmCandidate = {
30
+ id: string;
31
+ canonicalId: string;
32
+ canonicalLabel: string;
33
+ algorithm: AlgorithmIdentifier | RsaHashedKeyGenParams | EcKeyGenParams;
34
+ usages: KeyUsage[];
35
+ };
36
+ export type CertificateKeyUsage = {
37
+ id: string;
38
+ label: string;
39
+ bit: number;
40
+ defaultChecked?: boolean;
41
+ };
42
+ export type GenerateKeyPairOptions = {
43
+ createId?: () => string;
44
+ label?: string;
45
+ };
46
+ export type CreateCsrOptions = {
47
+ privateKeyDer: Uint8Array;
48
+ publicKeyDer: Uint8Array;
49
+ subjectDn: string;
50
+ subjectBytes: Uint8Array;
51
+ hashAlgorithm: string;
52
+ };
53
+ export type CsrResult = {
54
+ subjectDn: string;
55
+ hashAlgorithm: string;
56
+ bytes: Uint8Array;
57
+ };
58
+ export type CreateSelfSignedCertificateOptions = {
59
+ privateKeyDer: Uint8Array;
60
+ publicKeyDer: Uint8Array;
61
+ subjectDn: string;
62
+ subjectBytes: Uint8Array;
63
+ hashAlgorithm: string;
64
+ validityDays: number;
65
+ keyUsages: string[];
66
+ };
67
+ export type CertificateResult = {
68
+ subjectDn: string;
69
+ hashAlgorithm: string;
70
+ validityDays: number;
71
+ bytes: Uint8Array;
72
+ };
73
+ export type PvkGadgetsCoreApi = {
74
+ version: string;
75
+ keyAlgorithms: KeyAlgorithmCandidate[];
76
+ certificateKeyUsages: CertificateKeyUsage[];
77
+ getSupportedKeyAlgorithms: () => Promise<KeyAlgorithmCandidate[]>;
78
+ generateKeyPair: (selection: string, options?: GenerateKeyPairOptions) => Promise<PvkGadgetsKeyMaterial>;
79
+ recognizeKeyMaterial: (material: Pick<PvkGadgetsKeyMaterial, 'privateKeyDer' | 'publicKeyDer'>) => RecognizedKeyInfo;
80
+ certificateMatchesKey: (material: Pick<PvkGadgetsKeyMaterial, 'privateKeyDer' | 'publicKeyDer'>, certificatePublicKeyDer: Uint8Array) => Promise<boolean>;
81
+ verifyPrivateKeyMatchesPublicKey: (privateKeyDer: Uint8Array, publicKeyDer: Uint8Array, info?: RecognizedKeyInfo) => Promise<boolean>;
82
+ createSubjectDn: (subjectDn: string) => Uint8Array;
83
+ getCertificateSubjectDn: (certificateDer: Uint8Array) => Uint8Array;
84
+ parseSubjectDn: (bytes: Uint8Array) => RelativeDistinguishedNames;
85
+ subjectDnToString: (bytes: Uint8Array) => string;
86
+ createCsr: (options: CreateCsrOptions) => Promise<CsrResult>;
87
+ createSelfSignedCertificate: (options: CreateSelfSignedCertificateOptions) => Promise<CertificateResult>;
88
+ readPkcs12: typeof readPkcs12Keys;
89
+ writePkcs12: typeof writePkcs12Keys;
90
+ derToPem: (label: string, bytes: Uint8Array) => string;
91
+ pemToDer: (text: string, expectedLabel?: string) => Uint8Array;
92
+ bytesEqual: (left: Uint8Array, right: Uint8Array) => boolean;
93
+ toArrayBuffer: (bytes: Uint8Array) => ArrayBuffer;
94
+ };
95
+ export declare const KEY_ALGORITHM_CANDIDATES: KeyAlgorithmCandidate[];
96
+ export declare const CERTIFICATE_KEY_USAGES: CertificateKeyUsage[];
97
+ export declare const PvkGadgetsCore: PvkGadgetsCoreApi;
@@ -0,0 +1,18 @@
1
+ export type Pkcs12KeyMaterial = {
2
+ id: string;
3
+ label?: string;
4
+ privateKeyDer: Uint8Array;
5
+ publicKeyDer?: Uint8Array;
6
+ certificateDer?: Uint8Array;
7
+ sourceName?: string;
8
+ };
9
+ export type Pkcs12ExportKeyMaterial = {
10
+ label?: string;
11
+ privateKeyDer?: Uint8Array;
12
+ certificateDer?: Uint8Array;
13
+ };
14
+ export declare function readPkcs12Keys(bytes: Uint8Array, password: string, options?: {
15
+ sourceName?: string;
16
+ createId?: () => string;
17
+ }): Promise<Pkcs12KeyMaterial[]>;
18
+ export declare function writePkcs12Keys(keys: Pkcs12ExportKeyMaterial[], password: string): Promise<Uint8Array>;
@@ -0,0 +1,47 @@
1
+ export type PkiStudioInstance = {
2
+ close?: () => void;
3
+ getNodeBytes?: (nodeId: string) => Uint8Array;
4
+ loadBytes: (bytes: Uint8Array, notice?: string) => void;
5
+ root?: DocumentFragment | Element;
6
+ };
7
+ export type PkiStudioCoreNode = {
8
+ id?: string;
9
+ tagClass: number;
10
+ tagNumber: number;
11
+ constructed: boolean;
12
+ encapsulated?: boolean;
13
+ valueStart: number;
14
+ valueEnd: number;
15
+ end: number;
16
+ children: PkiStudioCoreNode[];
17
+ };
18
+ export type PkiStudioCoreApi = {
19
+ VERSION?: string;
20
+ base64ToBytes: (base64: string) => Uint8Array;
21
+ bytesToBase64: (bytes: Uint8Array) => string;
22
+ decodeOid: (bytes: Uint8Array) => string;
23
+ decodePem: (text: string) => Uint8Array;
24
+ encodeNodes: (nodes: PkiStudioCoreNode[]) => Uint8Array;
25
+ hexToBytes: (text: string, options?: {
26
+ allowEmpty?: boolean;
27
+ }) => Uint8Array;
28
+ parseElements: (bytes: Uint8Array, offset?: number, end?: number, depth?: number) => PkiStudioCoreNode[];
29
+ };
30
+ export type PkiStudioOidResolverApi = {
31
+ names: Record<string, string>;
32
+ resolve: (oid: string) => string;
33
+ create: (extraNames?: Record<string, string>) => PkiStudioOidResolverApi;
34
+ };
35
+ export type PkiStudioApi = {
36
+ core?: PkiStudioCoreApi | null;
37
+ init: (options: {
38
+ mount: string | Element;
39
+ oidNames?: Record<string, string>;
40
+ oidResolver?: PkiStudioOidResolverApi | ((oid: string) => string);
41
+ oidUrl?: string;
42
+ newWindowUrl?: string;
43
+ shadowRoot?: boolean;
44
+ fullscreen?: boolean;
45
+ }) => PkiStudioInstance;
46
+ version?: string;
47
+ };
@@ -0,0 +1,4 @@
1
+ import type { PkiStudioApi, PkiStudioCoreApi, PkiStudioOidResolverApi } from './pkistudio-types';
2
+ export declare const PkiStudioCore: PkiStudioCoreApi;
3
+ export declare const PkiStudioOidResolver: PkiStudioOidResolverApi;
4
+ export declare const PkiStudio: PkiStudioApi;
@@ -0,0 +1,15 @@
1
+ <!doctype html>
2
+ <html lang="ja">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <link rel="icon" href="./favicon.ico" sizes="any" />
7
+ <title>PkiStudioJS Viewer</title>
8
+ <script type="module" crossorigin src="./viewer.js"></script>
9
+ <link rel="modulepreload" crossorigin href="./chunks/modulepreload-polyfill-B5Qt9EMX.js">
10
+ <link rel="modulepreload" crossorigin href="./chunks/pkistudio--jw2SR0V.js">
11
+ </head>
12
+ <body>
13
+ <div id="pkistudioViewer"></div>
14
+ </body>
15
+ </html>
package/dist/viewer.js ADDED
@@ -0,0 +1 @@
1
+ import"./chunks/modulepreload-polyfill-B5Qt9EMX.js";import{PkiStudio as i,PkiStudioOidResolver as e}from"./chunks/pkistudio--jw2SR0V.js";window.addEventListener("DOMContentLoaded",()=>{i.init({mount:"#pkistudioViewer",oidResolver:e,fullscreen:!0})});
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "@pkistudio/pvkgadgets",
3
+ "version": "0.3.0",
4
+ "description": "Browser PKI key material tools and reusable Private Key Gadgets API.",
5
+ "type": "module",
6
+ "main": "./dist/core.js",
7
+ "module": "./dist/core.js",
8
+ "types": "./dist/types/core.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/types/core.d.ts",
12
+ "import": "./dist/core.js"
13
+ },
14
+ "./core": {
15
+ "types": "./dist/types/core.d.ts",
16
+ "import": "./dist/core.js"
17
+ },
18
+ "./pkcs12": {
19
+ "types": "./dist/types/pkcs12.d.ts",
20
+ "import": "./dist/pkcs12.js"
21
+ },
22
+ "./app": {
23
+ "types": "./dist/types/app.d.ts",
24
+ "import": "./dist/app.js"
25
+ },
26
+ "./styles.css": "./dist/styles.css"
27
+ },
28
+ "files": [
29
+ "dist",
30
+ "README.md",
31
+ "LICENSE"
32
+ ],
33
+ "sideEffects": [
34
+ "*.css"
35
+ ],
36
+ "scripts": {
37
+ "dev": "vite --host 0.0.0.0",
38
+ "build": "tsc --noEmit && vite build && tsc -p tsconfig.types.json",
39
+ "preview": "vite preview --host 0.0.0.0",
40
+ "check": "tsc --noEmit",
41
+ "pack:dry-run": "npm pack --dry-run"
42
+ },
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "https://github.com/pkistudio/pvkgadgets"
46
+ },
47
+ "keywords": [
48
+ "pki",
49
+ "pkcs12",
50
+ "webcrypto",
51
+ "certificate",
52
+ "csr"
53
+ ],
54
+ "license": "MIT",
55
+ "devDependencies": {
56
+ "@types/node": "^24.0.0",
57
+ "typescript": "^5.9.0",
58
+ "vite": "^7.0.0"
59
+ },
60
+ "dependencies": {
61
+ "asn1js": "^3.0.10",
62
+ "pkijs": "^3.4.0",
63
+ "pkistudiojs": "^0.4.1",
64
+ "pvtsutils": "^1.3.6"
65
+ }
66
+ }