Page 1 of 1

API not working after an upgrade

Posted: Tue Jul 02, 2019 10:02 pm
by jrmr
Hello,
I upgraded some software on my Ubuntu 18.04 server, and then tried logging into Zoneminder 1.32 afterwards, and I managed to break something that appears to be related to the API, and am unable to login without editing /etc/zm/zm.conf and adding line:

Code: Select all

ZM_OPT_USE_AUTH=1
I've tried stumbling through the forums, but I think I'm just making things worse. Would someone be able to point me in the right direction?

http://ip/zm/api/ displays:

Notice (8): Constant ZM_OPT_USE_AUTH already defined [/usr/share/zoneminder/www/includes/config.php, line 173]
define - [internal], line ??
loadConfig - /usr/share/zoneminder/www/includes/config.php, line 173
require_once - /usr/share/zoneminder/www/includes/config.php, line 140
include - APP/Config/bootstrap.php, line 123
Configure::bootstrap() - CORE/Cake/Core/Configure.php, line 98
include - CORE/Cake/bootstrap.php, line 442
[main] - APP/webroot/index.php, line 90

Warning (2): ini_set() [<a href='http://php.net/function.ini-set'>function.ini-set</a>]: Headers already sent. You cannot change the session module's ini settings at this time [CORE/Cake/Model/Datasource/CakeSession.php, line 581]
ini_set - [internal], line ??
CakeSession::_configureSession() - CORE/Cake/Model/Datasource/CakeSession.php, line 581
CakeSession::_cookieName() - CORE/Cake/Model/Datasource/CakeSession.php, line 619
CakeSession::_hasSession() - CORE/Cake/Model/Datasource/CakeSession.php, line 632
CakeSession::read() - CORE/Cake/Model/Datasource/CakeSession.php, line 404
SessionComponent::read() - CORE/Cake/Controller/Component/SessionComponent.php, line 69
AppController::beforeFilter() - APP/Controller/AppController.php, line 70
CakeEventManager::dispatch() - CORE/Cake/Event/CakeEventManager.php, line 243
Controller::startupProcess() - CORE/Cake/Controller/Controller.php, line 677
Dispatcher::_invoke() - CORE/Cake/Routing/Dispatcher.php, line 189
Dispatcher::dispatch() - CORE/Cake/Routing/Dispatcher.php, line 167
[main] - APP/webroot/index.php, line 107

Re: API not working after an upgrade

Posted: Wed Jul 03, 2019 6:35 pm
by AfricanSwallow
Might need more info. Did you not have authentication set before the upgrade? If so, it should've remained set. If not, is there a reason you chose to set it up (i think its a good idea, just curious - especially if you're using api). Are there more to the logs than the lines you've pruned? They dont state much, though first thing to come to mind is "Headers already sent. You cannot change the session module's ini settings at this time"

are you doing a simple GET from a browser, or using POSTMAN or another tool? If so, are you passing the credentials since you've enabled them? If through a browser, are you logged into the main (read non-api) web interface first? You should do so and open api call in another tab in the same NON-PRIVATE!! browsing session.

Lastly, have you cleared your cache and browser history to ensure you aren't sending stale headers?

Thanks,
AfricanSwallow

Re: API not working after an upgrade

Posted: Thu Jul 25, 2019 5:15 am
by jrmr
Hello AfricanSwallow,
Thank you for the response. I am sorry not see your response sooner. I apologize I am ignorant with some of the terms and processes you are throwing out there, but I'll try to answer to the best of my abilities.
AfricanSwallow wrote: Wed Jul 03, 2019 6:35 pm Might need more info. Did you not have authentication set before the upgrade? If so, it should've remained set. If not, is there a reason you chose to set it up (i think its a good idea, just curious - especially if you're using api).
I did have authentication set before the upgrade. I setup Zoneminder based on the installation guide for Ubuntu 18.04. I added Plex to the server, and somehow broke ZM authentication in the process. Maybe I was trying to get too cute. Everything worked prior to the Plex installation including remote access via my phone.
AfricanSwallow wrote: Wed Jul 03, 2019 6:35 pm Are there more to the logs than the lines you've pruned? They dont state much, though first thing to come to mind is "Headers already sent. You cannot change the session module's ini settings at this time"
I can add additional logs. That was just the web output from the test they have you do at the end of the installation guide.

