mirror of
https://github.com/parabirb/freeremote-server.git
synced 2026-05-01 13:54:01 -04:00
init code shit
This commit is contained in:
commit
f979c4272d
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
config.js
|
||||
database.json
|
||||
10
LICENSE
Normal file
10
LICENSE
Normal file
@ -0,0 +1,10 @@
|
||||
Permission to use, copy, modify, and/or distribute this software for
|
||||
any purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL
|
||||
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE
|
||||
FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
|
||||
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
17
generateKeys.js
Normal file
17
generateKeys.js
Normal file
@ -0,0 +1,17 @@
|
||||
import { generateKey } from "openpgp";
|
||||
import config from "./config.json" with { type: "json" };
|
||||
|
||||
const { publicKey, privateKey } = await generateKey({
|
||||
curve: "ed25519",
|
||||
userIDs: [
|
||||
{
|
||||
name: config.clubName,
|
||||
email: config.clubEmail
|
||||
}
|
||||
],
|
||||
format: "armored"
|
||||
});
|
||||
|
||||
console.log(`Public key: ${JSON.stringify(publicKey)}
|
||||
|
||||
Private key: ${JSON.stringify(privateKey)}`);
|
||||
5
getAudioDevices.js
Normal file
5
getAudioDevices.js
Normal file
@ -0,0 +1,5 @@
|
||||
import audify from "audify";
|
||||
|
||||
const rtAudio = new audify.RtAudio();
|
||||
|
||||
console.log(rtAudio.getDevices())
|
||||
293
index.js
Normal file
293
index.js
Normal file
@ -0,0 +1,293 @@
|
||||
import ngrok from "ngrok";
|
||||
import audify from "audify";
|
||||
import xmlrpc from "xmlrpc";
|
||||
import * as ft8 from "ft8js";
|
||||
import config from "./config.js";
|
||||
import { Server } from "socket.io";
|
||||
import { JSONFilePreset } from "lowdb/node";
|
||||
import { SlashCommandBuilder } from "@discordjs/builders";
|
||||
import {
|
||||
readKey,
|
||||
readPrivateKey,
|
||||
readCleartextMessage,
|
||||
createCleartextMessage,
|
||||
sign,
|
||||
verify,
|
||||
} from "openpgp";
|
||||
import {
|
||||
REST,
|
||||
Routes,
|
||||
Client,
|
||||
AttachmentBuilder,
|
||||
GatewayIntentBits,
|
||||
} from "discord.js";
|
||||
|
||||
// get the db
|
||||
const db = await JSONFilePreset("database.json", { users: [] });
|
||||
|
||||
// read the pgp keys
|
||||
const publicKey = await readKey({ armoredKey: config.publicKey });
|
||||
const privateKey = await readPrivateKey({ armoredKey: config.privateKey });
|
||||
|
||||
// state
|
||||
let state = {
|
||||
transmitting: false,
|
||||
};
|
||||
|
||||
// xmlrpc clients
|
||||
const flrigClient = xmlrpc.createClient({
|
||||
host: "127.0.0.1",
|
||||
port: config.flrigPort,
|
||||
});
|
||||
const fldigiClient = xmlrpc.createClient({
|
||||
host: "127.0.0.1",
|
||||
port: config.fldigiPort,
|
||||
});
|
||||
|
||||
// shutdown function
|
||||
async function shutdown() {
|
||||
console.log("Shutting down...");
|
||||
}
|
||||
|
||||
// promisify callback
|
||||
function asyncRpc(client, method, params = []) {
|
||||
return new Promise((resolve) => {
|
||||
client.methodCall(method, params, (err, val) => {
|
||||
if (err) throw err;
|
||||
resolve(val);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// discord client
|
||||
const discordClient = new Client({
|
||||
intents: [GatewayIntentBits.Guilds],
|
||||
});
|
||||
|
||||
const addUserCommand = new SlashCommandBuilder()
|
||||
.setName("adduser")
|
||||
.setDescription("Add a user to the whitelist.")
|
||||
.addUserOption((option) =>
|
||||
option
|
||||
.setName("user")
|
||||
.setDescription("The user to whitelist.")
|
||||
.setRequired(true)
|
||||
)
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName("license")
|
||||
.setDescription("The type of license.")
|
||||
.setRequired(true)
|
||||
.addChoices(
|
||||
{
|
||||
name: "Amateur Extra",
|
||||
value: "extra",
|
||||
},
|
||||
{
|
||||
name: "General",
|
||||
value: "general",
|
||||
},
|
||||
{
|
||||
name: "Technician",
|
||||
value: "technician",
|
||||
}
|
||||
)
|
||||
)
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName("callsign")
|
||||
.setDescription("The callsign of the licensee.")
|
||||
.setRequired(true)
|
||||
);
|
||||
|
||||
const delUserCommand = new SlashCommandBuilder()
|
||||
.setName("deluser")
|
||||
.setDescription("Remove a user from the whitelist.")
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName("user")
|
||||
.setDescription("The ID of the user to be removed.")
|
||||
.setRequired(true)
|
||||
);
|
||||
|
||||
const requestKeyCommand = new SlashCommandBuilder()
|
||||
.setName("requestkey")
|
||||
.setDescription("Request a key to the remote station.");
|
||||
|
||||
const shutdownCommand = new SlashCommandBuilder()
|
||||
.setName("shutdown")
|
||||
.setDescription("Shut down the server.");
|
||||
|
||||
discordClient.on("interactionCreate", async (interaction) => {
|
||||
try {
|
||||
// return if not command
|
||||
if (!interaction.isCommand()) return;
|
||||
|
||||
// defer the reply so discord doesn't time out on us
|
||||
await interaction.deferReply({ ephemeral: true });
|
||||
|
||||
// get the command name
|
||||
const command = interaction.commandName;
|
||||
|
||||
// add user command
|
||||
if (command === "adduser") {
|
||||
// return if the user isn't an admin
|
||||
if (!config.admins.includes(interaction.user.id)) {
|
||||
await interaction.editReply({
|
||||
content: "You are not authorized to run this command!",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// get the user to be added :3
|
||||
const toAdd = interaction.options.getUser("user").id;
|
||||
|
||||
// return if the user to be added is already in the db
|
||||
if (
|
||||
db.data.users.filter((user) => user.id === toAdd).length !== 0
|
||||
) {
|
||||
await interaction.editReply({
|
||||
content: "This user is already in the whitelist!",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await db.update(({ users }) =>
|
||||
users.push({
|
||||
id: toAdd,
|
||||
callsign: interaction.options.getString("callsign"),
|
||||
license: interaction.options.getString("license"),
|
||||
logbook: [],
|
||||
})
|
||||
);
|
||||
|
||||
await interaction.editReply({
|
||||
content: "This user has been added to the whitelist.",
|
||||
});
|
||||
}
|
||||
// del user command
|
||||
else if (command === "deluser") {
|
||||
// return if the user isn't an admin
|
||||
if (!config.admins.includes(interaction.user.id)) {
|
||||
await interaction.editReply({
|
||||
content: "You are not authorized to run this command!",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// get the id of the user to be deleted
|
||||
const toDelete = db.data.users.find(
|
||||
(user) => user.id === interaction.options.getString("user")
|
||||
);
|
||||
|
||||
if (!toDelete) {
|
||||
await interaction.editReply({
|
||||
content: "User is not in the database.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await db.update(({ users }) =>
|
||||
users.splice(users.indexOf(toDelete), 1)
|
||||
);
|
||||
|
||||
await interaction.editReply({
|
||||
content: "User has been deleted from the whitelist.",
|
||||
});
|
||||
}
|
||||
// request key command
|
||||
else if (command === "requestkey") {
|
||||
// get the user requesting the thingy
|
||||
const user = db.data.users.find(
|
||||
(user) => user.id === interaction.user.id
|
||||
);
|
||||
|
||||
// return if user isn't in the db
|
||||
if (!user) {
|
||||
await interaction.editReply({
|
||||
content: "You are not in the whitelist.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const message = await createCleartextMessage({
|
||||
text: JSON.stringify({
|
||||
callsign: user.callsign,
|
||||
license: user.license,
|
||||
id: user.id,
|
||||
url: state.url,
|
||||
expiration: Date.now() + config.keyExpiry * 1000,
|
||||
}),
|
||||
});
|
||||
|
||||
const signed = await sign({
|
||||
message,
|
||||
signingKeys: privateKey,
|
||||
});
|
||||
|
||||
await interaction.editReply({
|
||||
content: "Below is your key.",
|
||||
files: [
|
||||
new AttachmentBuilder(Buffer.from(signed)).setName(
|
||||
`${user.callsign}-${Date.now()}.txt`
|
||||
),
|
||||
],
|
||||
});
|
||||
}
|
||||
// shutdown command
|
||||
else if (command === "shutdown") {
|
||||
// return if the user isn't an admin
|
||||
if (!config.admins.includes(interaction.user.id)) {
|
||||
await interaction.editReply({
|
||||
content: "You are not authorized to run this command!",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await interaction.editReply({
|
||||
content: "Shutting down."
|
||||
});
|
||||
|
||||
shutdown();
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
});
|
||||
|
||||
const rest = new REST().setToken(config.discordToken);
|
||||
|
||||
await rest.put(
|
||||
Routes.applicationGuildCommands(config.applicationId, config.guildId),
|
||||
{
|
||||
body: [
|
||||
addUserCommand,
|
||||
delUserCommand,
|
||||
requestKeyCommand,
|
||||
shutdownCommand,
|
||||
],
|
||||
}
|
||||
);
|
||||
|
||||
await discordClient.login(config.discordToken);
|
||||
|
||||
// socket.io server
|
||||
const io = new Server(config.port);
|
||||
|
||||
|
||||
|
||||
// connect ngrok!
|
||||
state.url = (
|
||||
await ngrok.connect({
|
||||
authtoken: config.ngrokToken,
|
||||
proto: "tcp",
|
||||
addr: config.port,
|
||||
onStatusChange: (status) => {
|
||||
if (status !== "connected") {
|
||||
console.log("Fuck");
|
||||
}
|
||||
},
|
||||
})
|
||||
).replace("tcp://", "");
|
||||
|
||||
console.log("remoteham is now up.");
|
||||
2623
package-lock.json
generated
Normal file
2623
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
34
package.json
Normal file
34
package.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "remoteham-server",
|
||||
"version": "1.0.0",
|
||||
"description": "the server for remoteham, an open source, radio-agnostic program for remote station control.",
|
||||
"homepage": "https://github.com/parabirb/remoteham-server#readme",
|
||||
"bugs": {
|
||||
"url": "https://github.com/parabirb/remoteham-server/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/parabirb/remoteham-server.git"
|
||||
},
|
||||
"license": "0BSD",
|
||||
"author": "parabirb",
|
||||
"type": "module",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "nodemon ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "^3.1.9"
|
||||
},
|
||||
"dependencies": {
|
||||
"@discordjs/builders": "^1.10.1",
|
||||
"audify": "^1.9.0",
|
||||
"discord.js": "^14.18.0",
|
||||
"ft8js": "^0.0.2",
|
||||
"lowdb": "^7.0.1",
|
||||
"ngrok": "^5.0.0-beta.2",
|
||||
"openpgp": "^6.1.0",
|
||||
"socket.io": "^4.8.1",
|
||||
"xmlrpc": "^1.3.2"
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user