Fix transpiler + Ajout /freebox
This commit is contained in:
146
src/commands/global/freebox.ts
Normal file
146
src/commands/global/freebox.ts
Normal file
@@ -0,0 +1,146 @@
|
||||
import { SlashCommandBuilder, ChatInputCommandInteraction, EmbedBuilder, Message, inlineCode } from 'discord.js'
|
||||
import https from 'https'
|
||||
import crypto from 'crypto'
|
||||
//import path from 'path'
|
||||
//import fs from 'fs'
|
||||
|
||||
import * as Freebox from '../../utils/freebox'
|
||||
import dbGuild from '../../schemas/guild'
|
||||
|
||||
|
||||
function returnMsg(result: any) {
|
||||
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 <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 <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))}` })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
23
src/index.ts
23
src/index.ts
@@ -31,8 +31,27 @@ declare module 'discord.js' {
|
||||
|
||||
|
||||
// CLIENT INITIALIZATION
|
||||
let intents = [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers, GatewayIntentBits.GuildVoiceStates]
|
||||
const client = new Client({ intents })
|
||||
const client = new Client({ intents: [
|
||||
GatewayIntentBits.AutoModerationConfiguration,
|
||||
GatewayIntentBits.AutoModerationExecution,
|
||||
GatewayIntentBits.DirectMessageReactions,
|
||||
GatewayIntentBits.DirectMessageTyping,
|
||||
GatewayIntentBits.DirectMessages,
|
||||
GatewayIntentBits.GuildEmojisAndStickers,
|
||||
GatewayIntentBits.GuildIntegrations,
|
||||
GatewayIntentBits.GuildInvites,
|
||||
GatewayIntentBits.GuildMembers,
|
||||
GatewayIntentBits.GuildMessageReactions,
|
||||
GatewayIntentBits.GuildMessageTyping,
|
||||
GatewayIntentBits.GuildMessages,
|
||||
GatewayIntentBits.GuildModeration,
|
||||
GatewayIntentBits.GuildPresences,
|
||||
GatewayIntentBits.GuildScheduledEvents,
|
||||
GatewayIntentBits.GuildVoiceStates,
|
||||
GatewayIntentBits.GuildWebhooks,
|
||||
GatewayIntentBits.Guilds,
|
||||
GatewayIntentBits.MessageContent
|
||||
] })
|
||||
client.commands = new Collection()
|
||||
client.buttons = new Collection()
|
||||
|
||||
|
||||
@@ -33,6 +33,14 @@ const guildSchema = new Schema({
|
||||
username: { type: String, required: false },
|
||||
sessionID: { type: String, required: false },
|
||||
rememberMeToken: { type: String, required: false }
|
||||
},
|
||||
guildFbx: {
|
||||
enabled: { type: Boolean, required: true },
|
||||
host: { type: String, required: false },
|
||||
version: { type: Number, required: false },
|
||||
appToken: { type: String, required: false },
|
||||
sessionToken: { type: String, required: false },
|
||||
password_salt: { type: String, required: false }
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
15
src/static/freebox-ecc-root-ca.crt
Normal file
15
src/static/freebox-ecc-root-ca.crt
Normal file
@@ -0,0 +1,15 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICWTCCAd+gAwIBAgIJAMaRcLnIgyukMAoGCCqGSM49BAMCMGExCzAJBgNVBAYT
|
||||
AkZSMQ8wDQYDVQQIDAZGcmFuY2UxDjAMBgNVBAcMBVBhcmlzMRMwEQYDVQQKDApG
|
||||
cmVlYm94IFNBMRwwGgYDVQQDDBNGcmVlYm94IEVDQyBSb290IENBMB4XDTE1MDkw
|
||||
MTE4MDIwN1oXDTM1MDgyNzE4MDIwN1owYTELMAkGA1UEBhMCRlIxDzANBgNVBAgM
|
||||
BkZyYW5jZTEOMAwGA1UEBwwFUGFyaXMxEzARBgNVBAoMCkZyZWVib3ggU0ExHDAa
|
||||
BgNVBAMME0ZyZWVib3ggRUNDIFJvb3QgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNi
|
||||
AASCjD6ZKn5ko6cU5Vxh8GA1KqRi6p2GQzndxHtuUmwY8RvBbhZ0GIL7bQ4f08ae
|
||||
JOv0ycWjEW0fyOnAw6AYdsN6y1eNvH2DVfoXQyGoCSvXQNAUxla+sJuLGICRYiZz
|
||||
mnijYzBhMB0GA1UdDgQWBBTIB3c2GlbV6EIh2ErEMJvFxMz/QTAfBgNVHSMEGDAW
|
||||
gBTIB3c2GlbV6EIh2ErEMJvFxMz/QTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB
|
||||
/wQEAwIBhjAKBggqhkjOPQQDAgNoADBlAjA8tzEMRVX8vrFuOGDhvZr7OSJjbBr8
|
||||
gl2I70LeVNGEXZsAThUkqj5Rg9bV8xw3aSMCMQCDjB5CgsLH8EdZmiksdBRRKM2r
|
||||
vxo6c0dSSNrr7dDN+m2/dRvgoIpGL2GauOGqDFY=
|
||||
-----END CERTIFICATE-----
|
||||
32
src/static/freebox-root-ca.crt
Normal file
32
src/static/freebox-root-ca.crt
Normal file
@@ -0,0 +1,32 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFmjCCA4KgAwIBAgIJAKLyz15lYOrYMA0GCSqGSIb3DQEBCwUAMFoxCzAJBgNV
|
||||
BAYTAkZSMQ8wDQYDVQQIDAZGcmFuY2UxDjAMBgNVBAcMBVBhcmlzMRAwDgYDVQQK
|
||||
DAdGcmVlYm94MRgwFgYDVQQDDA9GcmVlYm94IFJvb3QgQ0EwHhcNMTUwNzMwMTUw
|
||||
OTIwWhcNMzUwNzI1MTUwOTIwWjBaMQswCQYDVQQGEwJGUjEPMA0GA1UECAwGRnJh
|
||||
bmNlMQ4wDAYDVQQHDAVQYXJpczEQMA4GA1UECgwHRnJlZWJveDEYMBYGA1UEAwwP
|
||||
RnJlZWJveCBSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA
|
||||
xqYIvq8538SH6BJ99jDlOPoyDBrlwKEp879oYplicTC2/p0X66R/ft0en1uSQadC
|
||||
sL/JTyfgyJAgI1Dq2Y5EYVT/7G6GBtVH6Bxa713mM+I/v0JlTGFalgMqamMuIRDQ
|
||||
tdyvqEIs8DcfGB/1l2A8UhKOFbHQsMcigxOe9ZodMhtVNn0mUyG+9Zgu1e/YMhsS
|
||||
iG4Kqap6TGtk80yruS1mMWVSgLOq9F5BGD4rlNlWLo0C3R10mFCpqvsFU+g4kYoA
|
||||
dTxaIpi1pgng3CGLE0FXgwstJz8RBaZObYEslEYKDzmer5zrU1pVHiwkjsgwbnuy
|
||||
WtM1Xry3Jxc7N/i1rxFmN/4l/Tcb1F7x4yVZmrzbQVptKSmyTEvPvpzqzdxVWuYi
|
||||
qIFSe/njl8dX9v5hjbMo4CeLuXIRE4nSq2A7GBm4j9Zb6/l2WIBpnCKtwUVlroKw
|
||||
NBgB6zHg5WI9nWGuy3ozpP4zyxqXhaTgrQcDDIG/SQS1GOXKGdkCcSa+VkJ0jTf5
|
||||
od7PxBn9/TuN0yYdgQK3YDjD9F9+CLp8QZK1bnPdVGywPfL1iztngF9J6JohTyL/
|
||||
VMvpWfS/X6R4Y3p8/eSio4BNuPvm9r0xp6IMpW92V8SYL0N6TQQxzZYgkLV7TbQI
|
||||
Hw6v64yMbbF0YS9VjS0sFpZcFERVQiodRu7nYNC1jy8CAwEAAaNjMGEwHQYDVR0O
|
||||
BBYEFD2erMkECujilR0BuER09FdsYIebMB8GA1UdIwQYMBaAFD2erMkECujilR0B
|
||||
uER09FdsYIebMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqG
|
||||
SIb3DQEBCwUAA4ICAQAZ2Nx8mWIWckNY8X2t/ymmCbcKxGw8Hn3BfTDcUWQ7GLRf
|
||||
MGzTqxGSLBQ5tENaclbtTpNrqPv2k6LY0VjfrKoTSS8JfXkm6+FUtyXpsGK8MrLL
|
||||
hZ/YdADTfbbWOjjD0VaPUoglvo2N4n7rOuRxVYIij11fL/wl3OUZ7GHLgL3qXSz0
|
||||
+RGW+1oZo8HQ7pb6RwLfv42Gf+2gyNBckM7VVh9R19UkLCsHFqhFBbUmqwJgNA2/
|
||||
3twgV6Y26qlyHXXODUfV3arLCwFoNB+IIrde1E/JoOry9oKvF8DZTo/Qm6o2KsdZ
|
||||
dxs/YcIUsCvKX8WCKtH6la/kFCUcXIb8f1u+Y4pjj3PBmKI/1+Rs9GqB0kt1otyx
|
||||
Q6bqxqBSgsrkuhCfRxwjbfBgmXjIZ/a4muY5uMI0gbl9zbMFEJHDojhH6TUB5qd0
|
||||
JJlI61gldaT5Ci1aLbvVcJtdeGhElf7pOE9JrXINpP3NOJJaUSueAvxyj/WWoo0v
|
||||
4KO7njox8F6jCHALNDLdTsX0FTGmUZ/s/QfJry3VNwyjCyWDy1ra4KWoqt6U7SzM
|
||||
d5jENIZChM8TnDXJzqc+mu00cI3icn9bV9flYCXLTIsprB21wVSMh0XeBGylKxeB
|
||||
S27oDfFq04XSox7JM9HdTt2hLK96x1T7FpFrBTnALzb7vHv9MhXqAT90fPR/8A==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -13,7 +13,8 @@ export default async (guild: Guild) => {
|
||||
disco: { enabled: false }
|
||||
},
|
||||
guildRss: { enabled: false, feeds: [] },
|
||||
guildAmp: { enabled: false }
|
||||
guildAmp: { enabled: false },
|
||||
guildFbx: { enabled: false }
|
||||
})
|
||||
await guildProfile.save().catch(console.error)
|
||||
return guildProfile
|
||||
|
||||
79
src/utils/freebox.ts
Normal file
79
src/utils/freebox.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import axios from 'axios'
|
||||
import https from 'https'
|
||||
|
||||
export interface App {
|
||||
app_id: string
|
||||
app_name: string
|
||||
app_version: string
|
||||
device_name: string
|
||||
}
|
||||
|
||||
export const Core = {
|
||||
async Version(host: string, httpsAgent: https.Agent) {
|
||||
let request = axios.get(host + '/api_version', { httpsAgent })
|
||||
|
||||
return await request.then(response => {
|
||||
if (response.status !== 200) return { status: 'fail', data: response.data }
|
||||
return { status: 'success', data: response.data }
|
||||
}).catch(error => {
|
||||
console.error(error)
|
||||
return { status: 'error', data: error }
|
||||
})
|
||||
},
|
||||
async Init(host: string, version: Number, httpsAgent: https.Agent, app: App, trackId: String) {
|
||||
let request
|
||||
|
||||
if (trackId) request = axios.get(host + `/api/v${version}/login/authorize/` + trackId, { httpsAgent })
|
||||
else request = axios.post(host + `/api/v${version}/login/authorize/`, app, { httpsAgent })
|
||||
|
||||
return await request.then(response => {
|
||||
if (!response.data.success) return { status: 'fail', data: response.data }
|
||||
return { status: 'success', data: response.data.result }
|
||||
}).catch(error => {
|
||||
console.error(error)
|
||||
return { status: 'error', data: error }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const Login = {
|
||||
async Challenge(host: string, version: Number, httpsAgent: https.Agent) {
|
||||
let request = axios.get(host + `/api/v${version}/login/`, { httpsAgent })
|
||||
|
||||
return await request.then(response => {
|
||||
console.log(response.data)
|
||||
if (response.status !== 200) return { status: 'fail', data: response.data }
|
||||
return { status: 'success', data: response.data.result }
|
||||
}).catch(error => {
|
||||
console.error(error)
|
||||
return { status: 'error', data: error }
|
||||
})
|
||||
},
|
||||
async Session(host: string, version: Number, httpsAgent: https.Agent, app_id: string, password: string) {
|
||||
let request = axios.post(host + `/api/v${version}/login/session/`, { app_id, password }, { httpsAgent })
|
||||
|
||||
return await request.then(response => {
|
||||
console.log(response.data)
|
||||
if (response.status !== 200) return { status: 'fail', data: response.data }
|
||||
return { status: 'success', data: response.data.result }
|
||||
}).catch(error => {
|
||||
console.error(error)
|
||||
return { status: 'error', data: error }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const Get = {
|
||||
async Connection(host: string, version: Number, httpsAgent: https.Agent, sessionToken: string) {
|
||||
let request = axios.get(host + `/api/v${version}/connection/`, { httpsAgent, headers: { 'X-Fbx-App-Auth': sessionToken } })
|
||||
|
||||
return await request.then(response => {
|
||||
console.log(response.data)
|
||||
if (!response.data.success) return { status: 'fail', data: response.data }
|
||||
return { status: 'success', data: response.data.result }
|
||||
}).catch(error => {
|
||||
console.error(error)
|
||||
return { status: 'error', data: error }
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user