mirror of
https://github.com/denoland/deno.git
synced 2025-08-04 10:59:13 +00:00
feat: startTLS (#4773)
This commit is contained in:
parent
10469ec279
commit
47617e60d5
9 changed files with 222 additions and 12 deletions
|
@ -106,7 +106,7 @@ export { resources, close } from "./ops/resources.ts";
|
|||
export { signal, signals, Signal, SignalStream } from "./signals.ts";
|
||||
export { FileInfo, statSync, lstatSync, stat, lstat } from "./ops/fs/stat.ts";
|
||||
export { symlinkSync, symlink } from "./ops/fs/symlink.ts";
|
||||
export { connectTLS, listenTLS } from "./tls.ts";
|
||||
export { connectTLS, listenTLS, startTLS } from "./tls.ts";
|
||||
export { truncateSync, truncate } from "./ops/fs/truncate.ts";
|
||||
export { isatty, setRaw } from "./ops/tty.ts";
|
||||
export { umask } from "./ops/fs/umask.ts";
|
||||
|
|
27
cli/js/lib.deno.ns.d.ts
vendored
27
cli/js/lib.deno.ns.d.ts
vendored
|
@ -2038,6 +2038,33 @@ declare namespace Deno {
|
|||
*/
|
||||
export function connectTLS(options: ConnectTLSOptions): Promise<Conn>;
|
||||
|
||||
export interface StartTLSOptions {
|
||||
/** A literal IP address or host name that can be resolved to an IP address.
|
||||
* If not specified, defaults to `127.0.0.1`. */
|
||||
hostname?: string;
|
||||
/** Server certificate file. */
|
||||
certFile?: string;
|
||||
}
|
||||
|
||||
/** **UNSTABLE**: new API, yet to be vetted.
|
||||
*
|
||||
* Start TLS handshake from an existing connection using
|
||||
* an optional cert file, hostname (default is "127.0.0.1"). The
|
||||
* cert file is optional and if not included Mozilla's root certificates will
|
||||
* be used (see also https://github.com/ctz/webpki-roots for specifics)
|
||||
* Using this function requires that the other end of the connection is
|
||||
* prepared for TLS handshake.
|
||||
*
|
||||
* const conn = await Deno.connect({ port: 80, hostname: "127.0.0.1" });
|
||||
* const tlsConn = await Deno.startTLS(conn, { certFile: "./certs/my_custom_root_CA.pem", hostname: "127.0.0.1", port: 80 });
|
||||
*
|
||||
* Requires `allow-net` permission.
|
||||
*/
|
||||
export function startTLS(
|
||||
conn: Conn,
|
||||
options?: StartTLSOptions
|
||||
): Promise<Conn>;
|
||||
|
||||
/** **UNSTABLE**: not sure if broken or not */
|
||||
export interface Metrics {
|
||||
opsDispatched: number;
|
||||
|
|
|
@ -8,7 +8,7 @@ export interface ConnectTLSRequest {
|
|||
certFile?: string;
|
||||
}
|
||||
|
||||
interface ConnectTLSResponse {
|
||||
interface EstablishTLSResponse {
|
||||
rid: number;
|
||||
localAddr: {
|
||||
hostname: string;
|
||||
|
@ -24,7 +24,7 @@ interface ConnectTLSResponse {
|
|||
|
||||
export function connectTLS(
|
||||
args: ConnectTLSRequest
|
||||
): Promise<ConnectTLSResponse> {
|
||||
): Promise<EstablishTLSResponse> {
|
||||
return sendAsync("op_connect_tls", args);
|
||||
}
|
||||
|
||||
|
@ -66,3 +66,13 @@ interface ListenTLSResponse {
|
|||
export function listenTLS(args: ListenTLSRequest): ListenTLSResponse {
|
||||
return sendSync("op_listen_tls", args);
|
||||
}
|
||||
|
||||
export interface StartTLSRequest {
|
||||
rid: number;
|
||||
hostname: string;
|
||||
certFile?: string;
|
||||
}
|
||||
|
||||
export function startTLS(args: StartTLSRequest): Promise<EstablishTLSResponse> {
|
||||
return sendAsync("op_start_tls", args);
|
||||
}
|
||||
|
|
|
@ -209,3 +209,54 @@ unitTest(
|
|||
await resolvable;
|
||||
}
|
||||
);
|
||||
|
||||
unitTest(
|
||||
{ perms: { read: true, net: true } },
|
||||
async function startTLS(): Promise<void> {
|
||||
const hostname = "smtp.gmail.com";
|
||||
const port = 587;
|
||||
const encoder = new TextEncoder();
|
||||
|
||||
let conn = await Deno.connect({
|
||||
hostname,
|
||||
port,
|
||||
});
|
||||
|
||||
let writer = new BufWriter(conn);
|
||||
let reader = new TextProtoReader(new BufReader(conn));
|
||||
|
||||
let line: string | Deno.EOF = (await reader.readLine()) as string;
|
||||
assert(line.startsWith("220"));
|
||||
|
||||
await writer.write(encoder.encode(`EHLO ${hostname}\r\n`));
|
||||
await writer.flush();
|
||||
|
||||
while ((line = (await reader.readLine()) as string)) {
|
||||
assert(line.startsWith("250"));
|
||||
if (line.startsWith("250 ")) break;
|
||||
}
|
||||
|
||||
await writer.write(encoder.encode("STARTTLS\r\n"));
|
||||
await writer.flush();
|
||||
|
||||
line = await reader.readLine();
|
||||
|
||||
// Received the message that the server is ready to establish TLS
|
||||
assertEquals(line, "220 2.0.0 Ready to start TLS");
|
||||
|
||||
conn = await Deno.startTLS(conn, { hostname });
|
||||
writer = new BufWriter(conn);
|
||||
reader = new TextProtoReader(new BufReader(conn));
|
||||
|
||||
// After that use TLS communication again
|
||||
await writer.write(encoder.encode(`EHLO ${hostname}\r\n`));
|
||||
await writer.flush();
|
||||
|
||||
while ((line = (await reader.readLine()) as string)) {
|
||||
assert(line.startsWith("250"));
|
||||
if (line.startsWith("250 ")) break;
|
||||
}
|
||||
|
||||
conn.close();
|
||||
}
|
||||
);
|
||||
|
|
|
@ -57,3 +57,20 @@ export function listenTLS({
|
|||
});
|
||||
return new TLSListenerImpl(res.rid, res.localAddr);
|
||||
}
|
||||
|
||||
interface StartTLSOptions {
|
||||
hostname?: string;
|
||||
certFile?: string;
|
||||
}
|
||||
|
||||
export async function startTLS(
|
||||
conn: Conn,
|
||||
{ hostname = "127.0.0.1", certFile = undefined }: StartTLSOptions = {}
|
||||
): Promise<Conn> {
|
||||
const res = await tlsOps.startTLS({
|
||||
rid: conn.rid,
|
||||
hostname,
|
||||
certFile,
|
||||
});
|
||||
return new ConnImpl(res.rid, res.remoteAddr!, res.localAddr!);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue