Restructuring repo

This commit is contained in:
Lauren Toivanen 2024-12-11 11:50:28 +02:00
parent 1a8e913f28
commit 436fd4d2cd
Signed by: jt
GPG key ID: 9151B109B73ECAD5
85 changed files with 8 additions and 2 deletions

4
src/api/.htaccess Normal file
View file

@ -0,0 +1,4 @@
RewriteEngine on
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
RewriteRule ^ index.php

20
src/api/index.php Normal file
View file

@ -0,0 +1,20 @@
<?php
$url = explode('/', $_SERVER['REQUEST_URI']);
while ($url[0] !== "api") {
array_shift($url);
}
array_shift($url);
$count = 0;
while (!empty($url[0])) {
switch ($url[0]) {
case 'asd':
echo "asdasd";
break;
default:
echo $url[0] . "\n";
}
$count += 1;
array_shift($url);
}
echo "\n" . $count;
?>

2
src/inc/.htaccess Executable file
View file

@ -0,0 +1,2 @@
order deny,allow
deny from all

196
src/inc/database.php Executable file
View file

@ -0,0 +1,196 @@
<?php
if(count(get_included_files()) ==1) {
http_response_code(403);
die("403: Forbidden");
}
class DataBase extends SQLite3 {
function __construct() {
$this->open('data/database.db');
$this->exec('PRAGMA foreign_keys=ON;');
$this->exec('PRAGMA full_column_names=ON;');
$this->exec('PRAGMA short_column_names=OFF;');
$sql = "
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY UNIQUE,
pass TEXT,
email TEXT UNIQUE,
handle TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
about TEXT
);
CREATE TABLE IF NOT EXISTS personas (
id INTEGER PRIMARY KEY UNIQUE,
userid INTEGER NOT NULL,
handle TEXT NOT NULL,
name TEXT NOT NULL,
about TEXT,
colour INTEGER,
FOREIGN KEY (userid) REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE,
UNIQUE (userid, handle)
);
CREATE TABLE IF NOT EXISTS posts (
id INTEGER PRIMARY KEY UNIQUE,
time INTEGER NOT NULL,
userid INTEGER NOT NULL,
personaid INTEGER NOT NULL,
text TEXT NOT NULL,
FOREIGN KEY (userid) REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE,
FOREIGN KEY (personaid) REFERENCES personas(id) ON UPDATE CASCADE ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS comments (
id INTEGER PRIMARY KEY UNIQUE,
time INTEGER NOT NULL,
userid INTEGER NOT NULL,
personaid INTEGER,
postid INTEGER NOT NULL,
text TEXT NOT NULL,
FOREIGN KEY (postid) REFERENCES posts(id),
FOREIGN KEY (userid) REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE,
FOREIGN KEY (personaid) REFERENCES personas(id) ON UPDATE CASCADE ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS tokens (
id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
userid INTEGER NOT NULL,
token TEXT NOT NULL UNIQUE,
lastuse TEXT NOT NULL,
expires TEXT NOT NULL,
FOREIGN KEY (userid) REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE
);
INSERT OR IGNORE INTO users (id, handle, name, about) VALUES ('0', 'SYSTEM', 'SYSTEM', 'SYSTEM');
";
$ret = $this->exec($sql);
}
function addUser($handle, $name, $about=NULL) {
$id = hexdec(uniqid());
$sql = "INSERT INTO users (id, handle, name, about) VALUES ('$id', '$handle', '$name', '$about')";
$ret = $this->exec($sql);
if(!$ret) {
die($this->lastErrorMsg());
}
}
function getUserByHandle($handle) {
$handle = $this->escapeString($handle);
$sql = "SELECT * FROM users AS user WHERE handle='$handle';";
$ret = $this->query($sql)->fetchArray(SQLITE3_ASSOC);
if(!$ret) {
return false;
}
return $ret;
}
function addPost($text, $userid=NULL, $personaid=NULL) {
$id = hexdec(uniqid());
$time = time();
$sql = $this->prepare("INSERT INTO posts (id, time, userid, personaid, text) values ('$id', '$time', '$userid', :personaid, '$text')");
$sql->bindParam(':personaid', $personaid, SQLITE3_INTEGER);
$ret = $sql->execute();
if(!$ret) {
die($this->lastErrorMsg());
}
}
function addPersona($userid, $handle, $name, $about=NULL, $colour=NULL) {
$id = hexdec(uniqid());
$sql = "INSERT INTO personas (id, userid, handle, name, colour) VALUES ('$id', '$userid', '$handle', '$about', '$colour');";
$ret = $this->exec($sql);
if(!$ret) {
die($this->lastErrorMsg());
}
}
function passwordSet($userid, $password=NULL) {
$hash = empty($password) ? NULL : password_hash($password, PASSWORD_DEFAULT);
$sql = "UPDATE USERS SET pass='$hash' WHERE id='$userid';";
$ret = $this->exec($sql);
if(!$ret) {
die($this->lastErrorMsg());
}
}
function passwordVerify($userid, $password) {
$sql = "SELECT pass FROM users WHERE id='$userid';";
$ret = $this->query($sql)->fetchArray(SQLITE3_NUM);
if(!$ret) {
return false;
}
$dbhash = $ret[0];
return password_verify($password, $dbhash);
}
function tokenGen() {
return random_bytes(32);
}
function tokenAdd($userid) {
$token = $this->tokenGen();
$hashed = hash('sha256', $token);
$time = time();
$expires = $time + 2592000; // 30 days
$sql = "INSERT INTO tokens (userid, token, lastuse, expires) VALUES ('$userid', '$hashed', '$time', '$expires');";
$ret = $this->exec($sql);
if(!$ret) {
die($this->lastErrorMsg());
}
return $token;
}
function tokenRefresh($tokenid) {
$time = time();
$expires = $time + 2592000; // 30 days
$sql = "UPDATE tokens SET lastuse='$time', expires='$expires' WHERE id='$tokenid';";
$ret = $this->exec($sql);
if(!$ret) {
die($this->lastErrorMsg());
}
}
function tokenRemove($token) {
$hashed = hash('sha256', $token);
$sql = "DELETE FROM tokens WHERE token='$hashed';";
$ret = $this->exec($sql);
if(!$ret) {
die($this->lastErrorMsg());
}
}
function getAuthedUserId($token=NULL) {
if (empty($token)) {
if (empty($_COOKIE['token'])) {
return false;
}
$token = base64_decode($_COOKIE['token']);
}
$hashed = hash('sha256', $token);
$sql = "SELECT id AS id, userid AS userid, expires AS expires FROM tokens WHERE token='$hashed';";
$ret = $this->query($sql)->fetchArray(SQLITE3_ASSOC);
if(!$ret) {
return false;
}
if ($ret['expires'] < time()) {
$this->tokenRemove($token);
return false;
}
$this->tokenRefresh($ret['id']);
return $ret['userid'];
}
function getPosts($userid=NULL, $personaid = NULL) {
$sql = "SELECT * FROM posts AS post LEFT JOIN users AS user ON post.userid=user.id LEFT JOIN personas AS persona ON post.personaid=persona.id;";
$ret = $this->query($sql);
$array = array();
while ($row = $ret->fetchArray(SQLITE3_ASSOC)) {
array_push($array, $row);
}
return $array;
}
}
?>

106
src/index.php Executable file
View file

@ -0,0 +1,106 @@
<?php
require_once "inc/database.php";
function getRandomIcon() {
$files = glob('./snufficon/*.png');
$random_file_num = array_rand($files);
return $files[$random_file_num];;
}
$randomicon = getRandomIcon();
$database = new DataBase();
if(!$database) {
die($database->lastErrorMsg());
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<link rel="stylesheet" href="style.css" />
<link rel="icon" type="image/x-icon" href="snufficon/mouthless.png">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Snuffler</title>
</head>
<body>
<div id="flexout">
<div id="lpanel" class="flexpanel">
<ul>
<li>Kotisivu</li>
<li>Viestit</li>
<li>Kalavaleet</li>
<li>Takasivu</li>
</ul>
</div>
<div id="rpanel" class="flexpanel">
<ul>
<li>Mikko Mällikäs<br /><small>@mmallikas</small></li>
<li>Jarkko Toivanen<br /><small>@jt</small></li>
</ul>
</div>
<div id="centerbox">
<div id="titlebox"><img src="<?php echo $randomicon; ?>" alt="" />Snuffler</div>
<?php
if (!$database->getAuthedUserId()) {
?>
<form id="loginform" method="post" action="login.php">
<input type="text" name="name" placeholder="username" />
<input type="password" name="pass" placeholder="password" />
<input type="submit" name="submit" value="Log in" />
</form>
<?php
} else {
?>
<a href="logout.php">LOG OUT</a>
<form id="postform">
<textarea id="postformtextarea" name="text" rows="5" placeholder="Whatcha snuffin' about?"></textarea><br />
<div id="postformactionrow">
<select id="user" name="user">
<option value=0>SYSTEM</option>
<option value=1>User</option>
</select>
<input type="submit" id="submit" name="submit" value="Snuff!" />
</div>
</form>
<?php
}
?>
<?php
//$database->addPost("Test post", 0);
$posts = array_reverse($database->getPosts());
//var_dump($posts);
foreach($posts as $post) {
echo '<div class="post">';
echo '<div class="postinfo">';
echo '<strong>' . $post["user.name"] . '</strong>';
echo '<br><small>@' . $post["user.handle"] . '</small>';
echo '</div>';
echo '<p>' . $post["post.text"] . '</p>';
echo '<hr><small>' . date("D j.n.Y \@ G:i", $post["post.time"]) . '</small>';
echo '
<span class="postactions">
<img class="reactionaction" src="snufficon/thumbs_up.png" />
<img class="reactionaction" src="snufficon/thumbs_down.png" />
<img class="reactionaction" src="snufficon/joy.png" />
<img class="reactionaction" src="snufficon/sob.png" />
<img class="reactionaction" src="snufficon/heart_eyes.png" />
</span>';
echo "</div>";
}
$database->close();
?>
</div>
</div>
</body>
</html>

16
src/login.php Normal file
View file

@ -0,0 +1,16 @@
<?php
if (empty($_POST) || !isset($_POST['submit'])) {
die("Login canceled: no post / no submit");
}
require_once('inc/database.php');
$db = new DataBase();
$user = $db->getUserByHandle($_POST['name']);
if ($db->passwordVerify($user['user.id'], $_POST['pass'])) {
$token = $db->tokenAdd($user['user.id']);
$token64 = base64_encode($token);
$expires = time() + 2592000; // 30 days
setcookie('token', $token64, $expires);
}
header("Location: /");
?>

7
src/logout.php Normal file
View file

@ -0,0 +1,7 @@
<?php
setcookie("token", "", 0);
require_once('inc/database.php');
$db = new DataBase();
$db->tokenRemove(base64_decode($_COOKIE['token']));
header("Location: /");
?>

BIN
src/snufficon/angel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

BIN
src/snufficon/angry.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

BIN
src/snufficon/cat_face.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
src/snufficon/clown.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
src/snufficon/cold.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
src/snufficon/cowboy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
src/snufficon/drool.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
src/snufficon/excited.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

BIN
src/snufficon/fearful.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
src/snufficon/flush.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
src/snufficon/giggle.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

BIN
src/snufficon/happy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

BIN
src/snufficon/hot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
src/snufficon/hug.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
src/snufficon/joy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

BIN
src/snufficon/kissing.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9 KiB

BIN
src/snufficon/laughing.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

BIN
src/snufficon/lying.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

BIN
src/snufficon/mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

BIN
src/snufficon/melting.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

BIN
src/snufficon/mouthless.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

BIN
src/snufficon/nerd.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

BIN
src/snufficon/partying.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

BIN
src/snufficon/raging.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

BIN
src/snufficon/sad.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

BIN
src/snufficon/saluting.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

BIN
src/snufficon/scream.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

BIN
src/snufficon/shrug.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
src/snufficon/shush.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

BIN
src/snufficon/sick.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
src/snufficon/sleeping.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9 KiB

BIN
src/snufficon/smiling.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
src/snufficon/smirk.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

BIN
src/snufficon/sneeze.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

BIN
src/snufficon/sob.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

BIN
src/snufficon/swearing.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
src/snufficon/sweat.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
src/snufficon/thinking.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
src/snufficon/thumbs_up.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

BIN
src/snufficon/triumph.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

BIN
src/snufficon/vomiting.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
src/snufficon/wink.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

BIN
src/snufficon/woozy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
src/snufficon/yawning.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

BIN
src/snufficon/zany.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

100
src/style.css Normal file
View file

@ -0,0 +1,100 @@
body {
font-family: Tahoma, Verdana, sans-serif;
background-color: #000000;
color: #ffc000;
}
hr {
border-color: #584200;
}
#flexout {
display: flex;
max-width: 75rem;
margin: auto;
justify-content: center;
}
#lpanel {
order: 0;
}
#rpanel {
order: 2;
}
#rpanel, #lpanel, .flexpanel {
width: 15rem;
border-radius: 1rem;
padding: .5rem;
background-color: #271d00;
}
#loginform {
text-align: center;
}
#titlebox {
font-size: 5em;
text-align: center;
}
#titlebox > img {
height: 1.25em;
vertical-align: sub;
}
#centerbox {
margin-left: 1rem;
margin-right: 1rem;
background-color: #271d00;
border-radius: 1rem;
padding: .5rem;
flex-grow: 1;
order: 1;
}
#postform {
margin-top: 1rem;
margin-bottom: 1rem;
}
#postformtextarea {
box-sizing: border-box;
width: 100%;
border-radius: 1rem;
}
#postformactionrow {
text-align: right;
}
.post {
position: relative;
border-style: solid;
border-width: 1px;
padding: 1rem;
margin-top: 3rem;
border-radius: 1rem;
}
.postinfo {
position: absolute;
left: -1px;
top: -2em;
height: 3rem;
min-width: 15rem;
background-color: #ffc000;
color: #000000;
border-radius: 3rem;
border-bottom-left-radius: 0;
padding: .25rem;
padding-left: 1rem;
padding-right: 1rem;
text-wrap: nowrap;
}
.postactions {
/*float: right;*/
position: absolute;
background-color: #ffc000;
padding: .25rem;
border-radius: 2rem;
border-top-right-radius: 0;
right: -1px;
bottom: -1rem;
}
.reactionaction {
height: 2rem;
vertical-align: bottom;
}