1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/ffsync_ynh.git synced 2024-09-03 18:26:38 +02:00

first commit

This commit is contained in:
root 2013-12-12 11:12:22 +00:00
commit 027ac79654
17 changed files with 2978 additions and 0 deletions

16
conf/nginx.conf Normal file
View file

@ -0,0 +1,16 @@
location PATHTOCHANGE {
alias ALIASTOCHANGE;
if ($scheme = http) {
rewrite ^ https://$server_name$request_uri? permanent;
}
index index.php;
try_files $uri $uri/ /index.php?$args;
location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param REMOTE_USER $remote_user;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}

26
conf/settings.php Normal file
View file

@ -0,0 +1,26 @@
<?php
// you can disable registration to the firefox sync server here,
// by setting ENABLE_REGISTER to false
//
define("ENABLE_REGISTER", true);
// firefox sync server url, this should end with a /
// e.g. https://YourDomain.de/Folder_und_ggf_/index.php/
//
define("FSYNCMS_ROOT", "https://URLFFSYNC/");
// Database connection credentials
//
define("SQLITE_FILE", "weave_db");
define("MYSQL_ENABLE", true);
define("MYSQL_HOST", "localhost");
define("MYSQL_DB", "yunobase");
define("MYSQL_USER", "yunouser");
define("MYSQL_PASSWORD", "yunopass");
// Use bcrypt instead of MD5 for password hashing
define("BCRYPT", true);
define("BCRYPT_ROUNDS", 12);
?>

33
manifest.json Normal file
View file

@ -0,0 +1,33 @@
{
"name": "Firefox Sync Server",
"id": "ffsync",
"description": {
"en": "",
"fr": ""
},
"developer": {
"name": "beudbeud",
"email": "beudbeud@beudibox.fr",
"url": "https://github.com/balu-/FSyncMS"
},
"multi_instance": "false",
"arguments": {
"install" : [
{
"name": "domain",
"ask": {
"en": "Choose a domain for Firefox-Sync Server"
},
"example": "domain.org"
},
{
"name": "path",
"ask": {
"en": "Choose a path for Firefox-Sync Server"
},
"example": "/ffsync",
"default": "/ffsync"
}
]
}
}

46
scripts/install Normal file
View file

@ -0,0 +1,46 @@
#!/bin/bash
# Retrieve arguments
domain=$1
path=$2
# Check domain/path availability
sudo yunohost app checkurl $domain$path -a ffsync
if [[ ! $? -eq 0 ]]; then
exit 1
fi
# Generate random password
db_pwd=$(dd if=/dev/urandom bs=1 count=200 2> /dev/null | tr -c -d '[A-Za-z0-9]' | sed -n 's/\(.\{24\}\).*/\1/p')
# Use 'FSyncMS' as database name and user
db_user=ffsync
# Initialize database and store mysql password for upgrade
sudo yunohost app initdb $db_user -p $db_pwd
sudo yunohost app setting ffsync mysqlpwd -v $db_pwd
# Copy files to the right place
final_path=/var/www/ffsync
sudo mkdir -p $final_path
sudo cp -a ../sources/* $final_path
sudo cp ../conf/settings.php $final_path/
# Change variables in FSyncMS configuration
sudo sed -i "s/yunouser/$db_user/g" $final_path/settings.php
sudo sed -i "s/yunopass/$db_pwd/g" $final_path/settings.php
sudo sed -i "s/yunobase/$db_user/g" $final_path/settings.php
sudo sed -i "s@URLFFSYNC@$domain$path@g" $final_path/settings.php
# Set permissions to roundcube directory
sudo chown -R www-data: $final_path
# Modify Nginx configuration file and copy it to Nginx conf directory
sed -i "s@PATHTOCHANGE@$path@g" ../conf/nginx.conf*
sed -i "s@ALIASTOCHANGE@$final_path/@g" ../conf/nginx.conf*
sudo cp ../conf/nginx.conf /etc/nginx/conf.d/$domain.d/wordpress.conf
# Reload Nginx and regenerate SSOwat conf
sudo service nginx reload
sudo yunohost app setting ffsync skipped_uris -v "/"
sudo yunohost app ssowatconf

10
scripts/remove Normal file
View file

@ -0,0 +1,10 @@
#!/bin/bash
db_user=wordpress
db_name=wordpress
root_pwd=$(sudo cat /etc/yunohost/mysql)
domain=$(sudo yunohost app setting ffsync domain)
mysql -u root -p$root_pwd -e "DROP DATABASE $db_name ; DROP USER $db_user@localhost ;"
sudo rm -rf /var/www/ffsync
sudo rm -f /etc/nginx/conf.d/$domain.d/ffsync.conf

2
sources/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*~
*.swp

81
sources/README.md Normal file
View file

@ -0,0 +1,81 @@
FSyncMS
=======
PHP Sync Server für Firefox Sync
Eine Erweiterung des Weave-Minimal Server (dessen Support leider eingestellt wurde).
Die derzeit aktuelle Versionen,
sowie alte Versionen und Anleitungen sind hier:
https://www.ohnekontur.de/category/technik/sync/fsyncms/
zu finden.
Weitere Erweiterungen sind in Planung.
Stay tuned.
Visit http://www.ohnekontur.de/2011/07/24/how-to-install-fsyncms-firefox-sync-eigener-server/ for install instructions
Visit http://www.ohnekontur.de for the newest version
FSyncMS v013
======
Database upgrade
for more information and some migration notice see
http://www.ohnekontur.de/2013/07/05/fsyncms-version-0-13-database-upgrade/
FSyncMS v012
======
Compatibility update
FSyncMS v011
======
Added dedicated setup script, which will create the database and the config file: settings.php
If you want to create it by your own, just generate the settings.php with the following content
<?php
//you can disable registration to the firefox sync server here,
// by setting ENABLE_REGISTER to false
//
//
//define("ENABLE_REGISTER",false);
define("ENABLE_REGISTER", true);
//pleas set the URL where firefox clients find the root of
// firefox sync server
// this should end with a /
//
define("FSYNCMS_ROOT","https://DOMAIN.de/Folder_und_ggf_/index.php/");
//MYSQL Params
define("MYSQL_ENABLE", false);
define("MYSQL_HOST","localhost");
define("MYSQL_DB","databaseName");
define("MYSQL_USER", "databaseUserName");
define("MYSQL_PASSWORD", "databaseUserPW");
?>
FSyncMS v010
======
MYSQL Support
FSyncMS v 09
======
Change Password now supported
working with firefox 12 (and lower)
Changelog:
Added change Password feature
FSyncMS v 08
======
Should be working with firefox 11 and lower (tested with 11)
Changelog:
Fixed user registration process,
fixed some delete problems

7
sources/TODO Normal file
View file

@ -0,0 +1,7 @@
== SOME TODOS ==
- Ein Präfix für die Tabellen, damit sie in eine vorhandene DB gelegt werden können.
- NOTIZ: Update der md5 Spalte der Usertabelle von length 64 auf length 124
- >ALTER TABLE `users` CHANGE `md5` `md5` VARCHAR( 124 ) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL

154
sources/WBOJsonOutput.php Normal file
View file

@ -0,0 +1,154 @@
<?php
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is Weave Minimal Server
#
# The Initial Developer of the Original Code is
# Mozilla Labs.
# Portions created by the Initial Developer are Copyright (C) 2008
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Toby Elliott (telliott@mozilla.com)
# Luca Tettamanti
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
#The datasets we might be dealing with here are too large for sticking it all into an array, so
#we need to define a direct-output method for the storage class to use. If we start producing multiples
#(unlikely), we can put them in their own class.
class WBOJsonOutput
{
private $_full = null;
private $_comma_flag = 0;
private $_output_format = 'json';
function __construct ($full = false)
{
$this->_full = $full;
if (array_key_exists('HTTP_ACCEPT', $_SERVER)
&& !preg_match('/\*\/\*/', $_SERVER['HTTP_ACCEPT'])
&& !preg_match('/application\/json/', $_SERVER['HTTP_ACCEPT']))
{
if (preg_match('/application\/whoisi/', $_SERVER['HTTP_ACCEPT']))
{
header("Content-type: application/whoisi");
$this->_output_format = 'whoisi';
}
elseif (preg_match('/application\/newlines/', $_SERVER['HTTP_ACCEPT']))
{
header("Content-type: application/newlines");
$this->_output_format = 'newlines';
}
}
}
function set_format($format)
{
$this->_output_format = $format;
}
function output($sth)
{
if (($rowcount = $sth->rowCount()) > 0)
{
header('X-Weave-Records: ' . $rowcount);
}
if ($this->_output_format == 'newlines')
{
return $this->output_newlines($sth);
}
elseif ($this->_output_format == 'whoisi')
{
return $this->output_whoisi($sth);
}
else
{
return $this->output_json($sth);
}
}
function output_json($sth)
{
echo '[';
while ($result = $sth->fetch(PDO::FETCH_ASSOC))
{
if ($this->_comma_flag) { echo ','; } else { $this->_comma_flag = 1; }
if ($this->_full)
{
$wbo = new wbo();
$wbo->populate($result);
echo $wbo->json();
}
else
echo json_encode($result{'id'});
}
echo ']';
return 1;
}
function output_whoisi($sth)
{
while ($result = $sth->fetch(PDO::FETCH_ASSOC))
{
if ($this->_full)
{
$wbo = new wbo();
$wbo->populate($result);
$output = $wbo->json();
}
else
$output = json_encode($result{'id'});
echo pack('N', mb_strlen($output, '8bit')) . $output;
}
return 1;
}
function output_newlines($sth)
{
while ($result = $sth->fetch(PDO::FETCH_ASSOC))
{
if ($this->_full)
{
$wbo = new wbo();
$wbo->populate($result);
echo preg_replace('/\n/', '\u000a', $wbo->json());
}
else
echo json_encode($result{'id'});
echo "\n";
}
return 1;
}
}
?>

