? Success

User tests: Successful: Unsuccessful:

avatar shumisha
shumisha
8 Jan 2014

Hi,

In starting to use the paid-for extensions updater recently introduced in 3.x (tracker 32684, #2508), I came across some limitations that make it difficult for us to actually use it.
Therefore I'm proposing the following small contribution to make this feature a bit more universal.

What could be improved:

  • cannot use in J! 2.5 (w/o backporting, ie lots of work and maintenance)
  • pass all credentials into the url, which means credentials are stored in servers and proxies log files along the way, for all to view
  • not easily made dynamic: ie download credentials are "hardcoded" in the update sites DB table, which allow "replaying", ie: once somebody has sniffed credentials, they can use them at will, an unlimited number of times, and pass them along to anyone
  • cannot easily share credentials between extensions, ie one main component, controlling updates of various plugins or language files for instance

The proposal is simply to add firing an event at the right time and place, to allow an extension-supplied plugin to alter the url and/or headers on the fly as required by the extension supplier authorization mechanism.

Drawbacks:

  • need to add a plugin to respond to the event, easy for larger extension which may already have one or more plugins, more work for those who don't

Benefits:

  • simple, backward compatible change (4 lines added in one file)
  • same 4 lines and same plugin can be used the same on J! 2.5, providing Joomla update for paid extension on 2.5 as well
  • fairly simple plugin, I'll provide sample one
  • same plugin can control update for several extensions
  • can use urls var or headers to pass credentials, less data stored in log files in the later case
  • can use dynamic, time stamped requests to avoid replay

This PR is backward compatible and doesn't touch existing code, it only adds a bit more flexibility.

Also see tracker item: http://joomlacode.org/gf/project/joomla/tracker/?action=TrackerItemEdit&tracker_item_id=33096&start=0

avatar shumisha shumisha - open - 8 Jan 2014
avatar shumisha
shumisha - comment - 8 Jan 2014

Here is a sample plugin to respond the download event, and insert credentials in the download request. The plugin should be in the "installer" group, but any other plugin type is fine as long as you make sure the plugin is loaded when needed.

<?php
/**
 * @ant_title_ant@
 *
 * @author      @ant_author_ant@
 * @copyright   @ant_copyright_ant@
 * @package     @ant_package_ant@
 * @license     @ant_license_ant@
 * @version     @ant_version_ant@
 * @date        @ant_current_date_ant@
 */

defined('_JEXEC') or die;

/**
 * Handle commercial extension update authorization
 *
 * @package     MyPackage
 * @subpackage  MyPackage.update
 * @since       2.5
 */
class PlgInstallerSample extends JPlugin
{
    /**
     * @var    String  base update url, to decide whether to process the event or not
     * @since  2.5
     */
    private $baseUrl = 'http://update.example.com/subscribers/com_sample';

    /**
     * @var    String  your extension identifier, to retrieve its params
     * @since  2.5
     */
    private $extension = 'com_sample';

    /**
     * Handle adding credentials to package download request
     *
     * @param   string  $url        url from which package is going to be downloaded
     * @param   array   $headers    headers to be sent along the download request (key => value format)
     *
     * @return  boolean true        Always true, regardless of success
     *
     * @since   2.5
     */
    public function onInstallerBeforePackageDownload(&$url, &$headers)
    {
        // are we trying to update our extension?
        if (strpos($url, $this->baseUrl) !== 0)
        {
            return true;
        }

        // read credentials from extension params or any other source
        $credentials = $this->fetchCredentials($url, $headers);

        // bind credentials to request, either in the urls, or using headers
        // or a combination of both
        $this->bindCredentials($credentials, $url, $headers);

        return true;
    }

    /**
     * Retrieve user credentials, adjust as needed based on extension being processed
     *
     * @return mixed an array with credentials (access, secret)
     */
    private function fetchCredentials($url, $headers)
    {
        // fetch credentials from extension parameters, or
        // wherever you want to store them
        JLoader::import('joomla.application.component.helper');
        $component = JComponentHelper::getComponent($this->extension);
        $credentials = array('access' => $component->params->get('update_credentials_access', ''),
            'secret' => $component->params->get('update_credentials_secret', ''));
        return $credentials;
    }

    /**
     * Bind credentials to the download request. Can be done by adding them to 
     * the download url, or using headers, or any other method you like
     * As a sample, below is (close to) what we use, ie authorization headers, so that access and secrets are 
     * not stored in web servers and proxies log files
     *
     * @param   array   $credentials    whatever credentials were retrieved for the current user/website
     * @param   string  $url            url from which package is going to be downloaded
     * @param   array   $headers        headers to be sent along the download request (key => value format)
     * 
     * @return void
     */
    private function bindCredentials($credentials, &$url, &$headers)
    {
        $headers['X-download-auth-ts'] = time();
        $headers['X-download-auth-access'] = $credentials['access'];
        $headers['X-download-auth-token'] = sha1($headers['X-download-auth-ts'] . mt_rand() . $credentials['secret'] . $url);
        $headers['X-download-auth-sig'] = sha1(
            $credentials['access'] . $headers['X-download-auth-token'] . $credentials['secret'] . $headers['X-download-auth-ts'] . $this->extension);
    }
}
avatar spignataro
spignataro - comment - 16 Jan 2014

I tested this pull request and it doesn't seem to effect anything. My component still updated properly.

However I did not create a plugin to test the additional install plugin trigger.

avatar shumisha
shumisha - comment - 16 Jan 2014

Steven, FYI, I have attached a plugin implementing Akeeba Release system to the tracker item: http://joomlacode.org/gf/project/joomla/tracker/?action=TrackerItemEdit&tracker_item_id=33133&start=0

(same plugin works both on 2.x and 3.x)

avatar shumisha shumisha - change - 27 Jan 2014
Labels Added: ? ?
avatar mbabker mbabker - change - 22 Feb 2014
Status New Closed
Closed_Date 0000-00-00 00:00:00 2014-02-22 19:20:35
avatar mbabker mbabker - close - 22 Feb 2014

Add a Comment

Login with GitHub to post a comment