1 | <?php |
||||
2 | class Auth_Internal extends Plugin implements IAuthModule { |
||||
3 | |||||
4 | private $host; |
||||
5 | |||||
6 | public function about() { |
||||
7 | return array(1.0, |
||||
8 | "Authenticates against internal tt-rss database", |
||||
9 | "fox", |
||||
10 | true); |
||||
11 | } |
||||
12 | |||||
13 | /* @var PluginHost $host */ |
||||
14 | public function init($host) { |
||||
15 | $this->host = $host; |
||||
16 | $this->pdo = Db::pdo(); |
||||
17 | |||||
18 | $host->add_hook($host::HOOK_AUTH_USER, $this); |
||||
19 | } |
||||
20 | |||||
21 | public function authenticate($login, $password, $service = '') { |
||||
22 | |||||
23 | $pwd_hash1 = encrypt_password($password); |
||||
24 | $pwd_hash2 = encrypt_password($password, $login); |
||||
25 | $otp = $_REQUEST["otp"]; |
||||
26 | |||||
27 | if (get_schema_version() > 96) { |
||||
28 | |||||
29 | $sth = $this->pdo->prepare("SELECT otp_enabled,salt FROM ttrss_users WHERE |
||||
30 | login = ?"); |
||||
31 | $sth->execute([$login]); |
||||
32 | |||||
33 | if ($row = $sth->fetch()) { |
||||
34 | $otp_enabled = $row['otp_enabled']; |
||||
35 | |||||
36 | if ($otp_enabled) { |
||||
37 | |||||
38 | // only allow app password checking if OTP is enabled |
||||
39 | if ($service && get_schema_version() > 138) { |
||||
40 | return $this->check_app_password($login, $password, $service); |
||||
41 | } |
||||
42 | |||||
43 | if ($otp) { |
||||
44 | $base32 = new \OTPHP\Base32(); |
||||
0 ignored issues
–
show
|
|||||
45 | |||||
46 | $secret = $base32->encode(mb_substr(sha1($row["salt"]), 0, 12), false); |
||||
47 | $secret_legacy = $base32->encode(sha1($row["salt"])); |
||||
48 | |||||
49 | $totp = new \OTPHP\TOTP($secret); |
||||
0 ignored issues
–
show
The call to
OTPHP\TOTP::__construct() has too few arguments starting with period .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() |
|||||
50 | $otp_check = $totp->now(); |
||||
51 | |||||
52 | $totp_legacy = new \OTPHP\TOTP($secret_legacy); |
||||
53 | $otp_check_legacy = $totp_legacy->now(); |
||||
54 | |||||
55 | if ($otp != $otp_check && $otp != $otp_check_legacy) { |
||||
56 | return false; |
||||
57 | } |
||||
58 | } else { |
||||
59 | $return = urlencode($_REQUEST["return"]); |
||||
60 | ?> |
||||
61 | <!DOCTYPE html> |
||||
62 | <html> |
||||
63 | <head> |
||||
64 | <title>Tiny Tiny RSS</title> |
||||
65 | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> |
||||
66 | </head> |
||||
67 | <?php echo stylesheet_tag("css/default.css") ?> |
||||
0 ignored issues
–
show
Are you sure the usage of
stylesheet_tag('css/default.css') is correct as it seems to always return null .
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. ![]() The function
stylesheet_tag() has been deprecated: Use Twig filter cssTag
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||
68 | <body class="ttrss_utility otp"> |
||||
69 | <h1><?php echo __("Authentication") ?></h1> |
||||
70 | <div class="content"> |
||||
71 | <form action="public.php?return=<?php echo $return ?>" |
||||
72 | method="POST" class="otpform"> |
||||
73 | <input type="hidden" name="op" value="login"> |
||||
74 | <input type="hidden" name="login" value="<?php echo htmlspecialchars($login) ?>"> |
||||
75 | <input type="hidden" name="password" value="<?php echo htmlspecialchars($password) ?>"> |
||||
76 | <input type="hidden" name="bw_limit" value="<?php echo htmlspecialchars($_POST["bw_limit"]) ?>"> |
||||
77 | <input type="hidden" name="remember_me" value="<?php echo htmlspecialchars($_POST["remember_me"]) ?>"> |
||||
78 | <input type="hidden" name="profile" value="<?php echo htmlspecialchars($_POST["profile"]) ?>"> |
||||
79 | |||||
80 | <fieldset> |
||||
81 | <label><?php echo __("Please enter your one time password:") ?></label> |
||||
82 | <input autocomplete="off" size="6" name="otp" value=""/> |
||||
83 | <input type="submit" value="Continue"/> |
||||
84 | </fieldset> |
||||
85 | </form></div> |
||||
86 | <script type="text/javascript"> |
||||
87 | document.forms[0].otp.focus(); |
||||
88 | </script> |
||||
89 | <?php |
||||
90 | exit; |
||||
0 ignored issues
–
show
|
|||||
91 | } |
||||
92 | } |
||||
93 | } |
||||
94 | } |
||||
95 | |||||
96 | // check app passwords first but allow regular password as a fallback for the time being |
||||
97 | // if OTP is not enabled |
||||
98 | |||||
99 | if ($service && get_schema_version() > 138) { |
||||
100 | $user_id = $this->check_app_password($login, $password, $service); |
||||
101 | |||||
102 | if ($user_id) { |
||||
103 | return $user_id; |
||||
104 | } |
||||
105 | } |
||||
106 | |||||
107 | if (get_schema_version() > 87) { |
||||
108 | |||||
109 | $sth = $this->pdo->prepare("SELECT salt FROM ttrss_users WHERE login = ?"); |
||||
110 | $sth->execute([$login]); |
||||
111 | |||||
112 | if ($row = $sth->fetch()) { |
||||
113 | $salt = $row['salt']; |
||||
114 | |||||
115 | if ($salt == "") { |
||||
116 | |||||
117 | $sth = $this->pdo->prepare("SELECT id FROM ttrss_users WHERE |
||||
118 | login = ? AND (pwd_hash = ? OR pwd_hash = ?)"); |
||||
119 | |||||
120 | $sth->execute([$login, $pwd_hash1, $pwd_hash2]); |
||||
121 | |||||
122 | // verify and upgrade password to new salt base |
||||
123 | |||||
124 | if ($row = $sth->fetch()) { |
||||
125 | // upgrade password to MODE2 |
||||
126 | |||||
127 | $user_id = $row['id']; |
||||
128 | |||||
129 | $salt = substr(bin2hex(get_random_bytes(125)), 0, 250); |
||||
130 | $pwd_hash = encrypt_password($password, $salt, true); |
||||
131 | |||||
132 | $sth = $this->pdo->prepare("UPDATE ttrss_users SET |
||||
133 | pwd_hash = ?, salt = ? WHERE login = ?"); |
||||
134 | |||||
135 | $sth->execute([$pwd_hash, $salt, $login]); |
||||
136 | |||||
137 | return $user_id; |
||||
138 | |||||
139 | } else { |
||||
140 | return false; |
||||
141 | } |
||||
142 | |||||
143 | } else { |
||||
144 | $pwd_hash = encrypt_password($password, $salt, true); |
||||
145 | |||||
146 | $sth = $this->pdo->prepare("SELECT id |
||||
147 | FROM ttrss_users WHERE |
||||
148 | login = ? AND pwd_hash = ?"); |
||||
149 | $sth->execute([$login, $pwd_hash]); |
||||
150 | |||||
151 | if ($row = $sth->fetch()) { |
||||
152 | return $row['id']; |
||||
153 | } |
||||
154 | } |
||||
155 | |||||
156 | } else { |
||||
157 | $sth = $this->pdo->prepare("SELECT id |
||||
158 | FROM ttrss_users WHERE |
||||
159 | login = ? AND (pwd_hash = ? OR pwd_hash = ?)"); |
||||
160 | |||||
161 | $sth->execute([$login, $pwd_hash1, $pwd_hash2]); |
||||
162 | |||||
163 | if ($row = $sth->fetch()) { |
||||
164 | return $row['id']; |
||||
165 | } |
||||
166 | } |
||||
167 | } else { |
||||
168 | $sth = $this->pdo->prepare("SELECT id |
||||
169 | FROM ttrss_users WHERE |
||||
170 | login = ? AND (pwd_hash = ? OR pwd_hash = ?)"); |
||||
171 | |||||
172 | $sth->execute([$login, $pwd_hash1, $pwd_hash2]); |
||||
173 | |||||
174 | if ($row = $sth->fetch()) { |
||||
175 | return $row['id']; |
||||
176 | } |
||||
177 | } |
||||
178 | |||||
179 | return false; |
||||
180 | } |
||||
181 | |||||
182 | public function check_password($owner_uid, $password) { |
||||
183 | |||||
184 | $sth = $this->pdo->prepare("SELECT salt,login,otp_enabled FROM ttrss_users WHERE |
||||
185 | id = ?"); |
||||
186 | $sth->execute([$owner_uid]); |
||||
187 | |||||
188 | if ($row = $sth->fetch()) { |
||||
189 | |||||
190 | $salt = $row['salt']; |
||||
191 | $login = $row['login']; |
||||
192 | |||||
193 | if (!$salt) { |
||||
194 | $password_hash1 = encrypt_password($password); |
||||
195 | $password_hash2 = encrypt_password($password, $login); |
||||
196 | |||||
197 | $sth = $this->pdo->prepare("SELECT id FROM ttrss_users WHERE |
||||
198 | id = ? AND (pwd_hash = ? OR pwd_hash = ?)"); |
||||
199 | |||||
200 | $sth->execute([$owner_uid, $password_hash1, $password_hash2]); |
||||
201 | |||||
202 | return $sth->fetch(); |
||||
203 | |||||
204 | } else { |
||||
205 | $password_hash = encrypt_password($password, $salt, true); |
||||
206 | |||||
207 | $sth = $this->pdo->prepare("SELECT id FROM ttrss_users WHERE |
||||
208 | id = ? AND pwd_hash = ?"); |
||||
209 | |||||
210 | $sth->execute([$owner_uid, $password_hash]); |
||||
211 | |||||
212 | return $sth->fetch(); |
||||
213 | } |
||||
214 | } |
||||
215 | |||||
216 | return false; |
||||
217 | } |
||||
218 | |||||
219 | public function change_password($owner_uid, $old_password, $new_password) { |
||||
220 | |||||
221 | if ($this->check_password($owner_uid, $old_password)) { |
||||
222 | |||||
223 | $new_salt = substr(bin2hex(get_random_bytes(125)), 0, 250); |
||||
224 | $new_password_hash = encrypt_password($new_password, $new_salt, true); |
||||
225 | |||||
226 | $sth = $this->pdo->prepare("UPDATE ttrss_users SET |
||||
227 | pwd_hash = ?, salt = ?, otp_enabled = false |
||||
228 | WHERE id = ?"); |
||||
229 | $sth->execute([$new_password_hash, $new_salt, $owner_uid]); |
||||
230 | |||||
231 | $_SESSION["pwd_hash"] = $new_password_hash; |
||||
232 | |||||
233 | $sth = $this->pdo->prepare("SELECT email, login FROM ttrss_users WHERE id = ?"); |
||||
234 | $sth->execute([$owner_uid]); |
||||
235 | |||||
236 | if ($row = $sth->fetch()) { |
||||
237 | $mailer = new Mailer(); |
||||
238 | |||||
239 | require_once "lib/MiniTemplator.class.php"; |
||||
240 | |||||
241 | $tpl = new MiniTemplator; |
||||
242 | |||||
243 | $tpl->readTemplateFromFile("templates/password_change_template.txt"); |
||||
244 | |||||
245 | $tpl->setVariable('LOGIN', $row["login"]); |
||||
246 | $tpl->setVariable('TTRSS_HOST', SELF_URL_PATH); |
||||
0 ignored issues
–
show
|
|||||
247 | |||||
248 | $tpl->addBlock('message'); |
||||
249 | |||||
250 | $tpl->generateOutputToString($message); |
||||
251 | |||||
252 | $mailer->mail(["to_name" => $row["login"], |
||||
253 | "to_address" => $row["email"], |
||||
254 | "subject" => "[tt-rss] Password change notification", |
||||
255 | "message" => $message]); |
||||
256 | |||||
257 | } |
||||
258 | |||||
259 | return __("Password has been changed."); |
||||
260 | } else { |
||||
261 | return "ERROR: ".__('Old password is incorrect.'); |
||||
262 | } |
||||
263 | } |
||||
264 | |||||
265 | private function check_app_password($login, $password, $service) { |
||||
266 | $sth = $this->pdo->prepare("SELECT p.id, p.pwd_hash, u.id AS uid |
||||
267 | FROM ttrss_app_passwords p, ttrss_users u |
||||
268 | WHERE p.owner_uid = u.id AND u.login = ? AND service = ?"); |
||||
269 | $sth->execute([$login, $service]); |
||||
270 | |||||
271 | while ($row = $sth->fetch()) { |
||||
272 | list ($algo, $hash, $salt) = explode(":", $row["pwd_hash"]); |
||||
273 | |||||
274 | if ($algo == "SSHA-512") { |
||||
275 | $test_hash = hash('sha512', $salt.$password); |
||||
276 | |||||
277 | if ($test_hash == $hash) { |
||||
278 | $usth = $this->pdo->prepare("UPDATE ttrss_app_passwords SET last_used = NOW() WHERE id = ?"); |
||||
279 | $usth->execute([$row['id']]); |
||||
280 | |||||
281 | return $row['uid']; |
||||
282 | } |
||||
283 | } else { |
||||
284 | user_error("Got unknown algo of app password for user $login: $algo"); |
||||
285 | } |
||||
286 | } |
||||
287 | |||||
288 | return false; |
||||
289 | } |
||||
290 | |||||
291 | public function api_version() { |
||||
292 | return 2; |
||||
293 | } |
||||
294 | |||||
295 | } |
||||
296 |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"]
, you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths