Index: salesforce/README.txt
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/salesforce/README.txt,v
retrieving revision 1.4.6.12
diff -u -p -r1.4.6.12 README.txt
--- salesforce/README.txt	8 Jun 2010 21:08:11 -0000	1.4.6.12
+++ salesforce/README.txt	4 Jul 2010 01:57:27 -0000
@@ -43,6 +43,17 @@ REQUIREMENTS
   http://php.net/soap
 
 
+RECOMMENDED
+-----------
+ 
+  1) Download and install your organization's generated Enterprise WSDL file. 
+     (see WORKING WITH WSDL FILES)
+ 
+  2) AES encryption 
+    http://drupal.org/project/aes
+    (see SOME NOTES ABOUT SECURITY).
+    
+
 INSTALLATION
 ------------
   1) Download, uncompress and situate the module as per usual.
@@ -132,6 +143,20 @@ EXPORT QUEUE
   administrators maximum flexibility in setting up the queue.
 
 
+SOME NOTES ABOUT SECURITY
+--------------------------
+  By default all SalesForce credentials are stored in the variables table, 
+  unencrypted. If this is a problem for you, this module supports encryption via  
+  aes module http://drupal.org/project/aes. You will need to create a directory
+  outside your webroot (you can use the same one you used for your WSDL) wherein
+  your encryption key will be stored. Your credentials will thus forth be 
+  encrypted as securely as AES allows. PLEASE NOTE: your data is still only as 
+  secure as your network. It may be possible for a savvy attacker to access your
+  data at any of various points between your Drupal site and SalesForce.com. As 
+  this always, you should educate yourself about the risks involved before storing
+  and transferring sensitive data across the internet.
+
+
 WORKING WITH WSDL FILES
 -----------------------
   If you do not upload a WSDL file, Salesforce module will use a default .wsdl
Index: salesforce/salesforce_api/salesforce_api.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/salesforce/salesforce_api/salesforce_api.admin.inc,v
retrieving revision 1.2.2.34
diff -u -p -r1.2.2.34 salesforce_api.admin.inc
--- salesforce/salesforce_api/salesforce_api.admin.inc	8 Jun 2010 21:08:11 -0000	1.2.2.34
+++ salesforce/salesforce_api/salesforce_api.admin.inc	4 Jul 2010 01:57:27 -0000
@@ -10,7 +10,7 @@
 /**
  * The settings form at admin/settings/salesforce.
  */
