first commit

This commit is contained in:
raven 2023-01-10 17:13:31 -05:00
commit 47f3f8a6cf
4 changed files with 237 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
node_modules
.env

48
README.md Normal file
View File

@ -0,0 +1,48 @@
# shChat Bridge
A Peer to Peer bridge between Discord and sshChat using [Hyper-Protocol](https://docs.holepunch.to/)
A high-level API for finding and connecting to peers who are interested in a "topic."
[@hyperswarm/dht](https://docs.holepunch.to/building-blocks/hyperswarm#dht):
A DHT powering Hyperswarm. Through this DHT, each server is bound to a unique key pair, with the client connecting to the server using the server's public key.
[@hyperswarm/secretstream](https://docs.holepunch.to/building-blocks/hyperswarm#secretstream):
Secretstream is used to securely create connections between two peers in Hyperswarm.
## What is HyperSwarm?
Hyperswarm allows you to find and connect to peers who are announcing a common "topic". The swarm topic can be anything. This means that, with Hyperswarm, you can discover and connect peers with a shared interest over a distributed network. As an example, we often use Hypercore's discovery key as the swarm topic for discovering peers to replicate with.
Once Hyperswarm has discovered peers, nodes in the DHT help those peers connect via a UDP-based hole-punching algorithm that's designed to work well in home networks.
https://docs.holepunch.to/building-blocks/hyperswarm
## Usage
To install:
`git clone git@git.codingvm.codes:snxraven/sshChatBridge.git`
`cd sshChatBridge`
`npm i`
To run a new topic (room):
`node bot.js`
This will log the bot into Discord.
To set a topic use the !set-topic command within the channel you wish to bridge.
The bot will provide a connection topic hash to connect to.
Once a peer connects all messages will be sent both ways.
!leave [TOPIC HASH] will destroy a topic bridge.

165
bot.js Normal file
View File

@ -0,0 +1,165 @@
const Discord = require('discord.js');
const Hyperswarm = require('hyperswarm');
const crypto = require('hypercore-crypto');
const { Client, GatewayIntentBits, Partials, messageLink } = require("discord.js");
const goodbye = require('graceful-goodbye')
require('dotenv').config()
const client = new Client({
'intents': [
GatewayIntentBits.DirectMessages,
GatewayIntentBits.MessageContent,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildBans,
GatewayIntentBits.GuildMessages
],
'partials': [Partials.Channel, Partials.Message, Partials.MessageContent]
});
const topicMap = new Map();
goodbye(() => {
for(let [channel_id, topic_obj] of topicMap)
{
topic_obj.swarm.destroy();
}
})
client.on('ready', () => {
console.log(`Logged in as ${client.user.tag}!`);
});
client.on('messageCreate', msg => {
if (msg.content.startsWith("!") && !msg.author.bot){
const args = msg.content.split(" ");
const cmd = args.shift().slice(1);
if (cmd === "current-topic") {
if(topicMap.has(msg.channel.id))
{
let topic_obj = topicMap.get(msg.channel.id);
msg.reply(`The current topic for this channel is: ${topic_obj.topic.toString('hex')}`);
}
else{
msg.reply(`No topic is assigned for this channel`);
}
}
if (cmd === "join-topic") {
if (!args[0]) {
msg.reply("Please provide a new topic in hexadecimal format");
return;
}
let topic = crypto.randomBytes(32);
let channel_id = args[1];
if(!channel_id)
{
msg.reply("Please provide a channel_id to send this topic's messages")
return;
}
//Check if the given channel_id exists or not.
if(!client.channels.cache.get(channel_id))
{
msg.reply("The provided channel id does not exist.");
return;
}
let swarm;
let conns =[];
if(topicMap.has(channel_id))
{
topic_obj = topicMap.get(channel_id);
swarm = topic_obj.swarm;
conns = topic_obj.conns;
}
else
{
swarm = new Hyperswarm();
topicMap.set(channel_id, {topic: topic, swarm: swarm, conns: conns});
// Join the new topic
swarm.join(topic, {
lookup: true,
announce: true,
timeout: 30000
});
swarm.on('connection', (conn, info) => {
console.log(`Connected to a peer for topic ${topic.toString('hex')}`);
conns.push(conn);
conn.on('data', data => {
// Send the message from the topic to the Discord channel
client.channels.fetch(channel_id).then(channel=>channel.send(data.toString()))
});
});
client.channels.fetch(channel_id).then(channel => {
msg.reply(`Successfully joined topic and sending messages to ${channel}`);
});
}
}
if (cmd === "set-topic") {
let channel_id = msg.channel.id;
//Check if the given channel_id exists or not.
if(!client.channels.cache.get(channel_id))
{
msg.reply("The provided channel id does not exist.");
return;
}
let topic = crypto.randomBytes(32);
let swarm;
let conns =[];
if(topicMap.has(channel_id))
{
topic_obj = topicMap.get(channel_id);
topic_obj.swarm.leave(topic_obj.topic);
topic_obj.topic = topic;
swarm = topic_obj.swarm;
conns = topic_obj.conns;
}
else{
swarm = new Hyperswarm();
conns = [];
topicMap.set(channel_id, {topic: topic, swarm: swarm, conns: conns});
// Join the new topic
swarm.join(topic, {
lookup: true,
announce: true,
timeout: 30000
});
swarm.on('connection', (conn, info) => {
console.log(`Connected to a peer for topic ${topic.toString('hex')}`);
conns.push(conn);
conn.on('data', data => {
// Send the message from the topic to the Discord channel
client.channels.fetch(channel_id).then(channel=>channel.send(data.toString()))
});
});
}
msg.reply(`Successfully set topic ${topic.toString('hex')} for channel ${channel_id}`);
}
if (cmd === "leave-topic") {
let channel_id = msg.channel.id;
let topic_obj = topicMap.get(channel_id);
if (topic_obj) {
topic_obj.swarm.leave(topic_obj.topic);
topicMap.delete(channel_id);
return msg.reply(`Successfully left topic ${topic_obj.topic.toString('hex')} for channel ${channel_id}`);
} else {
return msg.reply(`No topic is assigned for this channel`);
}
}
}
// Check if message is sent in a channel with a topic assigned and send it to the topic
if(topicMap.has(msg.channel.id) && !msg.author.bot){
let topic_obj = topicMap.get(msg.channel.id);
let conns = topic_obj.conns;
for (const conn of conns) {
conn.write(`${msg.author.username}(Discord): ${msg.content}`);
}
}
});
client.login(process.env.TOKEN);

22
package.json Normal file
View File

@ -0,0 +1,22 @@
{
"name": "ssh-chat-bridge",
"version": "1.0.0",
"description": "A bridge for Discord and sshchat",
"main": "bot.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git@git.codingvm.codes:snxraven/sshChatBridge.git"
},
"author": "",
"license": "ISC",
"dependencies": {
"discord.js": "^14.7.1",
"dotenv": "^16.0.3",
"graceful-goodbye": "^1.2.0",
"hypercore-crypto": "^3.3.1",
"hyperswarm": "^4.3.5"
}
}