-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathconnect.js
93 lines (88 loc) · 2.88 KB
/
connect.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
'use strict'
/**
* Connect module. Provides a function to fetch a TLS certificate from
* a network server.
* @module connect
*/
const net = require('net')
const tls = require('tls')
const { startssl } = require('./startssl')
const getPort = (port) => {
if (port === undefined || port === '') return { port: 443 }
if (typeof port === 'number') return { port }
if (/^[0-9]+$/.test(port)) return { port: parseInt(port) }
return {
https: { port: 443 },
imap: { port: 143, protocol: 'imap' },
imaps: { port: 993 },
pop3s: { port: 995 },
smtp: { port: 25, protocol: 'smtp' },
smtps: { port: 465 },
submission: { port: 587, protocol: 'smtp' }
}[port]
}
/**
* Connect to a network service, optionally perform some sort of STARTSSL
* procedure, then negotiate TLS and return the server's certificate.
*
* @async
* @param {string} servername - The DNS name to connect to.
* @param {(string|integer)} [port=443] - The TCP port to connect to.
* @param {string} [protocol] - The STARTTLS protocol to use. Defaults to
* 'none', except if <port> is 'smtp', 'submission' or 'imap'.
* @param {string} [ipoverride] - The IP address to connect to, overriding
* the DNS address of the servername
* @param {integer} [timeout] - The number of milliseconds to wait.
* @param {object} [ca] - secureContext 'ca' parameter.
* @returns {certificate} The server's certificate.
*/
module.exports.connect =
(servername, port, protocol, ipoverride, timeout, ca) => {
const portInfo = getPort(port)
if (!portInfo) throw new Error(`Unknown port ${port}`)
if (!protocol && portInfo.protocol) protocol = portInfo.protocol
return new Promise((resolve, reject) => {
let socket
try {
socket = net.createConnection(
portInfo.port,
ipoverride || servername,
async () => {
try {
await startssl(socket, protocol)
} catch (e) {
reject(e)
socket.destroy()
return
}
const tlsSocket = tls.connect({ ca, servername, socket }, () => {
if (!tlsSocket.authorized) {
reject(new Error(tlsSocket.authorizationError))
} else {
const certificate = tlsSocket.getPeerCertificate(true)
resolve(certificate)
}
socket.destroy()
})
tlsSocket.on('error', (e) => {
reject(e)
socket.destroy()
})
}
)
if (timeout) {
socket.setTimeout(timeout, () => {
reject(new Error('Timeout connecting to server'))
socket.destroy()
})
}
socket.on('error', (e) => {
reject(e)
socket.destroy()
})
} catch (e) {
reject(e)
if (socket) socket.destroy()
}
})
}