-function salesforce_api_settings_form() {
+function salesforce_api_settings_form($form_state) {
   $form = array();
 
   // Use the username field to collapse the API settings fieldset.
@@ -25,25 +25,60 @@ function salesforce_api_settings_form() 
     '#weight' => -10,
   );
   $form['api']['salesforce_api_username'] = array(
-    '#type' => 'textfield',
+    '#type' => 'password',
     '#title' => t('Username'),
     '#description' => t('Should be in the form of an e-mail address.'),
-    '#default_value' => variable_get('salesforce_api_username', ''),
-    '#required' => TRUE,
+    '#default_value' => $form_state['values']['salesforce_api_username'],
+    '#required' => !variable_get('salesforce_api_username', FALSE),
   );
   $form['api']['salesforce_api_password'] = array(
     '#type' => 'password',
     '#title' => t('Password'),
     '#description' => t('Enter the password used when logging into Salesforce.'),
-    '#default_value' => variable_get('salesforce_api_password', ''),
+    '#default_value' => $form_state['values']['salesforce_api_password'],
+    '#required' => !variable_get('salesforce_api_password', FALSE),
   );
   $form['api']['salesforce_api_token'] = array(
-    '#type' => 'textfield',
+    '#type' => 'password',
     '#title' => t('Security token'),
-    '#description' => t('Set your security token by logging into Salesforce and navigating to Setup > My Personal Information > Reset My Security Token.'),
-    '#required' => TRUE,
-    '#default_value' => variable_get('salesforce_api_token', ''),
-  );
+    '#description' => t('Set your security token by logging into Salesforce and 
+      navigating to Setup > My Personal Information > Reset My Security Token.'),
+    '#default_value' => $form_state['values']['salesforce_api_token'],
+    '#required' => !variable_get('salesforce_api_token', FALSE),
+  );
+
+  if (!empty($username)) {
+    $form['api']['#description'] = 
+      t('Salesforce.com connection is working properly.<br />Edit the following
+        fields only if you wish to change your login credentials.');
+    $form['api']['salesforce_api_reset_credentials'] = array(
+      '#type' => 'checkbox',
+      '#title' => 'Clear SalesForce API credentials',
+      '#description' => 'Erase current API login settings. Clearing SalesForce 
+        API credentials will prevent your website from connecting to Salesforce.com',
+      );
+  }
+  $form['api']['encryption'] = array(
+    '#type' => 'item',
+    '#title' => 'Encryption',
+    '#value' => t('It is highly recommended that you use encryption to protect your SalesForce.com credentials. Encryption is supported via <a href="http://drupal.org/project/aes">AES module</a>.'),
+    'status' => array('#type' => 'item', '#title' => FALSE),
+    );
+  if (salesforce_api_encryption_available(array('display_all' => TRUE))) {
+    $form['api']['encryption']['status']['#value'] =
+      'Encryption is available and configured properly.';
+    $form['api']['encryption']['salesforce_api_encrypt'] = array(
+      '#type' => 'checkbox',
+      '#title' => 'Encrypt SalesForce credentials (HIGHLY RECOMMENDED)',
+      '#description' => 'Note: enabling this setting will not encrypt existing credentials.',
+      '#default_value' => TRUE,
+    );
+  }
+  else {
+    $form['api']['encryption']['status']['#value'] = 
+      '<span class="error">AES is not installed - encryption is not
+      available.</span>';
+  }
 
   $form['log'] = array(
     '#type' => 'fieldset',
@@ -102,11 +137,11 @@ function salesforce_api_settings_form() 
   $wsdl_dir = variable_get('salesforce_api_dir_wsdl', FALSE);
   $form['wsdl'] = array(
     '#type' => 'fieldset',
-    '#title' => 'WSDL directory',
-    '#description' => 'Your organization\'s WSDL file can expose potentially sensitive information. It is highly recommended that your WSDL file be stored outside your webroot. Please enter either a path relative to your webroot (e.g. ../wsdl) or a fully qualified path (e.g. /home/username/wsdl) in which to store your WSDL.',
+    '#title' => t('WSDL directory'),
+    '#description' => t('Your organization\'s WSDL file can expose potentially sensitive information. It is highly recommended that your WSDL file be stored outside your webroot. Please enter either a path relative to your webroot (e.g. ../wsdl) or a fully qualified path (e.g. /home/username/wsdl) in which to store your WSDL.'),
     'salesforce_api_dir_wsdl' => array(
       '#type' => 'textfield',
-      '#title' => 'WSDL Directory',
+      '#title' => t('WSDL Directory'),
       '#default_value' => $wsdl_dir,
       ),
     '#collapsible' => TRUE,
@@ -121,21 +156,56 @@ function salesforce_api_settings_form() 
 }
 
 /**
- * Settings form validate handler to verify new salesforce credentials before saving them.
+ * Settings form validate handler to verify new salesforce credentials before
+ * saving them.
  */
 function salesforce_api_settings_form_validate($form, &$form_state) {
   $values = $form_state['values'];
-  if (!salesforce_api_connect($values['salesforce_api_username'], $values['salesforce_api_password'], $values['salesforce_api_token'], TRUE)) {
-    // If not, prevent the user from overwriting the current configuration.
-    form_set_error('salesforce_api_username', t('Unable to connect to Salesforce. Please check your credentials.'));
+
+  if (isset($values['salesforce_api_dir_wsdl'])
+  && !file_exists($values['salesforce_api_dir_wsdl'])) {
+    form_set_error('salesforce_api_dir_wsdl', 'The specified WSDL directory does not exist. Please make sure the directory exists, check your input, and try again.');
   }
-  else {
-    drupal_set_message(t('Salesforce connection established.'));
+  
+  // If we are clearing values, no need to continue validation.
+  if ($values['salesforce_api_reset_credentials']) {
+    return;
   }
 
-  if (isset($form_state['values']['salesforce_api_dir_wsdl'])
-  && !file_exists($form_state['values']['salesforce_api_dir_wsdl'])) {
-    form_set_error('salesforce_api_dir_wsdl', 'The specified directory does not exist. Please make sure the directory exists, check your input, and try again.');
+  foreach (array('salesforce_api_username', 'salesforce_api_password', 'salesforce_api_token') as $value) {
+    if (empty($values[$value])) {
+      $errors[$value] = ucwords(str_replace('salesforce_api_', ' ', $value)) . ' is required';
+    }
+  }
+    
+  if (count($errors) == 3) {
+    // If all 3 fields are empty, the user has not tried to change credentials.
+    // Unset the form values in order to preserve existing credentials.
+    unset($form_state['values']['salesforce_api_username'],
+          $form_state['salesforce_api_password'],         
+          $form_state['values']['salesforce_api_token']);
+    return;
+  }
+  elseif (!empty($errors)) {
+    drupal_set_message(t('Unable to reset SalesForce API credentials.'), 'error');
+    foreach ($errors as $field => $error) {
+      form_set_error($field, $error);
+    }
+    // If we got errors already no need to continue with validation.
+    return;
+  }
+  
+  // If we are setting or resetting values, test the connection.
+  $connection = salesforce_api_connect($values['salesforce_api_username'], 
+    $values['salesforce_api_password'], $values['salesforce_api_token'], TRUE);
+  if (is_object($connection)) {
+     drupal_set_message(t('Connection established. SalesForce credentials updated.'));
+  } else {
+    drupal_set_message(
+      t('Resetting SalesForce API credentials failed.', 'error'));
+    form_set_error('salesforce_api_username', t('Unable to connect to Salesforce. Please check your credentials.'));
+    form_set_error('salesforce_api_password');
+    form_set_error('salesforce_api_token');
   }
 }
 
@@ -143,22 +213,37 @@ function salesforce_api_settings_form_va
  * Settings form submit handler so that password doesn't get deleted.
  */
 function salesforce_api_settings_form_submit($form, &$form_state) {
-  // If the user hit "Save Configuration" and the required field
-  // salesforce_api_password is blank, try to get it from variables
-  if ($form_state['values']['submit'] == $form_state['values']['op'] and empty($form_state['values']['salesforce_api_password'])) {
-    $pass = variable_get('salesforce_api_password', FALSE);
-    if (isset($pass)) {
-      $form_state['values']['salesforce_api_password'] = $pass;
-    }
-  }
-  if (variable_get('salesforce_api_dir_wsdl', FALSE) !=
-      $form_state['values']['salesforce_api_dir_wsdl']) {
+  $values = $form_state['values'];
+
+  if (variable_get('salesforce_api_dir_wsdl', FALSE) 
+  != $values['salesforce_api_dir_wsdl']) {
     drupal_set_message('Please make sure the WSDL directory is writeable, and upload a valid SalesForce .xml or .wsdl file.');
     $form_state['redirect'] = array(
       SALESFORCE_PATH_UPDATE_WSDL,
       'destination=' . SALESFORCE_PATH_ADMIN);
     ini_set('soap.wsdl_cache_enabled',  '0');
   }
+
+  if ($values['salesforce_api_reset_credentials']) {
+    unset($form_state['values']['salesforce_api_reset_credentials']);
+    foreach (array('username', 'password', 'token', 'encrypt') as $value) {
+      variable_del('salesforce_api_' . $value);
+      unset($form_state['values']['salesforce_api_' . $value]);
+    }
+    drupal_set_message('SalesForce credentials reset.');
+    // If credentials were reset, we don't need to continue to encryption.
+    return;
+  }
+
+  if ($values['salesforce_api_encrypt']
+  && !empty($values['salesforce_api_username'])) {
+    $form_state['values']['salesforce_api_username'] =
+      salesforce_api_encrypt($values['salesforce_api_username']);
+    $form_state['values']['salesforce_api_password'] =
+      salesforce_api_encrypt($values['salesforce_api_password']);
+    $form_state['values']['salesforce_api_token'] =
+      salesforce_api_encrypt($values['salesforce_api_token']);
+  }
 }
 
 /**
Index: salesforce/salesforce_api/salesforce_api.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/salesforce/salesforce_api/salesforce_api.install,v
retrieving revision 1.2.2.20
diff -u -p -r1.2.2.20 salesforce_api.install
--- salesforce/salesforce_api/salesforce_api.install	7 Jun 2010 17:57:24 -0000	1.2.2.20
+++ salesforce/salesforce_api/salesforce_api.install	4 Jul 2010 01:57:28 -0000
@@ -166,6 +166,14 @@ function salesforce_api_requirements($ph
         $description = t('Unable to connect to Salesforce using <a href="!url">current credentials</a>.', array('!url' => url(SALESFORCE_PATH_ADMIN)));
         $severity = REQUIREMENT_ERROR;
       }
+      elseif (!salesforce_api_encryption_available(array('check_config' => FALSE))) {
+        $description = t('Encryption is unavailable. Using encryption is <strong>highly recommended</strong> in order to better secure your data.');
+        $severity = REQUIREMENT_ERROR;
+      }
+      elseif (!salesforce_api_encryption_available(array('check_config' => TRUE))) {
+        $description = t('SalesForce encryption is enabled but not configured securely.');
+        $severity = REQUIREMENT_WARNING;
+      }
       else {
         $description = '';
         $severity = REQUIREMENT_OK;
Index: salesforce/salesforce_api/salesforce_api.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/salesforce/salesforce_api/salesforce_api.module,v
retrieving revision 1.2.2.48
diff -u -p -r1.2.2.48 salesforce_api.module
--- salesforce/salesforce_api/salesforce_api.module	8 Jun 2010 21:08:11 -0000	1.2.2.48
+++ salesforce/salesforce_api/salesforce_api.module	4 Jul 2010 01:57:28 -0000
@@ -268,13 +268,25 @@ function salesforce_api_connect($usernam
     return $sf;
   }
 
-  // Boolean, whether we are connecting with the default website user or not.
-  $default_site_user = $username == variable_get('salesforce_api_username', FALSE);
+  // Load up the sitewide API credentials if none were provided.
+  $encrypted = variable_get('salesforce_api_encrypt', FALSE);
+  $default_username = $encrypted
+    ? salesforce_api_decrypt(variable_get('salesforce_api_username', ''))
+    : variable_get('salesforce_api_username', '');
+  $username = $username ? $username : $default_username;
+  $password = $password
+    ? $password
+    : ($encrypted 
+        ? salesforce_api_decrypt(variable_get('salesforce_api_password', ''))
+        : variable_get('salesforce_api_password', ''));
+  $token = $token
+    ? $token
+    : ($encrypted 
+        ? salesforce_api_decrypt(variable_get('salesforce_api_token', ''))
+        : variable_get('salesforce_api_token', ''));
 
-  // Load up the sitewide API credentials if no others were provided:
-  $username = $username ? $username : variable_get('salesforce_api_username', '');
-  $password = $password ? $password : variable_get('salesforce_api_password', '');
-  $token = $token ? $token : variable_get('salesforce_api_token', '');
+  // Boolean, whether we are connecting with the default website user or not.
+  $default_site_user = $username == $default_username;
 
   // Include the file that defines the class.
   require_once(drupal_get_path('module', 'salesforce_api') .'/salesforce.class.inc');
@@ -984,6 +996,68 @@ function salesforce_api_cron() {
   return;
 }
 
+/**
+ * Wrappers for encryption lib. Right now only AES encryption is supported.
+ * If/when other methods are supported, this abstraction layer will make the 
+ * transition easier.
+ */
+function salesforce_api_decrypt($value) {
+  return aes_decrypt($value);
+}
+function salesforce_api_encrypt($value) {
+  return aes_encrypt($value);
+}
+function salesforce_api_encryption_available($options = array()) {
+  $defaults = array(
+    'check_config' => TRUE,
+    'display_errors' => FALSE,
+    'display_warnings' => FALSE,
+    'display_all' => FALSE,
+    'fail_threshold' => 'warnings',
+    );
+  $options = array_merge($defaults, $options);
+  extract($options);
+  $errors = array();
+  $warnings = array();
+  
+  if (!module_exists('aes')) {
+    $errors[] = 'AES Encryption module is not installed.';
+  }
+  elseif ($check_config) {
+    if (!variable_get('aes_key_path', FALSE)
+    || variable_get('aes_key_storage_method', FALSE) != 'File') {
+      $warnings[] = 'AES Encryption is installed but not configured securely.
+        Please go <a href="/admin/settings/aes">configure AES Encryption to use
+        file storage</a> to enable encryption for SalesForce credentials.';
+    }
+  }
+  
+  if ($display_errors || $display_all) {
+    foreach ($errors as $msg) {
+      drupal_set_message(t($msg), 'error');
+    }
+  }
+  
+  if ($display_warnings || $display_all) {
+    foreach ($warnings as $msg) {
+      drupal_set_message(t($msg), 'warning');
+    }
+  }
+  
+  switch ($fail_threshold) {
+    case 'errors': {
+      if (empty($errors)) {
+        return TRUE;
+      }
+    }
+    case 'warnings': {
+      if (empty($errors) && empty($warnings)) {
+        return TRUE;
+      }
+    }
+  }
+  return FALSE;
+}
 
 /**
  * Wrapper for SOAP SforceBaseClient::describeSObject