column view n live threads
							parent
							
								
									55fdc45073
								
							
						
					
					
						commit
						b2b15231df
					
				
							
								
								
									
										111
									
								
								client/chat.js
								
								
								
								
							
							
						
						
									
										111
									
								
								client/chat.js
								
								
								
								
							| 
						 | 
				
			
			@ -19,43 +19,6 @@ async function auth() {
 | 
			
		|||
	window.socket.emit("authenticate", { name: window.name, message: sig });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function register(e) {
 | 
			
		||||
  e.preventDefault();
 | 
			
		||||
  const name = document.getElementById("name").value;
 | 
			
		||||
  if (!name) return;
 | 
			
		||||
  const keys = await openpgp.generateKey({
 | 
			
		||||
    userIDs: [{ name }],
 | 
			
		||||
  });
 | 
			
		||||
  const priv = await openpgp.readKey({ armoredKey: keys.privateKey });
 | 
			
		||||
  const pub = await openpgp.readKey({ armoredKey: keys.publicKey });
 | 
			
		||||
  window.keys = { priv, pub };
 | 
			
		||||
  localStorage.setItem("keys", JSON.stringify(keys));
 | 
			
		||||
  localStorage.setItem("name", name);
 | 
			
		||||
  window.name = name;
 | 
			
		||||
  window.socket.emit("create_user", { name, pubkey: keys.publicKey });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function message(e) {
 | 
			
		||||
  e.preventDefault();
 | 
			
		||||
  const msg = document.getElementById("msg").value;
 | 
			
		||||
  if (!msg) return;
 | 
			
		||||
  window.socket.emit("send_message", {
 | 
			
		||||
    message: msg,
 | 
			
		||||
    thread: window.currentThreadId,
 | 
			
		||||
  });
 | 
			
		||||
  document.getElementById("msg").value = "";
 | 
			
		||||
  const el = document.createElement("div");
 | 
			
		||||
  el.classList.add("message");
 | 
			
		||||
  el.innerHTML = `<strong>${window.name}: </strong>${msg}`;
 | 
			
		||||
  document.getElementById("messages").appendChild(el);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function startThreadPicker() {
 | 
			
		||||
  document.getElementById("chat").classList.add("hidden");
 | 
			
		||||
  document.getElementById("threads").classList.remove("hidden");
 | 
			
		||||
  window.socket.emit("list_threads");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function chooseThread(thread) {
 | 
			
		||||
	window.currentThreadId = thread.id;
 | 
			
		||||
	window.earliestMessage = null;
 | 
			
		||||
| 
						 | 
				
			
			@ -63,14 +26,6 @@ function chooseThread(thread) {
 | 
			
		|||
	document.getElementById("chat").classList.remove("hidden");
 | 
			
		||||
	document.getElementById("messages").innerHTML = "";
 | 
			
		||||
	document.getElementById("threadname").innerHTML = thread.name;
 | 
			
		||||
  document.getElementById("threads").classList.add("hidden");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function createThread(e) {
 | 
			
		||||
  e.preventDefault();
 | 
			
		||||
  window.socket.emit("create_thread", {
 | 
			
		||||
    name: document.getElementById("newthreadname").value,
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function loadKeys(keys) {
 | 
			
		||||
| 
						 | 
				
			
			@ -80,13 +35,6 @@ async function loadKeys(keys) {
 | 
			
		|||
	await auth();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function loadMessages() {
 | 
			
		||||
  window.socket.emit(
 | 
			
		||||
    "get_history",
 | 
			
		||||
    { before: window.earliestMessage, thread: window.currentThreadId }
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
window.onload = () => {
 | 
			
		||||
	window.currentThreadId = 1;
 | 
			
		||||
	window.socket = io();
 | 
			
		||||
| 
						 | 
				
			
			@ -121,7 +69,9 @@ window.onload = () => {
 | 
			
		|||
	window.socket.on("authenticate", (msg) => {
 | 
			
		||||
		if (msg.success) {
 | 
			
		||||
			document.getElementById("register").classList.add("hidden");
 | 
			
		||||
			document.getElementById("threads").classList.remove("hidden");
 | 
			
		||||
			document.getElementById("chat").classList.remove("hidden");
 | 
			
		||||
			window.socket.emit("list_threads");
 | 
			
		||||
		}
 | 
			
		||||
		let emitter = window.socket.emit;
 | 
			
		||||
		window.socket.emit = (type, data) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -133,9 +83,7 @@ window.onload = () => {
 | 
			
		|||
			else return emitter.call(window.socket, type);
 | 
			
		||||
		};
 | 
			
		||||
	});
 | 
			
		||||
  window.socket.on("list_threads", (msg) => {
 | 
			
		||||
    document.getElementById("threadlist").innerHTML = "";
 | 
			
		||||
    for (let thread of msg.threads) {
 | 
			
		||||
	function addThread(thread) {
 | 
			
		||||
		const el = document.createElement("div");
 | 
			
		||||
		el.classList.add("thread");
 | 
			
		||||
		el.innerHTML = thread.name;
 | 
			
		||||
| 
						 | 
				
			
			@ -145,7 +93,12 @@ window.onload = () => {
 | 
			
		|||
		el.appendChild(btn);
 | 
			
		||||
		document.getElementById("threadlist").appendChild(el);
 | 
			
		||||
	}
 | 
			
		||||
	window.socket.on("list_threads", (msg) => {
 | 
			
		||||
		document.getElementById("threadlist").innerHTML = "";
 | 
			
		||||
		for (let thread of msg.threads)
 | 
			
		||||
			addThread(thread);
 | 
			
		||||
	});
 | 
			
		||||
	window.socket.on('new_thread', addThread);
 | 
			
		||||
	window.socket.on("create_thread", (msg) => {
 | 
			
		||||
		chooseThread({
 | 
			
		||||
			name: document.getElementById("newthreadname").value,
 | 
			
		||||
| 
						 | 
				
			
			@ -153,6 +106,49 @@ window.onload = () => {
 | 
			
		|||
		});
 | 
			
		||||
		document.getElementById("newthreadname").value = "";
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	document.getElementById("registerform").onsubmit = async e => {
 | 
			
		||||
		e.preventDefault();
 | 
			
		||||
		const name = document.getElementById("name").value;
 | 
			
		||||
		if (!name) return;
 | 
			
		||||
		const keys = await openpgp.generateKey({
 | 
			
		||||
			userIDs: [{ name }],
 | 
			
		||||
		});
 | 
			
		||||
		const priv = await openpgp.readKey({ armoredKey: keys.privateKey });
 | 
			
		||||
		const pub = await openpgp.readKey({ armoredKey: keys.publicKey });
 | 
			
		||||
		window.keys = { priv, pub };
 | 
			
		||||
		localStorage.setItem("keys", JSON.stringify(keys));
 | 
			
		||||
		localStorage.setItem("name", name);
 | 
			
		||||
		window.name = name;
 | 
			
		||||
		window.socket.emit("create_user", { name, pubkey: keys.publicKey });
 | 
			
		||||
	};
 | 
			
		||||
	document.getElementById("msginput").onsubmit = e => {
 | 
			
		||||
		e.preventDefault();
 | 
			
		||||
		const msg = document.getElementById("msg").value;
 | 
			
		||||
		if (!msg) return;
 | 
			
		||||
		window.socket.emit("send_message", {
 | 
			
		||||
			message: msg,
 | 
			
		||||
			thread: window.currentThreadId,
 | 
			
		||||
		});
 | 
			
		||||
		document.getElementById("msg").value = "";
 | 
			
		||||
		const el = document.createElement("div");
 | 
			
		||||
		el.classList.add("message");
 | 
			
		||||
		el.innerHTML = `<strong>${window.name}: </strong>${msg}`;
 | 
			
		||||
		document.getElementById("messages").appendChild(el);
 | 
			
		||||
	};
 | 
			
		||||
	document.getElementById("loadmore").onclick = e => {
 | 
			
		||||
		window.socket.emit(
 | 
			
		||||
			"get_history",
 | 
			
		||||
			{ before: window.earliestMessage, thread: window.currentThreadId }
 | 
			
		||||
		);
 | 
			
		||||
	};
 | 
			
		||||
	document.getElementById("createthread").onsubmit = e => {
 | 
			
		||||
		e.preventDefault();
 | 
			
		||||
		window.socket.emit("create_thread", {
 | 
			
		||||
			name: document.getElementById("newthreadname").value,
 | 
			
		||||
		});
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	const keys = localStorage.getItem("keys");
 | 
			
		||||
	if (keys) {
 | 
			
		||||
		window.name = localStorage.getItem("name");
 | 
			
		||||
| 
						 | 
				
			
			@ -160,9 +156,4 @@ window.onload = () => {
 | 
			
		|||
	}
 | 
			
		||||
	else
 | 
			
		||||
		document.getElementById("register").classList.remove("hidden");
 | 
			
		||||
  document.getElementById("registerform").onsubmit = register;
 | 
			
		||||
  document.getElementById("msginput").onsubmit = message;
 | 
			
		||||
  document.getElementById("loadmore").onclick = loadMessages;
 | 
			
		||||
  document.getElementById("change").onclick = startThreadPicker;
 | 
			
		||||
  document.getElementById("createthread").onsubmit = createThread;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,6 +15,15 @@
 | 
			
		|||
				background: #020202;
 | 
			
		||||
				color: #eaeaea;
 | 
			
		||||
			}
 | 
			
		||||
			body {
 | 
			
		||||
				display: flex;
 | 
			
		||||
				align-items: stretch;
 | 
			
		||||
				margin: 0;
 | 
			
		||||
				min-width: min-content;
 | 
			
		||||
			}
 | 
			
		||||
			.column {
 | 
			
		||||
				flex-grow: 1;
 | 
			
		||||
			}
 | 
			
		||||
			button {
 | 
			
		||||
				border-color: #767676;
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -50,8 +59,19 @@
 | 
			
		|||
				<button id="submit" type="submit">generate keys & register</button>
 | 
			
		||||
			</form>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div id="chat" class="hidden">
 | 
			
		||||
		<div id="threads" class="column hidden">
 | 
			
		||||
			<h1>vybe</h1>
 | 
			
		||||
			<h1>threads</h1>
 | 
			
		||||
			<h3>create thread</h3>
 | 
			
		||||
			<form id="createthread">
 | 
			
		||||
				<label for="newthreadname">thread name</label>
 | 
			
		||||
				<input type="text" id="newthreadname" />
 | 
			
		||||
				<button id="submitthread" type="submit">create</button>
 | 
			
		||||
			</form>
 | 
			
		||||
			<h3>choose existing thread</h3>
 | 
			
		||||
			<div id="threadlist">loading...</div>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div id="chat" class="column hidden">
 | 
			
		||||
			<h3 class="thread">
 | 
			
		||||
				current thread: <strong id="threadname">meow</strong>
 | 
			
		||||
				<button id="change">change thread</button>
 | 
			
		||||
| 
						 | 
				
			
			@ -64,17 +84,6 @@
 | 
			
		|||
				<button type="submit" class="hidden" id="sendmsg"></button>
 | 
			
		||||
			</form>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div id="threads" class="hidden">
 | 
			
		||||
			<h1>threads</h1>
 | 
			
		||||
			<h3>create thread</h3>
 | 
			
		||||
			<form id="createthread">
 | 
			
		||||
				<label for="newthreadname">thread name</label>
 | 
			
		||||
				<input type="text" id="newthreadname" />
 | 
			
		||||
				<button id="submitthread" type="submit">create</button>
 | 
			
		||||
			</form>
 | 
			
		||||
			<h3>choose existing thread</h3>
 | 
			
		||||
			<div id="threadlist">loading...</div>
 | 
			
		||||
		</div>
 | 
			
		||||
		<script src="/openpgp.min.js"></script>
 | 
			
		||||
		<script src="/chat.js"></script>
 | 
			
		||||
		<script src="/socket.io.min.v4.6.1.js"></script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								index.js
								
								
								
								
							
							
						
						
									
										2
									
								
								index.js
								
								
								
								
							| 
						 | 
				
			
			@ -17,7 +17,7 @@ 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)
 | 
			
		||||
      actions[action](msg, (response) => socket.emit(action, response), socket, io)
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
const db = require("../db");
 | 
			
		||||
 | 
			
		||||
const authwrap = (fn) => async (msg, respond, socket) => {
 | 
			
		||||
const authwrap = (fn) => async (msg, respond, socket, io) => {
 | 
			
		||||
  if (!msg.__session) {
 | 
			
		||||
    return respond({
 | 
			
		||||
      success: false,
 | 
			
		||||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ const authwrap = (fn) => async (msg, respond, socket) => {
 | 
			
		|||
      message: "User not found",
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
  return await fn({ ...msg, auth_user: result.rows[0] }, respond, socket);
 | 
			
		||||
  return await fn({ ...msg, auth_user: result.rows[0] }, respond, socket, io);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module.exports = authwrap;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
const db = require("../db");
 | 
			
		||||
const authwrap = require("./authwrap");
 | 
			
		||||
 | 
			
		||||
const create_thread = async (msg, respond) => {
 | 
			
		||||
const create_thread = async (msg, respond, socket, io) => {
 | 
			
		||||
  // validate inputs
 | 
			
		||||
  if (!msg.name) {
 | 
			
		||||
    return respond({
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +14,10 @@ const create_thread = async (msg, respond) => {
 | 
			
		|||
    "insert into threads (name, creator) values (?, ?) returning id",
 | 
			
		||||
    [msg.name, msg.auth_user.id]
 | 
			
		||||
  );
 | 
			
		||||
  io.emit('new_thread', {
 | 
			
		||||
    name: msg.name,
 | 
			
		||||
    id: insert.rows[0].id
 | 
			
		||||
  });
 | 
			
		||||
  // respond
 | 
			
		||||
  return respond({
 | 
			
		||||
    success: true,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue