Skip to content

Instantly share code, notes, and snippets.

Created April 28, 2014 02:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/11360646 to your computer and use it in GitHub Desktop.
Save anonymous/11360646 to your computer and use it in GitHub Desktop.
Download handler with the following features: 1. Proper direct link protection 2. Lazy referrer checking 3. Makes sure the file is a real file 4. Semi-proper download count generation 5. File path hack protection (can't use "../" to get system files)
<?php
class Controller_Dl extends Controller
{
public function action_devs()
{
$thisIp = Input::ip();
$thisIp = hash('sha256', $thisIp);
if (null !== Input::get('dl')) {
$dlpath = Input::get('dl');
if (!empty($dlpath)) {
// make sure we received the session uid marker
if (null !== Input::get('dluid')) {
// the get var is there, is it empty?
$sessionUid = Input::get('dluid');
if (empty($sessionUid)) {
// it is empty, so throw a 404
Response::redirect('/devs');
} else {
// it is not empty, move along
$fullpath = DOCROOT . "uploads/devs/$dlpath";
if (strpos($fullpath, '../') !== false) {
// we captured a hacking attempt!
Response::redirect('/devs');
} else {
// ok this is a legitimate request
if (file_exists($fullpath)) {
// its a real file, so let's validate the session uid marker
$sessionUidMarker = Session::get('dluid');
if ($sessionUid != $sessionUidMarker) {
// they don't match, throw a 404 error
Response::redirect('/devs');
} else {
$referrer = Input::referrer();
// they do match, hand over the requested data
if (strpos($referrer, 'basketbuild.com') !== false) {
// ^ lazy referrer checking, only checks if basketbuild.com is somewhere in the string
/*
* checking for dupe downloads
*
*
* how it works:
*
* We first fetch any entries in the database that match both the originating
* IP address and the exact matching file path that is being requested.
*
* If there are any matching entries:
* Check the timestamp. Was the last download over 30 seconds ago? If so,
* then we can add a new entry. This also fixes a bug where Android
* generates dupe download requests; one from the browser, and one from the
* Download activity. If the last download was 30 seconds or under ago, then
* we hand over the requested data without adding anything to the database.
*
* If there are not any matching entries:
* This is obviously the first time this IP has attempted to download this
* file, so we add a new database entry and hand over the requested data.
*/
$dupes = Model_Download::find('all', array(
'where' => array(
'ip' => $thisIp,
'filepath' => $fullpath,
),
'limit' => 1,
));
/*
* The above code only selects one matching entry, without the limit
* it will generate new entries for all entries in the database. It's
* a very nasty bug and there is probably a much better way of doing this
* but it works.
*/
if (!empty($dupes)) {
foreach ($dupes as $dupe) {
$currTime = time();
$prevTime = $dupe['created_at'];
$timeDilation = $currTime - $prevTime;
if ($timeDilation > 30) {
/*
* It's been more than 30 seconds since the last time this file
* was downloaded by this IP, so we add a db entry.
*/
$dlM = new Model_Download();
$dlM->filepath = $fullpath;
$dlM->ip = $thisIp;
$dlM->save();
}
}
} else {
/*
* This IP has never downloaded this file, so we add a db entry.
*/
$dlM = new Model_Download();
$dlM->filepath = $fullpath;
$dlM->ip = $thisIp;
$dlM->save();
}
File::download($fullpath);
} else {
// bad referrer string, take this!!!
Response::redirect('/devs');
}
}
} else {
// the file doesn't exist, throw a 404 page
Response::redirect('/devs');
}
}
}
} else {
// the dluid wasn't even given, wtf are you doing?
Response::redirect('/devs');
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment