UNPKG

@visulima/email

Version:

A comprehensive email library with multi-provider support, crypto utilities, and template engines

7 lines (6 loc) 5.14 kB
var K=Object.defineProperty;var g=(s,e)=>K(s,"name",{value:e,configurable:!0});import{createRequire as U}from"node:module";import{B as S}from"./readFile-BlZxbhCU-C8bCdiA2.js";import{fromBER as $,OctetString as T}from"asn1js";import{Certificate as j,EnvelopedData as z,EncryptedContentInfo as J,id_ContentType_Data as Q,RecipientInfo as W,KeyTransRecipientInfo as X,IssuerAndSerialNumber as Y,AlgorithmIdentifier as x,ContentInfo as Z,id_ContentType_EnvelopedData as ee}from"pkijs";const q=U(import.meta.url),h=typeof globalThis<"u"&&typeof globalThis.process<"u"?globalThis.process:process,H=g(s=>{if(typeof h<"u"&&h.versions&&h.versions.node){const[e,t]=h.versions.node.split(".").map(Number);if(e>22||e===22&&t>=3||e===20&&t>=16)return h.getBuiltinModule(s)}return q(s)},"__cjs_getBuiltinModule"),{randomBytes:I,createCipheriv:L,createPublicKey:G,publicEncrypt:V}=H("node:crypto");var te=Object.defineProperty,y=g((s,e)=>te(s,"name",{value:e,configurable:!0}),"l");const w=globalThis.Buffer!==void 0,N=y(s=>{const e=s.replaceAll(/-----BEGIN[^-]+-----/g,"").replaceAll(/-----END[^-]+-----/g,"").replaceAll(/\s/g,"");if(w)return Buffer.from(e,"base64");const t=atob(e),n=new Uint8Array(t.length);for(let r=0;r<t.length;r+=1)n[r]=t.charCodeAt(r);return n},"pemToDer"),R=y((s,e)=>{let t;if(w)t=Buffer.from(s).toString("base64");else{const r=new Uint8Array(s);let u="";const o=8192;for(let i=0;i<r.length;i+=o){const m=r.subarray(i,Math.min(i+o,r.length));u+=String.fromCharCode.apply(void 0,m)}t=btoa(u)}const n=t.match(/.{1,64}/g)||[];return`-----BEGIN ${e}----- ${n.join(` `)} -----END ${e}----- `},"derToPem");class a{static{g(this,"SmimeEncrypter")}static{y(this,"SmimeEncrypter")}static collectRecipients(e){const t=[],n=y(r=>{if(!r)return;const u=Array.isArray(r)?r:[r];for(const o of u){const i=typeof o=="string"?o:o.email;i&&t.push(i)}},"extractEmails");return n(e.to),n(e.cc),n(e.bcc),[...new Set(t)]}static formatAddress(e){return typeof e=="string"?e:e.name?`"${e.name}" <${e.email}>`:e.email}static formatAddresses(e){return(Array.isArray(e)?e:[e]).map(t=>a.formatAddress(t)).join(", ")}options;constructor(e){this.options=e}async encrypt(e){const t=a.collectRecipients(e),n=[];if(typeof this.options.certificates=="string"){const c=await S(this.options.certificates,{encoding:"utf8"}),f=N(c),l=$(f);if(l.offset===-1)throw new Error("Failed to parse certificate: Invalid ASN.1 structure");n.push(new j({schema:l.result}))}else{const c=t.map(async f=>{const l=this.options.certificates[f];if(!l)throw new Error(`No certificate found for recipient: ${f}`);const E=await S(l,{encoding:"utf8"}),v=N(E),p=$(v);if(p.offset===-1)throw new Error(`Failed to parse certificate for ${f}: Invalid ASN.1 structure`);return new j({schema:p.result})});n.push(...await Promise.all(c))}const r=await this.buildMessage(e),u=new TextEncoder().encode(r),o=new z({version:0});o.encryptedContentInfo=new J({contentType:Q});const i=(this.options.algorithm||"aes-256-cbc").toLowerCase();if(i==="3des"||i==="des-ede3-cbc")throw new Error("3DES/DES-EDE3-CBC is deprecated and insecure (Sweet32 vulnerability). Please use AES-256-CBC, AES-192-CBC, or AES-128-CBC instead.");let m,d;switch(i){case"aes128":case"aes-128-cbc":{m="2.16.840.1.101.3.4.1.2",d=16;break}case"aes192":case"aes-192-cbc":{m="2.16.840.1.101.3.4.1.22",d=24;break}default:{m="2.16.840.1.101.3.4.1.42",d=32;break}}const A=I(d),D=w?A:new Uint8Array(A),C=I(16),P=w?C:new Uint8Array(C),B=L(`aes-${d*8}-cbc`,A,C),_=Buffer.from(u),k=[B.update(_),B.final()],b=Buffer.concat(k);o.encryptedContentInfo.encryptedContent=new T({valueHex:b.buffer.slice(b.byteOffset,b.byteOffset+b.byteLength)});const M=await Promise.all(n.map(async c=>{const f=c.toSchema().toBER(!1),l=R(f,"CERTIFICATE"),E=G(l),v=Buffer.from(D),p=V({key:E,padding:1},v);return new W({value:new X({encryptedKey:new T({valueHex:p.buffer.slice(p.byteOffset,p.byteOffset+p.byteLength)}),keyEncryptionAlgorithm:new x({algorithmId:"1.2.840.113549.1.1.1"}),rid:new Y({issuer:c.issuer,serialNumber:c.serialNumber}),version:0}),variant:0})}));o.recipientInfos.push(...M),o.encryptedContentInfo.contentEncryptionAlgorithm=new x({algorithmId:m,algorithmParams:new T({valueHex:P.buffer})});const O=new Z({content:o.toSchema(),contentType:ee}).toSchema().toBER(!1),F=R(O,"PKCS7");return{...e,headers:{...e.headers,"Content-Disposition":"attachment; filename=smime.p7m","Content-Transfer-Encoding":"base64","Content-Type":"application/pkcs7-mime; smime-type=enveloped-data; name=smime.p7m"},html:void 0,text:F}}async buildMessage(e){const t=[`From: ${a.formatAddress(e.from)}`,`To: ${a.formatAddresses(e.to)}`,...e.cc?[`Cc: ${a.formatAddresses(e.cc)}`]:[]];if(e.replyTo&&t.push(`Reply-To: ${a.formatAddress(e.replyTo)}`),t.push(`Subject: ${e.subject}`,"MIME-Version: 1.0"),e.headers)for(const[n,r]of Object.entries(e.headers))t.push(`${n}: ${r}`);return e.html?t.push("Content-Type: text/html; charset=utf-8"):e.text&&t.push("Content-Type: text/plain; charset=utf-8"),t.push(""),e.html?t.push(e.html):e.text&&t.push(e.text),t.join(`\r `)}}const ae=y(s=>new a(s),"createSmimeEncrypter");export{a as SmimeEncrypter,ae as createSmimeEncrypter};