Merge branch 'FS#2751' of git://github.com/splitbrain/dokuwiki into pull-request-245

* 'FS#2751' of git://github.com/splitbrain/dokuwiki:
  coding corrections. correct type hint, remove unused variable assignment
  de/de-informal: localization updates (delete user function)
  unit tests for self deleting of user accounts
  FS#2751 - self deletion of user account
This commit is contained in:
Andreas Gohr 2013-08-02 21:49:24 +02:00
commit 836a176267
13 changed files with 288 additions and 11 deletions

View File

@ -0,0 +1,179 @@
<?php
class Mock_Auth_Plugin extends DokuWiki_Auth_Plugin {
public $loggedOff = false;
public function __construct($canDeleteUser = true) {
$this->cando['delUser'] = $canDeleteUser;
}
public function checkPass($user, $pass) {
return $pass == 'password';
}
public function deleteUsers($users) {
return in_array($_SERVER['REMOTE_USER'], $users);
}
public function logoff() {
$this->loggedOff = true;
}
}
class auth_deleteprofile_test extends DokuWikiTest {
/*
* Tests:
*
* 1. It works and the user is logged off
* 2. Password matches when config requires it
* 3,4. Auth plugin can prevent & wiki config can prevent
* 5. Any of invalid security token, missing/not set 'delete' flag, missing/unchecked 'confirm_delete'
*
*/
function test_success() {
global $ACT, $INPUT, $conf, $auth;
$ACT = 'profile_delete';
$conf['profileconfirm'] = false;
$_SERVER['REMOTE_USER'] = 'testuser';
$input = array(
'do' => $ACT,
'sectok' => getSecurityToken(),
'delete' => '1',
'confirm_delete' => '1',
);
$_POST = $input;
$_REQUEST = $input;
$INPUT = new Input();
$auth = new Mock_Auth_Plugin();
$this->assertTrue(auth_deleteprofile());
$this->assertTrue($auth->loggedOff);
}
function test_confirmation_required() {
global $ACT, $INPUT, $conf, $auth;
$ACT = 'profile_delete';
$conf['profileconfirm'] = true;
$_SERVER['REMOTE_USER'] = 'testuser';
$input = array(
'do' => $ACT,
'sectok' => getSecurityToken(),
'delete' => '1',
'confirm_delete' => '1',
'oldpass' => 'wrong',
);
$_POST = $input;
$_REQUEST = $input;
$INPUT = new Input();
$auth = new Mock_Auth_Plugin();
// password check required - it fails, so don't delete profile
$this->assertFalse(auth_deleteprofile());
// now it passes, we're good to go
$INPUT->set('oldpass','password');
$INPUT->post->set('oldpass','password');
$this->assertTrue(auth_deleteprofile());
}
function test_authconfig_prevents() {
global $ACT, $INPUT, $conf, $auth;
$ACT = 'profile_delete';
$conf['profileconfirm'] = false;
$_SERVER['REMOTE_USER'] = 'testuser';
$input = array(
'do' => $ACT,
'sectok' => getSecurityToken(),
'delete' => '1',
'confirm_delete' => '1',
);
$_POST = $input;
$_REQUEST = $input;
$INPUT = new Input();
$auth = new Mock_Auth_Plugin(false);
$conf['disableactions'] = '';
$this->assertFalse(auth_deleteprofile());
}
function test_wikiconfig_prevents() {
global $ACT, $INPUT, $conf, $auth;
$ACT = 'profile_delete';
$conf['profileconfirm'] = false;
$_SERVER['REMOTE_USER'] = 'testuser';
$input = array(
'do' => $ACT,
'sectok' => getSecurityToken(),
'delete' => '1',
'confirm_delete' => '1',
);
$_POST = $input;
$_REQUEST = $input;
$INPUT = new Input();
$auth = new Mock_Auth_Plugin();
$conf['disableactions'] = 'profile_delete';
$this->assertFalse(actionOK('profile_delete'));
$this->assertTrue($auth->canDo('delUser'));
$this->assertFalse(auth_deleteprofile());
}
function test_basic_parameters() {
global $ACT, $INPUT, $conf, $auth;
$ACT = 'profile_delete';
$conf['profileconfirm'] = true;
$_SERVER['REMOTE_USER'] = 'testuser';
$input = array(
'do' => $ACT,
'sectok' => getSecurityToken(),
'delete' => '1',
'confirm_delete' => '1',
'oldpass' => 'password',
);
$_POST = $input;
$_REQUEST = $input;
$input_foundation = new Input();
$auth = new Mock_Auth_Plugin();
$INPUT = clone $input_foundation;
$INPUT->remove('delete');
$this->assertFalse(auth_deleteprofile());
$INPUT = clone $input_foundation;
$INPUT->set('sectok','wrong');
$this->assertFalse(auth_deleteprofile());
$INPUT = clone $input_foundation;
$INPUT->remove('confirm_delete');
$this->assertFalse(auth_deleteprofile());
}
}

