Issues (982)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

util.js (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
// util.js
2
// copyright Sébastien Lucas
3
// https://github.com/seblucas/cops
4
5
/*jshint curly: true, latedef: true, trailing: true, noarg: true, undef: true, browser: true, jquery: true, unused: true, devel: true, loopfunc: true */
6
/*global LRUCache, doT, Bloodhound, postRefresh */
7
8
var templatePage, templateBookDetail, templateMain, templateSuggestion, currentData, before, filterList;
9
10
if (typeof LRUCache != 'undefined') {
11
    console.log('ERROR: LRUCache module not loaded!');
0 ignored issues
show
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
12
}
13
var cache = new LRUCache(30);
14
15
$.ajaxSetup({
16
    cache: false
17
});
18
19
var copsTypeahead = new Bloodhound({
20
    datumTokenizer: Bloodhound.tokenizers.obj.whitespace('title'),
21
    queryTokenizer: Bloodhound.tokenizers.whitespace,
22
    limit: 30,
23
    remote: {
24
                url: 'getJSON.php?page=9&search=1&db=%DB&query=%QUERY',
25
                replace: function (url, query) {
26
                    if (currentData.multipleDatabase === 1 && currentData.databaseId === "") {
27
                        return url.replace('%QUERY', query).replace('&db=%DB', "");
28
                    }
29
                    return url.replace('%QUERY', query).replace('%DB', currentData.databaseId);
30
                }
31
            }
32
});
33
34
copsTypeahead.initialize();
35
36
var DEBUG = false;
37
var isPushStateEnabled = window.history && window.history.pushState && window.history.replaceState &&
38
  // pushState isn't reliable on iOS until 5.
39
  !window.navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]|WebApps\/.+CFNetwork)/);
