############################################################################### # 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. ############################################################################### /// Name: Image Proxy /// Author: Dwayne C. Litzenberger /// Description: This plugin proxies images that might otherwise be protected by a "referer check". /// Configuration: __imageproxy_config /// Version: 0.9 define('IMAGEPROXY_VERSION', '0.9'); define('IMAGEPROXY_CONFIG_HASHKEY', 'imageproxy.hash_key'); define('IMAGEPROXY_HASHKEY_LENGTH', 16); # 128 bits function __imageproxy_urlencode_cb($m) { return rawurlencode($m[1]); } function __imageproxy_urlencode($s) { // cURL doesn't do _any_ URL encoding, so URLs like // "http://example.com/big image.jpg" get sent in the request as // "GET /big image.jpg HTTP/1.1", which obviously doesn't work. // RFC 2396 section 2.4.3 lists some "Excluded US-ASCII Characters", which // we escape here. return preg_replace_callback( '#([\x00-\x1f\x7f <>"{}|\\^+\[\]`])#s', '__imageproxy_urlencode_cb', $s); } function __imageproxy_gregarius_version_is_at_least($minver) { $ver = explode('.', _VERSION_); $min = explode('.', $minver); for ($i = 0; $i < min(count($ver), count($min)); $i++) { if ($ver[$i] < $min[$i]) { return false; } } return true; } function __imageproxy_random($bytes) { # Generate random bits _pf("__imageproxy_random"); if (function_exists("mcrypt_create_iv")) { _pf("... using mcrypt_create_iv to generate key"); $data = mcrypt_create_iv($bytes, MCRYPT_DEV_URANDOM); if (!$data) { // SECURITY: This is insecure _pf("... Warning: generating insecure key using MCRYPT_RAND"); srand(); $data = mcrypt_create_iv($bytes, MCRYPT_RAND); } else { _pf("... key generated using MCRYPT_DEV_URANDOM"); } } else { // SECURITY: This is insecure _pf("... Warning: generating insecure key using mt_rand"); mt_srand(); $data = ""; for($i = 0; $i < $bytes; $i++) { $data .= chr(mt_rand(0, 255)); } } if (!isset($data) or !$data or strlen($data) != $bytes) { _pf("... error"); die("Internal error while generating random data"); } return $data; } function __imageproxy_make_hash($url, $hash_key=null) { # Hash format: # url = *OCTET # key = 16OCTET ; the hash key # url-length = 1*DIGIT ; length of the url # unique = "36:6338dc36-5add-11db-8783-001617467794," # key-ns = "16:" key "," # url-ns = url-length ":" url "," # hash-data = unique key-ns url-ns # hash = BIN2HEX( SHA1( SHA1( hash-data ) ) ) # Test vector: # key = "ABCDEFGHIJKLMNOP" (hex: 4142434445464748494a4b4c4d4e4f50) # url = "about:blank" # hash-data = "36:6338dc36-5add-11db-8783-001617467794,16:ABCDEFGHIJKLMNOP,11:about:blank," # hash = "1d6f8564bc3555f00ebda1a6b1a349741688d4e6" if (!__imageproxy_is_valid_key($hash_key)) { $hash_key = __imageproxy_get_key(); } $binary_hash_key = pack('H*', $hash_key); $uuid = "6338dc36-5add-11db-8783-001617467794"; $hash = sha1(sha1( strlen($uuid) . ":" . $uuid . "," . strlen($binary_hash_key) . ":" . $binary_hash_key . "," . strlen($url) . ":" . $url . ",", true)); return $hash; } function __imageproxy_config() { $encoding = (getConfig('rss.output.encoding') ? getConfig('rss.output.encoding') : DEFAULT_OUTPUT_ENCODING); $hash_key = __imageproxy_get_key(); if (rss_plugins_is_submit()) { $hash_key = $_REQUEST['hash_key']; if (!__imageproxy_is_valid_key($hash_key)) { // The specified key is invalid. Generate a new one. $hash_key = __imageproxy_generate_key(); } else { // Normalize the key $hash_key = bin2hex(pack('H*', $hash_key)); } // Save the key in the database rss_plugins_add_option(IMAGEPROXY_CONFIG_HASHKEY, $hash_key, 'string', 'x'); return; } print "
\n"; } function __imageproxy_generate_key() { return bin2hex(__imageproxy_random(IMAGEPROXY_HASHKEY_LENGTH)); } function __imageproxy_get_key() { $hash_key = rss_plugins_get_option(IMAGEPROXY_CONFIG_HASHKEY); if (!__imageproxy_is_valid_key($hash_key)) { $hash_key = __imageproxy_generate_key(); rss_plugins_add_option(IMAGEPROXY_CONFIG_HASHKEY, $hash_key, 'string', 'x'); } return $hash_key; } function __imageproxy_is_valid_key($hash_key) { if (empty($hash_key)) { return false; } $tmp = @pack('H*', $hash_key); if (empty($tmp) or strlen($tmp) != IMAGEPROXY_HASHKEY_LENGTH) { return false; } return true; } function __imageproxy_changeSrc__cb($m) { $pre = $m[1]; $src = $m[2]; $post = $m[3]; $encoding = (getConfig('rss.output.encoding') ? getConfig('rss.output.encoding') : DEFAULT_OUTPUT_ENCODING); $q = substr($src, 0, 1); $q2 = substr($src, strlen($src)-1, 1); if ($q === $q2 and ($q === "'" or $q === '"')) { $url = html_entity_decode(substr($src, 1, strlen($src)-2), ENT_QUOTES, $encoding); } else { $url = html_entity_decode($src, ENT_QUOTES, $encoding); } $hash = __imageproxy_make_hash($url); $url = rss_plugins_get_plugins_http_path() . "imageproxy.php?do_proxy=1&hash=".urlencode($hash)."&url=" . urlencode($url); return $pre . '"' . htmlspecialchars($url, ENT_COMPAT, $encoding) . '"' . $post; } function __imageproxy_filter($item) { if (!array_key_exists('description', $item)) { return $item; } $content = $item->description; $content = preg_replace_callback( '#(