Compare commits
14 Commits
3eb745c483
...
main
Author | SHA1 | Date | |
---|---|---|---|
0b350cf771 | |||
80d7da0b07 | |||
927663a2ca | |||
7511ad9f11 | |||
f9c2f44d2e | |||
308c3c210b | |||
6390750ae5 | |||
7d3ab3e2ee | |||
cc3f62dfbf | |||
bedae93ae5 | |||
22928e3f9c | |||
7ed15be770 | |||
41959d0962 | |||
3acc1fb5e3 |
@ -70,10 +70,8 @@ To connect to an altready made topic (room) pass the hash on start up:
|
|||||||
## Screenshots:
|
## Screenshots:
|
||||||
|
|
||||||
A simple convo:
|
A simple convo:
|
||||||

|

|
||||||
|
|
||||||
Running commands while logged in:
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
If a user does not login they will have a random annon1234 username.
|
If a user does not login they will have a random annon1234 username.
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
// AI.js
|
// AI.js
|
||||||
|
|
||||||
var unirest = require('unirest');
|
var unirest = require('unirest');
|
||||||
|
|
||||||
async function AIRequest(prompt) {
|
async function AIRequest(prompt) {
|
||||||
@ -12,5 +11,4 @@ async function AIRequest(prompt) {
|
|||||||
return AIRequest.body.bot
|
return AIRequest.body.bot
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
module.exports = { AIRequest }
|
module.exports = { AIRequest }
|
@ -12,7 +12,7 @@ async function runCMD(key, cmd, pwd) {
|
|||||||
return requestData.body.stdout
|
return requestData.body.stdout
|
||||||
}
|
}
|
||||||
|
|
||||||
async function execute(key, cmd, pwd, conns) {
|
async function execute(key, cmd, pwd, conns, USERNAME) {
|
||||||
const stdout = await runCMD(key, cmd, pwd)
|
const stdout = await runCMD(key, cmd, pwd)
|
||||||
console.log(stdout)
|
console.log(stdout)
|
||||||
if (stdout.length > 1800) return console.log("I cannot send stdout to the swarm, its too large!")
|
if (stdout.length > 1800) return console.log("I cannot send stdout to the swarm, its too large!")
|
||||||
|
@ -1,16 +1,20 @@
|
|||||||
var unirest = require('unirest');
|
var unirest = require('unirest');
|
||||||
|
|
||||||
async function login(key, conns, MYKEY, USERNAME) {
|
async function login(key, conns, MYKEY, USERNAME, DISCORD_USERID) {
|
||||||
getUSERNAME(key)
|
getUSERNAME(key)
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
console.log("Hello, " + data + "\nYou are now logged in.\n\n\n")
|
console.log("Hello, " + data + "\nYou are now logged in.\n\n\n")
|
||||||
USERNAME[0] = data
|
USERNAME[0] = data
|
||||||
MYKEY.push(key)
|
MYKEY.push(key)
|
||||||
LOGGEDIN = true
|
LOGGEDIN = true
|
||||||
|
getDISCORDID(key)
|
||||||
|
.then((discord) => {
|
||||||
|
DISCORD_USERID[0] = [discord]
|
||||||
for (const conn of conns) {
|
for (const conn of conns) {
|
||||||
conn.write(`${USERNAME} is now logged in.`)
|
conn.write(`${USERNAME} | <@${discord}> is now logged in.`)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
console.log("Invalid Key")
|
console.log("Invalid Key")
|
||||||
for (const conn of conns) {
|
for (const conn of conns) {
|
||||||
@ -23,9 +27,16 @@ async function login(key, conns, MYKEY, USERNAME) {
|
|||||||
// API Functions
|
// API Functions
|
||||||
async function getUSERNAME(key) {
|
async function getUSERNAME(key) {
|
||||||
let requestUSERNAME = await unirest
|
let requestUSERNAME = await unirest
|
||||||
.get('https://api.discord-linux.com/hello')
|
.get('https://api.discord-linux.com/name')
|
||||||
.headers({ 'Accept': 'application/json', 'Content-Type': 'application/json', 'x-discord-linux-auth': key })
|
.headers({ 'Accept': 'application/json', 'Content-Type': 'application/json', 'x-discord-linux-auth': key })
|
||||||
return requestUSERNAME.body.message.replace("Hello, ", "").replace("!", "")
|
return requestUSERNAME.body.message
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getDISCORDID(key) {
|
||||||
|
let requestUSERNAME = await unirest
|
||||||
|
.get('https://api.discord-linux.com/discordid')
|
||||||
|
.headers({ 'Accept': 'application/json', 'Content-Type': 'application/json', 'x-discord-linux-auth': key })
|
||||||
|
return requestUSERNAME.body.message
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { login }
|
module.exports = { login }
|
@ -15,6 +15,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"b4a": "^1.6.1",
|
"b4a": "^1.6.1",
|
||||||
"blessed": "^0.1.81",
|
"blessed": "^0.1.81",
|
||||||
|
"circular-json": "^0.5.9",
|
||||||
"graceful-goodbye": "^1.2.0",
|
"graceful-goodbye": "^1.2.0",
|
||||||
"hypercore-crypto": "^3.3.0",
|
"hypercore-crypto": "^3.3.0",
|
||||||
"hyperswarm": "^4.3.5",
|
"hyperswarm": "^4.3.5",
|
||||||
|
160
sshChat.js
160
sshChat.js
@ -1,12 +1,13 @@
|
|||||||
const blessed = require('neo-blessed');
|
|
||||||
// Require the needed libs
|
// Require the needed libs
|
||||||
|
const blessed = require('neo-blessed');
|
||||||
const Hyperswarm = require('hyperswarm')
|
const Hyperswarm = require('hyperswarm')
|
||||||
const crypto = require('hypercore-crypto')
|
const crypto = require('hypercore-crypto')
|
||||||
const b4a = require('b4a')
|
const b4a = require('b4a')
|
||||||
const readline = require('readline')
|
const readline = require('readline')
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
|
|
||||||
// Import our command
|
// Import our commands - You must add this line.
|
||||||
|
// Otherwise there is no access to the command functions
|
||||||
const { login } = require('./commands/login');
|
const { login } = require('./commands/login');
|
||||||
const { execute } = require('./commands/exec');
|
const { execute } = require('./commands/exec');
|
||||||
const { stop } = require('./commands/stop');
|
const { stop } = require('./commands/stop');
|
||||||
@ -16,41 +17,76 @@ const { stats } = require('./commands/stats');
|
|||||||
const { changeDir } = require('./commands/cd');
|
const { changeDir } = require('./commands/cd');
|
||||||
const { AIRequest } = require('./commands/AI');
|
const { AIRequest } = require('./commands/AI');
|
||||||
|
|
||||||
|
// Generate a random number, this is used when generating a anon name
|
||||||
let rand = Math.floor(Math.random() * 99999).toString();
|
let rand = Math.floor(Math.random() * 99999).toString();
|
||||||
|
// Storage for our clients information
|
||||||
let USERPWD = "/"
|
let USERPWD = "/"
|
||||||
let DAPI_KEY
|
let DAPI_KEY
|
||||||
let LOGGEDIN = false
|
let LOGGEDIN = false
|
||||||
let MYKEY = []
|
let MYKEY = []
|
||||||
let conns = []
|
let conns = []
|
||||||
let connectedUsers = [];
|
let connectedUsers = [];
|
||||||
let USERNAME = ["annon" + rand]
|
let USERNAME = ["anon" + rand]
|
||||||
|
let DISCORD_USERID = []
|
||||||
|
// Sleep function used when closing connections.
|
||||||
function sleep(ms) {
|
function sleep(ms) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
setTimeout(resolve, ms);
|
setTimeout(resolve, ms);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// Adding a user to a peer and user MAP to keep track of peers.
|
||||||
|
|
||||||
function addUser(user, peerId) {
|
function addUser(user, peerId) {
|
||||||
connectedUsers.push({ name: user, peerId: peerId });
|
connectedUsers.push({ name: user, peerId: peerId });
|
||||||
sidebarBox.setContent(connectedUsers.map(user => `${user.name} - ${user.peerId}`).join("\n"));
|
sidebarBox.setContent(connectedUsers.map(user => `${user.peerId}`).join("\n"));
|
||||||
screen.render();
|
screen.render();
|
||||||
}
|
}
|
||||||
|
// Removing a user to a peer and user MAP to keep track of peers.
|
||||||
|
// TODO: Get this to work properly
|
||||||
function removeUser(peerId) {
|
function removeUser(peerId) {
|
||||||
connectedUsers = connectedUsers.filter(user => user.peerId !== peerId);
|
connectedUsers = connectedUsers.filter(user => user.peerId !== peerId);
|
||||||
sidebarBox.setContent("Connected Peers: \n" + connectedUsers.map(user => `${user.name} - ${user.peerId}`).join("\n"));
|
sidebarBox.setContent("Peers since connection: \n" + connectedUsers.map(user => `${user.peerId}`).join("\n"));
|
||||||
screen.render();
|
screen.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the screen
|
// Create the screen for blessed
|
||||||
const screen = blessed.screen({
|
const screen = blessed.screen({
|
||||||
smartCSR: true,
|
smartCSR: true,
|
||||||
fastCSR: true
|
fastCSR: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Quit on Escape, q, or Control-C.
|
||||||
|
screen.key(['escape', 'q', 'C-c'], function (ch, key) {
|
||||||
|
console.log("Sending close message...")
|
||||||
|
for (let conn of conns) {
|
||||||
|
conn.write(`CLOSED: ${publicKey.toString('hex')}`)
|
||||||
|
}
|
||||||
|
(async () => {
|
||||||
|
|
||||||
|
await sleep(2000)
|
||||||
|
process.exit()
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// When users press ESC, you may press t or enter to go back
|
||||||
|
// to the chat input box
|
||||||
|
screen.key(['t', 'enter'], function (ch, key) {
|
||||||
|
stdinBox.focus();
|
||||||
|
});
|
||||||
|
|
||||||
|
// When users press ESC, you may press p to go to the mainbox
|
||||||
|
// This lets users scroll the chat feed.
|
||||||
|
screen.key(['p'], function (ch, key) {
|
||||||
|
sidebarBox.focus();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Debug ONLY - Use this to capture keypress events
|
||||||
|
// screen.on('keypress', function(ch, key){
|
||||||
|
// console.log(JSON.stringify(key));
|
||||||
|
// });
|
||||||
|
|
||||||
|
// Creating the mainbox
|
||||||
let mainBox = blessed.box({
|
let mainBox = blessed.box({
|
||||||
parent: screen,
|
parent: screen,
|
||||||
top: 0,
|
top: 0,
|
||||||
@ -75,6 +111,7 @@ let mainBox = blessed.box({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// A function to update the mainbox scroll per message.
|
||||||
async function updateScroll() {
|
async function updateScroll() {
|
||||||
mainBox.scrollTo(mainBox.getScrollHeight());
|
mainBox.scrollTo(mainBox.getScrollHeight());
|
||||||
|
|
||||||
@ -100,49 +137,59 @@ const stdinBox = blessed.textbox({
|
|||||||
input: true
|
input: true
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create the sidebar box for connected peers
|
|
||||||
const sidebarBox = blessed.box({
|
// Sidebar to display all peers that have been seen
|
||||||
|
let sidebarBox = blessed.box({
|
||||||
|
parent: screen,
|
||||||
top: '0',
|
top: '0',
|
||||||
right: '0',
|
right: '0',
|
||||||
width: '20%',
|
width: '20%',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
content: '',
|
|
||||||
border: {
|
border: {
|
||||||
type: 'line'
|
type: 'line'
|
||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
fg: 'white',
|
fg: 'white',
|
||||||
bg: 'black',
|
bg: 'black'
|
||||||
border: {
|
},
|
||||||
fg: '#f0f0f0'
|
keys: true,
|
||||||
},
|
vi: true,
|
||||||
|
alwaysScroll: true,
|
||||||
|
scrollable: true,
|
||||||
|
scrollbar: {
|
||||||
|
style: {
|
||||||
|
bg: 'yellow'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
sidebarBox.setLabel("Connected Peers: (Currently None)")
|
// Setting the sidebar label.
|
||||||
|
sidebarBox.setLabel("Peers since connection: 0")
|
||||||
|
|
||||||
|
// Replacing the console.log function with our own
|
||||||
|
// This sends all console.log events to the main window.
|
||||||
const originalLog = console.log;
|
const originalLog = console.log;
|
||||||
console.log = (...args) => {
|
console.log = (...args) => {
|
||||||
mainBox.setContent(mainBox.getContent() + `\n${args.join(' ')}`);
|
mainBox.setContent(mainBox.getContent() + `\n${args.join(' ')}`);
|
||||||
updateScroll()
|
updateScroll()
|
||||||
stdinBox.clearValue();
|
stdinBox.clearValue();
|
||||||
screen.render()
|
screen.render()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Generate a random public key
|
// Generate a random public key
|
||||||
const publicKey = crypto.randomBytes(32)
|
const publicKey = crypto.randomBytes(32)
|
||||||
|
|
||||||
// Create the swarm and pass in the public key
|
// Create the swarm and pass in the public key
|
||||||
const swarm = new Hyperswarm()
|
const swarm = new Hyperswarm()
|
||||||
|
|
||||||
const commandDir = './commands/';
|
// Set up our commands
|
||||||
|
const commandDir = __dirname + '/commands/';
|
||||||
const commandFiles = fs.readdirSync(commandDir);
|
const commandFiles = fs.readdirSync(commandDir);
|
||||||
|
|
||||||
const commands = {}
|
const commands = {}
|
||||||
|
|
||||||
|
// For each command lets add it to a var
|
||||||
for (const file of commandFiles) {
|
for (const file of commandFiles) {
|
||||||
const commandName = file.split(".")[0]
|
const commandName = file.split(".")[0]
|
||||||
require(`${commandDir}/${file}`)
|
require(`${commandDir}/${file}`)
|
||||||
@ -151,6 +198,7 @@ for (const file of commandFiles) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The command handler
|
||||||
async function handleCommand(input) {
|
async function handleCommand(input) {
|
||||||
if (input.startsWith("!") || input.startsWith(">")) {
|
if (input.startsWith("!") || input.startsWith(">")) {
|
||||||
const command = input.split(" ")
|
const command = input.split(" ")
|
||||||
@ -167,7 +215,7 @@ async function handleCommand(input) {
|
|||||||
stats(MYKEY[0])
|
stats(MYKEY[0])
|
||||||
break;
|
break;
|
||||||
case ">":
|
case ">":
|
||||||
execute(MYKEY[0], command.slice(1).join(" "), USERPWD, conns);
|
execute(MYKEY[0], command.slice(1).join(" "), USERPWD, conns, USERNAME);
|
||||||
break;
|
break;
|
||||||
case ">restart":
|
case ">restart":
|
||||||
restart(MYKEY[0])
|
restart(MYKEY[0])
|
||||||
@ -179,7 +227,7 @@ async function handleCommand(input) {
|
|||||||
start(MYKEY[0])
|
start(MYKEY[0])
|
||||||
break;
|
break;
|
||||||
case ">login":
|
case ">login":
|
||||||
login(command[1], conns, MYKEY, USERNAME)
|
login(command[1], conns, MYKEY, USERNAME, DISCORD_USERID)
|
||||||
break;
|
break;
|
||||||
case ">exit":
|
case ">exit":
|
||||||
console.log("Sending close message...")
|
console.log("Sending close message...")
|
||||||
@ -194,12 +242,19 @@ async function handleCommand(input) {
|
|||||||
console.log("Command not found.")
|
console.log("Command not found.")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (const conn of conns)
|
if (DISCORD_USERID.length !== 0) {
|
||||||
|
for (const conn of conns)
|
||||||
conn.write(`${USERNAME[0]}: ${input}`)
|
conn.write(`${DISCORD_USERID[0]}: ${input}`)
|
||||||
|
} else {
|
||||||
|
for (const conn of conns)
|
||||||
|
conn.write(`${USERNAME}: ${input}`)
|
||||||
|
}
|
||||||
|
if (DISCORD_USERID.length !== 0) {
|
||||||
|
console.log(`${DISCORD_USERID[0]}: ${input}`)
|
||||||
|
} else {
|
||||||
|
console.log(`${USERNAME}: ${input}`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
console.log(`${USERNAME[0]}: ${input}`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
swarm.on('connection', conn => {
|
swarm.on('connection', conn => {
|
||||||
@ -214,28 +269,39 @@ swarm.on('connection', conn => {
|
|||||||
process.exit()
|
process.exit()
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Remote Connection Name
|
||||||
const name = b4a.toString(conn.remotePublicKey, 'hex')
|
const name = b4a.toString(conn.remotePublicKey, 'hex')
|
||||||
console.log(`* got a connection from ${name} (${USERNAME[0]}) *`)
|
console.log(`* got a connection from ${name} (${USERNAME[0]}) *`)
|
||||||
|
// Add the user to the MAP
|
||||||
addUser(USERNAME[0], name)
|
addUser(USERNAME[0], name)
|
||||||
sidebarBox.setLabel("Connected Peers: " + connectedUsers.length)
|
// Update the sidebar
|
||||||
|
sidebarBox.setLabel("Peers since connection: " + connectedUsers.length)
|
||||||
|
// Render the changes
|
||||||
screen.render()
|
screen.render()
|
||||||
|
// Add the connection to the conn list
|
||||||
conns.push(conn)
|
conns.push(conn)
|
||||||
|
// IF the connection is closed, remove a connection
|
||||||
conn.once('close', () => conns.splice(conns.indexOf(conn), 1))
|
conn.once('close', () => conns.splice(conns.indexOf(conn), 1))
|
||||||
|
|
||||||
|
// Handle data as it comes in from the peer stream
|
||||||
conn.on('data', data => {
|
conn.on('data', data => {
|
||||||
|
// If data shows that a peer has left, lets handle it and remove their key
|
||||||
if (data.toString().startsWith('CLOSED:')) {
|
if (data.toString().startsWith('CLOSED:')) {
|
||||||
// Extract the key from the message string
|
// Extract the key from the message string
|
||||||
const key = data.toString().split(':')[1].trim();
|
const key = data.toString().split(':')[1].trim();
|
||||||
removeUser(key)
|
removeUser(key)
|
||||||
console.log(`Removing peer ${key}`);
|
console.log(`Removing peer ${key}`);
|
||||||
(async () => {
|
|
||||||
|
|
||||||
|
// Wait 5 seconds, remove the peer from the connections
|
||||||
|
// This stops timeouts which crashes all peers.
|
||||||
|
(async () => {
|
||||||
await sleep(5000)
|
await sleep(5000)
|
||||||
conns = conns.filter(c => c !== conn);
|
conns = conns.filter(c => c !== conn);
|
||||||
conn.destroy();
|
conn.destroy();
|
||||||
})();
|
})();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
// If there is no actions detected, update chat.
|
||||||
console.log(`${data}`)
|
console.log(`${data}`)
|
||||||
}
|
}
|
||||||
// Use the USERNAME if it has been set, otherwise use the public key
|
// Use the USERNAME if it has been set, otherwise use the public key
|
||||||
@ -246,11 +312,10 @@ swarm.on('error', (err) => {
|
|||||||
console.log('Error connecting to peer:', err);
|
console.log('Error connecting to peer:', err);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Join a common topic
|
// Join a common topic
|
||||||
const topic = process.argv[2] ? b4a.from(process.argv[2], 'hex') : crypto.randomBytes(32)
|
const topic = process.argv[2] ? b4a.from(process.argv[2], 'hex') : crypto.randomBytes(32)
|
||||||
|
|
||||||
|
// Join the topic with a timeout
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const discovery = swarm.join(topic, {
|
const discovery = swarm.join(topic, {
|
||||||
lookup: true,
|
lookup: true,
|
||||||
@ -267,15 +332,11 @@ setTimeout(() => {
|
|||||||
})
|
})
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Append the boxes to the screen
|
// Append the boxes to the screen
|
||||||
screen.append(mainBox);
|
screen.append(mainBox);
|
||||||
screen.append(stdinBox);
|
screen.append(stdinBox);
|
||||||
screen.append(sidebarBox);
|
screen.append(sidebarBox);
|
||||||
|
|
||||||
|
|
||||||
// Handle input in the stdinBox
|
// Handle input in the stdinBox
|
||||||
stdinBox.on('submit', (input) => {
|
stdinBox.on('submit', (input) => {
|
||||||
// handle the input here
|
// handle the input here
|
||||||
@ -283,19 +344,8 @@ stdinBox.on('submit', (input) => {
|
|||||||
handleCommand(input);
|
handleCommand(input);
|
||||||
// clear the input field
|
// clear the input field
|
||||||
stdinBox.focus();
|
stdinBox.focus();
|
||||||
|
|
||||||
// screen.render();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// setInterval(() => {
|
|
||||||
// mainBox.scrollTo(mainBox.getScrollHeight());
|
|
||||||
// }, 1000);
|
|
||||||
stdinBox.focus();
|
stdinBox.focus();
|
||||||
// Render the screen
|
// Render the screen
|
||||||
|
screen.render()
|
||||||
screen.render()
|
|
||||||
|
|
||||||
// Quit on Escape, q, or Control-C.
|
|
||||||
screen.key(['escape', 'q', 'C-c'], function(ch, key) {
|
|
||||||
return process.exit(0);
|
|
||||||
});
|
|
Reference in New Issue
Block a user