import { SlashCommandBuilder, ChatInputCommandInteraction, EmbedBuilder, Message, inlineCode } from 'discord.js' import * as Freebox from '../../utils/freebox' import dbGuild from '../../schemas/guild' import crypto from 'crypto' import https from 'https' //import path from 'path' //import fs from 'fs' interface ReturnMsgData { status: string error_code?: string Title?: string Message?: string } function returnMsg(result: ReturnMsgData) { if (result.status === 'fail') return `La commande a échouée !\n${inlineCode(`${result.Title}: ${result.Message}`)}` if (result.status === 'error') return `Y'a eu une erreur !\n${inlineCode(`${result.error_code}`)}` } export default { data: new SlashCommandBuilder().setName('freebox').setDescription("Accéder à l'API FreeboxOS !") .addSubcommand(subcommand => subcommand.setName('import').setDescription("Envoyer un fichier d'autorité de certification.")) .addSubcommand(subcommand => subcommand.setName('version').setDescription("Afficher la version de l'API.")) .addSubcommand(subcommand => subcommand.setName('init').setDescription("Créer une app sur la Freebox pour s'authentifier.")) .addSubcommandGroup(subcommandGroup => subcommandGroup.setName('get').setDescription('Récupérer des données.') .addSubcommand(subcommand => subcommand.setName('connection').setDescription('Récupérer les informations de connexion.')) ), async execute(interaction: ChatInputCommandInteraction) { let guildProfile = await dbGuild.findOne({ guildId: interaction?.guild?.id }) if (!guildProfile) return interaction.reply({ content: `Database data for **${interaction.guild?.name}** does not exist, please initialize with \`/database init\` !` }) let dbData = guildProfile.get('guildFbx') if (!dbData?.enabled) return interaction.reply({ content: `Freebox module is disabled for **${interaction.guild?.name}**, please activate with \`/database edit guildFbx.enabled True\` !` }) let host = dbData.host as string if (!host) return interaction.reply({ content: `Freebox host is not set for **${interaction.guild?.name}**, please set with \`/database edit guildFbx.host \` !` }) let version = dbData.version as number if (!version) return interaction.reply({ content: `Freebox API version is not set for **${interaction.guild?.name}**, please set with \`/database edit guildFbx.version \` !` }) let httpsOptions = {} //let caCrt = fs.readFileSync(path.resolve(__dirname, '../../static/freebox-ecc-root-ca.crt')) // MIME Type : application/x-x509-ca-cert //if (caCrt) httpsOptions = { ca: caCrt } let httpsAgent = new https.Agent(httpsOptions) if (interaction.options.getSubcommand() === 'import') { let filter = (m: Message) => m.author.id === interaction.user.id await interaction.reply({ content: 'Please send another message with the CA file attached, you have one minute.', fetchReply: true }).then(async () => { console.log('waiting for message') await interaction.channel?.awaitMessages({ filter, time: 60_000, errors: ['time'] }).then(async collected => { console.log(collected) let message = collected.first() if (!message?.attachments.size) return interaction.followUp('No file was sent in your message!') let attachment = message.attachments.first() console.log(attachment) // Save the file to the database // TODO interaction.followUp(`File saved, you can now interact with your Freebox!`) }).catch(() => interaction.followUp('No message was sent before the time limit!')) }) } else if (interaction.options.getSubcommand() === 'version') { let result = await Freebox.Core.Version(host, httpsAgent) if (result.status === 'success') { let embed = new EmbedBuilder() embed.setTitle('FreeboxOS API Version') embed.setDescription(`Version: ${result.data.api_version}`) return await interaction.reply({ embeds: [embed] }) } else if (result.status === 'fail') return await interaction.reply({ content: `Failed to retrieve the API version: ${result.data}`, ephemeral: true }) else if (result.status === 'error') return await interaction.reply({ content: `An error occurred while retrieving the API version: ${result.data}`, ephemeral: true }) } else if (interaction.options.getSubcommand() === 'init') { await interaction.deferReply({ ephemeral: true }) let app = { app_id: 'fr.angels.bot_tamiseur', app_name: 'Bot Tamiseur', app_version: '2.3.0', device_name: 'Bot Discord NodeJS' } let result = await Freebox.Core.Init(host, version, httpsAgent, app, '') if (result.status === 'success') { let appToken = result.data.app_token let trackId = result.data.track_id let initCheck = setInterval(async () => { let result = await Freebox.Core.Init(host, version, httpsAgent, app, trackId) if (result.status !== 'success') return await interaction.followUp(returnMsg(result) as string) let status = result.data.status if (status === 'granted') { clearInterval(initCheck) let password_salt = result.data.password_salt if (!dbData) return dbData['appToken'] = appToken dbData['password_salt'] = password_salt if (!guildProfile) return guildProfile.set('guildFbx', dbData) guildProfile.markModified('guildFbx') await guildProfile.save().catch(console.error) return await interaction.followUp('Done !') } else if (status === 'denied') { clearInterval(initCheck) return await interaction.followUp('The user denied the app access to the Freebox.') } else if (status === 'pending') return }, 2000) } else return await interaction.followUp({ content: returnMsg(result) as string, ephemeral: true }) } else if (interaction.options.getSubcommandGroup() === 'get') { let appToken = dbData.appToken as string if (!appToken) return await interaction.reply({ content: `Freebox appToken is not set for **${interaction.guild?.name}**, please init the app with \`/freebox init\` !` }) console.log(appToken) let challengeData = await Freebox.Login.Challenge(host, version, httpsAgent) if (!challengeData) return await interaction.reply({ content: `Failed to retrieve the challenge for **${interaction.guild?.name}** !` }) let challenge = challengeData.data.challenge console.log(challenge) let password = crypto.createHmac('sha1', appToken).update(challenge).digest('hex') console.log(password) let session = await Freebox.Login.Session(host, version, httpsAgent, 'fr.angels.bot_tamiseur', password) if (!session) return await interaction.reply({ content: `Failed to retrieve the session for **${interaction.guild?.name}** !` }) let sessionToken = dbData['sessionToken'] = session.data.session_token guildProfile.set('guildFbx', dbData) guildProfile.markModified('guildFbx') await guildProfile.save().catch(console.error) if (interaction.options.getSubcommand() === 'connection') { let connection = await Freebox.Get.Connection(host, version, httpsAgent, sessionToken) if (!connection) return await interaction.reply({ content: `Failed to retrieve the connection details for **${interaction.guild?.name}** !` }) return await interaction.reply({ content: `Connection details for **${interaction.guild?.name}**:\n${inlineCode(JSON.stringify(connection))}` }) } } } }