]> git.wh0rd.org Git - tt-rss.git/commitdiff
implement basic feed authentication parameter encryption in the database (FEED_CRYPT_KEY)
authorAndrew Dolgov <fox@fakecake.org>
Sat, 13 Apr 2013 14:24:27 +0000 (18:24 +0400)
committerAndrew Dolgov <fox@fakecake.org>
Sat, 13 Apr 2013 14:24:41 +0000 (18:24 +0400)
classes/pref/feeds.php
config.php-dist
include/crypt.php [new file with mode: 0644]
include/functions.php
include/rssfuncs.php
include/sanity_check.php
include/sanity_config.php
install/index.php

index f57cc37d6fdebf2ea52cd88189679bafc114cfd1..4a77ed8cfdf166fc952189adccd153065c250ae8 100644 (file)
@@ -528,6 +528,9 @@ class Pref_Feeds extends Handler_Protected {
                        "SELECT * FROM ttrss_feeds WHERE id = '$feed_id' AND
                                owner_uid = " . $_SESSION["uid"]);
 
+               $auth_pass_encrypted = sql_bool_to_bool(db_fetch_result($result, 0,
+                       "auth_pass_encrypted"));
+
                $title = htmlspecialchars(db_fetch_result($result,
                        0, "title"));
 
@@ -613,7 +616,14 @@ class Pref_Feeds extends Handler_Protected {
                        placeHolder=\"".__("Login")."\"
                        name=\"auth_login\" value=\"$auth_login\"><hr/>";
 
-               $auth_pass = htmlspecialchars(db_fetch_result($result, 0, "auth_pass"));
+               $auth_pass = db_fetch_result($result, 0, "auth_pass");
+
+               if ($auth_pass_encrypted) {
+                       require_once "crypt.php";
+                       $auth_pass = decrypt_string($auth_pass);
+               }
+
+               $auth_pass = htmlspecialchars($auth_pass);
 
                print "<input dojoType=\"dijit.form.TextBox\" type=\"password\" name=\"auth_pass\"
                        placeHolder=\"".__("Password")."\"
@@ -936,6 +946,14 @@ class Pref_Feeds extends Handler_Protected {
                $mark_unread_on_update = checkbox_to_sql_bool(
                        db_escape_string($this->link, $_POST["mark_unread_on_update"]));
 
+               if (strlen(FEED_CRYPT_KEY) > 0) {
+                       require_once "crypt.php";
+                       $auth_pass = substr(encrypt_string($auth_pass), 0, 250);
+                       $auth_pass_encrypted = 'true';
+               } else {
+                       $auth_pass_encrypted = 'false';
+               }
+
                if (get_pref($this->link, 'ENABLE_FEED_CATS')) {
                        if ($cat_id && $cat_id != 0) {
                                $category_qpart = "cat_id = '$cat_id',";
@@ -958,6 +976,7 @@ class Pref_Feeds extends Handler_Protected {
                                purge_interval = '$purge_intl',
                                auth_login = '$auth_login',
                                auth_pass = '$auth_pass',
+                               auth_pass_encrypted = $auth_pass_encrypted,
                                private = $private,
                                cache_images = $cache_images,
                                hide_images = $hide_images,
@@ -1003,7 +1022,8 @@ class Pref_Feeds extends Handler_Protected {
                                                break;
 
                                        case "auth_pass":
-                                               $qpart = "auth_pass = '$auth_pass'";
+                                               $qpart = "auth_pass = '$auth_pass' AND
+                                                       auth_pass_encrypted = $auth_pass_encrypted";
                                                break;
 
                                        case "private":
@@ -1841,12 +1861,20 @@ class Pref_Feeds extends Handler_Protected {
                                        "SELECT id FROM ttrss_feeds
                                        WHERE feed_url = '$feed' AND owner_uid = ".$_SESSION["uid"]);
 
+                               if (strlen(FEED_CRYPT_KEY) > 0) {
+                                       require_once "crypt.php";
+                                       $pass = substr(encrypt_string($pass), 0, 250);
+                                       $auth_pass_encrypted = 'true';
+                               } else {
+                                       $auth_pass_encrypted = 'false';
+                               }
+
                                if (db_num_rows($result) == 0) {
                                        $result = db_query($this->link,
                                                "INSERT INTO ttrss_feeds
-                                                       (owner_uid,feed_url,title,cat_id,auth_login,auth_pass,update_method)
+                                                       (owner_uid,feed_url,title,cat_id,auth_login,auth_pass,update_method,auth_pass_encrypted)
                                                VALUES ('".$_SESSION["uid"]."', '$feed',
-                                                       '[Unknown]', $cat_qpart, '$login', '$pass', 0)");
+                                                       '[Unknown]', $cat_qpart, '$login', '$pass', 0, $auth_pass_encrypted)");
                                }
 
                                db_query($this->link, "COMMIT");
index eb3339742d5608f77961e141188ff9972c6ff977..fc999354bdb8b3808f86d411cb1b9b3ccc7522a2 100644 (file)
        // You need to set this option correctly otherwise several features
        // including PUSH, bookmarklets and browser integration will not work properly.
 
+       define('FEED_CRYPT_KEY', '');
+   // Key used for encryption of login/passwords for password-protected feeds
+   // in the database. A string of 24 random characters. If left blank, encryption
+       // is not used. Requires mcrypt functions.
+       // Warning: changing this key will make your stored feed passwords impossible
+       // to decrypt.
+       
        define('SINGLE_USER_MODE', false);
        // Operate in single user mode, disables all functionality related to
        // multiple users and authentication. Enabling this assumes you have
diff --git a/include/crypt.php b/include/crypt.php
new file mode 100644 (file)
index 0000000..f06483e
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+       function decrypt_string($str) {
+               $pair = explode(":", $str);
+
+               if (count($pair) == 2) {
+                       @$iv = base64_decode($pair[0]);
+                       @$encstr = base64_decode($pair[1]);
+
+                       if ($iv && $encstr) {
+                               $key = hash('SHA256', FEED_CRYPT_KEY, true);
+
+                               $str = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $encstr,
+                                       MCRYPT_MODE_CBC, $iv);
+
+                               if ($str) return rtrim($str);
+                       }
+               }
+
+               return false;
+       }
+
+       function encrypt_string($str) {
+               $key = hash('SHA256', FEED_CRYPT_KEY, true);
+
+               $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128,
+                       MCRYPT_MODE_CBC), MCRYPT_RAND);
+
+               $encstr = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $str,
+                       MCRYPT_MODE_CBC, $iv);
+
+               $iv_base64 = base64_encode($iv);
+               $encstr_base64 = base64_encode($encstr);
+
+               return "$iv_base64:$encstr_base64";
+       }
+?>
index f5685b89a191b612eba7d10b4338b82ef3ce5a4f..73ed97d086bbcc8338a337d4ca35fc9cc795de2c 100644 (file)
                        "SELECT id FROM ttrss_feeds
                        WHERE feed_url = '$url' AND owner_uid = ".$_SESSION["uid"]);
 
+               if (strlen(FEED_CRYPT_KEY) > 0) {
+                       require_once "crypt.php";
+                       $auth_pass = substr(encrypt_string($auth_pass), 0, 250);
+                       $auth_pass_encrypted = 'true';
+               } else {
+                       $auth_pass_encrypted = 'false';
+               }
+
                if (db_num_rows($result) == 0) {
                        $result = db_query($link,
                                "INSERT INTO ttrss_feeds
-                                       (owner_uid,feed_url,title,cat_id, auth_login,auth_pass,update_method)
+                                       (owner_uid,feed_url,title,cat_id, auth_login,auth_pass,update_method,auth_pass_encrypted)
                                VALUES ('".$_SESSION["uid"]."', '$url',
-                               '[Unknown]', $cat_qpart, '$auth_login', '$auth_pass', 0)");
+                               '[Unknown]', $cat_qpart, '$auth_login', '$auth_pass', 0, $auth_pass_encrypted)");
 
                        $result = db_query($link,
                                "SELECT id FROM ttrss_feeds WHERE feed_url = '$url'
index 6e3ef4cf15e4371127981e397fc018e2fc694c00..859c575cce233a70754c24aee694c418d2a0cb7c 100644 (file)
                $result = db_query($link, "SELECT id,update_interval,auth_login,
                        feed_url,auth_pass,cache_images,last_updated,
                        mark_unread_on_update, owner_uid,
-                       pubsub_state
+                       pubsub_state, auth_pass_encrypted
                        FROM ttrss_feeds WHERE id = '$feed'");
 
                if (db_num_rows($result) == 0) {
                $mark_unread_on_update = sql_bool_to_bool(db_fetch_result($result,
                        0, "mark_unread_on_update"));
                $pubsub_state = db_fetch_result($result, 0, "pubsub_state");
+               $auth_pass_encrypted = sql_bool_to_bool(db_fetch_result($result,
+                       0, "auth_pass_encrypted"));
 
                db_query($link, "UPDATE ttrss_feeds SET last_update_started = NOW()
                        WHERE id = '$feed'");
                $auth_login = db_fetch_result($result, 0, "auth_login");
                $auth_pass = db_fetch_result($result, 0, "auth_pass");
 
+               if ($auth_pass_encrypted) {
+                       require_once "crypt.php";
+                       $auth_pass = decrypt_string($auth_pass);
+               }
+
                $cache_images = sql_bool_to_bool(db_fetch_result($result, 0, "cache_images"));
                $fetch_url = db_fetch_result($result, 0, "feed_url");
 
index 69309290e643aa58518ced268f9bf7a4e1beaa3b..b4102d23492ac74214923ef505ec06d470b0d3b6 100644 (file)
                                array_push($errors, "Javascript cache is not writable (chmod -R 777 ".CACHE_DIR."/js)");
                        }
 
+                       if (strlen(FEED_CRYPT_KEY) != 24) {
+                               array_push($errors, "FEED_CRYPT_KEY should be exactly 24 characters in length.");
+                       }
+
+                       if (strlen(FEED_CRYPT_KEY) != 0 && !function_exists("mcrypt_decrypt")) {
+                               array_push($errors, "FEED_CRYPT_KEY requires mcrypt functions which are not found.");
+                       }
+
                        if (GENERATED_CONFIG_CHECK != EXPECTED_CONFIG_VERSION) {
                                array_push($errors,
                                        "Configuration option checker sanity_config.php is outdated, please recreate it using ./utils/regen_config_checks.sh");
index cb1c1e8cad1f5d9a6fbfd3fc15b7df1e57db4160..0c829981ea9ea9b2d8d53923470f0d273269d1ab 100644 (file)
@@ -1,3 +1,3 @@
-<?php # This file has been generated at:  Mon Apr 1 18:30:54 IDT 2013
+<?php # This file has been generated at:  Sat Apr 13 17:41:19 MSK 2013
 define('GENERATED_CONFIG_CHECK', 26);
-$requred_defines = array( 'DB_TYPE', 'DB_HOST', 'DB_USER', 'DB_NAME', 'DB_PASS', 'MYSQL_CHARSET', 'SELF_URL_PATH', 'SINGLE_USER_MODE', 'SIMPLE_UPDATE_MODE', 'PHP_EXECUTABLE', 'LOCK_DIRECTORY', 'CACHE_DIR', 'ICONS_DIR', 'ICONS_URL', 'AUTH_AUTO_CREATE', 'AUTH_AUTO_LOGIN', 'FORCE_ARTICLE_PURGE', 'PUBSUBHUBBUB_HUB', 'PUBSUBHUBBUB_ENABLED', 'SPHINX_ENABLED', 'SPHINX_INDEX', 'ENABLE_REGISTRATION', 'REG_NOTIFY_ADDRESS', 'REG_MAX_USERS', 'SESSION_COOKIE_LIFETIME', 'SESSION_CHECK_ADDRESS', 'SMTP_FROM_NAME', 'SMTP_FROM_ADDRESS', 'DIGEST_SUBJECT', 'SMTP_HOST', 'SMTP_PORT', 'SMTP_LOGIN', 'SMTP_PASSWORD', 'CHECK_FOR_NEW_VERSION', 'ENABLE_GZIP_OUTPUT', 'PLUGINS', 'CONFIG_VERSION'); ?>
+$requred_defines = array( 'DB_TYPE', 'DB_HOST', 'DB_USER', 'DB_NAME', 'DB_PASS', 'MYSQL_CHARSET', 'SELF_URL_PATH', 'FEED_CRYPT_KEY', 'SINGLE_USER_MODE', 'SIMPLE_UPDATE_MODE', 'PHP_EXECUTABLE', 'LOCK_DIRECTORY', 'CACHE_DIR', 'ICONS_DIR', 'ICONS_URL', 'AUTH_AUTO_CREATE', 'AUTH_AUTO_LOGIN', 'FORCE_ARTICLE_PURGE', 'PUBSUBHUBBUB_HUB', 'PUBSUBHUBBUB_ENABLED', 'SPHINX_ENABLED', 'SPHINX_INDEX', 'ENABLE_REGISTRATION', 'REG_NOTIFY_ADDRESS', 'REG_MAX_USERS', 'SESSION_COOKIE_LIFETIME', 'SESSION_CHECK_ADDRESS', 'SMTP_FROM_NAME', 'SMTP_FROM_ADDRESS', 'DIGEST_SUBJECT', 'SMTP_HOST', 'SMTP_PORT', 'SMTP_LOGIN', 'SMTP_PASSWORD', 'CHECK_FOR_NEW_VERSION', 'ENABLE_GZIP_OUTPUT', 'PLUGINS', 'CONFIG_VERSION'); ?>
index 3b6a1f544fadb3fbd765e853ddaf07a63b36efee..1aae5da831ffad68ef0eab81c0212a1a4d519747 100644 (file)
 <body>
 
 <?php
+       function make_password($length = 8) {
+
+               $password = "";
+               $possible = "0123456789abcdfghjkmnpqrstvwxyzABCDFGHJKMNPQRSTVWXYZ*%+^";
+
+       $i = 0;
+
+               while ($i < $length) {
+                       $char = substr($possible, mt_rand(0, strlen($possible)-1), 1);
+
+                       if (!strstr($password, $char)) {
+                               $password .= $char;
+                               $i++;
+                       }
+               }
+               return $password;
+       }
+
+
        function sanity_check($db_type) {
                $errors = array();
 
 
                $finished = false;
 
+               if (function_exists("mcrypt_decrypt")) {
+                       $crypt_key = make_password(24);
+               } else {
+                       $crypt_key = "";
+               }
+
                foreach ($data as $line) {
                        if (preg_match("/define\('DB_TYPE'/", $line)) {
                                $rv .= "\tdefine('DB_TYPE', '$DB_TYPE');\n";
                                $rv .= "\tdefine('DB_PORT', '$DB_PORT');\n";
                        } else if (preg_match("/define\('SELF_URL_PATH'/", $line)) {
                                $rv .= "\tdefine('SELF_URL_PATH', '$SELF_URL_PATH');\n";
+                       } else if (preg_match("/define\('FEED_CRYPT_KEY'/", $line)) {
+                               $rv .= "\tdefine('FEED_CRYPT_KEY', '$crypt_key');\n";
                        } else if (!$finished) {
                                $rv .= "$line\n";
                        }