Skip to content

Commit

Permalink
Merge pull request #3711 from WoltLab/mfa-meta
Browse files Browse the repository at this point in the history
Multifactor Authentication: Integration branch
  • Loading branch information
TimWolla committed Dec 9, 2020
2 parents c9b1a9a + ed44825 commit 2a73891
Show file tree
Hide file tree
Showing 76 changed files with 4,408 additions and 30 deletions.
50 changes: 49 additions & 1 deletion com.woltlab.wcf/objectType.xml
Original file line number Diff line number Diff line change
Expand Up @@ -943,6 +943,13 @@
<propertyname>trophyPoints</propertyname>
<minvalue>0</minvalue>
</type>
<type>
<name>com.woltlab.wcf.user.multifactor</name>
<definitionname>com.woltlab.wcf.condition.notice</definitionname>
<classname>wcf\system\condition\UserMultifactorCondition</classname>
<conditionobject>com.woltlab.wcf.user</conditionobject>
<conditiongroup>general</conditiongroup>
</type>
<!-- /notice conditions -->
<!-- ad locations -->
<type>
Expand Down Expand Up @@ -1450,6 +1457,12 @@
<classname>wcf\system\condition\UserOptionsCondition</classname>
<conditiongroup>userOptions</conditiongroup>
</type>
<type>
<name>com.woltlab.wcf.user.multifactor</name>
<definitionname>com.woltlab.wcf.condition.userSearch</definitionname>
<classname>wcf\system\condition\UserMultifactorCondition</classname>
<conditiongroup>general</conditiongroup>
</type>
<!-- /user search conditions -->
<!-- box controllers -->
<type>
Expand Down Expand Up @@ -1720,6 +1733,41 @@
<name>com.woltlab.wcf.comment</name>
<definitionname>com.woltlab.wcf.floodControl</definitionname>
</type>
<!-- multi factor -->
<type>
<name>com.woltlab.wcf.multifactor.backup</name>
<definitionname>com.woltlab.wcf.multifactor</definitionname>
<icon>sticky-note</icon>
<priority>1</priority>
<classname>wcf\system\user\multifactor\BackupMultifactorMethod</classname>
</type>
<type>
<name>com.woltlab.wcf.multifactor.backup</name>
<definitionname>com.woltlab.wcf.floodControl</definitionname>
</type>
<type>
<name>com.woltlab.wcf.multifactor.totp</name>
<definitionname>com.woltlab.wcf.multifactor</definitionname>
<icon>mobile</icon>
<priority>10</priority>
<classname>wcf\system\user\multifactor\TotpMultifactorMethod</classname>
</type>
<type>
<name>com.woltlab.wcf.multifactor.totp</name>
<definitionname>com.woltlab.wcf.floodControl</definitionname>
</type>
<type>
<name>com.woltlab.wcf.multifactor.email</name>
<definitionname>com.woltlab.wcf.multifactor</definitionname>
<icon>envelope</icon>
<priority>5</priority>
<classname>wcf\system\user\multifactor\EmailMultifactorMethod</classname>
</type>
<type>
<name>com.woltlab.wcf.multifactor.email</name>
<definitionname>com.woltlab.wcf.floodControl</definitionname>
</type>
<!-- /multi factor -->
<!-- deprecated -->
<type>
<name>com.woltlab.wcf.page.controller</name>
Expand All @@ -1734,7 +1782,7 @@
<conditionobject>com.woltlab.wcf.page</conditionobject>
</type>
<!-- /deprecated -->
</import>
</import>
<delete>
<type name="com.woltlab.wcf.like.user">
<definitionname>com.woltlab.wcf.rebuildData</definitionname>
Expand Down
4 changes: 4 additions & 0 deletions com.woltlab.wcf/objectTypeDefinition.xml
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,10 @@
<definition>
<name>com.woltlab.wcf.floodControl</name>
</definition>
<definition>
<name>com.woltlab.wcf.multifactor</name>
<interfacename>wcf\system\user\multifactor\IMultifactorMethod</interfacename>
</definition>
</import>
<delete>
<definition name="com.woltlab.wcf.notification.notificationType"/>
Expand Down
3 changes: 3 additions & 0 deletions com.woltlab.wcf/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -98,5 +98,8 @@ tar cvf com.woltlab.wcf/files_pre.tar -C wcfsetup/install/files/ \
<instruction type="userMenu" />
<instruction type="page" />
<instruction type="language" />

<!-- Migration of multi-factor authentication. -->
<instruction type="script" run="standalone">acp/update_com.woltlab.wcf_5.4_migrate_multifactor.php</instruction>
</instructions>
</package>
58 changes: 54 additions & 4 deletions com.woltlab.wcf/page.xml
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,6 @@
<name language="de">Dashboard</name>
<name language="en">Dashboard</name>
<allowSpidersToIndex>1</allowSpidersToIndex>

