summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Dolgov <[email protected]>2017-06-28 12:32:48 +0300
committerAndrew Dolgov <[email protected]>2017-06-28 12:32:48 +0300
commit9f4927825bb5efeefdff9a2aac05c5b3200f5ef6 (patch)
treef7782cb57127c68bfd5c67fb0d90c725eb8f0e68
parent4496d4a5e1f3ddb5fd0b3a0315f12c207e7c9041 (diff)
move to internal user management because it's impossible to implement
proper transparent offline mode with http auth (worker is incapable of authenticating properly) MIGRATION: 1. disable HTTP authentication (this is important!) 2. add two new tables to db/scratch.db (sessions & users) 3. create users via useradm.php (same names and passwords, previous data is kept)
-rw-r--r--backend.php13
-rw-r--r--db.php20
-rw-r--r--index.php15
-rw-r--r--login.php73
-rw-r--r--logout.php10
-rw-r--r--schema.sql16
-rw-r--r--sessions.php68
-rw-r--r--useradm.php59
-rw-r--r--worker.js42
9 files changed, 295 insertions, 21 deletions
diff --git a/backend.php b/backend.php
index 7a4b63e..4ab000d 100644
--- a/backend.php
+++ b/backend.php
@@ -1,15 +1,16 @@
<?php
require_once "config.php";
+ require_once "sessions.php";
+ require_once "db.php";
+
+ $ldb = Db::get();
$op = $_REQUEST["op"];
header("Content-type: text/json");
- $ldb = new SQLite3(SCRATCH_DB);
- $ldb->busyTimeout(30*1000);
-
- $owner = SQLite3::escapeString($_SERVER["PHP_AUTH_USER"]);
+ $owner = SQLite3::escapeString($_SESSION["owner"]);
if (!$owner) {
header($_SERVER["SERVER_PROTOCOL"]." 401 Unauthorized");
@@ -43,7 +44,11 @@
}
break;
+ case "getowner":
+ $owner = SQLite3::escapeString($_SESSION["owner"]);;
+ print json_encode(["owner" => $owner]);
+ break;
case "getinfo":
$id = (int) $_REQUEST["id"];
diff --git a/db.php b/db.php
new file mode 100644
index 0000000..1dc8ce0
--- /dev/null
+++ b/db.php
@@ -0,0 +1,20 @@
+<?php
+class Db {
+ private static $instance;
+ private $dbh;
+
+ private function __construct() {
+ $this->dbh = new SQLite3(__DIR__ . "/" . SCRATCH_DB);
+ $this->dbh->busyTimeout(30*1000);
+ }
+
+ public static function get() {
+ if (self::$instance == null)
+ self::$instance = new self();
+
+ return self::$instance->dbh;
+ }
+
+};
+
+?>
diff --git a/index.php b/index.php
index 59486eb..508148a 100644
--- a/index.php
+++ b/index.php
@@ -4,9 +4,15 @@
}
require_once "config.php";
+ require_once "sessions.php";
+ require_once "db.php";
- $owner = SQLite3::escapeString($_SERVER["PHP_AUTH_USER"]);
+ @$owner = SQLite3::escapeString($_SESSION["owner"]);
+ if (!$owner) {
+ header("Location: login.php");
+ exit;
+ }
if (basename(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)) != 'index.php') {
header('Location: index.php');
@@ -27,8 +33,7 @@
die(dirname(SCRATCH_DB) . " directory is not writable");
}
- $ldb = new SQLite3(SCRATCH_DB);
- $ldb->busyTimeout(30*1000);
+ $ldb = Db::get();
?>
<!DOCTYPE html>
<html>
@@ -85,6 +90,10 @@
<button type="submit" class="btn btn-default">Search</button>
</form>
+ <ul class="nav navbar-nav navbar-right">
+ <li><a href="logout.php">Logout</a></li>
+ </li>
+
</div>
</div>
diff --git a/login.php b/login.php
new file mode 100644
index 0000000..e54d989
--- /dev/null
+++ b/login.php
@@ -0,0 +1,73 @@
+<?php
+ require_once "config.php";
+ require_once "sessions.php";
+
+ @$op = $_REQUEST["op"];
+
+ if ($op == "perform-login") {
+ $user = SQLite3::escapeString($_REQUEST["user"]);
+ $password = SQLite3::escapeString('SHA256:' . hash('sha256', "$user:" . $_REQUEST["password"]));
+
+ $dbh = Db::get();
+
+ $res = $dbh->query("SELECT id FROM epube_users WHERE user = '$user' AND pass = '$password'");
+
+ if ($line = $res->fetchArray(SQLITE3_ASSOC)) {
+ $_SESSION["owner"] = $user;
+ header("Location: index.php");
+ }
+ }
+
+?>
+<!DOCTYPE html>
+<html>
+<head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <link href="lib/bootstrap/v3/css/bootstrap.min.css" rel="stylesheet" media="screen">
+ <link href="lib/bootstrap/v3/css/bootstrap-theme.min.css" rel="stylesheet" media="screen">
+ <link href="lib/qtip2/jquery.qtip.min.css" rel="stylesheet" media="screen">
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+ <script src="lib/bootstrap/v3/js/jquery.js"></script>
+ <script src="lib/bootstrap/v3/js/bootstrap.min.js"></script>
+ <script src="lib/holder.min.js"></script>
+ <script src="lib/localforage.min.js"></script>
+ <script src="lib/qtip2/jquery.qtip.min.js"></script>
+ <title>The Epube</title>
+ <link type="text/css" rel="stylesheet" media="screen" href="css/index.css" />
+ <link rel="shortcut icon" type="image/png" href="img/favicon.png" />
+ <link rel="icon" sizes="192x192" href="img/favicon_hires.png">
+ <link rel="manifest" href="manifest.json">
+ <meta name="mobile-web-app-capable" content="yes">
+ <script src="js/index.js"></script>
+ <script src="js/common.js"></script>
+</head>
+<body>
+
+<div class="navbar navbar-default navbar-static-top">
+<div class="container">
+ <div class="navbar-header">
+ <span class="navbar-brand"><a href="?">The Epube</a></span>
+ </div>
+</div>
+</div>
+
+<div class="container">
+
+ <form>
+ <input type="hidden" name="op" value="perform-login">
+
+ <div class="form-group">
+ <label>User</label>
+ <input class="form-control" required="true" name="user">
+ </div>
+ <div class="form-group">
+ <label>Password</label>
+ <input type="password" class="form-control" name="password" required="true">
+ </div>
+ <button type="submit" class="btn btn-default">Log in</button>
+ </form>
+
+</div>
+
+</body>
+</html>
diff --git a/logout.php b/logout.php
new file mode 100644
index 0000000..e4d40ed
--- /dev/null
+++ b/logout.php
@@ -0,0 +1,10 @@
+<?php
+ require_once "config.php";
+ require_once "sessions.php";
+
+ session_destroy();
+
+ header("Location: login.php");
+
+?>
+
diff --git a/schema.sql b/schema.sql
index 457b499..1cd0971 100644
--- a/schema.sql
+++ b/schema.sql
@@ -1,5 +1,9 @@
drop table if exists epube_pagination;
drop table if exists epube_books;
+drop table if exists epube_users;
+drop table if exists epube_sessions;
+
+drop index if exists epube_sessions_expire;
create table epube_pagination(
id integer not null primary key autoincrement,
@@ -13,3 +17,15 @@ create table epube_books(
owner varchar(200) not null,
lastcfi varchar(200) not null,
lastread integer not null);
+
+create table epube_users(
+ id integer not null primary key autoincrement,
+ user varchar(100) not null,
+ pass varchar(200) not null);
+
+create table epube_sessions (
+ id varchar(250) not null primary key,
+ data text,
+ expire integer not null);
+
+create index epube_sessions_expire on epube_sessions(expire);
diff --git a/sessions.php b/sessions.php
new file mode 100644
index 0000000..9a90ad4
--- /dev/null
+++ b/sessions.php
@@ -0,0 +1,68 @@
+<?php
+ require_once "config.php";
+ require_once "db.php";
+
+ define('SESSION_LIFETIME', 365 * 86400);
+
+ ini_set("session.name", "epube_sid");
+ ini_set("session.use_only_cookies", true);
+ ini_set("session.gc_maxlifetime", SESSION_LIFETIME);
+ ini_set("session.cookie_lifetime", SESSION_LIFETIME);
+
+ if (@$_SERVER['HTTPS'] == "on") {
+ ini_set("session.cookie_secure", true);
+ }
+
+ session_set_cookie_params(SESSION_LIFETIME);
+
+ function s_open ($s, $n) {
+ return true;
+ }
+
+ function s_read ($id){
+ $res = Db::get()->query("SELECT data FROM epube_sessions WHERE id='$id'");
+
+ if ($line = $res->fetchArray(SQLITE3_ASSOC)) {
+ return base64_decode($line["data"]);
+ } else {
+ $expire = time() + SESSION_LIFETIME;
+
+ Db::get()->query("INSERT INTO epube_sessions (id, data, expire)
+ VALUES ('$id', '', '$expire')");
+ }
+
+ }
+
+ function s_write ($id, $data) {
+ $data = base64_encode($data);
+ $expire = time() + SESSION_LIFETIME;
+
+ Db::get()->query("UPDATE epube_sessions SET data = '$data', expire = '$expire' WHERE id = '$id'");
+
+ return true;
+ }
+
+ function s_close () {
+ return true;
+ }
+
+ function s_destroy($id) {
+ Db::get()->query("DELETE FROM epube_sessions WHERE id = '$id'");
+
+ return true;
+ }
+
+ function s_gc ($expire) {
+ Db::get()->query("DELETE FROM epube_sessions WHERE expire < " . time());
+
+ return true;
+ }
+ session_set_save_handler("s_open",
+ "s_close", "s_read", "s_write",
+ "s_destroy", "s_gc");
+
+ register_shutdown_function('session_write_close');
+
+ session_start();
+
+?>
diff --git a/useradm.php b/useradm.php
new file mode 100644
index 0000000..2af25d2
--- /dev/null
+++ b/useradm.php
@@ -0,0 +1,59 @@
+#!/usr/bin/php
+<?php
+ require_once "config.php";
+ require_once "db.php";
+
+ $dbh = Db::get();
+
+ $longopts = [ "add:", "del:", "list", "help" ];
+
+ $options = getopt("", $longopts);
+
+ if (count($options) == 0 || isset($options["help"])) {
+ print "Manage Epube user database. Usage:
+ --add USER:PASSWORD
+ --del USER
+ --list\n";
+ }
+
+ if (isset($options["del"])) {
+ $user = SQLite3::escapeString($options["del"]);
+
+ print "Deleting user $user...\n";
+ $dbh->query("DELETE FROM epube_users WHERE user = '$user'");
+ }
+
+ if (isset($options["list"])) {
+ $res = $dbh->query("SELECT id, user FROM epube_users ORDER BY user");
+
+ while ($line = $res->fetchArray(SQLITE3_ASSOC)) {
+ printf("%d. %s\n", $line["id"], $line["user"]);
+ }
+
+ }
+
+ if (isset($options["add"])) {
+ @list($user, $pass) = explode(":", $options["add"]);
+
+ if (!$user || !$pass) {
+ print "Not enough arguments.\n";
+ exit;
+ }
+
+ $user = SQLite3::escapeString($user);
+ $pass_hash = SQLite3::escapeString('SHA256:' . hash('sha256', "$user:$pass"));
+
+ print "Adding user $user with password $pass...\n";
+
+ $res = $dbh->query("SELECT user FROM epube_users WHERE user = '$user'");
+
+ if ($line = $res->fetchArray(SQLITE3_ASSOC)) {
+ print "User already exists.\n";
+ } else {
+ $dbh->query("INSERT INTO epube_users (user, pass)
+ VALUES ('$user', '$pass_hash')");
+ }
+
+ }
+
+?>
diff --git a/worker.js b/worker.js
index d2ed2f7..268aee2 100644
--- a/worker.js
+++ b/worker.js
@@ -44,7 +44,7 @@ self.addEventListener('message', function(event){
cache.keys().then(function(keys) {
for (var i = 0; i < keys.length; i++) {
- fetch(keys[i],{credentials:'same-origin'}).then(function(resp) {
+ fetch(keys[i]).then(function(resp) {
if (resp.status == 200) {
cache.put(resp.url, resp);
}
@@ -59,24 +59,38 @@ self.addEventListener('message', function(event){
this.addEventListener('fetch', function(event) {
var req = event.request.clone();
- if (!navigator.onLine) {
- event.respondWith(
- caches.match(req).then(function(resp) {
+ event.respondWith(
+ caches.match(req).then(function(resp) {
- if (resp) return resp;
+ if (resp) {
+ return resp;
+ }
- if (req.url.match("read.html")) {
- return caches.match("read.html");
- }
+ if (req.url.match("read.html")) {
+ return caches.match("read.html");
+ }
- if (req.url.match("offline.html")) {
- return caches.match("offline.html");
+ if (req.url.match("offline.html")) {
+ return caches.match("offline.html");
+ }
+
+ return fetch(req).then(function(resp) {
+
+ if (resp.status == 200) {
+ if (resp.url.match("backend.php\\?op=cover")) {
+ return caches.open(CACHE_NAME).then(function(cache) {
+ cache.put(resp.url, resp.clone());
+ return resp;
+ });
+ }
}
- if (req.url.match("index.php")) {
+ return resp;
+ }).catch(function() {
+ if (req.url[req.url.length-1] == "/" || req.url.match("index.php")) {
return caches.match("offline.html");
}
- })
- );
- }
+ });
+ })
+ );
});