40
41
function debug_log(text) {
42
    if ( DEBUG ) {
43
        console.log(text);
0 ignored issues
show
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
44
    }
45
}
46
47
/*exported updateCookie */
48
function updateCookie (id) {
49
    if ($(id).prop('pattern') && !$(id).val().match(new RegExp ($(id).prop('pattern')))) {
50
        return;
51
    }
52
    var name = $(id).attr('id');
53
    var value = $(id).val ();
54
    $.cookie(name, value, { expires: 365 });
55
}
56
57
/*exported updateCookieFromCheckbox */
58
function updateCookieFromCheckbox (id) {
59
    var name = $(id).attr('id');
60
    if ((/^style/).test (name)) {
61
        name = "style";
62
    }
63
    if ($(id).is(":checked"))
64
    {
65
        if ($(id).is(':radio')) {
66
            $.cookie(name, $(id).val (), { expires: 365 });
67
        } else {
68
            $.cookie(name, '1', { expires: 365 });
69
        }
70
    }
71
    else
72
    {
73
        $.cookie(name, '0', { expires: 365 });
74
    }
75
}
76
77
/*exported updateCookieFromCheckboxGroup */
78
function updateCookieFromCheckboxGroup (id) {
79
    var name = $(id).attr('name');
80
    var idBase = name.replace (/\[\]/, "");
81
    var group = [];
82
    $(':checkbox[name="' + name + '"]:checked').each (function () {
83
        var id = $(this).attr("id");
84
        group.push (id.replace (idBase + "_", ""));
85
    });
86
    $.cookie(idBase, group.join (), { expires: 365 });
87
}
88
89
90
function elapsed () {
91
    var elapsedTime = new Date () - before;
92
    return "Elapsed : " + elapsedTime;
93
}
94
95
function retourMail(data) {
96
    $("#mailButton :first-child").removeClass ("icon-spinner icon-spin").addClass ("icon-envelope");
97
    alert (data);
98
}
99
100
/*exported sendToMailAddress */
101
function sendToMailAddress (component, dataid) {
102
    var email = $.cookie ('email');
103
    if (!$.cookie ('email')) {
104
        email = window.prompt (currentData.c.i18n.customizeEmail, "");
105
        if (email === null)
106
        {
107
            return;
108
        }
109
        $.cookie ('email', email, { expires: 365 });
110
    }
111
    var url = 'sendtomail.php';
112
    if (currentData.databaseId) {
113
        url = url + '?db=' + currentData.databaseId;
114
    }
115
    $("#mailButton :first-child").removeClass ("icon-envelope").addClass ("icon-spinner icon-spin");
116
    $.ajax ({'url': url, 'type': 'post', 'data': { 'data':  dataid, 'email': email }, 'success': retourMail});
117
}
118
119
function str_format () {
120
    var s = arguments[0];
121
    for (var i = 0; i < arguments.length - 1; i++) {
122
        var reg = new RegExp("\\{" + i + "\\}", "gm");
123
        s = s.replace(reg, arguments[i + 1]);
124
    }
125
    return s;
126
}
127
128
function isDefined(x) {
129
    return (typeof x !== 'undefined');
130
}
131
132
function getCurrentOption (option) {
133
    if (!$.cookie (option)) {
134
        if (currentData && currentData.c && currentData.c.config && currentData.c.config [option]) {
135
            return currentData.c.config [option];
136
        }
137
    }
138
    return $.cookie (option);
139
}
140
141
/*exported htmlspecialchars */
142
function htmlspecialchars(str) {
143
    return String(str)
144
            .replace(/&/g, '&amp;')
145
            .replace(/"/g, '&quot;')
146
            .replace(/'/g, '&#39;')
147
            .replace(/</g, '&lt;')
148
            .replace(/>/g, '&gt;');
149
}
150
151
/************************************************
152
 * All functions needed to filter the book list by tags
153
 ************************************************
154
 */
155
156
function getTagList () {
157
    var tagList = {};
158
    $(".se").each (function(){
159
        if ($(this).parents (".filtered").length > 0) { return; }
160
        var taglist = $(this).text();
161
162
        var tagarray = taglist.split (",");
163
        for (var i in tagarray) {
164
            if (!tagarray.hasOwnProperty(i)) {
165
                continue;
166
            }
167
            var tag = tagarray [i].replace(/^\s+/g,'').replace(/\s+$/g,'');
168
            tagList [tag] = 1;
169
        }
170
    });
171
    return tagList;
172
}
173
174
function updateFilters () {
175
    var tagList = getTagList ();
176
177
    // If there is already some filters then let's prepare to update the list
178
    $("#filter ul li").each (function () {
179
        var text = $(this).text ();
180
        if (isDefined (tagList [text]) || $(this).attr ('class')) {
181
            tagList [text] = 0;
182
        } else {
183
            tagList [text] = -1;
184
        }
185
    });
186
187
    // Update the filter -1 to remove, 1 to add, 0 already there
188
    for (var tag in tagList) {
189
        if (!tagList.hasOwnProperty(tag)) {
190
            continue;
191
        }
192
        var tagValue = tagList [tag];
193
        if (tagValue === -1) {
194
            $("#filter ul li").filter (function () { return $.text([this]) === tag; }).remove();
195
        }
196
        if (tagValue === 1) {
197
            $("#filter ul").append ("<li>" + tag + "</li>");
198
        }
199
    }
200
201
    $("#filter ul").append ("<li>_CLEAR_</li>");
202
203
    // Sort the list alphabetically
204
    $('#filter ul li').sortElements(function(a, b){
205
        return $(a).text() > $(b).text() ? 1 : -1;
206
    });
207
}
208
209
function doFilter () {
210
    $(".books").removeClass("filtered");
211
    if (jQuery.isEmptyObject(filterList)) {
212
        updateFilters ();
213
        return;
214
    }
215
216
    $(".se").each (function(){
217
        var taglist = ", " + $(this).text() + ", ";
218
        var toBeFiltered = false;
219
        for (var filter in filterList) {
220
            if (!filterList.hasOwnProperty(filter)) {
221
                continue;
222
            }
223
            var onlyThisTag = filterList [filter];
224
            filter = ', ' + filter + ', ';
225
            var myreg = new RegExp (filter);
226
            if (myreg.test (taglist)) {
227
                if (onlyThisTag === false) {
228
                    toBeFiltered = true;
229
                }
230
            } else {
231
                if (onlyThisTag === true) {
232
                    toBeFiltered = true;
233
                }
234
            }
235
        }
236
        if (toBeFiltered) { $(this).parents (".books").addClass ("filtered"); }
237
    });
238
239
    // Handle the books with no tags
240
    var atLeastOneTagSelected = false;
241
    for (var filter in filterList) {
242
        if (!filterList.hasOwnProperty(filter)) {
243
            continue;
244
        }
245
        if (filterList[filter] === true) {
246
            atLeastOneTagSelected = true;
247
        }
248
    }
249
    if (atLeastOneTagSelected) {
250
        $(".books").not (":has(span.se)").addClass ("filtered");
251
    }
252
253
    updateFilters ();
254
}
255
256
function handleFilterEvents () {
257
    $("#filter ul").on ("click", "li", function(){
258
        var filter = $(this).text ();
259
        if (filter === "_CLEAR_") {
260
            filterList = {};
261
            $("#filter ul li").removeClass ("filter-exclude");
262
            $("#filter ul li").removeClass ("filter-include");
263
            doFilter ();
264
            return;
265
        }
266
        switch ($(this).attr("class")) {
267
            case "filter-include" :
268
                $(this).attr("class", "filter-exclude");
269
                filterList [filter] = false;
270
                break;
271
            case "filter-exclude" :
272
                $(this).removeClass ("filter-exclude");
273
                delete filterList [filter];
274
                break;
275
            default :
276
                $(this).attr("class", "filter-include");
277
                filterList [filter] = true;
278
                break;
279
        }
280
        doFilter ();
281
    });
282
}
283
284
/************************************************
285
 * Functions to handle Ajax navigation
286
 ************************************************
287
 */
288
289
var updatePage, navigateTo;
290
291
updatePage = function (data) {
292
    var result;
293
    filterList = {};
294
    data.c = currentData.c;
295
    if (false && $("section").length && currentData.isPaginated === 0 &&  data.isPaginated === 0) {
296
        // Partial update (for now disabled)
297
        debug_log ("Partial update");
298
        result = templateMain (data);
299
        $("h1").html (data.title);
300
        $("section").html (result);
301
    } else {
302
        // Full update
303
        result = templatePage (data);
304
        $("body").html (result);
305
    }
306
    document.title = data.title;
307
    currentData = data;
308
    setTimeout( function() { $("input[name=query]").focus(); }, 500 );
309
310
    debug_log (elapsed ());
311
312
    if ($.cookie('toolbar') === '1') { $("#tool").show (); }
313
    if (currentData.containsBook === 1) {
314
        $("#sortForm").show ();
315
        if (getCurrentOption ("html_tag_filter") === "1") {
316
            $("#filter ul").empty ();
317
            updateFilters ();
318
            handleFilterEvents ();
319
        }
320
    } else {
321
        $("#sortForm").hide ();
322
    }
323
324
    $('input[name=query]').typeahead(
325
    {
326
        hint: true,
327
        minLength : 3
328
    },
329
    {
330
        name: 'search',
331
        displayKey: 'title',
332
        templates: {
333
            suggestion: templateSuggestion
334
        },
335
        source: copsTypeahead.ttAdapter()
336
    });
337
338
    $('input[name=query]').bind('typeahead:selected', function(obj, datum) {
339
        if (isPushStateEnabled) {
340
            navigateTo (datum.navlink);
341
        } else {
342
            window.location = datum.navlink;
343
        }
344
    });
345
346
    if(typeof postRefresh == 'function')
347
    { postRefresh(); }
348
};
349
350
navigateTo = function (url) {
351
    $("h1").append (" <i class='icon-spinner icon-spin'></i>");
352
    before = new Date ();
353
    var jsonurl = url.replace ("index", "getJSON");
354
    var cachedData = cache.get (jsonurl);
355
    if (cachedData) {
356
        window.history.pushState(jsonurl, "", url);
357
        updatePage (cachedData);
358
    } else {
359
        $.getJSON(jsonurl, function(data) {
360
            window.history.pushState(jsonurl, "", url);
361
            cache.put (jsonurl, data);
362
            updatePage (data);
363
        });
364
    }
365
};
366
367
function link_Clicked (event) {
368
    var currentLink = $(this);
369
    if (!isPushStateEnabled ||
370
        currentData.page === "19") {
371
        return;
372
    }
373
    event.preventDefault();
374
    var url = currentLink.attr('href');
375
376
    if ($(".mfp-ready").length)
377
    {
378
        $.magnificPopup.close();
379
    }
380
381
    // The bookdetail / about should be displayed in a lightbox
382
    if (getCurrentOption ("use_fancyapps") === "1" &&
383
        (currentLink.hasClass ("fancydetail") || currentLink.hasClass ("fancyabout"))) {
384
        before = new Date ();
385
        var jsonurl = url.replace ("index", "getJSON");
386
        $.getJSON(jsonurl, function(data) {
387
            data.c = currentData.c;
388
            var detail = "";
389
            if (data.page === "16") {
390
                detail = data.fullhtml;
391
            } else {
392
                detail = templateBookDetail (data);
393
            }
394
            $.magnificPopup.open({
395
              items: {
396
                src: detail,
397
                type: 'inline'
398
              }
399
            });
400
            debug_log (elapsed ());
401
        });
402
        return;
403
    }
404
    navigateTo (url);
405
}
406
407
function search_Submitted (event) {
408
    if (!isPushStateEnabled ||
409
        currentData.page === "19") {
410
        return;
411
    }
412
    event.preventDefault();
413
    var url = str_format ("index.php?page=9&current={0}&query={1}&db={2}", currentData.page, encodeURIComponent ($("input[name=query]").val ()), currentData.databaseId);
414
    navigateTo (url);
415
}
416
417
/*exported handleLinks */
418
function handleLinks () {
419
    $("body").on ("click", "a[href^='index']", link_Clicked);
420
    $("body").on ("submit", "#searchForm", search_Submitted);
421
    $("body").on ("click", "#sort", function(){
422
        $('.books').sortElements(function(a, b){
423
            var test = 1;
424
            if ($("#sortorder").val() === "desc")
425
            {
426
                test = -1;
427
            }
428
            return $(a).find ("." + $("#sortchoice").val()).text() > $(b).find ("." + $("#sortchoice").val()).text() ? test : -test;
429
        });
430
    });
431
432
    $("body").on ("click", ".headright", function(){
433
        if ($("#tool").is(":hidden")) {
434
            $("#tool").slideDown("slow");
435
            $("input[name=query]").focus();
436
            $.cookie('toolbar', '1', { expires: 365 });
437
        } else {
438
            $("#tool").slideUp();
439
            $.removeCookie('toolbar');
440
        }
441
    });
442
    $("body").magnificPopup({
443
        delegate: '.fancycover', // child items selector, by clicking on it popup will open
444
        type: 'image',
445
        gallery:{enabled:true, preload: [0,2]},
446
        disableOn: function() {
447
          if( getCurrentOption ("use_fancyapps") === "1" ) {
448
            return true;
449
          }
450
          return false;
451
        }
452
    });
453
}
454
455
window.onpopstate = function(event) {
456
    if (!isDefined (currentData)) {
457
        return;
458
    }
459
460
    before = new Date ();
461
    var data = cache.get (event.state);
462
    updatePage (data);
463
};
464
465
$(document).keydown(function(e){
466
    if (e.keyCode === 37 && $("#prevLink").length > 0) {
467
        navigateTo ($("#prevLink").attr('href'));
468
    }
469
    if (e.keyCode === 39  && $("#nextLink").length > 0) {
470
        navigateTo ($("#nextLink").attr('href'));
471
    }
472
});
473
474
/*exported initiateAjax */
475
function initiateAjax (url, theme) {
476
    $.when($.get('templates/' + theme + '/header.html'),
477
           $.get('templates/' + theme + '/footer.html'),
478
           $.get('templates/' + theme + '/bookdetail.html'),
479
           $.get('templates/' + theme + '/main.html'),
480
           $.get('templates/' + theme + '/page.html'),
481
           $.get('templates/' + theme + '/suggestion.html'),
482
           $.getJSON(url)).done(function(header, footer, bookdetail, main, page, suggestion, data){
483
        templateBookDetail = doT.template (bookdetail [0]);
484
485
        var defMain = {
486
            bookdetail: bookdetail [0]
487
        };
488
489
        templateMain = doT.template (main [0], undefined, defMain);
490
491
        var defPage = {
492
            header: header [0],
493
            footer: footer [0],
494
            main  : main [0],
495
            bookdetail: bookdetail [0]
496
        };
497
498
        templatePage = doT.template (page [0], undefined, defPage);
499
500
        templateSuggestion = doT.template (suggestion [0]);
501
502
        currentData = data [0];
503
504
        updatePage (data [0]);
505
        cache.put (url, data [0]);
506
        if (isPushStateEnabled) {
507
            window.history.replaceState(url, "", window.location);
508
        }
509
        handleLinks ();
510
    });
511
}
512