diff options
author | Karl 'vollmerk' Vollmer <vollmer@ampache.org> | 2007-12-18 05:31:54 +0000 |
---|---|---|
committer | Karl 'vollmerk' Vollmer <vollmer@ampache.org> | 2007-12-18 05:31:54 +0000 |
commit | 698f05d14f880eb4ec7866ec3a8416ee4d1f838f (patch) | |
tree | afcfb18b11f13c1ba429612a94432fa0a64aa12c /lib/class | |
parent | 74201cb6158db6448ebf5d8330ace6ad4a139693 (diff) | |
download | ampache-698f05d14f880eb4ec7866ec3a8416ee4d1f838f.tar.gz ampache-698f05d14f880eb4ec7866ec3a8416ee4d1f838f.tar.bz2 ampache-698f05d14f880eb4ec7866ec3a8416ee4d1f838f.zip |
fixed XML-RPC mostly, uses insecure/old authentication method, needs more work
Diffstat (limited to 'lib/class')
-rw-r--r-- | lib/class/catalog.class.php | 124 | ||||
-rw-r--r-- | lib/class/song.class.php | 2 | ||||
-rw-r--r-- | lib/class/xmlrpcserver.class.php | 142 |
3 files changed, 200 insertions, 68 deletions
diff --git a/lib/class/catalog.class.php b/lib/class/catalog.class.php index ce5c3e0d..d0388477 100644 --- a/lib/class/catalog.class.php +++ b/lib/class/catalog.class.php @@ -223,7 +223,7 @@ class Catalog { $path = Dba::escape($data['path']); // Make sure the path is readable/exists - if (!is_readable($data['path'])) { + if (!is_readable($data['path']) AND $data['type'] == 'local') { Error::add('general','Error: ' . scrub_out($data['path']) . ' is not readable or does not exist'); return false; } @@ -271,6 +271,13 @@ class Catalog { */ public function run_add($options) { + if ($this->catalog_type == 'remote') { + show_box_top(_('Running Remote Sync') . '. . .'); + $this->get_remote_catalog($type=0); + show_box_bottom(); + return true; + } + // Catalog Add start $start_time = time(); @@ -1178,8 +1185,9 @@ class Catalog { public function add_to_catalog() { if ($this->catalog_type == 'remote') { - echo _('Running Remote Update') . ". . .<br />"; + show_box_top(_('Running Remote Update') . '. . .'); $this->get_remote_catalog($type=0); + show_box_bottom(); return true; } @@ -1242,14 +1250,10 @@ class Catalog { /** * get_remote_catalog - * get a remote catalog and runs update if needed - * @package XMLRPC - * @catagory Client - * @author Karl Vollmer - * @todo Add support for something besides port 80 - * @todo Add a Pub/Private Key swap in here for extra security + * get a remote catalog and runs update if needed this requires + * the XML RPC stuff and a key to be passed */ - function get_remote_catalog($type=0) { + public function get_remote_catalog($type=0) { /* Make sure the xmlrpc lib is loaded */ if (!class_exists('xmlrpc_client')) { @@ -1273,13 +1277,15 @@ class Catalog { /* encode the variables we need to send over */ $encoded_key = new xmlrpcval($this->key,"string"); - $encoded_path = new xmlrpcval(conf('web_path'),"string"); + $encoded_path = new xmlrpcval(Config::get('web_path'),"string"); - $f = new xmlrpcmsg('remote_catalog_query', array($encoded_key,$encoded_path)); + $xmlrpc_message = new xmlrpcmsg('xmlrpcserver.get_catalogs', array($encoded_key,$encoded_path)); - if (conf('debug')) { $client->setDebug(1); } + // 6 that's right, the secret level because if you do have debug on most likely you're + // going to just crash your browser... sorry folks + if (Config::get('debug') AND Config::get('debug_level') == '6') { $client->setDebug(1); } - $response = $client->send($f,30); + $response = $client->send($xmlrpc_message,30); $value = $response->value(); if ( !$response->faultCode() ) { @@ -1287,8 +1293,8 @@ class Catalog { // Print out the catalogs we are going to sync foreach ($data as $vars) { - $catalog_name = $vars[0]; - $count = $vars[1]; + $catalog_name = $vars['name']; + $count = $vars['count']; print("<b>Reading Remote Catalog: $catalog_name ($count Songs)</b> [$this->path]<br />\n"); $total += $count; } @@ -1298,7 +1304,7 @@ class Catalog { } // if we didn't get an error else { $error_msg = _("Error connecting to") . " " . $server . " " . _("Code") . ": " . $response->faultCode() . " " . _("Reason") . ": " . $response->faultString(); - debug_event('xmlrpc-client',$error_msg,'1','ampache-catalog'); + debug_event('XMLCLIENT',$error_msg,'1'); echo "<p class=\"error\">$error_msg</p>"; return; } @@ -1324,11 +1330,8 @@ class Catalog { * get_remote_song * This functions takes a start and end point for gathering songs from a remote server. It is broken up * in attempt to get around the problem of very large target catalogs - * @package XMLRPC - * @catagory Client - * @todo Allow specificion of single catalog */ - function get_remote_song($client,$start,$end) { + public function get_remote_song($client,$start,$end) { $encoded_start = new xmlrpcval($start,"int"); $encoded_end = new xmlrpcval($end,"int"); @@ -1336,12 +1339,12 @@ class Catalog { $query_array = array($encoded_key,$encoded_start,$encoded_end); - $f = new xmlrpcmsg('remote_song_query',$query_array); + $xmlrpc_message = new xmlrpcmsg('xmlrpcserver.get_songs',$query_array); /* Depending upon the size of the target catalog this can be a very slow/long process */ set_time_limit(0); // Sixty Second time out per chunk - $response = $client->send($f,60); + $response = $client->send($xmlrpc_message,60); $value = $response->value(); if ( !$response->faultCode() ) { @@ -1353,7 +1356,7 @@ class Catalog { } else { $error_msg = _('Error connecting to') . " " . $server . " " . _("Code") . ": " . $response->faultCode() . " " . _("Reason") . ": " . $response->faultString(); - debug_event('xmlrpc-client',$error_msg,'1','ampache-catalog'); + debug_event('XMLCLIENT',$error_msg,'1'); echo "<p class=\"error\">$error_msg</p>"; } @@ -1370,37 +1373,26 @@ class Catalog { * @todo This should be based off of seralize * @todo some kind of cleanup of dead songs? */ - function update_remote_catalog($songs,$root_path) { + function update_remote_catalog($data,$root_path) { /* We need to check the incomming songs to see which ones need to be added */ - foreach ($songs as $song) { + foreach ($data as $serialized_song) { // Prevent a timeout set_time_limit(0); - $song = base64_decode($song); - - $data = explode("::", $song); - - $new_song->artist = self::check_artist($data[0]); - $new_song->album = self::check_album($data[1],$data[4]); - $new_song->title = $data[2]; - $new_song->year = $data[4]; - $new_song->bitrate = $data[5]; - $new_song->rate = $data[6]; - $new_song->mode = $data[7]; - $new_song->size = $data[8]; - $new_song->time = $data[9]; - $new_song->track = $data[10]; - $new_song->genre = self::check_genre($data[11]); - $new_song->file = $root_path . "/play/index.php?song=" . $data[12]; - $new_song->catalog = $this->id; + $song = unserialize($serialized_song); + $song->artist = self::check_artist($song->artist); + $song->album = self::check_album($song->album,$song->year); + $song->genre = self::check_genre($song->genre); + $song->file = $root_path . "/play/index.php?song=" . $data[12]; + $song->catalog = $this->id; - if (!$this->check_remote_song($new_song->file)) { - $this->insert_remote_song($new_song); + if (!$this->check_remote_song($song->file)) { + $this->insert_remote_song($song); } } // foreach new Songs @@ -2113,22 +2105,22 @@ class Catalog { } // insert_local_song - /*! - @function insert_remote_song - @discussion takes the information gotten from XML-RPC and - inserts it into the local database. The filename - ends up being the url. - */ - function insert_remote_song($song) { + /** + * insert_remote_song + * takes the information gotten from XML-RPC and + * inserts it into the local database. The filename + * ends up being the url. + */ + public function insert_remote_song($song) { - $url = sql_escape($song->file); + $url = Dba::escape($song->file); $title = self::check_title($song->title); - $title = sql_escape($title); + $title = Dba::escape($title); $current_time = time(); $sql = "INSERT INTO song (file,catalog,album,artist,title,bitrate,rate,mode,size,time,track,genre,addition_time,year)" . " VALUES ('$url','$song->catalog','$song->album','$song->artist','$title','$song->bitrate','$song->rate','$song->mode','$song->size','$song->time','$song->track','$song->genre','$current_time','$song->year')"; - $db_results = mysql_query($sql, dbh()); + $db_results = Dba::query($sql); if (!$db_results) { debug_event('insert',"Unable to Add Remote $url -- $sql",'5','ampache-catalog'); @@ -2138,20 +2130,19 @@ class Catalog { } // insert_remote_song - /*! - @function check_remote_song - @discussion checks to see if a remote song exists in the database or not - if it find a song it returns the UID - */ - function check_remote_song($url) { + /** + * check_remote_song + * checks to see if a remote song exists in the database or not + * if it find a song it returns the UID + */ + public function check_remote_song($url) { - $url = sql_escape($url); + $url = Dba::escape($url); - $sql = "SELECT id FROM song WHERE file='$url'"; - - $db_results = mysql_query($sql, dbh()); + $sql = "SELECT `id` FROM `song` WHERE `file`='$url'"; + $db_results = Dba::query($sql); - if (mysql_num_rows($db_results)) { + if (Dba::num_rows($db_results)) { return true; } @@ -2159,12 +2150,11 @@ class Catalog { } // check_remote_song - /** * check_local_mp3 * Checks the song to see if it's there already returns true if found, false if not */ - function check_local_mp3($full_file, $gather_type='') { + public function check_local_mp3($full_file, $gather_type='') { if ($gather_type == 'fast_add') { $file_date = filemtime($full_file); diff --git a/lib/class/song.class.php b/lib/class/song.class.php index 4aa773fd..61ee2b93 100644 --- a/lib/class/song.class.php +++ b/lib/class/song.class.php @@ -659,7 +659,7 @@ class Song { * and does a ton of formating on it creating f_??? variables on the current * object */ - function format() { + public function format() { $this->fill_ext_info(); diff --git a/lib/class/xmlrpcserver.class.php b/lib/class/xmlrpcserver.class.php new file mode 100644 index 00000000..97f0208b --- /dev/null +++ b/lib/class/xmlrpcserver.class.php @@ -0,0 +1,142 @@ +<?php +/* + + Copyright (c) 2001 - 2007 Ampache.org + All rights reserved. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License v2 + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +/** + * xmlRpcServer + * This class contains all the methods that the /server/xmlrpc.server.php will respond to + * to add a new method, just define a new public static function in here and it will be automagicaly + * populated to xmlrpcserver.<FUNCTION> in /server/xmlrpc.server.php + */ + +class xmlRpcServer { + + /** + * get_catalogs + * This returns a list of the current non-remote catalogs hosted on this Ampache instance + * It requires a key be passed as the first element + * //FIXME: USE TOKEN! + */ + public static function get_catalogs($xmlrpc_object) { + + // Pull out the key + $variable = $xmlrpc_object->getParam(0); + $key = $variable->scalarval(); + + // Check it and make sure we're super green + if (!Access::check_network('rpc',$_SERVER['REMOTE_ADDR'],'','5',$key)) { + debug_event('XMLSERVER','Error ' . $_SERVER['REMOTE_ADDR'] . ' with key ' . $key . ' does not match any ACLs','1'); + return new xmlrpcresp(0,'503','Key/IP Mis-match Access Denied'); + } + + // Go ahead and gather up the information they are legit + $results = array(); + + $sql = "SELECT `catalog`.`name`,COUNT(`song`.`id`) AS `count`,`catalog`.`id` AS `catalog_id` FROM `catalog` ". + "LEFT JOIN `song` ON `catalog`.`id`=`song`.`catalog` WHERE `catalog`.`catalog_type`='local' " . + "GROUP BY `catalog`.`id`"; + $db_results = Dba::query($sql); + + while ($row = Dba::fetch_assoc($db_results)) { + $results[] = $row; + } + + // We need to set time limit at this point as who know how long this data is going to take + // to return to the client + set_time_limit(0); + + $encoded_array = php_xmlrpc_encode($results); + debug_event('XMLSERVER','Returning data about ' . count($results) . ' catalogs to ' . $_SERVER['REMOTE_ADDR'],'5'); + + return new xmlrpcresp($encoded_array); + + } // get_catalogs + + /** + * get_songs + * This is a basic function to return all of the song data in a serialized format. It takes a start and end point + * as well as the TOKEN for auth mojo + * //FIXME: USE TOKEN! + */ + public static function get_songs($xmlrpc_object) { + + // We're going to be here a while + set_time_limit(0); + + // Pull out the key + $variable = $xmlrpc_object->getParam(0); + $key = $variable->scalarval(); + + // Check it and make sure we're super green + if (!Access::check_network('rpc',$_SERVER['REMOTE_ADDR'],'','5',$key)) { + debug_event('XMLSERVER','Error ' . $_SERVER['REMOTE_ADDR'] . ' with key ' . $key . ' does not match any ACLs','1'); + return new xmlrpcresp(0,'503','Key/IP Mis-match Access Denied'); + } + + // Now pull out the start and end + $start = intval($xmlrpc_object->params['1']->me['int']); + $end = intval($xmlrpc_object->params['2']->me['int']); + + // Get Catalogs first + $sql = "SELECT `catalog`.`id` FROM `catalog` WHERE `catalog`.`catalog_type`='local'"; + $db_results = Dba::query($sql); + + while ($row = Dba::fetch_assoc($db_results)) { + $where_sql .= "`song`.`catalog`='" . $row['id'] . "' OR"; + } + + $where_sql = rtrim($where_sql,'OR'); + + $sql = "SELECT `song`.`id` FROM `song` WHERE `song`.`enabled`='1' AND ($where_sql) LIMIT $start,$end"; + $db_results = Dba::query($sql); + + while ($row = Dba::fetch_assoc($db_results)) { + $song = new Song($row['id']); + $song->fill_ext_info(); + $song->album = $song->get_album_name(); + $song->artist = $song->get_artist_name(); + $song->genre = $song->get_genre_name(); + + $output = serialize($song); + $results[] = $output; + } // end while + + $encoded_array = php_xmlrpc_encode($results); + debug_event('XMLSERVER','Encoded ' . count($results) . ' songs (' . $start . ',' . $end . ')','5'); + + return new xmlrpcresp($encoded_array); + + } // get_songs + + /** + * handshake + * This should be run before any other XMLRPC actions, it checks the KEY encoded with a timestamp then returns a valid TOKEN to be + * used in all further communication + */ + public static function handshake($xmlrpc_object) { + + // Pull out the params + $encoded_key = $xmlrpc_object->params['0']->me['string']; + $timestamp = $xmlrpc_object->params['0']->me['int']; + + } // handshake + +} // xmlRpcServer +?> |