reorganized source files
							parent
							
								
									b3ae3f8a78
								
							
						
					
					
						commit
						b3c461f394
					
				
							
								
								
									
										28
									
								
								db.js
								
								
								
								
							
							
						
						
									
										28
									
								
								db.js
								
								
								
								
							|  | @ -1,28 +0,0 @@ | |||
| const sqlite3 = require("sqlite3"); | ||||
| const fs = require("fs"); | ||||
| 
 | ||||
| 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 }); | ||||
|     }); | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| (async () => { | ||||
|   if (!fs.existsSync("vybe.db")) { | ||||
|     for (let sql of fs | ||||
|       .readFileSync("db/1-init.sql") | ||||
|       .toString() | ||||
|       .split(";") | ||||
|       .filter((x) => x)) { | ||||
|       await db.query(sql); | ||||
|     } | ||||
|   } | ||||
| })(); | ||||
| 
 | ||||
| module.exports = db; | ||||
							
								
								
									
										18
									
								
								index.js
								
								
								
								
							
							
						
						
									
										18
									
								
								index.js
								
								
								
								
							|  | @ -1,22 +1,16 @@ | |||
| const fs = require('fs'); | ||||
| const express = require('express'); | ||||
| const http = require('http'); | ||||
| const { Server } = require('socket.io'); | ||||
| const compression = require('compression'); | ||||
| 
 | ||||
| const events = Object.fromEntries( | ||||
| 	[ | ||||
| 		'authenticate', | ||||
| 		'create_thread', | ||||
| 		'create_user', | ||||
| 		'get_history', | ||||
| 		'get_keys', | ||||
| 		'get_space', | ||||
| 		'list_threads', | ||||
| 		'save_span', | ||||
| 		'send_message' | ||||
| 	].map(event => [event, require('./src/' + event)]) | ||||
| 	fs.readdirSync('./src/event') | ||||
| 		.map(event => [event.slice(0, -3), require('./src/event/' + event)]) | ||||
| ); | ||||
| 
 | ||||
| const PORT = process.env.PORT || 3435; | ||||
| 
 | ||||
| const app = express(); | ||||
| app.use(compression()); | ||||
| const server = http.createServer(app); | ||||
|  | @ -26,8 +20,6 @@ const io = new Server(server, { | |||
| 	}, | ||||
| }); | ||||
| 
 | ||||
| const PORT = process.env.PORT || 3435; | ||||
| 
 | ||||
| io.cache = {}; | ||||
| 
 | ||||