<content>
<title>Dashboard</title>
<customURL>dashboard</customURL>
Expand All @@ -669,7 +668,6 @@
<name language="en">Cookie Policy</name>
<availableDuringOfflineMode>1</availableDuringOfflineMode>
<allowSpidersToIndex>0</allowSpidersToIndex>

<content language="en">
<title>Cookie Policy</title>
<content><![CDATA[<p>This website uses cookies required to operate and use this site. Below you will find an explanation on our cookie usage.</p>
Expand Down Expand Up @@ -729,7 +727,6 @@
<name language="en">Privacy Policy</name>
<availableDuringOfflineMode>1</availableDuringOfflineMode>
<allowSpidersToIndex>0</allowSpidersToIndex>

<content language="en">
<title>Privacy Policy</title>
<content><![CDATA[<h2>1. An overview of data protection</h2>
Expand Down Expand Up @@ -831,8 +828,61 @@ E-Mail: [E-Mail-Adresse der verantwortlichen Stelle]</p><p><br></p><p>Verantwort
<customURL>datenschutzerklaerung</customURL>
</content>
</page>
<page identifier="com.woltlab.wcf.MultifactorManage">
<pageType>system</pageType>
<controller>wcf\form\MultifactorManageForm</controller>
<name language="en">Manage Multi-Factor Authentication</name>
<name language="de">Mehrfaktor-Authentifizierung einrichten</name>
<hasFixedParent>1</hasFixedParent>
<parent>com.woltlab.wcf.AccountSecurity</parent>
<excludeFromLandingPage>1</excludeFromLandingPage>
<requireObjectID>1</requireObjectID>
</page>
<page identifier="com.woltlab.wcf.MultifactorAuthentication">
<pageType>system</pageType>
<controller>wcf\form\MultifactorAuthenticationForm</controller>
<name language="en">Multi-Factor Authentication</name>
<name language="de">Mehrfaktor-Authentifizierung</name>
<hasFixedParent>1</hasFixedParent>
<parent>com.woltlab.wcf.Login</parent>
<excludeFromLandingPage>1</excludeFromLandingPage>
<availableDuringOfflineMode>1</availableDuringOfflineMode>
<requireObjectID>1</requireObjectID>
</page>
<page identifier="com.woltlab.wcf.MultifactorDisable">
<pageType>system</pageType>
<controller>wcf\form\MultifactorDisableForm</controller>
<name language="en">Disable Multi-Factor Authentication</name>
<name language="de">Mehrfaktor-Authentifizierung deaktivieren</name>
<hasFixedParent>1</hasFixedParent>
<parent>com.woltlab.wcf.AccountSecurity</parent>
<excludeFromLandingPage>1</excludeFromLandingPage>
<availableDuringOfflineMode>1</availableDuringOfflineMode>
<requireObjectID>1</requireObjectID>
<content language="en">
<title>Disable Multi-Factor Authentication</title>
</content>
<content language="de">
<title>Mehrfaktor-Authentifizierung deaktivieren</title>
</content>
</page>
<page identifier="com.woltlab.wcf.Reauthentication">
<pageType>system</pageType>
<controller>wcf\form\ReauthenticationForm</controller>
<name language="en">Re-authentication</name>
<name language="de">Erneute Authentifizierung</name>
<hasFixedParent>1</hasFixedParent>
<excludeFromLandingPage>1</excludeFromLandingPage>
<availableDuringOfflineMode>1</availableDuringOfflineMode>
<content language="en">
<title>Re-authentication</title>
</content>
<content language="de">
<title>Erneute Authentifizierung</title>
</content>
</page>
</import>
<delete>
<page identifier="com.woltlab.wcf.Mail" />
<page identifier="com.woltlab.wcf.Mail"/>
</delete>
</data>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<dl>
<dt>{lang}wcf.user.security.multifactor.authentication.loginAs{/lang}</dt>
<dd>{$user->username}</dd>
</dl>
17 changes: 17 additions & 0 deletions com.woltlab.wcf/templates/__multifactorBackupCodeField.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<input type="text" {*
*}id="{@$field->getPrefixedId()}" {*
*}name="{@$field->getPrefixedId()}" {*
*}value="{if !$field->isI18n() || !$field->hasI18nValues() || $availableLanguages|count === 1}{$field->getValue()}{/if}" {*
*}class="multifactorBackupCode" {*
*}autocomplete="off" {*
*}pattern="[0-9\s]*" {*
*}inputmode="numeric"{*
*}{if $field->getChunks() && $field->getChunkLength()} size="{$field->getChunks() - 1 + $field->getChunks() * $field->getChunkLength()}"{/if}{*
*}{if $field->isAutofocused()} autofocus{/if}{*
*}{if $field->isRequired()} required{/if}{*
*}{if $field->isImmutable()} disabled{/if}{*
*}{if $field->getMinimumLength() !== null} minlength="{$field->getMinimumLength()}"{/if}{*
*}{if $field->getMaximumLength() !== null} maxlength="{$field->getMaximumLength()}"{/if}{*
*}{if $field->getPlaceholder() !== null} placeholder="{$field->getPlaceholder()}"{/if}{*
*}{if $field->getDocument()->isAjax()} data-dialog-submit-on-enter="true"{/if}{*
*}>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{lang}wcf.user.security.multifactor.disable.explanation{/lang}
17 changes: 17 additions & 0 deletions com.woltlab.wcf/templates/__multifactorEmailCodeField.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<input type="text" {*
*}id="{@$field->getPrefixedId()}" {*
*}name="{@$field->getPrefixedId()}" {*
*}value="{if !$field->isI18n() || !$field->hasI18nValues() || $availableLanguages|count === 1}{$field->getValue()}{/if}" {*
*}class="multifactorEmailCode" {*
*}autocomplete="off" {*
*}{if $field->getMaximumLength() !== null}size="{$field->getMaximumLength()}" {/if}{*
*}pattern="[0-9]*" {*
*}inputmode="numeric"{*
*}{if $field->isAutofocused()} autofocus{/if}{*
*}{if $field->isRequired()} required{/if}{*
*}{if $field->isImmutable()} disabled{/if}{*
*}{if $field->getMinimumLength() !== null} minlength="{$field->getMinimumLength()}"{/if}{*
*}{if $field->getMaximumLength() !== null} maxlength="{$field->getMaximumLength()}"{/if}{*
*}{if $field->getPlaceholder() !== null} placeholder="{$field->getPlaceholder()}"{/if}{*
*}{if $field->getDocument()->isAjax()} data-dialog-submit-on-enter="true"{/if}{*
*}>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{lang}wcf.user.security.multifactor.initialBackup{/lang}
17 changes: 17 additions & 0 deletions com.woltlab.wcf/templates/__multifactorTotpCodeField.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<input type="text" {*
*}id="{@$field->getPrefixedId()}" {*
*}name="{@$field->getPrefixedId()}" {*
*}value="{if !$field->isI18n() || !$field->hasI18nValues() || $availableLanguages|count === 1}{$field->getValue()}{/if}" {*
*}class="multifactorTotpCode" {*
*}autocomplete="off" {*
*}{if $field->getMaximumLength() !== null}size="{$field->getMaximumLength()}" {/if}{*
*}pattern="[0-9]*" {*
*}inputmode="numeric"{*
*}{if $field->isAutofocused()} autofocus{/if}{*
*}{if $field->isRequired()} required{/if}{*
*}{if $field->isImmutable()} disabled{/if}{*
*}{if $field->getMinimumLength() !== null} minlength="{$field->getMinimumLength()}"{/if}{*
*}{if $field->getMaximumLength() !== null} maxlength="{$field->getMaximumLength()}"{/if}{*
*}{if $field->getPlaceholder() !== null} placeholder="{$field->getPlaceholder()}"{/if}{*
*}{if $field->getDocument()->isAjax()} data-dialog-submit-on-enter="true"{/if}{*
*}>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<button type="button" id="{@$button->getPrefixedId()}" class="jsStaticDialog" data-dialog-id="{@$button->getPrefixedId()}DeletionInfo">{$button->getLabel()}</button>
<div style="display: none;" id="{@$button->getPrefixedId()}DeletionInfo" data-title="{lang}wcf.user.security.multifactor.totp.lastDevice.title{/lang}">
{lang deviceName=$device[deviceName]}wcf.user.security.multifactor.totp.lastDevice{/lang}
</div>
13 changes: 13 additions & 0 deletions com.woltlab.wcf/templates/__multifactorTotpDeviceNode.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

<tr>
<td class="columnText">{$device[deviceName]}</td>
<td class="columnDate">{$device[createTime]|plainTime}</td>
<td class="columnDate">{if $device[useTime]}{$device[useTime]|plainTime}{else}&ndash;{/if}</td>
<td class="columnText">
{foreach from=$container item='child'}
{if $child->isAvailable()}
{@$child->getHtml()}
{/if}
{/foreach}
</td>
</tr>
43 changes: 43 additions & 0 deletions com.woltlab.wcf/templates/__multifactorTotpDevicesContainer.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<section id="{@$container->getPrefixedId()}Container"{*
*}{if !$container->getClasses()|empty} class="{implode from=$container->getClasses() item='class' glue=' '}{$class}{/implode}"{/if}{*
*}{foreach from=$container->getAttributes() key='attributeName' item='attributeValue'} {$attributeName}="{$attributeValue}"{/foreach}{*
*}{if !$container->checkDependencies()} style="display: none;"{/if}{*
*}>
{if $container->getLabel() !== null}
{if $container->getDescription() !== null}
<header class="sectionHeader">
<h2 class="sectionTitle">{@$container->getLabel()}{if $container->markAsRequired()} <span class="formFieldRequired">*</span>{/if}</h2>
<p class="sectionDescription">{@$container->getDescription()}</p>
</header>
{else}
<h2 class="sectionTitle">{@$container->getLabel()}{if $container->markAsRequired()} <span class="formFieldRequired">*</span>{/if}</h2>
{/if}
{/if}

<table class="table table-responsive">
<thead>
<tr>
<th class="columnText">{lang}wcf.user.security.multifactor.totp.deviceName{/lang}</th>
<th class="columnText">{lang}wcf.user.security.multifactor.totp.createTime{/lang}</th>
<th class="columnText">{lang}wcf.user.security.multifactor.totp.useTime{/lang}</th>
<th></th>
</tr>
</thead>

<tbody>
{foreach from=$container item='child'}
{if $child->isAvailable()}
{@$child->getHtml()}
{/if}
{/foreach}
</tbody>
</table>
</section>

{include file='__formContainerDependencies'}

<script data-relocate="true">
require(['WoltLabSuite/Core/Form/Builder/Field/Dependency/Container/Default'], function(DefaultContainerDependency) {
new DefaultContainerDependency('{@$container->getPrefixedId()}Container');
});
</script>
46 changes: 46 additions & 0 deletions com.woltlab.wcf/templates/__multifactorTotpNewDeviceContainer.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<section id="{@$container->getPrefixedId()}Container"{*
*}{if !$container->getClasses()|empty} class="{implode from=$container->getClasses() item='class' glue=' '}{$class}{/implode}"{/if}{*
*}{foreach from=$container->getAttributes() key='attributeName' item='attributeValue'} {$attributeName}="{$attributeValue}"{/foreach}{*
*}{if !$container->checkDependencies()} style="display: none;"{/if}{*
*}>
{if $container->getLabel() !== null}
{if $container->getDescription() !== null}
<header class="sectionHeader">
<h2 class="sectionTitle">{@$container->getLabel()}{if $container->markAsRequired()} <span class="formFieldRequired">*</span>{/if}</h2>
<p class="sectionDescription">{@$container->getDescription()}</p>
</header>
{else}
<h2 class="sectionTitle">{@$container->getLabel()}{if $container->markAsRequired()} <span class="formFieldRequired">*</span>{/if}</h2>
{/if}
{/if}

{lang}wcf.user.security.multifactor.totp.newDevice.description{/lang}

<div class="multifactorTotpNewDevice">
{if $container->getNodeById('secret')->isAvailable()}
{@$container->getNodeById('secret')->getFieldHtml()}
{/if}

<div class="multifactorTotpNewDeviceFields">
{foreach from=$container item='child'}
{if $child->getId() !== 'secret' && $child->getId() !== 'submitButton' && $child->isAvailable()}
{@$child->getHtml()}
{/if}
{/foreach}

{if $container->getNodeById('submitButton')->isAvailable()}
<div class="formSubmit">
{@$container->getNodeById('submitButton')->getHtml()}
</div>
{/if}
</div>
</div>
</section>

{include file='__formContainerDependencies'}

<script data-relocate="true">
require(['WoltLabSuite/Core/Form/Builder/Field/Dependency/Container/Default'], function(DefaultContainerDependency) {
new DefaultContainerDependency('{@$container->getPrefixedId()}Container');
});
</script>
15 changes: 15 additions & 0 deletions com.woltlab.wcf/templates/__multifactorTotpSecretField.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<div class="totpSecretContainer">
<input type="hidden" name="{@$field->getPrefixedId()}" value="{$field->getSignedValue()}">
<canvas></canvas><br>
<kbd {*
*}class="totpSecret" {*
*}data-issuer="{PAGE_TITLE}" {*
*}data-accountname="{$__wcf->user->username}"{*
*}>{$field->getEncodedValue()}</kbd>

<script>
(function (script) {
require(['WoltLabSuite/Core/Ui/User/Multifactor/Totp/Qr'], (Qr) => Qr.render(script.closest(".totpSecretContainer")));
})(document.currentScript);
</script>
</div>
4 changes: 4 additions & 0 deletions com.woltlab.wcf/templates/__reauthenticationLoginAs.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<dl>
<dt>{lang}wcf.user.reauthentication.loginAs{/lang}</dt>
<dd>{$__wcf->user->username}</dd>
</dl>

0 comments on commit 2a73891

Please sign in to comment.