first commit
This commit is contained in:
commit
47f3f8a6cf
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
node_modules
|
||||||
|
.env
|
48
README.md
Normal file
48
README.md
Normal 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
165
bot.js
Normal 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
22
package.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user