@gjsify/tls 0.4.29 → 0.4.31
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/connect.js +1 -1
- package/lib/esm/index.js +1 -1
- package/lib/esm/session-access.js +1 -0
- package/lib/esm/tls-socket.js +1 -1
- package/lib/types/index.d.ts +8 -0
- package/lib/types/session-access.d.ts +38 -0
- package/lib/types/session-access.gjs.spec.d.ts +2 -0
- package/lib/types/tls-socket.d.ts +69 -0
- package/package.json +6 -6
package/lib/esm/connect.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import{
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{hasTlsSessionAccess as e}from"./session-access.js";import{TLSSocket as t}from"./tls-socket.js";import{createSecureContext as n}from"./secure-context.js";import r from"@girs/gio-2.0";import i from"@girs/glib-2.0";function connect(a,o){let s=new t(void 0,a);o&&s.once(`secureConnect`,o);let c=a.port||443,l=a.host||`localhost`,u=a.servername||l,d=a.rejectUnauthorized!==!1,f=a.secureContext??n(a);s._secureContext=f,s.servername=u;let p=a.checkServerIdentity;return s.once(`connect`,()=>{let t=s._connection;if(!t){s.destroy(Error(`No underlying connection for TLS upgrade`));return}try{let n=r.NetworkAddress.new(u,c),o=r.TlsClientConnection.new(t,n);if(o.set_server_identity(n),a.session&&e())try{s._tlsConnection=o,s.setSession(a.session)}catch{}if(f.certificate)try{o.set_certificate(f.certificate)}catch(e){console.warn(`[tls] failed to set client certificate:`,e)}if(a.ALPNProtocols&&a.ALPNProtocols.length>0)try{o.set_advertised_protocols(a.ALPNProtocols)}catch{}o.connect(`accept-certificate`,(e,t,i)=>{if(!d)return!0;if(f.caCertificates.length===0)return!1;for(let e of f.caCertificates)try{if(t.verify(n,e)===r.TlsCertificateFlags.NO_FLAGS)return!0}catch{}return!1});let l=new r.Cancellable;o.handshake_async(i.PRIORITY_DEFAULT,l,(t,n)=>{try{if(o.handshake_finish(n),s.authorized=!0,s._setupTlsStreams(o),s.alpnProtocol=s.getAlpnProtocol(),p){let e=p(u,s.getPeerCertificate());if(e&&(s.authorized=!1,s.authorizationError=e.message,d)){s.destroy(e);return}}let t=s;if(t._reading=!1,t._startReading(),e()){let e=s.getSession();e&&s.emit(`session`,e)}s.emit(`secureConnect`)}catch(e){s.authorized=!1,s.authorizationError=e instanceof Error?e.message:String(e),d?s.destroy(e instanceof Error?e:Error(String(e))):(s._setupTlsStreams(o),s.emit(`secureConnect`))}})}catch(e){s.destroy(e instanceof Error?e:Error(String(e)))}}),s.connect({port:c,host:l}),s}export{connect};
|
package/lib/esm/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import{
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{TlsChannelBindingType as e,hasTlsSessionAccess as t}from"./session-access.js";import{TLSSocket as n}from"./tls-socket.js";import{createSecureContext as r}from"./secure-context.js";import{connect as i}from"./connect.js";import{checkServerIdentity as a}from"./internal/hostname.js";import{TLSServer as o,createServer as s}from"./tls-server.js";import{OcspCertStatus as c,OcspResponseStatus as l,hasOcspSupport as u,parseOcspResponse as d}from"./ocsp.js";const f=`TLSv1.2`,p=`TLSv1.3`,m=`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`]}const h=[],g={TLSSocket:n,TLSServer:o,Server:o,connect:i,createServer:s,createSecureContext:r,checkServerIdentity:a,getCiphers,rootCertificates:h,DEFAULT_MIN_VERSION:f,DEFAULT_MAX_VERSION:p,DEFAULT_CIPHERS:m,parseOcspResponse:d,hasOcspSupport:u,OcspCertStatus:c,OcspResponseStatus:l,hasTlsSessionAccess:t,TlsChannelBindingType:e};export{m as DEFAULT_CIPHERS,p as DEFAULT_MAX_VERSION,f as DEFAULT_MIN_VERSION,c as OcspCertStatus,l as OcspResponseStatus,o as Server,o as TLSServer,n as TLSSocket,e as TlsChannelBindingType,a as checkServerIdentity,i as connect,r as createSecureContext,s as createServer,g as default,getCiphers,u as hasOcspSupport,t as hasTlsSessionAccess,d as parseOcspResponse,h as rootCertificates};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{TlsChannelBindingType as e,TlsChannelBindingType as t,createSessionAccess as n,hasTlsSessionAccess as r}from"@gjsify/tls-native";function hasTlsSessionAccess(){return r()}function createSessionAccess(e){return n(e)}export{e as TlsChannelBindingType,t as _TlsChannelBindingType,createSessionAccess,hasTlsSessionAccess};
|
package/lib/esm/tls-socket.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import{tlsCertToPeerCert as e}from"./internal/cert-utils.js";import t from"@girs/gio-2.0";import{Socket as
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{tlsCertToPeerCert as e}from"./internal/cert-utils.js";import{createSessionAccess as t,hasTlsSessionAccess as n}from"./session-access.js";import r from"@girs/gio-2.0";import{Buffer as i}from"node:buffer";import{Socket as a}from"node:net";var TLSSocket=class extends a{encrypted=!0;authorized=!1;authorizationError;alpnProtocol=!1;servername;_tlsConnection=null;_secureContext=null;_sessionAccess=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}_getSessionAccess(){if(this._sessionAccess)return this._sessionAccess;if(!this._tlsConnection)return null;try{this._sessionAccess=t(this._tlsConnection)}catch{this._sessionAccess=null}return this._sessionAccess}getPeerCertificate(t=!1){if(!this._tlsConnection)return{};try{let n=this._tlsConnection.get_peer_certificate();return n?e(n,t):{}}catch{return{}}}getProtocol(){if(!this._tlsConnection)return null;try{switch(this._tlsConnection.get_protocol_version()){case r.TlsProtocolVersion.TLS_1_0:return`TLSv1`;case r.TlsProtocolVersion.TLS_1_1:return`TLSv1.1`;case r.TlsProtocolVersion.TLS_1_2:return`TLSv1.2`;case r.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}}getFinished(){if(!n())return;let e=this._getSessionAccess();if(e)try{return _bytesToBuffer(e.get_finished())}catch{return}}getPeerFinished(){if(!n())return;let e=this._getSessionAccess();if(e)try{return _bytesToBuffer(e.get_peer_finished())}catch{return}}getSession(){if(!n())return;let e=this._getSessionAccess();if(e)try{return _bytesToBuffer(e.get_session_data())}catch{return}}setSession(e){if(!n())return;let t=this._getSessionAccess();if(t)try{t.set_session_data(_bufferToBytes(e))}catch{}}isSessionReused(){if(!n())return!1;let e=this._getSessionAccess();if(!e)return!1;try{return e.is_session_reused()}catch{return!1}}};function _bytesToBuffer(e){if(e==null)return;if(e instanceof Uint8Array)return i.from(e);let t=e;if(typeof t.toArray==`function`)try{return i.from(t.toArray())}catch{return}}function _bufferToBytes(e){return e}export{TLSSocket};
|
package/lib/types/index.d.ts
CHANGED
|
@@ -16,12 +16,14 @@ export type { SNICallback, TlsServerOptions } from './tls-server.js';
|
|
|
16
16
|
export { TLSServer, createServer } from './tls-server.js';
|
|
17
17
|
export { TLSServer as Server } from './tls-server.js';
|
|
18
18
|
export { parseOcspResponse, hasOcspSupport, OcspCertStatus, OcspResponseStatus, type OcspResponseInfo, } from './ocsp.js';
|
|
19
|
+
export { hasTlsSessionAccess, TlsChannelBindingType, type NativeSessionAccess as TlsSessionAccess, } from './session-access.js';
|
|
19
20
|
import { checkServerIdentity as _checkServerIdentity } from './internal/hostname.js';
|
|
20
21
|
import { createSecureContext as _createSecureContext } from './secure-context.js';
|
|
21
22
|
import { TLSSocket as _TLSSocket } from './tls-socket.js';
|
|
22
23
|
import { connect as _connect } from './connect.js';
|
|
23
24
|
import { TLSServer as _TLSServer, createServer as _createServer } from './tls-server.js';
|
|
24
25
|
import { parseOcspResponse as _parseOcspResponse, hasOcspSupport as _hasOcspSupport } from './ocsp.js';
|
|
26
|
+
import { hasTlsSessionAccess as _hasTlsSessionAccess } from './session-access.js';
|
|
25
27
|
declare const tlsExports: {
|
|
26
28
|
TLSSocket: typeof _TLSSocket;
|
|
27
29
|
TLSServer: typeof _TLSServer;
|
|
@@ -50,5 +52,11 @@ declare const tlsExports: {
|
|
|
50
52
|
readonly SIG_REQUIRED: 5;
|
|
51
53
|
readonly UNAUTHORIZED: 6;
|
|
52
54
|
};
|
|
55
|
+
hasTlsSessionAccess: typeof _hasTlsSessionAccess;
|
|
56
|
+
TlsChannelBindingType: {
|
|
57
|
+
readonly TLS_UNIQUE: 0;
|
|
58
|
+
readonly TLS_SERVER_END_POINT: 1;
|
|
59
|
+
readonly TLS_EXPORTER: 2;
|
|
60
|
+
};
|
|
53
61
|
};
|
|
54
62
|
export default tlsExports;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { TlsChannelBindingType as _TlsChannelBindingType, type NativeSessionAccess as _NativeSessionAccess, type TlsConnectionHandle as _TlsConnectionHandle } from '@gjsify/tls-native';
|
|
2
|
+
export { TlsChannelBindingType } from '@gjsify/tls-native';
|
|
3
|
+
export type { NativeSessionAccess, TlsConnectionHandle } from '@gjsify/tls-native';
|
|
4
|
+
/**
|
|
5
|
+
* Returns `true` when the @gjsify/tls-native Phase 2 session-access
|
|
6
|
+
* bridge is loaded AND functional. Today this returns `false` even
|
|
7
|
+
* on GJS with the typelib installed — the underlying gnutls_session_t
|
|
8
|
+
* extraction from `Gio.TlsConnection` is not yet implemented
|
|
9
|
+
* (`docs/poc/tls-phase2-session-access.md`).
|
|
10
|
+
*
|
|
11
|
+
* Use this predicate to detect "session-resumption / channel-binding
|
|
12
|
+
* available on this runtime" without triggering a thrown error. When
|
|
13
|
+
* it returns `false`:
|
|
14
|
+
*
|
|
15
|
+
* - `TLSSocket.getFinished()` / `getPeerFinished()` return `undefined`.
|
|
16
|
+
* - `TLSSocket.getSession()` returns `undefined`.
|
|
17
|
+
* - `TLSSocket.setSession()` / `tls.connect({session})` silently
|
|
18
|
+
* skip the resumption attempt (full handshake instead).
|
|
19
|
+
* - The `'session'` event never fires.
|
|
20
|
+
*
|
|
21
|
+
* This matches Node's behavior on a build without OpenSSL session
|
|
22
|
+
* support — present API surface, no-op when unavailable.
|
|
23
|
+
*/
|
|
24
|
+
export declare function hasTlsSessionAccess(): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Internal: build a {@link NativeSessionAccess} wrapper around a live
|
|
27
|
+
* `Gio.TlsConnection`. Returns `null` when the native typelib isn't
|
|
28
|
+
* loaded OR @connection is `null`. The returned wrapper's methods
|
|
29
|
+
* may throw — callers must wrap in `try/catch` AND check
|
|
30
|
+
* `hasTlsSessionAccess()` first.
|
|
31
|
+
*
|
|
32
|
+
* @internal — used by `TLSSocket` and `connect.ts`. Public consumers
|
|
33
|
+
* should rely on the Node-shaped getters/setters on `TLSSocket`.
|
|
34
|
+
*/
|
|
35
|
+
export declare function createSessionAccess(connection: _TlsConnectionHandle | null): _NativeSessionAccess | null;
|
|
36
|
+
/** Re-export for code that wants the channel-binding type constants
|
|
37
|
+
* without importing through the native package directly. */
|
|
38
|
+
export { _TlsChannelBindingType };
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import Gio from '@girs/gio-2.0';
|
|
2
|
+
import { Buffer } from 'node:buffer';
|
|
2
3
|
import { Socket } from 'node:net';
|
|
3
4
|
import { type PeerCertificate } from './internal/cert-utils.js';
|
|
4
5
|
import type { SecureContext, SecureContextOptions } from './secure-context.js';
|
|
6
|
+
import type { NativeSessionAccess } from './session-access.js';
|
|
5
7
|
export interface TlsConnectOptions extends SecureContextOptions {
|
|
6
8
|
host?: string;
|
|
7
9
|
port?: number;
|
|
@@ -12,6 +14,15 @@ export interface TlsConnectOptions extends SecureContextOptions {
|
|
|
12
14
|
secureContext?: SecureContext;
|
|
13
15
|
/** Custom server-identity check (runs after the GnuTLS-level check). */
|
|
14
16
|
checkServerIdentity?: (host: string, cert: PeerCertificate) => Error | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Previously serialized session blob to attempt resumption with.
|
|
19
|
+
* Pulled from a prior connection's `'session'` event / `getSession()`.
|
|
20
|
+
*
|
|
21
|
+
* Silently ignored when {@link hasTlsSessionAccess} returns `false`
|
|
22
|
+
* (no native bridge, or the GIO struct-layout work hasn't landed
|
|
23
|
+
* yet) — the connection falls back to a full handshake.
|
|
24
|
+
*/
|
|
25
|
+
session?: Buffer | Uint8Array;
|
|
15
26
|
}
|
|
16
27
|
/**
|
|
17
28
|
* Internal cast for Socket's private-field shape. We own `node:net`'s
|
|
@@ -40,12 +51,24 @@ export declare class TLSSocket extends Socket {
|
|
|
40
51
|
_tlsConnection: Gio.TlsConnection | null;
|
|
41
52
|
/** @internal — preserved for diagnostics + future cert-chain verification. */
|
|
42
53
|
_secureContext: SecureContext | null;
|
|
54
|
+
/**
|
|
55
|
+
* @internal Lazily constructed Phase 2 session-access bridge for
|
|
56
|
+
* this connection. Built on first call to a session/binding getter
|
|
57
|
+
* (`_getSessionAccess()`), reused across subsequent calls.
|
|
58
|
+
*/
|
|
59
|
+
_sessionAccess: NativeSessionAccess | null;
|
|
43
60
|
constructor(_socket?: Socket, _options?: SecureContextOptions);
|
|
44
61
|
/**
|
|
45
62
|
* @internal Wire the TLS connection's I/O streams into this socket
|
|
46
63
|
* so that read/write operations go through the encrypted channel.
|
|
47
64
|
*/
|
|
48
65
|
_setupTlsStreams(tlsConn: Gio.TlsConnection): void;
|
|
66
|
+
/**
|
|
67
|
+
* @internal Build (or reuse) the `NativeSessionAccess` for this
|
|
68
|
+
* TLS connection. Returns `null` when no TLS connection is wired
|
|
69
|
+
* yet or the native typelib is unavailable.
|
|
70
|
+
*/
|
|
71
|
+
_getSessionAccess(): NativeSessionAccess | null;
|
|
49
72
|
/**
|
|
50
73
|
* Get the peer certificate. When `detailed` is true, walks the issuer chain
|
|
51
74
|
* via `Gio.TlsCertificate.get_issuer()` and populates `issuerCertificate`
|
|
@@ -61,4 +84,50 @@ export declare class TLSSocket extends Socket {
|
|
|
61
84
|
} | null;
|
|
62
85
|
/** Get the negotiated ALPN protocol (or false if none). */
|
|
63
86
|
getAlpnProtocol(): string | false;
|
|
87
|
+
/**
|
|
88
|
+
* Get the local Finished message bytes (RFC 5246 §7.4.9) for use
|
|
89
|
+
* as a `tls-unique` channel binding (RFC 5929 §3). Used by
|
|
90
|
+
* SCRAM-SHA-* SASL mechanisms (RFC 5802 §6).
|
|
91
|
+
*
|
|
92
|
+
* Returns `undefined` when:
|
|
93
|
+
* - The handshake has not completed.
|
|
94
|
+
* - The native session-access bridge is not available
|
|
95
|
+
* ({@link hasTlsSessionAccess} returns `false`).
|
|
96
|
+
*
|
|
97
|
+
* On TLS 1.3 the underlying GnuTLS call returns the
|
|
98
|
+
* `tls-exporter` (RFC 9266) bytes — the Node-compat `getFinished`
|
|
99
|
+
* name is preserved but the semantics auto-degrade to the
|
|
100
|
+
* version-appropriate binding.
|
|
101
|
+
*/
|
|
102
|
+
getFinished(): Buffer | undefined;
|
|
103
|
+
/**
|
|
104
|
+
* Get the peer's Finished message bytes. Same TLS 1.3 fallback as
|
|
105
|
+
* {@link getFinished}.
|
|
106
|
+
*/
|
|
107
|
+
getPeerFinished(): Buffer | undefined;
|
|
108
|
+
/**
|
|
109
|
+
* Get the serialized session for resumption. Suitable for caching
|
|
110
|
+
* and feeding back into a future `tls.connect({session})` call.
|
|
111
|
+
*
|
|
112
|
+
* Returns `undefined` when the native session-access bridge is
|
|
113
|
+
* not available.
|
|
114
|
+
*/
|
|
115
|
+
getSession(): Buffer | undefined;
|
|
116
|
+
/**
|
|
117
|
+
* Inject a previously serialized session blob. Must be called
|
|
118
|
+
* BEFORE the handshake completes — typically Node consumers use
|
|
119
|
+
* `tls.connect({session})` instead, which forwards here at the
|
|
120
|
+
* right time.
|
|
121
|
+
*
|
|
122
|
+
* Silently no-ops when the native session-access bridge is not
|
|
123
|
+
* available (matches Node's behavior on a build without session
|
|
124
|
+
* support).
|
|
125
|
+
*/
|
|
126
|
+
setSession(session: Buffer | Uint8Array): void;
|
|
127
|
+
/**
|
|
128
|
+
* Returns `true` if this connection resumed an earlier session
|
|
129
|
+
* (via session ID or ticket). `false` for fresh handshakes and
|
|
130
|
+
* when the native bridge is unavailable.
|
|
131
|
+
*/
|
|
132
|
+
isSessionReused(): boolean;
|
|
64
133
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/tls",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.31",
|
|
4
4
|
"description": "Node.js tls module for Gjs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "lib/esm/index.js",
|
|
@@ -33,16 +33,16 @@
|
|
|
33
33
|
"tls"
|
|
34
34
|
],
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@gjsify/cli": "^0.4.
|
|
37
|
-
"@gjsify/unit": "^0.4.
|
|
36
|
+
"@gjsify/cli": "^0.4.31",
|
|
37
|
+
"@gjsify/unit": "^0.4.31",
|
|
38
38
|
"@types/node": "^25.9.1",
|
|
39
39
|
"typescript": "^6.0.3"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@girs/gio-2.0": "2.88.0-4.0.1",
|
|
43
43
|
"@girs/glib-2.0": "2.88.0-4.0.1",
|
|
44
|
-
"@gjsify/net": "^0.4.
|
|
45
|
-
"@gjsify/tls-native": "^0.4.
|
|
46
|
-
"@gjsify/utils": "^0.4.
|
|
44
|
+
"@gjsify/net": "^0.4.31",
|
|
45
|
+
"@gjsify/tls-native": "^0.4.31",
|
|
46
|
+
"@gjsify/utils": "^0.4.31"
|
|
47
47
|
}
|
|
48
48
|
}
|