Skip to content

Instantly share code, notes, and snippets.

@donpdonp
Last active June 28, 2023 16:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save donpdonp/75716e63d6fe5bab92c07c2fd77fecdd to your computer and use it in GitHub Desktop.
Save donpdonp/75716e63d6fe5bab92c07c2fd77fecdd to your computer and use it in GitHub Desktop.
gluon tls ssl checks
(function() {
setup()
return {name:"tls"}
})
var alert_channel = "#pdxbots"
var watchlist = {}
var key = "tls:watchlist"
function setup() {
scan("*", function(result){
result = result.filter(function(i,idx){return idx % 2 == 0})
bot.say(bot.admin_channel, "tls watchlist: "+JSON.stringify(result))
})
}
function go(msg) {
if (msg.method == "clocktower") {
var now = new Date(Date.parse(msg.params.time))
if (now.getMinutes() == 0 && now.getHours() == 6) {
//bot.say(bot.admin_channel, "!tls check "+now)
scan("*", function(result){
result.forEach(function(str, idx){
if(idx % 2 == 0) {
var parts = str.split(':')
var nick = parts[0]
var domain = parts[1]
var hostinfo = tls_check(domain, bot.admin_channel)
var remaining_days = (hostinfo.expires_at - (new Date()))/1000/60/60/24
if (remaining_days < 3) {
bot.say(alert_channel, nick+": "+domain+" cert expires in "+remaining_days.toFixed(1)+" days. (!tls)")
}
if (hostinfo.expired) {
bot.say(alert_channel, nick+": EXPIRED "+hostinfo.expired+" "+domain+" (!tls help)")
}
}
})
})
}
}
if (msg.method == "irc.privmsg") {
var cmd = /^!tls(\s+(\S+))?(\s+(.*))?/.exec(msg.params.message)
if(cmd) {
if(cmd[2]) {
if (cmd[2] == "add") {
bot.say(msg.params.channel, "watching: "+cmd[4])
add_host(msg.params.nick, cmd[4])
} else
if (cmd[2] == "del") {
bot.say(msg.params.channel, "unwatching: "+cmd[4])
del_host(msg.params.nick, cmd[4])
} else
if (cmd[2] == "check") {
nickscan(msg.params.nick, function(result){
Object.keys(result).forEach(function(hostname){
var hostinfo = tls_check(hostname, msg.params.channel)
bot.say(msg.params.channel, hostname+": "+hostwords(hostinfo))
})
})
} else
if (cmd[2] == "list") {
nickscan(msg.params.nick, function(result){
bot.say(msg.params.channel, msg.params.nick+": "+Object.keys(result).join(", "))
})
} else
if (cmd[2] == "help") {
say_help(msg.params.channel)
} else {
var hostinfo = tls_check(cmd[2], msg.params.channel)
bot.say(msg.params.channel, cmd[2]+": "+hostwords(hostinfo))
}
} else {
say_help(msg.params.channel)
}
}
}
}
function say_help(channel) {
bot.say(channel, "!tls [<domainname> | check | list | add <domainname> | del <domainname> ]")
}
function hostwords(hostinfo) {
var msg
if (hostinfo.expired) {
msg = "EXPIRED "+hostinfo.expired
} else if (hostinfo.error) {
msg = hostinfo.error.message
} else {
msg = hostinfo.tls_version+" "+ certFormat(hostinfo)
}
return msg
}
function tls_check(host, channel) {
var data = http.get({url:"https://"+host})
delete data.body // todo: http.head
var response = {}
if(data.error) {
if (data.error.message.indexOf('expired') >= 0) {
response.expired = data.error.message.slice(-20)
} else {
response.error = data.error
}
}
// {"tls":{"peer_certs":[{"dns_names":["*.donp.org","donp.org"],"not_after":"2023-07-30T09:00:30Z","not_before":"2023-05-01T09:00:31Z"},
if (data.tls) {
if(data.tls.version == 0x0304) { response.tls_version = "tls1.3" }
if(data.tls.version == 0x0303) { response.tls_version = "tls1.2" }
if(data.tls.version == 0x0302) { response.tls_version = "tls1.1" }
if (data.tls.peer_certs) {
if (data.tls.peer_certs.length > 0) {
var cert = data.tls.peer_certs[0]
response.expires_at = new Date(cert.not_after)
response.dns_names = cert.dns_names
}
} else {
bot.say(bot.admin_channel, "warning: no tls.peer_certs for "+host)
bot.say(bot.admin_channel, JSON.stringify(data))
}
}
return response
}
function certFormat(cert) {
var dns_names = JSON.stringify(cert.dns_names)
var now = new Date()
var expired = now > cert.expires_at
var remaining_days = (cert.expires_at - now)/1000/60/60/24
var exp_date_str = [cert.expires_at.getFullYear(), cert.expires_at.getMonth()+1, cert.expires_at.getDate() ].join('-')
return [(expired ? "EXPIRED " : "expires ")+exp_date_str,
remaining_days.toFixed(1)+" days", "dns_names "+dns_names ].join(' ')
}
function add_host(nick, hostname) {
var dbkey = [key, nick, hostname].join(':')
db.set(dbkey, "{}", function(){
})
}
function del_host(nick, hostname) {
var dbkey = [key, nick, hostname].join(':')
db.del(dbkey)
}
function load_host(nick, hostname, cb) {
var dbkey = [key, nick, hostname].join(':')
db.get(dbkey, cb)
}
function nickscan(nick, cb) {
scan(nick+":*", function(result){
var hosts = {}
result.forEach(function(r,idx){
if (idx % 2 == 0) {
hosts[r.substr(nick.length+1)] = result[idx+1]
}
})
cb(hosts)
})
}
function scan(match, cb, cursor, answers, loop) {
if(cursor == null) { cursor = 0; answers = []; loop = 1 }
loop = loop + 1
db.scan(cursor, key+':'+match, 100, function(result){
cursor = result[0]
answers = answers.concat(result[1])
var count = answers.length/2
if(cursor == 0) {
var short_answers = answers.map(function(a, idx){
if(idx % 2 == 0) {
return a.substr(key.length+1)
} else {
return JSON.parse(a)
}
})
cb(short_answers)
} else {
if(loop < 1500) {
scan(match, cb, cursor, answers, loop)
} else {
cb({error: "tls scan overload. stopping."})
}
}
})
}
function inspect(x) {
return (typeof x)+" "+JSON.stringify(x)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment