decide.nolog.cz/api/classes/poll.php
jelhan b9bef69977 user has to proof that he knows encryption key when he participates
Therefore sha256 hash of encryption key is validated against one which is stored
on server on poll creation.
This one is transfered as X-Croodle-Proof-Key-Knowledge HTTP HEADER.

Prevents an attacker of transmitting data with wrong encryption key, which
would cause decryption errors for legit users.
2015-08-23 18:56:41 +02:00

132 lines
3 KiB
PHP

<?php
require_once 'model.php';
require_once 'user.php';
class Poll extends model {
const ENCRYPTED_PROPERTIES = [
'anonymousUser',
'answers',
'answerType',
'creationDate',
'description',
'expirationDate',
'forceAnswer',
'isDateTime',
'options',
'pollType',
'timezone',
'title'
];
const ID_LENGTH = 10;
const ID_CHARACTERS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
const PLAIN_PROPERTIES = [
'version'
];
const PROOF_KEY_KNOWLEDGE = 'save';
const SERVER_PROPERTIES = [
'serverExpirationDate'
];
private function delete() {
$this->deleteDirRecursively(
$this->getDir()
);
}
private function deleteDirRecursively($dir) {
if (substr($dir, -1) !== '/') {
throw new Exception('dir has to end on /');
}
$dirHandle = opendir($dir);
while (false !== ($filename = readdir($dirHandle))) {
if ($filename === '.' || $filename === '..') {
continue;
}
if (is_dir($dir . $filename)) {
$this->deleteDirRecursively($dir . $filename . '/');
}
elseif (is_file($dir . $filename)) {
unlink($dir . $filename);
}
else {
throw new Exception($filename . " in " . $dir . " is not a dir neither a file - what is it?");
}
}
closedir($dirHandle);
rmdir($dir);
}
protected function generateNewId() {
$characters = self::ID_CHARACTERS;
$randomString = '';
for ($i = 0; $i < self::ID_LENGTH; $i++) {
$randomString .= $characters[rand(0, strlen($characters) - 1)];
}
return $randomString;
}
protected function getDir() {
if (($this->get('id') === null)) {
throw new Exception('id must be set before calling getDir');
}
return DATA_FOLDER . $this->get('id') . '/';
}
protected function getPollDir() {
return $this->getDir();
}
protected function getPath() {
return $this->getDir() . 'poll_data';
}
protected function getUsers() {
$users = [];
$userDir = DATA_FOLDER . $this->get('id') . '/users/';
if (is_dir($userDir)) {
$dir = opendir($userDir);
while(false !== ($file = readdir($dir))) {
if($file === '.' || $file === '..') {
continue;
}
$users[] = User::restore($this->get('id') . '_' . $file)->export();
}
closedir($dir);
}
return $users;
}
protected function includeRelationships(&$data) {
$data->users = $this->getUsers();
}
private function isExpired() {
return
( $expirationDate = DateTime::createFromFormat('Y-m-d\TH:i:s.uO', $this->get('serverExpirationDate')) ) &&
$expirationDate < new DateTime();
}
public static function isValidId($id) {
$idCharacters = str_split($id);
return strlen($id) === 10 &&
count(array_diff($idCharacters, str_split(self::ID_CHARACTERS))) === 0;
}
protected function restoreHook() {
if ($this->isExpired()) {
$this->delete();
return false;
}
}
}