329
sources/index.php Normal file
View file

@ -0,0 +1,329 @@
<?php
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is Weave Minimal Server
#
# The Initial Developer of the Original Code is
# Mozilla Labs.
# Portions created by the Initial Developer are Copyright (C) 2008
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Toby Elliott (telliott@mozilla.com)
# Luca Tettamanti
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
if ( ! file_exists("settings.php") && file_exists("setup.php") ) {
require_once "setup.php";
exit;
} else if ( ! file_exists("settings.php") ) {
echo "<hr><h2>Maybe the setup is not completed, missing settings.php</h2><hr>";
exit;
} else if ( file_exists("setup.php") ) {
echo "<hr><h2>Maybe the setup is not completed, else please delete setup.php</h2><hr>";
exit;
}
require_once 'weave_storage.php';
require_once 'weave_basic_object.php';
require_once 'weave_utils.php';
require_once 'weave_hash.php';
require_once "WBOJsonOutput.php";
//header("Content-type: application/json");
$server_time = round(microtime(1), 2);
header("X-Weave-Timestamp: " . $server_time);
# Basic path extraction and validation. No point in going on if these are missing
$path = '/';
if (!empty($_SERVER['PATH_INFO']))
$path = $_SERVER['PATH_INFO'];
else if (!empty($_SERVER['ORIG_PATH_INFO']))
$path = $_SERVER['ORIG_PATH_INFO'];
else if (!empty($_SERVER["REQUEST_URI"]))
{
log_error("experimental path");
# this is kind of an experimental try, i needed it so i build it,
# but that doesent mean that it does work... well it works for me
# and it shouldnt break anything...
$path = $_SERVER["REQUEST_URI"];
$lastfolder = substr(FSYNCMS_ROOT,strrpos(FSYNCMS_ROOT, "/",-2));
$path = substr($path, (strpos($path,$lastfolder) + strlen($lastfolder)-1)); #chop the lead slash
if(strpos($path,'?') != false)
$path = substr($path, 0, strpos($path,'?')); //remove php arguments
log_error("path_exp:".$path);
}
else
report_problem("No path found", 404);
$path = substr($path, 1); #chop the lead slash
log_error("start request_____" . $path);
// ensure that we got a valid request
if ( !$path )
report_problem("Invalid request, this was not a firefox sync request!", 400);
// split path into parts and make sure that all values are properly initialized
list($version, $username, $function, $collection, $id) = array_pad(explode('/', $path.'///'), 5, '');
if($version == 'user' || $version == 'misc')
{
//asking for userApi -> user.php
$include = true;
require 'user.php';
exit(); // should not get here, but how knows
}
header("Content-type: application/json");
if ($version != '1.0' && $version != '1.1')
report_problem('Function not found', 404);
if ($function != "info" && $function != "storage")
report_problem(WEAVE_ERROR_FUNCTION_NOT_SUPPORTED, 400);
if (!validate_username($username))
report_problem(WEAVE_ERROR_INVALID_USERNAME, 400);
#only a delete has meaning without a collection
if ($collection)
{
if (!validate_collection($collection))
report_problem(WEAVE_ERROR_INVALID_COLLECTION, 400);
}
else if ($_SERVER['REQUEST_METHOD'] != 'DELETE')
report_problem(WEAVE_ERROR_INVALID_PROTOCOL, 400);
#quick check to make sure that any non-storage function calls are just using GET
if ($function != 'storage' && $_SERVER['REQUEST_METHOD'] != 'GET')
report_problem(WEAVE_ERROR_INVALID_PROTOCOL, 400);
#user passes preliminaries, connections made, onto actually getting the data
try
{
$db = new WeaveStorage($username);
#Auth the user
verify_user($username, $db);
#user passes preliminaries, connections made, onto actually getting the data
if ($_SERVER['REQUEST_METHOD'] == 'GET')
{
if ($function == 'info')
{
switch ($collection)
{
case 'quota':
exit(json_encode(array($db->get_storage_total())));
case 'collections':
exit(json_encode($db->get_collection_list_with_timestamps()));
case 'collection_counts':
exit(json_encode($db->get_collection_list_with_counts()));
case 'collection_usage':
$results = $db->get_collection_storage_totals();
foreach (array_keys($results) as $collection)
{
$results[$collection] = ceil($results[$collection] / 1024); #converting to k from bytes
}
exit(json_encode($results));
default:
report_problem(WEAVE_ERROR_INVALID_PROTOCOL, 400);
}
}
elseif ($function == 'storage')
{
log_error("function storage");
if ($id) #retrieve a single record
{
$wbo = $db->retrieve_objects($collection, $id, 1); #get the full contents of one record
if (count($wbo) > 0)
{
$item = array_shift($wbo);
echo $item->json();
}
else
report_problem("record not found", 404);
}
else #retrieve a batch of records. Sadly, due to potential record sizes, have the storage object stream the output...
{
log_error("retrieve a batch");
$full = array_key_exists('full', $_GET) && $_GET['full'];
$outputter = new WBOJsonOutput($full);
$params = validate_search_params();
$ids = $db->retrieve_objects($collection, null, $full, $outputter,
$params['parentid'], $params['predecessorid'],
$params['newer'], $params['older'],
$params['sort'],
$params['limit'], $params['offset'],
$params['ids'],
$params['index_above'], $params['index_below'], $params['depth']
);
}
}
}
else if ($_SERVER['REQUEST_METHOD'] == 'PUT') #add a single record to the server
{
$wbo = new wbo();
if (!$wbo->extract_json(get_json()))
report_problem(WEAVE_ERROR_JSON_PARSE, 400);
check_quota($db);
check_timestamp($collection, $db);
#use the url if the json object doesn't have an id
if (!$wbo->id() && $id) { $wbo->id($id); }
$wbo->collection($collection);
$wbo->modified($server_time); #current microtime
if ($wbo->validate())
{
#if there's no payload (as opposed to blank), then update the metadata
if ($wbo->payload_exists())
$db->store_object($wbo);
else
$db->update_object($wbo);
}
else
{
report_problem(WEAVE_ERROR_INVALID_WBO, 400);
}
echo json_encode($server_time);
}
else if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
$json = get_json();
check_quota($db);
check_timestamp($collection, $db);
$success_ids = array();
$failed_ids = array();
$db->begin_transaction();
foreach ($json as $wbo_data)
{
$wbo = new wbo();
if (!$wbo->extract_json($wbo_data))
{
$failed_ids[$wbo->id()] = $wbo->get_error();
continue;
}
$wbo->collection($collection);
$wbo->modified($server_time);
if ($wbo->validate())
{
#if there's no payload (as opposed to blank), then update the metadata
if ($wbo->payload_exists())
{
$db->store_object($wbo);
}
else
{
$db->update_object($wbo);
}
$success_ids[] = $wbo->id();
}
else
{
$failed_ids[$wbo->id()] = $wbo->get_error();
}
}
$db->commit_transaction();
echo json_encode(array('success' => $success_ids, 'failed' => $failed_ids));
}
else if ($_SERVER['REQUEST_METHOD'] == 'DELETE')
{
check_timestamp($collection, $db);
if ($id)
{
$db->delete_object($collection, $id);
}
else if ($collection)
{
$params = validate_search_params();
$db->delete_objects($collection, null,
$params['parentid'], $params['predecessorid'],
$params['newer'], $params['older'],
$params['sort'],
$params['limit'], $params['offset'],
$params['ids'],
$params['index_above'], $params['index_below']
);
}
else if($function == 'storage') // ich vermute mal storage reinigen
{
if (!array_key_exists('HTTP_X_CONFIRM_DELETE', $_SERVER))
report_problem(WEAVE_ERROR_NO_OVERWRITE, 412);
$db->delete_storage($username);
}
else
{
if (!array_key_exists('HTTP_X_CONFIRM_DELETE', $_SERVER))
report_problem(WEAVE_ERROR_NO_OVERWRITE, 412);
log_error("delete "."Server ".print_r( $_SERVER, true));
$db->delete_user($username);
}
echo json_encode($server_time);
}
else
{
#bad protocol. There are protocols left? HEAD, I guess.
report_problem(1, 400);
}
}
catch(Exception $e)
{
report_problem($e->getMessage(), $e->getCode());
}
#The datasets we might be dealing with here are too large for sticking it all into an array, so
#we need to define a direct-output method for the storage class to use. If we start producing multiples
#(unlikely), we can put them in their own class.
#include_once "WBOJsonOutput.php";
?>

399
sources/setup.php Normal file
View file

@ -0,0 +1,399 @@
<?php
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is Weave Minimal Server
#
# The Initial Developer of the Original Code is
# Stefan Fischer
# Portions created by the Initial Developer are Copyright (C) 2012
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Daniel Triendl <daniel@pew.cc>
# balu
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
// --------------------------------------------
// variables start
// --------------------------------------------
$action = null;
$dbType = null;
$dbUser = null;
$dbName = null;
$dbPass = null;
$dbHost = null;
// --------------------------------------------
// variables end
// --------------------------------------------
// --------------------------------------------
// post handling start
// --------------------------------------------
if ( isset( $_POST['action'] ) ) {
$action = check_input($_POST['action']);
}
if ( isset( $_POST['dbType'] ) ) {
$dbType = check_input($_POST['dbType']);
}
if ( isset( $_POST['dbhost'] ) ) {
$dbHost = check_input($_POST['dbhost']);
}
if ( isset( $_POST['dbname'] ) ) {
$dbName = check_input($_POST['dbname']);
}
if ( isset( $_POST['dbuser'] ) ) {
$dbUser = check_input($_POST['dbuser']);
}
if ( isset( $_POST['dbpass'] ) ) {
$dbPass = check_input($_POST['dbpass']);
}
// --------------------------------------------
// post handling end
// --------------------------------------------
// --------------------------------------------
// functions start
// --------------------------------------------
/*
ensure that the input is not total waste
*/
function check_input( $data ) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
}
/*
create the config file with the database type
and the given connection credentials
*/
function write_config_file($dbt, $dbh, $dbn, $dbu, $dbp, $fsRoot) {
// construct the name of config file
//
$path = explode('/', $_SERVER['SCRIPT_FILENAME']);
array_pop($path);
array_push($path, 'settings.php');
$cfg_file_name = implode('/', $path);
if ( file_exists($cfg_file_name) && filesize( $cfg_file_name ) > 0 ) {
echo "<hr>The config file $cfg_file_name is already present</hr>";
return;
}
echo "Creating cfg file: " . $cfg_file_name;
// now build the content of the config file
//
$cfg_content = "<?php\n\n";
$cfg_content .= " // you can disable registration to the firefox sync server here,\n";
$cfg_content .= " // by setting ENABLE_REGISTER to false\n";
$cfg_content .= " // \n";
$cfg_content .= " define(\"ENABLE_REGISTER\", true);\n\n";
$cfg_content .= " // firefox sync server url, this should end with a /\n";
$cfg_content .= " // e.g. https://YourDomain.de/Folder_und_ggf_/index.php/\n";
$cfg_content .= " // \n";
$cfg_content .= " define(\"FSYNCMS_ROOT\", \"$fsRoot\");\n\n";
$cfg_content .= " // Database connection credentials\n";
$cfg_content .= " // \n";
$cfg_content .= " define(\"SQLITE_FILE\", \"weave_db\");\n";
if ( $dbt != "mysql" ) {
$cfg_content .= " define(\"MYSQL_ENABLE\", false);\n";
$cfg_content .= " define(\"MYSQL_HOST\", \"localhost\");\n";
$cfg_content .= " define(\"MYSQL_DB\", \"fsync\");\n";
$cfg_content .= " define(\"MYSQL_USER\", \"fsyncUserName\");\n";
$cfg_content .= " define(\"MYSQL_PASSWORD\", \"fsyncUserPassword\");\n";
} else {
$cfg_content .= " define(\"MYSQL_ENABLE\", true);\n";
$cfg_content .= " define(\"MYSQL_HOST\", \"$dbh\");\n";
$cfg_content .= " define(\"MYSQL_DB\", \"$dbn\");\n";
$cfg_content .= " define(\"MYSQL_USER\", \"$dbu\");\n";
$cfg_content .= " define(\"MYSQL_PASSWORD\", \"$dbp\");\n";
}
$cfg_content .= "\n";
$cfg_content .= " // Use bcrypt instead of MD5 for password hashing\n";
$cfg_content .= " define(\"BCRYPT\", true);\n";
$cfg_content .= " define(\"BCRYPT_ROUNDS\", 12);\n";
$cfg_content .= "\n?>\n";
// now write everything
//
$cfg_file = fopen($cfg_file_name, "a");
fputs($cfg_file, "$cfg_content");
fclose($cfg_file);
}
/*
print the html header for the form
*/
function print_header( $title ) {
if ( ! isset( $title ) ) {
$title = "";
}
print '<html><header><title>' . $title . '</title><body>
<h1>Setup FSyncMS</h1>
<form action="setup.php" method="post">';
}
/*
print the html footer
*/
function print_footer() {
print '</form></body></html>';
}
/*
print the html for for the mysql connection credentials
*/
function print_mysql_connection_form() {
print_header("MySQL database connection setup");
print 'MySQL database connection setup
<table>
<tr>
<td>Host</td>
<td><input type="text" name="dbhost" /></td>
</tr>
<tr>
<td>Instance name</td>
<td><input type="text" name="dbname" /></td>
</tr>
<tr>
<td>Username</td>
<td><input type="text" name="dbuser" /></td>
</tr>
<tr>
<td>Password</td>
<td><input type="password" name="dbpass" /></td>
</tr>
</table>
<input type="hidden" name="action" value="step2">
<input type="hidden" name="dbType" value="mysql">
<p><input type="submit" value="OK"></p>';
print_footer();
}
// --------------------------------------------
// functions end
// --------------------------------------------
// check if we have no configuration at the moment
//
if ( file_exists("settings.php") && filesize( "settings.php" ) > 0 ) {
echo "<hr><h2>The setup looks like it's completed, please delete settings.php</h2><hr>";
exit;
}
// inital page - select the database type
//
if ( ! $action ) {
// first check if we have pdo installed (untested)
//
if ( ! extension_loaded('PDO') ) {
print "ERROR - PDO is missing in the php installation!";
exit();
}
$validPdoDriver = 0;
print_header("Setup FSyncMS - DB Selection");
print 'Which database type should be used?<br>';
if ( extension_loaded('pdo_mysql') ) {
print '<input type="radio" name="dbType" value="mysql" /> MySQL <br>';
$validPdoDriver++;
} else {
print 'MySQL not possible (Driver missing) <br>';
}
if ( extension_loaded('pdo_sqlite') ) {
print '<input type="radio" name="dbType" value="sqlite" checked="checked" /> SQLite ';
$validPdoDriver++;
} else {
print 'SQLite not possible (Driver missing) <br>';
}
if ( $validPdoDriver < 1 ) {
print '<hr> No valid pdo driver found! Please install a valid pdo driver first <hr>';
} else {
print '<input type="hidden" name="action" value="step1">
<p><input type="submit" value="OK" /></p>';
}
// ensure we bail out at this point ;)
exit();
};
// step 2 (connection data) below
//
if ( $action == "step1" ) {
// now check if the database is in place
//
print_header("Setup FSyncMS - DB Setup: $dbType!");
switch ( $dbType ) {
case "sqlite":
$action = "step2";
break;
case "mysql":
print_mysql_connection_form();
break;
default:
print "ERROR - This type of database ($dbType) is not valid at the moment!";
exit();
break;
}
}
// now generate the database
//
if ( $action == "step2" ) {
$dbInstalled = false;
$dbHandle = null;
try {
if ( $dbType == "sqlite" ) {
$path = explode('/', $_SERVER['SCRIPT_FILENAME']);
$db_name = 'weave_db';
array_pop($path);
array_push($path, $db_name);
$db_name = implode('/', $path);
if ( file_exists($db_name) && filesize( $db_name ) > 0 ) {
$dbInstalled = true;
} else {
echo("Creating sqlite weave storage: ". $db_name ."<br>");
$dbHandle = new PDO('sqlite:' . $db_name);
$dbHandle->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
} else if ( $dbType == "mysql" ) {
$dbHandle = new PDO("mysql:host=". $dbHost .";dbname=". $dbName, $dbUser, $dbPass);
$select_stmt = "show tables like 'wbo'";
$sth = $dbHandle->prepare($select_stmt);
$sth->execute();
$count = $sth->rowCount();
if ( $count > 0 ) {
$dbInstalled = true;
}
};
} catch ( PDOException $exception ) {
echo("database unavailable " . $exception->getMessage());
throw new Exception("Database unavailable " . $exception->getMessage() , 503);
}
if ( $dbInstalled ) {
echo "DB is already installed!<br>";
} else {
echo "Now going to install the new database! Type is: $dbType<br>";
try {
$create_statement = " create table wbo ( username varchar(100), id varchar(65), collection varchar(100),
parentid varchar(65), predecessorid int, modified real, sortindex int,
payload text, payload_size int, ttl int, primary key (username,collection,id))";
$create_statement2 = " create table users ( username varchar(255), md5 varchar(124), primary key (username)) ";
$index1 = 'create index parentindex on wbo (username, parentid)';
$index2 = 'create index predecessorindex on wbo (username, predecessorid)';
$index3 = 'create index modifiedindex on wbo (username, collection, modified)';
$sth = $dbHandle->prepare($create_statement);
$sth->execute();
$sth = $dbHandle->prepare($create_statement2);
$sth->execute();
$sth = $dbHandle->prepare($index1);
$sth->execute();
$sth = $dbHandle->prepare($index2);
$sth->execute();
$sth = $dbHandle->prepare($index3);
$sth->execute();
echo "Database created <br>";
} catch( PDOException $exception ) {
throw new Exception("Database unavailable", 503);
}
}
//guessing fsroot
// get the FSYNC_ROOT url
//
$fsRoot ="https://";
if ( ! isset($_SERVER['HTTPS']) ) {
$fsRoot = "http://";
}
$fsRoot .= $_SERVER['SERVER_NAME'] . dirname($_SERVER['SCRIPT_NAME']) . "/";
if( strpos( $_SERVER['REQUEST_URI'], 'index.php') !== 0 ) {
$fsRoot .= "index.php/";
}
// write settings.php, if not possible, display the needed contant
//
write_config_file($dbType, $dbHost, $dbName, $dbUser, $dbPass, $fsRoot);
echo "<hr><hr> Finished the setup, please delete setup.php and go on with the FFSync<hr><hr>";
echo <<<EOT
<hr><hr>
<h4>This script has guessed the Address of your installation, this might not be accurate,<br/>
Please check if this script can be reached by <a href="$fsRoot">$fsRoot</a> .<br/>
If thats not the case you have to ajust the settings.php<br />
</h4>
EOT;
}
?>

59
sources/test/hash.php Normal file
View file

@ -0,0 +1,59 @@
<?php
define("BCRYPT", true);
define("BCRYPT_ROUNDS", 12);
require_once __DIR__ . '/../weave_hash.php';
$pwd = "asdfASDFghjkGHJK2134$%&";
try {
$hash = WeaveHashFactory::factory();
$time_start = microtime(true);
echo $hash->hash($pwd) . "\n";
$time = microtime(true) - $time_start;
echo "Hashing took " . $time . " seconds\n";
if (!$hash->verify($pwd, '$2a$12$O2Bn6lDUYS5NDIJ1uCZjGezSI/jeGTD7Ow0bd3PFMRBcGIqfqI4Oi')) {
throw new Exception("bcrypt hash compare failed");
}
if (!$hash->needsUpdate(md5($pwd))) {
throw new Exception("bcrypt hash needs update.");
}
if ($hash->needsUpdate('$2a$12$O2Bn6lDUYS5NDIJ1uCZjGezSI/jeGTD7Ow0bd3PFMRBcGIqfqI4Oi')) {
throw new Exception("bcrypt hash doesn't needs update.");
}
if (!$hash->verify($pwd, 'a96b71c678b01b98b9f7a0d8ec4b633b')) {
throw new Exception("bcrypt hash compare with md5 failed");
}
$hash2 = new WeaveHashBCrypt(6);
if (!$hash2->needsUpdate('$2a$12$O2Bn6lDUYS5NDIJ1uCZjGezSI/jeGTD7Ow0bd3PFMRBcGIqfqI4Oi')) {
throw new Exception("bcrypt hash needs update because of different rounds.");
}
$hashmd5 = new WeaveHashMD5();
if (!$hashmd5->verify($pwd, 'a96b71c678b01b98b9f7a0d8ec4b633b')) {
throw new Exception("md5 hash compare failed");
}
if (!$hashmd5->needsUpdate('$2a$12$O2Bn6lDUYS5NDIJ1uCZjGezSI/jeGTD7Ow0bd3PFMRBcGIqfqI4Oi')) {
throw new Exception("md5 hash needs update.");
}
if ($hashmd5->needsUpdate(md5($pwd))) {
throw new Exception("md5 hash doesn't need update.");
}
echo "all tests ok\n";
exit(0);
} catch(Exception $e) {
echo $e->getMessage() . "\n";
exit(1);
}
?>

275
sources/user.php Normal file
View file

@ -0,0 +1,275 @@
<?php
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Initial Developer of the Original Code is balu
#
# Portions created by the Initial Developer are Copyright (C) 2012
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
/*
## DESCRIPTION: Implementation of user api v1.0
##
## AUTHOR: balu
##
## DATE: 20.02.2012
##
## VERSION: 0.1
*/
require_once 'weave_utils.php';
if(!$include) //file should only be used in context of index.php
{
log_error("include error");
report_problem('Function not found', 404);
}
require_once "settings.php";
// basic path extraction and validation. No point in going on if these are missing
$path = '/';
if (!empty($_SERVER['PATH_INFO']))
$path = $_SERVER['PATH_INFO'];
else if (!empty($_SERVER['ORIG_PATH_INFO']))
$path = $_SERVER['ORIG_PATH_INFO'];
else if (!empty($_SERVER["REQUEST_URI"]))
{
// improved path handling to prevent invalid server url error message in Firefox
log_error("experimental path");
// this is kind of an experimental try, i needed it so i build it,
// but that doesent mean that it does work... well it works for me
// and it shouldnt break anything...
$path = $_SERVER["REQUEST_URI"];
$lastfolder = substr(FSYNCMS_ROOT,strrpos(FSYNCMS_ROOT, "/",-2));
$path = substr($path, (strpos($path,$lastfolder) + strlen($lastfolder)-1)); // chop the lead slash
if(strpos($path,'?') != false)
$path = substr($path, 0, strpos($path,'?')); // remove php arguments
log_error("path_exp:".$path);
}
else
{
log_error("user.php: No path found");
report_problem("No path found", 404);
}
$path = substr($path, 1); #chop the lead slash
// split path into parts and make sure that all values are properly initialized
list($preinstr, $version, $username, $function, $collection, $id) = array_pad(explode('/', $path.'///'), 6, '');
log_error("Pfad:".$path);
if( $preinstr != 'user' && $preinstr != 'misc' )
report_problem('Function not found', 404);
if ($version != '1.0')
report_problem('Function not found', 404);
//if captcha
if(($preinstr =='misc') && ($_SERVER['REQUEST_METHOD'] == 'GET') && ($username =='captcha_html'))
{
if(ENABLE_REGISTER)
exit("And click to the next page");
else
exit("Register to this Server is not permitted, sorry");
}
//probably no need but...
header("Content-type: application/json");
//if ($function != "info" && $function != "storage")
// report_problem(WEAVE_ERROR_FUNCTION_NOT_SUPPORTED, 400);
if (!validate_username($username))
{
log_error( "invalid user");
report_problem(WEAVE_ERROR_INVALID_USERNAME, 400);
}
#user passes preliminaries, connections made, onto actually getting the data
try
{
if ($_SERVER['REQUEST_METHOD'] == 'GET')
{
$db = new WeaveStorage($username);
log_error("user.php: GET");
if($function == 'node' && $collection == 'weave') //client fragt node an
{
// reply node server for user
//to be compatible with users how use /index.php/ in their path
/*$index ="https://";
if (!isset($_SERVER['HTTPS']))
$index = "http://";
$index .= $_SERVER['SERVER_NAME']. dirname($_SERVER['SCRIPT_NAME']) . "/";
if(strpos($_SERVER['REQUEST_URI'],'index.php') !== 0)
$index .= "index.php/";
*/
// modification to support iPhone/iPod Touch devices
// check http://www.rfkd.de/?p=974 for further details
if (isset($_SERVER['HTTPS'])) {
exit("https://" . parse_url(FSYNCMS_ROOT, PHP_URL_HOST) . parse_url(FSYNCMS_ROOT, PHP_URL_PATH));
} else {
// allow http requests because use of self-signed certificates
// on iPhone/iPod Touch devices doesn't work
exit("http://" . parse_url(FSYNCMS_ROOT, PHP_URL_HOST) . parse_url(FSYNCMS_ROOT, PHP_URL_PATH));
}
}
else if($function == 'password_reset')
{
//email mit neuem pw senden
/*
Possible errors:
503: problems with looking up the user or sending the email
400: 12 (No email address on file)
400: 3 (Incorrect or missing username)
400: 2 (Incorrect or missing captcha)
*/
report_problem(WEAVE_ERROR_NO_EMAIL, 400);
}
//node/weave
else if($function == '' && $collection == '' && $id =='') //frage nach freiem usernamen
//User exists
{
//$db = new WeaveStorage($username);
if(exists_user($db))
exit(json_encode(1));
else
exit(json_encode(0));
}
else
report_problem(WEAVE_ERROR_INVALID_PROTOCOL, 400);
}
else if($_SERVER['REQUEST_METHOD'] == 'PUT')
{
if(ENABLE_REGISTER)
{
$db = new WeaveStorage(null);
//Requests that an account be created for username.
/*
The JSON payload should include
Field Description
password The password to be associated with the account.
email Email address associated with the account
captcha-challenge The challenge string from the captcha (see miscellaneous functions below)
captcha-response The response to the captcha. Only required if WEAVE_REGISTER_USE_CAPTCHA is set
*/
log_error("PUT");
$data = get_json();
log_error(print_r($data,true));
//werte vorhanden
if($data == NULL)
report_problem(WEAVE_ERROR_JSON_PARSE, 400);
$name = $username;
$pwd = fix_utf8_encoding($data['password']);
$email = $data['email'];
if($email == '')
{
log_error('create user datenfehler');
report_problem(WEAVE_ERROR_NO_EMAIL, 400);
}
else if ( $pwd == '' )
{
log_error('create user datenfehler');
report_problem(WEAVE_ERROR_MISSING_PASSWORD, 400);
}
if($name == '' || $pwd == '' || $email == '')
{
log_error('create user datenfehler');
report_problem(WEAVE_ERROR_JSON_PARSE, 400);
}
log_error("create user ".$name." pw : ".$pwd);
try{
if ($db->create_user($name, $pwd))
{
log_error("successfully created user");
exit(json_encode(strtolower($name)));
}
else
{
log_error("create user failed");
report_problem(WEAVE_ERROR_NO_OVERWRITE, 503);
}
}
catch(Exception $e)
{
log_error("db exception create user");
header("X-Weave-Backoff: 1800");
report_problem($e->getMessage(), $e->getCode());
}
}
else
{
log_error("register not enabled");
report_problem(WEAVE_ERROR_FUNCTION_NOT_SUPPORTED,400);
}
} // ende put
else if($_SERVER['REQUEST_METHOD'] == 'POST')
{
if($username == '')
{
log_error("user.php : Post no username");
report_problem(WEAVE_ERROR_INVALID_USERNAME, 400);
}
$db = new WeaveStorage($username);
log_error("user.php: POST");
if($function == "password")
{
#Auth the user
verify_user($username, $db);
$new_pwd = get_phpinput();
log_error("user.php: POST password ");
//to do
// change pw in db
if($db->change_password($new_pwd))
exit("success");
else
report_problem(WEAVE_ERROR_INVALID_PROTOCOL, 503); //server db messed up somehow
// return success
// report_problem(7, 400);
}
else if($function == "email")
{
//change email adr
}
else
{
report_problem(WEAVE_ERROR_INVALID_PROTOCOL, 400);
}
// exit('success');
}
}
catch(Exception $e)
{
report_problem($e->getMessage(), $e->getCode());
}
#The datasets we might be dealing with here are too large for sticking it all into an array, so
#we need to define a direct-output method for the storage class to use. If we start producing multiples
#(unlikely), we can put them in their own class.
#include_once "WBOJsonOutput.php";
?>

View file

@ -0,0 +1,249 @@
<?php
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is Weave Basic Object Server
#
# The Initial Developer of the Original Code is
# Mozilla Labs.
# Portions created by the Initial Developer are Copyright (C) 2008
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Toby Elliott (telliott@mozilla.com)
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
class wbo
{
var $wbo_hash = array();
var $_collection;
var $_error = array();
function extract_json(&$json)
{
$extracted = is_string($json) ? json_decode($json, true) : $json;
#need to check the json was valid here...
if ($extracted === null)
{
$this->_error[] = "unable to extract from json";
return false;
}
#must have an id, or all sorts of badness happens. However, it can be added later
if (array_key_exists('id', $extracted))
{
$this->id($extracted['id']);
}
if (array_key_exists('parentid', $extracted))
{
$this->parentid($extracted['parentid']);
}
if (array_key_exists('predecessorid', $extracted))
{
$this->predecessorid($extracted['predecessorid']);
}
if (array_key_exists('sortindex', $extracted))
{
# Due to complicated logic in the getter, we need to validate
# the value space of sortindex here.
if (!is_numeric($extracted['sortindex'])) {
$this->_error[] = "invalid sortindex";
return false;
}
$this->sortindex($extracted['sortindex']);
}
if (array_key_exists('payload', $extracted))
{
$this->payload($extracted['payload']);
}
return true;
}
function populate(&$datahash)
{
if (array_key_exists('id', $datahash))
$this->id($datahash['id']);
if (array_key_exists('collection', $datahash))
$this->collection($datahash['collection']);
if (array_key_exists('parentid', $datahash))
$this->parentid($datahash['parentid']);
if (array_key_exists('modified', $datahash))
$this->modified($datahash['modified']);
if (array_key_exists('predecessorid', $datahash))
$this->predecessorid($datahash['predecessorid']);
if (array_key_exists('sortindex', $datahash))
$this->sortindex($datahash['sortindex']);
if (array_key_exists('payload', $datahash))
$this->payload($datahash['payload']);
}
function id($id = null)
{
if (!is_null($id)) { $this->wbo_hash['id'] = (string)$id; }
return array_key_exists('id', $this->wbo_hash) ? $this->wbo_hash['id'] : null;
}
function collection($collection = null)
{
if (!is_null($collection)){ $this->_collection = $collection; }
return $this->_collection;
}
function parentid($parentid = null)
{
if (!is_null($parentid)){ $this->wbo_hash['parentid'] = (string)$parentid; }
return array_key_exists('parentid', $this->wbo_hash) ? $this->wbo_hash['parentid'] : null;
}
function parentid_exists()
{
return array_key_exists('parentid', $this->wbo_hash);
}
function predecessorid($predecessorid = null)
{
if (!is_null($predecessorid)){ $this->wbo_hash['predecessorid'] = (string)$predecessorid; }
return array_key_exists('predecessorid', $this->wbo_hash) ? $this->wbo_hash['predecessorid'] : null;
}
function predecessorid_exists()
{
return array_key_exists('predecessorid', $this->wbo_hash);
}
function modified($modified = null)
{
if (!is_null($modified)){ $this->wbo_hash['modified'] = round((float)$modified, 2); }
return array_key_exists('modified', $this->wbo_hash) ? $this->wbo_hash['modified'] : null;
}
function modified_exists()
{
return array_key_exists('modified', $this->wbo_hash);
}
function payload($payload = null)
{
if (!is_null($payload)){ $this->wbo_hash['payload'] = $payload; }
return array_key_exists('payload', $this->wbo_hash) ? $this->wbo_hash['payload'] : null;
}
function payload_exists()
{
return array_key_exists('payload', $this->wbo_hash);
}
function payload_size()
{
return mb_strlen($this->wbo_hash['payload'], '8bit');
}
function sortindex($index = null)
{
if (!is_null($index)){
$this->wbo_hash['sortindex'] = (int)($index);
}
return array_key_exists('sortindex', $this->wbo_hash) ? $this->wbo_hash['sortindex'] : null;
}
function sortindex_exists()
{
return array_key_exists('sortindex', $this->wbo_hash);
}
function validate()
{
if (!$this->id() || mb_strlen($this->id(), '8bit') > 64 || strpos($this->id(), '/') !== false)
{ $this->_error[] = "invalid id"; }
if ($this->parentid_exists() && mb_strlen($this->parentid(), '8bit') > 64)
{ $this->_error[] = "invalid parentid"; }
if ($this->predecessorid_exists() && mb_strlen($this->predecessorid(), '8bit') > 64)
{ $this->_error[] = "invalid predecessorid"; }
if (!is_numeric($this->modified()))
{ $this->_error[] = "invalid modified date"; }
if (!$this->modified())
{ $this->_error[] = "no modification date"; }
if (!$this->_collection || mb_strlen($this->_collection, '8bit') > 64)
{ $this->_error[] = "invalid collection"; }
if ($this->sortindex_exists() &&
(!is_numeric($this->wbo_hash['sortindex']) ||
intval($this->sortindex()) > 999999999 ||
intval($this->sortindex()) < -999999999 ))
{ $this->_error[] = "invalid sortindex"; }
if ($this->payload_exists())
{
if (!is_string($this->wbo_hash['payload']))
{ $this->_error[] = "payload needs to be json-encoded"; }
}
return !$this->get_error();
}
function get_error()
{
return $this->_error;
}
function clear_error()
{
$this->_error = array();
}
function raw_hash()
{
return $this->wbo_hash;
}
function json()
{
return json_encode($this->wbo_hash);
}
}
?>

191
sources/weave_hash.php Normal file
View file

@ -0,0 +1,191 @@
<?php
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is http://stackoverflow.com/a/6337021/833893
#
# Contributor(s):
# Daniel Triendl <daniel@pew.cc>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
interface WeaveHash {
public function hash($input);
public function verify($input, $existingHash);
public function needsUpdate($existingHash);
}
class WeaveHashMD5 implements WeaveHash {
public function hash($input) {
return md5($input);
}
public function verify($input, $existingHash) {
return $this->hash($input) == $existingHash;
}
public function needsUpdate($existingHash) {
return substr($existingHash, 0, 4) == "$2a$";
}
}
class WeaveHashBCrypt implements WeaveHash {
private $_rounds;
public function __construct($rounds = 12) {
if(CRYPT_BLOWFISH != 1) {
throw new Exception("bcrypt not available");
}
$this->_rounds = $rounds;
}
public function hash($input) {
$hash = crypt($input, $this->getSalt());
if (strlen($hash) <= 13) {
throw new Exception("error while generating hash");
}
return $hash;
}
public function verify($input, $existingHash) {
if ($this->isMD5($existingHash)) {
$md5 = new WeaveHashMD5();
return $md5->verify($input, $existingHash);
}
$hash = crypt($input, $existingHash);
return $hash === $existingHash;
}
public function needsUpdate($existingHash) {
$identifier = $this->getIdentifier();
return substr($existingHash, 0, strlen($identifier)) != $identifier;
}
private function isMD5($existingHash) {
return substr($existingHash, 0, 4) != "$2a$";
}
private function getSalt() {
$salt = $this->getIdentifier();
$bytes = $this->getRandomBytes(16);
$salt .= $this->encodeBytes($bytes);
return $salt;
}
private function getIdentifier() {
return sprintf("$2a$%02d$", $this->_rounds);
}
private $randomState;
private function getRandomBytes($count) {
$bytes = '';
if(function_exists('openssl_random_pseudo_bytes') &&
(strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')) { // OpenSSL slow on Win
$bytes = openssl_random_pseudo_bytes($count);
}
if($bytes === '' && is_readable('/dev/urandom') &&
($hRand = @fopen('/dev/urandom', 'rb')) !== FALSE) {
$bytes = fread($hRand, $count);
fclose($hRand);
}
if(strlen($bytes) < $count) {
$bytes = '';
if($this->randomState === null) {
$this->randomState = microtime();
if(function_exists('getmypid')) {
$this->randomState .= getmypid();
}
}
for($i = 0; $i < $count; $i += 16) {
$this->randomState = md5(microtime() . $this->randomState);
if (PHP_VERSION >= '5') {
$bytes .= md5($this->randomState, true);
} else {
$bytes .= pack('H*', md5($this->randomState));
}
}
$bytes = substr($bytes, 0, $count);
}
return $bytes;
}
private function encodeBytes($input) {
// The following is code from the PHP Password Hashing Framework
$itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$output = '';
$i = 0;
do {
$c1 = ord($input[$i++]);
$output .= $itoa64[$c1 >> 2];
$c1 = ($c1 & 0x03) << 4;
if ($i >= 16) {
$output .= $itoa64[$c1];
break;
}
$c2 = ord($input[$i++]);
$c1 |= $c2 >> 4;
$output .= $itoa64[$c1];
$c1 = ($c2 & 0x0f) << 2;
$c2 = ord($input[$i++]);
$c1 |= $c2 >> 6;
$output .= $itoa64[$c1];
$output .= $itoa64[$c2 & 0x3f];
} while (1);
return $output;
}
}
class WeaveHashFactory {
public static function factory() {
if (defined("BCRYPT") && BCRYPT) {
return new WeaveHashBCrypt(BCRYPT_ROUNDS);
} else {
return new WeaveHashMD5();
}
}
}
?>

815
sources/weave_storage.php Normal file
View file

@ -0,0 +1,815 @@
<?php
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is Weave Basic Object Server
#
# The Initial Developer of the Original Code is
# Mozilla Labs.
# Portions created by the Initial Developer are Copyright (C) 2008
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Toby Elliott (telliott@mozilla.com)
# balu
# Daniel Triendl <daniel@pew.cc>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
require_once 'weave_basic_object.php';
require_once 'weave_utils.php';
require_once 'settings.php';
class WeaveStorage
{
private $_username;
private $_dbh;
function __construct($username)
{
$this->_username = $username;
log_error("Initalizing DB connecion!");
try
{
if ( ! MYSQL_ENABLE )
{
$path = explode('/', $_SERVER['SCRIPT_FILENAME']);
$db_name = SQLITE_FILE;
array_pop($path);
array_push($path, $db_name);
$db_name = implode('/', $path);
if ( ! file_exists($db_name) )
{
log_error("The required sqllite database is not present! $db_name");
}
log_error("Starting SQLite connection");
$this->_dbh = new PDO('sqlite:' . $db_name);
$this->_dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
else if ( MYSQL_ENABLE )
{
log_error("Starting MySQL connection");
$this->_dbh = new PDO("mysql:host=". MYSQL_HOST .";dbname=". MYSQL_DB, MYSQL_USER, MYSQL_PASSWORD);
}
}
catch( PDOException $exception )
{
log_error("database unavailable " . $exception->getMessage());
throw new Exception("Database unavailable " . $exception->getMessage() , 503);
}
}
function get_connection()
{
return $this->_dbh;
}
function begin_transaction()
{
try
{
$this->_dbh->beginTransaction();
}
catch( PDOException $exception )
{
error_log("begin_transaction: " . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
return 1;
}
function commit_transaction()
{
$this->_dbh->commit();
return 1;
}
function get_max_timestamp($collection)
{
if (!$collection)
{
return 0;
}
try
{
$select_stmt = 'select max(modified) from wbo where username = :username and collection = :collection';
$sth = $this->_dbh->prepare($select_stmt);
$sth->bindParam(':username', $this->_username);
$sth->bindParam(':collection', $collection);
$sth->execute();
}
catch( PDOException $exception )
{
error_log("get_max_timestamp: " . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
$result = $sth->fetchColumn();
return round((float)$result, 2);
}
function get_collection_list()
{
try
{
$select_stmt = 'select distinct(collection) from wbo where username = :username';
$sth = $this->_dbh->prepare($select_stmt);
$sth->bindParam(':username', $this->_username);
$sth->execute();
}
catch( PDOException $exception )
{
error_log("get_collection_list: " . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
$collections = array();
while ($result = $sth->fetchColumn())
{
$collections[] = $result;
}
return $collections;
}
function get_collection_list_with_timestamps()
{
try
{
$select_stmt = 'select collection, max(modified) as timestamp from wbo where username = :username group by collection';
$sth = $this->_dbh->prepare($select_stmt);
$sth->bindParam(':username', $this->_username);
$sth->execute();
}
catch( PDOException $exception )
{
error_log("get_collection_list: " . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
$collections = array();
while ($result = $sth->fetch(PDO::FETCH_NUM))
{
$collections[$result[0]] = (float)$result[1];
}
return $collections;
}
function get_collection_list_with_counts()
{
try
{
$select_stmt = 'select collection, count(*) as ct from wbo where username = :username group by collection';
$sth = $this->_dbh->prepare($select_stmt);
$sth->bindParam(':username', $this->_username);
$sth->execute();
}
catch( PDOException $exception )
{
error_log("get_collection_list_with_counts: " . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
$collections = array();
while ($result = $sth->fetch(PDO::FETCH_NUM))
{
$collections[$result[0]] = (int)$result[1];
}
return $collections;
}
function store_object(&$wbo)
{
try
{
$insert_stmt = 'replace into wbo (username, id, collection, parentid, predecessorid, sortindex, modified, payload, payload_size)
values (:username, :id, :collection, :parentid, :predecessorid, :sortindex, :modified, :payload, :payload_size)';
$sth = $this->_dbh->prepare($insert_stmt);
$username = $this->_username;
$id = $wbo->id();
$collection = $wbo->collection();
$parentid = $wbo->parentid();
$predecessorid = $wbo->predecessorid();
$sortindex = $wbo->sortindex();
$modified = $wbo->modified();
$payload = $wbo->payload();
$payload_size = $wbo->payload_size();
$sth->bindParam(':username', $username);
$sth->bindParam(':id', $id);
$sth->bindParam(':collection', $collection);
$sth->bindParam(':parentid', $parentid);
$sth->bindParam(':predecessorid', $predecessorid);
$sth->bindParam(':sortindex', $sortindex);
$sth->bindParam(':modified', $modified);
$sth->bindParam(':payload', $payload);
$sth->bindParam(':payload_size', $payload_size);
$sth->execute();
}
catch( PDOException $exception )
{
error_log("store_object: " . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
return 1;
}
function update_object(&$wbo)
{
$update = "update wbo set ";
$params = array();
$update_list = array();
#make sure we have an id and collection. No point in continuing otherwise
if (!$wbo->id() || !$wbo->collection())
{
error_log('Trying to update without a valid id or collection!');
return 0;
}
if ($wbo->parentid_exists())
{
$update_list[] = "parentid = ?";
$params[] = $wbo->parentid();
}
if ($wbo->predecessorid_exists())
{
$update_list[] = "predecessorid = ?";
$params[] = $wbo->predecessorid();
}
if ($wbo->sortindex_exists())
{
$update_list[] = "sortindex = ?";
$params[] = $wbo->sortindex();
}
if ($wbo->payload_exists())
{
$update_list[] = "payload = ?";
$update_list[] = "payload_size = ?";
$params[] = $wbo->payload();
$params[] = $wbo->payload_size();
}
# Don't modify the timestamp on a non-payload/non-parent change change
if ($wbo->parentid_exists() || $wbo->payload_exists())
{
#better make sure we have a modified date. Should have been handled earlier
if (!$wbo->modified_exists())
{
error_log("Called update_object with no defined timestamp. Please check");
$wbo->modified(microtime(1));
}
$update_list[] = "modified = ?";
$params[] = $wbo->modified();
}
if (count($params) == 0)
{
return 0;
}
$update .= join($update_list, ",");
$update .= " where username = ? and collection = ? and id = ?";
$params[] = $this->_username;
$params[] = $wbo->collection();
$params[] = $wbo->id();
try
{
$sth = $this->_dbh->prepare($update);
$sth->execute($params);
}
catch( PDOException $exception )
{
error_log("update_object: " . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
return 1;
}
function delete_object($collection, $id)
{
try
{
$delete_stmt = 'delete from wbo where username = :username and collection = :collection and id = :id';
$sth = $this->_dbh->prepare($delete_stmt);
$username = $this->_username;
$sth->bindParam(':username', $username);
$sth->bindParam(':collection', $collection);
$sth->bindParam(':id', $id);
$sth->execute();
}
catch( PDOException $exception )
{
error_log("delete_object: " . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
return 1;
}
function delete_objects($collection, $id = null, $parentid = null, $predecessorid = null, $newer = null,
$older = null, $sort = null, $limit = null, $offset = null, $ids = null,
$index_above = null, $index_below = null)
{
$params = array();
$select_stmt = '';
if ($limit || $offset || $sort)
{
#sqlite can't do sort or limit deletes without special compiled versions
#so, we need to grab the set, then delete it manually.
$params = $this->retrieve_objects($collection, $id, 0, 0, $parentid, $predecessorid, $newer, $older, $sort, $limit, $offset, $ids, $index_above, $index_below);
if (!count($params))
{
return 1; #nothing to delete
}
$paramqs = array();
$select_stmt = "delete from wbo where username = ? and collection = ? and id in (" . join(", ", array_pad($paramqs, count($params), '?')) . ")";
array_unshift($params, $collection);
array_unshift($params, $username);
}
else
{
$select_stmt = "delete from wbo where username = ? and collection = ?";
$params[] = $this->_username;
$params[] = $collection;
if ($id)
{
$select_stmt .= " and id = ?";
$params[] = $id;
}
if ($ids && count($ids) > 0)
{
$qmarks = array();
$select_stmt .= " and id in (";
foreach ($ids as $temp)
{
$params[] = $temp;
$qmarks[] = '?';
}
$select_stmt .= implode(",", $qmarks);
$select_stmt .= ')';
}
if ($parentid)
{
$select_stmt .= " and parentid = ?";
$params[] = $parentid;
}
if ($predecessorid)
{
$select_stmt .= " and predecessorid = ?";
$params[] = $parentid;
}
if ($index_above)
{
$select_stmt .= " and sortindex > ?";
$params[] = $parentid;
}
if ($index_below)
{
$select_stmt .= " and sortindex < ?";
$params[] = $parentid;
}
if ($newer)
{
$select_stmt .= " and modified > ?";
$params[] = $newer;
}
if ($older)
{
$select_stmt .= " and modified < ?";
$params[] = $older;
}
if ($sort == 'index')
{
$select_stmt .= " order by sortindex desc";
}
else if ($sort == 'newest')
{
$select_stmt .= " order by modified desc";
}
else if ($sort == 'oldest')
{
$select_stmt .= " order by modified";
}
}
try
{
$sth = $this->_dbh->prepare($select_stmt);
$sth->execute($params);
}
catch( PDOException $exception )
{
error_log("delete_objects: " . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
return 1;
}
function retrieve_object($collection, $id)
{
try
{
$select_stmt = 'select * from wbo where username = :username and collection = :collection and id = :id';
$sth = $this->_dbh->prepare($select_stmt);
$username = $this->_username;
$sth->bindParam(':username', $username);
$sth->bindParam(':collection', $collection);
$sth->bindParam(':id', $id);
$sth->execute();
}
catch( PDOException $exception )
{
error_log("retrieve_object: " . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
$result = $sth->fetch(PDO::FETCH_ASSOC);
$wbo = new wbo();
$wbo->populate($result);
return $wbo;
}
function retrieve_objects($collection, $id = null, $full = null, $direct_output = null, $parentid = null,
$predecessorid = null, $newer = null, $older = null, $sort = null,
$limit = null, $offset = null, $ids = null,
$index_above = null, $index_below = null)
{
$full_list = $full ? '*' : 'id';
$select_stmt = "select $full_list from wbo where username = ? and collection = ?";
$params[] = $this->_username;
$params[] = $collection;
if ($id)
{
$select_stmt .= " and id = ?";
$params[] = $id;
}
if ($ids && count($ids) > 0)
{
$qmarks = array();
$select_stmt .= " and id in (";
foreach ($ids as $temp)
{
$params[] = $temp;
$qmarks[] = '?';
}
$select_stmt .= implode(",", $qmarks);
$select_stmt .= ')';
}
if ($parentid)
{
$select_stmt .= " and parentid = ?";
$params[] = $parentid;
}
if ($predecessorid)
{
$select_stmt .= " and predecessorid = ?";
$params[] = $predecessorid;
}
if ($index_above)
{
$select_stmt .= " and sortindex > ?";
$params[] = $parentid;
}
if ($index_below)
{
$select_stmt .= " and sortindex < ?";
$params[] = $parentid;
}
if ($newer)
{
$select_stmt .= " and modified > ?";
$params[] = $newer;
}
if ($older)
{
$select_stmt .= " and modified < ?";
$params[] = $older;
}
if ($sort == 'index')
{
$select_stmt .= " order by sortindex desc";
}
else if ($sort == 'newest')
{
$select_stmt .= " order by modified desc";
}
else if ($sort == 'oldest')
{
$select_stmt .= " order by modified";
}
if ($limit)
{
$select_stmt .= " limit " . intval($limit);
if ($offset)
{
$select_stmt .= " offset " . intval($offset);
}
}
try
{
$sth = $this->_dbh->prepare($select_stmt);
$sth->execute($params);
}
catch( PDOException $exception )
{
error_log("retrieve_collection: " . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
if ($direct_output)
return $direct_output->output($sth);
$ids = array();
while ($result = $sth->fetch(PDO::FETCH_ASSOC))
{
if ($full)
{
$wbo = new wbo();
$wbo->populate($result);
$ids[] = $wbo;
}
else
$ids[] = $result{'id'};
}
return $ids;
}
function get_storage_total()
{
try
{
$select_stmt = 'select round(sum(length(payload))/1024) from wbo where username = :username';
$sth = $this->_dbh->prepare($select_stmt);
$username = $this->_username;
$sth->bindParam(':username', $username);
$sth->execute();
}
catch( PDOException $exception )
{
error_log("get_storage_total: " . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
return (int)$sth->fetchColumn();
}
function get_collection_storage_totals()
{
try
{
$select_stmt = 'select collection, sum(payload_size) from wbo where username = :username group by collection';
$sth = $this->_dbh->prepare($select_stmt);
$username = $this->_username;
$sth->bindParam(':username', $username);
$sth->execute();
}
catch( PDOException $exception )
{
error_log("get_storage_total (" . $this->connection_details_string() . "): " . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
$results = $sth->fetchAll(PDO::FETCH_NUM);
$sth->closeCursor();
$collections = array();
foreach ($results as $result)
{
$collections[$result[0]] = (int)$result[1];
}
return $collections;
}
function get_user_quota()
{
return null;
}
function delete_storage($username)
{
log_error("delete storage");
if (!$username)
{
throw new Exception("3", 404);
}
try
{
$delete_stmt = 'delete from wbo where username = :username';
$sth = $this->_dbh->prepare($delete_stmt);
$sth->bindParam(':username', $username);
$sth->execute();
$sth->closeCursor();
}
catch( PDOException $exception )
{
error_log("delete_user: " . $exception->getMessage());
return 0;
}
return 1;
}
function delete_user($username)
{
log_error("delete User");
if (!$username)
{
throw new Exception("3", 404);
}
try
{
$delete_stmt = 'delete from users where username = :username';
$sth = $this->_dbh->prepare($delete_stmt);
$sth->bindParam(':username', $username);
$sth->execute();
$sth->closeCursor();
$delete_wbo_stmt = 'delete from wbo where username = :username';
$sth = $this->_dbh->prepare($delete_wbo_stmt);
$sth->bindParam(':username', $username);
$sth->execute();
}
catch( PDOException $exception )
{
error_log("delete_user: " . $exception->getMessage());
return 0;
}
return 1;
}
function create_user($username, $password)
{
log_error("Create User - Username: ".$username."|".$password);
try
{
$create_statement = "insert into users values (:username, :md5)";
$sth = $this->_dbh->prepare($create_statement);
$hash = WeaveHashFactory::factory();
$password = $hash->hash($password);
$sth->bindParam(':username', $username);
$sth->bindParam(':md5', $password);
$sth->execute();
}
catch( PDOException $exception )
{
log_error("create_user:" . $exception->getMessage());
error_log("create_user:" . $exception->getMessage());
return 0;
}
return 1;
}
function change_password($hash)
{
try
{
$update_statement = "update users set md5 = :md5 where username = :username";
$sth = $this->_dbh->prepare($update_statement);
$sth->bindParam(':username', $this->_username);
$sth->bindParam(':md5', $hash);
$sth->execute();
}
catch( PDOException $exception )
{
log_error("change_password:" . $exception->getMessage());
return 0;
}
return 1;
}
#function checks if user exists
function exists_user()
{
try
{
$select_stmt = 'select username from users where username = :username';
$sth = $this->_dbh->prepare($select_stmt);
$username = $this->_username;
$sth->bindParam(':username', $username);
$sth->execute();
}
catch( PDOException $exception )
{
error_log("exists_user: " . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
if (!$result = $sth->fetch(PDO::FETCH_ASSOC))
{
return null;
}
return 1;
}
function get_password_hash()
{
log_error("auth-user: " . $this->_username);
try
{
$select_stmt = 'select md5 from users where username = :username';
$sth = $this->_dbh->prepare($select_stmt);
$username = $this->_username;
$sth->bindParam(':username', $username);
$sth->execute();
}
catch( PDOException $exception )
{
error_log("get_password_hash: " . $exception->getMessage());
throw new Exception("Database unavailable", 503);
}
$result = $sth->fetchColumn();
if ($result === FALSE) $result = "";
return $result;
}
}
?>

286
sources/weave_utils.php Normal file
View file

@ -0,0 +1,286 @@
<?php
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Initial Developer of the Original Code is balu
#
# Portions created by the Initial Developer are Copyright (C) 2012
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Daniel Triendl <daniel@pew.cc>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
#Error constants
define ('WEAVE_ERROR_INVALID_PROTOCOL', 1);
define ('WEAVE_ERROR_INCORRECT_CAPTCHA', 2);
define ('WEAVE_ERROR_INVALID_USERNAME', 3);
define ('WEAVE_ERROR_NO_OVERWRITE', 4);
define ('WEAVE_ERROR_USERID_PATH_MISMATCH', 5);
define ('WEAVE_ERROR_JSON_PARSE', 6);
define ('WEAVE_ERROR_MISSING_PASSWORD', 7);
define ('WEAVE_ERROR_INVALID_WBO', 8);
define ('WEAVE_ERROR_BAD_PASSWORD_STRENGTH', 9);
define ('WEAVE_ERROR_INVALID_RESET_CODE', 10);
define ('WEAVE_ERROR_FUNCTION_NOT_SUPPORTED', 11);
define ('WEAVE_ERROR_NO_EMAIL', 12);
define ('WEAVE_ERROR_INVALID_COLLECTION', 13);
define ('LOG_THE_ERROR', 0);
function log_error($msg)
{
if ( LOG_THE_ERROR == 1 )
{
$datei = fopen("/tmp/FSyncMS-error.txt","a");
$fmsg = sprintf("$msg\n");
fputs($datei,$fmsg);
fputs($datei,"Server ".print_r( $_SERVER, true));
fclose($datei);
}
}
function report_problem($message, $code = 503)
{
$headers = array('400' => '400 Bad Request',
'401' => '401 Unauthorized',
'403' => '403 Forbidden',
'404' => '404 Not Found',
'412' => '412 Precondition Failed',
'503' => '503 Service Unavailable');
header('HTTP/1.1 ' . $headers{$code},true,$code);
if ($code == 401)
{
header('WWW-Authenticate: Basic realm="Weave"');
}
log_error($message);
exit(json_encode($message));
}
function fix_utf8_encoding($string)
{
if(mb_detect_encoding($string . " ", 'UTF-8,ISO-8859-1') == 'UTF-8')
return $string;
else
return utf8_encode($string);
}
function get_phpinput()
{
#stupid php being helpful with input data...
$putdata = fopen("php://input", "r");
$string = '';
while ($data = fread($putdata,2048)) {$string .= $data;} //hier will man ein limit einbauen
return $string;
}
function get_json()
{
$jsonstring = get_phpinput();
$json = json_decode(fix_utf8_encoding($jsonstring), true);
if ($json === null)
report_problem(WEAVE_ERROR_JSON_PARSE, 400);
return $json;
}
function validate_username($username)
{
if (!$username)
return false;
if (strlen($username) > 32)
return false;
return preg_match('/[^A-Z0-9._-]/i', $username) ? false : true;
}
function validate_collection($collection)
{
if (!$collection)
return false;
if (strlen($collection) > 32)
return false;
// allow characters '?' and '=' in the collection string which e.g.
// appear if the following request is send from firefox:
// http://<server>/weave/1.1/<user>/storage/clients?full=1
return preg_match('/[^A-Z0-9?=._-]/i', $collection) ? false : true;
}
#user exitsts
function exists_user( $db)
{
#$user = strtolower($user);
try{
if(!$db->exists_user())
return 0;
return 1;
}
catch(Exception $e)
{
header("X-Weave-Backoff: 1800");
report_problem($e->getMessage(), $e->getCode());
}
}
# Gets the username and password out of the http headers, and checks them against the auth
function verify_user($url_user, $db)
{
if (!$url_user || !preg_match('/^[A-Z0-9._-]+$/i', $url_user))
report_problem(WEAVE_ERROR_INVALID_USERNAME, 400);
$auth_user = array_key_exists('PHP_AUTH_USER', $_SERVER) ? $_SERVER['PHP_AUTH_USER'] : null;
$auth_pw = array_key_exists('PHP_AUTH_PW', $_SERVER) ? $_SERVER['PHP_AUTH_PW'] : null;
if (is_null($auth_user) || is_null($auth_pw))
{
/* CGI/FCGI auth workarounds */
$auth_str = null;
if (array_key_exists('Authorization', $_SERVER))
/* Standard fastcgi configuration */
$auth_str = $_SERVER['Authorization'];
else if (array_key_exists('AUTHORIZATION', $_SERVER))
/* Alternate fastcgi configuration */
$auth_str = $_SERVER['AUTHORIZATION'];
else if (array_key_exists('HTTP_AUTHORIZATION', $_SERVER))
/* IIS/ISAPI and newer (yet to be released) fastcgi */
$auth_str = $_SERVER['HTTP_AUTHORIZATION'];
else if (array_key_exists('REDIRECT_HTTP_AUTHORIZATION', $_SERVER))
/* mod_rewrite - per-directory internal redirect */
$auth_str = $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
if (!is_null($auth_str))
{
/* Basic base64 auth string */
if (preg_match('/Basic\s+(.*)$/', $auth_str))
{
$auth_str = substr($auth_str, 6);
$auth_str = base64_decode($auth_str, true);
if ($auth_str != FALSE) {
$tmp = explode(':', $auth_str);
if (count($tmp) == 2)
{
$auth_user = $tmp[0];
$auth_pw = $tmp[1];
}
}
}
}
}
if ( ! $auth_user || ! $auth_pw) #do this first to avoid the cryptic error message if auth is missing
{
log_error("Auth failed 1 {");
log_error(" User pw: ". $auth_user ." | ". $auth_pw);
log_error(" Url_user: ". $url_user);
log_error("}");
report_problem('Authentication failed', '401');
}
$url_user = strtolower($url_user);
if (strtolower($auth_user) != $url_user)
{
log_error("(140) Missmatch:".strtolower($auth_user)."|".$url_user);
report_problem(WEAVE_ERROR_USERID_PATH_MISMATCH, 400);
}
try
{
$existingHash = $db->get_password_hash();
$hash = WeaveHashFactory::factory();
if ( ! $hash->verify(fix_utf8_encoding($auth_pw), $existingHash) )
{
log_error("Auth failed 2 {");
log_error(" User pw: ". $auth_user ."|".$auth_pw ."|md5:". md5($auth_pw) ."|fix:". fix_utf8_encoding($auth_pw) ."|fix md5 ". md5(fix_utf8_encoding($auth_pw)));
log_error(" Url_user: ".$url_user);
log_error(" Existing hash: ".$existingHash);
log_error("}");
report_problem('Authentication failed', '401');
} else {
if ( $hash->needsUpdate($existingHash) ) {
$db->change_password($hash->hash(fix_utf8_encoding($auth_pw)));
}
}
}
catch(Exception $e)
{
header("X-Weave-Backoff: 1800");
log_error($e->getMessage(), $e->getCode());
report_problem($e->getMessage(), $e->getCode());
}
return true;
}
function check_quota(&$db)
{
return;
}
function check_timestamp($collection, &$db)
{
if (array_key_exists('HTTP_X_IF_UNMODIFIED_SINCE', $_SERVER)
&& $db->get_max_timestamp($collection) > $_SERVER['HTTP_X_IF_UNMODIFIED_SINCE'])
report_problem(WEAVE_ERROR_NO_OVERWRITE, 412);
}
function validate_search_params()
{
$params = array();
$params['parentid'] = (array_key_exists('parentid', $_GET) && mb_strlen($_GET['parentid'], '8bit') <= 64 && strpos($_GET['parentid'], '/') === false) ? $_GET['parentid'] : null;
$params['predecessorid'] = (array_key_exists('predecessorid', $_GET) && mb_strlen($_GET['predecessorid'], '8bit') <= 64 && strpos($_GET['predecessorid'], '/') === false) ? $_GET['predecessorid'] : null;
$params['newer'] = (array_key_exists('newer', $_GET) && is_numeric($_GET['newer'])) ? round($_GET['newer'],2) : null;
$params['older'] = (array_key_exists('older', $_GET) && is_numeric($_GET['older'])) ? round($_GET['older'],2) : null;
$params['sort'] = (array_key_exists('sort', $_GET) && ($_GET['sort'] == 'oldest' || $_GET['sort'] == 'newest' || $_GET['sort'] == 'index')) ? $_GET['sort'] : null;
$params['limit'] = (array_key_exists('limit', $_GET) && is_numeric($_GET['limit']) && $_GET['limit'] > 0) ? (int)$_GET['limit'] : null;
$params['offset'] = (array_key_exists('offset', $_GET) && is_numeric($_GET['offset']) && $_GET['offset'] > 0) ? (int)$_GET['offset'] : null;
$params['ids'] = null;
if (array_key_exists('ids', $_GET))
{
$params['ids'] = array();
foreach(explode(',', $_GET['ids']) as $id)
{
if (mb_strlen($id, '8bit') <= 64 && strpos($id, '/') === false)
$params['ids'][] = $id;
}
}
$params['index_above'] = (array_key_exists('index_above', $_GET) && is_numeric($_GET['index_above']) && $_GET['index_above'] > 0) ? (int)$_GET['index_above'] : null;
$params['index_below'] = (array_key_exists('index_below', $_GET) && is_numeric($_GET['index_below']) && $_GET['index_below'] > 0) ? (int)$_GET['index_below'] : null;
$params['depth'] = (array_key_exists('depth', $_GET) && is_numeric($_GET['depth']) && $_GET['depth'] > 0) ? (int)$_GET['depth'] : null;
return $params;
}
?>