First shot at getting a session management system in place. Login and logout pages are there, and auth seems to be working and sufficiently secure for the moment. Sessions last indefinitely and are cookie-based.
authorDan
Mon, 01 Sep 2008 16:51:13 -0400
changeset 44 92dd253f501c
parent 43 2634d550a97b
child 45 7978f037eab3
First shot at getting a session management system in place. Login and logout pages are there, and auth seems to be working and sufficiently secure for the moment. Sessions last indefinitely and are cookie-based.
ajax.php
greyhound.php
playlist.php
sessions.php
themes/funkymonkey/images/greylogo.png
themes/funkymonkey/images/login.png
themes/funkymonkey/images/src/login.xcf
themes/funkymonkey/login.css
themes/funkymonkey/login.tpl
themes/funkymonkey/playlist.tpl
themes/grey/images/ajax.gif
themes/grey/images/greylogo.png
themes/grey/images/login.png
themes/grey/images/src/login.xcf
themes/grey/login.css
themes/grey/login.tpl
themes/grey/playlist.tpl
themes/iphone/images/greylogo.png
themes/iphone/images/login.png
themes/iphone/images/src/login.xcf
themes/iphone/login.css
themes/iphone/login.tpl
themes/iphone/playlist.tpl
--- a/ajax.php	Mon Sep 01 16:50:03 2008 -0400
+++ b/ajax.php	Mon Sep 01 16:51:13 2008 -0400
@@ -39,27 +39,8 @@
   global $playlist, $mime_types, $json, $allowcontrol;
   global $use_auth, $auth_data;
   
-  if ( $use_auth )
-  {
-    if ( !isset($_SERVER['PHP_AUTH_USER']) )
-    {
-      $httpd->header('WWW-Authenticate: basic');
-      $httpd->send_http_error($socket, 401, "A username and password are required to access this resource. Either you did not specify a username and password, or the supplied credentials were incorrect.");
-      return true;
-    }
-    if ( !isset($auth_data[$_SERVER['PHP_AUTH_USER']]) )
-    {
-      $httpd->header('WWW-Authenticate: basic');
-      $httpd->send_http_error($socket, 401, "A username and password are required to access this resource. Either you did not specify a username and password, or the supplied credentials were incorrect.");
-      return true;
-    }
-    else if ( $_SERVER['PHP_AUTH_PW'] !== $auth_data[$_SERVER['PHP_AUTH_USER']] )
-    {
-      $httpd->header('WWW-Authenticate: basic');
-      $httpd->send_http_error($socket, 401, "A username and password are required to access this resource. Either you did not specify a username and password, or the supplied credentials were incorrect.");
-      return true;
-    }
-  }
+  if ( !session_check() )
+    return true;
   
   // Set content type
   $httpd->header("Content-type: {$mime_types['js']}");
--- a/greyhound.php	Mon Sep 01 16:50:03 2008 -0400
+++ b/greyhound.php	Mon Sep 01 16:51:13 2008 -0400
@@ -12,6 +12,8 @@
  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
  */
 
+define('GREY_VERSION', '0.1a4');
+
 // Try to trap termination signals to cleanly close the socket when needed
 // AmaroK sends a SIGTERM when it is shut down or the user requests to stop
 // the script
@@ -37,15 +39,13 @@
 // set this to false, it will only display the playlist.
 $allowcontrol = true;
 // The default theme. This should be a name of a directory in ./themes.
-$theme = 'grey';
+$theme = 'funkymonkey';
 // Allow forking when an HTTP request is received. This has advantages
 // and disadvantages. If this experimental option is enabled, it will
 // result in faster responses and load times but more memory usage.
 $allow_fork = true;
 // set to true to enable authentication
-// WARNING: THIS HAS SOME SERIOUS SECURITY PROBLEMS RIGHT NOW. I don't
-// know what's causing it to not prompt for authentication from any
-// client after the first successful auth.
+// this uses cookies, so make sure they're enabled in your browser
 $use_auth = false;
 // valid users and passwords
 $auth_data = array(
@@ -69,7 +69,7 @@
 
 // start up...
 
-status('Starting Greyhound Web Control v0.1a3');
+status('Starting Greyhound Web Control v' . GREY_VERSION);
 status('loading files');
 
 require('webserver.php');
@@ -79,6 +79,7 @@
 require(GREY_ROOT . '/json.php');
 require(GREY_ROOT . '/ajax.php');
 require(GREY_ROOT . '/imagetools.php');
+require(GREY_ROOT . '/sessions.php');
 
 // signal handler
 function sigterm($signal)
@@ -102,6 +103,11 @@
   burnout('SimpleXML required to continue. You may have an outdated version of PHP; most versions of PHP 5 have SimpleXML built-in. Check your distribution\'s documentation to find out how to enable PHP\'s SimpleXML support.');
 }
 
+if ( !function_exists('imagepng') || !function_exists('imagecopyresampled') || !function_exists('imagecreatefromjpeg') || !function_exists('imagecreatefromwbmp') )
+{
+  warning('Can\'t find support for GD 2.0. Artwork will not be displayed. Look around in your distro\'s package manager for php-gd or php5-gd.');
+}
+
 status('initializing playlist');
 
 // init playlist object
@@ -121,6 +127,8 @@
   // setup handlers
   status('initializing handlers');
   $httpd->add_handler('index',                'function', 'amarok_playlist');
+  $httpd->add_handler('login',                'function', 'greyhound_login_page');
+  $httpd->add_handler('logout',               'function', 'greyhound_logout');
   $httpd->add_handler('action.json',          'function', 'ajax_request_handler');
   $httpd->add_handler('artwork',              'function', 'artwork_request_handler');
   $httpd->add_handler('scripts',              'dir',      GREY_ROOT . '/scripts');
