Closes #7, closes #9, closes #12.

Rewrote the error handling module to check for object keys and report the correct error code associated with the failure, as well as includes default cases.
This commit is contained in:
Craine Runton 2016-06-17 14:20:56 -06:00
parent 2bad1fa923
commit 0500ae139b
7 changed files with 327 additions and 190 deletions

View File

@ -1,7 +1,7 @@
# tls-dashboard
A dashboard written in JavaScript & HTML to check the remaining time before a TLS certificate expires. A combination of a Node module and an HTML/CSS/JS webpage to display the info.
**Version:** 1.1.0
![version](https://img.shields.io/badge/version-1.2.0-brightgreen.svg?style=flat-square)
## Node Setup
### `node_app/config.js`
@ -34,8 +34,7 @@ To get the web service started on a remote server, you'll need to either move th
## Example
Take a look at a live example page [here on GitLab][1]. Screenshots below.
![Example dashboard](https://raw.githubusercontent.com/cmrunton/tls-dashboard/master/screenshot.png)
![Example dashboard](https://raw.githubusercontent.com/cmrunton/tls-dashboard/master/screenshot_2.png)
![Example dashboard](https://raw.githubusercontent.com/cmrunton/tls-dashboard/master/tls-dashboard.png)
## TODO
1. Database integration?

101
node_app/error_codes.md Normal file
View File

@ -0,0 +1,101 @@
# Expired Certificate
## Object keys
[ 'code' ]
e.code => CERT_HAS_EXPIRED
## Console output
{ Error: certificate has expired
at Error (native)
at TLSSocket.<anonymous> (_tls_wrap.js:1055:38)
at emitNone (events.js:86:13)
at TLSSocket.emit (events.js:185:7)
at TLSSocket._finishInit (_tls_wrap.js:580:8)
at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:412:38) code: 'CERT_HAS_EXPIRED' }
# Host Timeout
## Object keys
[ 'code' ]
e.code => ECONNRESET
## Console output
{ Error: socket hang up
at createHangUpError (_http_client.js:250:15)
at TLSSocket.socketCloseListener (_http_client.js:282:23)
at emitOne (events.js:101:20)
at TLSSocket.emit (events.js:188:7)
at TCP._handle.close [as _onclose] (net.js:492:12) code: 'ECONNRESET' }
# Connection refused
## Object keys
[ 'code', 'errno', 'syscall', 'address', 'port' ]
e.code => ECONNREFUSED
## Console output
{ Error: connect ECONNREFUSED 10.7.29.195:443
at Object.exports._errnoException (util.js:949:11)
at exports._exceptionWithHostPort (util.js:972:20)
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1080:14)
code: 'ECONNREFUSED',
errno: 'ECONNREFUSED',
syscall: 'connect',
address: '10.7.29.195',
port: 443 }
# Self-signed Certificate
## Object keys
[ 'code' ]
e.code => UNABLE_TO_VERIFY_LEAF_SIGNATURE
## Console output
{ Error: unable to verify the first certificate
at Error (native)
at TLSSocket.<anonymous> (_tls_wrap.js:1055:38)
at emitNone (events.js:86:13)
at TLSSocket.emit (events.js:185:7)
at TLSSocket._finishInit (_tls_wrap.js:580:8)
at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:412:38) code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE' }
# Incomplete Certificate Chain
## Object Keys
[ 'code' ]
e.code => UNABLE_TO_VERIFY_LEAF_SIGNATURE
## Console output
{ Error: unable to verify the first certificate
at Error (native)
at TLSSocket.<anonymous> (_tls_wrap.js:1055:38)
at emitNone (events.js:86:13)
at TLSSocket.emit (events.js:185:7)
at TLSSocket._finishInit (_tls_wrap.js:580:8)
at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:412:38) code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE' }
# Hostname Mismatch
## Object keys
[ 'reason', 'host', 'cert' ]
e.reason => Host: wrong.host.badssl.com. is not in the cert's altnames: DNS:*.badssl.com, DNS:badssl.com
## Console output
{ Error: Hostname/IP doesn't match certificate's altnames: "Host: wrong.host.badssl.com. is not in the cert's altnames: DNS:*.badssl.com, DNS:badssl.com"
at Object.checkServerIdentity (tls.js:203:15)
at TLSSocket.<anonymous> (_tls_wrap.js:1061:29)
at emitNone (events.js:86:13)
at TLSSocket.emit (events.js:185:7)
at TLSSocket._finishInit (_tls_wrap.js:580:8)
at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:412:38)
reason: 'Host: wrong.host.badssl.com. is not in the cert\'s altnames: DNS:*.badssl.com, DNS:badssl.com',
host: 'wrong.host.badssl.com.',
cert:
{ subject: { OU: [Object], CN: '*.badssl.com' },
issuer:
{ C: 'GB',
ST: 'Greater Manchester',
L: 'Salford',
O: 'COMODO CA Limited',
CN: 'COMODO RSA Domain Validation Secure Server CA' },
subjectaltname: 'DNS:*.badssl.com, DNS:badssl.com',
infoAccess: { 'CA Issuers - URI': [Object], 'OCSP - URI': [Object] },
modulus: 'C204ECF88CEE04C2B3D850D57058CC9318EB5CA86849B022B5F9959EB12B2C763E6CC04B604C4CEAB2B4C00F80B6B0F972C98602F95C415D132B7F71C44BBCE9942E5037A6671C618CF64142C546D31687279F74EB0A9D11522621736C844C7955E4D16BE8063D481552ADB328DBAAFF6EFF60954A776B39F124D131B6DD4DC0C4FC53B96D42ADB57CFEAEF515D23348E72271C7C2147A6C28EA374ADFEA6CB572B47E5AA216DC69B15744DB0A12ABDEC30F47745C4122E19AF91B93E6AD2206292EB1BA491C0C279EA3FB8BF7407200AC9208D98C5784538105CBE6FE6B5498402785C710BB7370EF6918410745557CF9643F3D2CC3A97CEB931A4C86D1CA85',
exponent: '0x10001',
valid_from: 'Apr 9 00:00:00 2015 GMT',
valid_to: 'Jul 7 23:59:59 2016 GMT',
fingerprint: 'C8:67:8E:DB:FD:BB:30:B5:3F:2D:7B:F9:66:B8:14:C6:2E:95:92:CE',
ext_key_usage: [ '1.3.6.1.5.5.7.3.1', '1.3.6.1.5.5.7.3.2' ],
serialNumber: '2FEB1825187C1A5086407B44E5B785A5',
raw: <Buffer 30 82 05 4b 30 82 04 33 a0 03 02 01 02 02 10 2f eb 18 25 18 7c 1a 50 86 40 7b 44 e5 b7 85 a5 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 81 90 31 ... > } }

View File

@ -64,91 +64,78 @@ function get_cert_parameters(element, index, array) {
req.on('error', function(e) {
// Increment the error count for the final output
errors++;
var parsed = {
'server': element,
'subject': {
'org': 'Unknown',
'common_name': '',
'sans': 'Unknown'
},
'issuer': {
'org': 'Unknown',
'common_name': ''
},
'info': {
'days_left': '',
'sort_order': 100000,
'background_class': ''
}
};
if (e.code ==='ECONNREFUSED') {
// The connection was refused by the server (ex. 443 not open, not resonding, etc.)
assert(false, 'Connection to '+element+' refused');
var parsed = {
'server': element,
'subject': {
'org': 'Unknown',
'common_name': 'Unknown',
'sans': 'Unknown'
},
'issuer': {
'org': 'Unknown',
'common_name': 'Last check connection refused'
},
'info': {
'days_left': '??'
}
if (e.hasOwnProperty('code')) {
switch (e.code) {
case 'CERT_HAS_EXPIRED':
assert(false, element+' certificate expired.');
parsed.subject.common_name = 'The certificate has expired';
parsed.issuer.common_name = e.code;
parsed.info.days_left = '0';
parsed.info.sort_order = 0;
parsed.info.background_class = 'danger';
break;
case 'ECONNRESET':
assert(false, element+' connection timed out or was reset.');
parsed.subject.common_name = 'The connection was reset by the server or timed out';
parsed.issuer.common_name = e.code;
parsed.info.days_left = '--';
parsed.info.background_class = 'info';
break;
case 'ECONNREFUSED':
assert(false, element+' connection refused by server.');
parsed.subject.common_name = 'The connection was refused by the remote server';
parsed.issuer.common_name = e.code;
parsed.info.days_left = '--';
parsed.info.background_class = 'info';
break;
case 'UNABLE_TO_VERIFY_LEAF_SIGNATURE':
assert(false, element+' self-signed or incomplete certificate chain.');
parsed.subject.common_name = 'The server provided a self-signed certificate or the provided certificate chain was incomplete';
parsed.issuer.common_name = e.code;
parsed.info.days_left = '--';
parsed.info.background_class = 'info';
break;
default:
assert(false, element+' unspecified error.');
parsed.subject.common_name = 'An unspecified error occured';
parsed.issuer.common_name = e.code;
parsed.info.days_left = '--';
parsed.info.background_class = 'info';
break;
};
add_cert_details(parsed, iteration);
check_iterations();
} else if (e.code ==='ECONNRESET') {
// The connection to the server timed out
assert(false, 'Connection to '+element+' timed out');
var parsed = {
'server': element,
'subject': {
'org': 'Unknown',
'common_name': 'Unknown',
'sans': 'Unknown'
},
'issuer': {
'org': 'Unknown',
'common_name': 'Last check timed out'
},
'info': {
'days_left': '??'
}
};
add_cert_details(parsed, iteration);
check_iterations();
} else if (e.reason.startsWith('Host: '+element+'. is not in the cert\'s altnames')) {
// There is a hostname mismatch between the cert and the server
assert(false, element+' had a hostname mismatch');
var parsed = {
'server': element,
'subject': {
'org': 'Unknown',
'common_name': 'Unknown',
'sans': 'Unknown'
},
'issuer': {
'org': 'Unknown',
'common_name': 'Hostname mismatch'
},
'info': {
'days_left': '??'
}
};
add_cert_details(parsed, iteration);
check_iterations();
} else {
var err = e;
// Catchall for all other errors to prevent the script bombing out
assert(false, 'Connection to '+element+' errored out');
var parsed = {
'server': element,
'subject': {
'org': 'Unknown',
'common_name': 'Unknown',
'sans': 'Unknown'
},
'issuer': {
'org': 'Unknown',
'common_name': ''
},
'info': {
'days_left': '??',
'common_name': 'Unspecified error'
}
};
add_cert_details(parsed, iteration);
check_iterations();
} else if (e.hasOwnProperty('reason')) {
switch (e.reason) {
default:
assert(false, element+' hostname mismatch.');
parsed.subject.common_name = 'There was mismatch between the requested hostname and the certificate presented by the server';
parsed.issuer.common_name = 'HOSTNAME_MISMATCH';
parsed.info.days_left = '--';
parsed.info.background_class = 'info';
break;
}
}
add_cert_details(parsed, iteration);
check_iterations();
})
// Set the timeout threshold for the https connection. Set in config.js, default 5000ms

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 KiB

BIN
tls-dashboard.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 KiB

View File

@ -1,6 +1,23 @@
var run_date = 'Tue May 24 2016';
var run_date = 'Fri Jun 17 2016';
var cert_info = {
"1": {
"server": "http-only.runtondev.com",
"subject": {
"org": "Unknown",
"common_name": "The connection was refused by the remote server",
"sans": "Unknown"
},
"issuer": {
"org": "Unknown",
"common_name": "ECONNREFUSED"
},
"info": {
"days_left": "--",
"sort_order": 100000,
"background_class": "info"
}
},
"2": {
"server": "www.google.com",
"subject": {
"org": "Google Inc",
@ -12,12 +29,100 @@ var cert_info = {
"common_name": "Google Internet Authority G2"
},
"info": {
"valid_from": "2016-05-18T10:59:02.000Z",
"valid_to": "2016-08-10T10:46:00.000Z",
"days_left": 77
"valid_from": "2016-06-08T12:37:29.000Z",
"valid_to": "2016-08-31T12:30:00.000Z",
"days_left": 75,
"sort_order": 75,
"background_class": "success"
}
},
"2": {
"3": {
"server": "expired.badssl.com",
"subject": {
"org": "Unknown",
"common_name": "The certificate has expired",
"sans": "Unknown"
},
"issuer": {
"org": "Unknown",
"common_name": "CERT_HAS_EXPIRED"
},
"info": {
"days_left": "0",
"sort_order": 0,
"background_class": "danger"
}
},
"4": {
"server": "incomplete-chain.badssl.com",
"subject": {
"org": "Unknown",
"common_name": "The server provided a self-signed certificate or the provided certificate chain was incomplete",
"sans": "Unknown"
},
"issuer": {
"org": "Unknown",
"common_name": "UNABLE_TO_VERIFY_LEAF_SIGNATURE"
},
"info": {
"days_left": "--",
"sort_order": 100000,
"background_class": "info"
}
},
"5": {
"server": "wrong.host.badssl.com",
"subject": {
"org": "Unknown",
"common_name": "There was mismatch between the requested hostname and the certificate presented by the server",
"sans": "Unknown"
},
"issuer": {
"org": "Unknown",
"common_name": "HOSTNAME_MISMATCH"
},
"info": {
"days_left": "--",
"sort_order": 100000,
"background_class": "info"
}
},
"6": {
"server": "self-signed.badssl.com",
"subject": {
"org": "Unknown",
"common_name": "The server provided a self-signed certificate or the provided certificate chain was incomplete",
"sans": "Unknown"
},
"issuer": {
"org": "Unknown",
"common_name": "UNABLE_TO_VERIFY_LEAF_SIGNATURE"
},
"info": {
"days_left": "--",
"sort_order": 100000,
"background_class": "info"
}
},
"7": {
"server": "sha256.badssl.com",
"subject": {
"common_name": "*.badssl.com",
"sans": "DNS:*.badssl.com, DNS:badssl.com"
},
"issuer": {
"org": "COMODO CA Limited",
"common_name": "COMODO RSA Domain Validation Secure Server CA"
},
"info": {
"valid_from": "2015-04-09T00:00:00.000Z",
"valid_to": "2016-07-07T23:59:59.000Z",
"days_left": 20,
"sort_order": 20,
"background_class": "danger"
}
},
"8": {
"server": "www.twitter.com",
"subject": {
"org": "Twitter, Inc.",
@ -31,117 +136,62 @@ var cert_info = {
"info": {
"valid_from": "2016-03-09T00:00:00.000Z",
"valid_to": "2018-03-14T12:00:00.000Z",
"days_left": 659
}
},
"3": {
"server": "news.ycombinator.com",
"subject": {
"common_name": "*.ycombinator.com",
"sans": "DNS:*.ycombinator.com, DNS:ycombinator.com"
},
"issuer": {
"org": "COMODO CA Limited",
"common_name": "COMODO RSA Domain Validation Secure Server CA"
},
"info": {
"valid_from": "2014-08-22T00:00:00.000Z",
"valid_to": "2019-08-21T23:59:59.000Z",
"days_left": 1184
}
},
"4": {
"server": "www.github.com",
"subject": {
"org": "GitHub, Inc.",
"common_name": "github.com",
"sans": "DNS:github.com, DNS:www.github.com"
},
"issuer": {
"org": "DigiCert Inc",
"common_name": "DigiCert SHA2 Extended Validation Server CA"
},
"info": {
"valid_from": "2016-03-10T00:00:00.000Z",
"valid_to": "2018-05-17T12:00:00.000Z",
"days_left": 723
}
},
"5": {
"server": "example.dev",
"subject": {
"org": "Unknown",
"common_name": "Unknown",
"sans": "Unknown"
},
"issuer": {
"org": "Unknown",
"common_name": "Last check timed out"
},
"info": {
"days_left": "??"
}
},
"6": {
"server": "example.dev",
"subject": {
"org": "Unknown",
"common_name": "Unknown",
"sans": "Unknown"
},
"issuer": {
"org": "Unknown",
"common_name": "Last check connection refused"
},
"info": {
"days_left": "??"
}
},
"7": {
"server": "danger.example.com",
"subject": {
"common_name": "danger.example.com",
"sans": "DNS:pma.logthecrux.com"
},
"issuer": {
"org": "Let's Encrypt",
"common_name": "Let's Encrypt Authority X3"
},
"info": {
"valid_from": "2016-05-17T18:15:00.000Z",
"valid_to": "2016-08-15T18:15:00.000Z",
"days_left": 15
}
},
"8": {
"server": "warning.example.com",
"subject": {
"common_name": "warning.example.com",
"sans": "DNS:pma.logthecrux.com"
},
"issuer": {
"org": "Let's Encrypt",
"common_name": "Let's Encrypt Authority X3"
},
"info": {
"valid_from": "2016-05-17T18:15:00.000Z",
"valid_to": "2016-08-15T18:15:00.000Z",
"days_left": 40
"days_left": 635,
"sort_order": 635,
"background_class": "success"
}
},
"9": {
"server": "mismatch.example.com",
"server": "nonexistent.runtondev.com",
"subject": {
"org": "Unknown",
"common_name": "Unknown",
"common_name": "The connection was reset by the server or timed out",
"sans": "Unknown"
},
"issuer": {
"org": "Unknown",
"common_name": "Hostname mismatch"
"common_name": "ECONNRESET"
},
"info": {
"days_left": "??"
"days_left": "--",
"sort_order": 100000,
"background_class": "info"
}
}
},
"10": {
"server": "warning.runtondev.com",
"subject": {
"common_name": "warning.runtondev.com",
"sans": ""
},
"issuer": {
"org": "Madeup CA",
"common_name": "CA that doesn't exist"
},
"info": {
"valid_from": "2015-04-09T00:00:00.000Z",
"valid_to": "2016-07-07T23:59:59.000Z",
"days_left": 45,
"sort_order": 45,
"background_class": "warning"
}
},
"11": {
"server": "danger.runtondev.com",
"subject": {
"common_name": "danger.runtondev.com",
"sans": ""
},
"issuer": {
"org": "Madeup CA",
"common_name": "CA that doesn't exist"
},
"info": {
"valid_from": "2015-04-09T00:00:00.000Z",
"valid_to": "2016-07-07T23:59:59.000Z",
"days_left": 1,
"sort_order": 1,
"background_class": "danger"
}
},
}