1 | <?php |
||||||||
2 | |||||||||
3 | class Pref_Prefs extends Handler_Protected { |
||||||||
4 | |||||||||
5 | private $pref_help = []; |
||||||||
6 | private $pref_item_map = []; |
||||||||
7 | private $pref_blacklist = []; |
||||||||
8 | private $profile_blacklist = []; |
||||||||
9 | |||||||||
10 | public function csrf_ignore($method) { |
||||||||
11 | $csrf_ignored = array("index", "updateself", "customizecss", "editprefprofiles"); |
||||||||
12 | |||||||||
13 | return array_search($method, $csrf_ignored) !== false; |
||||||||
14 | } |
||||||||
15 | |||||||||
16 | public function __construct($args) { |
||||||||
17 | parent::__construct($args); |
||||||||
18 | |||||||||
19 | $this->pref_item_map = [ |
||||||||
20 | __('General') => [ |
||||||||
21 | 'USER_LANGUAGE', |
||||||||
22 | 'USER_TIMEZONE', |
||||||||
23 | 'BLOCK_SEPARATOR', |
||||||||
24 | 'USER_CSS_THEME', |
||||||||
25 | 'BLOCK_SEPARATOR', |
||||||||
26 | 'ENABLE_API_ACCESS', |
||||||||
27 | ], |
||||||||
28 | __('Feeds') => [ |
||||||||
29 | 'DEFAULT_UPDATE_INTERVAL', |
||||||||
30 | 'FRESH_ARTICLE_MAX_AGE', |
||||||||
31 | 'DEFAULT_SEARCH_LANGUAGE', |
||||||||
32 | 'BLOCK_SEPARATOR', |
||||||||
33 | 'ENABLE_FEED_CATS', |
||||||||
34 | 'BLOCK_SEPARATOR', |
||||||||
35 | 'CONFIRM_FEED_CATCHUP', |
||||||||
36 | 'ON_CATCHUP_SHOW_NEXT_FEED', |
||||||||
37 | 'BLOCK_SEPARATOR', |
||||||||
38 | 'HIDE_READ_FEEDS', |
||||||||
39 | 'HIDE_READ_SHOWS_SPECIAL', |
||||||||
40 | ], |
||||||||
41 | __('Articles') => [ |
||||||||
42 | 'PURGE_OLD_DAYS', |
||||||||
43 | 'PURGE_UNREAD_ARTICLES', |
||||||||
44 | 'BLOCK_SEPARATOR', |
||||||||
45 | 'COMBINED_DISPLAY_MODE', |
||||||||
46 | 'CDM_EXPANDED', |
||||||||
47 | 'BLOCK_SEPARATOR', |
||||||||
48 | 'CDM_AUTO_CATCHUP', |
||||||||
49 | 'VFEED_GROUP_BY_FEED', |
||||||||
50 | 'BLOCK_SEPARATOR', |
||||||||
51 | 'SHOW_CONTENT_PREVIEW', |
||||||||
52 | 'STRIP_IMAGES', |
||||||||
53 | ], |
||||||||
54 | __('Digest') => [ |
||||||||
55 | 'DIGEST_ENABLE', |
||||||||
56 | 'DIGEST_CATCHUP', |
||||||||
57 | 'DIGEST_PREFERRED_TIME', |
||||||||
58 | ], |
||||||||
59 | __('Advanced') => [ |
||||||||
60 | 'BLACKLISTED_TAGS', |
||||||||
61 | 'BLOCK_SEPARATOR', |
||||||||
62 | 'LONG_DATE_FORMAT', |
||||||||
63 | 'SHORT_DATE_FORMAT', |
||||||||
64 | 'BLOCK_SEPARATOR', |
||||||||
65 | 'SSL_CERT_SERIAL', |
||||||||
66 | ] |
||||||||
67 | ]; |
||||||||
68 | |||||||||
69 | $this->pref_help = [ |
||||||||
70 | "ALLOW_DUPLICATE_POSTS" => array(__("Allow duplicate articles"), ""), |
||||||||
71 | "BLACKLISTED_TAGS" => array(__("Blacklisted tags"), __("Never apply these tags automatically (comma-separated list).")), |
||||||||
72 | "DEFAULT_SEARCH_LANGUAGE" => array(__("Default language"), __("Used for full-text search")), |
||||||||
73 | "CDM_AUTO_CATCHUP" => array(__("Mark read on scroll"), __("Mark articles as read as you scroll past them")), |
||||||||
74 | "CDM_EXPANDED" => array(__("Always expand articles")), |
||||||||
75 | "COMBINED_DISPLAY_MODE" => array(__("Combined mode"), __("Show flat list of articles instead of separate panels")), |
||||||||
76 | "CONFIRM_FEED_CATCHUP" => array(__("Confirm marking feeds as read")), |
||||||||
77 | "DEFAULT_ARTICLE_LIMIT" => array(__("Amount of articles to display at once")), |
||||||||
78 | "DEFAULT_UPDATE_INTERVAL" => array(__("Default update interval")), |
||||||||
79 | "DIGEST_CATCHUP" => array(__("Mark sent articles as read")), |
||||||||
80 | "DIGEST_ENABLE" => array(__("Enable digest"), __("Send daily digest of new (and unread) headlines to your e-mail address")), |
||||||||
81 | "DIGEST_PREFERRED_TIME" => array(__("Try to send around this time"), __("Time in UTC")), |
||||||||
82 | "ENABLE_API_ACCESS" => array(__("Enable API"), __("Allows accessing this account through the API")), |
||||||||
83 | "ENABLE_FEED_CATS" => array(__("Enable categories")), |
||||||||
84 | "FEEDS_SORT_BY_UNREAD" => array(__("Sort feeds by unread articles count"), ""), |
||||||||
85 | "FRESH_ARTICLE_MAX_AGE" => array(__("Maximum age of fresh articles"), "<strong>".__("hours")."</strong>"), |
||||||||
86 | "HIDE_READ_FEEDS" => array(__("Hide read feeds")), |
||||||||
87 | "HIDE_READ_SHOWS_SPECIAL" => array(__("Always show special feeds"), __("While hiding read feeds")), |
||||||||
88 | "LONG_DATE_FORMAT" => array(__("Long date format"), __("Syntax is identical to PHP <a href='http://php.net/manual/function.date.php'>date()</a> function.")), |
||||||||
89 | "ON_CATCHUP_SHOW_NEXT_FEED" => array(__("Automatically show next feed"), __("After marking one as read")), |
||||||||
90 | "PURGE_OLD_DAYS" => array(__("Purge articles older than"), __("<strong>days</strong> (0 disables)")), |
||||||||
91 | "PURGE_UNREAD_ARTICLES" => array(__("Purge unread articles")), |
||||||||
92 | "REVERSE_HEADLINES" => array(__("Reverse headline order (oldest first)")), |
||||||||
93 | "SHORT_DATE_FORMAT" => array(__("Short date format")), |
||||||||
94 | "SHOW_CONTENT_PREVIEW" => array(__("Show content preview in headlines")), |
||||||||
95 | "SORT_HEADLINES_BY_FEED_DATE" => array(__("Sort headlines by feed date"), __("Use feed-specified date to sort headlines instead of local import date.")), |
||||||||
96 | "SSL_CERT_SERIAL" => array(__("SSL client certificate")), |
||||||||
97 | "STRIP_IMAGES" => array(__("Do not embed media")), |
||||||||
98 | "STRIP_UNSAFE_TAGS" => array(__("Strip unsafe tags from articles"), __("Strip all but most common HTML tags when reading articles.")), |
||||||||
99 | "USER_STYLESHEET" => array(__("Customize stylesheet")), |
||||||||
100 | "USER_TIMEZONE" => array(__("Time zone")), |
||||||||
101 | "VFEED_GROUP_BY_FEED" => array(__("Group by feed"), __("Group multiple-feed output by originating feed")), |
||||||||
102 | "USER_LANGUAGE" => array(__("Language")), |
||||||||
103 | "USER_CSS_THEME" => array(__("Theme")) |
||||||||
104 | ]; |
||||||||
105 | |||||||||
106 | $this->pref_blacklist = ["ALLOW_DUPLICATE_POSTS", "STRIP_UNSAFE_TAGS", "REVERSE_HEADLINES", |
||||||||
107 | "SORT_HEADLINES_BY_FEED_DATE", "DEFAULT_ARTICLE_LIMIT", |
||||||||
108 | "FEEDS_SORT_BY_UNREAD", "USER_STYLESHEET"]; |
||||||||
109 | |||||||||
110 | /* "FEEDS_SORT_BY_UNREAD", "HIDE_READ_FEEDS", "REVERSE_HEADLINES" */ |
||||||||
111 | |||||||||
112 | $this->profile_blacklist = ["ALLOW_DUPLICATE_POSTS", "PURGE_OLD_DAYS", |
||||||||
113 | "PURGE_UNREAD_ARTICLES", "DIGEST_ENABLE", "DIGEST_CATCHUP", |
||||||||
114 | "BLACKLISTED_TAGS", "ENABLE_API_ACCESS", "UPDATE_POST_ON_CHECKSUM_CHANGE", |
||||||||
115 | "DEFAULT_UPDATE_INTERVAL", "USER_TIMEZONE", "SORT_HEADLINES_BY_FEED_DATE", |
||||||||
116 | "SSL_CERT_SERIAL", "DIGEST_PREFERRED_TIME"]; |
||||||||
117 | } |
||||||||
118 | |||||||||
119 | public function changepassword() { |
||||||||
120 | |||||||||
121 | if (defined('_TTRSS_DEMO_INSTANCE')) { |
||||||||
122 | print "ERROR: ".format_error("Disabled in demo version."); |
||||||||
0 ignored issues
–
show
The function
format_error() has been deprecated: Use twig function errorMessage
(
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. ![]() Are you sure the usage of
format_error('Disabled in demo version.') 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. ![]() |
|||||||||
123 | return; |
||||||||
124 | } |
||||||||
125 | |||||||||
126 | $old_pw = clean($_POST["old_password"]); |
||||||||
127 | $new_pw = clean($_POST["new_password"]); |
||||||||
128 | $con_pw = clean($_POST["confirm_password"]); |
||||||||
129 | |||||||||
130 | if ($old_pw == $new_pw) { |
||||||||
131 | print "ERROR: ".format_error("New password must be different from the old one."); |
||||||||
0 ignored issues
–
show
Are you sure the usage of
format_error('New passwo...ent from the old one.') 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
format_error() has been deprecated: Use twig function errorMessage
(
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. ![]() |
|||||||||
132 | return; |
||||||||
133 | } |
||||||||
134 | |||||||||
135 | if ($old_pw == "") { |
||||||||
136 | print "ERROR: ".format_error("Old password cannot be blank."); |
||||||||
0 ignored issues
–
show
The function
format_error() has been deprecated: Use twig function errorMessage
(
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. ![]() Are you sure the usage of
format_error('Old password cannot be blank.') 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. ![]() |
|||||||||
137 | return; |
||||||||
138 | } |
||||||||
139 | |||||||||
140 | if ($new_pw == "") { |
||||||||
141 | print "ERROR: ".format_error("New password cannot be blank."); |
||||||||
0 ignored issues
–
show
The function
format_error() has been deprecated: Use twig function errorMessage
(
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. ![]() Are you sure the usage of
format_error('New password cannot be blank.') 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. ![]() |
|||||||||
142 | return; |
||||||||
143 | } |
||||||||
144 | |||||||||
145 | if ($new_pw != $con_pw) { |
||||||||
146 | print "ERROR: ".format_error("Entered passwords do not match."); |
||||||||
0 ignored issues
–
show
Are you sure the usage of
format_error('Entered passwords do not match.') 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
format_error() has been deprecated: Use twig function errorMessage
(
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. ![]() |
|||||||||
147 | return; |
||||||||
148 | } |
||||||||
149 | |||||||||
150 | $authenticator = PluginHost::getInstance()->get_plugin($_SESSION["auth_module"]); |
||||||||
151 | |||||||||
152 | if (method_exists($authenticator, "change_password")) { |
||||||||
153 | print format_notice($authenticator->change_password($_SESSION["uid"], $old_pw, $new_pw)); |
||||||||
0 ignored issues
–
show
The call to
format_notice() has too many arguments starting with $authenticator->change_p...id'], $old_pw, $new_pw) .
(
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 more 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. ![]() The function
format_notice() has been deprecated: Use twig function noticeMessage
(
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. ![]() Are you sure the usage of
format_notice($authentic...d'], $old_pw, $new_pw)) 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. ![]() |
|||||||||
154 | } else { |
||||||||
155 | print "ERROR: ".format_error("Function not supported by authentication module."); |
||||||||
0 ignored issues
–
show
The function
format_error() has been deprecated: Use twig function errorMessage
(
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. ![]() Are you sure the usage of
format_error('Function n...uthentication module.') 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. ![]() |
|||||||||
156 | } |
||||||||
157 | } |
||||||||
158 | |||||||||
159 | public function saveconfig() { |
||||||||
160 | $boolean_prefs = explode(",", clean($_POST["boolean_prefs"])); |
||||||||
0 ignored issues
–
show
It seems like
clean($_POST['boolean_prefs']) can also be of type array ; however, parameter $string of explode() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||
161 | |||||||||
162 | foreach ($boolean_prefs as $pref) { |
||||||||
163 | if (!isset($_POST[$pref])) { |
||||||||
164 | $_POST[$pref] = 'false'; |
||||||||
165 | } |
||||||||
166 | } |
||||||||
167 | |||||||||
168 | $need_reload = false; |
||||||||
169 | |||||||||
170 | foreach (array_keys($_POST) as $pref_name) { |
||||||||
171 | |||||||||
172 | $value = $_POST[$pref_name]; |
||||||||
173 | |||||||||
174 | switch ($pref_name) { |
||||||||
175 | case 'DIGEST_PREFERRED_TIME': |
||||||||
176 | if (get_pref('DIGEST_PREFERRED_TIME') != $value) { |
||||||||
177 | |||||||||
178 | $sth = $this->pdo->prepare("UPDATE ttrss_users SET |
||||||||
179 | last_digest_sent = NULL WHERE id = ?"); |
||||||||
180 | $sth->execute([$_SESSION['uid']]); |
||||||||
181 | |||||||||
182 | } |
||||||||
183 | break; |
||||||||
184 | case 'USER_LANGUAGE': |
||||||||
185 | if (!$need_reload) { |
||||||||
186 | $need_reload = $_SESSION["language"] != $value; |
||||||||
187 | } |
||||||||
188 | break; |
||||||||
189 | |||||||||
190 | case 'USER_CSS_THEME': |
||||||||
191 | if (!$need_reload) { |
||||||||
192 | $need_reload = get_pref($pref_name) != $value; |
||||||||
193 | } |
||||||||
194 | break; |
||||||||
195 | } |
||||||||
196 | |||||||||
197 | set_pref($pref_name, $value); |
||||||||
198 | } |
||||||||
199 | |||||||||
200 | if ($need_reload) { |
||||||||
0 ignored issues
–
show
|
|||||||||
201 | print "PREFS_NEED_RELOAD"; |
||||||||
202 | } else { |
||||||||
203 | print __("The configuration was saved."); |
||||||||
204 | } |
||||||||
205 | } |
||||||||
206 | |||||||||
207 | public function changeemail() { |
||||||||
208 | |||||||||
209 | $email = clean($_POST["email"]); |
||||||||
210 | $full_name = clean($_POST["full_name"]); |
||||||||
211 | $active_uid = $_SESSION["uid"]; |
||||||||
212 | |||||||||
213 | $sth = $this->pdo->prepare("SELECT email, login, full_name FROM ttrss_users WHERE id = ?"); |
||||||||
214 | $sth->execute([$active_uid]); |
||||||||
215 | |||||||||
216 | if ($row = $sth->fetch()) { |
||||||||
217 | $old_email = $row["email"]; |
||||||||
218 | |||||||||
219 | if ($old_email != $email) { |
||||||||
220 | $mailer = new Mailer(); |
||||||||
221 | |||||||||
222 | require_once "lib/MiniTemplator.class.php"; |
||||||||
223 | |||||||||
224 | $tpl = new MiniTemplator; |
||||||||
225 | |||||||||
226 | $tpl->readTemplateFromFile("templates/mail_change_template.txt"); |
||||||||
227 | |||||||||
228 | $tpl->setVariable('LOGIN', $row["login"]); |
||||||||
229 | $tpl->setVariable('NEWMAIL', $email); |
||||||||
0 ignored issues
–
show
It seems like
$email can also be of type array ; however, parameter $variableValue of MiniTemplator::setVariable() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||
230 | $tpl->setVariable('TTRSS_HOST', SELF_URL_PATH); |
||||||||
0 ignored issues
–
show
|
|||||||||
231 | |||||||||
232 | $tpl->addBlock('message'); |
||||||||
233 | |||||||||
234 | $tpl->generateOutputToString($message); |
||||||||
235 | |||||||||
236 | $mailer->mail(["to_name" => $row["login"], |
||||||||
237 | "to_address" => $row["email"], |
||||||||
238 | "subject" => "[tt-rss] Mail address change notification", |
||||||||
239 | "message" => $message]); |
||||||||
240 | |||||||||
241 | } |
||||||||
242 | } |
||||||||
243 | |||||||||
244 | $sth = $this->pdo->prepare("UPDATE ttrss_users SET email = ?, |
||||||||
245 | full_name = ? WHERE id = ?"); |
||||||||
246 | $sth->execute([$email, $full_name, $active_uid]); |
||||||||
247 | |||||||||
248 | print __("Your personal data has been saved."); |
||||||||
249 | |||||||||
250 | return; |
||||||||
251 | } |
||||||||
252 | |||||||||
253 | public function resetconfig() { |
||||||||
254 | |||||||||
255 | $_SESSION["prefs_op_result"] = "reset-to-defaults"; |
||||||||
256 | |||||||||
257 | $sth = $this->pdo->prepare("DELETE FROM ttrss_user_prefs |
||||||||
258 | WHERE (profile = :profile OR (:profile IS NULL AND profile IS NULL)) |
||||||||
259 | AND owner_uid = :uid"); |
||||||||
260 | $sth->execute([":profile" => $_SESSION['profile'], ":uid" => $_SESSION['uid']]); |
||||||||
261 | |||||||||
262 | initialize_user_prefs($_SESSION["uid"], $_SESSION["profile"]); |
||||||||
263 | |||||||||
264 | echo __("Your preferences are now set to default values."); |
||||||||
265 | } |
||||||||
266 | |||||||||
267 | public function index() { |
||||||||
268 | |||||||||
269 | global $access_level_names; |
||||||||
270 | |||||||||
271 | $_SESSION["prefs_op_result"] = ""; |
||||||||
272 | |||||||||
273 | print "<div dojoType='dijit.layout.AccordionContainer' region='center'>"; |
||||||||
274 | print "<div dojoType='dijit.layout.AccordionPane' |
||||||||
275 | title=\"<i class='material-icons'>person</i> ".__('Personal data / Authentication')."\">"; |
||||||||
276 | |||||||||
277 | print "<div dojoType='dijit.layout.TabContainer'>"; |
||||||||
278 | print "<div dojoType='dijit.layout.ContentPane' title=\"".__('Personal data')."\">"; |
||||||||
279 | |||||||||
280 | print "<form dojoType='dijit.form.Form' id='changeUserdataForm'>"; |
||||||||
281 | |||||||||
282 | print "<script type='dojo/method' event='onSubmit' args='evt'> |
||||||||
283 | evt.preventDefault(); |
||||||||
284 | if (this.validate()) { |
||||||||
285 | Notify.progress('Saving data...', true); |
||||||||
286 | |||||||||
287 | new Ajax.Request('backend.php', { |
||||||||
288 | parameters: dojo.objectToQuery(this.getValues()), |
||||||||
289 | onComplete: function(transport) { |
||||||||
290 | notify_callback2(transport); |
||||||||
291 | } }); |
||||||||
292 | |||||||||
293 | } |
||||||||
294 | </script>"; |
||||||||
295 | |||||||||
296 | $sth = $this->pdo->prepare("SELECT email,full_name,otp_enabled, |
||||||||
297 | access_level FROM ttrss_users |
||||||||
298 | WHERE id = ?"); |
||||||||
299 | $sth->execute([$_SESSION["uid"]]); |
||||||||
300 | $row = $sth->fetch(); |
||||||||
301 | |||||||||
302 | $email = htmlspecialchars($row["email"]); |
||||||||
303 | $full_name = htmlspecialchars($row["full_name"]); |
||||||||
304 | $otp_enabled = sql_bool_to_bool($row["otp_enabled"]); |
||||||||
305 | |||||||||
306 | print "<fieldset>"; |
||||||||
307 | print "<label>".__('Full name:')."</label>"; |
||||||||
308 | print "<input dojoType='dijit.form.ValidationTextBox' name='full_name' required='1' value='$full_name'>"; |
||||||||
309 | print "</fieldset>"; |
||||||||
310 | |||||||||
311 | print "<fieldset>"; |
||||||||
312 | print "<label>".__('E-mail:')."</label>"; |
||||||||
313 | print "<input dojoType='dijit.form.ValidationTextBox' name='email' required='1' value='$email'>"; |
||||||||
314 | print "</fieldset>"; |
||||||||
315 | |||||||||
316 | if (!SINGLE_USER_MODE && !$_SESSION["hide_hello"]) { |
||||||||
0 ignored issues
–
show
|
|||||||||
317 | |||||||||
318 | $access_level = $row["access_level"]; |
||||||||
319 | print "<fieldset>"; |
||||||||
320 | print "<label>".__('Access level:')."</label>"; |
||||||||
321 | print $access_level_names[$access_level]; |
||||||||
322 | print "</fieldset>"; |
||||||||
323 | } |
||||||||
324 | |||||||||
325 | print_hidden("op", "pref-prefs"); |
||||||||
326 | print_hidden("method", "changeemail"); |
||||||||
327 | |||||||||
328 | print "<hr/>"; |
||||||||
329 | |||||||||
330 | print "<button dojoType='dijit.form.Button' type='submit' class='alt-primary'>". |
||||||||
331 | __("Save data")."</button>"; |
||||||||
332 | |||||||||
333 | print "</form>"; |
||||||||
334 | |||||||||
335 | print "</div>"; # content pane |
||||||||
336 | print "<div dojoType='dijit.layout.ContentPane' title=\"".__('Password')."\">"; |
||||||||
337 | |||||||||
338 | if ($_SESSION["auth_module"]) { |
||||||||
339 | $authenticator = PluginHost::getInstance()->get_plugin($_SESSION["auth_module"]); |
||||||||
340 | } else { |
||||||||
341 | $authenticator = false; |
||||||||
342 | } |
||||||||
343 | |||||||||
344 | if ($authenticator && method_exists($authenticator, "change_password")) { |
||||||||
345 | |||||||||
346 | print "<div style='display : none' id='pwd_change_infobox'></div>"; |
||||||||
347 | |||||||||
348 | print "<form dojoType='dijit.form.Form'>"; |
||||||||
349 | |||||||||
350 | print "<script type='dojo/method' event='onSubmit' args='evt'> |
||||||||
351 | evt.preventDefault(); |
||||||||
352 | if (this.validate()) { |
||||||||
353 | Notify.progress('Changing password...', true); |
||||||||
354 | |||||||||
355 | new Ajax.Request('backend.php', { |
||||||||
356 | parameters: dojo.objectToQuery(this.getValues()), |
||||||||
357 | onComplete: function(transport) { |
||||||||
358 | Notify.close(); |
||||||||
359 | if (transport.responseText.indexOf('ERROR: ') == 0) { |
||||||||
360 | |||||||||
361 | $('pwd_change_infobox').innerHTML = |
||||||||
362 | transport.responseText.replace('ERROR: ', ''); |
||||||||
363 | |||||||||
364 | } else { |
||||||||
365 | $('pwd_change_infobox').innerHTML = |
||||||||
366 | transport.responseText.replace('ERROR: ', ''); |
||||||||
367 | |||||||||
368 | var warn = $('default_pass_warning'); |
||||||||
369 | if (warn) Element.hide(warn); |
||||||||
370 | } |
||||||||
371 | |||||||||
372 | new Effect.Appear('pwd_change_infobox'); |
||||||||
373 | |||||||||
374 | }}); |
||||||||
375 | this.reset(); |
||||||||
376 | } |
||||||||
377 | </script>"; |
||||||||
378 | |||||||||
379 | if ($otp_enabled) { |
||||||||
380 | print_notice(__("Changing your current password will disable OTP.")); |
||||||||
0 ignored issues
–
show
The call to
print_notice() has too many arguments starting with __('Changing your curren...ord will disable OTP.') .
(
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 more 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. ![]() The function
print_notice() has been deprecated: Use twig function noticeMessage
(
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. ![]() |
|||||||||
381 | } |
||||||||
382 | |||||||||
383 | print "<fieldset>"; |
||||||||
384 | print "<label>".__("Old password:")."</label>"; |
||||||||
385 | print "<input dojoType='dijit.form.ValidationTextBox' type='password' required='1' name='old_password'>"; |
||||||||
386 | print "</fieldset>"; |
||||||||
387 | |||||||||
388 | print "<fieldset>"; |
||||||||
389 | print "<label>".__("New password:")."</label>"; |
||||||||
390 | print "<input dojoType='dijit.form.ValidationTextBox' type='password' required='1' name='new_password'>"; |
||||||||
391 | print "</fieldset>"; |
||||||||
392 | |||||||||
393 | print "<fieldset>"; |
||||||||
394 | print "<label>".__("Confirm password:")."</label>"; |
||||||||
395 | print "<input dojoType='dijit.form.ValidationTextBox' type='password' required='1' name='confirm_password'>"; |
||||||||
396 | print "</fieldset>"; |
||||||||
397 | |||||||||
398 | print_hidden("op", "pref-prefs"); |
||||||||
399 | print_hidden("method", "changepassword"); |
||||||||
400 | |||||||||
401 | print "<hr/>"; |
||||||||
402 | |||||||||
403 | print "<button dojoType='dijit.form.Button' type='submit' class='alt-primary'>". |
||||||||
404 | __("Change password")."</button>"; |
||||||||
405 | |||||||||
406 | print "</form>"; |
||||||||
407 | |||||||||
408 | print "</div>"; # content pane |
||||||||
409 | |||||||||
410 | if ($_SESSION["auth_module"] == "auth_internal") { |
||||||||
411 | |||||||||
412 | print "<div dojoType='dijit.layout.ContentPane' title=\"".__('App passwords')."\">"; |
||||||||
413 | |||||||||
414 | print_notice("You can create separate passwords for API clients. Using one is required if you enable OTP."); |
||||||||
0 ignored issues
–
show
The function
print_notice() has been deprecated: Use twig function noticeMessage
(
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. ![]() |
|||||||||
415 | |||||||||
416 | print "<div id='app_passwords_holder'>"; |
||||||||
417 | $this->appPasswordList(); |
||||||||
418 | print "</div>"; |
||||||||
419 | |||||||||
420 | print "<hr>"; |
||||||||
421 | |||||||||
422 | print "<button style='float : left' class='alt-primary' dojoType='dijit.form.Button' |
||||||||
423 | onclick=\"Helpers.AppPasswords.generate()\">" . |
||||||||
424 | __('Generate new password')."</button> "; |
||||||||
425 | |||||||||
426 | print "<button style='float : left' class='alt-danger' dojoType='dijit.form.Button' |
||||||||
427 | onclick=\"Helpers.AppPasswords.removeSelected()\">" . |
||||||||
428 | __('Remove selected passwords')."</button>"; |
||||||||
429 | |||||||||
430 | print "</div>"; # content pane |
||||||||
431 | } |
||||||||
432 | |||||||||
433 | print "<div dojoType='dijit.layout.ContentPane' title=\"".__('One time passwords / Authenticator')."\">"; |
||||||||
434 | |||||||||
435 | if ($_SESSION["auth_module"] == "auth_internal") { |
||||||||
436 | |||||||||
437 | if ($otp_enabled) { |
||||||||
438 | |||||||||
439 | print_warning("One time passwords are currently enabled. Enter your current password below to disable."); |
||||||||
0 ignored issues
–
show
The call to
print_warning() has too many arguments starting with 'One time passwords are ...word below to disable.' .
(
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 more 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. ![]() The function
print_warning() has been deprecated: Use twig function warningMessage
(
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. ![]() |
|||||||||
440 | |||||||||
441 | print "<form dojoType='dijit.form.Form'>"; |
||||||||
442 | |||||||||
443 | print "<script type='dojo/method' event='onSubmit' args='evt'> |
||||||||
444 | evt.preventDefault(); |
||||||||
445 | if (this.validate()) { |
||||||||
446 | Notify.progress('Disabling OTP', true); |
||||||||
447 | |||||||||
448 | new Ajax.Request('backend.php', { |
||||||||
449 | parameters: dojo.objectToQuery(this.getValues()), |
||||||||
450 | onComplete: function(transport) { |
||||||||
451 | Notify.close(); |
||||||||
452 | if (transport.responseText.indexOf('ERROR: ') == 0) { |
||||||||
453 | Notify.error(transport.responseText.replace('ERROR: ', '')); |
||||||||
454 | } else { |
||||||||
455 | window.location.reload(); |
||||||||
456 | } |
||||||||
457 | }}); |
||||||||
458 | this.reset(); |
||||||||
459 | } |
||||||||
460 | </script>"; |
||||||||
461 | |||||||||
462 | print "<fieldset>"; |
||||||||
463 | print "<label>".__("Your password:")."</label>"; |
||||||||
464 | print "<input dojoType='dijit.form.ValidationTextBox' type='password' required='1' name='password'>"; |
||||||||
465 | print "</fieldset>"; |
||||||||
466 | |||||||||
467 | print_hidden("op", "pref-prefs"); |
||||||||
468 | print_hidden("method", "otpdisable"); |
||||||||
469 | |||||||||
470 | print "<hr/>"; |
||||||||
471 | |||||||||
472 | print "<button dojoType='dijit.form.Button' type='submit'>". |
||||||||
473 | __("Disable OTP")."</button>"; |
||||||||
474 | |||||||||
475 | print "</form>"; |
||||||||
476 | |||||||||
477 | } else { |
||||||||
478 | |||||||||
479 | print_warning("You will need a compatible Authenticator to use this. Changing your password would automatically disable OTP."); |
||||||||
0 ignored issues
–
show
The function
print_warning() has been deprecated: Use twig function warningMessage
(
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. ![]() |
|||||||||
480 | print_notice("You will need to generate app passwords for the API clients if you enable OTP."); |
||||||||
0 ignored issues
–
show
The function
print_notice() has been deprecated: Use twig function noticeMessage
(
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. ![]() |
|||||||||
481 | |||||||||
482 | if (function_exists("imagecreatefromstring")) { |
||||||||
483 | print "<h3>".__("Scan the following code by the Authenticator application or copy the key manually")."</h3>"; |
||||||||
484 | |||||||||
485 | $csrf_token = $_SESSION["csrf_token"]; |
||||||||
486 | print "<img alt='otp qr-code' src='backend.php?op=pref-prefs&method=otpqrcode&csrf_token=$csrf_token'>"; |
||||||||
487 | } else { |
||||||||
488 | print_error("PHP GD functions are required to generate QR codes."); |
||||||||
0 ignored issues
–
show
The call to
print_error() has too many arguments starting with 'PHP GD functions are re... to generate QR codes.' .
(
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 more 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. ![]() The function
print_error() has been deprecated: Use twig function errorMessage
(
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. ![]() |
|||||||||
489 | print "<h3>".__("Use the following OTP key with a compatible Authenticator application")."</h3>"; |
||||||||
490 | } |
||||||||
491 | |||||||||
492 | print "<form dojoType='dijit.form.Form' id='changeOtpForm'>"; |
||||||||
493 | |||||||||
494 | $otp_secret = $this->otpsecret(); |
||||||||
495 | |||||||||
496 | print "<fieldset>"; |
||||||||
497 | print "<label>".__("OTP Key:")."</label>"; |
||||||||
498 | print "<input dojoType='dijit.form.ValidationTextBox' disabled='disabled' value='$otp_secret' size='32'>"; |
||||||||
499 | print "</fieldset>"; |
||||||||
500 | |||||||||
501 | print_hidden("op", "pref-prefs"); |
||||||||
502 | print_hidden("method", "otpenable"); |
||||||||
503 | |||||||||
504 | print "<script type='dojo/method' event='onSubmit' args='evt'> |
||||||||
505 | evt.preventDefault(); |
||||||||
506 | if (this.validate()) { |
||||||||
507 | Notify.progress('Saving data...', true); |
||||||||
508 | |||||||||
509 | new Ajax.Request('backend.php', { |
||||||||
510 | parameters: dojo.objectToQuery(this.getValues()), |
||||||||
511 | onComplete: function(transport) { |
||||||||
512 | Notify.close(); |
||||||||
513 | if (transport.responseText.indexOf('ERROR:') == 0) { |
||||||||
514 | Notify.error(transport.responseText.replace('ERROR:', '')); |
||||||||
515 | } else { |
||||||||
516 | window.location.reload(); |
||||||||
517 | } |
||||||||
518 | } }); |
||||||||
519 | |||||||||
520 | } |
||||||||
521 | </script>"; |
||||||||
522 | |||||||||
523 | print "<fieldset>"; |
||||||||
524 | print "<label>".__("Your password:")."</label>"; |
||||||||
525 | print "<input dojoType='dijit.form.ValidationTextBox' type='password' required='1' |
||||||||
526 | name='password'>"; |
||||||||
527 | print "</fieldset>"; |
||||||||
528 | |||||||||
529 | print "<fieldset>"; |
||||||||
530 | print "<label>".__("One time password:")."</label>"; |
||||||||
531 | print "<input dojoType='dijit.form.ValidationTextBox' autocomplete='off' |
||||||||
532 | required='1' name='otp'>"; |
||||||||
533 | print "</fieldset>"; |
||||||||
534 | |||||||||
535 | print "<hr/>"; |
||||||||
536 | print "<button dojoType='dijit.form.Button' type='submit' class='alt-primary'>". |
||||||||
537 | __("Enable OTP")."</button>"; |
||||||||
538 | |||||||||
539 | print "</form>"; |
||||||||
540 | |||||||||
541 | } |
||||||||
542 | } |
||||||||
543 | |||||||||
544 | print "</div>"; # content pane |
||||||||
545 | print "</div>"; # tab container |
||||||||
546 | |||||||||
547 | } |
||||||||
548 | |||||||||
549 | PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, |
||||||||
550 | "hook_prefs_tab_section", "prefPrefsAuth"); |
||||||||
551 | |||||||||
552 | print "</div>"; #pane |
||||||||
553 | |||||||||
554 | print "<div dojoType='dijit.layout.AccordionPane' selected='true' |
||||||||
555 | title=\"<i class='material-icons'>settings</i> ".__('Preferences')."\">"; |
||||||||
556 | |||||||||
557 | print "<form dojoType='dijit.form.Form' id='changeSettingsForm'>"; |
||||||||
558 | |||||||||
559 | print "<script type='dojo/method' event='onSubmit' args='evt, quit'> |
||||||||
560 | if (evt) evt.preventDefault(); |
||||||||
561 | if (this.validate()) { |
||||||||
562 | console.log(dojo.objectToQuery(this.getValues())); |
||||||||
563 | |||||||||
564 | new Ajax.Request('backend.php', { |
||||||||
565 | parameters: dojo.objectToQuery(this.getValues()), |
||||||||
566 | onComplete: function(transport) { |
||||||||
567 | var msg = transport.responseText; |
||||||||
568 | if (quit) { |
||||||||
569 | document.location.href = 'index.php'; |
||||||||
570 | } else { |
||||||||
571 | if (msg == 'PREFS_NEED_RELOAD') { |
||||||||
572 | window.location.reload(); |
||||||||
573 | } else { |
||||||||
574 | Notify.info(msg); |
||||||||
575 | } |
||||||||
576 | } |
||||||||
577 | } }); |
||||||||
578 | } |
||||||||
579 | </script>"; |
||||||||
580 | |||||||||
581 | print '<div dojoType="dijit.layout.BorderContainer" gutters="false">'; |
||||||||
582 | |||||||||
583 | print '<div dojoType="dijit.layout.ContentPane" region="center" style="overflow-y : auto">'; |
||||||||
584 | |||||||||
585 | $profile = $_SESSION["profile"]; |
||||||||
586 | |||||||||
587 | if ($profile) { |
||||||||
588 | print_notice(__("Some preferences are only available in default profile.")); |
||||||||
0 ignored issues
–
show
The function
print_notice() has been deprecated: Use twig function noticeMessage
(
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. ![]() |
|||||||||
589 | |||||||||
590 | initialize_user_prefs($_SESSION["uid"], $profile); |
||||||||
591 | } else { |
||||||||
592 | initialize_user_prefs($_SESSION["uid"]); |
||||||||
593 | } |
||||||||
594 | |||||||||
595 | $prefs_available = []; |
||||||||
596 | |||||||||
597 | $sth = $this->pdo->prepare("SELECT DISTINCT |
||||||||
598 | ttrss_user_prefs.pref_name,value,type_name, |
||||||||
599 | ttrss_prefs_sections.order_id, |
||||||||
600 | def_value,section_id |
||||||||
601 | FROM ttrss_prefs,ttrss_prefs_types,ttrss_prefs_sections,ttrss_user_prefs |
||||||||
602 | WHERE type_id = ttrss_prefs_types.id AND |
||||||||
603 | (profile = :profile OR (:profile IS NULL AND profile IS NULL)) AND |
||||||||
604 | section_id = ttrss_prefs_sections.id AND |
||||||||
605 | ttrss_user_prefs.pref_name = ttrss_prefs.pref_name AND |
||||||||
606 | owner_uid = :uid |
||||||||
607 | ORDER BY ttrss_prefs_sections.order_id,pref_name"); |
||||||||
608 | $sth->execute([":uid" => $_SESSION['uid'], ":profile" => $profile]); |
||||||||
609 | |||||||||
610 | $listed_boolean_prefs = []; |
||||||||
611 | |||||||||
612 | while ($line = $sth->fetch()) { |
||||||||
613 | |||||||||
614 | if (in_array($line["pref_name"], $this->pref_blacklist)) { |
||||||||
615 | continue; |
||||||||
616 | } |
||||||||
617 | |||||||||
618 | if ($profile && in_array($line["pref_name"], $this->profile_blacklist)) { |
||||||||
619 | continue; |
||||||||
620 | } |
||||||||
621 | |||||||||
622 | $pref_name = $line["pref_name"]; |
||||||||
623 | $short_desc = $this->getShortDesc($pref_name); |
||||||||
624 | |||||||||
625 | if (!$short_desc) { |
||||||||
626 | continue; |
||||||||
627 | } |
||||||||
628 | |||||||||
629 | $prefs_available[$pref_name] = [ |
||||||||
630 | 'type_name' => $line["type_name"], |
||||||||
631 | 'value' => $line['value'], |
||||||||
632 | 'help_text' => $this->getHelpText($pref_name), |
||||||||
633 | 'short_desc' => $short_desc |
||||||||
634 | ]; |
||||||||
635 | } |
||||||||
636 | |||||||||
637 | foreach (array_keys($this->pref_item_map) as $section) { |
||||||||
638 | |||||||||
639 | print "<h2>$section</h2>"; |
||||||||
640 | |||||||||
641 | foreach ($this->pref_item_map[$section] as $pref_name) { |
||||||||
642 | |||||||||
643 | if ($pref_name == 'BLOCK_SEPARATOR' && !$profile) { |
||||||||
644 | print "<hr/>"; |
||||||||
645 | continue; |
||||||||
646 | } |
||||||||
647 | |||||||||
648 | if ($pref_name == "DEFAULT_SEARCH_LANGUAGE" && DB_TYPE != "pgsql") { |
||||||||
0 ignored issues
–
show
|
|||||||||
649 | continue; |
||||||||
650 | } |
||||||||
651 | |||||||||
652 | if ($item = $prefs_available[$pref_name]) { |
||||||||
653 | |||||||||
654 | print "<fieldset class='prefs'>"; |
||||||||
655 | |||||||||
656 | print "<label for='CB_$pref_name'>"; |
||||||||
657 | print $item['short_desc'].":"; |
||||||||
658 | print "</label>"; |
||||||||
659 | |||||||||
660 | $value = $item['value']; |
||||||||
661 | $type_name = $item['type_name']; |
||||||||
662 | |||||||||
663 | if ($pref_name == "USER_LANGUAGE") { |
||||||||
664 | print_select_hash($pref_name, $value, get_translations(), |
||||||||
665 | "style='width : 220px; margin : 0px' dojoType='fox.form.Select'"); |
||||||||
666 | |||||||||
667 | } else if ($pref_name == "USER_TIMEZONE") { |
||||||||
668 | |||||||||
669 | $timezones = explode("\n", file_get_contents("lib/timezones.txt")); |
||||||||
670 | |||||||||
671 | print_select($pref_name, $value, $timezones, 'dojoType="dijit.form.FilteringSelect"'); |
||||||||
672 | } else if ($pref_name == "USER_CSS_THEME") { |
||||||||
673 | |||||||||
674 | $themes = array_merge(glob("themes/*.php"), glob("themes/*.css"), glob("themes.local/*.css")); |
||||||||
0 ignored issues
–
show
It seems like
glob('themes.local/*.css') can also be of type false ; however, parameter $_ of array_merge() does only seem to accept array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() It seems like
glob('themes/*.php') can also be of type false ; however, parameter $array1 of array_merge() does only seem to accept array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() It seems like
glob('themes/*.css') can also be of type false ; however, parameter $array2 of array_merge() does only seem to accept array|null , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||
675 | $themes = array_map("basename", $themes); |
||||||||
676 | $themes = array_filter($themes, "theme_exists"); |
||||||||
677 | asort($themes); |
||||||||
678 | |||||||||
679 | if (!theme_exists($value)) { |
||||||||
680 | $value = "default.php"; |
||||||||
681 | } |
||||||||
682 | |||||||||
683 | print "<select name='$pref_name' id='$pref_name' dojoType='fox.form.Select'>"; |
||||||||
684 | |||||||||
685 | $issel = $value == "default.php" ? "selected='selected'" : ""; |
||||||||
686 | print "<option $issel value='default.php'>".__("default")."</option>"; |
||||||||
687 | |||||||||
688 | foreach ($themes as $theme) { |
||||||||
689 | $issel = $value == $theme ? "selected='selected'" : ""; |
||||||||
690 | print "<option $issel value='$theme'>$theme</option>"; |
||||||||
691 | } |
||||||||
692 | |||||||||
693 | print "</select>"; |
||||||||
694 | |||||||||
695 | print " <button dojoType=\"dijit.form.Button\" class='alt-info' |
||||||||
696 | onclick=\"Helpers.customizeCSS()\">" . __('Customize')."</button>"; |
||||||||
697 | |||||||||
698 | print " <button dojoType='dijit.form.Button' onclick='window.open(\"https://tt-rss.org/wiki/Themes\")'> |
||||||||
699 | <i class='material-icons'>open_in_new</i> ".__("More themes...")."</button>"; |
||||||||
700 | |||||||||
701 | } else if ($pref_name == "DEFAULT_UPDATE_INTERVAL") { |
||||||||
702 | |||||||||
703 | global $update_intervals_nodefault; |
||||||||
704 | |||||||||
705 | print_select_hash($pref_name, $value, $update_intervals_nodefault, |
||||||||
706 | 'dojoType="fox.form.Select"'); |
||||||||
707 | } else if ($pref_name == "DEFAULT_SEARCH_LANGUAGE") { |
||||||||
708 | |||||||||
709 | print_select($pref_name, $value, Pref_Feeds::get_ts_languages(), |
||||||||
710 | 'dojoType="fox.form.Select"'); |
||||||||
711 | |||||||||
712 | } else if ($type_name == "bool") { |
||||||||
713 | |||||||||
714 | array_push($listed_boolean_prefs, $pref_name); |
||||||||
715 | |||||||||
716 | $checked = ($value == "true") ? "checked=\"checked\"" : ""; |
||||||||
717 | |||||||||
718 | if ($pref_name == "PURGE_UNREAD_ARTICLES" && FORCE_ARTICLE_PURGE != 0) { |
||||||||
0 ignored issues
–
show
|
|||||||||
719 | $disabled = "disabled=\"1\""; |
||||||||
720 | $checked = "checked=\"checked\""; |
||||||||
721 | } else { |
||||||||
722 | $disabled = ""; |
||||||||
723 | } |
||||||||
724 | |||||||||
725 | print "<input type='checkbox' name='$pref_name' $checked $disabled |
||||||||
726 | dojoType='dijit.form.CheckBox' id='CB_$pref_name' value='1'>"; |
||||||||
727 | |||||||||
728 | } else if (array_search($pref_name, array('FRESH_ARTICLE_MAX_AGE', |
||||||||
729 | 'PURGE_OLD_DAYS', 'LONG_DATE_FORMAT', 'SHORT_DATE_FORMAT')) !== false) { |
||||||||
730 | |||||||||
731 | $regexp = ($type_name == 'integer') ? 'regexp="^\d*$"' : ''; |
||||||||
732 | |||||||||
733 | if ($pref_name == "PURGE_OLD_DAYS" && FORCE_ARTICLE_PURGE != 0) { |
||||||||
734 | $disabled = "disabled='1'"; |
||||||||
735 | $value = FORCE_ARTICLE_PURGE; |
||||||||
736 | } else { |
||||||||
737 | $disabled = ""; |
||||||||
738 | } |
||||||||
739 | |||||||||
740 | if ($type_name == 'integer') { |
||||||||
741 | print "<input dojoType=\"dijit.form.NumberSpinner\" |
||||||||
742 | required='1' $disabled |
||||||||
743 | name=\"$pref_name\" value=\"$value\">"; |
||||||||
744 | } else { |
||||||||
745 | print "<input dojoType=\"dijit.form.TextBox\" |
||||||||
746 | required='1' $regexp $disabled |
||||||||
747 | name=\"$pref_name\" value=\"$value\">"; |
||||||||
748 | } |
||||||||
749 | |||||||||
750 | } else if ($pref_name == "SSL_CERT_SERIAL") { |
||||||||
751 | |||||||||
752 | print "<input dojoType='dijit.form.ValidationTextBox' |
||||||||
753 | id='SSL_CERT_SERIAL' readonly='1' |
||||||||
754 | name=\"$pref_name\" value=\"$value\">"; |
||||||||
755 | |||||||||
756 | $cert_serial = htmlspecialchars(get_ssl_certificate_id()); |
||||||||
757 | $has_serial = ($cert_serial) ? "false" : "true"; |
||||||||
758 | |||||||||
759 | print "<button dojoType='dijit.form.Button' disabled='$has_serial' |
||||||||
760 | onclick=\"dijit.byId('SSL_CERT_SERIAL').attr('value', '$cert_serial')\">". |
||||||||
761 | __('Register')."</button>"; |
||||||||
762 | |||||||||
763 | print "<button dojoType='dijit.form.Button' class='alt-danger' |
||||||||
764 | onclick=\"dijit.byId('SSL_CERT_SERIAL').attr('value', '')\">" . |
||||||||
765 | __('Clear')."</button>"; |
||||||||
766 | |||||||||
767 | print "<button dojoType='dijit.form.Button' class='alt-info' |
||||||||
768 | onclick='window.open(\"https://tt-rss.org/wiki/SSL%20Certificate%20Authentication\")'> |
||||||||
769 | <i class='material-icons'>help</i> ".__("More info...")."</button>"; |
||||||||
770 | |||||||||
771 | } else if ($pref_name == 'DIGEST_PREFERRED_TIME') { |
||||||||
772 | print "<input dojoType=\"dijit.form.ValidationTextBox\" |
||||||||
773 | id=\"$pref_name\" regexp=\"[012]?\d:\d\d\" placeHolder=\"12:00\" |
||||||||
774 | name=\"$pref_name\" value=\"$value\">"; |
||||||||
775 | |||||||||
776 | $item['help_text'] .= ". ".T_sprintf("Current server time: %s", date("H:i")); |
||||||||
777 | } else { |
||||||||
778 | $regexp = ($type_name == 'integer') ? 'regexp="^\d*$"' : ''; |
||||||||
779 | |||||||||
780 | print "<input dojoType=\"dijit.form.ValidationTextBox\" $regexp name=\"$pref_name\" value=\"$value\">"; |
||||||||
781 | } |
||||||||
782 | |||||||||
783 | if ($item['help_text']) { |
||||||||
784 | print "<div class='help-text text-muted'><label for='CB_$pref_name'>".$item['help_text']."</label></div>"; |
||||||||
785 | } |
||||||||
786 | |||||||||
787 | print "</fieldset>"; |
||||||||
788 | } |
||||||||
789 | } |
||||||||
790 | } |
||||||||
791 | |||||||||
792 | $listed_boolean_prefs = htmlspecialchars(join(",", $listed_boolean_prefs)); |
||||||||
793 | |||||||||
794 | print_hidden("boolean_prefs", "$listed_boolean_prefs"); |
||||||||
795 | |||||||||
796 | PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, |
||||||||
797 | "hook_prefs_tab_section", "prefPrefsPrefsInside"); |
||||||||
798 | |||||||||
799 | print '</div>'; # inside pane |
||||||||
800 | print '<div dojoType="dijit.layout.ContentPane" region="bottom">'; |
||||||||
801 | |||||||||
802 | print_hidden("op", "pref-prefs"); |
||||||||
803 | print_hidden("method", "saveconfig"); |
||||||||
804 | |||||||||
805 | print "<div dojoType=\"fox.form.ComboButton\" type=\"submit\" class=\"alt-primary\"> |
||||||||
806 | <span>".__('Save configuration')."</span> |
||||||||
807 | <div dojoType=\"dijit.DropDownMenu\"> |
||||||||
808 | <div dojoType=\"dijit.MenuItem\" |
||||||||
809 | onclick=\"dijit.byId('changeSettingsForm').onSubmit(null, true)\">". |
||||||||
810 | __("Save and exit preferences")."</div> |
||||||||
811 | </div> |
||||||||
812 | </div>"; |
||||||||
813 | |||||||||
814 | print "<button dojoType=\"dijit.form.Button\" onclick=\"return Helpers.editProfiles()\">". |
||||||||
815 | __('Manage profiles')."</button> "; |
||||||||
816 | |||||||||
817 | print "<button dojoType=\"dijit.form.Button\" class=\"alt-danger\" onclick=\"return Helpers.confirmReset()\">". |
||||||||
818 | __('Reset to defaults')."</button>"; |
||||||||
819 | |||||||||
820 | print " "; |
||||||||
821 | |||||||||
822 | PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, |
||||||||
823 | "hook_prefs_tab_section", "prefPrefsPrefsOutside"); |
||||||||
824 | |||||||||
825 | print "</form>"; |
||||||||
826 | print '</div>'; # inner pane |
||||||||
827 | print '</div>'; # border container |
||||||||
828 | |||||||||
829 | print "</div>"; #pane |
||||||||
830 | |||||||||
831 | print "<div dojoType=\"dijit.layout.AccordionPane\" |
||||||||
832 | title=\"<i class='material-icons'>extension</i> ".__('Plugins')."\">"; |
||||||||
833 | |||||||||
834 | print "<form dojoType=\"dijit.form.Form\" id=\"changePluginsForm\">"; |
||||||||
835 | |||||||||
836 | print "<script type=\"dojo/method\" event=\"onSubmit\" args=\"evt\"> |
||||||||
837 | evt.preventDefault(); |
||||||||
838 | if (this.validate()) { |
||||||||
839 | Notify.progress('Saving data...', true); |
||||||||
840 | |||||||||
841 | new Ajax.Request('backend.php', { |
||||||||
842 | parameters: dojo.objectToQuery(this.getValues()), |
||||||||
843 | onComplete: function(transport) { |
||||||||
844 | Notify.close(); |
||||||||
845 | if (confirm(__('Selected plugins have been enabled. Reload?'))) { |
||||||||
846 | window.location.reload(); |
||||||||
847 | } |
||||||||
848 | } }); |
||||||||
849 | |||||||||
850 | } |
||||||||
851 | </script>"; |
||||||||
852 | |||||||||
853 | print_hidden("op", "pref-prefs"); |
||||||||
854 | print_hidden("method", "setplugins"); |
||||||||
855 | |||||||||
856 | print '<div dojoType="dijit.layout.BorderContainer" gutters="false">'; |
||||||||
857 | print '<div dojoType="dijit.layout.ContentPane" region="center" style="overflow-y : auto">'; |
||||||||
858 | |||||||||
859 | if (ini_get("open_basedir") && function_exists("curl_init") && !defined("NO_CURL")) { |
||||||||
860 | print_warning("Your PHP configuration has open_basedir restrictions enabled. Some plugins relying on CURL for functionality may not work correctly."); |
||||||||
0 ignored issues
–
show
The function
print_warning() has been deprecated: Use twig function warningMessage
(
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. ![]() |
|||||||||
861 | } |
||||||||
862 | |||||||||
863 | $feed_handler_whitelist = ["Af_Comics"]; |
||||||||
864 | |||||||||
865 | $feed_handlers = array_merge( |
||||||||
866 | PluginHost::getInstance()->get_hooks(PluginHost::HOOK_FEED_FETCHED), |
||||||||
867 | PluginHost::getInstance()->get_hooks(PluginHost::HOOK_FEED_PARSED), |
||||||||
868 | PluginHost::getInstance()->get_hooks(PluginHost::HOOK_FETCH_FEED)); |
||||||||
869 | |||||||||
870 | $feed_handlers = array_filter($feed_handlers, function($plugin) use ($feed_handler_whitelist) { |
||||||||
871 | return in_array(get_class($plugin), $feed_handler_whitelist) === false; }); |
||||||||
872 | |||||||||
873 | if (count($feed_handlers) > 0) { |
||||||||
874 | print_error( |
||||||||
0 ignored issues
–
show
The function
print_error() has been deprecated: Use twig function errorMessage
(
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. ![]() |
|||||||||
875 | T_sprintf("The following plugins use per-feed content hooks. This may cause excessive data usage and origin server load resulting in a ban of your instance: <b>%s</b>", |
||||||||
876 | implode(", ", array_map(function($plugin) { return get_class($plugin); }, $feed_handlers)) |
||||||||
877 | )." (<a href='https://tt-rss.org/wiki/FeedHandlerPlugins' target='_blank'>".__("More info...")."</a>)" |
||||||||
878 | ); |
||||||||
879 | } |
||||||||
880 | |||||||||
881 | print "<h2>".__("System plugins")."</h2>"; |
||||||||
882 | print_notice("System plugins are enabled in <strong>config.php</strong> for all users."); |
||||||||
0 ignored issues
–
show
The function
print_notice() has been deprecated: Use twig function noticeMessage
(
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. ![]() |
|||||||||
883 | |||||||||
884 | $system_enabled = array_map("trim", explode(",", PLUGINS)); |
||||||||
0 ignored issues
–
show
|
|||||||||
885 | $user_enabled = array_map("trim", explode(",", get_pref("_ENABLED_PLUGINS"))); |
||||||||
886 | |||||||||
887 | $tmppluginhost = new PluginHost(); |
||||||||
888 | $tmppluginhost->load_all($tmppluginhost::KIND_ALL, $_SESSION["uid"], true); |
||||||||
889 | $tmppluginhost->load_data(); |
||||||||
890 | |||||||||
891 | foreach ($tmppluginhost->get_plugins() as $name => $plugin) { |
||||||||
892 | $about = $plugin->about(); |
||||||||
893 | |||||||||
894 | if ($about[3]) { |
||||||||
895 | if (in_array($name, $system_enabled)) { |
||||||||
896 | $checked = "checked='1'"; |
||||||||
897 | } else { |
||||||||
898 | $checked = ""; |
||||||||
899 | } |
||||||||
900 | |||||||||
901 | print "<fieldset class='prefs plugin'> |
||||||||
902 | <label>$name:</label> |
||||||||
903 | <label class='checkbox description text-muted' id='PLABEL-$name'> |
||||||||
904 | <input disabled='1' |
||||||||
905 | dojoType='dijit.form.CheckBox' $checked type='checkbox'> |
||||||||
906 | ".htmlspecialchars($about[1])."</label>"; |
||||||||
907 | |||||||||
908 | if (@$about[4]) { |
||||||||
909 | print "<button dojoType='dijit.form.Button' class='alt-info' |
||||||||
910 | onclick='window.open(\"".htmlspecialchars($about[4])."\")'> |
||||||||
911 | <i class='material-icons'>open_in_new</i> ".__("More info...")."</button>"; |
||||||||
912 | } |
||||||||
913 | |||||||||
914 | print "<div dojoType='dijit.Tooltip' connectId='PLABEL-$name' position='after'>". |
||||||||
915 | htmlspecialchars(T_sprintf("v%.2f, by %s", $about[0], $about[2])). |
||||||||
916 | "</div>"; |
||||||||
917 | |||||||||
918 | print "</fieldset>"; |
||||||||
919 | |||||||||
920 | } |
||||||||
921 | } |
||||||||
922 | |||||||||
923 | print "<h2>".__("User plugins")."</h2>"; |
||||||||
924 | |||||||||
925 | foreach ($tmppluginhost->get_plugins() as $name => $plugin) { |
||||||||
926 | $about = $plugin->about(); |
||||||||
927 | |||||||||
928 | if (!$about[3]) { |
||||||||
929 | |||||||||
930 | $checked = ""; |
||||||||
931 | $disabled = ""; |
||||||||
932 | |||||||||
933 | if (in_array($name, $system_enabled)) { |
||||||||
934 | $checked = "checked='1'"; |
||||||||
935 | $disabled = "disabled='1'"; |
||||||||
936 | } else if (in_array($name, $user_enabled)) { |
||||||||
937 | $checked = "checked='1'"; |
||||||||
938 | } |
||||||||
939 | |||||||||
940 | print "<fieldset class='prefs plugin'> |
||||||||
941 | <label>$name:</label> |
||||||||
942 | <label class='checkbox description text-muted' id='PLABEL-$name'> |
||||||||
943 | <input name='plugins[]' value='$name' dojoType='dijit.form.CheckBox' $checked $disabled type='checkbox'> |
||||||||
944 | ".htmlspecialchars($about[1])."</label>"; |
||||||||
945 | |||||||||
946 | if (count($tmppluginhost->get_all($plugin)) > 0) { |
||||||||
947 | if (in_array($name, $system_enabled) || in_array($name, $user_enabled)) { |
||||||||
948 | print " <button dojoType='dijit.form.Button' |
||||||||
949 | onclick=\"Helpers.clearPluginData('$name')\"> |
||||||||
950 | <i class='material-icons'>clear</i> ".__("Clear data")."</button>"; |
||||||||
951 | } |
||||||||
952 | } |
||||||||
953 | |||||||||
954 | if (@$about[4]) { |
||||||||
955 | print " <button dojoType='dijit.form.Button' class='alt-info' |
||||||||
956 | onclick='window.open(\"".htmlspecialchars($about[4])."\")'> |
||||||||
957 | <i class='material-icons'>open_in_new</i> ".__("More info...")."</button>"; |
||||||||
958 | } |
||||||||
959 | |||||||||
960 | print "<div dojoType='dijit.Tooltip' connectId='PLABEL-$name' position='after'>". |
||||||||
961 | htmlspecialchars(T_sprintf("v%.2f, by %s", $about[0], $about[2])). |
||||||||
962 | "</div>"; |
||||||||
963 | |||||||||
964 | print "</fieldset>"; |
||||||||
965 | } |
||||||||
966 | } |
||||||||
967 | |||||||||
968 | print "</div>"; #content-pane |
||||||||
969 | print '<div dojoType="dijit.layout.ContentPane" region="bottom">'; |
||||||||
970 | |||||||||
971 | print "<button dojoType='dijit.form.Button' style='float : left' class='alt-info' onclick='window.open(\"https://tt-rss.org/wiki/Plugins\")'> |
||||||||
972 | <i class='material-icons'>help</i> ".__("More info...")."</button>"; |
||||||||
973 | |||||||||
974 | print "<button dojoType='dijit.form.Button' class='alt-primary' type='submit'>". |
||||||||
975 | __("Enable selected plugins")."</button>"; |
||||||||
976 | print "</div>"; #pane |
||||||||
977 | |||||||||
978 | print "</div>"; #pane |
||||||||
979 | print "</div>"; #border-container |
||||||||
980 | |||||||||
981 | print "</form>"; |
||||||||
982 | |||||||||
983 | PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB, |
||||||||
984 | "hook_prefs_tab", "prefPrefs"); |
||||||||
985 | |||||||||
986 | print "</div>"; #container |
||||||||
987 | |||||||||
988 | } |
||||||||
989 | |||||||||
990 | public function toggleAdvanced() { |
||||||||
991 | $_SESSION["prefs_show_advanced"] = !$_SESSION["prefs_show_advanced"]; |
||||||||
992 | } |
||||||||
993 | |||||||||
994 | public function otpsecret() { |
||||||||
995 | $sth = $this->pdo->prepare("SELECT salt, otp_enabled |
||||||||
996 | FROM ttrss_users |
||||||||
997 | WHERE id = ?"); |
||||||||
998 | $sth->execute([$_SESSION['uid']]); |
||||||||
999 | |||||||||
1000 | if ($row = $sth->fetch()) { |
||||||||
1001 | $otp_enabled = sql_bool_to_bool($row["otp_enabled"]); |
||||||||
1002 | |||||||||
1003 | if (!$otp_enabled) { |
||||||||
1004 | $base32 = new \OTPHP\Base32(); |
||||||||
0 ignored issues
–
show
The type
OTPHP\Base32 was not found. Maybe you did not declare it correctly or list all dependencies?
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. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||||||||
1005 | $secret = $base32->encode(mb_substr(sha1($row["salt"]), 0, 12), false); |
||||||||
1006 | |||||||||
1007 | return $secret; |
||||||||
1008 | } |
||||||||
1009 | } |
||||||||
1010 | |||||||||
1011 | return false; |
||||||||
1012 | } |
||||||||
1013 | |||||||||
1014 | public function otpqrcode() { |
||||||||
1015 | require_once "lib/phpqrcode/phpqrcode.php"; |
||||||||
1016 | |||||||||
1017 | $sth = $this->pdo->prepare("SELECT login |
||||||||
1018 | FROM ttrss_users |
||||||||
1019 | WHERE id = ?"); |
||||||||
1020 | $sth->execute([$_SESSION['uid']]); |
||||||||
1021 | |||||||||
1022 | if ($row = $sth->fetch()) { |
||||||||
1023 | $secret = $this->otpsecret(); |
||||||||
1024 | $login = $row['login']; |
||||||||
1025 | |||||||||
1026 | if ($secret) { |
||||||||
1027 | QRcode::png("otpauth://totp/".urlencode($login). |
||||||||
1028 | "?secret=$secret&issuer=".urlencode("Tiny Tiny RSS")); |
||||||||
1029 | } |
||||||||
1030 | } |
||||||||
1031 | } |
||||||||
1032 | |||||||||
1033 | public function otpenable() { |
||||||||
1034 | |||||||||
1035 | $password = clean($_REQUEST["password"]); |
||||||||
1036 | $otp = clean($_REQUEST["otp"]); |
||||||||
1037 | |||||||||
1038 | $authenticator = PluginHost::getInstance()->get_plugin($_SESSION["auth_module"]); |
||||||||
1039 | |||||||||
1040 | if ($authenticator->check_password($_SESSION["uid"], $password)) { |
||||||||
1041 | |||||||||
1042 | $secret = $this->otpsecret(); |
||||||||
1043 | |||||||||
1044 | if ($secret) { |
||||||||
1045 | $topt = 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. ![]() |
|||||||||
1046 | $otp_check = $topt->now(); |
||||||||
1047 | |||||||||
1048 | if ($otp == $otp_check) { |
||||||||
1049 | $sth = $this->pdo->prepare("UPDATE ttrss_users SET otp_enabled = true WHERE id = ?"); |
||||||||
1050 | |||||||||
1051 | $sth->execute([$_SESSION['uid']]); |
||||||||
1052 | |||||||||
1053 | print "OK"; |
||||||||
1054 | } else { |
||||||||
1055 | print "ERROR:".__("Incorrect one time password"); |
||||||||
1056 | } |
||||||||
1057 | } |
||||||||
1058 | |||||||||
1059 | } else { |
||||||||
1060 | print "ERROR:".__("Incorrect password"); |
||||||||
1061 | } |
||||||||
1062 | |||||||||
1063 | } |
||||||||
1064 | |||||||||
1065 | public static function isdefaultpassword() { |
||||||||
1066 | $authenticator = PluginHost::getInstance()->get_plugin($_SESSION["auth_module"]); |
||||||||
1067 | |||||||||
1068 | if ($authenticator && |
||||||||
1069 | method_exists($authenticator, "check_password") && |
||||||||
1070 | $authenticator->check_password($_SESSION["uid"], "password")) { |
||||||||
1071 | |||||||||
1072 | return true; |
||||||||
1073 | } |
||||||||
1074 | |||||||||
1075 | return false; |
||||||||
1076 | } |
||||||||
1077 | |||||||||
1078 | public function otpdisable() { |
||||||||
1079 | $password = clean($_REQUEST["password"]); |
||||||||
1080 | |||||||||
1081 | $authenticator = PluginHost::getInstance()->get_plugin($_SESSION["auth_module"]); |
||||||||
1082 | |||||||||
1083 | if ($authenticator->check_password($_SESSION["uid"], $password)) { |
||||||||
1084 | |||||||||
1085 | $sth = $this->pdo->prepare("SELECT email, login FROM ttrss_users WHERE id = ?"); |
||||||||
1086 | $sth->execute([$_SESSION['uid']]); |
||||||||
1087 | |||||||||
1088 | if ($row = $sth->fetch()) { |
||||||||
1089 | $mailer = new Mailer(); |
||||||||
1090 | |||||||||
1091 | require_once "lib/MiniTemplator.class.php"; |
||||||||
1092 | |||||||||
1093 | $tpl = new MiniTemplator; |
||||||||
1094 | |||||||||
1095 | $tpl->readTemplateFromFile("templates/otp_disabled_template.txt"); |
||||||||
1096 | |||||||||
1097 | $tpl->setVariable('LOGIN', $row["login"]); |
||||||||
1098 | $tpl->setVariable('TTRSS_HOST', SELF_URL_PATH); |
||||||||
0 ignored issues
–
show
|
|||||||||
1099 | |||||||||
1100 | $tpl->addBlock('message'); |
||||||||
1101 | |||||||||
1102 | $tpl->generateOutputToString($message); |
||||||||
1103 | |||||||||
1104 | $mailer->mail(["to_name" => $row["login"], |
||||||||
1105 | "to_address" => $row["email"], |
||||||||
1106 | "subject" => "[tt-rss] OTP change notification", |
||||||||
1107 | "message" => $message]); |
||||||||
1108 | } |
||||||||
1109 | |||||||||
1110 | $sth = $this->pdo->prepare("UPDATE ttrss_users SET otp_enabled = false WHERE |
||||||||
1111 | id = ?"); |
||||||||
1112 | $sth->execute([$_SESSION['uid']]); |
||||||||
1113 | |||||||||
1114 | print "OK"; |
||||||||
1115 | } else { |
||||||||
1116 | print "ERROR: ".__("Incorrect password"); |
||||||||
1117 | } |
||||||||
1118 | |||||||||
1119 | } |
||||||||
1120 | |||||||||
1121 | public function setplugins() { |
||||||||
1122 | if (is_array(clean($_REQUEST["plugins"]))) { |
||||||||
1123 | $plugins = join(",", clean($_REQUEST["plugins"])); |
||||||||
0 ignored issues
–
show
It seems like
clean($_REQUEST['plugins']) can also be of type string ; however, parameter $pieces of join() does only seem to accept array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||
1124 | } else { |
||||||||
1125 | $plugins = ""; |
||||||||
1126 | } |
||||||||
1127 | |||||||||
1128 | set_pref("_ENABLED_PLUGINS", $plugins); |
||||||||
1129 | } |
||||||||
1130 | |||||||||
1131 | public function clearplugindata() { |
||||||||
1132 | $name = clean($_REQUEST["name"]); |
||||||||
1133 | |||||||||
1134 | PluginHost::getInstance()->clear_data(PluginHost::getInstance()->get_plugin($name)); |
||||||||
1135 | } |
||||||||
1136 | |||||||||
1137 | public function customizeCSS() { |
||||||||
1138 | $value = get_pref("USER_STYLESHEET"); |
||||||||
1139 | $value = str_replace("<br/>", "\n", $value); |
||||||||
1140 | |||||||||
1141 | print_notice(__("You can override colors, fonts and layout of your currently selected theme with custom CSS declarations here.")); |
||||||||
0 ignored issues
–
show
The function
print_notice() has been deprecated: Use twig function noticeMessage
(
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. ![]() The call to
print_notice() has too many arguments starting with __('You can override col...SS declarations here.') .
(
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 more 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. ![]() |
|||||||||
1142 | |||||||||
1143 | print_hidden("op", "rpc"); |
||||||||
1144 | print_hidden("method", "setpref"); |
||||||||
1145 | print_hidden("key", "USER_STYLESHEET"); |
||||||||
1146 | |||||||||
1147 | print "<div id='css_edit_apply_msg' style='display : none'>"; |
||||||||
1148 | print_warning(__("User CSS has been applied, you might need to reload the page to see all changes.")); |
||||||||
0 ignored issues
–
show
The call to
print_warning() has too many arguments starting with __('User CSS has been ap...e to see all changes.') .
(
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 more 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. ![]() The function
print_warning() has been deprecated: Use twig function warningMessage
(
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. ![]() |
|||||||||
1149 | print "</div>"; |
||||||||
1150 | |||||||||
1151 | print "<textarea class='panel user-css-editor' dojoType='dijit.form.SimpleTextarea' |
||||||||
1152 | style='font-size : 12px;' name='value'>$value</textarea>"; |
||||||||
1153 | |||||||||
1154 | print "<footer>"; |
||||||||
1155 | print "<button dojoType='dijit.form.Button' class='alt-success' |
||||||||
1156 | onclick=\"dijit.byId('cssEditDlg').apply()\">".__('Apply')."</button> "; |
||||||||
1157 | print "<button dojoType='dijit.form.Button' class='alt-primary' |
||||||||
1158 | onclick=\"dijit.byId('cssEditDlg').execute()\">".__('Save and reload')."</button> "; |
||||||||
1159 | print "<button dojoType='dijit.form.Button' |
||||||||
1160 | onclick=\"dijit.byId('cssEditDlg').hide()\">".__('Cancel')."</button>"; |
||||||||
1161 | print "</footer>"; |
||||||||
1162 | |||||||||
1163 | } |
||||||||
1164 | |||||||||
1165 | public function editPrefProfiles() { |
||||||||
1166 | print "<div dojoType='fox.Toolbar'>"; |
||||||||
1167 | |||||||||
1168 | print "<div dojoType='fox.form.DropDownButton'>". |
||||||||
1169 | "<span>".__('Select')."</span>"; |
||||||||
1170 | print "<div dojoType='dijit.Menu' style='display: none'>"; |
||||||||
1171 | print "<div onclick=\"Tables.select('pref-profiles-list', true)\" |
||||||||
1172 | dojoType='dijit.MenuItem'>".__('All')."</div>"; |
||||||||
1173 | print "<div onclick=\"Tables.select('pref-profiles-list', false)\" |
||||||||
1174 | dojoType='dijit.MenuItem'>".__('None')."</div>"; |
||||||||
1175 | print "</div></div>"; |
||||||||
1176 | |||||||||
1177 | print "<div style='float : right'>"; |
||||||||
1178 | |||||||||
1179 | print "<input name='newprofile' dojoType='dijit.form.ValidationTextBox' |
||||||||
1180 | required='1'> |
||||||||
1181 | <button dojoType='dijit.form.Button' |
||||||||
1182 | onclick=\"dijit.byId('profileEditDlg').addProfile()\">". |
||||||||
1183 | __('Create profile')."</button></div>"; |
||||||||
1184 | |||||||||
1185 | print "</div>"; |
||||||||
1186 | |||||||||
1187 | $sth = $this->pdo->prepare("SELECT title,id FROM ttrss_settings_profiles |
||||||||
1188 | WHERE owner_uid = ? ORDER BY title"); |
||||||||
1189 | $sth->execute([$_SESSION['uid']]); |
||||||||
1190 | |||||||||
1191 | print "<div class='panel panel-scrollable'>"; |
||||||||
1192 | |||||||||
1193 | print "<form id='profile_edit_form' onsubmit='return false'>"; |
||||||||
1194 | |||||||||
1195 | print "<table width='100%' id='pref-profiles-list'>"; |
||||||||
1196 | |||||||||
1197 | print "<tr>"; # data-row-id='0' <-- no point, shouldn't be removed |
||||||||
1198 | |||||||||
1199 | print "<td><input onclick='Tables.onRowChecked(this);' dojoType='dijit.form.CheckBox' type='checkbox'></td>"; |
||||||||
1200 | |||||||||
1201 | if (!$_SESSION["profile"]) { |
||||||||
1202 | $is_active = __("(active)"); |
||||||||
1203 | } else { |
||||||||
1204 | $is_active = ""; |
||||||||
1205 | } |
||||||||
1206 | |||||||||
1207 | print "<td width='100%'><span>".__("Default profile")." $is_active</span></td>"; |
||||||||
1208 | |||||||||
1209 | print "</tr>"; |
||||||||
1210 | |||||||||
1211 | while ($line = $sth->fetch()) { |
||||||||
1212 | |||||||||
1213 | $profile_id = $line["id"]; |
||||||||
1214 | |||||||||
1215 | print "<tr data-row-id='$profile_id'>"; |
||||||||
1216 | |||||||||
1217 | $edit_title = htmlspecialchars($line["title"]); |
||||||||
1218 | |||||||||
1219 | print "<td><input onclick='Tables.onRowChecked(this);' dojoType='dijit.form.CheckBox' type='checkbox'></td>"; |
||||||||
1220 | |||||||||
1221 | if ($_SESSION["profile"] == $line["id"]) { |
||||||||
1222 | $is_active = __("(active)"); |
||||||||
1223 | } else { |
||||||||
1224 | $is_active = ""; |
||||||||
1225 | } |
||||||||
1226 | |||||||||
1227 | print "<td><span dojoType='dijit.InlineEditBox' |
||||||||
1228 | width='300px' autoSave='false' |
||||||||
1229 | profile-id='$profile_id'>".$edit_title. |
||||||||
1230 | "<script type='dojo/method' event='onChange' args='item'> |
||||||||
1231 | var elem = this; |
||||||||
1232 | dojo.xhrPost({ |
||||||||
1233 | url: 'backend.php', |
||||||||
1234 | content: {op: 'rpc', method: 'saveprofile', |
||||||||
1235 | value: this.value, |
||||||||
1236 | id: this.srcNodeRef.getAttribute('profile-id')}, |
||||||||
1237 | load: function(response) { |
||||||||
1238 | elem.attr('value', response); |
||||||||
1239 | } |
||||||||
1240 | }); |
||||||||
1241 | </script> |
||||||||
1242 | </span> $is_active</td>"; |
||||||||
1243 | |||||||||
1244 | print "</tr>"; |
||||||||
1245 | } |
||||||||
1246 | |||||||||
1247 | print "</table>"; |
||||||||
1248 | print "</form>"; |
||||||||
1249 | print "</div>"; |
||||||||
1250 | |||||||||
1251 | print "<footer> |
||||||||
1252 | <button style='float : left' class='alt-danger' dojoType=\"dijit.form.Button\" onclick=\"dijit.byId('profileEditDlg').removeSelected()\">". |
||||||||
1253 | __('Remove selected profiles')."</button> |
||||||||
1254 | <button dojoType='dijit.form.Button' class='alt-primary' type='submit' onclick=\"dijit.byId('profileEditDlg').activateProfile()\">". |
||||||||
1255 | __('Activate profile')."</button> |
||||||||
1256 | <button dojoType='dijit.form.Button' onclick=\"dijit.byId('profileEditDlg').hide()\">". |
||||||||
1257 | __('Cancel')."</button>"; |
||||||||
1258 | print "</footer>"; |
||||||||
1259 | |||||||||
1260 | } |
||||||||
1261 | |||||||||
1262 | private function getShortDesc($pref_name) { |
||||||||
1263 | if (isset($this->pref_help[$pref_name])) { |
||||||||
1264 | return $this->pref_help[$pref_name][0]; |
||||||||
1265 | } |
||||||||
1266 | return ""; |
||||||||
1267 | } |
||||||||
1268 | |||||||||
1269 | private function getHelpText($pref_name) { |
||||||||
1270 | if (isset($this->pref_help[$pref_name])) { |
||||||||
1271 | return $this->pref_help[$pref_name][1]; |
||||||||
1272 | } |
||||||||
1273 | return ""; |
||||||||
1274 | } |
||||||||
1275 | |||||||||
1276 | private function appPasswordList() { |
||||||||
1277 | print "<div dojoType='fox.Toolbar'>"; |
||||||||
1278 | print "<div dojoType='fox.form.DropDownButton'>". |
||||||||
1279 | "<span>".__('Select')."</span>"; |
||||||||
1280 | print "<div dojoType='dijit.Menu' style='display: none'>"; |
||||||||
1281 | print "<div onclick=\"Tables.select('app-password-list', true)\" |
||||||||
1282 | dojoType=\"dijit.MenuItem\">" . __('All')."</div>"; |
||||||||
1283 | print "<div onclick=\"Tables.select('app-password-list', false)\" |
||||||||
1284 | dojoType=\"dijit.MenuItem\">" . __('None')."</div>"; |
||||||||
1285 | print "</div></div>"; |
||||||||
1286 | print "</div>"; #toolbar |
||||||||
1287 | |||||||||
1288 | print "<div class='panel panel-scrollable'>"; |
||||||||
1289 | print "<table width='100%' id='app-password-list'>"; |
||||||||
1290 | print "<tr>"; |
||||||||
1291 | print "<th width='2%'></th>"; |
||||||||
1292 | print "<th align='left'>".__("Description")."</th>"; |
||||||||
1293 | print "<th align='right'>".__("Created")."</th>"; |
||||||||
1294 | print "<th align='right'>".__("Last used")."</th>"; |
||||||||
1295 | print "</tr>"; |
||||||||
1296 | |||||||||
1297 | $sth = $this->pdo->prepare("SELECT id, title, created, last_used |
||||||||
1298 | FROM ttrss_app_passwords WHERE owner_uid = ?"); |
||||||||
1299 | $sth->execute([$_SESSION['uid']]); |
||||||||
1300 | |||||||||
1301 | while ($row = $sth->fetch()) { |
||||||||
1302 | |||||||||
1303 | $row_id = $row["id"]; |
||||||||
1304 | |||||||||
1305 | print "<tr data-row-id='$row_id'>"; |
||||||||
1306 | |||||||||
1307 | print "<td align='center'> |
||||||||
1308 | <input onclick='Tables.onRowChecked(this)' dojoType='dijit.form.CheckBox' type='checkbox'></td>"; |
||||||||
1309 | print "<td>".htmlspecialchars($row["title"])."</td>"; |
||||||||
1310 | |||||||||
1311 | print "<td align='right' class='text-muted'>"; |
||||||||
1312 | print make_local_datetime($row['created'], false); |
||||||||
1313 | print "</td>"; |
||||||||
1314 | |||||||||
1315 | print "<td align='right' class='text-muted'>"; |
||||||||
1316 | print make_local_datetime($row['last_used'], false); |
||||||||
1317 | print "</td>"; |
||||||||
1318 | |||||||||
1319 | print "</tr>"; |
||||||||
1320 | } |
||||||||
1321 | |||||||||
1322 | print "</table>"; |
||||||||
1323 | print "</div>"; |
||||||||
1324 | } |
||||||||
1325 | |||||||||
1326 | private function encryptAppPassword($password) { |
||||||||
1327 | $salt = substr(bin2hex(get_random_bytes(24)), 0, 24); |
||||||||
1328 | |||||||||
1329 | return "SSHA-512:".hash('sha512', $salt.$password).":$salt"; |
||||||||
1330 | } |
||||||||
1331 | |||||||||
1332 | public function deleteAppPassword() { |
||||||||
1333 | $ids = explode(",", clean($_REQUEST['ids'])); |
||||||||
0 ignored issues
–
show
It seems like
clean($_REQUEST['ids']) can also be of type array ; however, parameter $string of explode() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||
1334 | $ids_qmarks = arr_qmarks($ids); |
||||||||
1335 | |||||||||
1336 | $sth = $this->pdo->prepare("DELETE FROM ttrss_app_passwords WHERE id IN ($ids_qmarks) AND owner_uid = ?"); |
||||||||
1337 | $sth->execute(array_merge($ids, [$_SESSION['uid']])); |
||||||||
1338 | |||||||||
1339 | $this->appPasswordList(); |
||||||||
1340 | } |
||||||||
1341 | |||||||||
1342 | public function generateAppPassword() { |
||||||||
1343 | $title = clean($_REQUEST['title']); |
||||||||
1344 | $new_password = make_password(16); |
||||||||
1345 | $new_password_hash = $this->encryptAppPassword($new_password); |
||||||||
1346 | |||||||||
1347 | print_warning(T_sprintf("Generated password <strong>%s</strong> for %s. Please remember it for future reference.", $new_password, $title)); |
||||||||
0 ignored issues
–
show
The call to
print_warning() has too many arguments starting with T_sprintf('Generated pas... $new_password, $title) .
(
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 more 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. ![]() The function
print_warning() has been deprecated: Use twig function warningMessage
(
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. ![]() |
|||||||||
1348 | |||||||||
1349 | $sth = $this->pdo->prepare("INSERT INTO ttrss_app_passwords |
||||||||
1350 | (title, pwd_hash, service, created, owner_uid) |
||||||||
1351 | VALUES |
||||||||
1352 | (?, ?, ?, NOW(), ?)"); |
||||||||
1353 | |||||||||
1354 | $sth->execute([$title, $new_password_hash, Auth_Base::AUTH_SERVICE_API, $_SESSION['uid']]); |
||||||||
1355 | |||||||||
1356 | $this->appPasswordList(); |
||||||||
1357 | } |
||||||||
1358 | } |
||||||||
1359 |
This check compares calls to functions or methods with their respective definitions. If the call has more 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.