summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKarl 'vollmerk' Vollmer <vollmer@ampache.org>2007-12-20 07:31:00 +0000
committerKarl 'vollmerk' Vollmer <vollmer@ampache.org>2007-12-20 07:31:00 +0000
commit897b35aeddd117409af95b270ec8309c2a564aaa (patch)
tree1becb256242920d81b1872a58f5b2b880045e664
parent9661434379a94791031604a4a5094f5631351457 (diff)
downloadampache-897b35aeddd117409af95b270ec8309c2a564aaa.tar.gz
ampache-897b35aeddd117409af95b270ec8309c2a564aaa.tar.bz2
ampache-897b35aeddd117409af95b270ec8309c2a564aaa.zip
fixed issues with user edit and create, fixed seek errors (Thx Karl Hungus) started digging myself out of the session tarded hole I created, API is broken with this commit
-rwxr-xr-xdocs/CHANGELOG4
-rw-r--r--lib/class/api.class.php2
-rw-r--r--lib/class/stream.class.php4
-rw-r--r--lib/class/vauth.class.php352
-rw-r--r--lib/class/xmlrpcserver.class.php28
-rw-r--r--play/index.php32
-rw-r--r--templates/show_add_user.inc.php2
-rw-r--r--templates/show_edit_user.inc.php14
-rw-r--r--themes/greysme/templates/default.css2
9 files changed, 418 insertions, 22 deletions
diff --git a/docs/CHANGELOG b/docs/CHANGELOG
index 6029e406..623e39fd 100755
--- a/docs/CHANGELOG
+++ b/docs/CHANGELOG
@@ -4,6 +4,10 @@
--------------------------------------------------------------------------
v.3.4-Alpha4
+ - Fixed some issues with downsampling + seeking and seeking in
+ general (Thx Karl Hungus)
+ - Fixed CSS references to missing files
+ - Fixed Missing Levels on Edit and incorrect level on edit
- Added check to make sure timestamp passed to API is less then
four hours old. Set to four hours to allow for some
difference in server/client time
diff --git a/lib/class/api.class.php b/lib/class/api.class.php
index a580bfbe..6a1707ab 100644
--- a/lib/class/api.class.php
+++ b/lib/class/api.class.php
@@ -72,7 +72,7 @@ class Api {
// Run the query and return the passphrases as we'll have to mangle them
// to figure out if they match what we've got
- $sql = "SELECT * FROM `access_list` WHERE `user`='$user_id' AND `start` <= '$ip' AND `end` >= '$ip'";
+ $sql = "SELECT * FROM `access_list` WHERE `type`='rpc' AND `user`='$user_id' AND `start` <= '$ip' AND `end` >= '$ip'";
$db_results = Dba::query($sql);
while ($row = Dba::fetch_assoc($db_results)) {
diff --git a/lib/class/stream.class.php b/lib/class/stream.class.php
index 507cee02..9c1ad1e8 100644
--- a/lib/class/stream.class.php
+++ b/lib/class/stream.class.php
@@ -521,7 +521,7 @@ class Stream {
* opened file handled a reference to the song object is passed so that the changes we make
* in here affect the external object, References++
*/
- public static function start_downsample(&$song,$now_playing_id=0,$song_name=0) {
+ public static function start_downsample(&$song,$now_playing_id=0,$song_name=0,$start=0) {
/* Check to see if bitrates are set if so let's go ahead and optomize! */
$max_bitrate = Config::get('max_bit_rate');
@@ -591,7 +591,7 @@ class Stream {
$song->size = floor($sample_ratio*$song->size);
/* Get Offset */
- $offset = ( $start*$song->time )/( $sample_ratio*$song->size );
+ $offset = ( $start*$song->time )/( $song->size );
$offsetmm = floor($offset/60);
$offsetss = floor($offset-$offsetmm*60);
$offset = sprintf("%02d.%02d",$offsetmm,$offsetss);
diff --git a/lib/class/vauth.class.php b/lib/class/vauth.class.php
new file mode 100644
index 00000000..d0f68e7e
--- /dev/null
+++ b/lib/class/vauth.class.php
@@ -0,0 +1,352 @@
+<?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.
+
+*/
+/**
+ * Vauth
+ * This class handles all of the session related stuff in Ampache
+ * it takes over for the vauth libs, and takes some stuff out of other
+ * classes where it didn't belong
+*/
+class vauth {
+
+ /* Variables from DB */
+
+
+ /**
+ * Constructor
+ * This should never be called
+ */
+ private function __construct() {
+
+ // Rien a faire
+
+ } // __construct
+
+ /**
+ * open
+ * This function is for opening a new session so we just verify that we have
+ * a database connection, nothing more is needed
+ */
+ public static function open($save_path,$session_name) {
+
+ if (!is_resource(Dba::dbh())) {
+ debug_event('SESSION','Error no database connection session failed','1');
+ return false;
+ }
+
+ return true;
+
+ } // open
+
+ /**
+ * close
+ * This is run on the end of a sessoin, nothing to do here for now
+ */
+ public static function close() {
+
+ return true;
+
+ } // close
+
+ /**
+ * read
+ * This takes a key and then looks in the database and returns the value
+ */
+ public static function read($key) {
+
+ $results = self::get_session_data($key);
+ if (strlen($results['value']) < 1) {
+ debug_event('SESSION','Error unable to read session from key ' . $key . ' no data found','1');
+ return '';
+ }
+
+ return $results['value'];
+
+ } // read
+
+ /**
+ * write
+ * This saves the sessoin information into the database
+ */
+ public static function write($key,$value) {
+
+
+ $length = Config::get('session_length');
+ $value = Dba::escape($value);
+ $key = Dba::escape($key);
+ // Check to see if remember me cookie is set, if so use remember length, otherwise use the session length
+ $expire = isset($_COOKIE[Config::get('session_name') . '_remember']) ? time() + Config::get('remember_length') : time() + Config::get('session_length');
+
+ $sql = "UPDATE `session` SET `value`='$value', `expire`='$expire' WHERE `id`='$key'";
+ $db_results = Dba::query($sql);
+
+ return $db_results;
+
+ } // write
+
+ /**
+ * destroy
+ * This removes the specified sessoin from the database
+ */
+ public static function destroy($key) {
+
+ $key = Dba::escape($key);
+
+ // Remove anything and EVERYTHING
+ $sql = "DELETE FROM `session` WHERE `id`='$key'";
+ $db_results = Dba::query($sql);
+
+ // Destory our cookie!
+ setcookie(Config::get('session_name'),'',time() - 86400);
+
+ return true;
+
+ } // destroy
+
+ /**
+ * gc
+ * This function is randomly called and it cleans up the poo
+ */
+ public static function gc($maxlifetime) {
+
+ $sql = "DELETE FROM `session` WHERE `expire` < '" . time() . "'";
+ $db_results = Dba::query($sql);
+
+ return true;
+
+ } // gc
+
+ /**
+ * logout
+ * This is called when you want to log out and nuke your session
+ * //FIXME: move all logout logic here
+ */
+ public static function logout($key) {
+
+ self::destroy($key);
+ return true;
+
+ } // logout
+
+ /**
+ * get_session_data
+ * This takes a key and returns the raw data from the database, nothing to
+ * see here move along people
+ */
+ public static function get_session_data($key) {
+
+ $key = Dba::escape($key);
+
+ $sql = "SELECT * FROM `session` WHERE `id`='$key' AND `expire` > '" . time() . "'";
+ $db_results = Dba::query($sql);
+
+ $results = Dba::fetch_assoc($db_results);
+
+ if (!count($results)) {
+ return false;
+ }
+
+ return $results;
+
+ } // get_session_data
+
+ /**
+ * create_cookie
+ * This is seperated into it's own function because of some flaws in specific
+ * webservers *cough* IIS *cough* which prevent us from setting a cookie at the
+ * same time as a header redirect. As such on view of a login a cookie is set with
+ * the proper name
+ */
+ public static function create_cookie() {
+
+ /* Setup the cookie prefs before we throw down, this is very important */
+ $cookie_life = Config::get('cookie_life');
+ $cookie_path = Config::get('cookie_path');
+ $cookie_domain = false;
+ $cookie_secure = Config::get('cookie_secure');
+
+ session_set_cookie_params($cookie_life,$cookie_path,$cookie_domain,$cookie_secure);
+
+ /* Start the session */
+ self::ungimp_ie();
+ session_start();
+
+ } // create_cookie, just watch out for the cookie monster
+
+ /**
+ * session_create
+ * This is called when you want to create a new session
+ * it takes care of setting the initial cookie, and inserting the first chunk of
+ * data, nifty ain't it!
+ */
+ public static function session_create($data) {
+
+ // Regenerate the session ID to prevent fixation
+ session_regenerate_id();
+
+ // Create our cookie!
+ self::create_cookie();
+
+ // Before refresh we don't have the cookie so we have to use session ID
+ $key = session_id();
+
+ $username = Dba::escape($data['username']);
+ $ip = Dba::escape(ip2int($_SERVER['REMOTE_ADDR']));
+ $type = Dba::escape($data['type']);
+ $value = Dba::escape($data['value']);
+ $agent = Dba::escape($_SERVER['HTTP_USER_AGENT']);
+ $expire = Dba::escape(time() + vauth_conf('session_length'));
+
+ /* We can't have null things here people */
+ if (!strlen($value)) { $value = ' '; }
+
+ /* Insert the row */
+ $sql = "INSERT INTO `session` (`id`,`username`,`ip`,`type`,`agent`,`value`,`expire`) " .
+ " VALUES ('$key','$username','$ip','$type','$agent','$value','$expire')";
+ $db_results = Dba::query($sql);
+
+ if (!$db_results) {
+ debug_event('SESSION',"Session Creation Failed with Query: $sql and " . Dba::error(),'1');
+ }
+
+ return $db_results;
+
+ } // session_create
+
+ /**
+ * check_session
+ * This checks for an existing sessoin and if it's still valid then go ahead and start it and return
+ * true
+ */
+ public static function check_session() {
+
+ // No cookie n go!
+ if (!isset($_COOKIE[Config::get('session_name')]) { return false; }
+
+ $key = scrub_in($_COOKIE[Config::get('session_name')]);
+ $data = self::get_session_data($key);
+
+ if (!is_array($results)) {
+ return false;
+ }
+
+ // Check for a remember me
+ if (isset($_COOKIE[Config::get('session_name') . '_remember'])) {
+ Config::set('cookie_life',Config::get('remember_length'),'1');
+ setcookie(Config::get('session_name') . '_remember',time() + Config::get('remember_length'),'/',Config::get('cookie_domain'));
+ }
+
+ // Setup the cookie params before we start the session this is vital
+ session_set_cookie_params(
+ Config::get('cookie_life'),
+ Config::get('cookie_path'),
+ Config::get('cookie_domain'),
+ Config::get('cookie_secure'));
+
+ // Set name
+ session_name(Config::get('session_name'));
+
+ // Ungimp IE and go
+ self::ungimp_io();
+ session_start();
+
+ return true;
+
+ } // check_session
+
+ /**
+ * session_exists
+ * This checks to see if the specified session of the specified type
+ * exists, it also provides an array of key'd data that may be required
+ * based on the type
+ */
+ public static function session_exists($data,$key,$type) {
+
+ // Switch on the type they pass
+ switch ($type) {
+ case 'xml-rpc':
+ case 'interface':
+ case 'api':
+ $key = Dba::escape($key);
+ $time = time();
+ $sql = "SELECT * FROM `session` WHERE `id`='$key' AND `expire` > '$time' AND `type`='$type'";
+ $db_results = Dba::query($sql);
+
+ if (Dba::num_rows($db_results)) {
+ return true;
+ }
+ break;
+ case 'stream':
+ $key = Dba::escape($key);
+ $ip = ip2int($data['ip']);
+ $agent = Dba::escape($data['agent']);
+ $sql = "SELECT * FROM `session_stream` WHERE `id`='$key' AND `expire` > '$time' AND `ip`='$ip' AND `agent`='$agent'";
+ $db_results = Dba::query($sql);
+
+ if (Dba::num_rows($db_results)) {
+ return true;
+ }
+
+ break;
+ default:
+ return false;
+ break;
+ } // type
+
+ // Default to false
+ return false;
+
+ } // session_exists
+
+ /**
+ * _auto_init
+ * This function is called when the object is included, this sets up the session_save_handler
+ */
+ public static function _auto_init() {
+
+ session_set_save_handler('vauth::open','vauth::close','vauth::read','vauth::write','vauth::destroy','vauth::gc');
+
+ } // auto init
+
+ /**
+ * ungimp_ie
+ * This function sets the cache limiting to public if you are running
+ * some flavor of IE. The detection used here is very conservative so feel free
+ * to fix it. This only has to be done if we're rolling HTTPS
+ */
+ public static function ungimp_ie() {
+
+ // If no https, no ungimpage required
+ if ($_SERVER['HTTPS'] != 'on') { return true; }
+
+ // Try to detect IE
+ $agent = trim($_SERVER['HTTP_USER_AGENT']);
+
+ if ((preg_match('|MSIE ([0-9).]+)|',$agent)) || preg_match('|Internet Explorer/([0-9.]+)|',$agent))) {
+ session_cache_limiter('public');
+ }
+
+ return true;
+
+ } // ungimp_ie
+
+} // end of vauth class
+
+?>
diff --git a/lib/class/xmlrpcserver.class.php b/lib/class/xmlrpcserver.class.php
index 97f0208b..abb8076e 100644
--- a/lib/class/xmlrpcserver.class.php
+++ b/lib/class/xmlrpcserver.class.php
@@ -136,6 +136,34 @@ class xmlRpcServer {
$encoded_key = $xmlrpc_object->params['0']->me['string'];
$timestamp = $xmlrpc_object->params['0']->me['int'];
+ // Check the timestamp make sure it's recent
+ if ($timestamp < (time() - 14400)) {
+ debug_event('XMLSERVER','Handshake failure, timestamp too old','1');
+ return new xmlrpcresp(php_xmlrpc_encoded("Handshake failure"));
+ }
+
+ // Log the attempt
+ debug_event('XMLSERVER','Login Attempt, IP: ' . $_SERVER['REMOTE_ADDR'] . ' Time: ' . $timestamp . ' Hash:' . $encoded_key,'5');
+
+ // Convert the IP Address to an int
+ $ip = ip2int($_SERVER['REMOTE_ADDR']);
+
+ // Run the query and return the key's for ACLs of type RPC that would match this IP
+ $sql = "SELECT * FROM `access_list` WHERE `type`='rpc' AND `start` <= '$ip' AND `end` >= '$ip'";
+ $db_results = Dba::query($sql);
+
+ while ($row = Dba::fetch_assoc($db_results)) {
+
+ // Build our encoded passphrase
+ $md5pass = md5($timestamp . $row['key']);
+
+ if ($md5pass == $encoded_key) {
+ $token = '';
+ }
+
+ } // end while rows
+
+
} // handshake
} // xmlRpcServer
diff --git a/play/index.php b/play/index.php
index 64d83e86..0a378be0 100644
--- a/play/index.php
+++ b/play/index.php
@@ -228,8 +228,8 @@ if ($_GET['action'] == 'download' AND $GLOBALS['user']->prefs['download']) {
} // if they are trying to download and they can
-$startArray = sscanf( $_SERVER[ "HTTP_RANGE" ], "bytes=%d-" );
-$start = $startArray[0];
+// Parse byte range request
+$n = sscanf($_SERVER['HTTP_RANGE'], "bytes=%d-%d",$start,$end);
// Generate browser class for sending headers
$browser = new Browser();
@@ -253,7 +253,7 @@ if (Config::get('access_control') AND Config::get('downsample_remote')) {
// If they are downsampling, or if the song is not a native stream or it's non-local
if (($GLOBALS['user']->prefs['transcode'] == 'always' || !$song->native_stream() || $not_local) && $GLOBALS['user']->prefs['transcode'] != 'never') {
debug_event('downsample','Starting Downsample...','5');
- $fp = Stream::start_downsample($song,$lastid,$song_name);
+ $fp = Stream::start_downsample($song,$lastid,$song_name,$start);
$song_name = $song->f_artist_full . " - " . $song->title . "." . $song->type;
} // end if downsampling
else {
@@ -276,7 +276,16 @@ if ($start) {
$range = $start ."-". ($song->size-1) . "/" . $song->size;
header("HTTP/1.1 206 Partial Content");
header("Content-Range: bytes=$range");
- header("Content-Length: ".($song->size-$start));
+
+ // Calculate stream size from byte range
+ if(isset($end)) {
+ $end = min($end,$song->size-1);
+ $stream_size = ($end-$start)+1;
+ }
+ else {
+ $stream_size = $song->size - $start;
+ }
+ header("Content-Length: ".($stream_size));
}
/* Last but not least pump em out */
@@ -284,24 +293,25 @@ else {
debug_event('stream','Starting stream of ' . $song->file . ' with size ' . $song->size,'5');
header("Content-Length: $song->size");
$browser->downloadHeaders($song_name, $song->mime, false, $song->size);
+ $stream_size = $song->size;
}
/* Let's force them to actually play a portion of the song before
* we count it in the statistics
*/
-$bytesStreamed = 0;
-$minBytesStreamed = $song->size / 2;
+$bytes_streamed = 0;
+$min_bytes_streamed = $song->size / 2;
// Actually do the streaming
do {
$buf = fread($fp, 2048);
print($buf);
- $bytesStreamed += 2048;
-} while (!feof($fp) && (connection_status() == 0));
+ $bytes_streamed += 2048;
+} while (!feof($fp) && (connection_status() == 0) AND $bytes_streamed < $stream_size);
// Make sure that a good chunk of the song has been played
-if ($bytesStreamed > $minBytesStreamed) {
+if ($bytes_streamed > $min_bytes_streamed) {
debug_event('Stats','Registering stats for ' . $song->title,'5');
$user->update_stats($song->id);
@@ -319,7 +329,7 @@ if ($bytesStreamed > $minBytesStreamed) {
} // if enough bytes are streamed
else {
- debug_event('stream',$bytesStreamed .' of ' . $song->size . ' streamed, less than ' . $minBytesStreamed . ' not collecting stats','5');
+ debug_event('stream',$bytes_streamed .' of ' . $song->size . ' streamed, less than ' . $min_bytes_streamed . ' not collecting stats','5');
}
@@ -332,6 +342,6 @@ else {
}
// Note that the stream has ended
-debug_event('stream','Stream Ended at ' . $bytesStreamed . ' bytes out of ' . $song->size,'5');
+debug_event('stream','Stream Ended at ' . $bytes_streamed . ' bytes out of ' . $song->size,'5');
?>
diff --git a/templates/show_add_user.inc.php b/templates/show_add_user.inc.php
index af0800cf..0b3adcd3 100644
--- a/templates/show_add_user.inc.php
+++ b/templates/show_add_user.inc.php
@@ -69,7 +69,7 @@
<?php echo _('User Access Level'); ?>:
</td>
<td>
- <?php $var_name = "on_" . $working_user->access; ${$var_name} = 'selected="selected"'; ?>
+ <?php $var_name = "on_" . $client->access; ${$var_name} = 'selected="selected"'; ?>
<select name="access">
<option value="5" <?php echo $on_5; ?>><?php echo _('Guest'); ?></option>
<option value="25" <?php echo $on_25; ?>><?php echo _('User'); ?></option>
diff --git a/templates/show_edit_user.inc.php b/templates/show_edit_user.inc.php
index 45dcb890..7b119736 100644
--- a/templates/show_edit_user.inc.php
+++ b/templates/show_edit_user.inc.php
@@ -69,12 +69,14 @@
<?php echo _('User Access Level'); ?>:
</td>
<td>
- <?php $var_name = "on_" . $client->access; ${$var_name} = 'selected="selected"'; ?>
- <select name="access">
- <option value="5" <?php echo $on_5; ?>><?php echo _('Guest'); ?></option>
- <option value="25" <?php echo $on_25; ?>><?php echo _('User'); ?></option>
- <option value="100" <?php echo $on_100; ?>><?php echo _('Admin'); ?></option>
- </select>
+ <?php $var_name = "on_" . $client->access; ${$var_name} = 'selected="selected"'; ?>
+ <select name="access">
+ <option value="5" <?php echo $on_5; ?>><?php echo _('Guest'); ?></option>
+ <option value="25" <?php echo $on_25; ?>><?php echo _('User'); ?></option>
+ <option value="50" <?php echo $on_50; ?>><?php echo _('Content Manager'); ?></option>
+ <option value="75" <?php echo $on_75; ?>><?php echo _('Catalog Manager'); ?></option>
+ <option value="100" <?php echo $on_100; ?>><?php echo _('Admin'); ?></option>
+ </select>
</td>
</tr>
</table>
diff --git a/themes/greysme/templates/default.css b/themes/greysme/templates/default.css
index 3e01a519..e6354e70 100644
--- a/themes/greysme/templates/default.css
+++ b/themes/greysme/templates/default.css
@@ -468,7 +468,7 @@ input[type=checkbox] { border:0;background:none; }
.box a:hover, .info-box a:hover { /*background-color: #8b3e38;*/ color: #e9ad51;}
.box-inside {
- background: url(../images/right.gif) top right repeat-y;
+/* background: url(../images/right.gif) top right repeat-y; */
}
.box-content {
padding:12px 12px;