mirror of
https://github.com/denoland/deno.git
synced 2024-12-23 15:49:44 -05:00
feat(ext/net): add TlsConn.handshake() (#12467)
A `handshake()` method was added that returns when the TLS handshake is complete. The `TlsListener` and `TlsConn` interfaces were added to accomodate this new method. Closes: #11759.
This commit is contained in:
parent
c27ef0ac7b
commit
cf9c4f0031
4 changed files with 47 additions and 30 deletions
4
cli/dts/lib.deno.unstable.d.ts
vendored
4
cli/dts/lib.deno.unstable.d.ts
vendored
|
@ -1091,7 +1091,7 @@ declare namespace Deno {
|
|||
*
|
||||
* Requires `allow-net` permission.
|
||||
*/
|
||||
export function connectTls(options: ConnectTlsOptions): Promise<Conn>;
|
||||
export function connectTls(options: ConnectTlsOptions): Promise<TlsConn>;
|
||||
|
||||
export interface StartTlsOptions {
|
||||
/** A literal IP address or host name that can be resolved to an IP address.
|
||||
|
@ -1130,7 +1130,7 @@ declare namespace Deno {
|
|||
export function startTls(
|
||||
conn: Conn,
|
||||
options?: StartTlsOptions,
|
||||
): Promise<Conn>;
|
||||
): Promise<TlsConn>;
|
||||
|
||||
export interface ListenTlsOptions {
|
||||
/** **UNSTABLE**: new API, yet to be vetted.
|
||||
|
|
|
@ -1122,14 +1122,6 @@ unitTest(
|
|||
},
|
||||
);
|
||||
|
||||
// TODO(piscisaureus): use `TlsConn.handhake()` instead, once this is added to
|
||||
// the public API in Deno 1.16.
|
||||
function tlsHandshake(conn: Deno.Conn): Promise<void> {
|
||||
// deno-lint-ignore no-explicit-any
|
||||
const opAsync = (Deno as any).core.opAsync;
|
||||
return opAsync("op_tls_handshake", conn.rid);
|
||||
}
|
||||
|
||||
unitTest(
|
||||
{ permissions: { read: true, net: true } },
|
||||
async function tlsHandshakeSuccess() {
|
||||
|
@ -1151,7 +1143,7 @@ unitTest(
|
|||
const [conn1, conn2] = await Promise.all([acceptPromise, connectPromise]);
|
||||
listener.close();
|
||||
|
||||
await Promise.all([tlsHandshake(conn1), tlsHandshake(conn2)]);
|
||||
await Promise.all([conn1.handshake(), conn2.handshake()]);
|
||||
|
||||
// Begin sending a 10mb blob over the TLS connection.
|
||||
const whole = new Uint8Array(10 << 20); // 10mb.
|
||||
|
@ -1162,28 +1154,28 @@ unitTest(
|
|||
const half = new Uint8Array(whole.byteLength / 2);
|
||||
const receivePromise = readFull(conn2, half);
|
||||
|
||||
await tlsHandshake(conn1);
|
||||
await tlsHandshake(conn2);
|
||||
await conn1.handshake();
|
||||
await conn2.handshake();
|
||||
|
||||
// Finish receiving the first 5mb.
|
||||
assertEquals(await receivePromise, half.length);
|
||||
|
||||
// See that we can call `handshake()` in the middle of large reads and writes.
|
||||
await tlsHandshake(conn1);
|
||||
await tlsHandshake(conn2);
|
||||
await conn1.handshake();
|
||||
await conn2.handshake();
|
||||
|
||||
// Receive second half of large blob. Wait for the send promise and check it.
|
||||
assertEquals(await readFull(conn2, half), half.length);
|
||||
assertEquals(await sendPromise, whole.length);
|
||||
|
||||
await tlsHandshake(conn1);
|
||||
await tlsHandshake(conn2);
|
||||
await conn1.handshake();
|
||||
await conn2.handshake();
|
||||
|
||||
await conn1.closeWrite();
|
||||
await conn2.closeWrite();
|
||||
|
||||
await tlsHandshake(conn1);
|
||||
await tlsHandshake(conn2);
|
||||
await conn1.handshake();
|
||||
await conn2.handshake();
|
||||
|
||||
conn1.close();
|
||||
conn2.close();
|
||||
|
@ -1216,7 +1208,7 @@ unitTest(
|
|||
for (let i = 0; i < 10; i++) {
|
||||
// Handshake fails because the client rejects the server certificate.
|
||||
await assertRejects(
|
||||
() => tlsHandshake(conn),
|
||||
() => conn.handshake(),
|
||||
Deno.errors.InvalidData,
|
||||
"BadCertificate",
|
||||
);
|
||||
|
@ -1230,7 +1222,7 @@ unitTest(
|
|||
const conn = await Deno.connectTls({ hostname, port });
|
||||
// Handshake fails because the server presents a self-signed certificate.
|
||||
await assertRejects(
|
||||
() => tlsHandshake(conn),
|
||||
() => conn.handshake(),
|
||||
Deno.errors.InvalidData,
|
||||
"UnknownIssuer",
|
||||
);
|
||||
|
@ -1247,7 +1239,7 @@ unitTest(
|
|||
});
|
||||
// Handshake fails because hostname doesn't match the certificate.
|
||||
await assertRejects(
|
||||
() => tlsHandshake(tlsConn),
|
||||
() => tlsConn.handshake(),
|
||||
Deno.errors.InvalidData,
|
||||
"CertNotValidForName",
|
||||
);
|
||||
|
|
|
@ -23,6 +23,16 @@
|
|||
return core.opAsync("op_start_tls", args);
|
||||
}
|
||||
|
||||
function opTlsHandshake(rid) {
|
||||
return core.opAsync("op_tls_handshake", rid);
|
||||
}
|
||||
|
||||
class TlsConn extends Conn {
|
||||
handshake() {
|
||||
return opTlsHandshake(this.rid);
|
||||
}
|
||||
}
|
||||
|
||||
async function connectTls({
|
||||
port,
|
||||
hostname = "127.0.0.1",
|
||||
|
@ -41,13 +51,13 @@
|
|||
certChain,
|
||||
privateKey,
|
||||
});
|
||||
return new Conn(res.rid, res.remoteAddr, res.localAddr);
|
||||
return new TlsConn(res.rid, res.remoteAddr, res.localAddr);
|
||||
}
|
||||
|
||||
class TLSListener extends Listener {
|
||||
class TlsListener extends Listener {
|
||||
async accept() {
|
||||
const res = await opAcceptTLS(this.rid);
|
||||
return new Conn(res.rid, res.remoteAddr, res.localAddr);
|
||||
return new TlsConn(res.rid, res.remoteAddr, res.localAddr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,7 +77,7 @@
|
|||
transport,
|
||||
alpnProtocols,
|
||||
});
|
||||
return new TLSListener(res.rid, res.localAddr);
|
||||
return new TlsListener(res.rid, res.localAddr);
|
||||
}
|
||||
|
||||
async function startTls(
|
||||
|
@ -80,13 +90,14 @@
|
|||
certFile,
|
||||
caCerts,
|
||||
});
|
||||
return new Conn(res.rid, res.remoteAddr, res.localAddr);
|
||||
return new TlsConn(res.rid, res.remoteAddr, res.localAddr);
|
||||
}
|
||||
|
||||
window.__bootstrap.tls = {
|
||||
startTls,
|
||||
listenTls,
|
||||
connectTls,
|
||||
TLSListener,
|
||||
TlsConn,
|
||||
TlsListener,
|
||||
};
|
||||
})(this);
|
||||
|
|
18
ext/net/lib.deno_net.d.ts
vendored
18
ext/net/lib.deno_net.d.ts
vendored
|
@ -33,6 +33,13 @@ declare namespace Deno {
|
|||
[Symbol.asyncIterator](): AsyncIterableIterator<Conn>;
|
||||
}
|
||||
|
||||
/** Specialized listener that accepts TLS connections. */
|
||||
export interface TlsListener extends Listener, AsyncIterable<TlsConn> {
|
||||
/** Waits for a TLS client to connect and accepts the connection. */
|
||||
accept(): Promise<TlsConn>;
|
||||
[Symbol.asyncIterator](): AsyncIterableIterator<TlsConn>;
|
||||
}
|
||||
|
||||
export interface Conn extends Reader, Writer, Closer {
|
||||
/** The local address of the connection. */
|
||||
readonly localAddr: Addr;
|
||||
|
@ -45,6 +52,13 @@ declare namespace Deno {
|
|||
closeWrite(): Promise<void>;
|
||||
}
|
||||
|
||||
export interface TlsConn extends Conn {
|
||||
/** Runs the client or server handshake protocol to completion if that has
|
||||
* not happened yet. Calling this method is optional; the TLS handshake
|
||||
* will be completed automatically as soon as data is sent or received. */
|
||||
handshake(): Promise<void>;
|
||||
}
|
||||
|
||||
export interface ListenOptions {
|
||||
/** The port to listen on. */
|
||||
port: number;
|
||||
|
@ -90,7 +104,7 @@ declare namespace Deno {
|
|||
* ```
|
||||
*
|
||||
* Requires `allow-net` permission. */
|
||||
export function listenTls(options: ListenTlsOptions): Listener;
|
||||
export function listenTls(options: ListenTlsOptions): TlsListener;
|
||||
|
||||
export interface ConnectOptions {
|
||||
/** The port to connect to. */
|
||||
|
@ -150,7 +164,7 @@ declare namespace Deno {
|
|||
*
|
||||
* Requires `allow-net` permission.
|
||||
*/
|
||||
export function connectTls(options: ConnectTlsOptions): Promise<Conn>;
|
||||
export function connectTls(options: ConnectTlsOptions): Promise<TlsConn>;
|
||||
|
||||
/** Shutdown socket send operations.
|
||||
*
|
||||
|
|
Loading…
Reference in a new issue