View File

@ -92,14 +92,26 @@ function act_dispatch(){
$ACT = 'login';
}
//update user profile
if ($ACT == 'profile') {
// user profile changes
if (in_array($ACT, array('profile','profile_delete'))) {
if(!$_SERVER['REMOTE_USER']) {
$ACT = 'login';
} else {
if(updateprofile()) {
msg($lang['profchanged'],1);
$ACT = 'show';
switch ($ACT) {
case 'profile' :
if(updateprofile()) {
msg($lang['profchanged'],1);
$ACT = 'show';
}
break;
case 'profile_delete' :
if(auth_deleteprofile()){
msg($lang['profdeleted'],1);
$ACT = 'show';
} else {
$ACT = 'profile';
}
break;
}
}
}
@ -247,7 +259,7 @@ function act_validate($act) {
//disable all acl related commands if ACL is disabled
if(!$conf['useacl'] && in_array($act,array('login','logout','register','admin',
'subscribe','unsubscribe','profile','revert',
'resendpwd'))){
'resendpwd','profile_delete'))){
msg('Command unavailable: '.htmlspecialchars($act),-1);
return 'show';
}
@ -258,7 +270,7 @@ function act_validate($act) {
if(!in_array($act,array('login','logout','register','save','cancel','edit','draft',
'preview','search','show','check','index','revisions',
'diff','recent','backlink','admin','subscribe','revert',
'unsubscribe','profile','resendpwd','recover',
'unsubscribe','profile','profile_delete','resendpwd','recover',
'draftdel','sitemap','media')) && substr($act,0,7) != 'export_' ) {
msg('Command unknown: '.htmlspecialchars($act),-1);
return 'show';
@ -287,7 +299,7 @@ function act_permcheck($act){
}else{
$permneed = AUTH_CREATE;
}
}elseif(in_array($act,array('login','search','recent','profile','index', 'sitemap'))){
}elseif(in_array($act,array('login','search','recent','profile','profile_delete','index', 'sitemap'))){
$permneed = AUTH_NONE;
}elseif($act == 'revert'){
$permneed = AUTH_ADMIN;

View File

@ -1042,6 +1042,45 @@ function updateprofile() {
return false;
}
function auth_deleteprofile(){
global $conf;
global $lang;
/* @var DokuWiki_Auth_Plugin $auth */
global $auth;
/* @var Input $INPUT */
global $INPUT;
if(!$INPUT->post->bool('delete')) return false;
if(!checkSecurityToken()) return false;
// action prevented or auth module disallows
if(!actionOK('profile_delete') || !$auth->canDo('delUser')) {
msg($lang['profnodelete'], -1);
return false;
}
if(!$INPUT->post->bool('confirm_delete')){
msg($lang['profconfdeletemissing'], -1);
return false;
}
if($conf['profileconfirm']) {
if(!$auth->checkPass($_SERVER['REMOTE_USER'], $INPUT->post->str('oldpass'))) {
msg($lang['badpassconfirm'], -1);
return false;
}
}
$deleted[] = $_SERVER['REMOTE_USER'];
if($auth->triggerUserMod('delete', array($deleted))) {
// force and immediate logout including removing the sticky cookie
auth_logoff();
return true;
}
return false;
}
/**
* Send a new password
*

View File

@ -241,7 +241,7 @@ function getConfigFiles($type) {
*/
function actionOK($action){
static $disabled = null;
if(is_null($disabled)){
if(is_null($disabled) || defined('SIMPLE_TEST')){
global $conf;
/** @var auth_basic $auth */
global $auth;
@ -261,6 +261,9 @@ function actionOK($action){
if (is_null($auth) || !$auth->canDo('Profile')) {
$disabled[] = 'profile';
}
if (is_null($auth) || !$auth->canDo('delUser')) {
$disabled[] = 'profile_delete';
}
if (is_null($auth)) {
$disabled[] = 'login';
}

View File

@ -1390,6 +1390,23 @@ function html_updateprofile(){
$form->endFieldset();
html_form('updateprofile', $form);
if ($auth->canDo('delUser') && actionOK('profile_delete')) {
$form_profiledelete = new Doku_Form(array('id' => 'dw__profiledelete'));
$form_profiledelete->startFieldset($lang['profdeleteuser']);
$form_profiledelete->addHidden('do', 'profile_delete');
$form_profiledelete->addHidden('delete', '1');
$form_profiledelete->addElement(form_makeCheckboxField('confirm_delete', '1', $lang['profconfdelete'],'dw__confirmdelete','', array('required' => 'required')));
if ($conf['profileconfirm']) {
$form_profiledelete->addElement(form_makeTag('br'));
$form_profiledelete->addElement(form_makePasswordField('oldpass', $lang['oldpass'], '', 'block', array('size'=>'50', 'required' => 'required')));
}
$form_profiledelete->addElement(form_makeButton('submit', '', $lang['btn_deleteuser']));
$form_profiledelete->endFieldset();
html_form('profiledelete', $form_profiledelete);
}
print '</div>'.NL;
}

View File

@ -64,6 +64,7 @@ $lang['btn_revert'] = 'Wiederherstellen';
$lang['btn_register'] = 'Registrieren';
$lang['btn_apply'] = 'Übernehmen';
$lang['btn_media'] = 'Medien-Manager';
$lang['btn_deleteuser'] = 'Benutzerprofil löschen';
$lang['loggedinas'] = 'Angemeldet als';
$lang['user'] = 'Benutzername';
$lang['pass'] = 'Passwort';
@ -75,6 +76,7 @@ $lang['fullname'] = 'Voller Name';
$lang['email'] = 'E-Mail';
$lang['profile'] = 'Benutzerprofil';
$lang['badlogin'] = 'Nutzername oder Passwort sind falsch.';
$lang['badpassconfirm'] = 'Das Passwort war falsch.';
$lang['minoredit'] = 'Kleine Änderung';
$lang['draftdate'] = 'Entwurf gespeichert am';
$lang['nosecedit'] = 'Diese Seite wurde in der Zwischenzeit geändert, da das Sektionsinfo veraltet ist. Die ganze Seite wird stattdessen geladen.';
@ -91,6 +93,11 @@ $lang['profna'] = 'Änderung des Benutzerprofils in diesem Wiki n
$lang['profnochange'] = 'Keine Änderungen, nichts zu tun.';
$lang['profnoempty'] = 'Es muss ein Name oder eine E-Mail Adresse angegeben werden.';
$lang['profchanged'] = 'Benutzerprofil erfolgreich geändert.';
$lang['profnodelete'] = 'Dieses Wiki unterstützt nicht das Löschen von Benutzern.';
$lang['profdeleteuser'] = 'Benutzerprofil löschen';
$lang['profdeleted'] = 'Dein Benutzerprofil wurde im Wiki gelöscht.';
$lang['profconfdelete'] = 'Ich möchte mein Benutzerprofil löschen.<br/> Diese Aktion ist nicht umkehrbar.';
$lang['profconfdeletemissing'] = 'Bestätigungs-Checkbox wurde nicht angehakt.';
$lang['pwdforget'] = 'Passwort vergessen? Fordere ein neues an';
$lang['resendna'] = 'Passwörter versenden ist in diesem Wiki nicht möglich.';
$lang['resendpwd'] = 'Neues Passwort setzen für';

View File

@ -65,6 +65,7 @@ $lang['btn_revert'] = 'Wiederherstellen';
$lang['btn_register'] = 'Registrieren';
$lang['btn_apply'] = 'Übernehmen';
$lang['btn_media'] = 'Medien-Manager';
$lang['btn_deleteuser'] = 'Benutzerprofil löschen';
$lang['loggedinas'] = 'Angemeldet als';
$lang['user'] = 'Benutzername';
$lang['pass'] = 'Passwort';
@ -76,6 +77,7 @@ $lang['fullname'] = 'Voller Name';
$lang['email'] = 'E-Mail';
$lang['profile'] = 'Benutzerprofil';
$lang['badlogin'] = 'Nutzername oder Passwort sind falsch.';
$lang['badpassconfirm'] = 'Das Passwort war falsch.';
$lang['minoredit'] = 'kleine Änderung';
$lang['draftdate'] = 'Entwurf gespeichert am';
$lang['nosecedit'] = 'Diese Seite wurde in der Zwischenzeit geändert, Sektionsinfo ist veraltet, lade stattdessen volle Seite.';
@ -92,6 +94,11 @@ $lang['profna'] = 'Änderung des Benutzerprofils in diesem Wiki n
$lang['profnochange'] = 'Keine Änderungen, nichts zu tun.';
$lang['profnoempty'] = 'Es muss ein Name und eine E-Mail-Adresse angegeben werden.';
$lang['profchanged'] = 'Benutzerprofil erfolgreich geändert.';
$lang['profnodelete'] = 'Dieses Wiki unterstützt nicht das Löschen von Benutzern.';
$lang['profdeleteuser'] = 'Benutzerprofil löschen';
$lang['profdeleted'] = 'Ihr Benutzerprofil wurde im Wiki gelöscht.';
$lang['profconfdelete'] = 'Ich möchte mein Benutzerprofil löschen.<br/> Diese Aktion ist nicht umkehrbar.';
$lang['profconfdeletemissing'] = 'Bestätigungs-Checkbox wurde nicht angehakt.';
$lang['pwdforget'] = 'Passwort vergessen? Fordere ein neues an';
$lang['resendna'] = 'Passwörter versenden ist in diesem Wiki nicht möglich.';
$lang['resendpwd'] = 'Neues Passwort setzen für';

View File

@ -51,6 +51,7 @@ $lang['btn_revert'] = 'Restore';
$lang['btn_register'] = 'Register';
$lang['btn_apply'] = 'Apply';
$lang['btn_media'] = 'Media Manager';
$lang['btn_deleteuser'] = 'Remove My Account';
$lang['loggedinas'] = 'Logged in as';
$lang['user'] = 'Username';
@ -63,6 +64,7 @@ $lang['fullname'] = 'Real name';
$lang['email'] = 'E-Mail';
$lang['profile'] = 'User Profile';
$lang['badlogin'] = 'Sorry, username or password was wrong.';
$lang['badpassconfirm'] = 'Sorry, the password was wrong';
$lang['minoredit'] = 'Minor Changes';
$lang['draftdate'] = 'Draft autosaved on'; // full dformat date will be added
$lang['nosecedit'] = 'The page was changed in the meantime, section info was out of date loaded full page instead.';
@ -81,6 +83,11 @@ $lang['profna'] = 'This wiki does not support profile modificatio
$lang['profnochange'] = 'No changes, nothing to do.';
$lang['profnoempty'] = 'An empty name or email address is not allowed.';
$lang['profchanged'] = 'User profile successfully updated.';
$lang['profnodelete'] = 'This wiki does not support deleting users';
$lang['profdeleteuser'] = 'Delete Account';
$lang['profdeleted'] = 'Your user account has been deleted from this wiki';
$lang['profconfdelete'] = 'I wish to remove my account from this wiki. <br/> This action can not be undone.';
$lang['profconfdeletemissing'] = 'Confirmation check box not ticked';
$lang['pwdforget'] = 'Forgotten your password? Get a new one';
$lang['resendna'] = 'This wiki does not support password resending.';

View File

@ -86,6 +86,7 @@ $lang['disableactions'] = 'Deaktiviere DokuWiki\'s Zugriffe';
$lang['disableactions_check'] = 'Check';
$lang['disableactions_subscription'] = 'Bestellen/Abbestellen';
$lang['disableactions_wikicode'] = 'Zeige Quelle/Exportiere Rohdaten';
$lang['disableactions_profile_delete'] = 'Eigenes Benutzerprofil löschen';
$lang['disableactions_other'] = 'Weitere Aktionen (durch Komma getrennt)';
$lang['auth_security_timeout'] = 'Zeitüberschreitung bei der Authentifizierung (Sekunden)';
$lang['securecookie'] = 'Sollen Cookies, die via HTTPS gesetzt wurden nur per HTTPS versendet werden? Deaktiviere diese Option, wenn nur der Login deines Wikis mit SSL gesichert ist, aber das Betrachten des Wikis ungesichert geschieht.';

View File

@ -98,6 +98,7 @@ $lang['disableactions'] = 'DokuWiki-Aktionen deaktivieren';
$lang['disableactions_check'] = 'Check';
$lang['disableactions_subscription'] = 'Seiten-Abonnements';
$lang['disableactions_wikicode'] = 'Quelltext betrachten/exportieren';
$lang['disableactions_profile_delete'] = 'Eigenes Benutzerprofil löschen';
$lang['disableactions_other'] = 'Andere Aktionen (durch Komma getrennt)';
$lang['sneaky_index'] = 'Standardmäßig zeigt DokuWiki alle Namensräume in der Übersicht. Wenn diese Option aktiviert wird, werden alle Namensräume, für die der Benutzer keine Lese-Rechte hat, nicht angezeigt. Dies kann unter Umständen dazu führen, das lesbare Unter-Namensräume nicht angezeigt werden und macht die Übersicht evtl. unbrauchbar in Kombination mit bestimmten ACL Einstellungen.';
$lang['auth_security_timeout'] = 'Authentifikations-Timeout (Sekunden)';

View File

@ -104,6 +104,7 @@ $lang['disableactions'] = 'Disable DokuWiki actions';
$lang['disableactions_check'] = 'Check';
$lang['disableactions_subscription'] = 'Subscribe/Unsubscribe';
$lang['disableactions_wikicode'] = 'View source/Export Raw';
$lang['disableactions_profile_delete'] = 'Delete Own Account';
$lang['disableactions_other'] = 'Other actions (comma separated)';
$lang['auth_security_timeout'] = 'Authentication Security Timeout (seconds)';
$lang['securecookie'] = 'Should cookies set via HTTPS only be sent via HTTPS by the browser? Disable this option when only the login of your wiki is secured with SSL but browsing the wiki is done unsecured.';

View File

@ -128,7 +128,7 @@ $meta['manager'] = array('string');
$meta['profileconfirm'] = array('onoff');
$meta['rememberme'] = array('onoff');
$meta['disableactions'] = array('disableactions',
'_choices' => array('backlink','index','recent','revisions','search','subscription','register','resendpwd','profile','edit','wikicode','check'),
'_choices' => array('backlink','index','recent','revisions','search','subscription','register','resendpwd','profile','profile_delete','edit','wikicode','check'),
'_combine' => array('subscription' => array('subscribe','unsubscribe'), 'wikicode' => array('source','export_raw')));
$meta['auth_security_timeout'] = array('numeric');
$meta['securecookie'] = array('onoff');

View File

@ -79,7 +79,10 @@
#dw__register fieldset {
padding-bottom: 0.7em;
}
#dw__profiledelete {
display: block;
margin-top: 2.8em;
}
/**
* Styles for the subscription page