<?php

/* By Grant Burton @ BURTONTECH.COM (11-30-2008): IP-Proxy-Cluster Fix */
function checkIP($ip) {
   if (!empty($ip) && ip2long($ip)!=-1 && ip2long($ip)!=false) {
       $private_ips = array (
       array('0.0.0.0','2.255.255.255'),
       array('10.0.0.0','10.255.255.255'),
       array('127.0.0.0','127.255.255.255'),
       array('169.254.0.0','169.254.255.255'),
       array('172.16.0.0','172.31.255.255'),
       array('192.0.2.0','192.0.2.255'),
       array('192.168.0.0','192.168.255.255'),
       array('255.255.255.0','255.255.255.255')
       );

       foreach ($private_ips as $r) {
           $min = ip2long($r[0]);
           $max = ip2long($r[1]);
           if ((ip2long($ip) >= $min) && (ip2long($ip) <= $max)) return false;
       }
       return true;
   } else { 
       return false;
   }
}

function determineIP() {
   if (checkIP($_SERVER["HTTP_CLIENT_IP"])) {
       return $_SERVER["HTTP_CLIENT_IP"];
   }
   foreach (explode(",",$_SERVER["HTTP_X_FORWARDED_FOR"]) as $ip) {
       if (checkIP(trim($ip))) {
           return $ip;
       }
   }
   if (checkIP($_SERVER["HTTP_X_FORWARDED"])) {
       return $_SERVER["HTTP_X_FORWARDED"];
   } elseif (checkIP($_SERVER["HTTP_X_CLUSTER_CLIENT_IP"])) {
       return $_SERVER["HTTP_X_CLUSTER_CLIENT_IP"];
   } elseif (checkIP($_SERVER["HTTP_FORWARDED_FOR"])) {
       return $_SERVER["HTTP_FORWARDED_FOR"];
   } elseif (checkIP($_SERVER["HTTP_FORWARDED"])) {
       return $_SERVER["HTTP_FORWARDED"];
   } else {
       return $_SERVER["REMOTE_ADDR"];
   }
}


// -------------------------------------------------------------------------------------------------
class ListopiaAuth extends ListopiaCore
{
  // -----------------------------------------------------------------------------------------------
  public function authAttemptLogin($authUser, $authPass)
  {
    $result = array();
    
    $escapedUser = $this->ldb->escape_string($authUser);
    $escapedPass = $this->ldb->escape_string($authPass);
    
    $query = $this->ldb->select(array(
                        'table' => 'users',
                        'condition' => 'user_name="'.$escapedUser.'"',
                        'limit' => 1
                        ));  

    // no such username
    if (empty($query[0])) 
    {
      $result["success"] = false;
      $result["reason"] = "Username not found";
      return $result;
    }
    
    // wrong pwd
    $userPassword = $query[0]['users']['user_password'];
    if ($escapedPass != $userPassword)
    {
      $result["success"] = false;
      $result["reason"] = "Incorrect password";
      return $result;    
    }
    
    // check the user_privilege > 1
    if ($query[0]['users']['user_privilege'] == 1)
    {
      $result["success"] = false;
      $result["reason"] = LS_USER_NOT_ACTIVATED;
      return $result;    
    }
    if ($query[0]['users']['user_privilege'] == 0)
    {
      $result["success"] = false;
      $result["reason"] = LS_USER_BANNED;
      return $result;    
    }
    
    FB::log("[Listopia] Auth successful");
    
    // weclome aboard
    $result["success"] = true;
    
    // store the authentication cookie
    $cookieExpire = time() + 2592000;
    SetCookieLive(__LAUTH_KEY__, hash('ripemd160', $userPassword), $cookieExpire);
    SetCookieLive(__LAUTH_USER__, $authUser, $cookieExpire);
    
    // get the session data punched in too
    $this->configureSessionFromAuth();
    
    return $result;
  }
  
  // -----------------------------------------------------------------------------------------------
  public function authLogoff()
  {
    UnSetCookie(__LAUTH_KEY__);
    UnSetCookie(__LAUTH_USER__);
    Session::getInstance()->destroy();
  }
  
  // -----------------------------------------------------------------------------------------------
  protected function configureSessionFromAuth()
  {
    if (isset($_COOKIE[__LAUTH_KEY__]))
    {
      $query = $this->ldb->select(array(
                          'fields' => 'users.*',
                          'table' => 'users',
                          'condition' => 'user_name="'.$_COOKIE[__LAUTH_USER__].'"',
                          'limit' => 1
                          ));
      
      if (empty($query[0]) || 
          hash('ripemd160', $query[0]['users']['user_password']) != $_COOKIE[__LAUTH_KEY__])
      {
        FB::error("[Listopia] session - existing cookie doesnt match db / auth");

        Session::getInstance()->destroy();
        return;
      }
      
      // check if we got banned since last login
      if ($query[0]['users']['user_privilege'] <= 1)
      {
        Session::getInstance()->destroy();
        return;
      }
      
      FB::info("[Listopia] session - set from auth cookie");
      
      $sesh = Session::getInstance();
      $sesh->gl_loggedin    = "apparently";
      $sesh->gl_userid      = $query[0]['users']['user_id'];
      $sesh->gl_username    = $query[0]['users']['user_name'];
      $sesh->gl_status      = $query[0]['users']['user_status'];
      $sesh->gl_privilege   = $query[0]['users']['user_privilege'];
      $sesh->gl_last_login  = $query[0]['users']['user_last_login'];
      $sesh->gl_unix_last_login  = strtotime($sesh->gl_last_login);
      FB::info("[Listopia] session - last_login stored as ".date($sesh->gl_unix_last_login));
      
      // update the login time when we refresh the session 
      $newLastLogin = date("Y-m-d H:i:s", time()); 
      $data = array(
        'user_last_login' => $newLastLogin
      );
      $this->ldb->update('users', $data, "user_id = ".$sesh->gl_userid);
      FB::info("[Listopia] session - last_login refreshed in DB to ".$newLastLogin);
    }
    else
    {
      Session::getInstance()->destroy();
    }
  }
  
  // -----------------------------------------------------------------------------------------------
  public function setupSession()
  {
    $sesh = Session::getInstance();
    
    // session not setup? go see if we can set it up from the auth cookie
    if (isset($sesh->gl_loggedin) == false)
    {
      FB::info("[Listopia] may create new session");
      $this->configureSessionFromAuth();
    }
  }
 
  
  // -----------------------------------------------------------------------------------------------
  public function authUsernameCheck($username)
  {
    $escapedUser = $this->ldb->escape_string($username);
    $query = $this->ldb->select(array(
                        'table' => 'users',
                        'condition' => 'user_name="'.$escapedUser.'"',
                        'limit' => 1
                        ));
                        
    if (empty($query[0])) 
    {
      $result = array();
      $result['success'] = true;
      return $result;
    }
    else
    {
      $suggestions = array(
        "Cock",
        "Buns",
        "Flap",
        "Chin",
        "Bug",
        "Hand",
        "Tits",
        "Flange",
        "Nuff",
        "Chuffer",
        "Wank",
        "Spaniel",
        "Tank",
        "Bulk",
        "Shaft",
        "Quim",
        "Pork",
        "Slab",
        "Guts",
        "Slut",
        "Norks",
        "Pump"
      );
      
      $userNameSuggestion = $suggestions[mt_rand(0, count($suggestions)-1)];
      $userNameSuggestion .= $suggestions[mt_rand(0, count($suggestions)-1)];
      $userNameSuggestion .= mt_rand(1, 9);

      $result = array();
      $result['failed'] = "That username is already taken";
      $result['instead'] = $userNameSuggestion;
      return $result;
    }
  }



  // -----------------------------------------------------------------------------------------------
  public function authAttemptToCreateNewUser($username, $pwd, $email)
  {
    $escapedUser = $this->ldb->escape_string($username);
    $escapedEmail = $this->ldb->escape_string($email);

    $result = array();
    
    if (strlen($username) <= 3)
    {
      $result['result'] = "username too short";
      return $result;
    }
    if (strlen($pwd) <= 1)
    {
      $result['result'] = "password too ludicrously short";
      return $result;
    }
    
    // check the user name is free
    $userCheck = $this->authUsernameCheck($username);
    if (isset($userCheck['failed']))
    {
      $result['result'] = $userCheck['failed'];
      return $result;
    }
    
    // check email format
    if(!preg_match("/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$/i", $email)) 
    {
      $result['result'] = "couldn't validate that email";
      return $result;
    }
    
    $query = $this->ldb->select(array(
                        'table' => 'users',
                        'condition' => 'user_email="'.$escapedEmail.'"',
                        'limit' => 1
                        ));
    if (!empty($query[0]))
    {
      $result['result'] = "email already in use";
      return $result;
    }
    /*
    if (hash('whirlpool', $captcha) !== $_COOKIE[__LAUTH_CAPT__])
    {
      $result['result'] = "captcha code incorrect";
      return $result;
    }
    */
    $validation_code = substr(hash('whirlpool', $username), 0, 10);
    $server_path = str_replace("\\", "/", $_SERVER['SERVER_NAME'] . dirname(dirname($_SERVER['SCRIPT_NAME'])));
    
    $date = date("Y-m-d H:i:s", time());

    $data = array(
      'user_name'         => $username,
      'user_password'     => $pwd,
      'user_status'           => 'member',
      'user_privilege'        => array(4),
      'user_allow_email'      =>  'no',
      'user_allow_admin_email'  =>  'no',
      'user_validation_code'    => $validation_code,
      'user_created'      => $date,
      'user_last_login'   => $date
    );
    $insertResult = $this->ldb->insert('users', $data);

    {
      $subject = "Listopia sign-up";
      $contents = <<<MSG
Hello there. You recently signed up at www.listopia.co.uk. Come try and login why not - your username is '$username' and password is '$pwd'.
Thanks for reading this email. We don't think it's inappropriate at this stage to say we love you.
MSG;
      $from_header = "From: noreply@listopia.co.uk";
      if(!mail($email, $subject, $contents, $from_header))
      {
        $result['result'] = "failed to send email";
        return $result;
      }
    }
    
    $result['success'] = true;
    return $result;
  }


  // -----------------------------------------------------------------------------------------------
  public function isLoggedIn()
  {
    return (isset(Session::getInstance()->gl_loggedin));
  }
  
  // -----------------------------------------------------------------------------------------------
  public function isUserOnProbation()
  {
    return (Session::getInstance()->gl_status == 'probation');
  }
  
  // -----------------------------------------------------------------------------------------------
  public function isAdminUser()
  {
    $sesh = Session::getInstance();
    if ($sesh->gl_userid == 101)
      return true;
    return (isset($sesh->gl_privilege) && $sesh->gl_privilege >= 8);
  }  

  // -----------------------------------------------------------------------------------------------
  public function isBannedUser($userID)
  {
    $query = $this->ldb->select(array(
                        'table' => 'users',
                        'condition' => 'user_id='.((int)$userID),
                        'limit' => 1
                        ));
    if (!empty($query[0]))
    {
      if ($query[0]['users']['user_privilege'] == 0)
      {
        return true;
      }
    }
    
    return false;
  }  
  
  // -----------------------------------------------------------------------------------------------
  public function echoUserName()
  {
    $sesh = Session::getInstance();
    if (isset($sesh->gl_loggedin))
    {
      echo $sesh->gl_username;
    }
    else
    {
      FB::error("[Listopia] echoUserName - not logged in");
      echo "Unknown";
    }
  }  
}