/* eslint-disable no-plusplus */ import cheerio from 'cheerio'; import axios, { AxiosError, AxiosResponse } from 'axios'; import { Message } from 'eris'; import { Client, Command, RichEmbed } from '../class'; interface TLSResponse { status: boolean, message?: string, subject: { commonName: string, organization: string[], organizationalUnit: string[], locality: string[], country: string[], }, issuer: { commonName: string, organization: string[], organizationalUnit: string[], locality: string[], country: string[], }, validationType: 'DV' | 'OV' | 'EV', signatureAlgorithm: string, publicKeyAlgorithm: string, serialNumber: number, keyUsage: number[], keyUsageAsText: ['CRL Signing'?, 'Certificate Signing'?, 'Content Commitment'?, 'Data Encipherment'?, 'Decipher Only'?, 'Digital Signature'?, 'Encipher Only'?, 'Key Agreement'?, 'Key Encipherment'?], extendedKeyUsage: number[], extendedKeyUsageAsText: ['All/Any Usages'?, 'TLS Web Server Authentication'?, 'TLS Web Client Authentication'?, 'Code Signing'?, 'E-mail Protection (S/MIME)'?], san: string[], fingerprint: string, connection: { cipherSuite: string, tlsVersion: 'SSLv3' | 'TLSv1' | 'TLSv1.1' | 'TLSv1.2' | 'TLSv1.3', }, } export default class TLS extends Command { constructor(client: Client) { super(client); this.name = 'tls'; this.description = 'Retrieves information about TLS and x509 configuration used by a site.'; this.usage = `${this.client.config.prefix}tls `; this.aliases = ['ssl', 'cert', 'certinfo', 'ci']; this.permissions = 2; this.guildOnly = true; this.enabled = true; } public async run(message: Message, args: string[]) { try { if (!args[0]) return this.client.commands.get('help').run(message, [this.name]); let r: AxiosResponse; let s: AxiosResponse; try { r = await axios.get(`https://certapi.libraryofcode.org?q=${args[0]}`); s = await axios.get(`https://${args[0]}`); } catch (err) { const error = err; return this.error(message.channel, `Unable to receive TLS information for this site. | ${error?.response?.data?.message ?? ''}`); } const resp: TLSResponse = r.data; const embed = new RichEmbed(); embed.setTitle('TLS Information'); embed.setColor('#4870fe'); try { const site = cheerio.load(s.data); let iconURI: string; try { await axios.get(`https://${args[0]}/favicon.ico`); iconURI = `https://${args[0]}/favicon.ico`; } catch { const att = site('link').toArray().filter((a) => a.attribs.rel === 'icon'); if (att?.length > 0) { if (att[0].attribs.href.startsWith('/')) { iconURI = `https://${args[0]}${att[0].attribs.href}`; } else { iconURI = att[0].attribs.href; } } } embed.setAuthor(site('title').text(), iconURI, `https://${args[0]}`); } catch { embed.setAuthor(`https://${args[0]}`, `https://${args[0]}/favicon.ico`, `https://${args[0]}`); } let subjectString = `**Common Name:** ${resp.subject.commonName}\n`; if (resp.subject.organization?.length > 0) subjectString += `**Organization:** ${resp.subject.organization[0]}\n`; if (resp.subject.organizationalUnit?.length > 0) subjectString += `**Organizational Unit:** ${resp.subject.organizationalUnit[0]}\n`; if (resp.subject.locality?.length > 0) subjectString += `**Locality:** ${resp.subject.locality[0]}\n`; if (resp.subject.country?.length > 0) subjectString += `**Country:** ${resp.subject.country[0]}`; embed.addField('Subject', subjectString, true); let issuerString = `**Common Name:** ${resp.subject.commonName}\n`; if (resp.issuer.organization?.length > 0) issuerString += `**Organization:** ${resp.issuer.organization[0]}\n`; if (resp.issuer.organizationalUnit?.length > 0) issuerString += `**Organizational Unit:** ${resp.issuer.organizationalUnit[0]}\n`; if (resp.issuer.locality?.length > 0) issuerString += `**Locality:** ${resp.issuer.locality[0]}\n`; if (resp.issuer.country?.length > 0) issuerString += `**Country:** ${resp.issuer.country[0]}`; embed.addField('Issuer', issuerString, true); embed.addBlankField(); let sanString = ''; for (let i = 0; i < resp.san.length; i++) { if (i >= 10) { sanString += '...'; break; } sanString += `${resp.san[i]}\n`; } embed.addField('Subject Alternative Names', sanString, true); embed.addBlankField(); embed.addField('Key Usage', resp.keyUsageAsText.join(', '), true); embed.addField('Extended Key Usage', resp.extendedKeyUsageAsText.join(', '), true); embed.addField('Validation Type', resp.validationType, true); embed.addBlankField(); embed.addField('Serial Number', String(resp.serialNumber), true); embed.addField('Fingerprint (SHA1)', resp.fingerprint, true); embed.addField('Signature Algorithm', resp.signatureAlgorithm, true); embed.addField('Public Key Algorithm', resp.publicKeyAlgorithm, true); embed.addBlankField(); embed.addField('TLS Cipher Suite', resp.connection.cipherSuite, true); embed.addField('TLS Version', resp.connection.tlsVersion, true); embed.setFooter(this.client.user.username, this.client.user.avatarURL); embed.setTimestamp(); return message.channel.createMessage({ embed }); } catch (err) { return this.client.util.handleError(err, message, this, false); } } }