use Friendica\Core\L10n;
use Friendica\Core\Renderer;
use Friendica\Database\DBA;
-use Friendica\Module\Login;
+use Friendica\Module\Security\Login;
require_once __DIR__ . '/../include/api.php';
use Friendica\Core\System;
use Friendica\Core\Session;
use Friendica\Database\DBA;
-use Friendica\Module\Login;
+use Friendica\Module\Security\Login;
use Friendica\Protocol\DFRN;
use Friendica\Protocol\OStatus;
use Friendica\Util\Network;
use Friendica\Model\Group;
use Friendica\Model\Profile;
use Friendica\Model\User;
-use Friendica\Module\Login;
+use Friendica\Module\Security\Login;
use Friendica\Network\Probe;
use Friendica\Protocol\Activity;
use Friendica\Util\DateTimeFormat;
use Friendica\Model\Event;
use Friendica\Model\Item;
use Friendica\Model\Profile;
-use Friendica\Module\Login;
+use Friendica\Module\Security\Login;
use Friendica\Util\ACLFormatter;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Strings;
use Friendica\Database\DBA;
use Friendica\Model\Contact;
use Friendica\Model\Mail;
-use Friendica\Module\Login;
+use Friendica\Module\Security\Login;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Proxy as ProxyUtils;
use Friendica\Util\Strings;
use Friendica\Model\Item;
use Friendica\Model\Profile;
use Friendica\Model\Term;
-use Friendica\Module\Login;
+use Friendica\Module\Security\Login;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Proxy as ProxyUtils;
use Friendica\Util\Strings;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Database\DBA;
-use Friendica\Module\Login;
+use Friendica\Module\Security\Login;
use Friendica\Model\Introduction;
use Friendica\Model\Notify;
use Friendica\Core\L10n;
use Friendica\Core\Renderer;
use Friendica\Core\System;
-use Friendica\Module\Login;
+use Friendica\Module\Security\Login;
use Friendica\Util\Network;
use Friendica\Util\Strings;
use Friendica\Model\GContact;
use Friendica\Model\Profile;
use Friendica\Model\User;
-use Friendica\Module\Login;
+use Friendica\Module\Security\Login;
use Friendica\Network\Probe;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Strings;
use Friendica\Database\DBA;
use Friendica\Model\Register;
use Friendica\Model\User;
-use Friendica\Module\Login;
+use Friendica\Module\Security\Login;
function user_allow($hash)
{
use Friendica\Model\GContact;
use Friendica\Model\Group;
use Friendica\Model\User;
-use Friendica\Module\Login;
+use Friendica\Module\Security\Login;
use Friendica\Protocol\Email;
use Friendica\Util\ACLFormatter;
use Friendica\Util\Network;
use Friendica\Core\Theme;
use Friendica\Database\Database;
use Friendica\Model\Profile;
-use Friendica\Module\Login;
+use Friendica\Module\Security\Login;
use Friendica\Module\Special\HTTPException as ModuleHTTPException;
use Friendica\Network\HTTPException;
use Friendica\Util\ConfigFileLoader;
use Friendica\BaseModule;
use Friendica\Core\ACL;
use Friendica\Core\L10n;
+use Friendica\Module\Security\Login;
use Friendica\Network\HTTPException;
use Friendica\Util\Strings;
use Friendica\Core\Worker;
use Friendica\Database\DBA;
use Friendica\Model;
+use Friendica\Module\Security\Login;
use Friendica\Network\HTTPException\BadRequestException;
use Friendica\Network\HTTPException\NotFoundException;
use Friendica\Network\Probe;
use Friendica\Core\Hook;
use Friendica\Core\L10n;
use Friendica\Core\Renderer;
+use Friendica\Module\Security\Login;
/**
* Home module - Landing page of the current node
use Friendica\Model\Group;
use Friendica\Model\Item;
use Friendica\Model\User;
-use Friendica\Module\Login;
+use Friendica\Module\Security\Login;
use Friendica\Network\HTTPException\NotImplementedException;
use Friendica\Util\ACLFormatter;
use Friendica\Util\Crypto;
+++ /dev/null
-<?php
-
-/**
- * @file src/Module/Login.php
- */
-
-namespace Friendica\Module;
-
-use Friendica\BaseModule;
-use Friendica\App\Authentication;
-use Friendica\Core\Config;
-use Friendica\Core\Hook;
-use Friendica\Core\L10n;
-use Friendica\Core\Renderer;
-use Friendica\Core\Session;
-use Friendica\Util\Strings;
-
-/**
- * Login module
- *
- * @author Hypolite Petovan <hypolite@mrpetovan.com>
- */
-class Login extends BaseModule
-{
- public static function content(array $parameters = [])
- {
- $a = self::getApp();
-
- if (local_user()) {
- $a->internalRedirect();
- }
-
- return self::form(Session::get('return_path'), intval(Config::get('config', 'register_policy')) !== \Friendica\Module\Register::CLOSED);
- }
-
- public static function post(array $parameters = [])
- {
- $return_path = Session::get('return_path');
- Session::clear();
- Session::set('return_path', $return_path);
-
- // OpenId Login
- if (
- empty($_POST['password'])
- && (!empty($_POST['openid_url'])
- || !empty($_POST['username']))
- ) {
- $openid_url = trim(($_POST['openid_url'] ?? '') ?: $_POST['username']);
-
- /** @var Authentication $authentication */
- $authentication = self::getClass(Authentication::class);
- $authentication->withOpenId($openid_url, !empty($_POST['remember']));
- }
-
- if (!empty($_POST['auth-params']) && $_POST['auth-params'] === 'login') {
- /** @var Authentication $authentication */
- $authentication = self::getClass(Authentication::class);
- $authentication->withPassword(
- self::getApp(),
- trim($_POST['username']),
- trim($_POST['password']),
- !empty($_POST['remember'])
- );
- }
- }
-
- /**
- * @brief Wrapper for adding a login box.
- *
- * @param string $return_path The path relative to the base the user should be sent
- * back to after login completes
- * @param bool $register If $register == true provide a registration link.
- * This will most always depend on the value of config.register_policy.
- * @param array $hiddens optional
- *
- * @return string Returns the complete html for inserting into the page
- *
- * @throws \Friendica\Network\HTTPException\InternalServerErrorException
- * @hooks 'login_hook' string $o
- */
- public static function form($return_path = null, $register = false, $hiddens = [])
- {
- $a = self::getApp();
- $o = '';
-
- $noid = Config::get('system', 'no_openid');
-
- if ($noid) {
- Session::remove('openid_identity');
- Session::remove('openid_attributes');
- }
-
- $reg = false;
- if ($register && intval($a->getConfig()->get('config', 'register_policy')) !== Register::CLOSED) {
- $reg = [
- 'title' => L10n::t('Create a New Account'),
- 'desc' => L10n::t('Register'),
- 'url' => self::getRegisterURL()
- ];
- }
-
- if (is_null($return_path)) {
- $return_path = $a->query_string;
- }
-
- if (local_user()) {
- $tpl = Renderer::getMarkupTemplate('logout.tpl');
- } else {
- $a->page['htmlhead'] .= Renderer::replaceMacros(
- Renderer::getMarkupTemplate('login_head.tpl'),
- [
- '$baseurl' => $a->getBaseURL(true)
- ]
- );
-
- $tpl = Renderer::getMarkupTemplate('login.tpl');
- $_SESSION['return_path'] = $return_path;
- }
-
- if (!empty(Session::get('openid_identity'))) {
- $openid_title = L10n::t('Your OpenID: ');
- $openid_readonly = true;
- $identity = Session::get('openid_identity');
- $username_desc = L10n::t('Please enter your username and password to add the OpenID to your existing account.');
- } else {
- $openid_title = L10n::t('Or login using OpenID: ');
- $openid_readonly = false;
- $identity = '';
- $username_desc = '';
- }
-
- $o .= Renderer::replaceMacros(
- $tpl,
- [
- '$dest_url' => self::getApp()->getBaseURL(true) . '/login',
- '$logout' => L10n::t('Logout'),
- '$login' => L10n::t('Login'),
-
- '$lname' => ['username', L10n::t('Nickname or Email: '), '', $username_desc],
- '$lpassword' => ['password', L10n::t('Password: '), '', ''],
- '$lremember' => ['remember', L10n::t('Remember me'), 0, ''],
-
- '$openid' => !$noid,
- '$lopenid' => ['openid_url', $openid_title, $identity, '', $openid_readonly],
-
- '$hiddens' => $hiddens,
-
- '$register' => $reg,
-
- '$lostpass' => L10n::t('Forgot your password?'),
- '$lostlink' => L10n::t('Password Reset'),
-
- '$tostitle' => L10n::t('Website Terms of Service'),
- '$toslink' => L10n::t('terms of service'),
-
- '$privacytitle' => L10n::t('Website Privacy Policy'),
- '$privacylink' => L10n::t('privacy policy'),
- ]
- );
-
- Hook::callAll('login_hook', $o);
-
- return $o;
- }
-
- /**
- * Get the URL to the register page and add OpenID parameters to it
- */
- private static function getRegisterURL()
- {
- if (empty(Session::get('openid_identity'))) {
- return 'register';
- }
-
- $args = [];
- $attr = Session::get('openid_attributes', []);
-
- if (is_array($attr) && count($attr)) {
- foreach ($attr as $k => $v) {
- if ($k === 'namePerson/friendly') {
- $nick = Strings::escapeTags(trim($v));
- }
- if ($k === 'namePerson/first') {
- $first = Strings::escapeTags(trim($v));
- }
- if ($k === 'namePerson') {
- $args['username'] = Strings::escapeTags(trim($v));
- }
- if ($k === 'contact/email') {
- $args['email'] = Strings::escapeTags(trim($v));
- }
- if ($k === 'media/image/aspect11') {
- $photosq = bin2hex(trim($v));
- }
- if ($k === 'media/image/default') {
- $photo = bin2hex(trim($v));
- }
- }
- }
-
- if (!empty($nick)) {
- $args['nickname'] = $nick;
- } elseif (!empty($first)) {
- $args['nickname'] = $first;
- }
-
- if (!empty($photosq)) {
- $args['photo'] = $photosq;
- } elseif (!empty($photo)) {
- $args['photo'] = $photo;
- }
-
- $args['openid_url'] = Strings::escapeTags(trim(Session::get('openid_identity')));
-
- return 'register?' . http_build_query($args);
- }
-}
+++ /dev/null
-<?php
-/**
- * @file src/Module/Logout.php
- */
-
-namespace Friendica\Module;
-
-use Friendica\BaseModule;
-use Friendica\App\Authentication;
-use Friendica\Core\Cache;
-use Friendica\Core\Hook;
-use Friendica\Core\L10n;
-use Friendica\Core\Session;
-use Friendica\Core\System;
-use Friendica\Model\Profile;
-
-/**
- * Logout module
- *
- * @author Hypolite Petovan <hypolite@mrpetovan.com>
- */
-class Logout extends BaseModule
-{
- /**
- * @brief Process logout requests
- */
- public static function init(array $parameters = [])
- {
- $visitor_home = null;
- if (remote_user()) {
- $visitor_home = Profile::getMyURL();
- Cache::delete('zrlInit:' . $visitor_home);
- }
-
- Hook::callAll("logging_out");
- Session::clear();
-
- if ($visitor_home) {
- System::externalRedirect($visitor_home);
- } else {
- info(L10n::t('Logged out.'));
- self::getApp()->internalRedirect();
- }
- }
-}
use Friendica\Model\Item;
use Friendica\Model\Profile as ProfileModel;
use Friendica\Model\User;
+use Friendica\Module\Security\Login;
use Friendica\Protocol\ActivityPub;
use Friendica\Protocol\DFRN;
use Friendica\Util\DateTimeFormat;
use Friendica\Content\Widget;
use Friendica\Core\L10n;
use Friendica\Module\BaseSearchModule;
-use Friendica\Module\Login;
+use Friendica\Module\Security\Login;
use Friendica\Util\Strings;
/**
--- /dev/null
+<?php
+
+/**
+ * @file src/Module/Login.php
+ */
+
+namespace Friendica\Module\Security;
+
+use Friendica\BaseModule;
+use Friendica\App\Authentication;
+use Friendica\Core\Config;
+use Friendica\Core\Hook;
+use Friendica\Core\L10n;
+use Friendica\Core\Renderer;
+use Friendica\Core\Session;
+use Friendica\Module\Register;
+use Friendica\Util\Strings;
+
+/**
+ * Login module
+ *
+ * @author Hypolite Petovan <hypolite@mrpetovan.com>
+ */
+class Login extends BaseModule
+{
+ public static function content(array $parameters = [])
+ {
+ $a = self::getApp();
+
+ if (local_user()) {
+ $a->internalRedirect();
+ }
+
+ return self::form(Session::get('return_path'), intval(Config::get('config', 'register_policy')) !== \Friendica\Module\Register::CLOSED);
+ }
+
+ public static function post(array $parameters = [])
+ {
+ $return_path = Session::get('return_path');
+ Session::clear();
+ Session::set('return_path', $return_path);
+
+ // OpenId Login
+ if (
+ empty($_POST['password'])
+ && (!empty($_POST['openid_url'])
+ || !empty($_POST['username']))
+ ) {
+ $openid_url = trim(($_POST['openid_url'] ?? '') ?: $_POST['username']);
+
+ /** @var Authentication $authentication */
+ $authentication = self::getClass(Authentication::class);
+ $authentication->withOpenId($openid_url, !empty($_POST['remember']));
+ }
+
+ if (!empty($_POST['auth-params']) && $_POST['auth-params'] === 'login') {
+ /** @var Authentication $authentication */
+ $authentication = self::getClass(Authentication::class);
+ $authentication->withPassword(
+ self::getApp(),
+ trim($_POST['username']),
+ trim($_POST['password']),
+ !empty($_POST['remember'])
+ );
+ }
+ }
+
+ /**
+ * @brief Wrapper for adding a login box.
+ *
+ * @param string $return_path The path relative to the base the user should be sent
+ * back to after login completes
+ * @param bool $register If $register == true provide a registration link.
+ * This will most always depend on the value of config.register_policy.
+ * @param array $hiddens optional
+ *
+ * @return string Returns the complete html for inserting into the page
+ *
+ * @throws \Friendica\Network\HTTPException\InternalServerErrorException
+ * @hooks 'login_hook' string $o
+ */
+ public static function form($return_path = null, $register = false, $hiddens = [])
+ {
+ $a = self::getApp();
+ $o = '';
+
+ $noid = Config::get('system', 'no_openid');
+
+ if ($noid) {
+ Session::remove('openid_identity');
+ Session::remove('openid_attributes');
+ }
+
+ $reg = false;
+ if ($register && intval($a->getConfig()->get('config', 'register_policy')) !== Register::CLOSED) {
+ $reg = [
+ 'title' => L10n::t('Create a New Account'),
+ 'desc' => L10n::t('Register'),
+ 'url' => self::getRegisterURL()
+ ];
+ }
+
+ if (is_null($return_path)) {
+ $return_path = $a->query_string;
+ }
+
+ if (local_user()) {
+ $tpl = Renderer::getMarkupTemplate('logout.tpl');
+ } else {
+ $a->page['htmlhead'] .= Renderer::replaceMacros(
+ Renderer::getMarkupTemplate('login_head.tpl'),
+ [
+ '$baseurl' => $a->getBaseURL(true)
+ ]
+ );
+
+ $tpl = Renderer::getMarkupTemplate('login.tpl');
+ $_SESSION['return_path'] = $return_path;
+ }
+
+ if (!empty(Session::get('openid_identity'))) {
+ $openid_title = L10n::t('Your OpenID: ');
+ $openid_readonly = true;
+ $identity = Session::get('openid_identity');
+ $username_desc = L10n::t('Please enter your username and password to add the OpenID to your existing account.');
+ } else {
+ $openid_title = L10n::t('Or login using OpenID: ');
+ $openid_readonly = false;
+ $identity = '';
+ $username_desc = '';
+ }
+
+ $o .= Renderer::replaceMacros(
+ $tpl,
+ [
+ '$dest_url' => self::getApp()->getBaseURL(true) . '/login',
+ '$logout' => L10n::t('Logout'),
+ '$login' => L10n::t('Login'),
+
+ '$lname' => ['username', L10n::t('Nickname or Email: '), '', $username_desc],
+ '$lpassword' => ['password', L10n::t('Password: '), '', ''],
+ '$lremember' => ['remember', L10n::t('Remember me'), 0, ''],
+
+ '$openid' => !$noid,
+ '$lopenid' => ['openid_url', $openid_title, $identity, '', $openid_readonly],
+
+ '$hiddens' => $hiddens,
+
+ '$register' => $reg,
+
+ '$lostpass' => L10n::t('Forgot your password?'),
+ '$lostlink' => L10n::t('Password Reset'),
+
+ '$tostitle' => L10n::t('Website Terms of Service'),
+ '$toslink' => L10n::t('terms of service'),
+
+ '$privacytitle' => L10n::t('Website Privacy Policy'),
+ '$privacylink' => L10n::t('privacy policy'),
+ ]
+ );
+
+ Hook::callAll('login_hook', $o);
+
+ return $o;
+ }
+
+ /**
+ * Get the URL to the register page and add OpenID parameters to it
+ */
+ private static function getRegisterURL()
+ {
+ if (empty(Session::get('openid_identity'))) {
+ return 'register';
+ }
+
+ $args = [];
+ $attr = Session::get('openid_attributes', []);
+
+ if (is_array($attr) && count($attr)) {
+ foreach ($attr as $k => $v) {
+ if ($k === 'namePerson/friendly') {
+ $nick = Strings::escapeTags(trim($v));
+ }
+ if ($k === 'namePerson/first') {
+ $first = Strings::escapeTags(trim($v));
+ }
+ if ($k === 'namePerson') {
+ $args['username'] = Strings::escapeTags(trim($v));
+ }
+ if ($k === 'contact/email') {
+ $args['email'] = Strings::escapeTags(trim($v));
+ }
+ if ($k === 'media/image/aspect11') {
+ $photosq = bin2hex(trim($v));
+ }
+ if ($k === 'media/image/default') {
+ $photo = bin2hex(trim($v));
+ }
+ }
+ }
+
+ if (!empty($nick)) {
+ $args['nickname'] = $nick;
+ } elseif (!empty($first)) {
+ $args['nickname'] = $first;
+ }
+
+ if (!empty($photosq)) {
+ $args['photo'] = $photosq;
+ } elseif (!empty($photo)) {
+ $args['photo'] = $photo;
+ }
+
+ $args['openid_url'] = Strings::escapeTags(trim(Session::get('openid_identity')));
+
+ return 'register?' . http_build_query($args);
+ }
+}
--- /dev/null
+<?php
+/**
+ * @file src/Module/Logout.php
+ */
+
+namespace Friendica\Module\Security;
+
+use Friendica\BaseModule;
+use Friendica\App\Authentication;
+use Friendica\Core\Cache;
+use Friendica\Core\Hook;
+use Friendica\Core\L10n;
+use Friendica\Core\Session;
+use Friendica\Core\System;
+use Friendica\Model\Profile;
+
+/**
+ * Logout module
+ *
+ * @author Hypolite Petovan <hypolite@mrpetovan.com>
+ */
+class Logout extends BaseModule
+{
+ /**
+ * @brief Process logout requests
+ */
+ public static function init(array $parameters = [])
+ {
+ $visitor_home = null;
+ if (remote_user()) {
+ $visitor_home = Profile::getMyURL();
+ Cache::delete('zrlInit:' . $visitor_home);
+ }
+
+ Hook::callAll("logging_out");
+ Session::clear();
+
+ if ($visitor_home) {
+ System::externalRedirect($visitor_home);
+ } else {
+ info(L10n::t('Logged out.'));
+ self::getApp()->internalRedirect();
+ }
+ }
+}
--- /dev/null
+<?php
+
+namespace Friendica\Module\Security\TwoFactor;
+
+use Friendica\BaseModule;
+use Friendica\App\Authentication;
+use Friendica\Core\L10n;
+use Friendica\Core\Renderer;
+use Friendica\Core\Session;
+use Friendica\Model\TwoFactor\RecoveryCode;
+
+/**
+ * // Page 1a: Recovery code verification
+ *
+ * @package Friendica\Module\TwoFactor
+ */
+class Recovery extends BaseModule
+{
+ public static function init(array $parameters = [])
+ {
+ if (!local_user()) {
+ return;
+ }
+ }
+
+ public static function post(array $parameters = [])
+ {
+ if (!local_user()) {
+ return;
+ }
+
+ if (($_POST['action'] ?? '') == 'recover') {
+ self::checkFormSecurityTokenRedirectOnError('2fa', 'twofactor_recovery');
+
+ $a = self::getApp();
+
+ $recovery_code = $_POST['recovery_code'] ?? '';
+
+ if (RecoveryCode::existsForUser(local_user(), $recovery_code)) {
+ RecoveryCode::markUsedForUser(local_user(), $recovery_code);
+ Session::set('2fa', true);
+ notice(L10n::t('Remaining recovery codes: %d', RecoveryCode::countValidForUser(local_user())));
+
+ // Resume normal login workflow
+ /** @var Authentication $authentication */
+ $authentication = self::getClass(Authentication::class);
+ $authentication->setForUser($a, $a->user, true, true);
+ } else {
+ notice(L10n::t('Invalid code, please retry.'));
+ }
+ }
+ }
+
+ public static function content(array $parameters = [])
+ {
+ if (!local_user()) {
+ self::getApp()->internalRedirect();
+ }
+
+ // Already authenticated with 2FA token
+ if (Session::get('2fa')) {
+ self::getApp()->internalRedirect();
+ }
+
+ return Renderer::replaceMacros(Renderer::getMarkupTemplate('twofactor/recovery.tpl'), [
+ '$form_security_token' => self::getFormSecurityToken('twofactor_recovery'),
+
+ '$title' => L10n::t('Two-factor recovery'),
+ '$message' => L10n::t('<p>You can enter one of your one-time recovery codes in case you lost access to your mobile device.</p>'),
+ '$recovery_message' => L10n::t('Don’t have your phone? <a href="%s">Enter a two-factor recovery code</a>', '2fa/recovery'),
+ '$recovery_code' => ['recovery_code', L10n::t('Please enter a recovery code'), '', '', '', 'placeholder="000000-000000"'],
+ '$recovery_label' => L10n::t('Submit recovery code and complete login'),
+ ]);
+ }
+}
--- /dev/null
+<?php
+
+namespace Friendica\Module\Security\TwoFactor;
+
+use Friendica\BaseModule;
+use Friendica\App\Authentication;
+use Friendica\Core\L10n;
+use Friendica\Core\PConfig;
+use Friendica\Core\Renderer;
+use Friendica\Core\Session;
+use PragmaRX\Google2FA\Google2FA;
+
+/**
+ * Page 1: Authenticator code verification
+ *
+ * @package Friendica\Module\TwoFactor
+ */
+class Verify extends BaseModule
+{
+ private static $errors = [];
+
+ public static function post(array $parameters = [])
+ {
+ if (!local_user()) {
+ return;
+ }
+
+ if (($_POST['action'] ?? '') == 'verify') {
+ self::checkFormSecurityTokenRedirectOnError('2fa', 'twofactor_verify');
+
+ $a = self::getApp();
+
+ $code = $_POST['verify_code'] ?? '';
+
+ $valid = (new Google2FA())->verifyKey(PConfig::get(local_user(), '2fa', 'secret'), $code);
+
+ // The same code can't be used twice even if it's valid
+ if ($valid && Session::get('2fa') !== $code) {
+ Session::set('2fa', $code);
+
+ // Resume normal login workflow
+ /** @var Authentication $authentication */
+ $authentication = self::getClass(Authentication::class);
+ $authentication->setForUser($a, $a->user, true, true);
+ } else {
+ self::$errors[] = L10n::t('Invalid code, please retry.');
+ }
+ }
+ }
+
+ public static function content(array $parameters = [])
+ {
+ if (!local_user()) {
+ self::getApp()->internalRedirect();
+ }
+
+ // Already authenticated with 2FA token
+ if (Session::get('2fa')) {
+ self::getApp()->internalRedirect();
+ }
+
+ return Renderer::replaceMacros(Renderer::getMarkupTemplate('twofactor/verify.tpl'), [
+ '$form_security_token' => self::getFormSecurityToken('twofactor_verify'),
+
+ '$title' => L10n::t('Two-factor authentication'),
+ '$message' => L10n::t('<p>Open the two-factor authentication app on your device to get an authentication code and verify your identity.</p>'),
+ '$errors_label' => L10n::tt('Error', 'Errors', count(self::$errors)),
+ '$errors' => self::$errors,
+ '$recovery_message' => L10n::t('Don’t have your phone? <a href="%s">Enter a two-factor recovery code</a>', '2fa/recovery'),
+ '$verify_code' => ['verify_code', L10n::t('Please enter a code from your authentication app'), '', '', 'required', 'autofocus placeholder="000000"', 'tel'],
+ '$verify_label' => L10n::t('Verify code and complete login'),
+ ]);
+ }
+}
use Friendica\Core\Renderer;
use Friendica\Model\TwoFactor\AppSpecificPassword;
use Friendica\Module\BaseSettingsModule;
-use Friendica\Module\Login;
+use Friendica\Module\Security\Login;
/**
* // Page 5: 2FA enabled, app-specific password generation
use Friendica\Model\TwoFactor\RecoveryCode;
use Friendica\Model\User;
use Friendica\Module\BaseSettingsModule;
-use Friendica\Module\Login;
+use Friendica\Module\Security\Login;
use PragmaRX\Google2FA\Google2FA;
class Index extends BaseSettingsModule
use Friendica\Core\Renderer;
use Friendica\Model\TwoFactor\RecoveryCode;
use Friendica\Module\BaseSettingsModule;
-use Friendica\Module\Login;
+use Friendica\Module\Security\Login;
/**
* // Page 3: 2FA enabled but not verified, show recovery codes
use Friendica\Core\Renderer;
use Friendica\Core\Session;
use Friendica\Module\BaseSettingsModule;
-use Friendica\Module\Login;
+use Friendica\Module\Security\Login;
use PragmaRX\Google2FA\Google2FA;
/**
+++ /dev/null
-<?php
-
-namespace Friendica\Module\TwoFactor;
-
-use Friendica\BaseModule;
-use Friendica\App\Authentication;
-use Friendica\Core\L10n;
-use Friendica\Core\Renderer;
-use Friendica\Core\Session;
-use Friendica\Model\TwoFactor\RecoveryCode;
-
-/**
- * // Page 1a: Recovery code verification
- *
- * @package Friendica\Module\TwoFactor
- */
-class Recovery extends BaseModule
-{
- public static function init(array $parameters = [])
- {
- if (!local_user()) {
- return;
- }
- }
-
- public static function post(array $parameters = [])
- {
- if (!local_user()) {
- return;
- }
-
- if (($_POST['action'] ?? '') == 'recover') {
- self::checkFormSecurityTokenRedirectOnError('2fa', 'twofactor_recovery');
-
- $a = self::getApp();
-
- $recovery_code = $_POST['recovery_code'] ?? '';
-
- if (RecoveryCode::existsForUser(local_user(), $recovery_code)) {
- RecoveryCode::markUsedForUser(local_user(), $recovery_code);
- Session::set('2fa', true);
- notice(L10n::t('Remaining recovery codes: %d', RecoveryCode::countValidForUser(local_user())));
-
- // Resume normal login workflow
- /** @var Authentication $authentication */
- $authentication = self::getClass(Authentication::class);
- $authentication->setForUser($a, $a->user, true, true);
- } else {
- notice(L10n::t('Invalid code, please retry.'));
- }
- }
- }
-
- public static function content(array $parameters = [])
- {
- if (!local_user()) {
- self::getApp()->internalRedirect();
- }
-
- // Already authenticated with 2FA token
- if (Session::get('2fa')) {
- self::getApp()->internalRedirect();
- }
-
- return Renderer::replaceMacros(Renderer::getMarkupTemplate('twofactor/recovery.tpl'), [
- '$form_security_token' => self::getFormSecurityToken('twofactor_recovery'),
-
- '$title' => L10n::t('Two-factor recovery'),
- '$message' => L10n::t('<p>You can enter one of your one-time recovery codes in case you lost access to your mobile device.</p>'),
- '$recovery_message' => L10n::t('Don’t have your phone? <a href="%s">Enter a two-factor recovery code</a>', '2fa/recovery'),
- '$recovery_code' => ['recovery_code', L10n::t('Please enter a recovery code'), '', '', '', 'placeholder="000000-000000"'],
- '$recovery_label' => L10n::t('Submit recovery code and complete login'),
- ]);
- }
-}
+++ /dev/null
-<?php
-
-namespace Friendica\Module\TwoFactor;
-
-use Friendica\BaseModule;
-use Friendica\App\Authentication;
-use Friendica\Core\L10n;
-use Friendica\Core\PConfig;
-use Friendica\Core\Renderer;
-use Friendica\Core\Session;
-use PragmaRX\Google2FA\Google2FA;
-
-/**
- * Page 1: Authenticator code verification
- *
- * @package Friendica\Module\TwoFactor
- */
-class Verify extends BaseModule
-{
- private static $errors = [];
-
- public static function post(array $parameters = [])
- {
- if (!local_user()) {
- return;
- }
-
- if (($_POST['action'] ?? '') == 'verify') {
- self::checkFormSecurityTokenRedirectOnError('2fa', 'twofactor_verify');
-
- $a = self::getApp();
-
- $code = $_POST['verify_code'] ?? '';
-
- $valid = (new Google2FA())->verifyKey(PConfig::get(local_user(), '2fa', 'secret'), $code);
-
- // The same code can't be used twice even if it's valid
- if ($valid && Session::get('2fa') !== $code) {
- Session::set('2fa', $code);
-
- // Resume normal login workflow
- /** @var Authentication $authentication */
- $authentication = self::getClass(Authentication::class);
- $authentication->setForUser($a, $a->user, true, true);
- } else {
- self::$errors[] = L10n::t('Invalid code, please retry.');
- }
- }
- }
-
- public static function content(array $parameters = [])
- {
- if (!local_user()) {
- self::getApp()->internalRedirect();
- }
-
- // Already authenticated with 2FA token
- if (Session::get('2fa')) {
- self::getApp()->internalRedirect();
- }
-
- return Renderer::replaceMacros(Renderer::getMarkupTemplate('twofactor/verify.tpl'), [
- '$form_security_token' => self::getFormSecurityToken('twofactor_verify'),
-
- '$title' => L10n::t('Two-factor authentication'),
- '$message' => L10n::t('<p>Open the two-factor authentication app on your device to get an authentication code and verify your identity.</p>'),
- '$errors_label' => L10n::tt('Error', 'Errors', count(self::$errors)),
- '$errors' => self::$errors,
- '$recovery_message' => L10n::t('Don’t have your phone? <a href="%s">Enter a two-factor recovery code</a>', '2fa/recovery'),
- '$verify_code' => ['verify_code', L10n::t('Please enter a code from your authentication app'), '', '', 'required', 'autofocus placeholder="000000"', 'tel'],
- '$verify_label' => L10n::t('Verify code and complete login'),
- ]);
- }
-}
],
'/2fa' => [
- '[/]' => [Module\TwoFactor\Verify::class, [R::GET, R::POST]],
- '/recovery' => [Module\TwoFactor\Recovery::class, [R::GET, R::POST]],
+ '[/]' => [Module\Security\TwoFactor\Verify::class, [R::GET, R::POST]],
+ '/recovery' => [Module\Security\TwoFactor\Recovery::class, [R::GET, R::POST]],
],
'/api' => [
'/like/{item:\d+}' => [Module\Like::class, [R::GET]],
'/localtime' => [Module\Debug\Localtime::class, [R::GET, R::POST]],
- '/login' => [Module\Login::class, [R::GET, R::POST]],
- '/logout' => [Module\Logout::class, [R::GET, R::POST]],
+ '/login' => [Module\Security\Login::class, [R::GET, R::POST]],
+ '/logout' => [Module\Security\Logout::class, [R::GET, R::POST]],
'/magic' => [Module\Magic::class, [R::GET]],
'/maintenance' => [Module\Maintenance::class, [R::GET]],
'/manifest' => [Module\Manifest::class, [R::GET]],