initial version
						commit
						ae5b63f1ea
					
				|  | @ -0,0 +1,2 @@ | |||
| node_modules | ||||
| vybe.db | ||||
|  | @ -0,0 +1,68 @@ | |||
| # vybe websocket protocol - sent by client | ||||
| 
 | ||||
| socket.io actions + expected msg format and other info | ||||
| 
 | ||||
| all responses have same type as original message | ||||
| 
 | ||||
| if a message fails, you get a response with the following format: | ||||
| 
 | ||||
| ```json | ||||
| { | ||||
|   "success": false, | ||||
|   "message": "Something broke" | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| ## create_user | ||||
| 
 | ||||
| Message format: | ||||
| 
 | ||||
| ```json | ||||
| { | ||||
|   "name": "unique_username", | ||||
|   "pubkey": "your PGP public key" | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| Response format: | ||||
| 
 | ||||
| ```json | ||||
| { | ||||
|   "success": true, | ||||
|   "id": 123 | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| ## get_history | ||||
| 
 | ||||
| todo | ||||
| 
 | ||||
| ## send_message | ||||
| 
 | ||||
| Message format: | ||||
| 
 | ||||
| ```json | ||||
| { | ||||
|   "name": "unique_username", | ||||
|   "message": "signed message" | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| Response format: | ||||
| 
 | ||||
| ```json | ||||
| { | ||||
|   "success": true | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| # sent by server | ||||
| 
 | ||||
| ## new_message | ||||
| 
 | ||||
| ```json | ||||
| { | ||||
|   "name": "unique_username", | ||||
|   "message": "msg text" | ||||
| } | ||||
| ``` | ||||
|  | @ -0,0 +1,13 @@ | |||
| # vybe server | ||||
| 
 | ||||
| very very unfinished !! right now it can do a chatroom | ||||
| 
 | ||||
| ## setup | ||||
| 
 | ||||
| currently uses sqlite! install sqlite for your machine then do the following | ||||
| 
 | ||||
| ```bash | ||||
| sqlite3 vybe.db < db/1-init.sql | ||||
| ``` | ||||
| 
 | ||||
| then you can `yarn install` and `node index.js` | ||||
|  | @ -0,0 +1,14 @@ | |||
| const sqlite3 = require("sqlite3"); | ||||
| const db = new sqlite3.Database("./vybe.db"); | ||||
| 
 | ||||
| db.query = function (sql, params) { | ||||
|   var that = this; | ||||
|   return new Promise(function (resolve, reject) { | ||||
|     that.all(sql, params, function (error, rows) { | ||||
|       if (error) reject(error); | ||||
|       else resolve({ rows: rows }); | ||||
|     }); | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| module.exports = db; | ||||
|  | @ -0,0 +1,24 @@ | |||
| CREATE TABLE users ( | ||||
|   id integer primary key asc, | ||||
|   name text, | ||||
|   pubkey text, | ||||
|   created timestamp default current_timestamp | ||||
| ); | ||||
| 
 | ||||
| CREATE TABLE threads ( | ||||
|   id integer primary key asc, | ||||
|   created timestamp default current_timestamp | ||||
| ); | ||||
| 
 | ||||
| CREATE TABLE posts ( | ||||
|   id integer primary key asc, | ||||
|   user integer, | ||||
|   thread integer, | ||||
|   content text, | ||||
|   sig text, | ||||
|   created timestamp default current_timestamp, | ||||
|   foreign key(user) references users(id), | ||||
|   foreign key(thread) references threads(id) | ||||
| ); | ||||
| 
 | ||||
| INSERT INTO threads default values; | ||||
|  | @ -0,0 +1,26 @@ | |||
| const express = require("express"); | ||||
| const app = express(); | ||||
| const http = require("http"); | ||||
| const server = http.createServer(app); | ||||
| const { Server } = require("socket.io"); | ||||
| const io = new Server(server, { | ||||
|   cors: { | ||||
|     origin: ["http://localhost:8000", "http://192.168.1.199:8000"], | ||||
|   }, | ||||
| }); | ||||
| 
 | ||||
| const PORT = process.env.PORT || 3435; | ||||
| 
 | ||||
| const actions = require("./src/actions"); | ||||
| 
 | ||||
| io.on("connection", (socket) => { | ||||
|   for (let action in actions) { | ||||
|     socket.on(action, (msg) => | ||||
|       actions[action](msg, (response) => socket.emit(action, response), socket) | ||||
|     ); | ||||
|   } | ||||
| }); | ||||
| 
 | ||||
| server.listen(PORT, () => { | ||||
|   console.log("server running on port " + PORT); | ||||
| }); | ||||
|  | @ -0,0 +1,18 @@ | |||
| { | ||||
|   "name": "server", | ||||
|   "version": "1.0.0", | ||||
|   "description": "", | ||||
|   "main": "index.js", | ||||
|   "scripts": { | ||||
|     "test": "echo \"Error: no test specified\" && exit 1" | ||||
|   }, | ||||
|   "author": "", | ||||
|   "license": "ISC", | ||||
|   "dependencies": { | ||||
|     "cors": "^2.8.5", | ||||
|     "express": "^4.18.2", | ||||
|     "openpgp": "^5.8.0", | ||||
|     "socket.io": "^4.6.1", | ||||
|     "sqlite3": "^5.1.6" | ||||
|   } | ||||
| } | ||||
|  | @ -0,0 +1,9 @@ | |||
| const create_user = require("./create_user"); | ||||
| const get_history = require("./get_history"); | ||||
| const send_message = require("./send_message"); | ||||
| 
 | ||||
| module.exports = { | ||||
|   create_user, | ||||
|   get_history, | ||||
|   send_message, | ||||
| }; | ||||
|  | @ -0,0 +1,49 @@ | |||
| const db = require("../db"); | ||||
| const openpgp = require("openpgp"); | ||||
| 
 | ||||
| const create_user = async (msg, respond) => { | ||||
|   // validate inputs
 | ||||
|   if (!msg.name) { | ||||
|     return respond({ | ||||
|       success: false, | ||||
|       message: "Username required", | ||||
|     }); | ||||
|   } | ||||
|   // ensure username is not taken
 | ||||
|   const result = await db.query("select * from users where name = ?", [ | ||||
|     msg.name, | ||||
|   ]); | ||||
|   if (result.rows.length > 0) { | ||||
|     return respond({ | ||||
|       success: false, | ||||
|       message: "A user with this name already exists on this server", | ||||
|     }); | ||||
|   } | ||||
|   // validate public key
 | ||||
|   if (!msg.pubkey) { | ||||
|     return respond({ | ||||
|       success: false, | ||||
|       message: "Public key required", | ||||
|     }); | ||||
|   } | ||||
|   try { | ||||
|     await openpgp.readKey({ armoredKey: msg.pubkey }); | ||||
|   } catch (err) { | ||||
|     return respond({ | ||||
|       success: false, | ||||
|       message: "Public key invalid", | ||||
|     }); | ||||
|   } | ||||
|   // add to db
 | ||||
|   const insert = await db.query( | ||||
|     "insert into users (name, pubkey) values (?, ?) returning id", | ||||
|     [msg.name, msg.pubkey] | ||||
|   ); | ||||
|   // respond
 | ||||
|   return respond({ | ||||
|     success: true, | ||||
|     id: insert.rows[0].id, | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| module.exports = create_user; | ||||
|  | @ -0,0 +1,3 @@ | |||
| const get_history = async (msg) => {}; | ||||
| 
 | ||||
| module.exports = get_history; | ||||
|  | @ -0,0 +1,42 @@ | |||
| const db = require("../db"); | ||||
| const openpgp = require("openpgp"); | ||||
| 
 | ||||
| const send_message = async (msg, respond, socket) => { | ||||
|   // find user
 | ||||
|   const result = await db.query("select * from users where name = ?", [ | ||||
|     msg.name, | ||||
|   ]); | ||||
|   if (result.rows.length === 0) { | ||||
|     return respond({ | ||||
|       success: false, | ||||
|       message: "User not found", | ||||
|     }); | ||||
|   } | ||||
|   // validate signature
 | ||||
|   try { | ||||
|     const key = await openpgp.readKey({ armoredKey: result.rows[0].pubkey }); | ||||
|     const verification = await openpgp.verify({ | ||||
|       message: await openpgp.readCleartextMessage({ | ||||
|         cleartextMessage: msg.message, | ||||
|       }), | ||||
|       verificationKeys: key, | ||||
|       expectSigned: true, | ||||
|     }); | ||||
|     // add message and send it to everyone
 | ||||
|     await db.query( | ||||
|       "insert into posts (user, thread, content, sig) values (?, 1, ?, ?)", | ||||
|       [result.rows[0].id, verification.data, msg.message] | ||||
|     ); | ||||
|     socket.broadcast.emit("new_message", { | ||||
|       name: msg.name, | ||||
|       message: verification.data, | ||||
|     }); | ||||
|   } catch (err) { | ||||
|     return respond({ | ||||
|       success: false, | ||||
|       message: "Message signature verification failed", | ||||
|     }); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| module.exports = send_message; | ||||
		Loading…
	
		Reference in New Issue