Code: Select all

nano /var/log/apache2/error.log

[Wed Jul 24 00:08:53.311431 2019] [mpm_prefork:notice] [pid 2851] AH00163: Apache/2.4.29 (Ubuntu) configured -- resuming normal operations
[Wed Jul 24 00:08:53.311479 2019] [core:notice] [pid 2851] AH00094: Command line: '/usr/sbin/apache2'
[Wed Jul 24 20:58:25.139425 2019] [php7:notice] [pid 8119] [client ip:port] PHP Notice:  Constant ZM_OPT_USE_AUTH already defined in /usr/share/zoneminder/www/includes/config.php on line 173
[Wed Jul 24 20:58:25.151373 2019] [php7:warn] [pid 8119] [client ip:port] PHP Warning:  session_start(): open(/var/lib/php/sessions/sess_6frak9imq94opoigkrcb83es23, O_RDWR) failed: Permission denied (13) in /usr/share/zoneminder/www/index.php on line 132
[Wed Jul 24 20:58:25.151400 2019] [php7:warn] [pid 8119] [client ip:port] PHP Warning:  session_start(): Failed to read session data: files (path: /var/lib/php/sessions) in /usr/share/zoneminder/www/index.php on line 132
[Wed Jul 24 20:58:25.325311 2019] [php7:warn] [pid 8119] [client ip:port] PHP Warning:  session_start(): open(/var/lib/php/sessions/sess_6frak9imq94opoigkrcb83es23, O_RDWR) failed: Permission denied (13) in /usr/share/zoneminder/www/skins/classic/views/_monit$
[Wed Jul 24 20:58:25.325347 2019] [php7:warn] [pid 8119] [client ip:port] PHP Warning:  session_start(): Failed to read session data: files (path: /var/lib/php/sessions) in /usr/share/zoneminder/www/skins/classic/views/_monitor_filters.php on line 26
[Wed Jul 24 20:58:26.250659 2019] [php7:notice] [pid 5958] [client ip:port] PHP Notice:  Constant ZM_OPT_USE_AUTH already defined in /usr/share/zoneminder/www/includes/config.php on line 173, referer: mydynamicdns
[Wed Jul 24 20:58:26.255411 2019] [php7:warn] [pid 5958] [client ip:port] PHP Warning:  session_start(): open(/var/lib/php/sessions/sess_6frak9imq94opoigkrcb83es23, O_RDWR) failed: Permission denied (13) in /usr/share/zoneminder/www/index.php on line 132, ref$
[Wed Jul 24 20:58:26.255441 2019] [php7:warn] [pid 5958] [client ip:port] PHP Warning:  session_start(): Failed to read session data: files (path: /var/lib/php/sessions) in /usr/share/zoneminder/www/index.php on line 132, referer: mydynamicdns$
[Wed Jul 24 20:58:32.510999 2019] [php7:notice] [pid 9062] [client ip:port] PHP Notice:  Constant ZM_OPT_USE_AUTH already defined in /usr/share/zoneminder/www/includes/config.php on line 173, referer: http:mydynamicdns

Code: Select all

  
nano /usr/share/zoneminder/www/index.php

<?php
//
// ZoneMinder main web interface file, $Date$, $Revision$
// Copyright (C) 2001-2008 Philip Coombes
// 
// This program is free software; you can redistribute it 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
// 

error_reporting(E_ALL);

$debug = false;
if ( $debug ) {
  // Use these for debugging, though not both at once!
  phpinfo(INFO_VARIABLES);
  //error_reporting( E_ALL );
}

// Use new style autoglobals where possible
if ( version_compare(phpversion(), '4.1.0', '<') ) {
  $_SESSION = &$HTTP_SESSION_VARS;
  $_SERVER = &$HTTP_SERVER_VARS;
}

// Useful debugging lines for mobile devices
if ( false ) {
  ob_start();
  phpinfo(INFO_VARIABLES);
  $fp = fopen('/tmp/env.html', 'w');
  fwrite($fp, ob_get_contents());
  fclose($fp);
  ob_end_clean();
}

require_once('includes/config.php');
require_once('includes/logger.php');
require_once('includes/Server.php');
require_once('includes/Storage.php');
require_once('includes/Event.php');
require_once('includes/Group.php');
require_once('includes/Monitor.php');


if (
  (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on')
  or
  (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) and ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'))
) {
  $protocol = 'https';
} else {
  $protocol = 'http';
}
define('ZM_BASE_PROTOCOL', $protocol);

// Absolute URL's are unnecessary and break compatibility with reverse proxies 
// define( "ZM_BASE_URL", $protocol.'://'.$_SERVER['HTTP_HOST'] );

// Use relative URL's instead
define('ZM_BASE_URL', '');

// Check time zone is set
if (!ini_get('date.timezone') || !date_default_timezone_set(ini_get('date.timezone'))) {
  date_default_timezone_set('UTC');
  Fatal( "ZoneMinder is not installed properly: php's date.timezone is not set to a valid timezone" );
}

if ( isset($_GET['skin']) ) {
  $skin = $_GET['skin'];
} else if ( isset($_COOKIE['zmSkin']) ) {
  $skin = $_COOKIE['zmSkin'];
} else if ( defined('ZM_SKIN_DEFAULT') ) {
  $skin = ZM_SKIN_DEFAULT;
} else {
  $skin = 'classic';
}

$skins = array_map('basename', glob('skins/*', GLOB_ONLYDIR));

if ( ! in_array($skin, $skins) ) {
  Error("Invalid skin '$skin' setting to " . $skins[0]);
  $skin = $skins[0];
}

if ( isset($_GET['css']) ) {
  $css = $_GET['css'];
} elseif ( isset($_COOKIE['zmCSS']) ) {
  $css = $_COOKIE['zmCSS'];
} elseif ( defined('ZM_CSS_DEFAULT') ) {
  $css = ZM_CSS_DEFAULT;
} else {
  $css = 'classic';
}

$css_skins = array_map('basename', glob('skins/'.$skin.'/css/*',GLOB_ONLYDIR));
if ( !in_array($css, $css_skins) ) {
  Error("Invalid skin css '$css' setting to " . $css_skins[0]);
  $css = $css_skins[0];
}

define('ZM_BASE_PATH', dirname($_SERVER['REQUEST_URI']));
define('ZM_SKIN_PATH', "skins/$skin");
define('ZM_SKIN_NAME', $skin);

$skinBase = array(); // To allow for inheritance of skins
if ( !file_exists(ZM_SKIN_PATH) )
  Fatal("Invalid skin '$skin'");
$skinBase[] = $skin;

$currentCookieParams = session_get_cookie_params(); 
//Logger::Debug('Setting cookie parameters to lifetime('.$currentCookieParams['lifetime'].') path('.$currentCookieParams['path'].') domain ('.$currentCookieParams['domain'].') secure('.$currentCookieParams['secure'].') httpOnly(1)');
session_set_cookie_params( 
    $currentCookieParams['lifetime'], 
    $currentCookieParams['path'], 
    $currentCookieParams['domain'],
    $currentCookieParams['secure'], 
    true
); 

ini_set('session.name', 'ZMSESSID');

session_start();

if ( !isset($_SESSION['skin']) || isset($_REQUEST['skin']) || !isset($_COOKIE['zmSkin']) || $_COOKIE['zmSkin'] != $skin ) {
  $_SESSION['skin'] = $skin;
  setcookie('zmSkin', $skin, time()+3600*24*30*12*10);
}

if ( !isset($_SESSION['css']) || isset($_REQUEST['css']) || !isset($_COOKIE['zmCSS']) || $_COOKIE['zmCSS'] != $css ) {
  $_SESSION['css'] = $css;
  setcookie('zmCSS', $css, time()+3600*24*30*12*10);
}

if ( ZM_OPT_USE_AUTH ) {
  if ( isset($_SESSION['user']) ) {
    $user = $_SESSION['user'];
  } else {
    unset($user);
  }
} else {
  $user = $defaultUser;
}
# Only one request can open the session file at a time, so let's close the session here to improve concurrency.
# Any file/page that sets session variables must re-open it.
session_write_close();

require_once('includes/lang.php');
require_once('includes/functions.php');
require_once('includes/auth.php');

# Running is global but only do the daemonCheck if it is actually needed
$running = null;

# Add Cross domain access headers
CORSHeaders();

// Check for valid content dirs
if ( !is_writable(ZM_DIR_EVENTS) || !is_writable(ZM_DIR_IMAGES) ) {
  Warning("Cannot write to content dirs('".ZM_DIR_EVENTS."','".ZM_DIR_IMAGES."').  Check that these exist and are owned by the web account user");
}

# Globals
$redirect = null;
$view = null;
if ( isset($_REQUEST['view']) )
  $view = detaintPath($_REQUEST['view']);

$request = null;
if ( isset($_REQUEST['request']) )
  $request = detaintPath($_REQUEST['request']);

foreach ( getSkinIncludes('skin.php') as $includeFile )
  require_once $includeFile;

if ( ZM_OPT_USE_AUTH ) {
    if ( ZM_AUTH_HASH_LOGINS && empty($user) && ! empty($_REQUEST['auth']) ) {
      if ( $authUser = getAuthUser($_REQUEST['auth']) ) {
        userLogin($authUser['Username'], $authUser['Password'], true);
      }
    } 
   else if ( isset($_REQUEST['username']) and isset($_REQUEST['password']) ) {
        userLogin($_REQUEST['username'], $_REQUEST['password'], false);
  }
  if ( !empty($user) ) {
    // generate it once here, while session is open.  Value will be cached in session and return when called later on
    generateAuthHash(ZM_AUTH_HASH_IPS);
  }
}

if ( isset($_REQUEST['action']) ) {
  $action = detaintPath($_REQUEST['action']);
}

# The only variable we really need to set is action. The others are informal.
isset($view) || $view = NULL;
isset($request) || $request = NULL;
isset($action) || $action = NULL;

Logger::Debug("View: $view Request: $request Action: $action");
if (
  ZM_ENABLE_CSRF_MAGIC &&
  ( $action != 'login' ) &&
  ( $view != 'view_video' ) &&
  ( $view != 'image' ) &&
  ( $request != 'control' ) && 
  ( $view != 'frames' ) && 
  ( $view != 'archive' )
) {
  require_once( 'includes/csrf/csrf-magic.php' );
  #Logger::Debug("Calling csrf_check with the following values: \$request = \"$request\", \$view = \"$view\", \$action = \"$action\"");
  csrf_check();
}

# Need to include actions because it does auth
require_once('includes/actions.php');

# If I put this here, it protects all views and popups, but it has to go after actions.php because actions.php does the actual logging in.
if ( ZM_OPT_USE_AUTH and !isset($user) ) {
  Logger::Debug('Redirecting to login');
  $view = 'login';
  $request = null;
} else if ( ZM_SHOW_PRIVACY && ($action != 'privacy') && ($view !='options') && (!$request) && canEdit('System') ) {
  Logger::Debug('Redirecting to privacy');
  $view = 'privacy';
  $request = null;
}

if ( $redirect ) {
  header('Location: '.$redirect);
  return;
}

if ( $request ) {
  foreach ( getSkinIncludes('ajax/'.$request.'.php', true, true) as $includeFile ) {
    if ( !file_exists($includeFile) )
      Fatal("Request '$request' does not exist");
    require_once $includeFile;
  }
  return;
} else {
  if ( $includeFiles = getSkinIncludes('views/'.$view.'.php', true, true) ) {
    foreach ( $includeFiles as $includeFile ) {
      if ( !file_exists($includeFile) )
        Fatal("View '$view' does not exist");
      require_once $includeFile;
    }
    // If the view overrides $view to 'error', and the user is not logged in, then the
    // issue is probably resolvable by logging in, so provide the opportunity to do so.
    // The login view should handle redirecting to the correct location afterward.
    if ( $view == 'error' && !isset($user) ) {
      $view = 'login';
      foreach ( getSkinIncludes('views/login.php', true, true) as $includeFile )
        require_once $includeFile;
    }
  }
  // If the view is missing or the view still returned error with the user logged in,
  // then it is not recoverable.
  if ( !$includeFiles || $view == 'error' ) {
    foreach ( getSkinIncludes('views/error.php', true, true) as $includeFile )
      require_once $includeFile;
  }
}
?>








Code: Select all

nano /usr/share/zoneminder/www/includes/auth.php
<?php
//
// ZoneMinder auth library, $Date$, $Revision$
// Copyright (C) 2001-2008 Philip Coombes
// 
// This program is free software; you can redistribute it 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
// 

function userLogin($username, $password='', $passwordHashed=false) {
  global $user;

  $sql = 'SELECT * FROM Users WHERE Enabled=1';
  $sql_values = NULL;
  if ( ZM_AUTH_TYPE == 'builtin' ) {
    if ( $passwordHashed ) {
      $sql .= ' AND Username=? AND Password=?';
    } else {
      $sql .= ' AND Username=? AND Password=password(?)';
    }
    $sql_values = array($username, $password);
  } else {
    $sql .= ' AND Username=?';
    $sql_values = array($username);
  }
  $close_session = 0;
  if ( !is_session_started() ) {
    Logger::Debug("Starting session in userLogin");
    session_start();
    $close_session = 1;
  }
  $_SESSION['username'] = $username;
  if ( ZM_AUTH_RELAY == 'plain' ) {
    // Need to save this in session
    $_SESSION['password'] = $password;
  }
  $_SESSION['remoteAddr'] = $_SERVER['REMOTE_ADDR']; // To help prevent session hijacking
  if ( $dbUser = dbFetchOne($sql, NULL, $sql_values) ) {
    Info("Login successful for user \"$username\"");
    $_SESSION['user'] = $user = $dbUser;
    unset($_SESSION['loginFailed']);
    if ( ZM_AUTH_TYPE == 'builtin' ) {
      $_SESSION['passwordHash'] = $user['Password'];
    }
    session_regenerate_id();
  } else {
    Warning("Login denied for user \"$username\"");
    $_SESSION['loginFailed'] = true;
    unset($user);
  }
  if ( $close_session )
    session_write_close();
  return isset($user) ? $user: null;
} # end function userLogin

function userLogout() {
  global $user;
  Info('User "'.$user['Username'].'" logged out');
  session_start();
  unset($_SESSION['user']);
    unset($user);

  session_destroy();
}

function getAuthUser($auth) {
  if ( ZM_OPT_USE_AUTH && ZM_AUTH_RELAY == 'hashed' && !empty($auth) ) {
    $remoteAddr = '';
    if ( ZM_AUTH_HASH_IPS ) {
      $remoteAddr = $_SERVER['REMOTE_ADDR'];
      if ( !$remoteAddr ) {
        Error("Can't determine remote address for authentication, using empty string");
        $remoteAddr = '';
      }
    }

    if ( isset($_SESSION['username']) ) {
      # Most of the time we will be logged in already and the session will have our username, so we can significantly speed up our hash testing by only looking at our user.
      # Only really important if you have a lot of users.
      $sql = "SELECT * FROM Users WHERE Enabled = 1 AND Username='".$_SESSION['username']."'";
    } else {
      $sql = 'SELECT * FROM Users WHERE Enabled = 1';
    }

    foreach ( dbFetchAll($sql) as $user ) {
      $now = time();
      for ( $i = 0; $i < ZM_AUTH_HASH_TTL; $i++, $now -= (3600) ) { // Try for last two hours
        $time = localtime($now);
        $authKey = ZM_AUTH_HASH_SECRET.$user['Username'].$user['Password'].$remoteAddr.$time[2].$time[3].$time[4].$time[5];
        $authHash = md5($authKey);

        if ( $auth == $authHash ) {
          return $user;
        }
      } // end foreach hour
    } // end foreach user
  } // end if using auth hash
  Error("Unable to authenticate user from auth hash '$auth'");
  return false;
} // end getAuthUser($auth)

function generateAuthHash($useRemoteAddr, $force=false) {
  if ( ZM_OPT_USE_AUTH and ZM_AUTH_RELAY == 'hashed' and isset($_SESSION['username']) and $_SESSION['passwordHash'] ) {
    # regenerate a hash at half the liftetime of a hash, an hour is 3600 so half is 1800
    $time = time();
    $mintime = $time - ( ZM_AUTH_HASH_TTL * 1800 );

    if ( $force or ( !isset($_SESSION['AuthHash'.$_SESSION['remoteAddr']]) ) or ( $_SESSION['AuthHashGeneratedAt'] < $mintime ) ) {
      # Don't both regenerating Auth Hash if an hour hasn't gone by yet
      $local_time = localtime();
      $authKey = '';
      if ( $useRemoteAddr ) {
        $authKey = ZM_AUTH_HASH_SECRET.$_SESSION['username'].$_SESSION['passwordHash'].$_SESSION['remoteAddr'].$local_time[2].$local_time[3].$local_time[4].$local_time[5];
      } else {
        $authKey = ZM_AUTH_HASH_SECRET.$_SESSION['username'].$_SESSION['passwordHash'].$local_time[2].$local_time[3].$local_time[4].$local_time[5];
      }
      #Logger::Debug("Generated using hour:".$local_time[2] . ' mday:' . $local_time[3] . ' month:'.$local_time[4] . ' year: ' . $local_time[5] );
      $auth = md5($authKey);
      if ( !$force ) {
        $close_session = 0;
        if ( !is_session_started() ) {
          session_start();
          $close_session = 1;
        }
        $_SESSION['AuthHash'.$_SESSION['remoteAddr']] = $auth;
        $_SESSION['AuthHashGeneratedAt'] = $time;
        session_write_close();
      } else {
        return $auth;
      }
      #Logger::Debug("Generated new auth $auth at " . $_SESSION['AuthHashGeneratedAt']. " using $authKey" );
      #} else {
      #Logger::Debug("Using cached auth " . $_SESSION['AuthHash'] ." beacuse generatedat:" . $_SESSION['AuthHashGeneratedAt'] . ' < now:'. $time . ' - ' .  ZM_AUTH_HASH_TTL . ' * 1800 = '. $mintime);
    } # end if AuthHash is not cached
    return $_SESSION['AuthHash'.$_SESSION['remoteAddr']];
  } # end if using AUTH and AUTH_RELAY
  return '';
}

function visibleMonitor($mid) {
  global $user;

  return ( empty($user['MonitorIds']) || in_array($mid, explode(',', $user['MonitorIds'])) );
}

function canView($area, $mid=false) {
  global $user;

  return ( ($user[$area] == 'View' || $user[$area] == 'Edit') && ( !$mid || visibleMonitor($mid) ) );
}

function canEdit($area, $mid=false) {
  global $user;

  return ( $user[$area] == 'Edit' && ( !$mid || visibleMonitor($mid) ));
}

function is_session_started() {
  if ( php_sapi_name() !== 'cli' ) {
    if ( version_compare(phpversion(), '5.4.0', '>=') ) {
      return session_status() === PHP_SESSION_ACTIVE ? TRUE : FALSE;
    } else {
      return session_id() === '' ? FALSE : TRUE;
    }
  } else {
    Warning("php_sapi_name === 'cli'");
  }
  return FALSE;
}

?>


AfricanSwallow wrote: Wed Jul 03, 2019 6:35 pm are you doing a simple GET from a browser, or using POSTMAN or another tool? If so, are you passing the credentials since you've enabled them? If through a browser, are you logged into the main (read non-api) web interface first? You should do so and open api call in another tab in the same NON-PRIVATE!! browsing session.

Lastly, have you cleared your cache and browser history to ensure you aren't sending stale headers?

Thanks,
AfricanSwallow
I am not familiar with your question here. I am using Google Chrome on a Mac, and I have cleared my browsing data.

Thank you again AfricanSwallow. I apologize I didn't have "Notify me when a reply is posted", and missed your response. I'll be sure to respond faster next time.
Thank you,
jrmr