| io.on('connection', (socket) => { | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| const db = require("../db"); | ||||
| const db = require('./db'); | ||||
| 
 | ||||
| const authwrap = (fn) => async (msg, respond, socket, io) => { | ||||
| 	if (!respond) | ||||
|  | @ -6,7 +6,7 @@ const authwrap = (fn) => async (msg, respond, socket, io) => { | |||
| 	if (!msg || !msg.__session) { | ||||
| 		return respond({ | ||||
| 			success: false, | ||||
| 			message: "Not authenticated", | ||||
| 			message: 'not authenticated', | ||||
| 		}); | ||||
| 	} | ||||
| 	const result = await db.query( | ||||
|  | @ -18,7 +18,7 @@ const authwrap = (fn) => async (msg, respond, socket, io) => { | |||
| 	if (result.rows.length === 0) { | ||||
| 		return respond({ | ||||
| 			success: false, | ||||
| 			message: "User not found", | ||||
| 			message: 'user not found', | ||||
| 		}); | ||||
| 	} | ||||
| 	return await fn({ ...msg, auth_user: result.rows[0] }, respond, socket, io); | ||||
|  |  | |||
|  | @ -1,15 +1,15 @@ | |||
| const db = require("../../db"); | ||||
| const db = require('./db'); | ||||
| 
 | ||||
| const check_permission = async (user_id, thread_id) => { | ||||
| 	// get all the permissions for the thread
 | ||||
| 	const permissions = await db.query( | ||||
| 		"select * from permission where thread = ?", | ||||
| 		'select * from permission where thread = ?', | ||||
| 		[thread_id] | ||||
| 	); | ||||
| 	// check if the user is a member
 | ||||
| 	const is_member = | ||||
| 		( | ||||
| 			await db.query("select * from member where thread = ? and user = ?", [ | ||||
| 			await db.query('select * from member where thread = ? and user = ?', [ | ||||
| 				thread_id, | ||||
| 				user_id, | ||||
| 			]) | ||||
|  | @ -19,18 +19,18 @@ const check_permission = async (user_id, thread_id) => { | |||
| 			(i) => i.permission === permission | ||||
| 		); | ||||
| 		for (let i of relevant) { | ||||
| 			if (i.type === "everyone" && i.value === "true") { | ||||
| 			if (i.type === 'everyone' && i.value === 'true') { | ||||
| 				return true; | ||||
| 			} | ||||
| 			if (i.type === "members" && i.value === "true" && is_member) { | ||||
| 			if (i.type === 'members' && i.value === 'true' && is_member) { | ||||
| 				return true; | ||||
| 			} | ||||
| 		} | ||||
| 	}; | ||||
| 	return { | ||||
| 		is_member, | ||||
| 		view: get_permission("view"), | ||||
| 		post: get_permission("post") | ||||
| 		view: get_permission('view'), | ||||
| 		post: get_permission('post') | ||||
| 	}; | ||||
| }; | ||||
| 
 | ||||
|  | @ -0,0 +1,28 @@ | |||
| const sqlite3 = require('sqlite3'); | ||||
| const fs = require('fs'); | ||||
| 
 | ||||
| const dbPath = 'vybe.db'; | ||||
| 
 | ||||
| const db = new sqlite3.Database(dbPath); | ||||
| 
 | ||||
| db.query = function (sql, params) { | ||||
| 	let self = this; | ||||
| 	return new Promise((resolve, reject) => { | ||||
| 		self.all(sql, params, (error, rows) => { | ||||
| 			if (error) | ||||
| 				reject(error); | ||||
| 			else | ||||
| 				resolve({ rows: rows }); | ||||
| 		}); | ||||
| 	}); | ||||
| }; | ||||
| 
 | ||||
| (async () => { | ||||
| 	if (fs.existsSync(dbPath)) | ||||
| 		return; | ||||
| 	for (let sql of fs.readFileSync('./db/1-init.sql').toString().split(';')) | ||||
| 		if (sql) | ||||
| 			await db.query(sql); | ||||
| })(); | ||||
| 
 | ||||
| module.exports = db; | ||||
|  | @ -1,20 +1,20 @@ | |||
| const db = require("../db"); | ||||
| const openpgp = require("openpgp"); | ||||
| const db = require('../db'); | ||||
| const openpgp = require('openpgp'); | ||||
| 
 | ||||
| const authenticate = async (msg, respond, socket, io) => { | ||||
| 	if (!msg.name || !msg.message) { | ||||
| 		return respond({ | ||||
| 			success: false, | ||||
| 			message: "Invalid message", | ||||
| 			message: 'invalid message' | ||||
| 		}); | ||||
| 	} | ||||
| 	const result = await db.query("select * from user where name = ?", [ | ||||
| 		msg.name, | ||||
| 	const result = await db.query('select * from user where name = ?', [ | ||||
| 		msg.name | ||||
| 	]); | ||||
| 	if (result.rows.length === 0) { | ||||
| 		return respond({ | ||||
| 			success: false, | ||||
| 			message: "User not found", | ||||
| 			message: 'user not found' | ||||
| 		}); | ||||
| 	} | ||||
| 	try { | ||||
|  | @ -24,23 +24,23 @@ const authenticate = async (msg, respond, socket, io) => { | |||
| 				cleartextMessage: msg.message, | ||||
| 			}), | ||||
| 			verificationKeys: key, | ||||
| 			expectSigned: true, | ||||
| 			expectSigned: true | ||||
| 		}); | ||||
| 		const data = verification.data.split(" "); | ||||
| 		if (data[0] !== "vybe_auth") { | ||||
| 		const data = verification.data.split(' '); | ||||
| 		if (data[0] !== 'vybe_auth') { | ||||
| 			return respond({ | ||||
| 				success: false, | ||||
| 				message: "Bad auth message", | ||||
| 				message: 'bad auth message' | ||||
| 			}); | ||||
| 		} | ||||
| 		const auths = await db.query( | ||||
| 			"select * from authentication where user = ? and salt = ?", | ||||
| 			'select * from authentication where user = ? and salt = ?', | ||||
| 			[result.rows[0].id, data[1]] | ||||
| 		); | ||||
| 		if (auths.rows.length === 0) { | ||||
| 			await db.query("insert into authentication (user, salt) values (?, ?)", [ | ||||
| 			await db.query('insert into authentication (user, salt) values (?, ?)', [ | ||||
| 				result.rows[0].id, | ||||
| 				data[1], | ||||
| 				data[1] | ||||
| 			]); | ||||
| 			socket.username = msg.name; | ||||
| 			if (io.cache[msg.name]) { | ||||
|  | @ -54,14 +54,14 @@ const authenticate = async (msg, respond, socket, io) => { | |||
| 		} else { | ||||
| 			return respond({ | ||||
| 				success: false, | ||||
| 				message: "Already authenticated with this message", | ||||
| 				message: 'already authenticated with this message' | ||||
| 			}); | ||||
| 		} | ||||
| 	} catch (err) { | ||||
| 		console.error("error in authentication: " + err); | ||||
| 		console.error('error in authentication: ' + err); | ||||
| 		return respond({ | ||||
| 			success: false, | ||||
| 			message: "Message signature verification failed", | ||||
| 			message: 'message signature verification failed' | ||||
| 		}); | ||||
| 	} | ||||
| }; | ||||
|  | @ -1,23 +1,23 @@ | |||
| const db = require("../db"); | ||||
| const authwrap = require("./authwrap"); | ||||
| const db = require('../db'); | ||||
| const authwrap = require('../authwrap'); | ||||
| 
 | ||||
| const create_thread = async (msg, respond, socket, io) => { | ||||
| 	// validate inputs
 | ||||
| 	if (typeof msg.name !== 'string') { | ||||
| 		return respond({ | ||||
| 			success: false, | ||||
| 			message: "thread name required", | ||||
| 			message: 'thread name required', | ||||
| 		}); | ||||
| 	} | ||||
| 	if (msg.name.length > 200) { | ||||
| 		return respond({ | ||||
| 			success: false, | ||||
| 			message: "thread name 200 chars max", | ||||
| 			message: 'thread name 200 chars max', | ||||
| 		}); | ||||
| 	} | ||||
| 	// add to db
 | ||||
| 	const insert = await db.query( | ||||
| 		"insert into thread (name, creator) values (?, ?) returning id", | ||||
| 		'insert into thread (name, creator) values (?, ?) returning id', | ||||
| 		[msg.name, msg.auth_user.id] | ||||
| 	); | ||||
| 	const thread_id = insert.rows[0].id; | ||||
|  | @ -26,44 +26,44 @@ const create_thread = async (msg, respond, socket, io) => { | |||
| 		await db.query( | ||||
| 			`insert into permission (thread, type, mutable, permission, value) 
 | ||||
| 			values (?, ?, ?, ?, ?)`,
 | ||||
| 			[thread_id, "everyone", false, "view", "true"] | ||||
| 			[thread_id, 'everyone', false, 'view', 'true'] | ||||
| 		); | ||||
| 		if (!msg.permissions || !msg.permissions.post_limited) { | ||||
| 			await db.query( | ||||
| 				`insert into permission (thread, type, mutable, permission, value) 
 | ||||
| 				values (?, ?, ?, ?, ?)`,
 | ||||
| 				[thread_id, "everyone", false, "post", "true"] | ||||
| 				[thread_id, 'everyone', false, 'post', 'true'] | ||||
| 			); | ||||
| 		} else { | ||||
| 			await db.query( | ||||
| 				`insert into permission (thread, type, mutable, permission, value) 
 | ||||
| 				values (?, ?, ?, ?, ?)`,
 | ||||
| 				[thread_id, "members", false, "post", "true"] | ||||
| 				[thread_id, 'members', false, 'post', 'true'] | ||||
| 			); | ||||
| 		} | ||||
| 	} else { | ||||
| 		await db.query( | ||||
| 			`insert into permission (thread, type, mutable, permission, value) 
 | ||||
| 			values (?, ?, ?, ?, ?)`,
 | ||||
| 			[thread_id, "members", false, "view", "true"] | ||||
| 			[thread_id, 'members', false, 'view', 'true'] | ||||
| 		); | ||||
| 		await db.query( | ||||
| 			`insert into permission (thread, type, mutable, permission, value) 
 | ||||
| 			values (?, ?, ?, ?, ?)`,
 | ||||
| 			[thread_id, "members", false, "post", "true"] | ||||
| 			[thread_id, 'members', false, 'post', 'true'] | ||||
| 		); | ||||
| 	} | ||||
| 	// add members
 | ||||
| 	for (let user of msg.members) { | ||||
| 		if (!user) continue; | ||||
| 		// get user id
 | ||||
| 		const id = await db.query("select id from user where name = ?", [ | ||||
| 		const id = await db.query('select id from user where name = ?', [ | ||||
| 			user.name, | ||||
| 		]); | ||||
| 		if (id.rows.length > 0) { | ||||
| 			const user_id = id.rows[0].id; | ||||
| 			await db.query( | ||||
| 				"insert into member (thread, user, key_delivery) values (?, ?, ?)", | ||||
| 				'insert into member (thread, user, key_delivery) values (?, ?, ?)', | ||||
| 				[thread_id, user_id, user.key] | ||||
| 			); | ||||
| 		} | ||||
|  | @ -71,7 +71,7 @@ const create_thread = async (msg, respond, socket, io) => { | |||
| 	if (!msg.permissions || !msg.permissions.view_limited) { | ||||
| 		for (let username in io.cache) { | ||||
| 			for (let socket of io.cache[username]) { | ||||
| 				io.to(socket).emit("new_thread", { | ||||
| 				io.to(socket).emit('new_thread', { | ||||
| 					name: msg.name, | ||||
| 					id: insert.rows[0].id, | ||||
| 					permissions: { | ||||
|  | @ -86,7 +86,7 @@ const create_thread = async (msg, respond, socket, io) => { | |||
| 	else { | ||||
| 		for (let member of msg.members) { | ||||
| 			for (let socket of io.cache[member.name]) { | ||||
| 				io.to(socket).emit("new_thread", { | ||||
| 				io.to(socket).emit('new_thread', { | ||||
| 					name: msg.name, | ||||
| 					id: insert.rows[0].id, | ||||
| 					permissions: { | ||||
|  | @ -1,44 +1,44 @@ | |||
| const db = require("../db"); | ||||
| const openpgp = require("openpgp"); | ||||
| 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", | ||||
| 			message: 'username required', | ||||
| 		}); | ||||
| 	} | ||||
| 	// ensure username is not taken
 | ||||
| 	const result = await db.query("select * from user where name = ?", [ | ||||
| 	const result = await db.query('select * from user where name = ?', [ | ||||
| 		msg.name, | ||||
| 	]); | ||||
| 	if (result.rows.length > 0) { | ||||
| 		console.log(`username already exists: ${result}`); | ||||
| 		return respond({ | ||||
| 			success: false, | ||||
| 			message: "a user with this name already exists on this server", | ||||
| 			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", | ||||
| 			message: 'public key required', | ||||
| 		}); | ||||
| 	} | ||||
| 	try { | ||||
| 		await openpgp.readKey({ armoredKey: msg.pubkey }); | ||||
| 	} catch (err) { | ||||
| 		console.err("error in create_user readkey: " + err); | ||||
| 		console.err('error in create_user readkey: ' + err); | ||||
| 		return respond({ | ||||
| 			success: false, | ||||
| 			message: "public key invalid", | ||||
| 			message: 'public key invalid', | ||||
| 		}); | ||||
| 	} | ||||
| 	// add to db
 | ||||
| 	const insert = await db.query( | ||||
| 		"insert into user (name, pubkey) values (?, ?) returning id", | ||||
| 		'insert into user (name, pubkey) values (?, ?) returning id', | ||||
| 		[msg.name, msg.pubkey] | ||||
| 	); | ||||
| 	// respond
 | ||||
|  | @ -1,18 +1,18 @@ | |||
| const db = require("../db"); | ||||
| const authwrap = require("./authwrap"); | ||||
| const check_permission = require("./helpers/check_permission"); | ||||
| const db = require('../db'); | ||||
| const authwrap = require('../authwrap'); | ||||
| const check_permission = require('../check_permission'); | ||||
| 
 | ||||
| const get_history = async (msg, respond) => { | ||||
| 	if (msg.before && isNaN(Number(msg.before))) { | ||||
| 		return respond({ | ||||
| 			success: false, | ||||
| 			message: "before must be a number", | ||||
| 			message: 'before must be a number', | ||||
| 		}); | ||||
| 	} | ||||
| 	if (!msg.thread) { | ||||
| 		return respond({ | ||||
| 			success: false, | ||||
| 			message: "thread ID required", | ||||
| 			message: 'thread ID required', | ||||
| 		}); | ||||
| 	} | ||||
| 	if (!(await check_permission(msg.auth_user.id, msg.thread)).view) { | ||||
|  | @ -24,7 +24,7 @@ const get_history = async (msg, respond) => { | |||
| 	const messages = await db.query( | ||||
| 		`select user.name, post.id, content from post
 | ||||
| 		join user on post.user = user.id | ||||
| 		${msg.before ? "where post.id < ? and" : "where"} | ||||
| 		${msg.before ? 'where post.id < ? and' : 'where'} | ||||
| 		thread = ? | ||||
| 		order by post.created desc | ||||
| 		limit 101`,
 | ||||
|  | @ -1,15 +1,15 @@ | |||
| const db = require("../db"); | ||||
| const authwrap = require("./authwrap"); | ||||
| const db = require('../db'); | ||||
| const authwrap = require('../authwrap'); | ||||
| 
 | ||||
| const get_keys = async (msg, respond, socket, io) => { | ||||
| 	// validate inputs
 | ||||
| 	if (!msg.names) { | ||||
| 		return respond({ | ||||
| 			success: false, | ||||
| 			message: "user names required", | ||||
| 			message: 'user names required', | ||||
| 		}); | ||||
| 	} | ||||
| 	if (typeof msg.names !== "object") { | ||||
| 	if (typeof msg.names !== 'object') { | ||||
| 		return respond({ | ||||
| 			success: false, | ||||
| 			message: "can't iterate user names", | ||||
|  | @ -17,8 +17,8 @@ const get_keys = async (msg, respond, socket, io) => { | |||
| 	} | ||||
| 	const keys = await db.query( | ||||
| 		`select name, pubkey from user where name in (${msg.names | ||||
| 			.map((i) => "?") | ||||
| 			.join(",")})`,
 | ||||
| 			.map((i) => '?') | ||||
| 			.join(',')})`,
 | ||||
| 		msg.names | ||||
| 	); | ||||
| 	// respond
 | ||||
|  | @ -1,6 +1,6 @@ | |||
| const db = require('../db'); | ||||
| const authwrap = require('./authwrap'); | ||||
| const check_permission = require('./helpers/check_permission'); | ||||
| const authwrap = require('../authwrap'); | ||||
| const check_permission = require('../check_permission'); | ||||
| 
 | ||||
| const get_space = async (msg, respond) => { | ||||
| 	if (!msg.thread) { | ||||
|  | @ -1,6 +1,6 @@ | |||
| const db = require("../db"); | ||||
| const authwrap = require("./authwrap"); | ||||
| const check_permission = require("./helpers/check_permission"); | ||||
| const db = require('../db'); | ||||
| const authwrap = require('../authwrap'); | ||||
| const check_permission = require('../check_permission'); | ||||
| 
 | ||||
| const list_threads = async (msg, respond) => { | ||||
| 	const threads = await db.query( | ||||
|  | @ -1,6 +1,6 @@ | |||
| const db = require('../db'); | ||||
| const authwrap = require('./authwrap'); | ||||
| const check_permission = require('./helpers/check_permission'); | ||||
| const authwrap = require('../authwrap'); | ||||
| const check_permission = require('../check_permission'); | ||||
| 
 | ||||
| const save_span = async (msg, respond, socket, io) => { | ||||
| 	if (!msg.thread) { | ||||
|  | @ -1,12 +1,12 @@ | |||
| const db = require("../db"); | ||||
| const authwrap = require("./authwrap"); | ||||
| const check_permission = require("./helpers/check_permission"); | ||||
| const db = require('../db'); | ||||
| const authwrap = require('../authwrap'); | ||||
| const check_permission = require('../check_permission'); | ||||
| 
 | ||||
| const send_message = async (msg, respond, socket, io) => { | ||||
| 	if (!msg.thread) { | ||||
| 		return respond({ | ||||
| 			success: false, | ||||
| 			message: "thread ID required", | ||||
| 			message: 'thread ID required', | ||||
| 		}); | ||||
| 	} | ||||
| 	if (!(await check_permission(msg.auth_user.id, msg.thread)).post) { | ||||
|  | @ -17,13 +17,13 @@ const send_message = async (msg, respond, socket, io) => { | |||
| 	} | ||||
| 	// add message and send it to everyone
 | ||||
| 	const id = await db.query( | ||||
| 		"insert into post (user, thread, content, encrypted) values (?, ?, ?, ?) returning id", | ||||
| 		'insert into post (user, thread, content, encrypted) values (?, ?, ?, ?) returning id', | ||||
| 		[msg.auth_user.id, msg.thread, msg.message, msg.encrypted] | ||||
| 	); | ||||
| 	// get thread members
 | ||||
| 	const members = ( | ||||
| 		await db.query( | ||||
| 			"select name from user join member on member.user = user.id where member.thread = ?", | ||||
| 			'select name from user join member on member.user = user.id where member.thread = ?', | ||||
| 			[msg.thread] | ||||
| 		) | ||||
| 	).rows.map((i) => i.name); | ||||
|  | @ -36,7 +36,7 @@ const send_message = async (msg, respond, socket, io) => { | |||
| 		if (permissions.rows.length > 0 || members.includes(username)) { | ||||
| 			const sockets = io.cache[username]; | ||||
| 			for (let s of sockets) { | ||||
| 				io.to(s).emit("new_message", { | ||||
| 				io.to(s).emit('new_message', { | ||||
| 					id: id.rows[0].id, | ||||
| 					name: msg.auth_user.name, | ||||
| 					message: msg.message, | ||||
		Loading…
	
		Reference in New Issue