@visulima/email
Version:
A comprehensive email library with multi-provider support, crypto utilities, and template engines
9 lines (8 loc) • 5.31 kB
JavaScript
var L=Object.defineProperty;var g=(n,e)=>L(n,"name",{value:e,configurable:!0});import{createRequire as V}from"node:module";import{B as b}from"./readFile-BlZxbhCU-C8bCdiA2.js";import{fromBER as B,ObjectIdentifier as Y,OctetString as E,UTCTime as Z}from"asn1js";import{Certificate as N,SignedData as ee,EncapsulatedContentInfo as te,id_ContentType_Data as D,SignerInfo as re,AlgorithmIdentifier as P,IssuerAndSerialNumber as ne,id_sha256 as se,SignedAndUnsignedAttributes as oe,Attribute as A,ContentInfo as ie,id_ContentType_SignedData as ae}from"pkijs";import ce from"./generateBoundary-CZ8kJuY6.js";const z=V(import.meta.url),u=typeof globalThis<"u"&&typeof globalThis.process<"u"?globalThis.process:process,J=g(n=>{if(typeof u<"u"&&u.versions&&u.versions.node){const[e,t]=u.versions.node.split(".").map(Number);if(e>22||e===22&&t>=3||e===20&&t>=16)return u.getBuiltinModule(n)}return z(n)},"__cjs_getBuiltinModule"),{createPrivateKey:x,createHash:Q,createSign:W,randomBytes:X}=J("node:crypto");var le=Object.defineProperty,y=g((n,e)=>le(n,"name",{value:e,configurable:!0}),"u");const pe="1.2.840.113549.1.9.3",ue="1.2.840.113549.1.9.4",fe="1.2.840.113549.1.9.5",me="1.2.840.113549.1.1.1",de={v1:1},he={v1:1},f=globalThis.Buffer!==void 0,M=y(n=>{const e=n.replaceAll(/-----BEGIN[^-]+-----/g,"").replaceAll(/-----END[^-]+-----/g,"").replaceAll(/\s/g,"");if(f)return Buffer.from(e,"base64");const t=atob(e),o=new Uint8Array(t.length);for(let r=0;r<t.length;r+=1)o[r]=t.codePointAt(r);return o},"pemToDer"),ge=y((n,e)=>{let t;if(f)t=Buffer.from(n).toString("base64");else{const r=new Uint8Array(n);let s="";const a=8192;for(let i=0;i<r.length;i+=a){const d=r.subarray(i,Math.min(i+a,r.length));s+=String.fromCharCode.apply(void 0,d)}t=btoa(s)}const o=t.match(/.{1,64}/g)||[];return`-----BEGIN ${e}-----
${o.join(`
`)}
-----END ${e}-----
`},"derToPem");class m{static{g(this,"SmimeSigner")}static{y(this,"SmimeSigner")}static formatAddress(e){return e.name?`"${e.name.replaceAll("\\","\\\\").replaceAll('"',String.raw`\"`)}" <${e.email}>`:e.email}options;constructor(e){this.options=e}async sign(e){const t=await b(this.options.certificate,{encoding:"utf8"}),o=await b(this.options.privateKey,{encoding:"utf8"}),r=M(t),s=B(r);if(s.offset===-1)throw new Error("Failed to parse certificate: Invalid ASN.1 structure");const a=new N({schema:s.result});let i;try{i=this.options.passphrase?x({key:o,passphrase:this.options.passphrase}):x(o)}catch(c){throw new Error(`Failed to parse private key: ${c.message}`)}const d=[];if(this.options.intermediateCerts){const c=this.options.intermediateCerts.map(async j=>{const q=await b(j,{encoding:"utf8"}),G=M(q),I=B(G);if(I.offset===-1)throw new Error(`Failed to parse intermediate certificate ${j}: Invalid ASN.1 structure`);return new N({schema:I.result})});d.push(...await Promise.all(c))}const v=this.buildMessage(e),$=new TextEncoder().encode(v),h=new ee({version:de.v1});h.encapContentInfo=new te({eContentType:D});const w=new re({digestAlgorithm:new P({algorithmId:se}),sid:new ne({issuer:a.issuer,serialNumber:a.serialNumber}),signatureAlgorithm:new P({algorithmId:me}),version:he.v1}),C=Q("sha256");C.update(f?Buffer.from($):$);const R=C.digest(),U=new Uint8Array(R),T=new oe({attributes:[new A({type:pe,values:[new Y({value:D})]}),new A({type:ue,values:[new E({valueHex:U.buffer.slice(0)})]}),new A({type:fe,values:[new Z({valueDate:new Date})]})]});w.signedAttrs=T;const S=T.toSchema().toBER(!1),k=f?Buffer.from(S):new Uint8Array(S),_=W("RSA-SHA256");_.update(k);const l=_.sign(i),O=f?l.buffer.slice(l.byteOffset,l.byteOffset+l.byteLength):l.buffer;w.signature=new E({valueHex:O}),h.signerInfos.push(w),h.certificates=[a,...d];const F=new ie({content:h.toSchema(),contentType:ae}).toSchema().toBER(!1),H=ge(F,"PKCS7"),p=`----_=_NextPart_${Date.now()}_${X(8).toString("hex")}`,K=[`Content-Type: multipart/signed; protocol="application/pkcs7-signature"; micalg=sha-256; boundary="${p}"`,"",`--${p}`,v,`--${p}`,"Content-Type: application/pkcs7-signature; name=smime.p7s","Content-Transfer-Encoding: base64","Content-Disposition: attachment; filename=smime.p7s","",H.split(`
`).filter(c=>c.trim()&&!c.includes("-----")).join(""),`--${p}--`].join(`\r
`);return{...e,headers:{...e.headers,"Content-Type":`multipart/signed; protocol="application/pkcs7-signature"; micalg=sha-256; boundary="${p}"`},html:void 0,text:K}}buildMessage(e){const t=[`From: ${m.formatAddress(e.from)}`,`To: ${this.formatAddresses(e.to)}`];if(e.cc&&t.push(`Cc: ${this.formatAddresses(e.cc)}`),e.replyTo&&t.push(`Reply-To: ${m.formatAddress(e.replyTo)}`),t.push(`Subject: ${e.subject}`,"MIME-Version: 1.0"),e.headers)for(const[a,i]of Object.entries(e.headers))t.push(`${a}: ${i}`);const o=!!e.text,r=!!e.html;let s;return o&&r?(s=ce(),t.push(`Content-Type: multipart/alternative; boundary="${s}"`)):r?t.push("Content-Type: text/html; charset=utf-8"):t.push("Content-Type: text/plain; charset=utf-8"),t.push(""),o&&r&&s?t.push(`--${s}`,"Content-Type: text/plain; charset=utf-8","",e.text,"",`--${s}`,"Content-Type: text/html; charset=utf-8","",e.html,"",`--${s}--`):o?t.push(e.text):r&&t.push(e.html),t.join(`\r
`)}formatAddresses(e){return(Array.isArray(e)?e:[e]).map(t=>m.formatAddress(t)).join(", ")}}const Ce=y(n=>new m(n),"createSmimeSigner");export{m as SmimeSigner,Ce as createSmimeSigner};