This commit is contained in:
Xodrium 2023-02-03 21:54:01 -05:00
parent ce7957e0bf
commit d8670ecf81
18 changed files with 191 additions and 193 deletions

View file

@ -37,6 +37,8 @@
<script> <script>
export let tiny = false; export let tiny = false;
let form;
</script> </script>
<div id='content'> <div id='content'>

View file

@ -6,6 +6,24 @@
let query = (id) ? `/post/${id}` : ''; let query = (id) ? `/post/${id}` : '';
let contentSplit = content.split('\n'); let contentSplit = content.split('\n');
let fData;
function vote(v) {
fData = (new FormData());
fData.append('vote',v);
fData.append('id',id);
fetch('/api/vote', {
method: 'POST',
body: fData
}).then(async x => {
var j = (await x.json());
upvotes = j.data.up;
downvotes = j.data.down;
})
}
</script> </script>
<style> <style>
@ -48,7 +66,7 @@
</span> </span>
<span slot="footer"> <span slot="footer">
<span class='vote-area'> <span class='vote-area'>
<a data-sveltekit-reload href='{query}?vote=up'> <a on:click={() => vote('up')} href=''>
<img src='/upvote.svg' class='button' alt='Upvote'> <img src='/upvote.svg' class='button' alt='Upvote'>
</a> </a>
<span class='votes'> <span class='votes'>
@ -56,7 +74,7 @@
</span> </span>
</span> </span>
<span class='vote-area'> <span class='vote-area'>
<a data-sveltekit-reload href='{query}?vote=down'> <a on:click={() => vote('down')} href=''>
<img src='/downvote.svg' class='button' alt='Downvote'> <img src='/downvote.svg' class='button' alt='Downvote'>
</a> </a>
<span class='votes'> <span class='votes'>

View file

@ -1,7 +1,10 @@
const rowCount = 5;
import sqlite3 from 'sqlite3' import sqlite3 from 'sqlite3'
import { open } from 'sqlite' import { open } from 'sqlite'
import { hash, compare } from 'bcrypt' import { hash, compare } from 'bcrypt'
import { calcVote } from './util.js'; import { calcVote } from './util.js';
import { checkLength, checkRegex } from './util.js';
const { const {
randomBytes randomBytes
@ -20,7 +23,20 @@ async function initDb() {
await db.run('CREATE TABLE IF NOT EXISTS vote (id CHAR(64), username CHAR(64), type INTEGER)'); await db.run('CREATE TABLE IF NOT EXISTS vote (id CHAR(64), username CHAR(64), type INTEGER)');
} }
async function registerBackend({user, pass}) { var backend = {};
backend.register = async ({user, pass, pass2}) => {
var lengthCheck = false;
lengthCheck =
checkLength(pass,'Password',4,1024) ||
checkLength(user,'Username',1,64) ||
checkRegex(user,'Username',/[^A-Za-z0-9\-\_]/g);
if (lengthCheck) return lengthCheck;
if (pass != pass2) return {'success': 'Passwords don\'t match.'};
if (!db) await initDb(); if (!db) await initDb();
var existingAccounts = await db.all('SELECT username FROM auth WHERE username = ?',[ var existingAccounts = await db.all('SELECT username FROM auth WHERE username = ?',[
@ -37,10 +53,10 @@ async function registerBackend({user, pass}) {
passHash passHash
]) ])
return { success: 'Successfully created account.' }; return { success: 'Successfully created account.', location: '/'};
} }
async function loginBackend({user, pass}) { backend.login = async ({user, pass, cookies}) => {
if (!db) await initDb(); if (!db) await initDb();
var existingAccounts = await db.all('SELECT username, password FROM auth WHERE username = ?',[ var existingAccounts = await db.all('SELECT username, password FROM auth WHERE username = ?',[
@ -62,10 +78,28 @@ async function loginBackend({user, pass}) {
token token
]) ])
return { success: 'Successfully logged into account.', token }; if (token) {
cookies.set('token',token, {
maxAge: 60 * 60 * 24 * 7,
path: '/'
});
};
return { success: 'Successfully logged into account.', data: token, location: '/'};
} }
async function postCreateBackend({user, content}) { backend.postCreate = async ({cookies, content}) => {
if (!db) await initDb();
var lengthCheck = checkLength(content,'Post content',1,10240);
if (lengthCheck)
return lengthCheck;
var user = (await backend.token({cookies})).data;
if (!user || !content || user == '') return {'success': 'Not authorized.' };
var id = randomBytes(10).toString('hex'); var id = randomBytes(10).toString('hex');
await db.run('INSERT INTO post (username, id, content, rating) VALUES (?, ?, ?, ?)', [ await db.run('INSERT INTO post (username, id, content, rating) VALUES (?, ?, ?, ?)', [
@ -74,9 +108,13 @@ async function postCreateBackend({user, content}) {
content, content,
calcVote(0,0) calcVote(0,0)
]) ])
return {'success': 'Your post has been broadcasted!' };
} }
async function postGetBackend({id}) { backend.postGet = async ({id}) => {
if (!db) await initDb();
var posts = await db.all('SELECT * from post WHERE id = ?', [ var posts = await db.all('SELECT * from post WHERE id = ?', [
id id
]) ])
@ -85,20 +123,26 @@ async function postGetBackend({id}) {
return {'success': 'Post does not exist.'} return {'success': 'Post does not exist.'}
} }
return posts[0]; return {data: posts[0]};
} }
async function postGetBulkBackend({page, rows}) { backend.postBulk = async ({page}) => {
if (!db) await initDb();
var posts = await db.all('SELECT * from post ORDER BY rating DESC LIMIT ?, ?', [ var posts = await db.all('SELECT * from post ORDER BY rating DESC LIMIT ?, ?', [
page*rows, page*rowCount,
rows rowCount
]) ])
return posts; return {data: posts};
} }
async function voteBackend({user, id, vote}) { backend.vote = async ({cookies, id, vote}) => {
if (!user || !id || user == '' || (vote != 'down' && vote != 'up')) return {}; if (!db) await initDb();
var user = (await backend.token({cookies})).data;
if (!user || !id || user == '' || (vote != 'down' && vote != 'up')) return {success: 'fail' };
await db.run('DELETE FROM vote WHERE username = ? AND id = ?', [ await db.run('DELETE FROM vote WHERE username = ? AND id = ?', [
user, user,
@ -125,28 +169,24 @@ async function voteBackend({user, id, vote}) {
id id
]); ]);
return {}; return {data: {up,down}};
} }
async function tokenBackend({token}) { backend.token = async ({cookies}) => {
if (!db) await initDb(); if (!db) await initDb();
var tokenIn = cookies.get('token');
var existingAccounts = await db.all('SELECT username from token WHERE token = ?',[ var existingAccounts = await db.all('SELECT username from token WHERE token = ?',[
token tokenIn
]); ]);
if (!existingAccounts || existingAccounts.length < 1) if (!existingAccounts || existingAccounts.length < 1)
return false; return false;
return existingAccounts[0].username; return {data: existingAccounts[0].username};
} }
export { export {
registerBackend, backend
loginBackend,
tokenBackend,
postCreateBackend,
postGetBackend,
voteBackend,
postGetBulkBackend
} }

View file

@ -35,8 +35,20 @@ let calcVote = function(up,down) {
return rating * Math.log(totalPadded); return rating * Math.log(totalPadded);
} }
let handleSubmit = async e => {
const ACTION_URL = e.target.action
const formData = new FormData(e.target)
return await fetch(ACTION_URL, {
method: 'POST',
body: formData
}).then(x => x.text());
}
export { export {
checkLength, checkLength,
checkRegex, checkRegex,
calcVote calcVote,
handleSubmit
}; };

View file

@ -1,7 +1,8 @@
/** @type {import('./$types').PageLoad} */ /** @type {import('./$types').PageLoad} */
export async function load({ fetch, params }) { export async function load({ fetch }) {
const res = await fetch(`/api/session`); const res = await fetch(`/api/token`);
const username = await res.text();
return { username }; const username = await res.json();
return { username: username.data };
} }

View file

@ -8,7 +8,7 @@ export async function load({ fetch, params, url }) {
await new Promise(resolve => setTimeout(resolve, 100)); await new Promise(resolve => setTimeout(resolve, 100));
const res = await fetch(`/api/explore?page=${id}`); const res = await fetch(`/api/postBulk?page=${id}`);
const postJson = await res.json(); const postJson = await res.json();
return { postJson, id }; return { postJson, id };

View file

@ -5,7 +5,7 @@
export let data; export let data;
</script> </script>
{#each data.postJson as post} {#each data.postJson.data as post}
<Post <Post
success={post.success} success={post.success}
username={post.username} username={post.username}

View file

@ -1,59 +0,0 @@
import { checkLength, checkRegex } from '../../lib/util.js';
import { registerBackend, loginBackend } from '../../lib/db.js';
async function basicChecks(data) {
const pass = data.get('pass') + '';
const user = data.get('user') + '';
var lengthCheck = false;
lengthCheck =
checkLength(pass,'Password',4,1024) ||
checkLength(user,'Username',1,64) ||
checkRegex(user,'Username',/[^A-Za-z0-9\-\_]/g);
return {
user,
pass,
lengthCheck
};
}
/** @type {import('./$types').Actions} */
export const actions = {
register: async ({ request }) => {
const data = await request.formData();
const pass2 = data.get('pass2') + '';
var {lengthCheck, user, pass} = await basicChecks(data);
if (lengthCheck)
return lengthCheck;
if (pass != pass2)
return { success: 'Failed to confirm password.' };
return await registerBackend({ user, pass });
},
login: async ({ request, cookies }) => {
const data = await request.formData();
var {lengthCheck, user, pass} = await basicChecks(data);
if (lengthCheck)
return lengthCheck;
var result = await loginBackend({ user, pass });
if (result.token) {
cookies.set('token',result.token, {
maxAge: 60 * 60 * 24 * 7,
path: '/'
});
}
return result;
}
};

View file

@ -1,33 +1,46 @@
<script> <script>
import Area from '$lib/Area.svelte'; import Area from '$lib/Area.svelte';
import { handleSubmit } from '$lib/util.js';
/** @type {import('./$types').PageData} */ export let form = {};
export let data;
/** @type {import('./$types').ActionData} */ let submitFunc = async e => form = JSON.parse(await handleSubmit(e))
export let form;
</script> </script>
<Area> <Area handleSubmit=''>
<p slot="header"> <p slot="header">
Log in / Register Log in
</p> </p>
<form slot="main" method='POST'>
<p> <span slot='main'>
Username: <input name='user'> <h2>Login</h2>
</p> <form action='/api/login' on:submit|preventDefault={submitFunc} method='POST'>
<p> <p>
Password: <input type='password' name='pass'> Username: <input name='user'>
</p> </p>
<p> <p>
Confirm Password: <input type='password' name='pass2'> Password: <input type='password' name='pass'>
</p> </p>
<p> <p>
<input formaction="?/login" type='submit' value='Log in'> <input type='submit' value='Log in'>
</p> </p>
<p> </form>
<input formaction="?/register" type='submit' value='Register'> <h2>Register</h2>
</p> <form action='/api/register' on:submit|preventDefault={submitFunc} method='POST'>
</form> <p>
Username: <input name='user'>
</p>
<p>
Password: <input type='password' name='pass'>
</p>
<p>
Confirm Password: <input type='password' name='pass2'>
</p>
<p>
<input type='submit' value='Register'>
</p>
</form>
</span>
<p slot="footer"> <p slot="footer">
{#if form?.success} {#if form?.success}
<p>{form?.success}</p> <p>{form?.success}</p>

View file

@ -0,0 +1,33 @@
import { backend } from '../../../lib/db.js';
/** @type {import('./$types').RequestHandler} */
export async function GET({ url, cookies, params }) {
var backendParams = {cookies};
for (const [key, value] of url.searchParams) {
backendParams[key] = value;
}
return await main({backendParams, route: params.route});
}
/** @type {import('./$types').RequestHandler} */
export async function POST({ url, cookies, request, params }) {
var backendParams = {cookies};
for (const [key, value] of (await request.formData()).entries()) {
backendParams[key] = value;
}
return await main({backendParams, route: params.route});
}
async function main({backendParams, route}) {
if (Object.keys(backend).indexOf(route) == -1) {
return new Response(JSON.stringify({success: 'route doesn\'t exist'}));
}
var resData = await backend[route](backendParams);
return new Response(JSON.stringify(resData));
};

View file

@ -1,10 +0,0 @@
import { postGetBulkBackend } from '../../../lib/db.js';
/** @type {import('./$types').RequestHandler} */
export async function GET({ url, cookies }) {
var page = url.searchParams.get('page') * 1;
var postData = await postGetBulkBackend({ rows: 5, page });
return new Response(JSON.stringify(postData));
};

View file

@ -1,10 +0,0 @@
import { postGetBackend } from '../../../lib/db.js';
/** @type {import('./$types').RequestHandler} */
export async function GET({ url, cookies }) {
var id = url.searchParams.get('post');
var postData = await postGetBackend({ id });
return new Response(JSON.stringify(postData));
};

View file

@ -1,11 +0,0 @@
import { tokenBackend } from '../../../lib/db.js';
/** @type {import('./$types').RequestHandler} */
export async function GET({ url, cookies }) {
var token = cookies.get('token') || '';
var username = await tokenBackend({token});
return new Response(username + '');
};

View file

@ -1,17 +0,0 @@
import { tokenBackend, voteBackend } from '../../../lib/db.js';
/** @type {import('./$types').RequestHandler} */
export async function GET({ url, cookies }) {
var token = cookies.get('token') || '';
var user = await tokenBackend({token});
if (!user) return new Response('fail');
var id = url.searchParams.get('post');
var vote = url.searchParams.get('vote');
voteBackend({user,id,vote});
return new Response();
};

View file

@ -1,17 +1,9 @@
import { tokenBackend, postCreateBackend } from '../../lib/db.js'; import { backend } from '../../lib/db.js';
import { checkLength, checkRegex } from '../../lib/util.js'; import { checkLength, checkRegex } from '../../lib/util.js';
/** @type {import('./$types').Actions} */ /** @type {import('./$types').Actions} */
export const actions = { export const actions = {
create: async ({ request, cookies }) => { create: async ({ request, cookies }) => {
var user = await tokenBackend({
token: cookies.get('token')
});
if (!user)
return {'success': 'Not logged in.'}
const data = await request.formData(); const data = await request.formData();
const content = data.get('content') + ''; const content = data.get('content') + '';
@ -20,7 +12,7 @@ export const actions = {
if (lengthCheck) if (lengthCheck)
return lengthCheck; return lengthCheck;
await postCreateBackend({user, content}); await backend.postCreate({user, content});
return {'success': 'Successfully posted.'}; return {'success': 'Successfully posted.'};
} }

View file

@ -1,8 +1,8 @@
<script> <script>
import Area from '$lib/Area.svelte'; import Area from '$lib/Area.svelte';
/** @type {import('./$types').PageData} */ import { handleSubmit } from '$lib/util.js';
export let data;
/** @type {import('./$types').ActionData} */ /** @type {import('./$types').ActionData} */
export let form; export let form;
</script> </script>
@ -18,7 +18,7 @@
<p slot="header"> <p slot="header">
Create Post Create Post
</p> </p>
<form slot="main" method='POST'> <form slot="main" action='/api/postCreate' method='POST' on:submit|preventDefault={async e => form = JSON.parse(await handleSubmit(e)) }>
<p> <p>
<textarea name='content'></textarea> <textarea name='content'></textarea>
</p> </p>

View file

@ -2,25 +2,21 @@ import { redirect } from '@sveltejs/kit';
/** @type {import('./$types').PageLoad} */ /** @type {import('./$types').PageLoad} */
export async function load({ fetch, params, url }) { export async function load({ fetch, params, url }) {
var search = url.searchParams;
var voteType = search.get('vote');
var id = params.post; var id = params.post;
if (voteType) {
var voteRes = await fetch(`/api/vote?post=${id}&vote=${voteType}`);
var voteJson = await voteRes.text();
if (voteJson == 'fail') {
throw redirect(302, '/account');
}
}
await new Promise(resolve => setTimeout(resolve, 100)); await new Promise(resolve => setTimeout(resolve, 100));
const res = await fetch(`/api/post?post=${id}`); var f = (new FormData());
const postJson = await res.json();
f.append('id',id);
const res = await fetch(`/api/postGet`, {
method: 'POST',
body: f
});
const postJson = (await res.json()).data;
console.log(postJson);
return postJson; return postJson;
} }

View file

@ -3,8 +3,6 @@
/** @type {import('./$types').PageData} */ /** @type {import('./$types').PageData} */
export let data; export let data;
/** @type {import('./$types').ActionData} */
export let form;
</script> </script>
<Post <Post