@gjsify/tls 0.4.14 → 0.4.16
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/lib/esm/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import e from"@girs/gio-2.0";import
|
|
2
|
-
`);if(typeof e==`string`)return e;if(e&&typeof e.toString==`function`)try{return e.toString(`utf-8`)}catch{return new TextDecoder(`utf-8`).decode(e)}return String(e)}function splitPemBlocks(e){let t=[],n=/-----BEGIN [^-]+-----[\s\S]*?-----END [^-]+-----/g,r;for(;(r=n.exec(e))!==null;)t.push(r[0]);return t}function buildGioCertificate(t,n){let r=pemToString(t),i=n?pemToString(n):``,a=i?`${r}\n${i}`:r;return e.TlsCertificate.new_from_pem(a,a.length)}function buildCaCertificates(t){let n=[];if(Array.isArray(t))for(let e of t)n.push(...splitPemBlocks(pemToString(e)));else n.push(...splitPemBlocks(pemToString(t)));let r=[];for(let t of n)try{r.push(e.TlsCertificate.new_from_pem(t,t.length))}catch{}return r}function parseDistinguishedName(e){if(!e)return{};let t={};for(let n of e.split(/,(?![^=]*=)/)){let e=n.indexOf(`=`);if(e<0)continue;let r=n.slice(0,e).trim(),i=n.slice(e+1).trim(),a=t[r];a===void 0?t[r]=i:Array.isArray(a)?a.push(i):t[r]=[a,i]}return t}function formatCertDate(e){if(!e)return``;try{return e.format(`%b %d %H:%M:%S %Y GMT`)??``}catch{return``}}function formatAltNames(e){let t=[];try{let n=e.get_dns_names();if(n)for(let e of n){let n=e.get_data();n&&t.push(`DNS:${new TextDecoder(`utf-8`).decode(n)}`)}}catch{}try{let n=e.get_ip_addresses();if(n)for(let e of n)t.push(`IP Address:${e.to_string()}`)}catch{}return t.join(`, `)}function fingerprintFromBytes(e,n){try{let r=new t.Checksum(n);r.update(e);let i=r.get_string();if(!i)return``;let a=[];for(let e=0;e<i.length;e+=2)a.push(i.slice(e,e+2).toUpperCase());return a.join(`:`)}catch{return``}}function pemToDer(e){let t=/-----BEGIN CERTIFICATE-----([\s\S]*?)-----END CERTIFICATE-----/.exec(e);if(!t)return new Uint8Array;let n=t[1].replace(/[\s\r\n]+/g,``);try{let e=globalThis.atob;if(!e)return new Uint8Array;let t=e(n),r=new Uint8Array(t.length);for(let e=0;e<t.length;e++)r[e]=t.charCodeAt(e);return r}catch{return new Uint8Array}}function tlsCertToPeerCert(e,n){let r={};try{r.subject=parseDistinguishedName(e.get_subject_name())}catch{}try{r.issuer=parseDistinguishedName(e.get_issuer_name())}catch{}r.subjectaltname=formatAltNames(e);try{r.valid_from=formatCertDate(e.get_not_valid_before()),r.valid_to=formatCertDate(e.get_not_valid_after())}catch{}try{let n=e,i=n.certificate_pem??n.certificatePem;if(i){let e=pemToDer(i);r.raw=e,r.fingerprint=fingerprintFromBytes(e,t.ChecksumType.SHA1),r.fingerprint256=fingerprintFromBytes(e,t.ChecksumType.SHA256)}}catch{}if(n)try{let t=e.get_issuer();t&&!t.is_same(e)?r.issuerCertificate=tlsCertToPeerCert(t,!0):t&&(r.issuerCertificate=r)}catch{}return r}function unfqdn(e){return e.endsWith(`.`)?e.slice(0,-1):e}function splitHost(e){return unfqdn(e).toLowerCase().split(`.`)}function isPrintableAscii(e){for(let t=0;t<e.length;t++){let n=e.charCodeAt(t);if(n<33||n>126)return!1}return!0}function checkHostMatch(e,t){if(!t)return!1;let n=splitHost(t);if(e.length!==n.length||n.includes(``)||!n.every(isPrintableAscii))return!1;for(let t=e.length-1;t>0;t--)if(e[t]!==n[t])return!1;let r=e[0],i=n[0],a=i.split(`*`,3);if(a.length===1||i.includes(`xn--`))return r===i;if(a.length>2||n.length<=2)return!1;let o=a[0],s=a[1];return!(o.length+s.length>r.length||!r.startsWith(o)||!r.endsWith(s))}function checkServerIdentity(e,t){let n=t.subject,r=t.subjectaltname,i=[],a=[];if(e=String(e),r){let e=r.split(`, `);for(let t of e)t.startsWith(`DNS:`)?i.push(t.slice(4)):t.startsWith(`IP Address:`)&&a.push(t.slice(11).trim())}let o=!1,s=`Unknown reason`;e=unfqdn(e);let c=/^(\d{1,3}\.){3}\d{1,3}$/.test(e),l=e.includes(`:`);if(c||l)o=a.some(t=>t.toLowerCase()===e.toLowerCase()),o||(s=`IP: ${e} is not in the cert's list: ${a.join(`, `)}`);else if(i.length>0||n?.CN){let t=splitHost(e);if(i.length>0)o=i.some(e=>checkHostMatch(t,e.trim())),o||(s=`Host: ${e}. is not in the cert's altnames: ${r}`);else{let r=n?.CN;Array.isArray(r)?o=r.some(e=>checkHostMatch(t,e)):r&&(o=checkHostMatch(t,r)),o||(s=`Host: ${e}. is not cert's CN: ${r}`)}}else s=`Cert does not contain a DNS name`;if(!o){let n=Error(s);return n.reason=s,n.host=e,n.cert=t,n.code=`ERR_TLS_CERT_ALTNAME_INVALID`,n}}function createSecureContext(e){let t=e??{},n=null;if(t.cert)try{n=buildGioCertificate(t.cert,t.key)}catch{n=null}let r=t.ca?buildCaCertificates(t.ca):[],i={certificate:n,caCertificates:r,options:t};return i.context=i,i}var TLSSocket=class extends r{encrypted=!0;authorized=!1;authorizationError;alpnProtocol=!1;servername;_tlsConnection=null;_secureContext=null;constructor(e,t){super()}_setupTlsStreams(e){this._tlsConnection=e;let t=this;t._inputStream=e.get_input_stream(),t._outputStream=e.get_output_stream(),t._connection=e}getPeerCertificate(e=!1){if(!this._tlsConnection)return{};try{let t=this._tlsConnection.get_peer_certificate();return t?tlsCertToPeerCert(t,e):{}}catch{return{}}}getProtocol(){if(!this._tlsConnection)return null;try{switch(this._tlsConnection.get_protocol_version()){case e.TlsProtocolVersion.TLS_1_0:return`TLSv1`;case e.TlsProtocolVersion.TLS_1_1:return`TLSv1.1`;case e.TlsProtocolVersion.TLS_1_2:return`TLSv1.2`;case e.TlsProtocolVersion.TLS_1_3:return`TLSv1.3`;default:return null}}catch{return null}}getCipher(){if(!this._tlsConnection)return null;try{return{name:this._tlsConnection.get_ciphersuite_name()||`unknown`,version:this.getProtocol()||`unknown`}}catch{return null}}getAlpnProtocol(){if(!this._tlsConnection)return!1;try{return this._tlsConnection.get_negotiated_protocol()||!1}catch{return!1}}};function connect(n,r){let i=new TLSSocket(void 0,n);r&&i.once(`secureConnect`,r);let a=n.port||443,o=n.host||`localhost`,s=n.servername||o,c=n.rejectUnauthorized!==!1,l=n.secureContext??createSecureContext(n);i._secureContext=l,i.servername=s;let u=n.checkServerIdentity;return i.once(`connect`,()=>{let r=i._connection;if(!r){i.destroy(Error(`No underlying connection for TLS upgrade`));return}try{let o=e.NetworkAddress.new(s,a),d=e.TlsClientConnection.new(r,o);if(d.set_server_identity(o),l.certificate)try{d.set_certificate(l.certificate)}catch(e){console.warn(`[tls] failed to set client certificate:`,e)}if(n.ALPNProtocols&&n.ALPNProtocols.length>0)try{d.set_advertised_protocols(n.ALPNProtocols)}catch{}d.connect(`accept-certificate`,(t,n,r)=>{if(!c)return!0;if(l.caCertificates.length===0)return!1;for(let t of l.caCertificates)try{if(n.verify(o,t)===e.TlsCertificateFlags.NO_FLAGS)return!0}catch{}return!1});let f=new e.Cancellable;d.handshake_async(t.PRIORITY_DEFAULT,f,(e,t)=>{try{if(d.handshake_finish(t),i.authorized=!0,i._setupTlsStreams(d),i.alpnProtocol=i.getAlpnProtocol(),u){let e=u(s,i.getPeerCertificate());if(e&&(i.authorized=!1,i.authorizationError=e.message,c)){i.destroy(e);return}}let e=i;e._reading=!1,e._startReading(),i.emit(`secureConnect`)}catch(e){i.authorized=!1,i.authorizationError=e instanceof Error?e.message:String(e),c?i.destroy(e instanceof Error?e:Error(String(e))):(i._setupTlsStreams(d),i.emit(`secureConnect`))}})}catch(e){i.destroy(e instanceof Error?e:Error(String(e)))}}),i.connect({port:a,host:o}),i}const l=[];var TLSServer=class extends n{_tlsCertificate=null;_tlsOptions;_sniContexts=new Map;_secureContext;constructor(e,t){super(),this._tlsOptions=e??{},this._secureContext=createSecureContext(this._tlsOptions),this._tlsCertificate=this._secureContext.certificate,t&&this.on(`secureConnection`,t),this._tlsOptions.cert&&!this._tlsCertificate&&a(this,`error`,i(Error(`Failed to parse TLS certificate`),`createServer`,{}))}addContext(e,t){try{let n=createSecureContext(t);this._sniContexts.set(e.toLowerCase(),n)}catch(e){this.emit(`error`,i(e,`addContext`,{}))}}_resolveSniContext(e,t){let n=this._secureContext;if(!e){t(n);return}let r=e.toLowerCase(),i=this._sniContexts.get(r);if(i){t(i);return}let a=splitHost(r);for(let[e,n]of this._sniContexts)if(checkHostMatch(a,e)){t(n);return}if(this._tlsOptions.SNICallback)try{this._tlsOptions.SNICallback(e,(e,r)=>{if(e||!r){t(n);return}t(r)});return}catch{t(n);return}t(n)}listen(...e){return this.on(`connection`,e=>{this._upgradeTls(e)}),super.listen(...e)}_upgradeTls(n){let r=n._connection;if(!r){let e=Error(`Cannot upgrade socket: no underlying connection`);this.emit(`tlsClientError`,e,n),n.destroy();return}if(!this._tlsCertificate&&this._sniContexts.size===0&&!this._tlsOptions.SNICallback){let e=Error(`TLS server has no certificate configured`);this.emit(`tlsClientError`,e,n),n.destroy();return}this._resolveSniContext(null,a=>{let o=a.certificate??this._tlsCertificate;if(!o){let e=Error(`SNI resolution returned no certificate`);this.emit(`tlsClientError`,e,n),n.destroy();return}try{let s=e.TlsServerConnection.new(r,o);this._tlsOptions.requestCert?s.authenticationMode=this._tlsOptions.rejectUnauthorized===!1?e.TlsAuthenticationMode.REQUESTED:e.TlsAuthenticationMode.REQUIRED:s.authenticationMode=e.TlsAuthenticationMode.NONE;let c=!!this._tlsOptions.requestCert&&this._tlsOptions.rejectUnauthorized!==!1,l=this._secureContext.caCertificates;if(s.connect(`accept-certificate`,(t,n,r)=>{if(!c)return!0;if(l.length===0)return!1;for(let t of l)try{if(n.verify(null,t)===e.TlsCertificateFlags.NO_FLAGS)return!0}catch{}return!1}),this._tlsOptions.ALPNProtocols&&this._tlsOptions.ALPNProtocols.length>0)try{s.set_advertised_protocols(this._tlsOptions.ALPNProtocols)}catch{}let u=new e.Cancellable;s.handshake_async(t.PRIORITY_DEFAULT,u,(e,t)=>{try{s.handshake_finish(t);let e=new TLSSocket;e.encrypted=!0,e.authorized=!0,e._secureContext=a,e._setupTlsStreams(s),e.alpnProtocol=e.getAlpnProtocol(),e._startReading(),this.emit(`secureConnection`,e)}catch(e){let t=i(e,`handshake`,{});this.emit(`tlsClientError`,t,n),n.destroy()}})}catch(e){let t=i(e,`tls_wrap`,{});this.emit(`tlsClientError`,t,n),n.destroy()}})}};function createServer(e,t){return typeof e==`function`?new TLSServer(void 0,e):new TLSServer(e,t)}const u={TLSSocket,TLSServer,Server:TLSServer,connect,createServer,createSecureContext,checkServerIdentity,getCiphers,rootCertificates:l,DEFAULT_MIN_VERSION:o,DEFAULT_MAX_VERSION:s,DEFAULT_CIPHERS:c};export{c as DEFAULT_CIPHERS,s as DEFAULT_MAX_VERSION,o as DEFAULT_MIN_VERSION,TLSServer as Server,TLSServer,TLSSocket,checkServerIdentity,connect,createSecureContext,createServer,u as default,getCiphers,l as rootCertificates};
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{parseClientHelloSni as e}from"./internal/sni-parser.js";import t from"@girs/gio-2.0";import n from"@girs/glib-2.0";import{Server as r,Socket as i}from"node:net";import{createNodeError as a,deferEmit as o}from"@gjsify/utils";const s=`TLSv1.2`,c=`TLSv1.3`,l=`TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384`;function getCiphers(){return[`aes-128-gcm`,`aes-256-gcm`,`chacha20-poly1305`,`aes-128-cbc`,`aes-256-cbc`]}function pemToString(e){if(Array.isArray(e))return e.map(pemToString).join(`
|
|
2
|
+
`);if(typeof e==`string`)return e;if(e&&typeof e.toString==`function`)try{return e.toString(`utf-8`)}catch{return new TextDecoder(`utf-8`).decode(e)}return String(e)}function splitPemBlocks(e){let t=[],n=/-----BEGIN [^-]+-----[\s\S]*?-----END [^-]+-----/g,r;for(;(r=n.exec(e))!==null;)t.push(r[0]);return t}function buildGioCertificate(e,n){let r=pemToString(e),i=n?pemToString(n):``,a=i?`${r}\n${i}`:r;return t.TlsCertificate.new_from_pem(a,a.length)}function buildCaCertificates(e){let n=[];if(Array.isArray(e))for(let t of e)n.push(...splitPemBlocks(pemToString(t)));else n.push(...splitPemBlocks(pemToString(e)));let r=[];for(let e of n)try{r.push(t.TlsCertificate.new_from_pem(e,e.length))}catch{}return r}function parseDistinguishedName(e){if(!e)return{};let t={};for(let n of e.split(/,(?![^=]*=)/)){let e=n.indexOf(`=`);if(e<0)continue;let r=n.slice(0,e).trim(),i=n.slice(e+1).trim(),a=t[r];a===void 0?t[r]=i:Array.isArray(a)?a.push(i):t[r]=[a,i]}return t}function formatCertDate(e){if(!e)return``;try{return e.format(`%b %d %H:%M:%S %Y GMT`)??``}catch{return``}}function formatAltNames(e){let t=[];try{let n=e.get_dns_names();if(n)for(let e of n){let n=e.get_data();n&&t.push(`DNS:${new TextDecoder(`utf-8`).decode(n)}`)}}catch{}try{let n=e.get_ip_addresses();if(n)for(let e of n)t.push(`IP Address:${e.to_string()}`)}catch{}return t.join(`, `)}function fingerprintFromBytes(e,t){try{let r=new n.Checksum(t);r.update(e);let i=r.get_string();if(!i)return``;let a=[];for(let e=0;e<i.length;e+=2)a.push(i.slice(e,e+2).toUpperCase());return a.join(`:`)}catch{return``}}function pemToDer(e){let t=/-----BEGIN CERTIFICATE-----([\s\S]*?)-----END CERTIFICATE-----/.exec(e);if(!t)return new Uint8Array;let n=t[1].replace(/[\s\r\n]+/g,``);try{let e=globalThis.atob;if(!e)return new Uint8Array;let t=e(n),r=new Uint8Array(t.length);for(let e=0;e<t.length;e++)r[e]=t.charCodeAt(e);return r}catch{return new Uint8Array}}function tlsCertToPeerCert(e,t){let r={};try{r.subject=parseDistinguishedName(e.get_subject_name())}catch{}try{r.issuer=parseDistinguishedName(e.get_issuer_name())}catch{}r.subjectaltname=formatAltNames(e);try{r.valid_from=formatCertDate(e.get_not_valid_before()),r.valid_to=formatCertDate(e.get_not_valid_after())}catch{}try{let t=e,i=t.certificate_pem??t.certificatePem;if(i){let e=pemToDer(i);r.raw=e,r.fingerprint=fingerprintFromBytes(e,n.ChecksumType.SHA1),r.fingerprint256=fingerprintFromBytes(e,n.ChecksumType.SHA256)}}catch{}if(t)try{let t=e.get_issuer();t&&!t.is_same(e)?r.issuerCertificate=tlsCertToPeerCert(t,!0):t&&(r.issuerCertificate=r)}catch{}return r}function unfqdn(e){return e.endsWith(`.`)?e.slice(0,-1):e}function splitHost(e){return unfqdn(e).toLowerCase().split(`.`)}function isPrintableAscii(e){for(let t=0;t<e.length;t++){let n=e.charCodeAt(t);if(n<33||n>126)return!1}return!0}function checkHostMatch(e,t){if(!t)return!1;let n=splitHost(t);if(e.length!==n.length||n.includes(``)||!n.every(isPrintableAscii))return!1;for(let t=e.length-1;t>0;t--)if(e[t]!==n[t])return!1;let r=e[0],i=n[0],a=i.split(`*`,3);if(a.length===1||i.includes(`xn--`))return r===i;if(a.length>2||n.length<=2)return!1;let o=a[0],s=a[1];return!(o.length+s.length>r.length||!r.startsWith(o)||!r.endsWith(s))}function checkServerIdentity(e,t){let n=t.subject,r=t.subjectaltname,i=[],a=[];if(e=String(e),r){let e=r.split(`, `);for(let t of e)t.startsWith(`DNS:`)?i.push(t.slice(4)):t.startsWith(`IP Address:`)&&a.push(t.slice(11).trim())}let o=!1,s=`Unknown reason`;e=unfqdn(e);let c=/^(\d{1,3}\.){3}\d{1,3}$/.test(e),l=e.includes(`:`);if(c||l)o=a.some(t=>t.toLowerCase()===e.toLowerCase()),o||(s=`IP: ${e} is not in the cert's list: ${a.join(`, `)}`);else if(i.length>0||n?.CN){let t=splitHost(e);if(i.length>0)o=i.some(e=>checkHostMatch(t,e.trim())),o||(s=`Host: ${e}. is not in the cert's altnames: ${r}`);else{let r=n?.CN;Array.isArray(r)?o=r.some(e=>checkHostMatch(t,e)):r&&(o=checkHostMatch(t,r)),o||(s=`Host: ${e}. is not cert's CN: ${r}`)}}else s=`Cert does not contain a DNS name`;if(!o){let n=Error(s);return n.reason=s,n.host=e,n.cert=t,n.code=`ERR_TLS_CERT_ALTNAME_INVALID`,n}}function createSecureContext(e){let t=e??{},n=null;if(t.cert)try{n=buildGioCertificate(t.cert,t.key)}catch{n=null}let r=t.ca?buildCaCertificates(t.ca):[],i={certificate:n,caCertificates:r,options:t};return i.context=i,i}var TLSSocket=class extends i{encrypted=!0;authorized=!1;authorizationError;alpnProtocol=!1;servername;_tlsConnection=null;_secureContext=null;constructor(e,t){super()}_setupTlsStreams(e){this._tlsConnection=e;let t=this;t._inputStream=e.get_input_stream(),t._outputStream=e.get_output_stream(),t._connection=e}getPeerCertificate(e=!1){if(!this._tlsConnection)return{};try{let t=this._tlsConnection.get_peer_certificate();return t?tlsCertToPeerCert(t,e):{}}catch{return{}}}getProtocol(){if(!this._tlsConnection)return null;try{switch(this._tlsConnection.get_protocol_version()){case t.TlsProtocolVersion.TLS_1_0:return`TLSv1`;case t.TlsProtocolVersion.TLS_1_1:return`TLSv1.1`;case t.TlsProtocolVersion.TLS_1_2:return`TLSv1.2`;case t.TlsProtocolVersion.TLS_1_3:return`TLSv1.3`;default:return null}}catch{return null}}getCipher(){if(!this._tlsConnection)return null;try{return{name:this._tlsConnection.get_ciphersuite_name()||`unknown`,version:this.getProtocol()||`unknown`}}catch{return null}}getAlpnProtocol(){if(!this._tlsConnection)return!1;try{return this._tlsConnection.get_negotiated_protocol()||!1}catch{return!1}}};function connect(e,r){let i=new TLSSocket(void 0,e);r&&i.once(`secureConnect`,r);let a=e.port||443,o=e.host||`localhost`,s=e.servername||o,c=e.rejectUnauthorized!==!1,l=e.secureContext??createSecureContext(e);i._secureContext=l,i.servername=s;let u=e.checkServerIdentity;return i.once(`connect`,()=>{let r=i._connection;if(!r){i.destroy(Error(`No underlying connection for TLS upgrade`));return}try{let o=t.NetworkAddress.new(s,a),d=t.TlsClientConnection.new(r,o);if(d.set_server_identity(o),l.certificate)try{d.set_certificate(l.certificate)}catch(e){console.warn(`[tls] failed to set client certificate:`,e)}if(e.ALPNProtocols&&e.ALPNProtocols.length>0)try{d.set_advertised_protocols(e.ALPNProtocols)}catch{}d.connect(`accept-certificate`,(e,n,r)=>{if(!c)return!0;if(l.caCertificates.length===0)return!1;for(let e of l.caCertificates)try{if(n.verify(o,e)===t.TlsCertificateFlags.NO_FLAGS)return!0}catch{}return!1});let f=new t.Cancellable;d.handshake_async(n.PRIORITY_DEFAULT,f,(e,t)=>{try{if(d.handshake_finish(t),i.authorized=!0,i._setupTlsStreams(d),i.alpnProtocol=i.getAlpnProtocol(),u){let e=u(s,i.getPeerCertificate());if(e&&(i.authorized=!1,i.authorizationError=e.message,c)){i.destroy(e);return}}let e=i;e._reading=!1,e._startReading(),i.emit(`secureConnect`)}catch(e){i.authorized=!1,i.authorizationError=e instanceof Error?e.message:String(e),c?i.destroy(e instanceof Error?e:Error(String(e))):(i._setupTlsStreams(d),i.emit(`secureConnect`))}})}catch(e){i.destroy(e instanceof Error?e:Error(String(e)))}}),i.connect({port:a,host:o}),i}const u=[];var TLSServer=class extends r{_tlsCertificate=null;_tlsOptions;_sniContexts=new Map;_secureContext;constructor(e,t){super(),this._tlsOptions=e??{},this._secureContext=createSecureContext(this._tlsOptions),this._tlsCertificate=this._secureContext.certificate,t&&this.on(`secureConnection`,t),this._tlsOptions.cert&&!this._tlsCertificate&&o(this,`error`,a(Error(`Failed to parse TLS certificate`),`createServer`,{}))}addContext(e,t){try{let n=createSecureContext(t);this._sniContexts.set(e.toLowerCase(),n)}catch(e){this.emit(`error`,a(e,`addContext`,{}))}}_resolveSniContext(e,t){let n=this._secureContext;if(!e){t(n);return}let r=e.toLowerCase(),i=this._sniContexts.get(r);if(i){t(i);return}let a=splitHost(r);for(let[e,n]of this._sniContexts)if(checkHostMatch(a,e)){t(n);return}if(this._tlsOptions.SNICallback)try{this._tlsOptions.SNICallback(e,(e,r)=>{if(e||!r){t(n);return}t(r)});return}catch{t(n);return}t(n)}listen(...e){return this.on(`connection`,e=>{this._upgradeTls(e)}),super.listen(...e)}_upgradeTls(r){let i=r._connection;if(!i){let e=Error(`Cannot upgrade socket: no underlying connection`);this.emit(`tlsClientError`,e,r),r.destroy();return}if(!this._tlsCertificate&&this._sniContexts.size===0&&!this._tlsOptions.SNICallback){let e=Error(`TLS server has no certificate configured`);this.emit(`tlsClientError`,e,r),r.destroy();return}let o=i,s=o.get_input_stream(),c=o.get_output_stream(),l=t.BufferedInputStream.new_sized(s,4096);l.fill_async(4096,n.PRIORITY_DEFAULT,null,(i,o)=>{let s=null;try{l.fill_finish(o),s=e(l.peek_buffer())}catch{}this._resolveSniContext(s,e=>{let i=e.certificate??this._tlsCertificate;if(!i){let e=Error(`SNI resolution returned no certificate`);this.emit(`tlsClientError`,e,r),r.destroy();return}try{let o=new t.SimpleIOStream({inputStream:l,outputStream:c}),s=t.TlsServerConnection.new(o,i);this._tlsOptions.requestCert?s.authenticationMode=this._tlsOptions.rejectUnauthorized===!1?t.TlsAuthenticationMode.REQUESTED:t.TlsAuthenticationMode.REQUIRED:s.authenticationMode=t.TlsAuthenticationMode.NONE;let u=!!this._tlsOptions.requestCert&&this._tlsOptions.rejectUnauthorized!==!1,d=this._secureContext.caCertificates;if(s.connect(`accept-certificate`,(e,n,r)=>{if(!u)return!0;if(d.length===0)return!1;for(let e of d)try{if(n.verify(null,e)===t.TlsCertificateFlags.NO_FLAGS)return!0}catch{}return!1}),this._tlsOptions.ALPNProtocols&&this._tlsOptions.ALPNProtocols.length>0)try{s.set_advertised_protocols(this._tlsOptions.ALPNProtocols)}catch{}let f=new t.Cancellable;s.handshake_async(n.PRIORITY_DEFAULT,f,(t,n)=>{try{s.handshake_finish(n);let t=new TLSSocket;t.encrypted=!0,t.authorized=!0,t._secureContext=e,t._setupTlsStreams(s),t.alpnProtocol=t.getAlpnProtocol(),t._startReading(),this.emit(`secureConnection`,t)}catch(e){let t=a(e,`handshake`,{});this.emit(`tlsClientError`,t,r),r.destroy()}})}catch(e){let t=a(e,`tls_wrap`,{});this.emit(`tlsClientError`,t,r),r.destroy()}})})}};function createServer(e,t){return typeof e==`function`?new TLSServer(void 0,e):new TLSServer(e,t)}const d={TLSSocket,TLSServer,Server:TLSServer,connect,createServer,createSecureContext,checkServerIdentity,getCiphers,rootCertificates:u,DEFAULT_MIN_VERSION:s,DEFAULT_MAX_VERSION:c,DEFAULT_CIPHERS:l};export{l as DEFAULT_CIPHERS,c as DEFAULT_MAX_VERSION,s as DEFAULT_MIN_VERSION,TLSServer as Server,TLSServer,TLSSocket,checkServerIdentity,connect,createSecureContext,createServer,d as default,getCiphers,u as rootCertificates};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"../_virtual/_rolldown/runtime.js";function parseClientHelloSni(e){if(e.length<11||e[0]!==22||e[1]!==3)return null;let t=e[3]<<8|e[4];if(t<4)return null;let n=5+t;if(e.length<n)return null;let r=5;if(e[r]!==1)return null;let i=e[r+1]<<16|e[r+2]<<8|e[r+3];r+=4;let a=r+i;if(a>n||r+34>a||(r+=34,r>=a))return null;let o=e[r];if(r+=1+o,r>a||r+2>a)return null;let s=e[r]<<8|e[r+1];if(r+=2+s,r>a||r+1>a)return null;let c=e[r];if(r+=1+c,r>a||r===a||r+2>a)return null;let l=e[r]<<8|e[r+1];r+=2;let u=r+l;if(u>a)return null;for(;r+4<=u;){let t=e[r]<<8|e[r+1],n=e[r+2]<<8|e[r+3];r+=4;let i=r+n;if(i>u)return null;if(t===0){if(r+2>i)return null;let t=e[r]<<8|e[r+1],n=r+2,a=n+t;if(a>i)return null;let o=n;for(;o+3<=a;){let t=e[o],n=e[o+1]<<8|e[o+2];if(o+=3,o+n>a)return null;if(t===0){let t=``;for(let r=0;r<n;r++)t+=String.fromCharCode(e[o+r]);return t}o+=n}return null}r=i}return null}export{parseClientHelloSni};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a TLS ClientHello record and extract the SNI host_name, if any.
|
|
3
|
+
*
|
|
4
|
+
* Inspects `bytes` as a TLS record (`content_type=Handshake`, handshake
|
|
5
|
+
* type `ClientHello`), walks the extensions list, and returns the first
|
|
6
|
+
* `server_name` entry of `NameType=host_name` (RFC 6066 §3).
|
|
7
|
+
*
|
|
8
|
+
* Returns `null` if:
|
|
9
|
+
* - the record is truncated;
|
|
10
|
+
* - the record is not a Handshake record or the handshake is not a
|
|
11
|
+
* ClientHello;
|
|
12
|
+
* - the ClientHello has no SNI extension or no `host_name` entry.
|
|
13
|
+
*
|
|
14
|
+
* Never throws; all bounds violations are treated as "no SNI".
|
|
15
|
+
*/
|
|
16
|
+
export declare function parseClientHelloSni(bytes: Uint8Array): string | null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/tls",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.16",
|
|
4
4
|
"description": "Node.js tls module for Gjs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "lib/esm/index.js",
|
|
@@ -33,15 +33,15 @@
|
|
|
33
33
|
"tls"
|
|
34
34
|
],
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@gjsify/cli": "^0.4.
|
|
37
|
-
"@gjsify/unit": "^0.4.
|
|
36
|
+
"@gjsify/cli": "^0.4.16",
|
|
37
|
+
"@gjsify/unit": "^0.4.16",
|
|
38
38
|
"@types/node": "^25.6.2",
|
|
39
39
|
"typescript": "^6.0.3"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@girs/gio-2.0": "2.88.0-4.0.0-rc.15",
|
|
43
43
|
"@girs/glib-2.0": "2.88.0-4.0.0-rc.15",
|
|
44
|
-
"@gjsify/net": "^0.4.
|
|
45
|
-
"@gjsify/utils": "^0.4.
|
|
44
|
+
"@gjsify/net": "^0.4.16",
|
|
45
|
+
"@gjsify/utils": "^0.4.16"
|
|
46
46
|
}
|
|
47
47
|
}
|