Commit 5662dae7 authored by Stefaan Lippens's avatar Stefaan Lippens
Browse files

refactored CAPTCHA point administration (changing challenge type, disabling, deleting):

* added confirmation dialog for deleting/disabling a CAPTCHA point (previously just a GET request was needed for disabling a CAPTCHA, which is not so secure)
* #214557: added form for adding a CAPTCHA point by hand
parent d90dd51f
......@@ -108,6 +108,17 @@ function captcha_update_2() {
return $items;
}
/**
* Implementation of hook_update_N()
*/
function captcha_update_3() {
// Clearing of the menu cache is needed because the internal menu structure
// of the CAPTCHA module changed a bit.
// Because update.php does menu cache clearing automatically,
// we just do nothing here except returning an empty array.
return array();
}
/**
* Remove tables on uninstall.
*/
......
......@@ -56,7 +56,8 @@ function captcha_menu($may_cache) {
'path' => 'admin/user/captcha',
'title' => t('CAPTCHA'),
'description' => t('Administer how and where CAPTCHAs are used.'),
'callback' => 'captcha_admin',
'callback' => 'drupal_get_form',
'callback arguments' => array('captcha_admin_settings'),
'access' => user_access('administer CAPTCHA settings'),
'type' => MENU_NORMAL_ITEM,
);
......@@ -82,6 +83,36 @@ function captcha_menu($may_cache) {
'type' => MENU_LOCAL_TASK,
'weight' => 5,
);
// form for adding/editing CAPTCHA points
$items[] = array(
'path' => 'admin/user/captcha/captcha/captcha_point',
'title' => t('Set CAPTCHA point'),
'description' => t('Add or edit form_id\'s to protect with a CAPTCHA.'),
'callback' => 'drupal_get_form',
'callback arguments' => array('captcha_point_admin_form'),
'type' => MENU_LOCAL_TASK,
'weight' => 2,
);
}
else {
// Some non cachable menu items for disabling/deleting CAPTCHA points
// start with arg(4) == 'captcha_point' for faster short circuit
if (arg(4) == 'captcha_point' && arg(0) == 'admin' && arg(1) == 'user' && arg(2) == 'captcha' && arg(3) == 'captcha' && !is_null(arg(5))) {
$items[] = array(
'path' => 'admin/user/captcha/captcha/captcha_point/'. arg(5) .'/disable',
'title' => t('Disable'),
'callback' => 'drupal_get_form',
'callback arguments' => array('captcha_point_disable_confirm', arg(5), FALSE),
'type' => MENU_CALLBACK,
);
$items[] = array(
'path' => 'admin/user/captcha/captcha/captcha_point/'. arg(5) .'/delete',
'title' => t('Delete'),
'callback' => 'drupal_get_form',
'callback arguments' => array('captcha_point_disable_confirm', arg(5), TRUE),
'type' => MENU_CALLBACK,
);
}
}
return $items;
}
......@@ -93,7 +124,6 @@ function captcha_perm() {
return array('administer CAPTCHA settings', 'skip CAPTCHA');
}
/**
* Implementation of hook_requirements().
*/
......@@ -161,48 +191,6 @@ function _captcha_get_description($lang_code=NULL) {
return $description;
}
/**
* General CAPTCHA settings handler. Main entry point for CAPTCHA management.
*
* If arguments are given: first argument is used as form_id, the second one
* is interpreted as action (such as disable, delete and enable) to execute on
* the form_id.
* Otherwise: returns the general CAPTCHA configuration form.
*/
function captcha_admin($form_id='', $op='') {
// if $form_id and action $op given: do the action
if ($form_id) {
switch ($op) {
case 'disable':
// disable the CAPTCHA for the form: set the module and type to NULL
db_query("UPDATE {captcha_points} SET module = NULL, type = NULL WHERE form_id = '%s'", $form_id);
drupal_set_message(t('Disabled CAPTCHA for form %form_id.', array('%form_id' => $form_id)));
// goto the CAPTCHA administration or alternative destination if present in URI
drupal_goto('admin/user/captcha');
break;
case 'delete':
db_query("DELETE FROM {captcha_points} WHERE form_id = '%s'", $form_id);
drupal_set_message(t('Deleted CAPTCHA for form %form_id.', array('%form_id' => $form_id)));
// goto the CAPTCHA administration or alternative destination if present in URI
drupal_goto('admin/user/captcha');
break;
case 'enable':
db_query("DELETE FROM {captcha_points} WHERE form_id = '%s'", $form_id);
db_query("INSERT INTO {captcha_points} (form_id, module, type) VALUES ('%s', NULL, NULL)", $form_id);
// No drupal_goto() call because we have to go to the CAPTCHA administration
// form and not a different destination if that would be present in the
// URI. So we call this form explicitly. The destination will be preserved
// so after completing the form, the user will still be redirected.
return drupal_get_form('captcha_captcha_point_settings_form', $form_id);
break;
}
// return edit form for individual form (aka CAPTCHA point)
return drupal_get_form('captcha_captcha_point_settings_form', $form_id);
}
// no $form_id or legal action given: generate general CAPTCHA settings form
return drupal_get_form('captcha_admin_settings');
}
/**
* Form builder function for the general CAPTCHA configuration
*/
......@@ -218,7 +206,9 @@ function captcha_admin_settings() {
$form['captcha_types'] = array(
'#type' => 'fieldset',
'#title' => t('Challenge type per form'),
'#description' => t('Select the challenge type you want for each of the listed forms (identified by their so called <em>form_id</em>\'s). You can easily add arbitrary forms with the help of the \'%CAPTCHA_admin_links\' option.', array('%CAPTCHA_admin_links' => t('Add CAPTCHA administration links to forms'))),
'#description' => t('Select the challenge type you want for each of the listed forms (identified by their so called <em>form_id</em>\'s). You can easily add arbitrary forms with the help of the \'%CAPTCHA_admin_links\' option or the <a href="!add_captcha_point">the CAPTCHA point form</a>.',
array('%CAPTCHA_admin_links' => t('Add CAPTCHA administration links to forms'),
'!add_captcha_point' => url('admin/user/captcha/captcha/captcha_point'))),
'#tree' => TRUE,
'#collapsible' => TRUE,
'#collapsed' => FALSE,
......@@ -240,7 +230,7 @@ function captcha_admin_settings() {
// additional operations
$form['captcha_types'][$captcha_point->form_id]['operations'] = array(
'#value' => implode(", ", array(
l(t('delete'), "admin/user/captcha/{$captcha_point->form_id}/delete"),
l(t('delete'), "admin/user/captcha/captcha/captcha_point/{$captcha_point->form_id}/delete"),
))
);
}
......@@ -344,63 +334,130 @@ function captcha_admin_settings_submit($form_id, $form_values) {
}
}
/**
* form generating function for CAPTCHA point settings
*/
function captcha_captcha_point_settings_form($form_id) {
$result = db_query("SELECT * FROM {captcha_points} WHERE form_id = '%s'", $form_id);
$captcha_point = db_fetch_object($result);
if ($captcha_point) {
$form = array();
function captcha_point_admin_form($captcha_point_form_id=NULL) {
$form = array();
$default_captcha_type = 'none';
if (isset($captcha_point_form_id)) {
// use given CAPTCHA point form_id
$form['captcha_point_form_id'] = array(
'#type' => 'hidden',
'#value' => $captcha_point->form_id,
);
// select widget for CAPTCHA type
$form['captcha_type'] = array(
'#type' => 'select',
'#title' => t('Select the challenge for @form_id', array('@form_id' => $form_id)),
'#default_value' => "{$captcha_point->module}/{$captcha_point->type}",
'#options' => _captcha_available_challenge_types(),
);
// submit button
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
'#type' => 'textfield',
'#title' => t('Form ID'),
'#description' => t('The Drupal form_id of the form to add the CAPTCHA to.'),
'#value' => check_plain($captcha_point_form_id),
'#disabled' => TRUE,
);
// cancel button
$form['cancel'] = array(
'#type' => 'submit',
'#value' => t('Cancel'),
$result = db_query("SELECT * FROM {captcha_points} WHERE form_id = '%s'", $captcha_point_form_id);
$captcha_point = db_fetch_object($result);
if ($captcha_point) {
$default_captcha_type = "{$captcha_point->module}/{$captcha_point->type}";
}
}
else {
// textfield for CAPTCHA point form_id
$form['captcha_point_form_id'] = array(
'#type' => 'textfield',
'#title' => t('Form ID'),
'#description' => t('The Drupal form_id of the form to add the CAPTCHA to.'),
);
return $form;
}
// select widget for CAPTCHA type
$form['captcha_type'] = array(
'#type' => 'select',
'#title' => t('Challenge type'),
'#description' => t('The CAPTCHA type to use for this form'),
'#default_value' => $default_captcha_type,
'#options' => _captcha_available_challenge_types(),
);
// redirect to general CAPTCHA settings page after submission
$form['#redirect'] = 'admin/user/captcha';
// submit button
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save'),
);
return $form;
}
/**
* validation function for captcha_point_admin_form
*/
function captcha_point_admin_form_validate($form, $form_values) {
if (!preg_match('/^[a-z0-9_]+$/', $form_values['captcha_point_form_id'])) {
form_set_error('captcha_point_form_id', t('Illegal form_id'));
}
}
/**
* submit function for captcha_point_admin_form
*/
function captcha_point_admin_form_submit($form, $form_values) {
$captcha_point_form_id = $form_values['captcha_point_form_id'];
$captcha_type = $form_values['captcha_type'];
// remove old settings
db_query("DELETE FROM {captcha_points} WHERE form_id = '%s'", $captcha_point_form_id);
// save new settings
if ($captcha_type == 'none') {
db_query("INSERT INTO {captcha_points} (form_id, module, type) VALUES ('%s', NULL, NULL)", $captcha_point_form_id);
}
else {
list($module, $type) = explode('/', $captcha_type);
db_query("INSERT INTO {captcha_points} (form_id, module, type) VALUES ('%s', '%s', '%s')", $captcha_point_form_id, $module, $type);
}
drupal_set_message(t('Saved CAPTCHA point settings.'), 'status');
}
/**
* Confirm dialog for disabling/deleting a CAPTCHA point
*
* @param $captcha_point_form_id the form_id of the form to disable the CAPTCHA
* from
* @param $delete boolean for also deleting the CAPTCHA point
*/
function captcha_point_disable_confirm($captcha_point_form_id, $delete) {
$form = array();
$form['captcha_point_form_id'] = array(
'#type' => 'value',
'#value' => $captcha_point_form_id,
);
$form['captcha_point_delete'] = array(
'#type' => 'value',
'#value' => $delete,
);
if ($delete) {
$message = t('Are you sure you want to delete the CAPTCHA for form_id %form_id?', array('%form_id' => $captcha_point_form_id));
$yes = t('Delete');
}
else {
// illegal form_id
drupal_set_message(t('Unavailable form_id %form_id ', array('%form_id' => $form_id)), 'error');
// goto the CAPTCHA administration or alternative destination if present in URI
drupal_goto('admin/user/captcha');
$message = t('Are you sure you want to disable the CAPTCHA for form_id %form_id?', array('%form_id' => $captcha_point_form_id));
$yes = t('Disable');
}
return confirm_form($form, $message, isset($_GET['destination']) ? $_GET['destination'] : 'admin/user/captcha/captcha', '', $yes);
}
/**
* submit function for captcha_captcha_point_settings_form
* submission handler of CAPTCHA point disabling/deleting confirm_form
*/
function captcha_captcha_point_settings_form_submit($form_id, $form_values) {
if ($form_id == 'captcha_captcha_point_settings_form' && $form_values['op'] == t('Submit')) {
$captcha_point_form_id = $form_values['captcha_point_form_id'];
$captcha_type = $form_values['captcha_type'];
if ($captcha_type == 'none') {
db_query("UPDATE {captcha_points} SET module = NULL, type = NULL WHERE form_id = '%s'", $captcha_point_form_id);
}
else {
list($module, $type) = explode('/', $captcha_type);
db_query("UPDATE {captcha_points} SET module = '%s', type = '%s' WHERE form_id = '%s'", $module, $type, $captcha_point_form_id);
}
drupal_set_message(t('Saved CAPTCHA settings.'), 'status');
function captcha_point_disable_confirm_submit($form, $form_values) {
$captcha_point_form_id = $form_values['captcha_point_form_id'];
$delete = $form_values['captcha_point_delete'];
if ($delete) {
db_query("DELETE FROM {captcha_points} WHERE form_id = '%s'", $captcha_point_form_id);
drupal_set_message(t('Deleted CAPTCHA for form %form_id.', array('%form_id' => $captcha_point_form_id)));
}
else {
db_query("UPDATE {captcha_points} SET module = NULL, type = NULL WHERE form_id = '%s'", $captcha_point_form_id);
drupal_set_message(t('Disabled CAPTCHA for form %form_id.', array('%form_id' => $captcha_point_form_id)));
}
// redirect to CAPTCHA admin
return 'admin/user/captcha';
}
/**
* Helper function for checking if the CAPTCHA for the given form_id should
* be skipped because of CAPTCHA persistence.
......@@ -542,14 +599,14 @@ function captcha_form_alter($form_id, &$form) {
'#value' => t('"@type" by module "@module" (!change, !disable)', array(
'@type' => $captcha_point->type,
'@module' => $captcha_point->module,
'!change' => l(t('change'), "admin/user/captcha/$form_id", array(), drupal_get_destination()),
'!disable' => l(t('disable'), "admin/user/captcha/$form_id/disable", array(), drupal_get_destination()),
'!change' => l(t('change'), "admin/user/captcha/captcha/captcha_point/$form_id", array(), drupal_get_destination()),
'!disable' => l(t('disable'), "admin/user/captcha/captcha/captcha_point/$form_id/disable", array(), drupal_get_destination()),
)),
);
}
else {
$form['captcha']['add_captcha'] = array(
'#value' => l(t('Place a CAPTCHA here for untrusted users.'), "admin/user/captcha/$form_id/enable", array(), drupal_get_destination())
'#value' => l(t('Place a CAPTCHA here for untrusted users.'), "admin/user/captcha/captcha/captcha_point/$form_id", array(), drupal_get_destination())
);
}
// Add pre_render function for placing the CAPTCHA just above the submit button
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment