3 * @copyright Copyright (C) 2010-2023, the Friendica project
5 * @license GNU AGPL version 3 or any later version
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 namespace Friendica\Module\Security;
25 use Friendica\BaseModule;
26 use Friendica\Core\Config\Capability\IManageConfigValues;
27 use Friendica\Core\Hook;
28 use Friendica\Core\L10n;
29 use Friendica\Core\Renderer;
30 use Friendica\Core\Session\Capability\IHandleUserSessions;
32 use Friendica\Module\Register;
33 use Friendica\Module\Response;
34 use Friendica\Security\Authentication;
35 use Friendica\Util\Profiler;
36 use Psr\Log\LoggerInterface;
41 class Login extends BaseModule
43 /** @var Authentication */
46 /** @var IManageConfigValues */
49 /** @var IHandleUserSessions */
52 public function __construct(Authentication $auth, IManageConfigValues $config, IHandleUserSessions $session, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = [])
54 parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
57 $this->config = $config;
58 $this->session = $session;
61 protected function content(array $request = []): string
63 $return_path = $request['return_path'] ?? $this->session->pop('return_path', '') ;
65 if ($this->session->getLocalUserId()) {
66 $this->baseUrl->redirect($return_path);
69 return self::form($return_path, intval($this->config->get('config', 'register_policy')) !== \Friendica\Module\Register::CLOSED);
72 protected function post(array $request = [])
74 $this->session->clear();
78 empty($request['password'])
79 && (!empty($request['openid_url'])
80 || !empty($request['username']))
82 $openid_url = trim(($request['openid_url'] ?? '') ?: $request['username']);
84 $this->auth->withOpenId($openid_url, !empty($request['remember']));
87 if (!empty($request['auth-params']) && $request['auth-params'] === 'login') {
88 $this->auth->withPassword(
90 trim($request['username']),
91 trim($request['password']),
92 !empty($request['remember']),
93 $request['return_path'] ?? ''
99 * Wrapper for adding a login box.
101 * @param string|null $return_path The path relative to the base the user should be sent back to after login completes.
102 * @param bool $register If $register == true provide a registration link.
103 * This will almost always depend on the value of config.register_policy.
105 * @return string Returns the complete html for inserting into the page
107 * @throws \Friendica\Network\HTTPException\InternalServerErrorException
108 * @throws \Friendica\Network\HTTPException\ServiceUnavailableException
109 * @hooks 'login_hook' string $o
111 public static function form(string $return_path = null, bool $register = false): string
113 $noid = DI::config()->get('system', 'no_openid');
116 DI::session()->remove('openid_identity');
117 DI::session()->remove('openid_attributes');
121 if ($register && intval(DI::config()->get('config', 'register_policy')) !== Register::CLOSED) {
123 'title' => DI::l10n()->t('Create a New Account'),
124 'desc' => DI::l10n()->t('Register'),
125 'url' => self::getRegisterURL()
129 if (DI::userSession()->getLocalUserId()) {
130 $tpl = Renderer::getMarkupTemplate('logout.tpl');
132 DI::page()['htmlhead'] .= Renderer::replaceMacros(
133 Renderer::getMarkupTemplate('login_head.tpl'),
138 $tpl = Renderer::getMarkupTemplate('login.tpl');
141 if (!empty(DI::session()->get('openid_identity'))) {
142 $openid_title = DI::l10n()->t('Your OpenID: ');
143 $openid_readonly = true;
144 $identity = DI::session()->get('openid_identity');
145 $username_desc = DI::l10n()->t('Please enter your username and password to add the OpenID to your existing account.');
147 $openid_title = DI::l10n()->t('Or login using OpenID: ');
148 $openid_readonly = false;
153 $o = Renderer::replaceMacros(
156 '$dest_url' => DI::baseUrl() . '/login',
157 '$logout' => DI::l10n()->t('Logout'),
158 '$login' => DI::l10n()->t('Login'),
160 '$lname' => ['username', DI::l10n()->t('Nickname or Email: '), '', $username_desc],
161 '$lpassword' => ['password', DI::l10n()->t('Password: '), '', ''],
162 '$lremember' => ['remember', DI::l10n()->t('Remember me'), 0, ''],
165 '$lopenid' => ['openid_url', $openid_title, $identity, '', $openid_readonly],
167 '$hiddens' => ['return_path' => $return_path ?? DI::args()->getQueryString()],
171 '$lostpass' => DI::l10n()->t('Forgot your password?'),
172 '$lostlink' => DI::l10n()->t('Password Reset'),
174 '$tostitle' => DI::l10n()->t('Website Terms of Service'),
175 '$toslink' => DI::l10n()->t('terms of service'),
177 '$privacytitle' => DI::l10n()->t('Website Privacy Policy'),
178 '$privacylink' => DI::l10n()->t('privacy policy'),
182 Hook::callAll('login_hook', $o);
188 * Get the URL to the register page and add OpenID parameters to it
190 private static function getRegisterURL(): string
192 if (empty(DI::session()->get('openid_identity'))) {
197 $attr = DI::session()->get('openid_attributes', []);
199 if (is_array($attr) && count($attr)) {
200 foreach ($attr as $k => $v) {
201 if ($k === 'namePerson/friendly') {
204 if ($k === 'namePerson/first') {
207 if ($k === 'namePerson') {
208 $args['username'] = trim($v);
210 if ($k === 'contact/email') {
211 $args['email'] = trim($v);
213 if ($k === 'media/image/aspect11') {
214 $photosq = bin2hex(trim($v));
216 if ($k === 'media/image/default') {
217 $photo = bin2hex(trim($v));
223 $args['nickname'] = $nick;
224 } elseif (!empty($first)) {
225 $args['nickname'] = $first;
228 if (!empty($photosq)) {
229 $args['photo'] = $photosq;
230 } elseif (!empty($photo)) {
231 $args['photo'] = $photo;
234 $args['openid_url'] = trim(DI::session()->get('openid_identity'));
236 return 'register?' . http_build_query($args);