3 * @copyright Copyright (C) 2010-2022, 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;
31 use Friendica\Core\Session\Capability\IHandleSessions;
33 use Friendica\Module\Register;
34 use Friendica\Module\Response;
35 use Friendica\Security\Authentication;
36 use Friendica\Util\Profiler;
37 use Psr\Log\LoggerInterface;
42 class Login extends BaseModule
44 /** @var Authentication */
47 /** @var IManageConfigValues */
50 /** @var IHandleSessions */
53 public function __construct(Authentication $auth, IManageConfigValues $config, IHandleSessions $session, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = [])
55 parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
58 $this->config = $config;
59 $this->session = $session;
62 protected function content(array $request = []): string
64 $return_path = $request['return_path'] ?? $this->session->pop('return_path', '') ;
66 if (Session::getLocalUser()) {
67 $this->baseUrl->redirect($return_path);
70 return self::form($return_path, intval($this->config->get('config', 'register_policy')) !== \Friendica\Module\Register::CLOSED);
73 protected function post(array $request = [])
75 $this->session->clear();
79 empty($request['password'])
80 && (!empty($request['openid_url'])
81 || !empty($request['username']))
83 $openid_url = trim(($request['openid_url'] ?? '') ?: $request['username']);
85 $this->auth->withOpenId($openid_url, !empty($request['remember']));
88 if (!empty($request['auth-params']) && $request['auth-params'] === 'login') {
89 $this->auth->withPassword(
91 trim($request['username']),
92 trim($request['password']),
93 !empty($request['remember']),
94 $request['return_path'] ?? ''
100 * Wrapper for adding a login box.
102 * @param string|null $return_path The path relative to the base the user should be sent back to after login completes.
103 * @param bool $register If $register == true provide a registration link.
104 * This will almost always depend on the value of config.register_policy.
106 * @return string Returns the complete html for inserting into the page
108 * @throws \Friendica\Network\HTTPException\InternalServerErrorException
109 * @throws \Friendica\Network\HTTPException\ServiceUnavailableException
110 * @hooks 'login_hook' string $o
112 public static function form(string $return_path = null, bool $register = false): string
114 $noid = DI::config()->get('system', 'no_openid');
117 DI::session()->remove('openid_identity');
118 DI::session()->remove('openid_attributes');
122 if ($register && intval(DI::config()->get('config', 'register_policy')) !== Register::CLOSED) {
124 'title' => DI::l10n()->t('Create a New Account'),
125 'desc' => DI::l10n()->t('Register'),
126 'url' => self::getRegisterURL()
130 if (Session::getLocalUser()) {
131 $tpl = Renderer::getMarkupTemplate('logout.tpl');
133 DI::page()['htmlhead'] .= Renderer::replaceMacros(
134 Renderer::getMarkupTemplate('login_head.tpl'),
136 '$baseurl' => DI::baseUrl()->get(true)
140 $tpl = Renderer::getMarkupTemplate('login.tpl');
143 if (!empty(DI::session()->get('openid_identity'))) {
144 $openid_title = DI::l10n()->t('Your OpenID: ');
145 $openid_readonly = true;
146 $identity = DI::session()->get('openid_identity');
147 $username_desc = DI::l10n()->t('Please enter your username and password to add the OpenID to your existing account.');
149 $openid_title = DI::l10n()->t('Or login using OpenID: ');
150 $openid_readonly = false;
155 $o = Renderer::replaceMacros(
158 '$dest_url' => DI::baseUrl()->get(true) . '/login',
159 '$logout' => DI::l10n()->t('Logout'),
160 '$login' => DI::l10n()->t('Login'),
162 '$lname' => ['username', DI::l10n()->t('Nickname or Email: '), '', $username_desc],
163 '$lpassword' => ['password', DI::l10n()->t('Password: '), '', ''],
164 '$lremember' => ['remember', DI::l10n()->t('Remember me'), 0, ''],
167 '$lopenid' => ['openid_url', $openid_title, $identity, '', $openid_readonly],
169 '$hiddens' => ['return_path' => $return_path ?? DI::args()->getQueryString()],
173 '$lostpass' => DI::l10n()->t('Forgot your password?'),
174 '$lostlink' => DI::l10n()->t('Password Reset'),
176 '$tostitle' => DI::l10n()->t('Website Terms of Service'),
177 '$toslink' => DI::l10n()->t('terms of service'),
179 '$privacytitle' => DI::l10n()->t('Website Privacy Policy'),
180 '$privacylink' => DI::l10n()->t('privacy policy'),
184 Hook::callAll('login_hook', $o);
190 * Get the URL to the register page and add OpenID parameters to it
192 private static function getRegisterURL(): string
194 if (empty(DI::session()->get('openid_identity'))) {
199 $attr = DI::session()->get('openid_attributes', []);
201 if (is_array($attr) && count($attr)) {
202 foreach ($attr as $k => $v) {
203 if ($k === 'namePerson/friendly') {
206 if ($k === 'namePerson/first') {
209 if ($k === 'namePerson') {
210 $args['username'] = trim($v);
212 if ($k === 'contact/email') {
213 $args['email'] = trim($v);
215 if ($k === 'media/image/aspect11') {
216 $photosq = bin2hex(trim($v));
218 if ($k === 'media/image/default') {
219 $photo = bin2hex(trim($v));
225 $args['nickname'] = $nick;
226 } elseif (!empty($first)) {
227 $args['nickname'] = $first;
230 if (!empty($photosq)) {
231 $args['photo'] = $photosq;
232 } elseif (!empty($photo)) {
233 $args['photo'] = $photo;
236 $args['openid_url'] = trim(DI::session()->get('openid_identity'));
238 return 'register?' . http_build_query($args);