From 08e9a4b6e9b0c6853c9327fe3ffc610c90cd3165 Mon Sep 17 00:00:00 2001 From: Matthew R Date: Thu, 24 Dec 2020 21:48:14 -0500 Subject: [PATCH] add tls command and updates to info --- src/commands/index.ts | 1 + src/commands/info.ts | 13 ++-- src/commands/tls.ts | 150 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 157 insertions(+), 7 deletions(-) create mode 100644 src/commands/tls.ts diff --git a/src/commands/index.ts b/src/commands/index.ts index 2f5f41f..cf37a6e 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -35,6 +35,7 @@ export { default as score } from './score'; export { default as stats } from './stats'; export { default as storemessages } from './storemessages'; export { default as sysinfo } from './sysinfo'; +export { default as tls } from './tls'; export { default as train } from './train'; export { default as tts } from './tts'; export { default as unban } from './unban'; diff --git a/src/commands/info.ts b/src/commands/info.ts index 17019df..5d72710 100644 --- a/src/commands/info.ts +++ b/src/commands/info.ts @@ -1,16 +1,13 @@ import { Message } from 'eris'; import { totalmem } from 'os'; import { Client, Command, RichEmbed } from '../class'; -import { version as erisVersion } from '../../node_modules/eris/package.json'; -import { version as expressVersion } from '../../node_modules/express/package.json'; -import { version as mongooseVersion } from '../../node_modules/mongoose/package.json'; import { version as tsVersion } from '../../node_modules/typescript/package.json'; export default class Info extends Command { constructor(client: Client) { super(client); this.name = 'info'; - this.description = 'System information.'; + this.description = 'Information about this application.'; this.usage = 'info'; this.permissions = 0; this.enabled = true; @@ -21,14 +18,16 @@ export default class Info extends Command { const embed = new RichEmbed(); embed.setTitle('Information'); embed.setThumbnail(this.client.user.avatarURL); + embed.setDescription(`*See \`${this.client.config.prefix}sysinfo\` for more information on libraries used by this application.*`); + embed.addField('Version', 'Rolling Release', true); embed.addField('Language(s)', '<:TypeScript:703451285789343774> TypeScript', true); embed.addField('Runtime', `Node (${process.version})`, true); embed.addField('Compilers/Transpilers', `TypeScript [tsc] (${tsVersion})`, true); - embed.addField('Discord Library', `Eris (${erisVersion})`, true); - embed.addField('HTTP Server Library', `Express (${expressVersion})`, true); - embed.addField('Database Library', `MongoDB w/ Mongoose ODM (${mongooseVersion})`, true); embed.addField('Memory Usage', `${Math.round(process.memoryUsage().rss / 1024 / 1024)} MB / ${Math.round(totalmem() / 1024 / 1024 / 1024)} GB`, true); embed.addField('Repository', 'https://loc.sh/crgit | Licensed under GNU Affero General Public License V3', true); + embed.addField('Branch', await this.client.util.exec('git branch --show-current'), true); + embed.addField('Commit SHA', await this.client.util.exec('git rev-parse --short HEAD'), true); + embed.addField('Commit Link', `https://gitlab.libraryofcode.org/engineering/communityrelations/-/commit/${await this.client.util.exec('git rev-parse HEAD')}`, true); embed.setFooter(this.client.user.username, this.client.user.avatarURL); embed.setTimestamp(); message.channel.createMessage({ embed }); diff --git a/src/commands/tls.ts b/src/commands/tls.ts new file mode 100644 index 0000000..3c7b062 --- /dev/null +++ b/src/commands/tls.ts @@ -0,0 +1,150 @@ +/* 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); + + return message.channel.createMessage({ embed }); + } catch (err) { + return this.client.util.handleError(err, message, this, false); + } + } +}