aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md4
-rw-r--r--classes/BusinessAdmin.php46
-rw-r--r--classes/Constants.php4
-rw-r--r--classes/File.php14
-rw-r--r--include/file-get.php47
-rw-r--r--index.php3
-rw-r--r--install/index.php113
-rw-r--r--install/upgrade.php21
8 files changed, 189 insertions, 63 deletions
diff --git a/README.md b/README.md
index fd06d18..5538798 100644
--- a/README.md
+++ b/README.md
@@ -56,7 +56,6 @@ In classes/constants.php, you should at least set the following options:
`ba_offer`, `ba_client`, etc.
* `files_folder`: the absolute path to the files folder (this is a folder in
the BusinessAdmin directory)
-* `files_folder_external`: an HTTP(S) URL to the same files folder
* `url_external`: the external HTTP(S) URL to BusinessAdmin
* `url_internal`: the same URL, without the domain part
@@ -84,6 +83,8 @@ Go to `/install/index.php?password_cost` to benchmark your system to find an
appropriate password cost. Set the constant `password_cost` in
`classes/constants.php` to this value.
+You need to deny any requests for any files in the /files folder.
+
## Permissions
The files folder will be used to put generated invoices in. Make your server
@@ -171,6 +172,7 @@ are listed by name and removal time. This way, you never really lose your file.
### 0.5 (Jul 28, 2016)
+0.5.1 Files are hidden from the world.
0.5 Braintree integration.
### 0.4 (Jul 26, 2016)
diff --git a/classes/BusinessAdmin.php b/classes/BusinessAdmin.php
index 3e654a2..be6f1a4 100644
--- a/classes/BusinessAdmin.php
+++ b/classes/BusinessAdmin.php
@@ -76,6 +76,52 @@ class BusinessAdmin {
}
/**
+ * Get all file ids
+ *
+ * @see BusinessAdmin::getFiles() This funtion returns instances of the file class instead of just the ids
+ *
+ * @param PDO $pdo The PDO class for database connection
+ * @param string[] $where An array of WHERE clauses that will be AND-ed into a prepared statement
+ * @param mixed[] $variables An array of variables that should go into the prepared statement
+ *
+ * @throws PDOException Is something went wrong with the database
+ *
+ * @return int[] The ids
+ */
+ public static function getFileIds($pdo, $where = [], $variables = []) {
+ $ids = [];
+ $files = $pdo->prepare("SELECT `id` FROM `".Constants::db_prefix."file`" . ((count($where) > 0) ? (" WHERE (" . implode(') AND (', $where) . ")") : ""));
+ $files->execute($variables);
+ $files = $files->fetchAll(PDO::FETCH_ASSOC);
+ foreach ($files as $file) {
+ $ids[] = $file['id'];
+ }
+ return $ids;
+ }
+
+ /**
+ * Get all files
+ *
+ * @see BusinessAdmin::getFileIds() This function returns just the ids of the files, and not instances of the file class
+ *
+ * @param PDO $pdo The PDO class for database connection
+ * @param string[] $where An array of WHERE clauses that will be AND-ed into a prepared statement
+ * @param mixed[] $variables An array of variables that should go into the prepared statement
+ *
+ * @throws PDOException If something went wrong with the database
+ *
+ * @return file[] An array indexed by id of instances of the file class
+ */
+ public static function getFiles($pdo, $where = [], $variables = []) {
+ $ids = self::getFileIds($pdo, $where, $variables);
+ $files = [];
+ foreach ($ids as $id) {
+ $files[$id] = new File($pdo, $id);
+ }
+ return $files;
+ }
+
+ /**
* Get all client ids
*
* @see BusinessAdmin::getClients() This funtion returns instances of the client class instead of just the ids
diff --git a/classes/Constants.php b/classes/Constants.php
index fb2435d..fbac6cf 100644
--- a/classes/Constants.php
+++ b/classes/Constants.php
@@ -30,8 +30,6 @@ class Constants {
/** @const files_folder The folder to store all files (appendices, invoices, etc.) in; with a trailing slash */
const files_folder = '/var/www/localhost/BusinessAdmin/files/';
- /** @const files_folder_external The external URI to this folder; with a trailing slash */
- const files_folder_external = 'http://localhost/BusinessAdmin/files/';
/** @const files_folder_trash The folder inside files_folder to use a trash, without any trailing slashes */
const files_folder_trash = 'trash';
@@ -80,5 +78,5 @@ class Constants {
const password_cost = 10;
/** @const version Version of BusinessAdmin. Don't change this yourself! */
- const version = '0.5';
+ const version = '0.5.1';
}
diff --git a/classes/File.php b/classes/File.php
index 2545dc9..4a28f80 100644
--- a/classes/File.php
+++ b/classes/File.php
@@ -27,7 +27,17 @@
class File extends Model {
public
$table = 'file',
- $fillable_columns = ['filename'];
+ $fillable_columns = ['filename', 'secret_key'];
+
+ /**
+ * A random max-63-char string that can be used as secret_key
+ *
+ * @return string The random string
+ */
+ public static function getRandomSecretKey() {
+ return preg_replace('/[^\w]+/', '',
+ base64_encode(openssl_random_pseudo_bytes(45)));
+ }
/**
* Get the full internal path to the file
@@ -48,7 +58,7 @@ class File extends Model {
* @return string The URI
*/
public function getFilenameURI() {
- return Constants::files_folder_external . $this->filename;
+ return Constants::url_external . 'file/get?name=' . $this->filename . '&key=' . $this->secret_key;
}
//------------------------------------------------------------------------------
diff --git a/include/file-get.php b/include/file-get.php
new file mode 100644
index 0000000..b3f575d
--- /dev/null
+++ b/include/file-get.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Landing page
+ *
+ * This handles basically all requests. Every request not to an existing file path, should be redirected here.
+ * This file checks basic configuration and includes the required page, based on the REQUEST_URI.
+ *
+ * @author Camil Staps
+ *
+ * BusinessAdmin: administrative software for small companies
+ * Copyright (C) 2015 Camil Staps (ViviSoft)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+require_once('./conf.php');
+
+$filename = $_REQUEST['name'];
+$filepath = Constants::files_folder . $filename;
+
+$key = $_REQUEST['key'];
+
+$files = BusinessAdmin::getFiles($_pdo, ['`filename`=?'], [$filename]);
+if (count($files) == 0 || !file_exists($filepath) || is_dir($filepath)) {
+ http_response_code(404);
+ header('Content-type: text/plain');
+ echo "$filename could not be found";
+} elseif (array_pop($files)->secret_key != $key) {
+ http_response_code(403);
+ header('Content-type: text/plain');
+ echo "incorrect key";
+} else {
+ header('Content-type: ' . mime_content_type($filepath));
+ header('Content-Disposition: attachment; filename="'.$filename.'"');
+ readfile($filepath);
+}
diff --git a/index.php b/index.php
index b0cdfc5..6c049af 100644
--- a/index.php
+++ b/index.php
@@ -56,7 +56,8 @@ $pages = array(
'/settings' => './include/settings.php',
'/users/new' => './include/users-new.php',
'/ajax/collapse' => './include/ajax-collapse.php',
- '/pay' => './include/pay.php'
+ '/pay' => './include/pay.php',
+ '/file/get' => './include/file-get.php'
);
$_page = null;
diff --git a/install/index.php b/install/index.php
index d40959f..519e3c5 100644
--- a/install/index.php
+++ b/install/index.php
@@ -22,72 +22,73 @@ require('../conf.php');
if (isset($_GET['create_tables'])) {
try {
$_pdo->query("CREATE TABLE IF NOT EXISTS `".Constants::db_prefix."assignment` (
- `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
- `offerId` smallint(5) unsigned NOT NULL,
- `title` tinytext NOT NULL,
- `description` text NOT NULL,
- `hours` float NOT NULL,
- `price_per_hour` float NOT NULL,
- `VAT_percentage` float NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `offerId - title` (`offerId`,`title`(255)),
- KEY `offerId` (`offerId`)
+ `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
+ `offerId` smallint(5) unsigned NOT NULL,
+ `title` tinytext NOT NULL,
+ `description` text NOT NULL,
+ `hours` float NOT NULL,
+ `price_per_hour` float NOT NULL,
+ `VAT_percentage` float NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `offerId - title` (`offerId`,`title`(255)),
+ KEY `offerId` (`offerId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1");
$_pdo->query("CREATE TABLE IF NOT EXISTS `".Constants::db_prefix."client` (
- `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
- `name` tinytext NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `name` (`name`(255))
+ `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
+ `name` tinytext NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `name` (`name`(255))
) ENGINE=InnoDB DEFAULT CHARSET=latin1");
$_pdo->query("CREATE TABLE IF NOT EXISTS `".Constants::db_prefix."contact` (
- `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
- `clientId` smallint(5) unsigned NOT NULL,
- `name` tinytext NOT NULL,
- `email` varchar(680) NOT NULL,
- `address` tinytext NOT NULL,
- `address_2` tinytext,
- `postal_code` varchar(7) NOT NULL,
- `city` tinytext NOT NULL,
- `country` tinytext NOT NULL,
- `language` varchar(3) NOT NULL DEFAULT 'en',
- PRIMARY KEY (`id`),
- UNIQUE KEY `clientId-name` (`clientId`,`name`(255)),
- KEY `clientId` (`clientId`)
+ `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
+ `clientId` smallint(5) unsigned NOT NULL,
+ `name` tinytext NOT NULL,
+ `email` varchar(680) NOT NULL,
+ `address` tinytext NOT NULL,
+ `address_2` tinytext,
+ `postal_code` varchar(7) NOT NULL,
+ `city` tinytext NOT NULL,
+ `country` tinytext NOT NULL,
+ `language` varchar(3) NOT NULL DEFAULT 'en',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `clientId-name` (`clientId`,`name`(255)),
+ KEY `clientId` (`clientId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1");
$_pdo->query("CREATE TABLE IF NOT EXISTS `".Constants::db_prefix."discount` (
- `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
- `offerId` smallint(5) unsigned NOT NULL,
- `title` tinytext NOT NULL,
- `description` text NOT NULL,
- `value` float unsigned NOT NULL,
+ `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
+ `offerId` smallint(5) unsigned NOT NULL,
+ `title` tinytext NOT NULL,
+ `description` text NOT NULL,
+ `value` float unsigned NOT NULL,
`VAT_percentage` float NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;");
$_pdo->query("CREATE TABLE IF NOT EXISTS `".Constants::db_prefix."file` (
- `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
- `filename` varchar(100) NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `filename` (`filename`)
+ `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
+ `filename` varchar(100) NOT NULL,
+ `secret_key` varchar(63) DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `filename` (`filename`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1");
$_pdo->query("CREATE TABLE IF NOT EXISTS `".Constants::db_prefix."offer` (
- `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
- `contactId` smallint(5) unsigned NOT NULL,
- `start_date` date NOT NULL,
- `end_date` date NOT NULL,
- `invoice_date` date NOT NULL,
- `accepted` tinyint(1) unsigned NOT NULL DEFAULT '0',
+ `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
+ `contactId` smallint(5) unsigned NOT NULL,
+ `start_date` date NOT NULL,
+ `end_date` date NOT NULL,
+ `invoice_date` date NOT NULL,
+ `accepted` tinyint(1) unsigned NOT NULL DEFAULT '0',
`invoice_fileId` smallint(5) unsigned DEFAULT NULL,
`payment_key` varchar(63) DEFAULT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `invoice_fileId` (`invoice_fileId`),
- KEY `contactId` (`contactId`),
- KEY `contactId_2` (`contactId`),
- KEY `invoice_fileId_2` (`invoice_fileId`)
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `invoice_fileId` (`invoice_fileId`),
+ KEY `contactId` (`contactId`),
+ KEY `contactId_2` (`contactId`),
+ KEY `invoice_fileId_2` (`invoice_fileId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1");
$_pdo->query("CREATE TABLE IF NOT EXISTS `payment` (
@@ -100,24 +101,24 @@ if (isset($_GET['create_tables'])) {
) ENGINE=InnoDB DEFAULT CHARSET=latin1;");
$_pdo->query("CREATE TABLE IF NOT EXISTS `".Constants::db_prefix."user` (
- `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
+ `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(24) NOT NULL,
`password` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;");
$_pdo->query("ALTER TABLE `".Constants::db_prefix."assignment`
- ADD CONSTRAINT `assignment_ibfk_1` FOREIGN KEY (`offerId`) REFERENCES `".Constants::db_prefix."offer` (`id`)");
+ ADD CONSTRAINT `assignment_ibfk_1` FOREIGN KEY (`offerId`) REFERENCES `".Constants::db_prefix."offer` (`id`)");
- $_pdo->query("ALTER TABLE `".Constants::db_prefix."contact`
- ADD CONSTRAINT `contact_ibfk_1` FOREIGN KEY (`clientId`) REFERENCES `".Constants::db_prefix."client` (`id`)");
+ $_pdo->query("ALTER LE `".Constants::db_prefix."contact`
+ ADD CONSTRAINT `contact_ibfk_1` FOREIGN KEY (`clientId`) REFERENCES `".Constants::db_prefix."client` (`id`)");
- $_pdo->query("ALTER TABLE `".Constants::db_prefix."discount`
- ADD CONSTRAINT `discount_ibfk_1` FOREIGN KEY (`offerId`) REFERENCES `".Constants::db_prefix."offer` (`id`);");
+ $_pdo->query("ALTER LE `".Constants::db_prefix."discount`
+ ADD CONSTRAINT `discount_ibfk_1` FOREIGN KEY (`offerId`) REFERENCES `".Constants::db_prefix."offer` (`id`);");
- $_pdo->query("ALTER TABLE `".Constants::db_prefix."offer`
- ADD CONSTRAINT `offer_ibfk_1` FOREIGN KEY (`invoice_fileId`) REFERENCES `".Constants::db_prefix."file` (`id`),
- ADD CONSTRAINT `offer_ibfk_2` FOREIGN KEY (`contactId`) REFERENCES `".Constants::db_prefix."contact` (`id`)");
+ $_pdo->query("ALTER LE `".Constants::db_prefix."offer`
+ ADD CONSTRAINT `offer_ibfk_1` FOREIGN KEY (`invoice_fileId`) REFERENCES `".Constants::db_prefix."file` (`id`),
+ ADD CONSTRAINT `offer_ibfk_2` FOREIGN KEY (`contactId`) REFERENCES `".Constants::db_prefix."contact` (`id`)");
$_pdo->query("CREATE UNIQUE INDEX `payment_uniq_1` ON `".Constants::db_prefix."payment` (`offerId`);");
$_pdo->query("ALTER TABLE `payment`
diff --git a/install/upgrade.php b/install/upgrade.php
index 8ead230..db0c913 100644
--- a/install/upgrade.php
+++ b/install/upgrade.php
@@ -31,6 +31,8 @@ function lower_version($that, $new) {
for ($i = 0; $i < count($new); $i++) {
if ($new[$i] > $that[$i]) {
return true;
+ } elseif ($new[$i] < $that[$i]) {
+ return false;
}
}
return false;
@@ -111,15 +113,34 @@ if (isset($_GET['upgrade'])) {
try {
$_pdo->query("ALTER TABLE `".Constants::db_prefix."offer`
ADD `payment_key` VARCHAR(63) DEFAULT NULL;");
+
$_pdo->query("ALTER TABLE `".Constants::db_prefix."payment`
ADD `braintree_id` VARCHAR(36) DEFAULT NULL,
ADD `braintree_status` VARCHAR (63) NULL DEFAULT NULL;");
+
$_pdo->query("CREATE UNIQUE INDEX `payment_uniq_1` ON `".Constants::db_prefix."payment` (`offerId`);");
} catch (PDOException $e) {
echo "Altering the database structure failed with a PDOException ({$e->getCode()}): {$e->getMessage()}<br/>" . $e->getTraceAsString();
}
}
+ if (lower_version($_GET['upgrade'], '0.5.1')) {
+ try {
+ $_pdo->query("ALTER TABLE `".Constants::db_prefix."file`
+ ADD `secret_key` VARCHAR(63) DEFAULT NULL;");
+
+ $files = $_pdo->query("SELECT `id` FROM `".Constants::db_prefix."file` WHERE `secret_key` IS NULL;");
+ $stmt = $_pdo->prepare("UPDATE `".Constants::db_prefix."file` SET `secret_key`=? WHERE `id`=?");
+ foreach ($files->fetchAll(PDO::FETCH_ASSOC) as $file) {
+ $key = preg_replace('/[^\w]+/', '',
+ base64_encode(openssl_random_pseudo_bytes(45)));
+ $stmt->execute([$key, $file['id']]);
+ }
+ } catch (PDOException $e) {
+ echo "Altering the database structure failed with a PDOException ({$e->getCode()}): {$e->getMessage()}<br/>" . $e->getTraceAsString();
+ }
+ }
+
echo "<br/>All done.";
}
?>