Skip to content
Snippets Groups Projects
Commit 920914fc authored by Janne Mareike Koschinski's avatar Janne Mareike Koschinski
Browse files

Initial PoC

parents
Branches
Tags
No related merge requests found
<?php
//
// Quassel Backlog Search - classes
// developed 2009 by m4yer <m4yer@minad.de> under a Creative Commons Licence by-nc-sa 3.0
//
// password hashing improvements developed 2015 by mamarley
//
function initialAuthenticateUser($plainPassword,$dbHashedPassword,$hashVersion){
switch($hashVersion){
case null:
case 0:
return initialCheckHashedPasswordSha1($plainPassword,$dbHashedPassword);
break;
case 1:
return initialCheckHashedPasswordSha2_512($plainPassword,$dbHashedPassword);
break;
default:
return false;
break;
}
}
function initialCheckHashedPasswordSha1($plainPassword,$dbHashedPassword){
$calculatedPasswordHash=hash("sha1",$plainPassword);
if($calculatedPasswordHash==$dbHashedPassword){
return $calculatedPasswordHash;
}
return false;
}
function initialCheckHashedPasswordSha2_512($plainPassword,$dbHashedPassword){
$dbHashedPasswordArray=explode(":",$dbHashedPassword);
if(count($dbHashedPasswordArray)==2){
$calculatedPasswordHash=hash("sha512",$plainPassword . $dbHashedPasswordArray[1]);
if($calculatedPasswordHash==$dbHashedPasswordArray[0]){
return $dbHashedPasswordArray[0];
}
}
return false;
}
?>
\ No newline at end of file
<?php
require_once('auth_functions.php');
class Backend {
private $dbh;
private $user;
public function connect($configfile) {
$config = parse_ini_file($configfile);
if ($config['local']) {
$this->dbh = new PDO('pgsql:dbname='.$config['dbname'].' user='.$config['user'].' password='.$config['password']);
} else {
$this->dbh = new PDO('pgsql:host='.$config['host'].' port='.$config['port'].' dbname='.$config['dbname'].' user='.$config['user'].' password='.$config['password']);
}
}
public function auth($username, $password) {
if (!isset($username) || !isset($password))
return false;
$stmt = $this->dbh->prepare("SELECT * FROM quasseluser WHERE username = ?");
$stmt->execute(array($_POST['username']));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (count($rows) !== 1)
return false;
$row = $rows[0];
if (!initialAuthenticateUser($_POST['password'], $row['password'], $row['hashversion']))
return false;
$this->user = array(
'id' => $row['userid'],
'name' => $row['username']
);
return true;
}
public function search($arg_query, $arg_limit, $arg_offset) {
$sql = "SELECT backlog.messageid, buffer.bufferid, buffer.buffername, sender.sender, backlog.\"time\", network.networkname, ts_headline(backlog.message, query) AS message FROM backlog JOIN sender ON backlog.senderid = sender.senderid JOIN buffer ON backlog.bufferid = buffer.bufferid JOIN network ON buffer.networkid = network.networkid, to_tsquery('simple', ?) query WHERE type = 1 AND buffer.userid = ? AND to_tsvector('simple', message) @@ query ORDER BY messageid DESC LIMIT ? OFFSET ?;";
$stmt = $this->dbh->prepare($sql);
$limit = max(min($arg_limit, 50), 10);
$offset = max(0, $arg_offset);
$stmt->execute(array($arg_query, $this->user['id'], $limit, $offset));
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
public function after($arg_id, $arg_buffer, $arg_limit) {
$sql = "SELECT backlog.messageid, buffer.bufferid, buffer.buffername, sender.sender, backlog.\"time\", network.networkname, backlog.message FROM backlog JOIN sender ON backlog.senderid = sender.senderid JOIN buffer ON backlog.bufferid = buffer.bufferid JOIN network ON buffer.networkid = network.networkid WHERE buffer.userid = ? AND buffer.bufferid = ? AND messageid >= ? ORDER BY messageid ASC LIMIT ?;";
$stmt = $this->dbh->prepare($sql);
$limit = max(min($arg_limit+1, 50), 1);
$stmt->execute(array($this->user['id'], $arg_buffer, $arg_id, $limit));
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
public function before($arg_id, $arg_buffer, $arg_limit) {
$sql = "SELECT backlog.messageid, buffer.bufferid, buffer.buffername, sender.sender, backlog.\"time\", network.networkname, backlog.message FROM backlog JOIN sender ON backlog.senderid = sender.senderid JOIN buffer ON backlog.bufferid = buffer.bufferid JOIN network ON buffer.networkid = network.networkid WHERE buffer.userid = ? AND buffer.bufferid = ? AND messageid < ? ORDER BY messageid DESC LIMIT ?;";
$stmt = $this->dbh->prepare($sql);
$limit = max(min($arg_limit, 50), 0);
$stmt->execute(array($this->user['id'], $arg_buffer, $arg_id, $limit));
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
public function context($arg_id, $arg_buffer, $arg_before, $arg_after) {
return array_merge(array_reverse($this->before($arg_id, $arg_buffer, $arg_before)), $this->after($arg_id, $arg_buffer, $arg_after));
}
}
?>
\ No newline at end of file
local=false
dbname=quassel
user=quassel
password=supersecurepassword
host=example.org
port=5436
<?php
require_once('backend.php');
$backend = new Backend();
$backend->connect('/var/www/config.ini');
if (!$backend->auth($_POST['username'], $_POST['password'])) {
header($_SERVER['SERVER_PROTOCOL'].' 403 Forbidden');
header('Status: 403 Forbidden');
exit;
}
header('Content-Type: application/json');
echo json_encode($backend->context(intval($_GET['msg']),intval($_GET['buffer']),intval($_GET['before']),intval($_GET['after'])))."\n";
?>
\ No newline at end of file
<!DOCTYPE html>
<meta charset="utf-8">
<title>Quassel Search</title>
<link rel="stylesheet" href="style.css">
<nav>
<div id="searchbar">
<input type="text" name="q" id="q">
<div id="searchicon"><span>Search</span></div>
</div>
</nav>
<section id="results">
<button id="login">Login</button> <button id="logout">Logout</button>
</section>
<script src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
<script>
var userdata = { "username": localStorage.getItem("username"), "password": localStorage.getItem("password") };
var result = undefined;
var renderBuffer = function (buffer) {
return (
"<buffer>" +
"<h2>" + buffer.network + "" + buffer.name + "</h2>" +
"<article>" +
buffer.messages.map(renderMessage).reduce((x, y) => x + y) +
"</article>" +
"</buffer>"
)
}
var renderMessage = function (message) {
return (
"<message data-id='" + message.messageid + "'>" +
"<time>" + message.time.toLocaleString() + "</time>" +
"<sender>" + message.sender.split("!")[0] + "</sender>" +
"<content>" + message.message + "</content>" +
"</message>"
)
}
var render = function (data) {
return $.map(data, renderBuffer).reduce((x, y) => x + y);
}
var display = function (data) {
$("#results").children().remove();
$("#results").append(data);
}
var sortData = function (data) {
var buffers = {};
data.forEach(message => {
if (!buffers.hasOwnProperty(message.bufferid)) {
buffers[message.bufferid] = {
id: message.bufferid,
name: message.buffername,
network: message.networkname,
messages: []
}
}
message.time = new Date(message.time.replace(" ", "T") + "Z");
buffers[message.bufferid].messages.push(message);
});
return buffers;
}
var show = function (data) {
result = data;
display(render(sortData(data)));
}
var load = function() {
$("#results").children().remove()
$.post("search.php?query="+$("#q").val(), userdata, show, "json");
}
$("#q").keypress(function (e) {
var key = e.which || e.keyCode;
if (key === 13) {
load();
}
})
$("#login").click(function() {
localStorage.setItem("username", prompt("username"));
localStorage.setItem("password", prompt("password"));
})
$("#logout").click(function() {
localStorage.removeItem("username");
localStorage.removeItem("password");
})
</script>
\ No newline at end of file
<?php
require_once('backend.php');
$backend = new Backend();
$backend->connect('/var/www/config.ini');
if (!$backend->auth($_POST['username'], $_POST['password'])) {
header($_SERVER['SERVER_PROTOCOL'].' 403 Forbidden');
header('Status: 403 Forbidden');
exit;
}
header('Content-Type: application/json');
echo json_encode($backend->search($_GET['query'],$_GET['limit'],$_GET['offset']))."\n";
?>
\ No newline at end of file
style.css 0 → 100644
* {
padding: 0;
margin: 0;
box-shadow: border-box;
}
body {
background: #F2F2F2;
font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif;
font-size: 81.25%;
}
section {
max-width: 1200px;
padding: 56px 4rem 0 4rem;
margin: 0 auto;
}
buffer > article {
background: #fff;
font-size: 13px;
box-shadow: 0 -1px 0 #e5e5e5,0 0 2px rgba(0,0,0,.12),0 2px 4px rgba(0,0,0,.24)
}
buffer > h2 {
border-bottom: 1px solid transparent;
border-top: 1px solid transparent;
color: #616161;
margin-top: 20px;
padding-bottom: 10px;
padding-left: 22px;
position: relative;
will-change: transform,-webkit-transform;
}
message {
display: flex;
height: 48px;
line-height: 48px;
border-bottom: 1px solid #e5e5e5;
color: #212121;
}
message sender {
width: 148px;
display: inline-block;
font-weight: bold;
flex-shrink: 0;
}
message time {
width: 148px;
display: inline-block;
padding: 0 24px;
text-align: right;
flex-shrink: 0;
}
message content {
padding: 0 24px;
flex-shrink: 1;
overflow: hidden;
}
message:last-child {
border-bottom: none;
}
nav {
position: fixed;
left: 0;
right: 0;
top: 0;
height: 56px;
background: #4285f4;
padding: 0px 4rem;
}
nav input[type=text]::-moz-placeholder {
color: #ffffff;
opacity: 1;
-webkit-font-smoothing: auto;
-moz-osx-font-smoothing: auto;
}
nav input[type=text]:focus::-moz-placeholder {
color: #757575;
opacity: 1;
-webkit-font-smoothing: auto;
-moz-osx-font-smoothing: auto;
}
#searchbar {
max-width: 1200px;
margin: 10px auto;
height: 36px;
display: block;
position: relative;
}
nav input[type=text] {
width: 100%;
height: 100%;
display: inline-block;
border: none;
-webkit-transition: background .15s;
transition: background .15s;
background: rgba(255,255,255,.15);
border-radius: 2px;
padding: 0 72px;
color: #ffffff;
box-sizing: border-box;
}
#searchicon {
background-image: url(https://ssl.gstatic.com/bt/C3341AA7A1A076756462EE2E5CD71C11/1x/ic_search_wht_24dp_r1.png);
display: inline-block;
width: 72px;
height: 36px;
position: absolute;
left: 0;
top: 0;
background-repeat: no-repeat;
background-position: center center;
}
#searchicon span {
display: none;
}
nav input[type=text]:hover {
background: rgba(255,255,255,.25);
}
nav input[type=text]:focus {
background: #f6f6f6;
color: #212121;
}
nav input[type=text]:focus+#searchicon {
background-image: url(https://ssl.gstatic.com/bt/C3341AA7A1A076756462EE2E5CD71C11/1x/ic_search_blk_24dp_r1.png);
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment