├── .gitignore ├── README.md ├── TODO ├── WBOJsonOutput.php ├── index.php ├── setup.php ├── test └── hash.php ├── user.php ├── weave_basic_object.php ├── weave_hash.php ├── weave_storage.php └── weave_utils.php /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.swp 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | FSyncMS 2 | ======= 3 | 4 | PHP Sync Server für Firefox Sync 5 | Eine Erweiterung des Weave-Minimal Server (dessen Support leider eingestellt wurde). 6 | 7 | Die derzeit aktuelle Versionen, 8 | sowie alte Versionen und Anleitungen sind hier: 9 | 10 | https://www.ohnekontur.de/category/technik/sync/fsyncms/ 11 | 12 | zu finden. 13 | Weitere Erweiterungen sind in Planung. 14 | Stay tuned. 15 | 16 | 17 | Visit http://www.ohnekontur.de/2011/07/24/how-to-install-fsyncms-firefox-sync-eigener-server/ for install instructions 18 | Visit http://www.ohnekontur.de for the newest version 19 | 20 | 21 | FSyncMS v013 22 | ====== 23 | Database upgrade 24 | for more information and some migration notice see 25 | http://www.ohnekontur.de/2013/07/05/fsyncms-version-0-13-database-upgrade/ 26 | 27 | 28 | FSyncMS v012 29 | ====== 30 | Compatibility update 31 | 32 | FSyncMS v011 33 | ====== 34 | Added dedicated setup script, which will create the database and the config file: settings.php 35 | 36 | If you want to create it by your own, just generate the settings.php with the following content 37 | 38 | 61 | 62 | 63 | FSyncMS v010 64 | ====== 65 | MYSQL Support 66 | 67 | FSyncMS v 09 68 | ====== 69 | Change Password now supported 70 | working with firefox 12 (and lower) 71 | 72 | Changelog: 73 | Added change Password feature 74 | 75 | FSyncMS v 08 76 | ====== 77 | Should be working with firefox 11 and lower (tested with 11) 78 | 79 | Changelog: 80 | Fixed user registration process, 81 | fixed some delete problems 82 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | == SOME TODOS == 2 | 3 | - Ein Präfix für die Tabellen, damit sie in eine vorhandene DB gelegt werden können. 4 | 5 | 6 | - NOTIZ: Update der md5 Spalte der Usertabelle von length 64 auf length 124 7 | - >ALTER TABLE `users` CHANGE `md5` `md5` VARCHAR( 124 ) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL 8 | -------------------------------------------------------------------------------- /WBOJsonOutput.php: -------------------------------------------------------------------------------- 1 | _full = $full; 55 | if (array_key_exists('HTTP_ACCEPT', $_SERVER) 56 | && !preg_match('/\*\/\*/', $_SERVER['HTTP_ACCEPT']) 57 | && !preg_match('/application\/json/', $_SERVER['HTTP_ACCEPT'])) 58 | { 59 | if (preg_match('/application\/whoisi/', $_SERVER['HTTP_ACCEPT'])) 60 | { 61 | header("Content-type: application/whoisi"); 62 | $this->_output_format = 'whoisi'; 63 | } 64 | elseif (preg_match('/application\/newlines/', $_SERVER['HTTP_ACCEPT'])) 65 | { 66 | header("Content-type: application/newlines"); 67 | $this->_output_format = 'newlines'; 68 | } 69 | 70 | } 71 | } 72 | 73 | function set_format($format) 74 | { 75 | $this->_output_format = $format; 76 | } 77 | 78 | 79 | function output($sth) 80 | { 81 | if (($rowcount = $sth->rowCount()) > 0) 82 | { 83 | header('X-Weave-Records: ' . $rowcount); 84 | } 85 | if ($this->_output_format == 'newlines') 86 | { 87 | return $this->output_newlines($sth); 88 | } 89 | elseif ($this->_output_format == 'whoisi') 90 | { 91 | return $this->output_whoisi($sth); 92 | } 93 | else 94 | { 95 | return $this->output_json($sth); 96 | } 97 | } 98 | 99 | function output_json($sth) 100 | { 101 | echo '['; 102 | 103 | while ($result = $sth->fetch(PDO::FETCH_ASSOC)) 104 | { 105 | if ($this->_comma_flag) { echo ','; } else { $this->_comma_flag = 1; } 106 | if ($this->_full) 107 | { 108 | $wbo = new wbo(); 109 | $wbo->populate($result); 110 | echo $wbo->json(); 111 | } 112 | else 113 | echo json_encode($result{'id'}); 114 | } 115 | 116 | echo ']'; 117 | return 1; 118 | } 119 | 120 | function output_whoisi($sth) 121 | { 122 | while ($result = $sth->fetch(PDO::FETCH_ASSOC)) 123 | { 124 | if ($this->_full) 125 | { 126 | $wbo = new wbo(); 127 | $wbo->populate($result); 128 | $output = $wbo->json(); 129 | } 130 | else 131 | $output = json_encode($result{'id'}); 132 | echo pack('N', mb_strlen($output, '8bit')) . $output; 133 | } 134 | return 1; 135 | } 136 | 137 | function output_newlines($sth) 138 | { 139 | while ($result = $sth->fetch(PDO::FETCH_ASSOC)) 140 | { 141 | if ($this->_full) 142 | { 143 | $wbo = new wbo(); 144 | $wbo->populate($result); 145 | echo preg_replace('/\n/', '\u000a', $wbo->json()); 146 | } 147 | else 148 | echo json_encode($result{'id'}); 149 | echo "\n"; 150 | } 151 | return 1; 152 | } 153 | } 154 | ?> 155 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 |

Maybe the setup is not completed, missing settings.php


"; 47 | exit; 48 | 49 | } else if ( file_exists("setup.php") ) { 50 | echo "

Maybe the setup is not completed, else please delete setup.php


"; 51 | exit; 52 | } 53 | 54 | require_once 'weave_storage.php'; 55 | require_once 'weave_basic_object.php'; 56 | require_once 'weave_utils.php'; 57 | require_once 'weave_hash.php'; 58 | 59 | require_once "WBOJsonOutput.php"; 60 | //header("Content-type: application/json"); 61 | 62 | $server_time = round(microtime(1), 2); 63 | header("X-Weave-Timestamp: " . $server_time); 64 | 65 | # Basic path extraction and validation. No point in going on if these are missing 66 | $path = '/'; 67 | if (!empty($_SERVER['PATH_INFO'])) 68 | $path = $_SERVER['PATH_INFO']; 69 | else if (!empty($_SERVER['ORIG_PATH_INFO'])) 70 | $path = $_SERVER['ORIG_PATH_INFO']; 71 | else if (!empty($_SERVER["REQUEST_URI"])) 72 | { 73 | log_error("experimental path"); 74 | # this is kind of an experimental try, i needed it so i build it, 75 | # but that doesent mean that it does work... well it works for me 76 | # and it shouldnt break anything... 77 | $path = $_SERVER["REQUEST_URI"]; 78 | $lastfolder = substr(FSYNCMS_ROOT,strrpos(FSYNCMS_ROOT, "/",-2)); 79 | $path = substr($path, (strpos($path,$lastfolder) + strlen($lastfolder)-1)); #chop the lead slash 80 | if(strpos($path,'?') != false) 81 | $path = substr($path, 0, strpos($path,'?')); //remove php arguments 82 | log_error("path_exp:".$path); 83 | } 84 | else 85 | report_problem("No path found", 404); 86 | 87 | $path = substr($path, 1); #chop the lead slash 88 | log_error("start request_____" . $path); 89 | // ensure that we got a valid request 90 | if ( !$path ) 91 | report_problem("Invalid request, this was not a firefox sync request!", 400); 92 | 93 | // split path into parts and make sure that all values are properly initialized 94 | list($version, $username, $function, $collection, $id) = array_pad(explode('/', $path.'///'), 5, ''); 95 | 96 | if($version == 'user' || $version == 'misc') 97 | { 98 | //asking for userApi -> user.php 99 | $include = true; 100 | require 'user.php'; 101 | exit(); // should not get here, but how knows 102 | } 103 | 104 | header("Content-type: application/json"); 105 | 106 | if ($version != '1.0' && $version != '1.1') 107 | report_problem('Function not found', 404); 108 | 109 | if ($function != "info" && $function != "storage") 110 | report_problem(WEAVE_ERROR_FUNCTION_NOT_SUPPORTED, 400); 111 | 112 | if (!validate_username($username)) 113 | report_problem(WEAVE_ERROR_INVALID_USERNAME, 400); 114 | 115 | #only a delete has meaning without a collection 116 | if ($collection) 117 | { 118 | if (!validate_collection($collection)) 119 | report_problem(WEAVE_ERROR_INVALID_COLLECTION, 400); 120 | } 121 | else if ($_SERVER['REQUEST_METHOD'] != 'DELETE') 122 | report_problem(WEAVE_ERROR_INVALID_PROTOCOL, 400); 123 | 124 | 125 | #quick check to make sure that any non-storage function calls are just using GET 126 | if ($function != 'storage' && $_SERVER['REQUEST_METHOD'] != 'GET') 127 | report_problem(WEAVE_ERROR_INVALID_PROTOCOL, 400); 128 | 129 | 130 | 131 | #user passes preliminaries, connections made, onto actually getting the data 132 | try 133 | { 134 | $db = new WeaveStorage($username); 135 | 136 | #Auth the user 137 | verify_user($username, $db); 138 | 139 | #user passes preliminaries, connections made, onto actually getting the data 140 | if ($_SERVER['REQUEST_METHOD'] == 'GET') 141 | { 142 | if ($function == 'info') 143 | { 144 | switch ($collection) 145 | { 146 | case 'quota': 147 | exit(json_encode(array($db->get_storage_total()))); 148 | case 'collections': 149 | exit(json_encode($db->get_collection_list_with_timestamps())); 150 | case 'collection_counts': 151 | exit(json_encode($db->get_collection_list_with_counts())); 152 | case 'collection_usage': 153 | $results = $db->get_collection_storage_totals(); 154 | foreach (array_keys($results) as $collection) 155 | { 156 | $results[$collection] = ceil($results[$collection] / 1024); #converting to k from bytes 157 | } 158 | exit(json_encode($results)); 159 | default: 160 | report_problem(WEAVE_ERROR_INVALID_PROTOCOL, 400); 161 | } 162 | } 163 | elseif ($function == 'storage') 164 | { 165 | log_error("function storage"); 166 | if ($id) #retrieve a single record 167 | { 168 | $wbo = $db->retrieve_objects($collection, $id, 1); #get the full contents of one record 169 | if (count($wbo) > 0) 170 | { 171 | $item = array_shift($wbo); 172 | echo $item->json(); 173 | } 174 | else 175 | report_problem("record not found", 404); 176 | } 177 | else #retrieve a batch of records. Sadly, due to potential record sizes, have the storage object stream the output... 178 | { 179 | log_error("retrieve a batch"); 180 | $full = array_key_exists('full', $_GET) && $_GET['full']; 181 | 182 | $outputter = new WBOJsonOutput($full); 183 | 184 | $params = validate_search_params(); 185 | 186 | $ids = $db->retrieve_objects($collection, null, $full, $outputter, 187 | $params['parentid'], $params['predecessorid'], 188 | $params['newer'], $params['older'], 189 | $params['sort'], 190 | $params['limit'], $params['offset'], 191 | $params['ids'], 192 | $params['index_above'], $params['index_below'], $params['depth'] 193 | ); 194 | } 195 | } 196 | } 197 | else if ($_SERVER['REQUEST_METHOD'] == 'PUT') #add a single record to the server 198 | { 199 | $wbo = new wbo(); 200 | if (!$wbo->extract_json(get_json())) 201 | report_problem(WEAVE_ERROR_JSON_PARSE, 400); 202 | 203 | check_quota($db); 204 | check_timestamp($collection, $db); 205 | 206 | #use the url if the json object doesn't have an id 207 | if (!$wbo->id() && $id) { $wbo->id($id); } 208 | 209 | $wbo->collection($collection); 210 | $wbo->modified($server_time); #current microtime 211 | 212 | if ($wbo->validate()) 213 | { 214 | #if there's no payload (as opposed to blank), then update the metadata 215 | if ($wbo->payload_exists()) 216 | $db->store_object($wbo); 217 | else 218 | $db->update_object($wbo); 219 | } 220 | else 221 | { 222 | report_problem(WEAVE_ERROR_INVALID_WBO, 400); 223 | } 224 | echo json_encode($server_time); 225 | } 226 | else if ($_SERVER['REQUEST_METHOD'] == 'POST') 227 | { 228 | $json = get_json(); 229 | 230 | check_quota($db); 231 | check_timestamp($collection, $db); 232 | 233 | $success_ids = array(); 234 | $failed_ids = array(); 235 | 236 | $db->begin_transaction(); 237 | 238 | foreach ($json as $wbo_data) 239 | { 240 | $wbo = new wbo(); 241 | 242 | if (!$wbo->extract_json($wbo_data)) 243 | { 244 | $failed_ids[$wbo->id()] = $wbo->get_error(); 245 | continue; 246 | } 247 | 248 | $wbo->collection($collection); 249 | $wbo->modified($server_time); 250 | 251 | 252 | if ($wbo->validate()) 253 | { 254 | #if there's no payload (as opposed to blank), then update the metadata 255 | if ($wbo->payload_exists()) 256 | { 257 | $db->store_object($wbo); 258 | } 259 | else 260 | { 261 | $db->update_object($wbo); 262 | } 263 | $success_ids[] = $wbo->id(); 264 | } 265 | else 266 | { 267 | $failed_ids[$wbo->id()] = $wbo->get_error(); 268 | } 269 | } 270 | $db->commit_transaction(); 271 | 272 | echo json_encode(array('success' => $success_ids, 'failed' => $failed_ids)); 273 | } 274 | else if ($_SERVER['REQUEST_METHOD'] == 'DELETE') 275 | { 276 | check_timestamp($collection, $db); 277 | 278 | if ($id) 279 | { 280 | $db->delete_object($collection, $id); 281 | } 282 | else if ($collection) 283 | { 284 | $params = validate_search_params(); 285 | 286 | $db->delete_objects($collection, null, 287 | $params['parentid'], $params['predecessorid'], 288 | $params['newer'], $params['older'], 289 | $params['sort'], 290 | $params['limit'], $params['offset'], 291 | $params['ids'], 292 | $params['index_above'], $params['index_below'] 293 | ); 294 | } 295 | else if($function == 'storage') // ich vermute mal storage reinigen 296 | { 297 | if (!array_key_exists('HTTP_X_CONFIRM_DELETE', $_SERVER)) 298 | report_problem(WEAVE_ERROR_NO_OVERWRITE, 412); 299 | $db->delete_storage($username); 300 | } 301 | else 302 | { 303 | if (!array_key_exists('HTTP_X_CONFIRM_DELETE', $_SERVER)) 304 | report_problem(WEAVE_ERROR_NO_OVERWRITE, 412); 305 | log_error("delete "."Server ".print_r( $_SERVER, true)); 306 | $db->delete_user($username); 307 | } 308 | 309 | echo json_encode($server_time); 310 | 311 | } 312 | else 313 | { 314 | #bad protocol. There are protocols left? HEAD, I guess. 315 | report_problem(1, 400); 316 | } 317 | } 318 | catch(Exception $e) 319 | { 320 | report_problem($e->getMessage(), $e->getCode()); 321 | } 322 | 323 | 324 | #The datasets we might be dealing with here are too large for sticking it all into an array, so 325 | #we need to define a direct-output method for the storage class to use. If we start producing multiples 326 | #(unlikely), we can put them in their own class. 327 | 328 | #include_once "WBOJsonOutput.php"; 329 | ?> 330 | -------------------------------------------------------------------------------- /setup.php: -------------------------------------------------------------------------------- 1 | 25 | # balu 26 | # 27 | # Alternatively, the contents of this file may be used under the terms of 28 | # either the GNU General Public License Version 2 or later (the "GPL"), or 29 | # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 30 | # in which case the provisions of the GPL or the LGPL are applicable instead 31 | # of those above. If you wish to allow use of your version of this file only 32 | # under the terms of either the GPL or the LGPL, and not to allow others to 33 | # use your version of this file under the terms of the MPL, indicate your 34 | # decision by deleting the provisions above and replace them with the notice 35 | # and other provisions required by the GPL or the LGPL. If you do not delete 36 | # the provisions above, a recipient may use your version of this file under 37 | # the terms of any one of the MPL, the GPL or the LGPL. 38 | # 39 | # ***** END LICENSE BLOCK ***** 40 | 41 | // -------------------------------------------- 42 | // variables start 43 | // -------------------------------------------- 44 | $action = null; 45 | $dbType = null; 46 | 47 | $dbUser = null; 48 | $dbName = null; 49 | $dbPass = null; 50 | $dbHost = null; 51 | 52 | 53 | // -------------------------------------------- 54 | // variables end 55 | // -------------------------------------------- 56 | 57 | 58 | // -------------------------------------------- 59 | // post handling start 60 | // -------------------------------------------- 61 | if ( isset( $_POST['action'] ) ) { 62 | $action = check_input($_POST['action']); 63 | } 64 | 65 | if ( isset( $_POST['dbType'] ) ) { 66 | $dbType = check_input($_POST['dbType']); 67 | } 68 | 69 | if ( isset( $_POST['dbhost'] ) ) { 70 | $dbHost = check_input($_POST['dbhost']); 71 | } 72 | 73 | if ( isset( $_POST['dbname'] ) ) { 74 | $dbName = check_input($_POST['dbname']); 75 | } 76 | 77 | if ( isset( $_POST['dbuser'] ) ) { 78 | $dbUser = check_input($_POST['dbuser']); 79 | } 80 | 81 | if ( isset( $_POST['dbpass'] ) ) { 82 | $dbPass = check_input($_POST['dbpass']); 83 | } 84 | 85 | // -------------------------------------------- 86 | // post handling end 87 | // -------------------------------------------- 88 | 89 | 90 | // -------------------------------------------- 91 | // functions start 92 | // -------------------------------------------- 93 | 94 | /* 95 | ensure that the input is not total waste 96 | */ 97 | function check_input( $data ) { 98 | $data = trim($data); 99 | $data = stripslashes($data); 100 | $data = htmlspecialchars($data); 101 | return $data; 102 | } 103 | 104 | 105 | /* 106 | create the config file with the database type 107 | and the given connection credentials 108 | */ 109 | function write_config_file($dbt, $dbh, $dbn, $dbu, $dbp, $fsRoot) { 110 | 111 | // construct the name of config file 112 | // 113 | $path = explode('/', $_SERVER['SCRIPT_FILENAME']); 114 | array_pop($path); 115 | array_push($path, 'settings.php'); 116 | $cfg_file_name = implode('/', $path); 117 | 118 | if ( file_exists($cfg_file_name) && filesize( $cfg_file_name ) > 0 ) { 119 | echo "
The config file $cfg_file_name is already present"; 120 | return; 121 | } 122 | 123 | echo "Creating cfg file: " . $cfg_file_name; 124 | 125 | // now build the content of the config file 126 | // 127 | $cfg_content = "\n"; 160 | 161 | // now write everything 162 | // 163 | $cfg_file = fopen($cfg_file_name, "a"); 164 | fputs($cfg_file, "$cfg_content"); 165 | fclose($cfg_file); 166 | } 167 | 168 | 169 | /* 170 | print the html header for the form 171 | */ 172 | function print_header( $title ) { 173 | if ( ! isset( $title ) ) { 174 | $title = ""; 175 | } 176 | print '
' . $title . ' 177 |

Setup FSyncMS

178 |
'; 179 | } 180 | 181 | 182 | /* 183 | print the html footer 184 | */ 185 | function print_footer() { 186 | print '
'; 187 | } 188 | 189 | 190 | /* 191 | print the html for for the mysql connection credentials 192 | */ 193 | function print_mysql_connection_form() { 194 | print_header("MySQL database connection setup"); 195 | print 'MySQL database connection setup 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 |
Host
Instance name
Username
Password
214 | 215 | 216 | 217 |

'; 218 | print_footer(); 219 | } 220 | // -------------------------------------------- 221 | // functions end 222 | // -------------------------------------------- 223 | 224 | // check if we have no configuration at the moment 225 | // 226 | if ( file_exists("settings.php") && filesize( "settings.php" ) > 0 ) { 227 | echo "

The setup looks like it's completed, please delete settings.php


"; 228 | exit; 229 | } 230 | 231 | 232 | // inital page - select the database type 233 | // 234 | if ( ! $action ) { 235 | 236 | // first check if we have pdo installed (untested) 237 | // 238 | if ( ! extension_loaded('PDO') ) { 239 | print "ERROR - PDO is missing in the php installation!"; 240 | exit(); 241 | } 242 | 243 | $validPdoDriver = 0; 244 | 245 | print_header("Setup FSyncMS - DB Selection"); 246 | 247 | print 'Which database type should be used?
'; 248 | if ( extension_loaded('pdo_mysql') ) { 249 | print ' MySQL
'; 250 | $validPdoDriver++; 251 | } else { 252 | print 'MySQL not possible (Driver missing)
'; 253 | } 254 | 255 | if ( extension_loaded('pdo_sqlite') ) { 256 | print ' SQLite '; 257 | $validPdoDriver++; 258 | } else { 259 | print 'SQLite not possible (Driver missing)
'; 260 | } 261 | 262 | if ( $validPdoDriver < 1 ) { 263 | print '
No valid pdo driver found! Please install a valid pdo driver first
'; 264 | } else { 265 | print ' 266 |

'; 267 | } 268 | 269 | // ensure we bail out at this point ;) 270 | exit(); 271 | }; 272 | 273 | 274 | // step 2 (connection data) below 275 | // 276 | if ( $action == "step1" ) { 277 | 278 | // now check if the database is in place 279 | // 280 | print_header("Setup FSyncMS - DB Setup: $dbType!"); 281 | switch ( $dbType ) { 282 | case "sqlite": 283 | $action = "step2"; 284 | break; 285 | 286 | case "mysql": 287 | print_mysql_connection_form(); 288 | break; 289 | 290 | default: 291 | print "ERROR - This type of database ($dbType) is not valid at the moment!"; 292 | exit(); 293 | break; 294 | } 295 | 296 | } 297 | 298 | // now generate the database 299 | // 300 | if ( $action == "step2" ) { 301 | 302 | $dbInstalled = false; 303 | $dbHandle = null; 304 | try { 305 | 306 | if ( $dbType == "sqlite" ) { 307 | 308 | $path = explode('/', $_SERVER['SCRIPT_FILENAME']); 309 | $db_name = 'weave_db'; 310 | array_pop($path); 311 | array_push($path, $db_name); 312 | $db_name = implode('/', $path); 313 | 314 | if ( file_exists($db_name) && filesize( $db_name ) > 0 ) { 315 | $dbInstalled = true; 316 | } else { 317 | echo("Creating sqlite weave storage: ". $db_name ."
"); 318 | $dbHandle = new PDO('sqlite:' . $db_name); 319 | $dbHandle->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 320 | } 321 | 322 | } else if ( $dbType == "mysql" ) { 323 | 324 | $dbHandle = new PDO("mysql:host=". $dbHost .";dbname=". $dbName, $dbUser, $dbPass); 325 | $select_stmt = "show tables like 'wbo'"; 326 | $sth = $dbHandle->prepare($select_stmt); 327 | $sth->execute(); 328 | $count = $sth->rowCount(); 329 | if ( $count > 0 ) { 330 | $dbInstalled = true; 331 | } 332 | 333 | }; 334 | 335 | } catch ( PDOException $exception ) { 336 | echo("database unavailable " . $exception->getMessage()); 337 | throw new Exception("Database unavailable " . $exception->getMessage() , 503); 338 | } 339 | 340 | if ( $dbInstalled ) { 341 | echo "DB is already installed!
"; 342 | 343 | } else { 344 | echo "Now going to install the new database! Type is: $dbType
"; 345 | 346 | try { 347 | $create_statement = " create table wbo ( username varchar(100), id varchar(65), collection varchar(100), 348 | parentid varchar(65), predecessorid int, modified real, sortindex int, 349 | payload text, payload_size int, ttl int, primary key (username,collection,id))"; 350 | $create_statement2 = " create table users ( username varchar(255), md5 varchar(124), primary key (username)) "; 351 | $index1 = 'create index parentindex on wbo (username, parentid)'; 352 | $index2 = 'create index predecessorindex on wbo (username, predecessorid)'; 353 | $index3 = 'create index modifiedindex on wbo (username, collection, modified)'; 354 | 355 | $sth = $dbHandle->prepare($create_statement); 356 | $sth->execute(); 357 | $sth = $dbHandle->prepare($create_statement2); 358 | $sth->execute(); 359 | $sth = $dbHandle->prepare($index1); 360 | $sth->execute(); 361 | $sth = $dbHandle->prepare($index2); 362 | $sth->execute(); 363 | $sth = $dbHandle->prepare($index3); 364 | $sth->execute(); 365 | echo "Database created
"; 366 | 367 | } catch( PDOException $exception ) { 368 | throw new Exception("Database unavailable", 503); 369 | } 370 | 371 | } 372 | 373 | //guessing fsroot 374 | // get the FSYNC_ROOT url 375 | // 376 | $fsRoot ="https://"; 377 | if ( ! isset($_SERVER['HTTPS']) ) { 378 | $fsRoot = "http://"; 379 | } 380 | $fsRoot .= $_SERVER['SERVER_NAME'] . dirname($_SERVER['SCRIPT_NAME']) . "/"; 381 | if( strpos( $_SERVER['REQUEST_URI'], 'index.php') !== 0 ) { 382 | $fsRoot .= "index.php/"; 383 | } 384 | 385 | // write settings.php, if not possible, display the needed contant 386 | // 387 | write_config_file($dbType, $dbHost, $dbName, $dbUser, $dbPass, $fsRoot); 388 | 389 | echo "

Finished the setup, please delete setup.php and go on with the FFSync

"; 390 | echo <<
392 |

This script has guessed the Address of your installation, this might not be accurate,
393 | Please check if this script can be reached by $fsRoot .
394 | If thats not the case you have to ajust the settings.php
395 |

396 | EOT; 397 | } 398 | 399 | ?> 400 | -------------------------------------------------------------------------------- /test/hash.php: -------------------------------------------------------------------------------- 1 | hash($pwd) . "\n"; 14 | $time = microtime(true) - $time_start; 15 | echo "Hashing took " . $time . " seconds\n"; 16 | 17 | if (!$hash->verify($pwd, '$2a$12$O2Bn6lDUYS5NDIJ1uCZjGezSI/jeGTD7Ow0bd3PFMRBcGIqfqI4Oi')) { 18 | throw new Exception("bcrypt hash compare failed"); 19 | } 20 | 21 | if (!$hash->needsUpdate(md5($pwd))) { 22 | throw new Exception("bcrypt hash needs update."); 23 | } 24 | 25 | if ($hash->needsUpdate('$2a$12$O2Bn6lDUYS5NDIJ1uCZjGezSI/jeGTD7Ow0bd3PFMRBcGIqfqI4Oi')) { 26 | throw new Exception("bcrypt hash doesn't needs update."); 27 | } 28 | 29 | if (!$hash->verify($pwd, 'a96b71c678b01b98b9f7a0d8ec4b633b')) { 30 | throw new Exception("bcrypt hash compare with md5 failed"); 31 | } 32 | 33 | $hash2 = new WeaveHashBCrypt(6); 34 | 35 | if (!$hash2->needsUpdate('$2a$12$O2Bn6lDUYS5NDIJ1uCZjGezSI/jeGTD7Ow0bd3PFMRBcGIqfqI4Oi')) { 36 | throw new Exception("bcrypt hash needs update because of different rounds."); 37 | } 38 | 39 | $hashmd5 = new WeaveHashMD5(); 40 | if (!$hashmd5->verify($pwd, 'a96b71c678b01b98b9f7a0d8ec4b633b')) { 41 | throw new Exception("md5 hash compare failed"); 42 | } 43 | 44 | if (!$hashmd5->needsUpdate('$2a$12$O2Bn6lDUYS5NDIJ1uCZjGezSI/jeGTD7Ow0bd3PFMRBcGIqfqI4Oi')) { 45 | throw new Exception("md5 hash needs update."); 46 | } 47 | 48 | if ($hashmd5->needsUpdate(md5($pwd))) { 49 | throw new Exception("md5 hash doesn't need update."); 50 | } 51 | 52 | echo "all tests ok\n"; 53 | exit(0); 54 | } catch(Exception $e) { 55 | echo $e->getMessage() . "\n"; 56 | exit(1); 57 | } 58 | 59 | ?> -------------------------------------------------------------------------------- /user.php: -------------------------------------------------------------------------------- 1 | create_user($name, $pwd)) 206 | { 207 | log_error("successfully created user"); 208 | exit(json_encode(strtolower($name))); 209 | } 210 | else 211 | { 212 | log_error("create user failed"); 213 | report_problem(WEAVE_ERROR_NO_OVERWRITE, 503); 214 | } 215 | } 216 | catch(Exception $e) 217 | { 218 | log_error("db exception create user"); 219 | header("X-Weave-Backoff: 1800"); 220 | report_problem($e->getMessage(), $e->getCode()); 221 | } 222 | 223 | } 224 | else 225 | { 226 | log_error("register not enabled"); 227 | report_problem(WEAVE_ERROR_FUNCTION_NOT_SUPPORTED,400); 228 | } 229 | } // ende put 230 | else if($_SERVER['REQUEST_METHOD'] == 'POST') 231 | { 232 | if($username == '') 233 | { 234 | log_error("user.php : Post no username"); 235 | report_problem(WEAVE_ERROR_INVALID_USERNAME, 400); 236 | } 237 | $db = new WeaveStorage($username); 238 | log_error("user.php: POST"); 239 | if($function == "password") 240 | { 241 | #Auth the user 242 | verify_user($username, $db); 243 | $new_pwd = get_phpinput(); 244 | log_error("user.php: POST password "); 245 | //to do 246 | // change pw in db 247 | $hash = WeaveHashFactory::factory(); 248 | if($db->change_password($hash->hash($new_pwd))) 249 | exit("success"); 250 | else 251 | report_problem(WEAVE_ERROR_INVALID_PROTOCOL, 503); //server db messed up somehow 252 | // return success 253 | // report_problem(7, 400); 254 | } 255 | else if($function == "email") 256 | { 257 | //change email adr 258 | } 259 | else 260 | { 261 | report_problem(WEAVE_ERROR_INVALID_PROTOCOL, 400); 262 | } 263 | // exit('success'); 264 | } 265 | } 266 | catch(Exception $e) 267 | { 268 | report_problem($e->getMessage(), $e->getCode()); 269 | } 270 | #The datasets we might be dealing with here are too large for sticking it all into an array, so 271 | #we need to define a direct-output method for the storage class to use. If we start producing multiples 272 | #(unlikely), we can put them in their own class. 273 | 274 | #include_once "WBOJsonOutput.php"; 275 | 276 | ?> 277 | -------------------------------------------------------------------------------- /weave_basic_object.php: -------------------------------------------------------------------------------- 1 | _error[] = "unable to extract from json"; 55 | return false; 56 | } 57 | 58 | #must have an id, or all sorts of badness happens. However, it can be added later 59 | if (array_key_exists('id', $extracted)) 60 | { 61 | $this->id($extracted['id']); 62 | } 63 | 64 | if (array_key_exists('parentid', $extracted)) 65 | { 66 | $this->parentid($extracted['parentid']); 67 | } 68 | 69 | if (array_key_exists('predecessorid', $extracted)) 70 | { 71 | $this->predecessorid($extracted['predecessorid']); 72 | } 73 | 74 | if (array_key_exists('sortindex', $extracted)) 75 | { 76 | # Due to complicated logic in the getter, we need to validate 77 | # the value space of sortindex here. 78 | if (!is_numeric($extracted['sortindex'])) { 79 | $this->_error[] = "invalid sortindex"; 80 | return false; 81 | } 82 | $this->sortindex($extracted['sortindex']); 83 | } 84 | 85 | if (array_key_exists('payload', $extracted)) 86 | { 87 | $this->payload($extracted['payload']); 88 | } 89 | return true; 90 | } 91 | 92 | function populate(&$datahash) 93 | { 94 | if (array_key_exists('id', $datahash)) 95 | $this->id($datahash['id']); 96 | 97 | if (array_key_exists('collection', $datahash)) 98 | $this->collection($datahash['collection']); 99 | 100 | if (array_key_exists('parentid', $datahash)) 101 | $this->parentid($datahash['parentid']); 102 | 103 | if (array_key_exists('modified', $datahash)) 104 | $this->modified($datahash['modified']); 105 | 106 | if (array_key_exists('predecessorid', $datahash)) 107 | $this->predecessorid($datahash['predecessorid']); 108 | 109 | if (array_key_exists('sortindex', $datahash)) 110 | $this->sortindex($datahash['sortindex']); 111 | 112 | if (array_key_exists('payload', $datahash)) 113 | $this->payload($datahash['payload']); 114 | } 115 | 116 | function id($id = null) 117 | { 118 | if (!is_null($id)) { $this->wbo_hash['id'] = (string)$id; } 119 | return array_key_exists('id', $this->wbo_hash) ? $this->wbo_hash['id'] : null; 120 | } 121 | 122 | function collection($collection = null) 123 | { 124 | if (!is_null($collection)){ $this->_collection = $collection; } 125 | return $this->_collection; 126 | } 127 | 128 | function parentid($parentid = null) 129 | { 130 | if (!is_null($parentid)){ $this->wbo_hash['parentid'] = (string)$parentid; } 131 | return array_key_exists('parentid', $this->wbo_hash) ? $this->wbo_hash['parentid'] : null; 132 | } 133 | 134 | function parentid_exists() 135 | { 136 | return array_key_exists('parentid', $this->wbo_hash); 137 | } 138 | 139 | function predecessorid($predecessorid = null) 140 | { 141 | if (!is_null($predecessorid)){ $this->wbo_hash['predecessorid'] = (string)$predecessorid; } 142 | return array_key_exists('predecessorid', $this->wbo_hash) ? $this->wbo_hash['predecessorid'] : null; 143 | } 144 | 145 | function predecessorid_exists() 146 | { 147 | return array_key_exists('predecessorid', $this->wbo_hash); 148 | } 149 | 150 | function modified($modified = null) 151 | { 152 | if (!is_null($modified)){ $this->wbo_hash['modified'] = round((float)$modified, 2); } 153 | return array_key_exists('modified', $this->wbo_hash) ? $this->wbo_hash['modified'] : null; 154 | } 155 | 156 | function modified_exists() 157 | { 158 | return array_key_exists('modified', $this->wbo_hash); 159 | } 160 | 161 | function payload($payload = null) 162 | { 163 | if (!is_null($payload)){ $this->wbo_hash['payload'] = $payload; } 164 | return array_key_exists('payload', $this->wbo_hash) ? $this->wbo_hash['payload'] : null; 165 | } 166 | 167 | function payload_exists() 168 | { 169 | return array_key_exists('payload', $this->wbo_hash); 170 | } 171 | 172 | function payload_size() 173 | { 174 | return mb_strlen($this->wbo_hash['payload'], '8bit'); 175 | } 176 | 177 | function sortindex($index = null) 178 | { 179 | if (!is_null($index)){ 180 | $this->wbo_hash['sortindex'] = (int)($index); 181 | } 182 | return array_key_exists('sortindex', $this->wbo_hash) ? $this->wbo_hash['sortindex'] : null; 183 | } 184 | 185 | function sortindex_exists() 186 | { 187 | return array_key_exists('sortindex', $this->wbo_hash); 188 | } 189 | 190 | 191 | function validate() 192 | { 193 | 194 | if (!$this->id() || mb_strlen($this->id(), '8bit') > 64 || strpos($this->id(), '/') !== false) 195 | { $this->_error[] = "invalid id"; } 196 | 197 | if ($this->parentid_exists() && mb_strlen($this->parentid(), '8bit') > 64) 198 | { $this->_error[] = "invalid parentid"; } 199 | 200 | if ($this->predecessorid_exists() && mb_strlen($this->predecessorid(), '8bit') > 64) 201 | { $this->_error[] = "invalid predecessorid"; } 202 | 203 | if (!is_numeric($this->modified())) 204 | { $this->_error[] = "invalid modified date"; } 205 | 206 | if (!$this->modified()) 207 | { $this->_error[] = "no modification date"; } 208 | 209 | if (!$this->_collection || mb_strlen($this->_collection, '8bit') > 64) 210 | { $this->_error[] = "invalid collection"; } 211 | 212 | if ($this->sortindex_exists() && 213 | (!is_numeric($this->wbo_hash['sortindex']) || 214 | intval($this->sortindex()) > 999999999 || 215 | intval($this->sortindex()) < -999999999 )) 216 | { $this->_error[] = "invalid sortindex"; } 217 | 218 | if ($this->payload_exists()) 219 | { 220 | if (!is_string($this->wbo_hash['payload'])) 221 | { $this->_error[] = "payload needs to be json-encoded"; } 222 | } 223 | 224 | return !$this->get_error(); 225 | } 226 | 227 | function get_error() 228 | { 229 | return $this->_error; 230 | } 231 | 232 | function clear_error() 233 | { 234 | $this->_error = array(); 235 | } 236 | 237 | function raw_hash() 238 | { 239 | return $this->wbo_hash; 240 | } 241 | 242 | function json() 243 | { 244 | return json_encode($this->wbo_hash); 245 | } 246 | } 247 | 248 | 249 | ?> -------------------------------------------------------------------------------- /weave_hash.php: -------------------------------------------------------------------------------- 1 | 20 | # 21 | # Alternatively, the contents of this file may be used under the terms of 22 | # either the GNU General Public License Version 2 or later (the "GPL"), or 23 | # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 24 | # in which case the provisions of the GPL or the LGPL are applicable instead 25 | # of those above. If you wish to allow use of your version of this file only 26 | # under the terms of either the GPL or the LGPL, and not to allow others to 27 | # use your version of this file under the terms of the MPL, indicate your 28 | # decision by deleting the provisions above and replace them with the notice 29 | # and other provisions required by the GPL or the LGPL. If you do not delete 30 | # the provisions above, a recipient may use your version of this file under 31 | # the terms of any one of the MPL, the GPL or the LGPL. 32 | # 33 | # ***** END LICENSE BLOCK ***** 34 | 35 | interface WeaveHash { 36 | public function hash($input); 37 | public function verify($input, $existingHash); 38 | public function needsUpdate($existingHash); 39 | } 40 | 41 | class WeaveHashMD5 implements WeaveHash { 42 | public function hash($input) { 43 | return md5($input); 44 | } 45 | 46 | public function verify($input, $existingHash) { 47 | return $this->hash($input) == $existingHash; 48 | } 49 | 50 | public function needsUpdate($existingHash) { 51 | return substr($existingHash, 0, 4) == "$2a$"; 52 | } 53 | } 54 | 55 | class WeaveHashBCrypt implements WeaveHash { 56 | private $_rounds; 57 | 58 | public function __construct($rounds = 12) { 59 | if(CRYPT_BLOWFISH != 1) { 60 | throw new Exception("bcrypt not available"); 61 | } 62 | 63 | $this->_rounds = $rounds; 64 | } 65 | 66 | public function hash($input) { 67 | $hash = crypt($input, $this->getSalt()); 68 | 69 | if (strlen($hash) <= 13) { 70 | throw new Exception("error while generating hash"); 71 | } 72 | 73 | return $hash; 74 | } 75 | 76 | public function verify($input, $existingHash) { 77 | if ($this->isMD5($existingHash)) { 78 | $md5 = new WeaveHashMD5(); 79 | return $md5->verify($input, $existingHash); 80 | } 81 | 82 | $hash = crypt($input, $existingHash); 83 | 84 | return $hash === $existingHash; 85 | } 86 | 87 | public function needsUpdate($existingHash) { 88 | $identifier = $this->getIdentifier(); 89 | return substr($existingHash, 0, strlen($identifier)) != $identifier; 90 | } 91 | 92 | private function isMD5($existingHash) { 93 | return substr($existingHash, 0, 4) != "$2a$"; 94 | } 95 | 96 | private function getSalt() { 97 | $salt = $this->getIdentifier(); 98 | 99 | $bytes = $this->getRandomBytes(16); 100 | 101 | $salt .= $this->encodeBytes($bytes); 102 | 103 | return $salt; 104 | } 105 | 106 | private function getIdentifier() { 107 | return sprintf("$2a$%02d$", $this->_rounds); 108 | } 109 | 110 | private $randomState; 111 | private function getRandomBytes($count) { 112 | $bytes = ''; 113 | 114 | if(function_exists('openssl_random_pseudo_bytes') && 115 | (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')) { // OpenSSL slow on Win 116 | $bytes = openssl_random_pseudo_bytes($count); 117 | } 118 | 119 | if($bytes === '' && is_readable('/dev/urandom') && 120 | ($hRand = @fopen('/dev/urandom', 'rb')) !== FALSE) { 121 | $bytes = fread($hRand, $count); 122 | fclose($hRand); 123 | } 124 | 125 | if(strlen($bytes) < $count) { 126 | $bytes = ''; 127 | 128 | if($this->randomState === null) { 129 | $this->randomState = microtime(); 130 | if(function_exists('getmypid')) { 131 | $this->randomState .= getmypid(); 132 | } 133 | } 134 | 135 | for($i = 0; $i < $count; $i += 16) { 136 | $this->randomState = md5(microtime() . $this->randomState); 137 | 138 | if (PHP_VERSION >= '5') { 139 | $bytes .= md5($this->randomState, true); 140 | } else { 141 | $bytes .= pack('H*', md5($this->randomState)); 142 | } 143 | } 144 | 145 | $bytes = substr($bytes, 0, $count); 146 | } 147 | 148 | return $bytes; 149 | } 150 | 151 | private function encodeBytes($input) { 152 | // The following is code from the PHP Password Hashing Framework 153 | $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; 154 | 155 | $output = ''; 156 | $i = 0; 157 | do { 158 | $c1 = ord($input[$i++]); 159 | $output .= $itoa64[$c1 >> 2]; 160 | $c1 = ($c1 & 0x03) << 4; 161 | if ($i >= 16) { 162 | $output .= $itoa64[$c1]; 163 | break; 164 | } 165 | 166 | $c2 = ord($input[$i++]); 167 | $c1 |= $c2 >> 4; 168 | $output .= $itoa64[$c1]; 169 | $c1 = ($c2 & 0x0f) << 2; 170 | 171 | $c2 = ord($input[$i++]); 172 | $c1 |= $c2 >> 6; 173 | $output .= $itoa64[$c1]; 174 | $output .= $itoa64[$c2 & 0x3f]; 175 | } while (1); 176 | 177 | return $output; 178 | } 179 | } 180 | 181 | class WeaveHashFactory { 182 | public static function factory() { 183 | if (defined("BCRYPT") && BCRYPT) { 184 | return new WeaveHashBCrypt(BCRYPT_ROUNDS); 185 | } else { 186 | return new WeaveHashMD5(); 187 | } 188 | } 189 | } 190 | 191 | ?> -------------------------------------------------------------------------------- /weave_storage.php: -------------------------------------------------------------------------------- 1 | 27 | # Mark Straver 28 | # 29 | # Alternatively, the contents of this file may be used under the terms of 30 | # either the GNU General Public License Version 2 or later (the "GPL"), or 31 | # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 32 | # in which case the provisions of the GPL or the LGPL are applicable instead 33 | # of those above. If you wish to allow use of your version of this file only 34 | # under the terms of either the GPL or the LGPL, and not to allow others to 35 | # use your version of this file under the terms of the MPL, indicate your 36 | # decision by deleting the provisions above and replace them with the notice 37 | # and other provisions required by the GPL or the LGPL. If you do not delete 38 | # the provisions above, a recipient may use your version of this file under 39 | # the terms of any one of the MPL, the GPL or the LGPL. 40 | # 41 | # ***** END LICENSE BLOCK ***** 42 | 43 | require_once 'weave_basic_object.php'; 44 | require_once 'weave_utils.php'; 45 | require_once 'settings.php'; 46 | 47 | class WeaveStorage 48 | { 49 | private $_username; 50 | private $_dbh; 51 | 52 | function __construct($username) 53 | { 54 | 55 | $this->_username = $username; 56 | 57 | log_error("Initalizing DB connecion!"); 58 | 59 | try 60 | { 61 | if ( ! MYSQL_ENABLE ) 62 | { 63 | $path = explode('/', $_SERVER['SCRIPT_FILENAME']); 64 | $db_name = SQLITE_FILE; 65 | array_pop($path); 66 | array_push($path, $db_name); 67 | $db_name = implode('/', $path); 68 | 69 | if ( ! file_exists($db_name) ) 70 | { 71 | log_error("The required sqllite database is not present! $db_name"); 72 | } 73 | 74 | log_error("Starting SQLite connection"); 75 | $this->_dbh = new PDO('sqlite:' . $db_name); 76 | $this->_dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 77 | } 78 | else if ( MYSQL_ENABLE ) 79 | { 80 | log_error("Starting MySQL connection"); 81 | $this->_dbh = new PDO("mysql:host=". MYSQL_HOST .";dbname=". MYSQL_DB, MYSQL_USER, MYSQL_PASSWORD); 82 | } 83 | 84 | } 85 | 86 | catch( PDOException $exception ) 87 | { 88 | log_error("database unavailable " . $exception->getMessage()); 89 | throw new Exception("Database unavailable " . $exception->getMessage() , 503); 90 | } 91 | 92 | } 93 | 94 | function get_connection() 95 | { 96 | return $this->_dbh; 97 | } 98 | 99 | function begin_transaction() 100 | { 101 | try 102 | { 103 | $this->_dbh->beginTransaction(); 104 | } 105 | catch( PDOException $exception ) 106 | { 107 | error_log("begin_transaction: " . $exception->getMessage()); 108 | throw new Exception("Database unavailable", 503); 109 | } 110 | return 1; 111 | } 112 | 113 | function commit_transaction() 114 | { 115 | $this->_dbh->commit(); 116 | return 1; 117 | } 118 | 119 | function get_max_timestamp($collection) 120 | { 121 | if (!$collection) 122 | { 123 | return 0; 124 | } 125 | 126 | try 127 | { 128 | $select_stmt = 'select max(modified) from wbo where username = :username and collection = :collection'; 129 | $sth = $this->_dbh->prepare($select_stmt); 130 | $sth->bindParam(':username', $this->_username); 131 | $sth->bindParam(':collection', $collection); 132 | $sth->execute(); 133 | } 134 | catch( PDOException $exception ) 135 | { 136 | error_log("get_max_timestamp: " . $exception->getMessage()); 137 | throw new Exception("Database unavailable", 503); 138 | } 139 | 140 | $result = $sth->fetchColumn(); 141 | return round((float)$result, 2); 142 | } 143 | 144 | function get_collection_list() 145 | { 146 | try 147 | { 148 | $select_stmt = 'select distinct(collection) from wbo where username = :username'; 149 | $sth = $this->_dbh->prepare($select_stmt); 150 | $sth->bindParam(':username', $this->_username); 151 | $sth->execute(); 152 | } 153 | catch( PDOException $exception ) 154 | { 155 | error_log("get_collection_list: " . $exception->getMessage()); 156 | throw new Exception("Database unavailable", 503); 157 | } 158 | 159 | 160 | $collections = array(); 161 | while ($result = $sth->fetchColumn()) 162 | { 163 | $collections[] = $result; 164 | } 165 | 166 | return $collections; 167 | } 168 | 169 | 170 | function get_collection_list_with_timestamps() 171 | { 172 | try 173 | { 174 | $select_stmt = 'select collection, max(modified) as timestamp from wbo where username = :username group by collection'; 175 | $sth = $this->_dbh->prepare($select_stmt); 176 | $sth->bindParam(':username', $this->_username); 177 | $sth->execute(); 178 | } 179 | catch( PDOException $exception ) 180 | { 181 | error_log("get_collection_list: " . $exception->getMessage()); 182 | throw new Exception("Database unavailable", 503); 183 | } 184 | 185 | $collections = array(); 186 | while ($result = $sth->fetch(PDO::FETCH_NUM)) 187 | { 188 | $collections[$result[0]] = (float)$result[1]; 189 | } 190 | 191 | return $collections; 192 | } 193 | 194 | function get_collection_list_with_counts() 195 | { 196 | try 197 | { 198 | $select_stmt = 'select collection, count(*) as ct from wbo where username = :username group by collection'; 199 | $sth = $this->_dbh->prepare($select_stmt); 200 | $sth->bindParam(':username', $this->_username); 201 | $sth->execute(); 202 | } 203 | catch( PDOException $exception ) 204 | { 205 | error_log("get_collection_list_with_counts: " . $exception->getMessage()); 206 | throw new Exception("Database unavailable", 503); 207 | } 208 | 209 | 210 | $collections = array(); 211 | while ($result = $sth->fetch(PDO::FETCH_NUM)) 212 | { 213 | $collections[$result[0]] = (int)$result[1]; 214 | } 215 | 216 | return $collections; 217 | } 218 | 219 | function store_object(&$wbo) 220 | { 221 | 222 | try 223 | { 224 | if ( MYSQL_ENABLE ) 225 | { 226 | $insert_stmt = 'insert into wbo (username, id, collection, parentid, predecessorid, sortindex, modified, payload, payload_size) 227 | values (:username, :id, :collection, :parentid, :predecessorid, :sortindex, :modified, :payload, :payload_size) 228 | on duplicate key update 229 | username=values(username), id=values(id), collection=values(collection), parentid=values(parentid), 230 | predecessorid=values(predecessorid), sortindex=values(sortindex), modified=values(modified), payload=values(payload), 231 | payload_size=values(payload_size)'; 232 | } 233 | else 234 | { 235 | $insert_stmt = 'replace into wbo (username, id, collection, parentid, predecessorid, sortindex, modified, payload, payload_size) 236 | values (:username, :id, :collection, :parentid, :predecessorid, :sortindex, :modified, :payload, :payload_size)'; 237 | } 238 | 239 | $sth = $this->_dbh->prepare($insert_stmt); 240 | 241 | $username = $this->_username; 242 | $id = $wbo->id(); 243 | $collection = $wbo->collection(); 244 | $parentid = $wbo->parentid(); 245 | $predecessorid = $wbo->predecessorid(); 246 | $sortindex = $wbo->sortindex(); 247 | $modified = $wbo->modified(); 248 | $payload = $wbo->payload(); 249 | $payload_size = $wbo->payload_size(); 250 | 251 | $sth->bindParam(':username', $username); 252 | $sth->bindParam(':id', $id); 253 | $sth->bindParam(':collection', $collection); 254 | $sth->bindParam(':parentid', $parentid); 255 | $sth->bindParam(':predecessorid', $predecessorid); 256 | $sth->bindParam(':sortindex', $sortindex); 257 | $sth->bindParam(':modified', $modified); 258 | $sth->bindParam(':payload', $payload); 259 | $sth->bindParam(':payload_size', $payload_size); 260 | 261 | $sth->execute(); 262 | 263 | } 264 | catch( PDOException $exception ) 265 | { 266 | error_log("store_object: " . $exception->getMessage()); 267 | throw new Exception("Database unavailable", 503); 268 | } 269 | return 1; 270 | } 271 | 272 | 273 | function update_object(&$wbo) 274 | { 275 | $update = "update wbo set "; 276 | $params = array(); 277 | $update_list = array(); 278 | 279 | #make sure we have an id and collection. No point in continuing otherwise 280 | if (!$wbo->id() || !$wbo->collection()) 281 | { 282 | error_log('Trying to update without a valid id or collection!'); 283 | return 0; 284 | } 285 | 286 | if ($wbo->parentid_exists()) 287 | { 288 | $update_list[] = "parentid = ?"; 289 | $params[] = $wbo->parentid(); 290 | } 291 | 292 | if ($wbo->predecessorid_exists()) 293 | { 294 | $update_list[] = "predecessorid = ?"; 295 | $params[] = $wbo->predecessorid(); 296 | } 297 | 298 | if ($wbo->sortindex_exists()) 299 | { 300 | $update_list[] = "sortindex = ?"; 301 | $params[] = $wbo->sortindex(); 302 | } 303 | 304 | if ($wbo->payload_exists()) 305 | { 306 | $update_list[] = "payload = ?"; 307 | $update_list[] = "payload_size = ?"; 308 | $params[] = $wbo->payload(); 309 | $params[] = $wbo->payload_size(); 310 | } 311 | 312 | # Don't modify the timestamp on a non-payload/non-parent change change 313 | if ($wbo->parentid_exists() || $wbo->payload_exists()) 314 | { 315 | #better make sure we have a modified date. Should have been handled earlier 316 | if (!$wbo->modified_exists()) 317 | { 318 | error_log("Called update_object with no defined timestamp. Please check"); 319 | $wbo->modified(microtime(1)); 320 | } 321 | $update_list[] = "modified = ?"; 322 | $params[] = $wbo->modified(); 323 | 324 | } 325 | 326 | 327 | if (count($params) == 0) 328 | { 329 | return 0; 330 | } 331 | 332 | $update .= join($update_list, ","); 333 | 334 | $update .= " where username = ? and collection = ? and id = ?"; 335 | $params[] = $this->_username; 336 | $params[] = $wbo->collection(); 337 | $params[] = $wbo->id(); 338 | 339 | try 340 | { 341 | $sth = $this->_dbh->prepare($update); 342 | $sth->execute($params); 343 | } 344 | catch( PDOException $exception ) 345 | { 346 | error_log("update_object: " . $exception->getMessage()); 347 | throw new Exception("Database unavailable", 503); 348 | } 349 | return 1; 350 | } 351 | 352 | function delete_object($collection, $id) 353 | { 354 | try 355 | { 356 | $delete_stmt = 'delete from wbo where username = :username and collection = :collection and id = :id'; 357 | $sth = $this->_dbh->prepare($delete_stmt); 358 | $username = $this->_username; 359 | $sth->bindParam(':username', $username); 360 | $sth->bindParam(':collection', $collection); 361 | $sth->bindParam(':id', $id); 362 | $sth->execute(); 363 | } 364 | catch( PDOException $exception ) 365 | { 366 | error_log("delete_object: " . $exception->getMessage()); 367 | throw new Exception("Database unavailable", 503); 368 | } 369 | return 1; 370 | } 371 | 372 | function delete_objects($collection, $id = null, $parentid = null, $predecessorid = null, $newer = null, 373 | $older = null, $sort = null, $limit = null, $offset = null, $ids = null, 374 | $index_above = null, $index_below = null) 375 | { 376 | $params = array(); 377 | $select_stmt = ''; 378 | 379 | if ($limit || $offset || $sort) 380 | { 381 | #sqlite can't do sort or limit deletes without special compiled versions 382 | #so, we need to grab the set, then delete it manually. 383 | 384 | $params = $this->retrieve_objects($collection, $id, 0, 0, $parentid, $predecessorid, $newer, $older, $sort, $limit, $offset, $ids, $index_above, $index_below); 385 | if (!count($params)) 386 | { 387 | return 1; #nothing to delete 388 | } 389 | $paramqs = array(); 390 | $select_stmt = "delete from wbo where username = ? and collection = ? and id in (" . join(", ", array_pad($paramqs, count($params), '?')) . ")"; 391 | array_unshift($params, $collection); 392 | array_unshift($params, $username); 393 | } 394 | else 395 | { 396 | 397 | $select_stmt = "delete from wbo where username = ? and collection = ?"; 398 | $params[] = $this->_username; 399 | $params[] = $collection; 400 | 401 | 402 | if ($id) 403 | { 404 | $select_stmt .= " and id = ?"; 405 | $params[] = $id; 406 | } 407 | 408 | if ($ids && count($ids) > 0) 409 | { 410 | $qmarks = array(); 411 | $select_stmt .= " and id in ("; 412 | foreach ($ids as $temp) 413 | { 414 | $params[] = $temp; 415 | $qmarks[] = '?'; 416 | } 417 | $select_stmt .= implode(",", $qmarks); 418 | $select_stmt .= ')'; 419 | } 420 | 421 | if ($parentid) 422 | { 423 | $select_stmt .= " and parentid = ?"; 424 | $params[] = $parentid; 425 | } 426 | 427 | if ($predecessorid) 428 | { 429 | $select_stmt .= " and predecessorid = ?"; 430 | $params[] = $parentid; 431 | } 432 | 433 | if ($index_above) 434 | { 435 | $select_stmt .= " and sortindex > ?"; 436 | $params[] = $parentid; 437 | } 438 | 439 | if ($index_below) 440 | { 441 | $select_stmt .= " and sortindex < ?"; 442 | $params[] = $parentid; 443 | } 444 | 445 | if ($newer) 446 | { 447 | $select_stmt .= " and modified > ?"; 448 | $params[] = $newer; 449 | } 450 | 451 | if ($older) 452 | { 453 | $select_stmt .= " and modified < ?"; 454 | $params[] = $older; 455 | } 456 | 457 | if ($sort == 'index') 458 | { 459 | $select_stmt .= " order by sortindex desc"; 460 | } 461 | else if ($sort == 'newest') 462 | { 463 | $select_stmt .= " order by modified desc"; 464 | } 465 | else if ($sort == 'oldest') 466 | { 467 | $select_stmt .= " order by modified"; 468 | } 469 | 470 | } 471 | 472 | try 473 | { 474 | $sth = $this->_dbh->prepare($select_stmt); 475 | $sth->execute($params); 476 | } 477 | catch( PDOException $exception ) 478 | { 479 | error_log("delete_objects: " . $exception->getMessage()); 480 | throw new Exception("Database unavailable", 503); 481 | } 482 | return 1; 483 | } 484 | 485 | function retrieve_object($collection, $id) 486 | { 487 | try 488 | { 489 | $select_stmt = 'select * from wbo where username = :username and collection = :collection and id = :id'; 490 | $sth = $this->_dbh->prepare($select_stmt); 491 | $username = $this->_username; 492 | $sth->bindParam(':username', $username); 493 | $sth->bindParam(':collection', $collection); 494 | $sth->bindParam(':id', $id); 495 | $sth->execute(); 496 | } 497 | catch( PDOException $exception ) 498 | { 499 | error_log("retrieve_object: " . $exception->getMessage()); 500 | throw new Exception("Database unavailable", 503); 501 | } 502 | 503 | $result = $sth->fetch(PDO::FETCH_ASSOC); 504 | 505 | $wbo = new wbo(); 506 | $wbo->populate($result); 507 | return $wbo; 508 | } 509 | 510 | function retrieve_objects($collection, $id = null, $full = null, $direct_output = null, $parentid = null, 511 | $predecessorid = null, $newer = null, $older = null, $sort = null, 512 | $limit = null, $offset = null, $ids = null, 513 | $index_above = null, $index_below = null) 514 | { 515 | $full_list = $full ? '*' : 'id'; 516 | 517 | 518 | $select_stmt = "select $full_list from wbo where username = ? and collection = ?"; 519 | $params[] = $this->_username; 520 | $params[] = $collection; 521 | 522 | 523 | if ($id) 524 | { 525 | $select_stmt .= " and id = ?"; 526 | $params[] = $id; 527 | } 528 | 529 | if ($ids && count($ids) > 0) 530 | { 531 | $qmarks = array(); 532 | $select_stmt .= " and id in ("; 533 | foreach ($ids as $temp) 534 | { 535 | $params[] = $temp; 536 | $qmarks[] = '?'; 537 | } 538 | $select_stmt .= implode(",", $qmarks); 539 | $select_stmt .= ')'; 540 | } 541 | 542 | if ($parentid) 543 | { 544 | $select_stmt .= " and parentid = ?"; 545 | $params[] = $parentid; 546 | } 547 | 548 | 549 | if ($predecessorid) 550 | { 551 | $select_stmt .= " and predecessorid = ?"; 552 | $params[] = $predecessorid; 553 | } 554 | 555 | if ($index_above) 556 | { 557 | $select_stmt .= " and sortindex > ?"; 558 | $params[] = $parentid; 559 | } 560 | 561 | if ($index_below) 562 | { 563 | $select_stmt .= " and sortindex < ?"; 564 | $params[] = $parentid; 565 | } 566 | 567 | if ($newer) 568 | { 569 | $select_stmt .= " and modified > ?"; 570 | $params[] = $newer; 571 | } 572 | 573 | if ($older) 574 | { 575 | $select_stmt .= " and modified < ?"; 576 | $params[] = $older; 577 | } 578 | 579 | if ($sort == 'index') 580 | { 581 | $select_stmt .= " order by sortindex desc"; 582 | } 583 | else if ($sort == 'newest') 584 | { 585 | $select_stmt .= " order by modified desc"; 586 | } 587 | else if ($sort == 'oldest') 588 | { 589 | $select_stmt .= " order by modified"; 590 | } 591 | 592 | if ($limit) 593 | { 594 | $select_stmt .= " limit " . intval($limit); 595 | if ($offset) 596 | { 597 | $select_stmt .= " offset " . intval($offset); 598 | } 599 | } 600 | 601 | try 602 | { 603 | $sth = $this->_dbh->prepare($select_stmt); 604 | $sth->execute($params); 605 | } 606 | catch( PDOException $exception ) 607 | { 608 | error_log("retrieve_collection: " . $exception->getMessage()); 609 | throw new Exception("Database unavailable", 503); 610 | } 611 | 612 | if ($direct_output) 613 | return $direct_output->output($sth); 614 | 615 | $ids = array(); 616 | while ($result = $sth->fetch(PDO::FETCH_ASSOC)) 617 | { 618 | if ($full) 619 | { 620 | $wbo = new wbo(); 621 | $wbo->populate($result); 622 | $ids[] = $wbo; 623 | } 624 | else 625 | $ids[] = $result{'id'}; 626 | } 627 | return $ids; 628 | } 629 | 630 | function get_storage_total() 631 | { 632 | try 633 | { 634 | $select_stmt = 'select round(sum(length(payload))/1024) from wbo where username = :username'; 635 | $sth = $this->_dbh->prepare($select_stmt); 636 | $username = $this->_username; 637 | $sth->bindParam(':username', $username); 638 | $sth->execute(); 639 | } 640 | catch( PDOException $exception ) 641 | { 642 | error_log("get_storage_total: " . $exception->getMessage()); 643 | throw new Exception("Database unavailable", 503); 644 | } 645 | 646 | return (int)$sth->fetchColumn(); 647 | } 648 | 649 | function get_collection_storage_totals() 650 | { 651 | try 652 | { 653 | $select_stmt = 'select collection, sum(payload_size) from wbo where username = :username group by collection'; 654 | $sth = $this->_dbh->prepare($select_stmt); 655 | $username = $this->_username; 656 | $sth->bindParam(':username', $username); 657 | $sth->execute(); 658 | } 659 | catch( PDOException $exception ) 660 | { 661 | error_log("get_storage_total (" . $this->connection_details_string() . "): " . $exception->getMessage()); 662 | throw new Exception("Database unavailable", 503); 663 | } 664 | $results = $sth->fetchAll(PDO::FETCH_NUM); 665 | $sth->closeCursor(); 666 | 667 | $collections = array(); 668 | foreach ($results as $result) 669 | { 670 | $collections[$result[0]] = (int)$result[1]; 671 | } 672 | return $collections; 673 | } 674 | 675 | 676 | function get_user_quota() 677 | { 678 | return null; 679 | } 680 | 681 | function delete_storage($username) 682 | { 683 | log_error("delete storage"); 684 | if (!$username) 685 | { 686 | throw new Exception("3", 404); 687 | } 688 | try 689 | { 690 | $delete_stmt = 'delete from wbo where username = :username'; 691 | $sth = $this->_dbh->prepare($delete_stmt); 692 | $sth->bindParam(':username', $username); 693 | $sth->execute(); 694 | $sth->closeCursor(); 695 | } 696 | catch( PDOException $exception ) 697 | { 698 | error_log("delete_user: " . $exception->getMessage()); 699 | return 0; 700 | } 701 | return 1; 702 | 703 | } 704 | 705 | function delete_user($username) 706 | { 707 | log_error("delete User"); 708 | if (!$username) 709 | { 710 | throw new Exception("3", 404); 711 | } 712 | 713 | try 714 | { 715 | $delete_stmt = 'delete from users where username = :username'; 716 | $sth = $this->_dbh->prepare($delete_stmt); 717 | $sth->bindParam(':username', $username); 718 | $sth->execute(); 719 | $sth->closeCursor(); 720 | 721 | $delete_wbo_stmt = 'delete from wbo where username = :username'; 722 | $sth = $this->_dbh->prepare($delete_wbo_stmt); 723 | $sth->bindParam(':username', $username); 724 | $sth->execute(); 725 | 726 | } 727 | catch( PDOException $exception ) 728 | { 729 | error_log("delete_user: " . $exception->getMessage()); 730 | return 0; 731 | } 732 | return 1; 733 | } 734 | 735 | function create_user($username, $password) 736 | { 737 | log_error("Create User - Username: ".$username."|".$password); 738 | 739 | try 740 | { 741 | $create_statement = "insert into users values (:username, :md5)"; 742 | 743 | $sth = $this->_dbh->prepare($create_statement); 744 | $hash = WeaveHashFactory::factory(); 745 | $password = $hash->hash($password); 746 | $sth->bindParam(':username', $username); 747 | $sth->bindParam(':md5', $password); 748 | $sth->execute(); 749 | } 750 | catch( PDOException $exception ) 751 | { 752 | log_error("create_user:" . $exception->getMessage()); 753 | error_log("create_user:" . $exception->getMessage()); 754 | return 0; 755 | } 756 | return 1; 757 | } 758 | 759 | function change_password($hash) 760 | { 761 | try 762 | { 763 | $update_statement = "update users set md5 = :md5 where username = :username"; 764 | 765 | $sth = $this->_dbh->prepare($update_statement); 766 | $sth->bindParam(':username', $this->_username); 767 | $sth->bindParam(':md5', $hash); 768 | $sth->execute(); 769 | } 770 | catch( PDOException $exception ) 771 | { 772 | log_error("change_password:" . $exception->getMessage()); 773 | return 0; 774 | } 775 | return 1; 776 | } 777 | 778 | #function checks if user exists 779 | function exists_user() 780 | { 781 | try 782 | { 783 | $select_stmt = 'select username from users where username = :username'; 784 | $sth = $this->_dbh->prepare($select_stmt); 785 | $username = $this->_username; 786 | $sth->bindParam(':username', $username); 787 | $sth->execute(); 788 | } 789 | catch( PDOException $exception ) 790 | { 791 | error_log("exists_user: " . $exception->getMessage()); 792 | throw new Exception("Database unavailable", 503); 793 | } 794 | 795 | if (!$result = $sth->fetch(PDO::FETCH_ASSOC)) 796 | { 797 | return null; 798 | } 799 | return 1; 800 | } 801 | 802 | 803 | function get_password_hash() 804 | { 805 | log_error("auth-user: " . $this->_username); 806 | try 807 | { 808 | $select_stmt = 'select md5 from users where username = :username'; 809 | $sth = $this->_dbh->prepare($select_stmt); 810 | $username = $this->_username; 811 | $sth->bindParam(':username', $username); 812 | $sth->execute(); 813 | } 814 | catch( PDOException $exception ) 815 | { 816 | error_log("get_password_hash: " . $exception->getMessage()); 817 | throw new Exception("Database unavailable", 503); 818 | } 819 | 820 | $result = $sth->fetchColumn(); 821 | if ($result === FALSE) $result = ""; 822 | 823 | return $result; 824 | } 825 | 826 | } 827 | 828 | 829 | ?> 830 | -------------------------------------------------------------------------------- /weave_utils.php: -------------------------------------------------------------------------------- 1 | 23 | # 24 | # Alternatively, the contents of this file may be used under the terms of 25 | # either the GNU General Public License Version 2 or later (the "GPL"), or 26 | # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 27 | # in which case the provisions of the GPL or the LGPL are applicable instead 28 | # of those above. If you wish to allow use of your version of this file only 29 | # under the terms of either the GPL or the LGPL, and not to allow others to 30 | # use your version of this file under the terms of the MPL, indicate your 31 | # decision by deleting the provisions above and replace them with the notice 32 | # and other provisions required by the GPL or the LGPL. If you do not delete 33 | # the provisions above, a recipient may use your version of this file under 34 | # the terms of any one of the MPL, the GPL or the LGPL. 35 | # 36 | # ***** END LICENSE BLOCK ***** 37 | 38 | #Error constants 39 | define ('WEAVE_ERROR_INVALID_PROTOCOL', 1); 40 | define ('WEAVE_ERROR_INCORRECT_CAPTCHA', 2); 41 | define ('WEAVE_ERROR_INVALID_USERNAME', 3); 42 | define ('WEAVE_ERROR_NO_OVERWRITE', 4); 43 | define ('WEAVE_ERROR_USERID_PATH_MISMATCH', 5); 44 | define ('WEAVE_ERROR_JSON_PARSE', 6); 45 | define ('WEAVE_ERROR_MISSING_PASSWORD', 7); 46 | define ('WEAVE_ERROR_INVALID_WBO', 8); 47 | define ('WEAVE_ERROR_BAD_PASSWORD_STRENGTH', 9); 48 | define ('WEAVE_ERROR_INVALID_RESET_CODE', 10); 49 | define ('WEAVE_ERROR_FUNCTION_NOT_SUPPORTED', 11); 50 | define ('WEAVE_ERROR_NO_EMAIL', 12); 51 | define ('WEAVE_ERROR_INVALID_COLLECTION', 13); 52 | 53 | 54 | define ('LOG_THE_ERROR', 0); 55 | 56 | function log_error($msg) 57 | { 58 | if ( LOG_THE_ERROR == 1 ) 59 | { 60 | $datei = fopen("/tmp/FSyncMS-error.txt","a"); 61 | $fmsg = sprintf("$msg\n"); 62 | fputs($datei,$fmsg); 63 | fputs($datei,"Server ".print_r( $_SERVER, true)); 64 | fclose($datei); 65 | } 66 | } 67 | 68 | function report_problem($message, $code = 503) 69 | { 70 | $headers = array('400' => '400 Bad Request', 71 | '401' => '401 Unauthorized', 72 | '403' => '403 Forbidden', 73 | '404' => '404 Not Found', 74 | '412' => '412 Precondition Failed', 75 | '503' => '503 Service Unavailable'); 76 | header('HTTP/1.1 ' . $headers{$code},true,$code); 77 | 78 | if ($code == 401) 79 | { 80 | header('WWW-Authenticate: Basic realm="Weave"'); 81 | } 82 | log_error($message); 83 | exit(json_encode($message)); 84 | } 85 | 86 | 87 | function fix_utf8_encoding($string) 88 | { 89 | if(mb_detect_encoding($string . " ", 'UTF-8,ISO-8859-1') == 'UTF-8') 90 | return $string; 91 | else 92 | return utf8_encode($string); 93 | } 94 | 95 | function get_phpinput() 96 | { 97 | #stupid php being helpful with input data... 98 | $putdata = fopen("php://input", "r"); 99 | $string = ''; 100 | while ($data = fread($putdata,2048)) {$string .= $data;} //hier will man ein limit einbauen 101 | return $string; 102 | } 103 | function get_json() 104 | { 105 | $jsonstring = get_phpinput(); 106 | $json = json_decode(fix_utf8_encoding($jsonstring), true); 107 | 108 | if ($json === null) 109 | report_problem(WEAVE_ERROR_JSON_PARSE, 400); 110 | 111 | return $json; 112 | } 113 | 114 | function validate_username($username) 115 | { 116 | if (!$username) 117 | return false; 118 | 119 | if (strlen($username) > 32) 120 | return false; 121 | 122 | return preg_match('/[^A-Z0-9._-]/i', $username) ? false : true; 123 | } 124 | 125 | function validate_collection($collection) 126 | { 127 | if (!$collection) 128 | return false; 129 | 130 | if (strlen($collection) > 32) 131 | return false; 132 | 133 | // allow characters '?' and '=' in the collection string which e.g. 134 | // appear if the following request is send from firefox: 135 | // http:///weave/1.1//storage/clients?full=1 136 | return preg_match('/[^A-Z0-9?=._-]/i', $collection) ? false : true; 137 | } 138 | 139 | #user exitsts 140 | function exists_user( $db) 141 | { 142 | #$user = strtolower($user); 143 | try{ 144 | 145 | if(!$db->exists_user()) 146 | return 0; 147 | return 1; 148 | } 149 | catch(Exception $e) 150 | { 151 | header("X-Weave-Backoff: 1800"); 152 | report_problem($e->getMessage(), $e->getCode()); 153 | } 154 | } 155 | # Gets the username and password out of the http headers, and checks them against the auth 156 | function verify_user($url_user, $db) 157 | { 158 | if (!$url_user || !preg_match('/^[A-Z0-9._-]+$/i', $url_user)) 159 | report_problem(WEAVE_ERROR_INVALID_USERNAME, 400); 160 | 161 | $auth_user = array_key_exists('PHP_AUTH_USER', $_SERVER) ? $_SERVER['PHP_AUTH_USER'] : null; 162 | $auth_pw = array_key_exists('PHP_AUTH_PW', $_SERVER) ? $_SERVER['PHP_AUTH_PW'] : null; 163 | 164 | if (is_null($auth_user) || is_null($auth_pw)) 165 | { 166 | /* CGI/FCGI auth workarounds */ 167 | $auth_str = null; 168 | if (array_key_exists('Authorization', $_SERVER)) 169 | /* Standard fastcgi configuration */ 170 | $auth_str = $_SERVER['Authorization']; 171 | else if (array_key_exists('AUTHORIZATION', $_SERVER)) 172 | /* Alternate fastcgi configuration */ 173 | $auth_str = $_SERVER['AUTHORIZATION']; 174 | else if (array_key_exists('HTTP_AUTHORIZATION', $_SERVER)) 175 | /* IIS/ISAPI and newer (yet to be released) fastcgi */ 176 | $auth_str = $_SERVER['HTTP_AUTHORIZATION']; 177 | else if (array_key_exists('REDIRECT_HTTP_AUTHORIZATION', $_SERVER)) 178 | /* mod_rewrite - per-directory internal redirect */ 179 | $auth_str = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; 180 | if (!is_null($auth_str)) 181 | { 182 | /* Basic base64 auth string */ 183 | if (preg_match('/Basic\s+(.*)$/', $auth_str)) 184 | { 185 | $auth_str = substr($auth_str, 6); 186 | $auth_str = base64_decode($auth_str, true); 187 | if ($auth_str != FALSE) { 188 | $tmp = explode(':', $auth_str); 189 | if (count($tmp) == 2) 190 | { 191 | $auth_user = $tmp[0]; 192 | $auth_pw = $tmp[1]; 193 | } 194 | } 195 | } 196 | } 197 | } 198 | 199 | if ( ! $auth_user || ! $auth_pw) #do this first to avoid the cryptic error message if auth is missing 200 | { 201 | log_error("Auth failed 1 {"); 202 | log_error(" User pw: ". $auth_user ." | ". $auth_pw); 203 | log_error(" Url_user: ". $url_user); 204 | log_error("}"); 205 | report_problem('Authentication failed', '401'); 206 | } 207 | $url_user = strtolower($url_user); 208 | if (strtolower($auth_user) != $url_user) 209 | { 210 | log_error("(140) Missmatch:".strtolower($auth_user)."|".$url_user); 211 | report_problem(WEAVE_ERROR_USERID_PATH_MISMATCH, 400); 212 | } 213 | 214 | try 215 | { 216 | $existingHash = $db->get_password_hash(); 217 | $hash = WeaveHashFactory::factory(); 218 | 219 | if ( ! $hash->verify(fix_utf8_encoding($auth_pw), $existingHash) ) 220 | { 221 | log_error("Auth failed 2 {"); 222 | 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))); 223 | log_error(" Url_user: ".$url_user); 224 | log_error(" Existing hash: ".$existingHash); 225 | log_error("}"); 226 | report_problem('Authentication failed', '401'); 227 | } else { 228 | if ( $hash->needsUpdate($existingHash) ) { 229 | $db->change_password($hash->hash(fix_utf8_encoding($auth_pw))); 230 | } 231 | } 232 | } 233 | catch(Exception $e) 234 | { 235 | header("X-Weave-Backoff: 1800"); 236 | log_error($e->getMessage(), $e->getCode()); 237 | report_problem($e->getMessage(), $e->getCode()); 238 | } 239 | 240 | return true; 241 | } 242 | 243 | function check_quota(&$db) 244 | { 245 | return; 246 | } 247 | 248 | function check_timestamp($collection, &$db) 249 | { 250 | if (array_key_exists('HTTP_X_IF_UNMODIFIED_SINCE', $_SERVER) 251 | && $db->get_max_timestamp($collection) > $_SERVER['HTTP_X_IF_UNMODIFIED_SINCE']) 252 | report_problem(WEAVE_ERROR_NO_OVERWRITE, 412); 253 | } 254 | 255 | function validate_search_params() 256 | { 257 | $params = array(); 258 | $params['parentid'] = (array_key_exists('parentid', $_GET) && mb_strlen($_GET['parentid'], '8bit') <= 64 && strpos($_GET['parentid'], '/') === false) ? $_GET['parentid'] : null; 259 | $params['predecessorid'] = (array_key_exists('predecessorid', $_GET) && mb_strlen($_GET['predecessorid'], '8bit') <= 64 && strpos($_GET['predecessorid'], '/') === false) ? $_GET['predecessorid'] : null; 260 | 261 | $params['newer'] = (array_key_exists('newer', $_GET) && is_numeric($_GET['newer'])) ? round($_GET['newer'],2) : null; 262 | $params['older'] = (array_key_exists('older', $_GET) && is_numeric($_GET['older'])) ? round($_GET['older'],2) : null; 263 | 264 | $params['sort'] = (array_key_exists('sort', $_GET) && ($_GET['sort'] == 'oldest' || $_GET['sort'] == 'newest' || $_GET['sort'] == 'index')) ? $_GET['sort'] : null; 265 | $params['limit'] = (array_key_exists('limit', $_GET) && is_numeric($_GET['limit']) && $_GET['limit'] > 0) ? (int)$_GET['limit'] : null; 266 | $params['offset'] = (array_key_exists('offset', $_GET) && is_numeric($_GET['offset']) && $_GET['offset'] > 0) ? (int)$_GET['offset'] : null; 267 | 268 | $params['ids'] = null; 269 | if (array_key_exists('ids', $_GET)) 270 | { 271 | $params['ids'] = array(); 272 | foreach(explode(',', $_GET['ids']) as $id) 273 | { 274 | if (mb_strlen($id, '8bit') <= 64 && strpos($id, '/') === false) 275 | $params['ids'][] = $id; 276 | } 277 | } 278 | 279 | $params['index_above'] = (array_key_exists('index_above', $_GET) && is_numeric($_GET['index_above']) && $_GET['index_above'] > 0) ? (int)$_GET['index_above'] : null; 280 | $params['index_below'] = (array_key_exists('index_below', $_GET) && is_numeric($_GET['index_below']) && $_GET['index_below'] > 0) ? (int)$_GET['index_below'] : null; 281 | $params['depth'] = (array_key_exists('depth', $_GET) && is_numeric($_GET['depth']) && $_GET['depth'] > 0) ? (int)$_GET['depth'] : null; 282 | 283 | return $params; 284 | } 285 | 286 | ?> 287 | --------------------------------------------------------------------------------