--- a/playlist.php	Mon Sep 01 16:50:03 2008 -0400
+++ b/playlist.php	Mon Sep 01 16:51:13 2008 -0400
@@ -16,28 +16,14 @@
 function amarok_playlist($httpd, $socket)
 {
   global $theme, $playlist, $allowcontrol;
-  global $use_auth, $auth_data;
+  global $use_auth;
   
-  if ( $use_auth )
+  if ( !session_check() )
   {
-    if ( !isset($_SERVER['PHP_AUTH_USER']) )
-    {
-      $httpd->header('WWW-Authenticate: basic');
-      $httpd->send_http_error($socket, 401, "A username and password are required to access this resource. Either you did not specify a username and password, or the supplied credentials were incorrect.");
-      return true;
-    }
-    if ( !isset($auth_data[$_SERVER['PHP_AUTH_USER']]) )
-    {
-      $httpd->header('WWW-Authenticate: basic');
-      $httpd->send_http_error($socket, 401, "A username and password are required to access this resource. Either you did not specify a username and password, or the supplied credentials were incorrect.");
-      return true;
-    }
-    else if ( $auth_data[$_SERVER['PHP_AUTH_USER']] !== $_SERVER['PHP_AUTH_PW'] )
-    {
-      $httpd->header('WWW-Authenticate: basic');
-      $httpd->send_http_error($socket, 401, "A username and password are required to access this resource. Either you did not specify a username and password, or the supplied credentials were incorrect.");
-      return true;
-    }
+    $httpd->header('HTTP/1.1 307 Temporary Redirect');
+    $httpd->header('Location: /login');
+    
+    return;
   }
   
   $iphone = ( ( strpos($_SERVER['HTTP_USER_AGENT'], 'iPhone') ||
@@ -61,6 +47,8 @@
       'position.js'
     ));
   $smarty->assign('allow_control', $allowcontrol);
+  $smarty->assign('use_auth', $use_auth);
+  $smarty->assign('greyhound_version', GREY_VERSION);
   $smarty->register_function('sprite', 'smarty_function_sprite');
   $smarty->display('playlist.tpl');
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sessions.php	Mon Sep 01 16:51:13 2008 -0400
@@ -0,0 +1,177 @@
+<?php
+
+/**
+ * Greyhound - real web management for Amarok
+ * Copyright (C) 2008 Dan Fuhry
+ *
+ * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
+ *
+ * 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 details.
+ */
+
+function greyhound_login_page($httpd, $socket)
+{
+  if ( session_check() )
+  {
+    $httpd->header('HTTP/1.1 307 Temporary Redirect');
+    $httpd->header('Location: /');
+    
+    return;
+  }
+  $tried = false;
+  $success = false;
+  if ( isset($_POST['username']) && isset($_POST['password']) )
+  {
+    $tried = true;
+    if ( $sessionid = login($_POST['username'], $_POST['password']) )
+    {
+      $success = true;
+      $httpd->setcookie('grey_session', $sessionid, time() + ( 86400 * 3650 ));
+    }
+  }
+  
+  global $theme;
+  $iphone = ( ( strpos($_SERVER['HTTP_USER_AGENT'], 'iPhone') ||
+       strpos($_SERVER['HTTP_USER_AGENT'], 'iPod') ||
+       strpos($_SERVER['HTTP_USER_AGENT'], 'BlackBerry') ||
+       isset($_GET['m']) )
+       && !isset($_GET['f'])
+       );
+  $theme_id = ( $iphone ) ? 'iphone' : $theme;
+  $smarty = load_theme($theme_id);
+  
+  $smarty->assign('theme', $theme_id);
+  $smarty->assign('greyhound_version', GREY_VERSION);
+  $smarty->assign('tried', $tried);
+  $smarty->assign('success', $success);
+  $smarty->display('login.tpl');
+}
+
+function greyhound_logout($httpd, $socket)
+{
+  // destroy the session
+  if ( isset($_COOKIE['grey_session']) )
+  {
+    load_session_data();
+    global $session_data;
+    unset($session_data[$_COOKIE['grey_session']]);
+    session_commit_db();
+  }
+  
+  $httpd->setcookie('grey_session', '', time() - 864000);
+  $httpd->header('HTTP/1.1 307 Temporary Redirect');
+  $httpd->header('Location: /');
+}
+
+/**
+ * Check to see if we're logged in
+ */
+
+function session_check()
+{
+  global $use_auth, $auth_data;
+  if ( isset($_COOKIE['grey_session']) )
+  {
+    load_session_data();
+    global $session_data;
+    if ( isset($session_data[$_COOKIE['grey_session']]) )
+    {
+      // has a cookie with a valid session ID, check credentials
+      $session =& $session_data[$_COOKIE['grey_session']];
+      if ( isset($auth_data[$session['user']]) )
+      {
+        if ( $session['hash'] === md5($auth_data[$session['user']] . $session['salt']) )
+        {
+          // session is valid, logged in
+          return true;
+        }
+      }
+    }
+  }
+  return ( $use_auth ) ? false : true;
+}
+
+function login($username, $password)
+{
+  global $use_auth, $auth_data;
+  if ( !$use_auth )
+    return false;
+  
+  if ( isset($auth_data[$username]) )
+  {
+    if ( $auth_data[$username] === $password )
+    {
+      return create_session($username, $password);
+    }
+  }
+  return false;
+}
+
+function create_session($username, $password)
+{
+  load_session_data();
+  global $session_data;
+  
+  $sessid = md5(sha1(microtime() . mt_rand()));
+  $salt = md5(sha1(md5(mt_rand() . microtime() . microtime() . mt_rand())));
+  
+  $session_data[$sessid] = array(
+      'user' => $username,
+      'hash' => md5($password . $salt),
+      'salt' => $salt
+    );
+  session_commit_db();
+  
+  return $sessid;
+}
+
+function var_export_string($arr)
+{
+  ob_start();
+  var_export($arr);
+  $r = ob_get_contents();
+  ob_end_clean();
+  return $r;
+}
+
+function session_commit_db()
+{
+  global $session_data;
+  $d = var_export_string($session_data);
+  $fp = @fopen('./session_db.php', 'w');
+  if ( !$fp )
+  {
+    warning('Could not open the session database for writing. Logins may not work.');
+    return false;
+  }
+  $d = <<<EOF
+<?php
+
+// Automatically generated session database for Greyhound. Do not edit this file!
+
+\$GLOBALS['session_data'] = $d;
+EOF;
+  
+  fwrite($fp, $d);
+  fclose($fp);
+  
+  return true;
+}
+
+function load_session_data()
+{
+  if ( file_exists('./session_db.php') )
+  {
+    require('./session_db.php');
+  }
+  else
+  {
+    $GLOBALS['session_data'] = array();
+  }
+}
+
+$session_data = array();
+
+?>
Binary file themes/funkymonkey/images/greylogo.png has changed
Binary file themes/funkymonkey/images/login.png has changed
Binary file themes/funkymonkey/images/src/login.xcf has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/themes/funkymonkey/login.css	Mon Sep 01 16:51:13 2008 -0400
@@ -0,0 +1,85 @@
+/**
+ * Based upon the AmaroK WebControl interface by:
+ *    Jonas Christian Drewsen ( kde at xspect dot dk )
+ *    André Kelpe ( fs111 at web dot de )
+ *    Peter C. Ndikuwera ( pndiku at gmail dot com )
+ */
+
+html, body {
+  margin: 0;
+  padding: 0;
+  height: 100%;
+}
+
+body {
+  font-family: sans-serif;
+  background-color: #212251;
+  color: #ffffff;
+  padding: 0;
+}
+
+body > table {
+  width: 100%;
+  height: 100%;
+}
+
+div.login-main {
+  background-image: url(images/login.png);
+  width: 340px;
+  height: 220px;
+  margin: 0 auto;
+  padding: 40px;
+  background-position: center center;
+  background-repeat: no-repeat;
+}
+
+table.loginform {
+  margin: 0 auto;
+}
+
+table.loginform td {
+  padding-top: 20px;
+}
+
+table.loginform td.left {
+  width: 33%;
+  text-align: left;
+}
+
+table.loginform td.right {
+  width: 66%;
+  text-align: left;
+}
+
+table.loginform td.error, table.loginform td.success {
+  text-align: center;
+  color: #ff5321;
+  padding-top: 2px;
+}
+
+table.loginform td.success {
+  color: #53ff21;
+}
+
+table.loginform td.submit {
+  font-size: larger;
+  padding-top: 12px;
+}
+
+input {
+  border-width: 0px;
+  background-color: #b1b5cd;
+  padding: 2px;
+  color: #383f61;
+}
+
+input.submit {
+  font-size: larger;
+  padding: 2px 5px;
+}
+
+input.submit:hover, input.submit:focus {
+  background-color: #b1b5cd;
+  cursor: pointer;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/themes/funkymonkey/login.tpl	Mon Sep 01 16:51:13 2008 -0400
@@ -0,0 +1,65 @@
+{**
+ * Template file for default Grey theme
+ * Greyhound: Web control interface script for Amarok
+ * Written by Dan Fuhry - (C) 2008
+ *}
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html>
+  <head>
+    <title>Greyhound: Login</title>
+    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
+    <link rel="stylesheet" type="text/css" href="/themes/{$theme|escape}/login.css" />
+    <link rel="favorite icon" type="image/ico" href="/favicon.ico" />
+    {if $success}
+    <meta http-equiv="refresh" content="0; url=/" />
+    {/if}
+  </head>
+  <body>
+    <table border="0" cellspacing="0" cellpadding="0">
+      <tr>
+        <td valign="middle" style="text-align: center;">
+          <!-- this is all centered on the screen now -->
+          <div class="login-main">
+            <img class="greylogo" src="/themes/{$theme|escape}/images/greylogo.png" />
+            <form action="/login" method="post">
+              <table border="0" class="loginform">
+                <tr>
+                  <td class="left">username:</td><td class="right"><input type="text" name="username" tabindex="1" autocomplete="off" /></td>
+                </tr>
+                <tr>
+                  <td class="left password">password:</td><td class="right"><input type="password" name="password" tabindex="2" /></td>
+                </tr>
+                {if $tried and !$success}
+                <tr>
+                  <td class="error" colspan="2">
+                    login failed
+                  </td>
+                </tr>
+                {elseif $tried and $success}
+                <tr>
+                  <td class="success" colspan="2">
+                    you're all good, redirecting...
+                  </td>
+                </tr>
+                {else}
+                <tr>
+                  <td class="error" colspan="2">
+                    &nbsp;
+                  </td>
+                </tr>
+                {/if}
+                <tr>
+                  <td colspan="2" class="submit">
+                    <input class="submit" type="submit" value="log in" tabindex="3" />
+                  </td>
+                </tr>
+              </table>
+            </form>
+          </div>
+        </td>
+      </tr>
+    </table>
+  </body>
+</html>
+
--- a/themes/funkymonkey/playlist.tpl	Mon Sep 01 16:50:03 2008 -0400
+++ b/themes/funkymonkey/playlist.tpl	Mon Sep 01 16:51:13 2008 -0400
@@ -85,7 +85,11 @@
       </table>
     </div>
     <div class="poweredby">
-      Powered by <a onclick="window.open(this.href); return false;" href="http://greyhound.enanocms.org/">Greyhound</a>
+      Powered by <a onclick="window.open(this.href); return false;" href="http://greyhound.enanocms.org/">Greyhound</a> v{$greyhound_version}
+      {if $use_auth}
+      &ndash;
+      <a href="/logout">log out</a>
+      {/if}
     </div>
   </body>
 </html>
Binary file themes/grey/images/ajax.gif has changed
Binary file themes/grey/images/greylogo.png has changed
Binary file themes/grey/images/login.png has changed
Binary file themes/grey/images/src/login.xcf has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/themes/grey/login.css	Mon Sep 01 16:51:13 2008 -0400
@@ -0,0 +1,85 @@
+/**
+ * Based upon the AmaroK WebControl interface by:
+ *    Jonas Christian Drewsen ( kde at xspect dot dk )
+ *    André Kelpe ( fs111 at web dot de )
+ *    Peter C. Ndikuwera ( pndiku at gmail dot com )
+ */
+
+html, body {
+  margin: 0;
+  padding: 0;
+  height: 100%;
+}
+
+body {
+  font-family: sans-serif;
+  background-color: #262626;
+  color: #ffffff;
+  padding: 0;
+}
+
+body > table {
+  width: 100%;
+  height: 100%;
+}
+
+div.login-main {
+  background-image: url(images/login.png);
+  width: 340px;
+  height: 220px;
+  margin: 0 auto;
+  padding: 40px;
+  background-position: center center;
+  background-repeat: no-repeat;
+}
+
+table.loginform {
+  margin: 0 auto;
+}
+
+table.loginform td {
+  padding-top: 20px;
+}
+
+table.loginform td.left {
+  width: 33%;
+  text-align: left;
+}
+
+table.loginform td.right {
+  width: 66%;
+  text-align: left;
+}
+
+table.loginform td.error, table.loginform td.success {
+  text-align: center;
+  color: #ff5321;
+  padding-top: 2px;
+}
+
+table.loginform td.success {
+  color: #53ff21;
+}
+
+table.loginform td.submit {
+  font-size: larger;
+  padding-top: 12px;
+}
+
+input {
+  border-width: 0px;
+  background-color: #272727;
+  padding: 2px;
+  color: #a8a8a8;
+}
+
+input.submit {
+  font-size: larger;
+  padding: 2px 5px;
+}
+
+input.submit:hover, input.submit:focus {
+  background-color: #323232;
+  cursor: pointer;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/themes/grey/login.tpl	Mon Sep 01 16:51:13 2008 -0400
@@ -0,0 +1,65 @@
+{**
+ * Template file for default Grey theme
+ * Greyhound: Web control interface script for Amarok
+ * Written by Dan Fuhry - (C) 2008
+ *}
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html>
+  <head>
+    <title>Greyhound: Login</title>
+    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
+    <link rel="stylesheet" type="text/css" href="/themes/{$theme|escape}/login.css" />
+    <link rel="favorite icon" type="image/ico" href="/favicon.ico" />
+    {if $success}
+    <meta http-equiv="refresh" content="0; url=/" />
+    {/if}
+  </head>
+  <body>
+    <table border="0" cellspacing="0" cellpadding="0">
+      <tr>
+        <td valign="middle" style="text-align: center;">
+          <!-- this is all centered on the screen now -->
+          <div class="login-main">
+            <img class="greylogo" src="/themes/{$theme|escape}/images/greylogo.png" />
+            <form action="/login" method="post">
+              <table border="0" class="loginform">
+                <tr>
+                  <td class="left">username:</td><td class="right"><input type="text" name="username" tabindex="1" autocomplete="off" /></td>
+                </tr>
+                <tr>
+                  <td class="left password">password:</td><td class="right"><input type="password" name="password" tabindex="2" /></td>
+                </tr>
+                {if $tried and !$success}
+                <tr>
+                  <td class="error" colspan="2">
+                    login failed
+                  </td>
+                </tr>
+                {elseif $tried and $success}
+                <tr>
+                  <td class="success" colspan="2">
+                    you're all good, redirecting...
+                  </td>
+                </tr>
+                {else}
+                <tr>
+                  <td class="error" colspan="2">
+                    &nbsp;
+                  </td>
+                </tr>
+                {/if}
+                <tr>
+                  <td colspan="2" class="submit">
+                    <input class="submit" type="submit" value="log in" tabindex="3" />
+                  </td>
+                </tr>
+              </table>
+            </form>
+          </div>
+        </td>
+      </tr>
+    </table>
+  </body>
+</html>
+
--- a/themes/grey/playlist.tpl	Mon Sep 01 16:50:03 2008 -0400
+++ b/themes/grey/playlist.tpl	Mon Sep 01 16:51:13 2008 -0400
@@ -85,7 +85,11 @@
       </table>
     </div>
     <div class="poweredby">
-      Powered by <a onclick="window.open(this.href); return false;" href="http://greyhound.enanocms.org/">Greyhound</a>
+      Powered by <a onclick="window.open(this.href); return false;" href="http://greyhound.enanocms.org/">Greyhound</a> v{$greyhound_version}
+      {if $use_auth}
+      &ndash;
+      <a href="/logout">log out</a>
+      {/if}
     </div>
   </body>
 </html>
Binary file themes/iphone/images/greylogo.png has changed
Binary file themes/iphone/images/login.png has changed
Binary file themes/iphone/images/src/login.xcf has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/themes/iphone/login.css	Mon Sep 01 16:51:13 2008 -0400
@@ -0,0 +1,91 @@
+/**
+ * Based upon the AmaroK WebControl interface by:
+ *    Jonas Christian Drewsen ( kde at xspect dot dk )
+ *    André Kelpe ( fs111 at web dot de )
+ *    Peter C. Ndikuwera ( pndiku at gmail dot com )
+ */
+
+html, body {
+  margin: 0;
+  padding: 0;
+  height: 100%;
+  font-size: 120%;
+}
+
+body {
+  font-family: sans-serif;
+  background-color: #212251;
+  color: #ffffff;
+  padding: 0;
+}
+
+body > table {
+  width: 100%;
+  height: 100%;
+}
+
+div.login-main {
+  background-image: url(images/login.png);
+  width: 240px;
+  height: 276px;
+  margin: 0 auto;
+  padding: 40px;
+  background-position: center center;
+  background-repeat: no-repeat;
+}
+
+table.loginform {
+  margin: 0 auto;
+}
+
+table.loginform td {
+  padding-top: 20px;
+}
+
+table.loginform td.left {
+  width: 33%;
+  text-align: left;
+}
+
+table.loginform td.right {
+  width: 66%;
+  text-align: left;
+}
+
+table.loginform td.error, table.loginform td.success {
+  text-align: center;
+  color: #ff5321;
+  padding-top: 2px;
+}
+
+table.loginform td.success {
+  color: #53ff21;
+}
+
+table.loginform td.submit {
+  font-size: larger;
+  padding-top: 12px;
+}
+
+input {
+  border-width: 0px;
+  background-color: #b1b5cd;
+  padding: 2px;
+  color: #383f61;
+  width: 120px;
+  height: 28px;
+  font-size: 23px;
+}
+
+input.submit {
+  font-size: larger;
+  padding: 2px 5px;
+  height: 36px;
+  font-size: 24px;
+}
+
+input.submit:hover, input.submit:focus {
+  background-color: #b1b5cd;
+  cursor: pointer;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/themes/iphone/login.tpl	Mon Sep 01 16:51:13 2008 -0400
@@ -0,0 +1,69 @@
+{**
+ * Template file for default Funky Monkey theme
+ * Web control interface script for Amarok
+ * Written by Dan Fuhry - 2008
+ *
+ * This script is in the public domain. Use it for good, not evil.
+ *}
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html>
+  <head>
+    <title>AmaroK playlist</title>
+    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
+    <!-- iPhone viewport hack from jailbreakme.com -->
+    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
+    <link rel="stylesheet" type="text/css" href="/themes/{$theme|escape}/login.css" />
+    <link rel="favorite icon" type="image/ico" href="/favicon.ico" />
+    {if $success}
+    <meta http-equiv="refresh" content="0; url=/" />
+    {/if}
+  </head>
+  <body>
+    <table border="0" cellspacing="0" cellpadding="0">
+      <tr>
+        <td valign="middle" style="text-align: center;">
+          <!-- this is all centered on the screen now -->
+          <div class="login-main">
+            <img class="greylogo" src="/themes/{$theme|escape}/images/greylogo.png" />
+            <form action="/login" method="post">
+              <table border="0" class="loginform">
+                <tr>
+                  <td class="left">username:</td><td class="right"><input type="text" name="username" tabindex="1" autocomplete="off" /></td>
+                </tr>
+                <tr>
+                  <td class="left password">password:</td><td class="right"><input type="password" name="password" tabindex="2" /></td>
+                </tr>
+                {if $tried and !$success}
+                <tr>
+                  <td class="error" colspan="2">
+                    login failed
+                  </td>
+                </tr>
+                {elseif $tried and $success}
+                <tr>
+                  <td class="success" colspan="2">
+                    you're all good, redirecting...
+                  </td>
+                </tr>
+                {else}
+                <tr>
+                  <td class="error" colspan="2">
+                    &nbsp;
+                  </td>
+                </tr>
+                {/if}
+                <tr>
+                  <td colspan="2" class="submit">
+                    <input class="submit" type="submit" value="log in" tabindex="3" />
+                  </td>
+                </tr>
+              </table>
+            </form>
+          </div>
+        </td>
+      </tr>
+    </table>
+  </body>
+</html>
+
--- a/themes/iphone/playlist.tpl	Mon Sep 01 16:50:03 2008 -0400
+++ b/themes/iphone/playlist.tpl	Mon Sep 01 16:51:13 2008 -0400
@@ -67,7 +67,7 @@
           <th>Track</th>
         </tr>
         {foreach key=tid item=track from=$playlist}
-        {* strip *}
+        {strip}
         <tr class="{cycle values="row1,row2"}{if $active == $tid} current{/if}" id="track_{$tid}" amarok:length_sec="{$track.length_int}">
           <td>
             <a class="tracklink" href="#action:jump;tid:{$tid}" onclick="expand_track({$tid}); return false;">
@@ -86,14 +86,18 @@
             </div>
           </td>
         </tr>
-        {* /strip *}
+        {/strip}
         {/foreach}
       </table>
     </div>
     <div id="footer">
       <img alt="AmaroK web control" src="/themes/{$theme|escape}/images/amarok.gif" /><br />
       <div class="poweredby">
-        Powered by <a onclick="window.open(this.href); return false;" href="http://greyhound.enanocms.org/">Greyhound</a>
+        Powered by <a onclick="window.open(this.href); return false;" href="http://greyhound.enanocms.org/">Greyhound</a> v{$greyhound_version}
+        {if $use_auth}
+        &ndash;
+        <a href="/logout">log out</a>
+        {/if}
       </div>
     </div>
     <script type="text/javascript">