Browse Source

More testing classes

pjc 5 years ago
parent
commit
bcd88aaa15

+ 10
- 0
classes/charts.class.php View File

@@ -1,4 +1,5 @@
1 1
 <?php
2
+
2 3
 class GOOGLE_CHARTS
3 4
 {
4 5
     protected $URL = 'https://chart.googleapis.com/chart';
@@ -11,6 +12,7 @@ class GOOGLE_CHARTS
11 12
         if ($Width * $Height > 300000 || $Height > 1000 || $Width > 1000) {
12 13
             trigger_error('Tried to make chart too large.');
13 14
         }
15
+
14 16
         $this->URL .= "?cht=$Type&amp;chs={$Width}x$Height";
15 17
         $this->Options = $Options;
16 18
     }
@@ -20,6 +22,7 @@ class GOOGLE_CHARTS
20 22
         if ($Number === -1) {
21 23
             return '__';
22 24
         }
25
+
23 26
         $CharKey = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-.';
24 27
         return $CharKey[floor($Number / 64)].$CharKey[floor($Number % 64)];
25 28
     }
@@ -40,6 +43,7 @@ class GOOGLE_CHARTS
40 43
         if (!empty($Color)) {
41 44
             $this->URL .= '&amp;chts='.$Color;
42 45
         }
46
+
43 47
         if (!empty($Size)) {
44 48
             $this->URL .= ','.$Size;
45 49
         }
@@ -99,6 +103,7 @@ class AREA_GRAPH extends GOOGLE_CHARTS
99 103
         $Max = max($this->Data);
100 104
         $Min = ((isset($this->Options['Break'])) ? $Min = min($this->Data) : 0);
101 105
         $Data = [];
106
+
102 107
         foreach ($this->Data as $Value) {
103 108
             $Data[] = $this->encode((($Value - $Min) / ($Max - $Min)) * 4095);
104 109
         }
@@ -136,6 +141,7 @@ class PIE_CHART extends GOOGLE_CHARTS
136 141
         foreach ($this->Data as $Key => $Value) {
137 142
             $ThisPercentage = number_format(($Value / $Sum) * 100, 2);
138 143
             $ThisData = ($Value / $Sum) * 4095;
144
+
139 145
             if ($Other && $ThisPercentage < 1) {
140 146
                 $OtherPercentage += $ThisPercentage;
141 147
                 $OtherData += $ThisData;
@@ -143,11 +149,13 @@ class PIE_CHART extends GOOGLE_CHARTS
143 149
                 unset($Labels[$Key]);
144 150
                 continue;
145 151
             }
152
+
146 153
             if ($LabelPercent) {
147 154
                 $Labels[$Key] .= ' ('.$ThisPercentage.'%)';
148 155
             }
149 156
             $Data[] = $this->encode($ThisData);
150 157
         }
158
+
151 159
         if ($OtherPercentage > 0) {
152 160
             $OtherLabel = 'Other';
153 161
             if ($LabelPercent) {
@@ -178,6 +186,7 @@ class LOG_BAR_GRAPH extends GOOGLE_CHARTS
178 186
         $Max = max($this->Data);
179 187
         $Min = ((isset($this->Options['Break'])) ? $Min = min($this->Data) : 0);
180 188
         $Data = [];
189
+
181 190
         foreach ($this->Data as $Value) {
182 191
             $Data[] = $this->encode((($Value - $Min) / ($Max - $Min)) * 4095);
183 192
         }
@@ -209,6 +218,7 @@ class POLL_GRAPH extends GOOGLE_CHARTS
209 218
         $Increment = ($Max / $Sum) * 25; // * 100% / 4divisions
210 219
         $Data = [];
211 220
         $Labels = [];
221
+        
212 222
         foreach ($this->Data as $Key => $Value) {
213 223
             $Data[] = $this->encode(($Value / $Max) * 4095);
214 224
             $Labels[] = '@t'.str_replace(array(' ', ','), array('+', '\,'), $this->Labels[$Key]).',000000,1,'.round((($Key + 1) / $Count) - (12 / $Height), 2).':0,12';

+ 30
- 24
classes/cookie.class.php View File

@@ -1,4 +1,5 @@
1
-<?
1
+<?php
2
+
2 3
 /*************************************************************************|
3 4
 |--------------- Cookie class --------------------------------------------|
4 5
 |*************************************************************************|
@@ -19,30 +20,35 @@ interface COOKIE_INTERFACE {
19 20
 }
20 21
 */
21 22
 
22
-class COOKIE /*implements COOKIE_INTERFACE*/ {
23
-  const LIMIT_ACCESS = true; //If true, blocks JS cookie API access by default (can be overridden case by case)
24
-  const PREFIX = ''; //In some cases you may desire to prefix your cookies
23
+class COOKIE /*implements COOKIE_INTERFACE*/
24
+{
25
+    const LIMIT_ACCESS = true; // If true, blocks JS cookie API access by default (can be overridden case by case)
26
+    const PREFIX = ''; // In some cases you may desire to prefix your cookies
27
+
28
+    public function get($Key)
29
+    {
30
+        if (!isset($_COOKIE[SELF::PREFIX.$Key])) {
31
+            return false;
32
+        }
33
+        return $_COOKIE[SELF::PREFIX.$Key];
34
+    }
25 35
 
26
-  public function get($Key) {
27
-    if (!isset($_COOKIE[SELF::PREFIX.$Key])) {
28
-      return false;
36
+    // Pass the 4th optional param as false to allow JS access to the cookie
37
+    public function set($Key, $Value, $Seconds = 86400, $LimitAccess = SELF::LIMIT_ACCESS)
38
+    {
39
+        setcookie(SELF::PREFIX.$Key, $Value, time() + $Seconds, '/', SITE_DOMAIN, $_SERVER['SERVER_PORT'] === '443', $LimitAccess, false);
29 40
     }
30
-    return $_COOKIE[SELF::PREFIX.$Key];
31
-  }
32
-
33
-  //Pass the 4th optional param as false to allow JS access to the cookie
34
-  public function set($Key, $Value, $Seconds = 86400, $LimitAccess = SELF::LIMIT_ACCESS) {
35
-    setcookie(SELF::PREFIX.$Key, $Value, time() + $Seconds, '/', SITE_DOMAIN, $_SERVER['SERVER_PORT'] === '443', $LimitAccess, false);
36
-  }
37
-
38
-  public function del($Key) {
39
-    setcookie(SELF::PREFIX.$Key, '', time() - 24 * 3600); //3600 vs 1 second to account for potential clock desyncs
40
-  }
41
-
42
-  public function flush() {
43
-    $Cookies = array_keys($_COOKIE);
44
-    foreach ($Cookies as $Cookie) {
45
-      $this->del($Cookie);
41
+
42
+    public function del($Key)
43
+    {
44
+        setcookie(SELF::PREFIX.$Key, '', time() - 24 * 3600); //3600 vs 1 second to account for potential clock desyncs
45
+    }
46
+
47
+    public function flush()
48
+    {
49
+        $Cookies = array_keys($_COOKIE);
50
+        foreach ($Cookies as $Cookie) {
51
+            $this->del($Cookie);
52
+        }
46 53
     }
47
-  }
48 54
 }

+ 658
- 606
classes/debug.class.php
File diff suppressed because it is too large
View File


+ 9
- 2
classes/file_checker.class.php View File

@@ -1,6 +1,10 @@
1 1
 <?php
2 2
 
3
+# todo: Leverage this class to parse file extensions
4
+# Work the expension parser on the upload form into this class
5
+
3 6
 $ComicsExtensions = array_fill_keys(array('cbr', 'cbz', 'gif', 'jpeg', 'jpg', 'pdf', 'png'), true);
7
+
4 8
 $MusicExtensions = array_fill_keys(
5 9
     array(
6 10
     'ac3', 'accurip', 'azw3', 'chm', 'cue', 'djv', 'djvu', 'doc', 'dts', 'epub', 'ffp',
@@ -8,6 +12,7 @@ $MusicExtensions = array_fill_keys(
8 12
     'md5', 'mobi', 'mp3', 'mp4', 'nfo', 'pdf', 'pls', 'png', 'rtf', 'sfv', 'txt'),
9 13
     true
10 14
 );
15
+
11 16
 $Keywords = array(
12 17
   'ahashare.com', 'demonoid.com', 'demonoid.me', 'djtunes.com', 'h33t', 'housexclusive.net',
13 18
   'limetorrents.com', 'mixesdb.com', 'mixfiend.blogstop', 'mixtapetorrent.blogspot',
@@ -23,11 +28,13 @@ function check_name($Name)
23 28
 {
24 29
     global $Keywords;
25 30
     $NameLC = strtolower($Name);
31
+
26 32
     foreach ($Keywords as &$Value) {
27 33
         if (strpos($NameLC, $Value) !== false) {
28 34
             forbidden_error($Name);
29 35
         }
30 36
     }
37
+
31 38
     if (preg_match('/INCOMPLETE~\*/i', $Name)) {
32 39
         forbidden_error($Name);
33 40
     }
@@ -52,11 +59,11 @@ function check_name($Name)
52 59
 function check_extensions($Type, $Name)
53 60
 {
54 61
     global $MusicExtensions, $ComicsExtensions;
55
-    if ($Type == 'Music' || $Type == 'Audiobooks' || $Type == 'Comedy' || $Type == 'E-Books') {
62
+    if ($Type === 'Music' || $Type === 'Audiobooks' || $Type === 'Comedy' || $Type === 'E-Books') {
56 63
         if (!isset($MusicExtensions[get_file_extension($Name)])) {
57 64
             invalid_error($Name);
58 65
         }
59
-    } elseif ($Type == 'Comics') {
66
+    } elseif ($Type === 'Comics') {
60 67
         if (!isset($ComicsExtensions[get_file_extension($Name)])) {
61 68
             invalid_error($Name);
62 69
         }

+ 538
- 509
classes/misc.class.php
File diff suppressed because it is too large
View File


+ 253
- 118
classes/rules.class.php View File

@@ -2,39 +2,56 @@
2 2
 
3 3
 class Rules
4 4
 {
5
-
6
-  /**
7
-   * Displays the site's "Golden Rules".
8
-   *
9
-   */
5
+    /**
6
+     * Displays the site's "Golden Rules".
7
+     *
8
+     */
10 9
     public static function display_golden_rules()
11 10
     {
12 11
         ?>
13 12
 <ul>
14
-  <li><strong>No personally identifying patient data is allowed anywhere on the site.</strong></li>
15
-
16
-  <li>Staff can do anything to anyone for any reason (or no reason). If you take issue with a decision, you must do so
17
-    privately with the staff member who issued the decision or with an administrator of the site.</li>
18
-
19
-  <li>One account per person per lifetime.</li>
20
-
21
-  <li>Follow proper private BitTorrent practices. Torrent files you download from this site are unique to you and should
22
-    not be shared with others. Torrent files from this site should not be modified by adding additional trackers or
23
-    enabling DHT or PEX under any circumstances.</li>
24
-
25
-  <li>Buying <?=SITE_NAME?> invites is not allowed. If staff discover
26
-    you have purchased an invite, you will be banned for life. You will be given amnesty if you approach us before you
27
-    are caught and reveal who your seller was. Waiting until after you are caught will get you nothing.</li>
28
-
29
-  <li>Accessing the site from any IP address is permitted, but your account will be linked with other accounts that have
30
-    accessed the site from the same IP as you. As such, it is <em>recommended</em> that you don't use public networks,
31
-    proxies, or VPNs to access the site.</li>
32
-
33
-  <li>Attempting to find a bug in the site code is allowed and sometimes even rewarded. Follow proper disclosure
34
-    procedures by contacting staff about the issue well before disclosing it publicly. Do not misuse any bugs you may
35
-    discover. Do not attempt to portray abuse as a bug in the hopes of a reward.</li>
36
-
37
-  <li>Don't reveal the criteria for hidden badges or events.</li>
13
+  <li>
14
+    <strong>No personally identifying patient data is allowed anywhere on the site.</strong>
15
+  </li>
16
+
17
+  <li>
18
+    Staff can do anything to anyone for any reason (or no reason).
19
+    If you take issue with a decision, you must do so privately with the staff member who issued the decision.
20
+  </li>
21
+
22
+  <li>
23
+    One account per person per lifetime.
24
+  </li>
25
+
26
+  <li>
27
+    Follow proper private BitTorrent practices.
28
+    Torrent files you download from this site are unique to you and should not be shared with others.
29
+    Torrent files from this site should not be modified under any circumstances.
30
+  </li>
31
+
32
+  <li>
33
+    Buying <?=SITE_NAME?> invites is not allowed.
34
+    If staff discover you have purchased an invite, you will be banned for life.
35
+    You will be given amnesty if you approach us before you are caught and reveal who your seller was.
36
+    Waiting until after you are caught will get you nothing.
37
+  </li>
38
+
39
+  <li>
40
+    Accessing the site from any IP address is permitted,
41
+    but your account will be linked with other accounts that have accessed the site from the same IP as you.
42
+    As such, it is <em>recommended</em> that you don't use public networks, proxies, or VPNs to access the site.
43
+  </li>
44
+
45
+  <li>
46
+    Attempting to find a bug in the site code is allowed and sometimes even rewarded.
47
+    Follow proper disclosure procedures by contacting staff about the issue well before disclosing it publicly.
48
+    Do not misuse any bugs you may discover.
49
+    Do not attempt to portray abuse as a bug in the hopes of a reward.
50
+  </li>
51
+
52
+  <li>
53
+    Don't reveal the criteria for hidden badges or events.
54
+  </li>
38 55
 </ul>
39 56
 <?php
40 57
     }
@@ -48,51 +65,126 @@ class Rules
48 65
     {
49 66
         ?>
50 67
 <ul>
51
-  <li><strong>Please use the <strong class="important_text_alt">vanity.house</strong> tag for sequences that you or your
52
-      lab produced.</strong> This helps us promote the DIYbio community's original contributions.</li>
53
-
54
-  <li>Tags should be comma-separated, and you should use a period to separate words inside a tag, e.g., <strong
55
-      class="important_text_alt">gram.negative</strong>.</li>
56
-
57
-  <li>There is a list of official tags <?=($OnUpload ? 'to the left of the text box' : 'on the <a href="upload.php">upload page</a>')?>.
58
-    Please use these tags instead of "unofficial" tags, e.g., use the official <strong
59
-      class="important_text_alt">fungi</strong> tag instead of an unofficial <strong
60
-      class="important_text">mushrooms</strong> tag.</li>
61
-
62
-  <li>Avoid using multiple synonymous tags. Using both <strong class="important_text">cyanobacteria</strong> and <strong
63
-      class="important_text_alt">bacteria</strong> is redundant and stupid &mdash; just use the official <strong
64
-      class="important_text_alt">bacteria</strong>.</li>
65
-
66
-  <li>Don't add useless tags that are already covered by other metadata. If a torrent is in the DNA category, please
67
-    don't tag it <strong class="important_text">dna</strong>.</li>
68
-
69
-  <li>Only tag information related to the group itself &mdash; <strong>not the individual release</strong>. Tags such as
70
-    <strong class="important_text">apollo.100</strong>, <strong class="important_text">hiseq.2500</strong>, etc., are
71
-    strictly forbidden. Remember that these tags will be used for other releases in the same group.</li>
72
-
73
-  <li><strong>Certain tags are strongly encouraged for appropriate uploads:</strong> <strong
74
-      class="important_text_alt">archaea</strong>, <strong class="important_text_alt">bacteria</strong>, <strong
75
-      class="important_text_alt">fungi</strong>, <strong class="important_text_alt">animals</strong>, <strong
76
-      class="important_text_alt">plants</strong>, <strong class="important_text_alt">plasmids</strong>. People search
77
-    for these kinds of things specifically, so tagging them properly will get you more snatches.</li>
68
+  <li>
69
+    <strong>Please use the
70
+      <strong class="important_text_alt">vanity.house</strong>
71
+      tag for sequences that you or your lab produced.</strong>
72
+    This helps us promote the DIYbio community's original contributions.
73
+  </li>
74
+
75
+  <li>
76
+    Tags should be comma-separated, and you should use a period to separate words inside a tag, e.g.,
77
+    <strong class="important_text_alt">gram.negative</strong>.
78
+  </li>
79
+
80
+  <li>
81
+    There is a list of official tags <?=($OnUpload ? 'to the left of the text box' : 'on the <a href="upload.php">upload page</a>')?>.
82
+    Please use these tags instead of "unofficial" tags, e.g., use the official
83
+    <strong class="important_text_alt">fungi</strong>
84
+    tag instead of an unofficial
85
+    <strong class="important_text">mushrooms</strong>
86
+    tag.
87
+  </li>
88
+
89
+  <li>Avoid using multiple synonymous tags.
90
+    Using both
91
+    <strong class="important_text">cyanobacteria</strong>
92
+    and
93
+    <strong class="important_text_alt">bacteria</strong>
94
+    is redundant and stupid &mdash; just use the official
95
+    <strong class="important_text_alt">bacteria</strong>.
96
+  </li>
97
+
98
+  <li>
99
+    Don't add useless tags that are already covered by other metadata.
100
+    If a torrent is in the DNA category, please don't tag it
101
+    <strong class="important_text">dna</strong>.
102
+  </li>
103
+
104
+  <li>
105
+    Only tag information related to the group itself &mdash;
106
+    <strong>not the individual release</strong>.
107
+    Tags such as
108
+    <strong class="important_text">apollo.100</strong>,
109
+    <strong class="important_text">hiseq.2500</strong>,
110
+    etc., are strictly forbidden.
111
+    Remember that these tags will be used for other releases in the same group.
112
+  </li>
113
+
114
+  <li>
115
+    <strong>Certain tags are strongly encouraged for appropriate uploads:</strong>
116
+    <strong class="important_text_alt">archaea</strong>,
117
+    <strong class="important_text_alt">bacteria</strong>,
118
+    <strong class="important_text_alt">fungi</strong>,
119
+    <strong class="important_text_alt">animals</strong>,
120
+    <strong class="important_text_alt">plants</strong>,
121
+    <strong class="important_text_alt">plasmids</strong>.
122
+    People search for these kinds of things specifically, so tagging them properly will get you more snatches.
123
+  </li>
78 124
 
79 125
   <!--
80
-      <li><strong>Use tag namespaces when appropriate.</strong> BioTorrents.de allows for tag namespaces to aid with searching. For example, you may want to use the tags "<strong class="important_text_alt">masturbation:male</strong>" or "<strong class="important_text_alt">masturbation:female</strong>" instead of just "<strong class="important_text">masturbation</strong>". They can be used to make search queries more specific. Searching for "<strong class="important_texti_alt">masturbation</strong>" will show all torrents tagged with "<strong class="important_text_alt">masturbation</strong>", "<strong class="important_text_alt">masturbation:male</strong>", or "<strong class="important_text_alt">masturbation:female</strong>". However, searching for "<strong class="important_text_alt">masturbation:female</strong>" will ONLY show torrents with that tag. Tags with namespaces will appear differently depending on the namespace used, which include:
81
-        <ul>
82
-          <li><strong>:parody</strong> - Used to denote a parodied work: <strong class="tag_parody">touhou</strong>, <strong class="tag_parody">kantai.collection</strong></li>
83
-          <li><strong>:character</strong> - Used to denote a character in a parodied work: <strong class="tag_character">iori.minase</strong>, <strong class="tag_character">hakurei.reimu</strong></li>
84
-          <li><strong>:male</strong> - Used to denote that the tag refers to a male character: <strong class="tag_male">masturbation</strong>, <strong class="tag_male">teacher</strong></li>
85
-          <li><strong>:female</strong> - Used to denote that the tag refers to a female character: <strong class="tag_female">masturbation</strong>, <strong class="tag_female">shaved</strong></li>
86
-        </ul>
126
+  <li>
127
+    <strong>Use tag namespaces when appropriate.</strong>
128
+    BioTorrents.de allows for tag namespaces to aid with searching.
129
+    For example, you may want to use the tags
130
+    <strong class="important_text_alt">masturbation:male</strong>
131
+    or
132
+    <strong class="important_text_alt">masturbation:female</strong>
133
+    instead of just
134
+    <strong class="important_text">masturbation</strong>.
135
+    They can be used to make search queries more specific.
136
+    Searching for
137
+    <strong class="important_texti_alt">masturbation</strong>
138
+    will show all torrents tagged with
139
+    <strong class="important_text_alt">masturbation</strong>,
140
+    <strong class="important_text_alt">masturbation:male</strong>,
141
+    or
142
+    <strong class="important_text_alt">masturbation:female</strong>.
143
+    However, searching for
144
+    <strong class="important_text_alt">masturbation:female</strong>
145
+    will <strong>only</strong> show torrents with that tag.
146
+    Tags with namespaces will appear differently depending on the namespace used, which include:
147
+
148
+    <ul>
149
+      <li>
150
+        <strong>:parody</strong> - Used to denote a parodied work:
151
+        <strong class="tag_parody">touhou</strong>,
152
+        <strong class="tag_parody">kantai.collection</strong>
87 153
       </li>
88
-      -->
89 154
 
90
-  <li><strong>All uploads require a minimum of 5 tags.</strong> Please don't add unrelated tags just to meet the 5 tag
91
-    requirement. If you can't think of 5 tags for your content, study it again until you can.</li>
155
+      <li>
156
+        <strong>:character</strong> - Used to denote a character in a parodied work:
157
+        <strong class="tag_character">iori.minase</strong>,
158
+        <strong class="tag_character">hakurei.reimu</strong>
159
+      </li>
92 160
 
93
-  <li><strong>You should be able to build up a list of tags using only the official tags <?=($OnUpload ? 'to the left of the text box' : 'on the <a href="upload.php">upload page</a>')?>.</strong>
161
+      <li>
162
+        <strong>:male</strong> - Used to denote that the tag refers to a male character:
163
+        <strong class="tag_male">masturbation</strong>,
164
+        <strong class="tag_male">teacher</strong>
165
+      </li>
166
+
167
+      <li>
168
+        <strong>:female</strong> - Used to denote that the tag refers to a female character:
169
+        <strong class="tag_female">masturbation</strong>,
170
+        <strong class="tag_female">shaved</strong>
171
+      </li>
172
+    </ul>
173
+  </li>
174
+  -->
175
+
176
+  <li>
177
+    <strong>All uploads require a minimum of 5 tags.</strong>
178
+    Please don't add unrelated tags just to meet the 5 tag requirement.
179
+    If you can't think of 5 tags for your content, study it again until you can.
180
+  </li>
181
+
182
+  <li>
183
+    <strong>You should be able to build up a list of tags using only the official tags
184
+      <?=($OnUpload ? 'to the left of the text box' : 'on the <a href="upload.php">upload page</a>')?>.</strong>
94 185
     If you doubt whether or not a tag is acceptable, please omit it for now and send a staff PM to request a new
95
-    official tag or an approved alias.</li>
186
+    official tag or an approved alias.
187
+  </li>
96 188
 </ul>
97 189
 <?php
98 190
     }
@@ -105,39 +197,62 @@ class Rules
105 197
     {
106 198
         ?>
107 199
 <ul>
108
-  <li>Let's treat the biology boards like how the Shroomery used to be: each thread a set of resourceful diverse wisdom
109
-    worth using permalinks to. It's okay if the boards are slow, that's why there are only a few of them.</li>
110
-
111
-  <li>Please discuss site news in the corresponding Announcements thread instead of making a new General thread.
200
+  <li>
201
+    Let's treat the biology boards like how the Shroomery used to be:
202
+    each thread a set of resourceful wisdom worth using permalinks to.
203
+    It's okay if the boards are slow, that's why there are only a few of them.
204
+  </li>
205
+
206
+  <li>
207
+    Please discuss site news in the corresponding Announcements thread instead of making a new General thread.
112 208
     Discussing science-related news in General is highly encouraged, but discussing political news is much less so.
113 209
     But don't self-censor, e.g., you can discuss the political and economic factors of the 2019-nCoV outbreak,
114 210
     but you can't start a thread about trade deals and hope to steer it toward biology.
115
-    Thank you.</li>
116
-
117
-  <li>No advertising, referrals, affiliate links, cryptocurrency pumps, or calls to action that involve using a
118
-    financial instrument. You'll be banned on the spot. The exceptions: discussions about cryptocurrencies that derive
119
-    their value from
120
-    work performed on distributed science networks, i.e., Curecoin, FoldingCoin, and Gridcoin.</li>
121
-
122
-  <li>Feel free to post announcements for your own projects, even and especially if they're commercial ones, in the
123
-    General board. Limit all discussion of trading biomaterials, including bulk giveaways, to the Marketplace forum
124
-    available to Power Users.</li>
125
-
126
-  <li>Please be modest when talking about your uploads. It's unnecessary to announce your uploads because Gazelle logs
127
-    everything (at least this installation's database is encrypted). If someone asks for help on his project and your
128
-    upload fits the bill, go write a post!</li>
129
-
130
-  <li>Use descriptive and specific subject lines. This helps others decide whether your particular words of "wisdom"
131
-    relate to a topic they care about.</li>
132
-
133
-  <li>Don't post comments that don't add anything to the discussion, such as "I agree" or "haha." Bottle the trained
134
-    dopamine response to social media because comment reactions are an unlikely feature.</li>
135
-
136
-  <li>Please refrain from quoting excessively. When quoting someone, use only the necessary parts of the quote. Avoid
137
-    quoting more than 3 levels deep.</li>
138
-
139
-  <li>Don't post potentially malicious links without sufficient warning, or post pictures > 2 MiB. Please only speak
140
-    English as stated in the upload rules.</li>
211
+    Thank you.
212
+  </li>
213
+
214
+  <li>
215
+    No advertising, referrals, affiliate links, cryptocurrency pumps, or calls to action that involve using a financial
216
+    instrument.
217
+    You'll be banned on the spot.
218
+    The exceptions: discussions about cryptocurrencies that derive their value from work performed on distributed
219
+    science networks, i.e., Curecoin, FoldingCoin, and Gridcoin.
220
+  </li>
221
+
222
+  <li>
223
+    Feel free to post announcements for your own projects, even and especially if they're commercial ones, in the
224
+    General board.
225
+    Limit all discussion of trading biomaterials, including bulk giveaways, to the Marketplace forum available to Power
226
+    Users.
227
+  </li>
228
+
229
+  <li>
230
+    Please be modest when talking about your uploads.
231
+    It's unnecessary to announce your uploads because Gazelle logs everything
232
+    (at least this installation's database is encrypted).
233
+    If someone asks for help on his project and your upload fits the bill, go write a post!
234
+  </li>
235
+
236
+  <li>
237
+    Use descriptive and specific subject lines.
238
+    This helps others decide whether your particular words of "wisdom" relate to a topic they care about.
239
+  </li>
240
+
241
+  <li>
242
+    Don't post comments that don't add anything to the discussion, such as "I agree" or "haha."
243
+    Bottle the trained dopamine response to social media because comment reactions are an unlikely feature.
244
+  </li>
245
+
246
+  <li>
247
+    Please refrain from quoting excessively.
248
+    When quoting someone, use only the necessary parts of the quote.
249
+    Avoid quoting more than 3 levels deep.
250
+  </li>
251
+
252
+  <li>
253
+    Don't post potentially malicious links without sufficient warning, or post pictures > 2 MiB.
254
+    Please only speak English as stated in the upload rules.
255
+  </li>
141 256
 </ul>
142 257
 <?php
143 258
     }
@@ -149,26 +264,46 @@ class Rules
149 264
     public static function display_irc_chat_rules()
150 265
     {
151 266
         ?>
152
-<li>BioTorrents.de's Slack channels are just are another quiet hangout you can stack your app with so you look cool at
153
-  conferences.</li>
154
-
155
-<li>Please use <code>#general</code> for the usual chit-chat, <code>#development</code> for questions about the Gazelle
156
-  software, and <code>#support</code> to get help with your account.</li>
157
-
158
-<li>Don't send mass alerts with <code>@channel</code>, <code>@everyone</code>, or <code>@here</code>. It's obnoxious and
159
-  you should handle anything genuinely important on the boards.</li>
160
-
161
-<li>Flooding is irritating and you'll get kicked for it. This includes "now playing" scripts, large amounts of
162
-  irrelevant text such as lorem ipsum, and unfunny non sequiturs.</li>
163
-
164
-<li>Impersonating other members, particularly staff members, will not go unpunished. Please remember that
165
-  the Slack channels are publicly accessible.</li>
166
-
167
-<li>Please use the threaded conversations feature in Slack and avoid replying to threads with new messages or
168
-  crossposting replies to the main channel.</li>
169
-
170
-<li>Announce and bot channels are in development, as standard IRC instead of Slack for obvious reasons. Any IRC bots you
171
-  have must authenticate with your own username and IRC key, and set the <code>+B</code> usermode on themselves.</li>
267
+<li>
268
+  <?=SITE_NAME?>'s Slack channels are just are another quiet hangout
269
+  you can stack your app with so you look cool at conferences.
270
+</li>
271
+
272
+<li>
273
+  Please use
274
+  <code>#general</code> for the usual chit-chat,
275
+  <code>#development</code> for questions about the Gazelle software, and
276
+  <code>#support</code> to get help with your account.
277
+</li>
278
+
279
+<li>
280
+  Don't send mass alerts with
281
+  <code>@channel</code>,
282
+  <code>@everyone</code>, or
283
+  <code>@here</code>.
284
+  It's obnoxious and you should handle anything genuinely important on the boards.
285
+</li>
286
+
287
+<li>
288
+  Flooding is irritating and you'll get kicked for it.
289
+  This includes "now playing" scripts, large amounts of irrelevant text such as lorem ipsum, and unfunny non sequiturs.
290
+</li>
291
+
292
+<li>
293
+  Impersonating other members, particularly staff members, will not go unpunished.
294
+  Please remember that the Slack channels are publicly accessible.
295
+</li>
296
+
297
+<li>
298
+  Please use the threaded conversations feature in Slack and avoid replying to threads with new messages or crossposting
299
+  replies to the main channel.
300
+</li>
301
+
302
+<li>
303
+  Announce and bot channels are in development, as standard IRC instead of Slack for obvious reasons.
304
+  Any IRC bots you have must authenticate with your own username and IRC key, and set the <code>+B</code> usermode on
305
+  themselves.
306
+</li>
172 307
 <?php
173 308
     }
174 309
 }

+ 184
- 175
classes/script_start.php View File

@@ -1,4 +1,5 @@
1 1
 <?php
2
+
2 3
 /*-- Script Start Class --------------------------------*/
3 4
 /*------------------------------------------------------*/
4 5
 /* This isnt really a class but a way to tie other      */
@@ -9,15 +10,19 @@
9 10
 /* generates the page are at the bottom.        */
10 11
 /*------------------------------------------------------*/
11 12
 /********************************************************/
12
-require 'config.php'; //The config contains all site wide configuration information
13
+require 'config.php'; // The config contains all site wide configuration information
13 14
 
14 15
 // Check for common setup pitfalls
15
-if (!ini_get('short_open_tag')) { die('short_open_tag must be On in php.ini'); }
16
-if (!extension_loaded('apcu')) { die('APCu extension not loaded'); }
16
+if (!ini_get('short_open_tag')) {
17
+    die('short_open_tag must be On in php.ini');
18
+}
19
+if (!extension_loaded('apcu')) {
20
+    die('APCu extension not loaded');
21
+}
17 22
 
18 23
 // Deal with dumbasses
19 24
 if (isset($_REQUEST['info_hash']) && isset($_REQUEST['peer_id'])) {
20
-  die('d14:failure reason40:Invalid .torrent, try downloading again.e');
25
+    die('d14:failure reason40:Invalid .torrent, try downloading again.e');
21 26
 }
22 27
 
23 28
 require(SERVER_ROOT.'/classes/proxies.class.php');
@@ -25,31 +30,34 @@ require(SERVER_ROOT.'/classes/proxies.class.php');
25 30
 // Get the user's actual IP address if they're proxied.
26 31
 // Or if cloudflare is used
27 32
 if (isset($_SERVER['HTTP_CF_CONNECTING_IP'])) {
28
-  $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_CF_CONNECTING_IP'];
33
+    $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_CF_CONNECTING_IP'];
29 34
 }
30 35
 if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])
31 36
     && proxyCheck($_SERVER['REMOTE_ADDR'])
32
-    && filter_var($_SERVER['HTTP_X_FORWARDED_FOR'],
37
+    && filter_var(
38
+        $_SERVER['HTTP_X_FORWARDED_FOR'],
33 39
         FILTER_VALIDATE_IP,
34
-        FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
35
-  $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
40
+        FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE
41
+    )) {
42
+    $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
36 43
 }
37 44
 
38 45
 if (!isset($argv) && !empty($_SERVER['HTTP_HOST'])) {
39
-  // Skip this block if running from cli or if the browser is old and shitty
40
-  // This should really be done in nginx config
41
-  // todo: Remove
42
-  if ($_SERVER['HTTP_HOST'] == 'www.'.SITE_DOMAIN) {
43
-    header('Location: https://'.SITE_DOMAIN.$_SERVER['REQUEST_URI']); die();
44
-  }
46
+    // Skip this block if running from cli or if the browser is old and shitty
47
+    // This should really be done in nginx config
48
+    // todo: Remove
49
+    if ($_SERVER['HTTP_HOST'] == 'www.'.SITE_DOMAIN) {
50
+        header('Location: https://'.SITE_DOMAIN.$_SERVER['REQUEST_URI']);
51
+        die();
52
+    }
45 53
 }
46 54
 
47 55
 
48 56
 
49 57
 $ScriptStartTime = microtime(true); //To track how long a page takes to create
50 58
 if (!defined('PHP_WINDOWS_VERSION_MAJOR')) {
51
-  $RUsage = getrusage();
52
-  $CPUTimeStart = $RUsage['ru_utime.tv_sec'] * 1000000 + $RUsage['ru_utime.tv_usec'];
59
+    $RUsage = getrusage();
60
+    $CPUTimeStart = $RUsage['ru_utime.tv_sec'] * 1000000 + $RUsage['ru_utime.tv_usec'];
53 61
 }
54 62
 ob_start(); //Start a buffer, mainly in case there is a mysql error
55 63
 
@@ -98,19 +106,19 @@ list($Classes, $ClassLevels) = Users::get_classes();
98 106
 // Permissions
99 107
 
100 108
 if (isset($_COOKIE['session']) && isset($_COOKIE['userid'])) {
101
-  $SessionID = $_COOKIE['session'];
102
-  $LoggedUser['ID'] = (int)$_COOKIE['userid'];
109
+    $SessionID = $_COOKIE['session'];
110
+    $LoggedUser['ID'] = (int)$_COOKIE['userid'];
103 111
 
104
-  $UserID = $LoggedUser['ID']; //todo: UserID should not be LoggedUser
112
+    $UserID = $LoggedUser['ID']; //todo: UserID should not be LoggedUser
105 113
 
106
-  if (!$LoggedUser['ID'] || !$SessionID) {
107
-    logout();
108
-  }
114
+    if (!$LoggedUser['ID'] || !$SessionID) {
115
+        logout();
116
+    }
109 117
 
110
-  $UserSessions = $Cache->get_value("users_sessions_$UserID");
111
-  if (!is_array($UserSessions)) {
112
-    $DB->query(
113
-     "SELECT
118
+    $UserSessions = $Cache->get_value("users_sessions_$UserID");
119
+    if (!is_array($UserSessions)) {
120
+        $DB->query(
121
+        "SELECT
114 122
         SessionID,
115 123
         Browser,
116 124
         OperatingSystem,
@@ -119,169 +127,167 @@ if (isset($_COOKIE['session']) && isset($_COOKIE['userid'])) {
119 127
       FROM users_sessions
120 128
       WHERE UserID = '$UserID'
121 129
         AND Active = 1
122
-      ORDER BY LastUpdate DESC");
123
-    $UserSessions = $DB->to_array('SessionID',MYSQLI_ASSOC);
124
-    $Cache->cache_value("users_sessions_$UserID", $UserSessions, 0);
125
-  }
130
+      ORDER BY LastUpdate DESC"
131
+    );
132
+        $UserSessions = $DB->to_array('SessionID', MYSQLI_ASSOC);
133
+        $Cache->cache_value("users_sessions_$UserID", $UserSessions, 0);
134
+    }
126 135
 
127
-  if (!array_key_exists($SessionID, $UserSessions)) {
128
-    logout();
129
-  }
136
+    if (!array_key_exists($SessionID, $UserSessions)) {
137
+        logout();
138
+    }
130 139
 
131
-  // Check if user is enabled
132
-  $Enabled = $Cache->get_value('enabled_'.$LoggedUser['ID']);
133
-  if ($Enabled === false) {
134
-    $DB->query("
140
+    // Check if user is enabled
141
+    $Enabled = $Cache->get_value('enabled_'.$LoggedUser['ID']);
142
+    if ($Enabled === false) {
143
+        $DB->query("
135 144
       SELECT Enabled
136 145
       FROM users_main
137 146
       WHERE ID = '$LoggedUser[ID]'");
138
-    list($Enabled) = $DB->next_record();
139
-    $Cache->cache_value('enabled_'.$LoggedUser['ID'], $Enabled, 0);
140
-  }
141
-  if ($Enabled == 2) {
142
-    logout();
143
-  }
147
+        list($Enabled) = $DB->next_record();
148
+        $Cache->cache_value('enabled_'.$LoggedUser['ID'], $Enabled, 0);
149
+    }
150
+    if ($Enabled == 2) {
151
+        logout();
152
+    }
144 153
 
145
-  // Up/Down stats
146
-  $UserStats = $Cache->get_value('user_stats_'.$LoggedUser['ID']);
147
-  if (!is_array($UserStats)) {
148
-    $DB->query("
154
+    // Up/Down stats
155
+    $UserStats = $Cache->get_value('user_stats_'.$LoggedUser['ID']);
156
+    if (!is_array($UserStats)) {
157
+        $DB->query("
149 158
       SELECT Uploaded AS BytesUploaded, Downloaded AS BytesDownloaded, RequiredRatio
150 159
       FROM users_main
151 160
       WHERE ID = '$LoggedUser[ID]'");
152
-    $UserStats = $DB->next_record(MYSQLI_ASSOC);
153
-    $Cache->cache_value('user_stats_'.$LoggedUser['ID'], $UserStats, 3600);
154
-  }
161
+        $UserStats = $DB->next_record(MYSQLI_ASSOC);
162
+        $Cache->cache_value('user_stats_'.$LoggedUser['ID'], $UserStats, 3600);
163
+    }
155 164
 
156
-  // Get info such as username
157
-  $LightInfo = Users::user_info($LoggedUser['ID']);
158
-  $HeavyInfo = Users::user_heavy_info($LoggedUser['ID']);
165
+    // Get info such as username
166
+    $LightInfo = Users::user_info($LoggedUser['ID']);
167
+    $HeavyInfo = Users::user_heavy_info($LoggedUser['ID']);
159 168
 
160
-  // Create LoggedUser array
161
-  $LoggedUser = array_merge($HeavyInfo, $LightInfo, $UserStats);
169
+    // Create LoggedUser array
170
+    $LoggedUser = array_merge($HeavyInfo, $LightInfo, $UserStats);
162 171
 
163
-  $LoggedUser['RSS_Auth'] = md5($LoggedUser['ID'] . RSS_HASH . $LoggedUser['torrent_pass']);
172
+    $LoggedUser['RSS_Auth'] = md5($LoggedUser['ID'] . RSS_HASH . $LoggedUser['torrent_pass']);
164 173
 
165
-  // $LoggedUser['RatioWatch'] as a bool to disable things for users on Ratio Watch
166
-  $LoggedUser['RatioWatch'] = (
167
-    $LoggedUser['RatioWatchEnds']
174
+    // $LoggedUser['RatioWatch'] as a bool to disable things for users on Ratio Watch
175
+    $LoggedUser['RatioWatch'] = (
176
+      $LoggedUser['RatioWatchEnds']
168 177
     && time() < strtotime($LoggedUser['RatioWatchEnds'])
169 178
     && ($LoggedUser['BytesDownloaded'] * $LoggedUser['RequiredRatio']) > $LoggedUser['BytesUploaded']
170 179
   );
171 180
 
172
-  // Load in the permissions
173
-  $LoggedUser['Permissions'] = Permissions::get_permissions_for_user($LoggedUser['ID'], $LoggedUser['CustomPermissions']);
174
-  $LoggedUser['Permissions']['MaxCollages'] += Donations::get_personal_collages($LoggedUser['ID']);
181
+    // Load in the permissions
182
+    $LoggedUser['Permissions'] = Permissions::get_permissions_for_user($LoggedUser['ID'], $LoggedUser['CustomPermissions']);
183
+    $LoggedUser['Permissions']['MaxCollages'] += Donations::get_personal_collages($LoggedUser['ID']);
175 184
 
176
-  // Change necessary triggers in external components
177
-  $Cache->CanClear = check_perms('admin_clear_cache');
185
+    // Change necessary triggers in external components
186
+    $Cache->CanClear = check_perms('admin_clear_cache');
178 187
 
179
-  // Because we <3 our staff
180
-  if (check_perms('site_disable_ip_history')) {
181
-    $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
182
-  }
188
+    // Because we <3 our staff
189
+    if (check_perms('site_disable_ip_history')) {
190
+        $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
191
+    }
183 192
 
184
-  // Update LastUpdate every 10 minutes
185
-  if (strtotime($UserSessions[$SessionID]['LastUpdate']) + 600 < time()) {
186
-    $DB->query("
193
+    // Update LastUpdate every 10 minutes
194
+    if (strtotime($UserSessions[$SessionID]['LastUpdate']) + 600 < time()) {
195
+        $DB->query("
187 196
       UPDATE users_main
188 197
       SET LastAccess = NOW()
189 198
       WHERE ID = '$LoggedUser[ID]'");
190
-    $SessionQuery =
199
+        $SessionQuery =
191 200
      "UPDATE users_sessions
192 201
       SET ";
193
-    // Only update IP if we have an encryption key in memory
194
-    if (apcu_exists('DBKEY')) {
195
-      $SessionQuery .= "IP = '".Crypto::encrypt($_SERVER['REMOTE_ADDR'])."', ";
196
-    }
197
-    $SessionQuery .=
202
+        // Only update IP if we have an encryption key in memory
203
+        if (apcu_exists('DBKEY')) {
204
+            $SessionQuery .= "IP = '".Crypto::encrypt($_SERVER['REMOTE_ADDR'])."', ";
205
+        }
206
+        $SessionQuery .=
198 207
        "Browser = '$Browser',
199 208
         OperatingSystem = '$OperatingSystem',
200 209
         LastUpdate = NOW()
201 210
       WHERE UserID = '$LoggedUser[ID]'
202 211
         AND SessionID = '".db_string($SessionID)."'";
203
-    $DB->query($SessionQuery);
204
-    $Cache->begin_transaction("users_sessions_$UserID");
205
-    $Cache->delete_row($SessionID);
206
-    $UsersSessionCache = array(
212
+        $DB->query($SessionQuery);
213
+        $Cache->begin_transaction("users_sessions_$UserID");
214
+        $Cache->delete_row($SessionID);
215
+        $UsersSessionCache = array(
207 216
         'SessionID' => $SessionID,
208 217
         'Browser' => $Browser,
209 218
         'OperatingSystem' => $OperatingSystem,
210 219
         'IP' => (apcu_exists('DBKEY') ? Crypto::encrypt($_SERVER['REMOTE_ADDR']) : $UserSessions[$SessionID]['IP']),
211 220
         'LastUpdate' => sqltime() );
212
-    $Cache->insert_front($SessionID, $UsersSessionCache);
213
-    $Cache->commit_transaction(0);
214
-  }
215
-
216
-  // Notifications
217
-  if (isset($LoggedUser['Permissions']['site_torrents_notify'])) {
218
-    $LoggedUser['Notify'] = $Cache->get_value('notify_filters_'.$LoggedUser['ID']);
219
-    if (!is_array($LoggedUser['Notify'])) {
220
-      $DB->query("
221
+        $Cache->insert_front($SessionID, $UsersSessionCache);
222
+        $Cache->commit_transaction(0);
223
+    }
224
+
225
+    // Notifications
226
+    if (isset($LoggedUser['Permissions']['site_torrents_notify'])) {
227
+        $LoggedUser['Notify'] = $Cache->get_value('notify_filters_'.$LoggedUser['ID']);
228
+        if (!is_array($LoggedUser['Notify'])) {
229
+            $DB->query("
221 230
         SELECT ID, Label
222 231
         FROM users_notify_filters
223 232
         WHERE UserID = '$LoggedUser[ID]'");
224
-      $LoggedUser['Notify'] = $DB->to_array('ID');
225
-      $Cache->cache_value('notify_filters_'.$LoggedUser['ID'], $LoggedUser['Notify'], 2592000);
233
+            $LoggedUser['Notify'] = $DB->to_array('ID');
234
+            $Cache->cache_value('notify_filters_'.$LoggedUser['ID'], $LoggedUser['Notify'], 2592000);
235
+        }
226 236
     }
227
-  }
228 237
 
229
-  // We've never had to disable the wiki privs of anyone.
230
-  if ($LoggedUser['DisableWiki']) {
231
-    unset($LoggedUser['Permissions']['site_edit_wiki']);
232
-  }
233
-
234
-  // IP changed
238
+    // We've never had to disable the wiki privs of anyone.
239
+    if ($LoggedUser['DisableWiki']) {
240
+        unset($LoggedUser['Permissions']['site_edit_wiki']);
241
+    }
235 242
 
236
-  if (apcu_exists('DBKEY') && Crypto::decrypt($LoggedUser['IP']) != $_SERVER['REMOTE_ADDR'] && !check_perms('site_disable_ip_history')) {
243
+    // IP changed
237 244
 
238
-    if (Tools::site_ban_ip($_SERVER['REMOTE_ADDR'])) {
239
-      error('Your IP address has been banned.');
240
-    }
245
+    if (apcu_exists('DBKEY') && Crypto::decrypt($LoggedUser['IP']) != $_SERVER['REMOTE_ADDR'] && !check_perms('site_disable_ip_history')) {
246
+        if (Tools::site_ban_ip($_SERVER['REMOTE_ADDR'])) {
247
+            error('Your IP address has been banned.');
248
+        }
241 249
 
242
-    $CurIP = db_string($LoggedUser['IP']);
243
-    $NewIP = db_string($_SERVER['REMOTE_ADDR']);
244
-    $DB->query("
250
+        $CurIP = db_string($LoggedUser['IP']);
251
+        $NewIP = db_string($_SERVER['REMOTE_ADDR']);
252
+        $DB->query("
245 253
       SELECT IP
246 254
       FROM users_history_ips
247 255
       WHERE EndTime IS NULL
248 256
         AND UserID = '$LoggedUser[ID]'");
249
-    while (list($EncIP) = $DB->next_record()) {
250
-      if (Crypto::decrypt($EncIP) == $CurIP) {
251
-        $CurIP = $EncIP;
252
-        // CurIP is now the encrypted IP that was already in the database (for matching)
253
-        break;
254
-      }
255
-    }
256
-    $DB->query("
257
+        while (list($EncIP) = $DB->next_record()) {
258
+            if (Crypto::decrypt($EncIP) == $CurIP) {
259
+                $CurIP = $EncIP;
260
+                // CurIP is now the encrypted IP that was already in the database (for matching)
261
+                break;
262
+            }
263
+        }
264
+        $DB->query("
257 265
       UPDATE users_history_ips
258 266
       SET EndTime = NOW()
259 267
       WHERE EndTime IS NULL
260 268
         AND UserID = '$LoggedUser[ID]'
261 269
         AND IP = '$CurIP'");
262
-    $DB->query("
270
+        $DB->query("
263 271
       INSERT IGNORE INTO users_history_ips
264 272
         (UserID, IP, StartTime)
265 273
       VALUES
266 274
         ('$LoggedUser[ID]', '".Crypto::encrypt($NewIP)."', NOW())");
267 275
 
268
-    $ipcc = Tools::geoip($NewIP);
269
-    $DB->query("
276
+        $ipcc = Tools::geoip($NewIP);
277
+        $DB->query("
270 278
       UPDATE users_main
271 279
       SET IP = '".Crypto::encrypt($NewIP)."', ipcc = '$ipcc'
272 280
       WHERE ID = '$LoggedUser[ID]'");
273
-    $Cache->begin_transaction('user_info_heavy_'.$LoggedUser['ID']);
274
-    $Cache->update_row(false, array('IP' => Crypto::encrypt($_SERVER['REMOTE_ADDR'])));
275
-    $Cache->commit_transaction(0);
276
-
277
-
278
-  }
281
+        $Cache->begin_transaction('user_info_heavy_'.$LoggedUser['ID']);
282
+        $Cache->update_row(false, array('IP' => Crypto::encrypt($_SERVER['REMOTE_ADDR'])));
283
+        $Cache->commit_transaction(0);
284
+    }
279 285
 
280 286
 
281
-  // Get stylesheets
282
-  $Stylesheets = $Cache->get_value('stylesheets');
283
-  if (!is_array($Stylesheets)) {
284
-    $DB->query('
287
+    // Get stylesheets
288
+    $Stylesheets = $Cache->get_value('stylesheets');
289
+    if (!is_array($Stylesheets)) {
290
+        $DB->query('
285 291
       SELECT
286 292
         ID,
287 293
         LOWER(REPLACE(Name, " ", "_")) AS Name,
@@ -289,16 +295,16 @@ if (isset($_COOKIE['session']) && isset($_COOKIE['userid'])) {
289 295
         LOWER(REPLACE(Additions, " ", "_")) AS Additions,
290 296
         Additions AS ProperAdditions
291 297
       FROM stylesheets');
292
-    $Stylesheets = $DB->to_array('ID', MYSQLI_BOTH);
293
-    $Cache->cache_value('stylesheets', $Stylesheets, 0);
294
-  }
298
+        $Stylesheets = $DB->to_array('ID', MYSQLI_BOTH);
299
+        $Cache->cache_value('stylesheets', $Stylesheets, 0);
300
+    }
295 301
 
296
-  // todo: Clean up this messy solution
297
-  $LoggedUser['StyleName'] = $Stylesheets[$LoggedUser['StyleID']]['Name'];
302
+    // todo: Clean up this messy solution
303
+    $LoggedUser['StyleName'] = $Stylesheets[$LoggedUser['StyleID']]['Name'];
298 304
 
299
-  if (empty($LoggedUser['Username'])) {
300
-    logout(); // Ghost
301
-  }
305
+    if (empty($LoggedUser['Username'])) {
306
+        logout(); // Ghost
307
+    }
302 308
 }
303 309
 G::initialize();
304 310
 $Debug->set_flag('end user handling');
@@ -308,48 +314,50 @@ $Debug->set_flag('start function definitions');
308 314
 /**
309 315
  * Log out the current session
310 316
  */
311
-function logout() {
312
-  global $SessionID;
313
-  setcookie('session', '', time() - 60 * 60 * 24 * 365, '/', '', false);
314
-  setcookie('userid', '', time() - 60 * 60 * 24 * 365, '/', '', false);
315
-  setcookie('keeplogged', '', time() - 60 * 60 * 24 * 365, '/', '', false);
316
-  if ($SessionID) {
317
-
318
-    G::$DB->query("
317
+function logout()
318
+{
319
+    global $SessionID;
320
+    setcookie('session', '', time() - 60 * 60 * 24 * 365, '/', '', false);
321
+    setcookie('userid', '', time() - 60 * 60 * 24 * 365, '/', '', false);
322
+    setcookie('keeplogged', '', time() - 60 * 60 * 24 * 365, '/', '', false);
323
+    if ($SessionID) {
324
+        G::$DB->query("
319 325
       DELETE FROM users_sessions
320 326
       WHERE UserID = '" . G::$LoggedUser['ID'] . "'
321 327
         AND SessionID = '".db_string($SessionID)."'");
322 328
 
323
-    G::$Cache->begin_transaction('users_sessions_' . G::$LoggedUser['ID']);
324
-    G::$Cache->delete_row($SessionID);
325
-    G::$Cache->commit_transaction(0);
326
-  }
327
-  G::$Cache->delete_value('user_info_' . G::$LoggedUser['ID']);
328
-  G::$Cache->delete_value('user_stats_' . G::$LoggedUser['ID']);
329
-  G::$Cache->delete_value('user_info_heavy_' . G::$LoggedUser['ID']);
329
+        G::$Cache->begin_transaction('users_sessions_' . G::$LoggedUser['ID']);
330
+        G::$Cache->delete_row($SessionID);
331
+        G::$Cache->commit_transaction(0);
332
+    }
333
+    G::$Cache->delete_value('user_info_' . G::$LoggedUser['ID']);
334
+    G::$Cache->delete_value('user_stats_' . G::$LoggedUser['ID']);
335
+    G::$Cache->delete_value('user_info_heavy_' . G::$LoggedUser['ID']);
330 336
 
331
-  header('Location: login.php');
337
+    header('Location: login.php');
332 338
 
333
-  die();
339
+    die();
334 340
 }
335 341
 
336
-function logout_all_sessions() {
337
-  $UserID = G::$LoggedUser['ID'];
342
+function logout_all_sessions()
343
+{
344
+    $UserID = G::$LoggedUser['ID'];
338 345
 
339
-  G::$DB->query("
346
+    G::$DB->query("
340 347
     DELETE FROM users_sessions
341 348
     WHERE UserID = '$UserID'");
342 349
 
343
-  G::$Cache->delete_value('users_sessions_' . $UserID);
344
-  logout();
350
+    G::$Cache->delete_value('users_sessions_' . $UserID);
351
+    logout();
345 352
 }
346 353
 
347
-function enforce_login() {
348
-  global $SessionID;
349
-  if (!$SessionID || !G::$LoggedUser) {
350
-    setcookie('redirect', $_SERVER['REQUEST_URI'], time() + 60 * 30, '/', '', false);
351
-    logout();
352
-  }
354
+function enforce_login()
355
+{
356
+    global $SessionID;
357
+    if (!$SessionID || !G::$LoggedUser) {
358
+        setcookie('redirect', $_SERVER['REQUEST_URI'], time() + 60 * 30, '/', '', false);
359
+        logout();
360
+    }
353 361
 }
354 362
 
355 363
 /**
@@ -359,20 +367,21 @@ function enforce_login() {
359 367
  * @param Are we using ajax?
360 368
  * @return authorisation status. Prints an error message to LAB_CHAN on IRC on failure.
361 369
  */
362
-function authorize($Ajax = false) {
363
-  if (empty($_REQUEST['auth']) || $_REQUEST['auth'] != G::$LoggedUser['AuthKey']) {
364
-    send_irc("PRIVMSG ".LAB_CHAN." :".G::$LoggedUser['Username']." just failed authorize on ".$_SERVER['REQUEST_URI'].(!empty($_SERVER['HTTP_REFERER']) ? " coming from ".$_SERVER['HTTP_REFERER'] : ""));
365
-    error('Invalid authorization key. Go back, refresh, and try again.', $Ajax);
366
-    return false;
367
-  }
368
-  return true;
370
+function authorize($Ajax = false)
371
+{
372
+    if (empty($_REQUEST['auth']) || $_REQUEST['auth'] != G::$LoggedUser['AuthKey']) {
373
+        send_irc("PRIVMSG ".LAB_CHAN." :".G::$LoggedUser['Username']." just failed authorize on ".$_SERVER['REQUEST_URI'].(!empty($_SERVER['HTTP_REFERER']) ? " coming from ".$_SERVER['HTTP_REFERER'] : ""));
374
+        error('Invalid authorization key. Go back, refresh, and try again.', $Ajax);
375
+        return false;
376
+    }
377
+    return true;
369 378
 }
370 379
 
371 380
 $Debug->set_flag('ending function definitions');
372 381
 //Include /sections/*/index.php
373 382
 $Document = basename(parse_url($_SERVER['SCRIPT_FILENAME'], PHP_URL_PATH), '.php');
374 383
 if (!preg_match('/^[a-z0-9]+$/i', $Document)) {
375
-  error(404);
384
+    error(404);
376 385
 }
377 386
 
378 387
 $StripPostKeys = array_fill_keys(array('password', 'cur_pass', 'new_pass_1', 'new_pass_2', 'verifypassword', 'confirm_password', 'ChangePassword', 'Password'), true);
@@ -389,9 +398,9 @@ define('STAFF_LOCKED', 1);
389 398
 $AllowedPages = ['staffpm', 'ajax', 'locked', 'logout', 'login'];
390 399
 
391 400
 if (isset(G::$LoggedUser['LockedAccount']) && !in_array($Document, $AllowedPages)) {
392
-  require(SERVER_ROOT . '/sections/locked/index.php');
401
+    require(SERVER_ROOT . '/sections/locked/index.php');
393 402
 } else {
394
-  require(SERVER_ROOT . '/sections/' . $Document . '/index.php');
403
+    require(SERVER_ROOT . '/sections/' . $Document . '/index.php');
395 404
 }
396 405
 
397 406
 $Debug->set_flag('completed module execution');
@@ -402,8 +411,8 @@ upon hit rather than being browser cached for changing content.
402 411
 Old versions of Internet Explorer choke when downloading binary files over HTTPS with disabled cache.
403 412
 Define the following constant in files that handle file downloads */
404 413
 if (!defined('SKIP_NO_CACHE_HEADERS')) {
405
-  header('Cache-Control: no-cache, must-revalidate, post-check=0, pre-check=0');
406
-  header('Pragma: no-cache');
414
+    header('Cache-Control: no-cache, must-revalidate, post-check=0, pre-check=0');
415
+    header('Pragma: no-cache');
407 416
 }
408 417
 
409 418
 //Flush to user

+ 15
- 12
classes/slaves.class.php View File

@@ -1,13 +1,16 @@
1
-<?
2
-class Slaves {
3
-  public static function get_level($SlaveID) {
4
-    G::$DB->query("
5
-      SELECT u.Uploaded, u.Downloaded, u.BonusPoints, COUNT(t.UserID)
6
-      FROM users_main AS u
7
-      LEFT JOIN torrents AS t ON u.ID=t.UserID
8
-      WHERE u.ID = $SlaveID");
9
-    list($Upload, $Download, $Points, $Uploads) = G::$DB->next_record();
10
-    return intval(((($Uploads**0.35)*1.5)+1) * max(($Upload+($Points*1000000)-$Download)/(1024**3),1));
11
-  }
1
+<?php
2
+
3
+class Slaves
4
+{
5
+    public static function get_level($SlaveID)
6
+    {
7
+        G::$DB->query("
8
+        SELECT u.Uploaded, u.Downloaded, u.BonusPoints, COUNT(t.UserID)
9
+        FROM users_main AS u
10
+          LEFT JOIN torrents AS t ON u.ID=t.UserID
11
+          WHERE u.ID = $SlaveID");
12
+          
13
+        list($Upload, $Download, $Points, $Uploads) = G::$DB->next_record();
14
+        return intval(((($Uploads**0.35)*1.5)+1) * max(($Upload+($Points*1000000)-$Download)/(1024**3), 1));
15
+    }
12 16
 };
13
-?>

+ 344
- 325
classes/u2f.class.php View File

@@ -1,4 +1,5 @@
1 1
 <?php
2
+
2 3
 // Taken from https://github.com/Yubico/php-u2flib-server/blob/master/src/u2flib_server/U2F.php
3 4
 
4 5
 /* Copyright (c) 2014 Yubico AB
@@ -73,12 +74,13 @@ const ERR_OLD_OPENSSL = 11;
73 74
 
74 75
 const PUBKEY_LEN = 65;
75 76
 
76
-class U2F {
77
-  private $appId;
77
+class U2F
78
+{
79
+    private $appId;
78 80
 
79
-  private $attestDir;
81
+    private $attestDir;
80 82
 
81
-  private $FIXCERTS = array(
83
+    private $FIXCERTS = array(
82 84
     '349bca1031f8c82c4ceca38b9cebf1a69df9fb3b94eed99eb3fb9aa3822d26e8',
83 85
     'dd574527df608e47ae45fbba75a2afdd5c20fd94a02419381813cd55a2a3398f',
84 86
     '1d8764f0f7cd1352df6150045c8f638e517270e8b5dda1c63ade9c2280240cae',
@@ -87,320 +89,331 @@ class U2F {
87 89
     'ca993121846c464d666096d35f13bf44c1b05af205f9b4a1e00cf6cc10c5e511'
88 90
   );
89 91
 
90
-  /**
91
-   * @param string $appId Application id for the running application
92
-   * @param string|null $attestDir Directory where trusted attestation roots may be found
93
-   * @throws Error If OpenSSL older than 1.0.0 is used
94
-   */
95
-  public function __construct($appId, $attestDir = null) {
96
-    if (OPENSSL_VERSION_NUMBER < 0x10000000) {
97
-      throw new Error('OpenSSL has to be at least version 1.0.0, this is ' . OPENSSL_VERSION_TEXT, ERR_OLD_OPENSSL);
98
-    }
99
-    $this->appId = $appId;
100
-    $this->attestDir = $attestDir;
101
-  }
102
-
103
-  /**
104
-   * Called to get a registration request to send to a user.
105
-   * Returns an array of one registration request and a array of sign requests.
106
-   *
107
-   * @param array $registrations List of current registrations for this
108
-   * user, to prevent the user from registering the same authenticator several
109
-   * times.
110
-   * @return array An array of two elements, the first containing a
111
-   * RegisterRequest the second being an array of SignRequest
112
-   * @throws Error
113
-   */
114
-  public function getRegisterData(array $registrations = []) {
115
-    $challenge = $this->createChallenge();
116
-    $request = new RegisterRequest($challenge, $this->appId);
117
-    $signs = $this->getAuthenticateData($registrations);
118
-    return [$request, $signs];
119
-  }
120
-
121
-  /**
122
-   * Called to verify and unpack a registration message.
123
-   *
124
-   * @param RegisterRequest $request this is a reply to
125
-   * @param object $response response from a user
126
-   * @param bool $includeCert set to true if the attestation certificate should be
127
-   * included in the returned Registration object
128
-   * @return Registration
129
-   * @throws Error
130
-   */
131
-  public function doRegister($request, $response, $includeCert = true) {
132
-    if (!is_object($request)) {
133
-      throw new \InvalidArgumentException('$request of doRegister() method only accepts object.');
92
+    /**
93
+     * @param string $appId Application id for the running application
94
+     * @param string|null $attestDir Directory where trusted attestation roots may be found
95
+     * @throws Error If OpenSSL older than 1.0.0 is used
96
+     */
97
+    public function __construct($appId, $attestDir = null)
98
+    {
99
+        if (OPENSSL_VERSION_NUMBER < 0x10000000) {
100
+            throw new Error('OpenSSL has to be at least version 1.0.0, this is ' . OPENSSL_VERSION_TEXT, ERR_OLD_OPENSSL);
101
+        }
102
+        $this->appId = $appId;
103
+        $this->attestDir = $attestDir;
134 104
     }
135 105
 
136
-    if (!is_object($response)) {
137
-      throw new \InvalidArgumentException('$response of doRegister() method only accepts object.');
106
+    /**
107
+     * Called to get a registration request to send to a user.
108
+     * Returns an array of one registration request and a array of sign requests.
109
+     *
110
+     * @param array $registrations List of current registrations for this
111
+     * user, to prevent the user from registering the same authenticator several
112
+     * times.
113
+     * @return array An array of two elements, the first containing a
114
+     * RegisterRequest the second being an array of SignRequest
115
+     * @throws Error
116
+     */
117
+    public function getRegisterData(array $registrations = [])
118
+    {
119
+        $challenge = $this->createChallenge();
120
+        $request = new RegisterRequest($challenge, $this->appId);
121
+        $signs = $this->getAuthenticateData($registrations);
122
+        return [$request, $signs];
138 123
     }
139 124
 
140
-    if (property_exists($response, 'errorCode') && $response->errorCode !== 0) {
141
-      throw new Error('User-agent returned error. Error code: ' . $response->errorCode, ERR_BAD_UA_RETURNING );
142
-    }
125
+    /**
126
+     * Called to verify and unpack a registration message.
127
+     *
128
+     * @param RegisterRequest $request this is a reply to
129
+     * @param object $response response from a user
130
+     * @param bool $includeCert set to true if the attestation certificate should be
131
+     * included in the returned Registration object
132
+     * @return Registration
133
+     * @throws Error
134
+     */
135
+    public function doRegister($request, $response, $includeCert = true)
136
+    {
137
+        if (!is_object($request)) {
138
+            throw new \InvalidArgumentException('$request of doRegister() method only accepts object.');
139
+        }
143 140
 
144
-    if (!is_bool($includeCert)) {
145
-      throw new \InvalidArgumentException('$include_cert of doRegister() method only accepts boolean.');
146
-    }
141
+        if (!is_object($response)) {
142
+            throw new \InvalidArgumentException('$response of doRegister() method only accepts object.');
143
+        }
147 144
 
148
-    $rawReg = $this->base64u_decode($response->registrationData);
149
-    $regData = array_values(unpack('C*', $rawReg));
150
-    $clientData = $this->base64u_decode($response->clientData);
151
-    $cli = json_decode($clientData);
145
+        if (property_exists($response, 'errorCode') && $response->errorCode !== 0) {
146
+            throw new Error('User-agent returned error. Error code: ' . $response->errorCode, ERR_BAD_UA_RETURNING);
147
+        }
152 148
 
153
-    if ($cli->challenge !== $request->challenge) {
154
-      throw new Error('Registration challenge does not match', ERR_UNMATCHED_CHALLENGE );
155
-    }
149
+        if (!is_bool($includeCert)) {
150
+            throw new \InvalidArgumentException('$include_cert of doRegister() method only accepts boolean.');
151
+        }
156 152
 
157
-    $registration = new Registration();
158
-    $offs = 1;
159
-    $pubKey = substr($rawReg, $offs, PUBKEY_LEN);
160
-    $offs += PUBKEY_LEN;
161
-    // decode the pubKey to make sure it's good
162
-    $tmpKey = $this->pubkey_to_pem($pubKey);
163
-    if ($tmpKey === null) {
164
-      throw new Error('Decoding of public key failed', ERR_PUBKEY_DECODE );
165
-    }
166
-    $registration->publicKey = base64_encode($pubKey);
167
-    $khLen = $regData[$offs++];
168
-    $kh = substr($rawReg, $offs, $khLen);
169
-    $offs += $khLen;
170
-    $registration->keyHandle = $this->base64u_encode($kh);
171
-
172
-    // length of certificate is stored in byte 3 and 4 (excluding the first 4 bytes)
173
-    $certLen = 4;
174
-    $certLen += ($regData[$offs + 2] << 8);
175
-    $certLen += $regData[$offs + 3];
176
-
177
-    $rawCert = $this->fixSignatureUnusedBits(substr($rawReg, $offs, $certLen));
178
-    $offs += $certLen;
179
-    $pemCert  = "-----BEGIN CERTIFICATE-----\r\n";
180
-    $pemCert .= chunk_split(base64_encode($rawCert), 64);
181
-    $pemCert .= "-----END CERTIFICATE-----";
182
-    if ($includeCert) {
183
-      $registration->certificate = base64_encode($rawCert);
184
-    }
185
-    if ($this->attestDir) {
186
-      if (openssl_x509_checkpurpose($pemCert, -1, $this->get_certs()) !== true) {
187
-        throw new Error('Attestation certificate can not be validated', ERR_ATTESTATION_VERIFICATION );
188
-      }
189
-    }
153
+        $rawReg = $this->base64u_decode($response->registrationData);
154
+        $regData = array_values(unpack('C*', $rawReg));
155
+        $clientData = $this->base64u_decode($response->clientData);
156
+        $cli = json_decode($clientData);
190 157
 
191
-    if (!openssl_pkey_get_public($pemCert)) {
192
-      throw new Error('Decoding of public key failed', ERR_PUBKEY_DECODE );
193
-    }
194
-    $signature = substr($rawReg, $offs);
195
-
196
-    $dataToVerify  = chr(0);
197
-    $dataToVerify .= hash('sha256', $request->appId, true);
198
-    $dataToVerify .= hash('sha256', $clientData, true);
199
-    $dataToVerify .= $kh;
200
-    $dataToVerify .= $pubKey;
201
-
202
-    if (openssl_verify($dataToVerify, $signature, $pemCert, 'sha256') === 1) {
203
-      return $registration;
204
-    } else {
205
-      throw new Error('Attestation signature does not match', ERR_ATTESTATION_SIGNATURE );
206
-    }
207
-  }
208
-
209
-  /**
210
-   * Called to get an authentication request.
211
-   *
212
-   * @param array $registrations An array of the registrations to create authentication requests for.
213
-   * @return array An array of SignRequest
214
-   * @throws Error
215
-   */
216
-  public function getAuthenticateData(array $registrations) {
217
-    $sigs = array();
218
-    $challenge = $this->createChallenge();
219
-    foreach ($registrations as $reg) {
220
-      if (!is_object($reg)) {
221
-        throw new \InvalidArgumentException('$registrations of getAuthenticateData() method only accepts array of object.');
222
-      }
223
-
224
-      $sig = new SignRequest();
225
-      $sig->appId = $this->appId;
226
-      $sig->keyHandle = $reg->keyHandle;
227
-      $sig->challenge = $challenge;
228
-      $sigs[] = $sig;
229
-    }
230
-    return $sigs;
231
-  }
232
-
233
-  /**
234
-   * Called to verify an authentication response
235
-   *
236
-   * @param array $requests An array of outstanding authentication requests
237
-   * @param array $registrations An array of current registrations
238
-   * @param object $response A response from the authenticator
239
-   * @return Registration
240
-   * @throws Error
241
-   *
242
-   * The Registration object returned on success contains an updated counter
243
-   * that should be saved for future authentications.
244
-   * If the Error returned is ERR_COUNTER_TOO_LOW this is an indication of
245
-   * token cloning or similar and appropriate action should be taken.
246
-   */
247
-  public function doAuthenticate(array $requests, array $registrations, $response) {
248
-    if (!is_object($response)) {
249
-      throw new \InvalidArgumentException('$response of doAuthenticate() method only accepts object.');
158
+        if ($cli->challenge !== $request->challenge) {
159
+            throw new Error('Registration challenge does not match', ERR_UNMATCHED_CHALLENGE);
160
+        }
161
+
162
+        $registration = new Registration();
163
+        $offs = 1;
164
+        $pubKey = substr($rawReg, $offs, PUBKEY_LEN);
165
+        $offs += PUBKEY_LEN;
166
+        // decode the pubKey to make sure it's good
167
+        $tmpKey = $this->pubkey_to_pem($pubKey);
168
+        if ($tmpKey === null) {
169
+            throw new Error('Decoding of public key failed', ERR_PUBKEY_DECODE);
170
+        }
171
+        $registration->publicKey = base64_encode($pubKey);
172
+        $khLen = $regData[$offs++];
173
+        $kh = substr($rawReg, $offs, $khLen);
174
+        $offs += $khLen;
175
+        $registration->keyHandle = $this->base64u_encode($kh);
176
+
177
+        // length of certificate is stored in byte 3 and 4 (excluding the first 4 bytes)
178
+        $certLen = 4;
179
+        $certLen += ($regData[$offs + 2] << 8);
180
+        $certLen += $regData[$offs + 3];
181
+
182
+        $rawCert = $this->fixSignatureUnusedBits(substr($rawReg, $offs, $certLen));
183
+        $offs += $certLen;
184
+        $pemCert  = "-----BEGIN CERTIFICATE-----\r\n";
185
+        $pemCert .= chunk_split(base64_encode($rawCert), 64);
186
+        $pemCert .= "-----END CERTIFICATE-----";
187
+        if ($includeCert) {
188
+            $registration->certificate = base64_encode($rawCert);
189
+        }
190
+        if ($this->attestDir) {
191
+            if (openssl_x509_checkpurpose($pemCert, -1, $this->get_certs()) !== true) {
192
+                throw new Error('Attestation certificate can not be validated', ERR_ATTESTATION_VERIFICATION);
193
+            }
194
+        }
195
+
196
+        if (!openssl_pkey_get_public($pemCert)) {
197
+            throw new Error('Decoding of public key failed', ERR_PUBKEY_DECODE);
198
+        }
199
+        $signature = substr($rawReg, $offs);
200
+
201
+        $dataToVerify  = chr(0);
202
+        $dataToVerify .= hash('sha256', $request->appId, true);
203
+        $dataToVerify .= hash('sha256', $clientData, true);
204
+        $dataToVerify .= $kh;
205
+        $dataToVerify .= $pubKey;
206
+
207
+        if (openssl_verify($dataToVerify, $signature, $pemCert, 'sha256') === 1) {
208
+            return $registration;
209
+        } else {
210
+            throw new Error('Attestation signature does not match', ERR_ATTESTATION_SIGNATURE);
211
+        }
250 212
     }
251 213
 
252
-    if (property_exists($response, 'errorCode') && $response->errorCode !== 0) {
253
-      throw new Error('User-agent returned error. Error code: ' . $response->errorCode, ERR_BAD_UA_RETURNING );
214
+    /**
215
+     * Called to get an authentication request.
216
+     *
217
+     * @param array $registrations An array of the registrations to create authentication requests for.
218
+     * @return array An array of SignRequest
219
+     * @throws Error
220
+     */
221
+    public function getAuthenticateData(array $registrations)
222
+    {
223
+        $sigs = array();
224
+        $challenge = $this->createChallenge();
225
+        foreach ($registrations as $reg) {
226
+            if (!is_object($reg)) {
227
+                throw new \InvalidArgumentException('$registrations of getAuthenticateData() method only accepts array of object.');
228
+            }
229
+
230
+            $sig = new SignRequest();
231
+            $sig->appId = $this->appId;
232
+            $sig->keyHandle = $reg->keyHandle;
233
+            $sig->challenge = $challenge;
234
+            $sigs[] = $sig;
235
+        }
236
+        return $sigs;
254 237
     }
255 238
 
256
-    $req = null;
257
-    $reg = null;
239
+    /**
240
+     * Called to verify an authentication response
241
+     *
242
+     * @param array $requests An array of outstanding authentication requests
243
+     * @param array $registrations An array of current registrations
244
+     * @param object $response A response from the authenticator
245
+     * @return Registration
246
+     * @throws Error
247
+     *
248
+     * The Registration object returned on success contains an updated counter
249
+     * that should be saved for future authentications.
250
+     * If the Error returned is ERR_COUNTER_TOO_LOW this is an indication of
251
+     * token cloning or similar and appropriate action should be taken.
252
+     */
253
+    public function doAuthenticate(array $requests, array $registrations, $response)
254
+    {
255
+        if (!is_object($response)) {
256
+            throw new \InvalidArgumentException('$response of doAuthenticate() method only accepts object.');
257
+        }
258
+
259
+        if (property_exists($response, 'errorCode') && $response->errorCode !== 0) {
260
+            throw new Error('User-agent returned error. Error code: ' . $response->errorCode, ERR_BAD_UA_RETURNING);
261
+        }
258 262
 
259
-    $clientData = $this->base64u_decode($response->clientData);
260
-    $decodedClient = json_decode($clientData);
261
-    foreach ($requests as $req) {
262
-      if (!is_object($req)) {
263
-        throw new \InvalidArgumentException('$requests of doAuthenticate() method only accepts array of object.');
264
-      }
263
+        $req = null;
264
+        $reg = null;
265 265
 
266
-      if ($req->keyHandle === $response->keyHandle && $req->challenge === $decodedClient->challenge) {
267
-        break;
268
-      }
266
+        $clientData = $this->base64u_decode($response->clientData);
267
+        $decodedClient = json_decode($clientData);
268
+        foreach ($requests as $req) {
269
+            if (!is_object($req)) {
270
+                throw new \InvalidArgumentException('$requests of doAuthenticate() method only accepts array of object.');
271
+            }
269 272
 
270
-      $req = null;
271
-    }
272
-    if ($req === null) {
273
-      throw new Error('No matching request found', ERR_NO_MATCHING_REQUEST );
274
-    }
275
-    foreach ($registrations as $reg) {
276
-      if (!is_object($reg)) {
277
-        throw new \InvalidArgumentException('$registrations of doAuthenticate() method only accepts array of object.');
278
-      }
279
-
280
-      if ($reg->keyHandle === $response->keyHandle) {
281
-        break;
282
-      }
283
-      $reg = null;
273
+            if ($req->keyHandle === $response->keyHandle && $req->challenge === $decodedClient->challenge) {
274
+                break;
275
+            }
276
+
277
+            $req = null;
278
+        }
279
+        if ($req === null) {
280
+            throw new Error('No matching request found', ERR_NO_MATCHING_REQUEST);
281
+        }
282
+        foreach ($registrations as $reg) {
283
+            if (!is_object($reg)) {
284
+                throw new \InvalidArgumentException('$registrations of doAuthenticate() method only accepts array of object.');
285
+            }
286
+
287
+            if ($reg->keyHandle === $response->keyHandle) {
288
+                break;
289
+            }
290
+            $reg = null;
291
+        }
292
+        if ($reg === null) {
293
+            throw new Error('No matching registration found', ERR_NO_MATCHING_REGISTRATION);
294
+        }
295
+        $pemKey = $this->pubkey_to_pem($this->base64u_decode($reg->publicKey));
296
+        if ($pemKey === null) {
297
+            throw new Error('Decoding of public key failed', ERR_PUBKEY_DECODE);
298
+        }
299
+
300
+        $signData = $this->base64u_decode($response->signatureData);
301
+        $dataToVerify  = hash('sha256', $req->appId, true);
302
+        $dataToVerify .= substr($signData, 0, 5);
303
+        $dataToVerify .= hash('sha256', $clientData, true);
304
+        $signature = substr($signData, 5);
305
+
306
+        if (openssl_verify($dataToVerify, $signature, $pemKey, 'sha256') === 1) {
307
+            $ctr = unpack("Nctr", substr($signData, 1, 4));
308
+            $counter = $ctr['ctr'];
309
+            /* todo: wrap-around should be handled somehow... */
310
+            if ($counter > $reg->counter) {
311
+                $reg->counter = $counter;
312
+                return $reg;
313
+            } else {
314
+                throw new Error('Counter too low.', ERR_COUNTER_TOO_LOW);
315
+            }
316
+        } else {
317
+            throw new Error('Authentication failed', ERR_AUTHENTICATION_FAILURE);
318
+        }
284 319
     }
285
-    if ($reg === null) {
286
-      throw new Error('No matching registration found', ERR_NO_MATCHING_REGISTRATION );
320
+
321
+    /**
322
+     * @return array
323
+     */
324
+    private function get_certs()
325
+    {
326
+        $files = array();
327
+        $dir = $this->attestDir;
328
+        if ($dir && $handle = opendir($dir)) {
329
+            while (false !== ($entry = readdir($handle))) {
330
+                if (is_file("$dir/$entry")) {
331
+                    $files[] = "$dir/$entry";
332
+                }
333
+            }
334
+            closedir($handle);
335
+        }
336
+        return $files;
287 337
     }
288
-    $pemKey = $this->pubkey_to_pem($this->base64u_decode($reg->publicKey));
289
-    if ($pemKey === null) {
290
-      throw new Error('Decoding of public key failed', ERR_PUBKEY_DECODE );
338
+
339
+    /**
340
+     * @param string $data
341
+     * @return string
342
+     */
343
+    private function base64u_encode($data)
344
+    {
345
+        return trim(strtr(base64_encode($data), '+/', '-_'), '=');
291 346
     }
292 347
 
293
-    $signData = $this->base64u_decode($response->signatureData);
294
-    $dataToVerify  = hash('sha256', $req->appId, true);
295
-    $dataToVerify .= substr($signData, 0, 5);
296
-    $dataToVerify .= hash('sha256', $clientData, true);
297
-    $signature = substr($signData, 5);
298
-
299
-    if (openssl_verify($dataToVerify, $signature, $pemKey, 'sha256') === 1) {
300
-      $ctr = unpack("Nctr", substr($signData, 1, 4));
301
-      $counter = $ctr['ctr'];
302
-      /* todo: wrap-around should be handled somehow... */
303
-      if ($counter > $reg->counter) {
304
-        $reg->counter = $counter;
305
-        return $reg;
306
-      } else {
307
-        throw new Error('Counter too low.', ERR_COUNTER_TOO_LOW );
308
-      }
309
-    } else {
310
-      throw new Error('Authentication failed', ERR_AUTHENTICATION_FAILURE );
348
+    /**
349
+     * @param string $data
350
+     * @return string
351
+     */
352
+    private function base64u_decode($data)
353
+    {
354
+        return base64_decode(strtr($data, '-_', '+/'));
311 355
     }
312
-  }
313
-
314
-  /**
315
-   * @return array
316
-   */
317
-  private function get_certs() {
318
-    $files = array();
319
-    $dir = $this->attestDir;
320
-    if ($dir && $handle = opendir($dir)) {
321
-      while(false !== ($entry = readdir($handle))) {
322
-        if (is_file("$dir/$entry")) {
323
-          $files[] = "$dir/$entry";
356
+
357
+    /**
358
+     * @param string $key
359
+     * @return null|string
360
+     */
361
+    private function pubkey_to_pem($key)
362
+    {
363
+        if (strlen($key) !== PUBKEY_LEN || $key[0] !== "\x04") {
364
+            return null;
324 365
         }
325
-      }
326
-      closedir($handle);
327
-    }
328
-    return $files;
329
-  }
330
-
331
-  /**
332
-   * @param string $data
333
-   * @return string
334
-   */
335
-  private function base64u_encode($data) {
336
-    return trim(strtr(base64_encode($data), '+/', '-_'), '=');
337
-  }
338
-
339
-  /**
340
-   * @param string $data
341
-   * @return string
342
-   */
343
-  private function base64u_decode($data) {
344
-    return base64_decode(strtr($data, '-_', '+/'));
345
-  }
346
-
347
-  /**
348
-   * @param string $key
349
-   * @return null|string
350
-   */
351
-  private function pubkey_to_pem($key) {
352
-    if (strlen($key) !== PUBKEY_LEN || $key[0] !== "\x04") {
353
-      return null;
366
+
367
+        /*
368
+         * Convert the public key to binary DER format first
369
+         * Using the ECC SubjectPublicKeyInfo OIDs from RFC 5480
370
+         *
371
+         *  SEQUENCE(2 elem)                        30 59
372
+         *   SEQUENCE(2 elem)                       30 13
373
+         *    OID1.2.840.10045.2.1 (id-ecPublicKey) 06 07 2a 86 48 ce 3d 02 01
374
+         *    OID1.2.840.10045.3.1.7 (secp256r1)    06 08 2a 86 48 ce 3d 03 01 07
375
+         *   BIT STRING(520 bit)                    03 42 ..key..
376
+         */
377
+        $der  = "\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01";
378
+        $der .= "\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42";
379
+        $der .= "\0".$key;
380
+
381
+        $pem  = "-----BEGIN PUBLIC KEY-----\r\n";
382
+        $pem .= chunk_split(base64_encode($der), 64);
383
+        $pem .= "-----END PUBLIC KEY-----";
384
+
385
+        return $pem;
354 386
     }
355 387
 
356
-    /*
357
-     * Convert the public key to binary DER format first
358
-     * Using the ECC SubjectPublicKeyInfo OIDs from RFC 5480
359
-     *
360
-     *  SEQUENCE(2 elem)                        30 59
361
-     *   SEQUENCE(2 elem)                       30 13
362
-     *    OID1.2.840.10045.2.1 (id-ecPublicKey) 06 07 2a 86 48 ce 3d 02 01
363
-     *    OID1.2.840.10045.3.1.7 (secp256r1)    06 08 2a 86 48 ce 3d 03 01 07
364
-     *   BIT STRING(520 bit)                    03 42 ..key..
388
+    /**
389
+     * @return string
390
+     * @throws Error
365 391
      */
366
-    $der  = "\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01";
367
-    $der .= "\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42";
368
-    $der .= "\0".$key;
369
-
370
-    $pem  = "-----BEGIN PUBLIC KEY-----\r\n";
371
-    $pem .= chunk_split(base64_encode($der), 64);
372
-    $pem .= "-----END PUBLIC KEY-----";
373
-
374
-    return $pem;
375
-  }
376
-
377
-  /**
378
-   * @return string
379
-   * @throws Error
380
-   */
381
-  private function createChallenge() {
382
-    $challenge = openssl_random_pseudo_bytes(32, $crypto_strong );
383
-    if ($crypto_strong !== true) {
384
-      throw new Error('Unable to obtain a good source of randomness', ERR_BAD_RANDOM);
385
-    }
392
+    private function createChallenge()
393
+    {
394
+        $challenge = openssl_random_pseudo_bytes(32, $crypto_strong);
395
+        if ($crypto_strong !== true) {
396
+            throw new Error('Unable to obtain a good source of randomness', ERR_BAD_RANDOM);
397
+        }
386 398
 
387
-    $challenge = $this->base64u_encode( $challenge );
399
+        $challenge = $this->base64u_encode($challenge);
388 400
 
389
-    return $challenge;
390
-  }
401
+        return $challenge;
402
+    }
391 403
 
392
-  /**
393
-   * Fixes a certificate where the signature contains unused bits.
394
-   *
395
-   * @param string $cert
396
-   * @return mixed
397
-   */
398
-  private function fixSignatureUnusedBits($cert) {
399
-    if (in_array(hash('sha256', $cert), $this->FIXCERTS)) {
400
-      $cert[strlen($cert) - 257] = "\0";
404
+    /**
405
+     * Fixes a certificate where the signature contains unused bits.
406
+     *
407
+     * @param string $cert
408
+     * @return mixed
409
+     */
410
+    private function fixSignatureUnusedBits($cert)
411
+    {
412
+        if (in_array(hash('sha256', $cert), $this->FIXCERTS)) {
413
+            $cert[strlen($cert) - 257] = "\0";
414
+        }
415
+        return $cert;
401 416
     }
402
-    return $cert;
403
-  }
404 417
 }
405 418
 
406 419
 /**
@@ -408,22 +421,24 @@ class U2F {
408 421
  *
409 422
  * @package u2flib_server
410 423
  */
411
-class RegisterRequest {
412
-  public $version = U2F_VERSION;
413
-
414
-  public $challenge;
415
-
416
-  public $appId;
417
-
418
-  /**
419
-   * @param string $challenge
420
-   * @param string $appId
421
-   * @internal
422
-   */
423
-  public function __construct($challenge, $appId) {
424
-    $this->challenge = $challenge;
425
-    $this->appId = $appId;
426
-  }
424
+class RegisterRequest
425
+{
426
+    public $version = U2F_VERSION;
427
+
428
+    public $challenge;
429
+
430
+    public $appId;
431
+
432
+    /**
433
+     * @param string $challenge
434
+     * @param string $appId
435
+     * @internal
436
+     */
437
+    public function __construct($challenge, $appId)
438
+    {
439
+        $this->challenge = $challenge;
440
+        $this->appId = $appId;
441
+    }
427 442
 }
428 443
 
429 444
 /**
@@ -431,14 +446,15 @@ class RegisterRequest {
431 446
  *
432 447
  * @package u2flib_server
433 448
  */
434
-class SignRequest {
435
-  public $version = U2F_VERSION;
449
+class SignRequest
450
+{
451
+    public $version = U2F_VERSION;
436 452
 
437
-  public $challenge;
453
+    public $challenge;
438 454
 
439
-  public $keyHandle;
455
+    public $keyHandle;
440 456
 
441
-  public $appId;
457
+    public $appId;
442 458
 }
443 459
 
444 460
 /**
@@ -446,14 +462,15 @@ class SignRequest {
446 462
  *
447 463
  * @package u2flib_server
448 464
  */
449
-class Registration {
450
-  public $keyHandle;
465
+class Registration
466
+{
467
+    public $keyHandle;
451 468
 
452
-  public $publicKey;
469
+    public $publicKey;
453 470
 
454
-  public $certificate;
471
+    public $certificate;
455 472
 
456
-  public $counter = -1;
473
+    public $counter = -1;
457 474
 }
458 475
 
459 476
 /**
@@ -461,14 +478,16 @@ class Registration {
461 478
  *
462 479
  * @package u2flib_server
463 480
  */
464
-class Error extends \Exception {
465
-  /**
466
-   * Override constructor and make message and code mandatory
467
-   * @param string $message
468
-   * @param int $code
469
-   * @param \Exception|null $previous
470
-   */
471
-  public function __construct($message, $code, \Exception $previous = null) {
472
-    parent::__construct($message, $code, $previous);
473
-  }
481
+class Error extends \Exception
482
+{
483
+    /**
484
+     * Override constructor and make message and code mandatory
485
+     * @param string $message
486
+     * @param int $code
487
+     * @param \Exception|null $previous
488
+     */
489
+    public function __construct($message, $code, \Exception $previous = null)
490
+    {
491
+        parent::__construct($message, $code, $previous);
492
+    }
474 493
 }

+ 43
- 38
classes/useragent.class.php View File

@@ -1,6 +1,8 @@
1
-<?
2
-class UserAgent {
3
-  private static $Browsers = array(
1
+<?php
2
+
3
+class UserAgent
4
+{
5
+    private static $Browsers = array(
4 6
     //Less popular
5 7
     'Shiira'     => 'Shiira',
6 8
     'Songbird'   => 'Songbird',
@@ -45,7 +47,7 @@ class UserAgent {
45 47
     */
46 48
   );
47 49
 
48
-  private static $OperatingSystems = array(
50
+    private static $OperatingSystems = array(
49 51
     //Mobile
50 52
     'SymbianOS'    => 'Symbian',
51 53
     'blackberry'   => 'BlackBerry',
@@ -117,44 +119,47 @@ class UserAgent {
117 119
     'mac' => 'Mac OS X'
118 120
   );
119 121
 
120
-  public static function operating_system(&$UserAgentString) {
121
-    if (empty($UserAgentString)) {
122
-      return 'Hidden';
123
-    }
124
-    foreach (self::$OperatingSystems as $String => $OperatingSystem) {
125
-      if (stripos($UserAgentString, $String) !== false) {
126
-        return $OperatingSystem;
127
-      }
122
+    public static function operating_system(&$UserAgentString)
123
+    {
124
+        if (empty($UserAgentString)) {
125
+            return 'Hidden';
126
+        }
127
+        foreach (self::$OperatingSystems as $String => $OperatingSystem) {
128
+            if (stripos($UserAgentString, $String) !== false) {
129
+                return $OperatingSystem;
130
+            }
131
+        }
132
+        return 'Unknown';
128 133
     }
129
-    return 'Unknown';
130
-  }
131 134
 
132
-  public static function mobile(&$UserAgentString) {
133
-    if (strpos($UserAgentString, 'iPad') !== false) {
134
-      return false;
135
-    }
135
+    public static function mobile(&$UserAgentString)
136
+    {
137
+        if (strpos($UserAgentString, 'iPad') !== false) {
138
+            return false;
139
+        }
136 140
 
137
-    // "Mobi" catches "Mobile" too
138
-    if (strpos($UserAgentString, 'Device') || strpos($UserAgentString, 'Mobi') || strpos($UserAgentString, 'Mini') || strpos($UserAgentString, 'webOS')) {
139
-      return true;
141
+        // "Mobi" catches "Mobile" too
142
+        if (strpos($UserAgentString, 'Device') || strpos($UserAgentString, 'Mobi') || strpos($UserAgentString, 'Mini') || strpos($UserAgentString, 'webOS')) {
143
+            return true;
144
+        }
145
+        return false;
140 146
     }
141
-    return false;
142
-  }
143 147
 
144
-  public static function browser(&$UserAgentString) {
145
-    if (empty($UserAgentString)) {
146
-      return 'Hidden';
147
-    }
148
-    $Return = 'Unknown';
149
-    foreach (self::$Browsers as $String => $Browser) {
150
-      if (strpos($UserAgentString, $String) !== false) {
151
-        $Return = $Browser;
152
-        break;
153
-      }
154
-    }
155
-    if (self::mobile($UserAgentString)) {
156
-      $Return .= ' Mobile';
148
+    public static function browser(&$UserAgentString)
149
+    {
150
+        if (empty($UserAgentString)) {
151
+            return 'Hidden';
152
+        }
153
+        $Return = 'Unknown';
154
+        foreach (self::$Browsers as $String => $Browser) {
155
+            if (strpos($UserAgentString, $String) !== false) {
156
+                $Return = $Browser;
157
+                break;
158
+            }
159
+        }
160
+        if (self::mobile($UserAgentString)) {
161
+            $Return .= ' Mobile';
162
+        }
163
+        return $Return;
157 164
     }
158
-    return $Return;
159
-  }
160 165
 }

+ 73
- 71
classes/userrank.class.php View File

@@ -1,47 +1,51 @@
1
-<?
2
-class UserRank {
3
-  const PREFIX = 'percentiles_'; // Prefix for memcache keys, to make life easier
1
+<?php
4 2
 
5
-  // Returns a 101 row array (101 percentiles - 0 - 100), with the minimum value for that percentile as the value for each row
6
-  // BTW - ingenious
7
-  private static function build_table($MemKey, $Query) {
8
-    $QueryID = G::$DB->get_query_id();
3
+class UserRank
4
+{
5
+    const PREFIX = 'percentiles_'; // Prefix for memcache keys, to make life easier
9 6
 
10
-    G::$DB->query("
7
+    // Returns a 101 row array (101 percentiles - 0 - 100), with the minimum value for that percentile as the value for each row
8
+    // BTW - ingenious
9
+    private static function build_table($MemKey, $Query)
10
+    {
11
+        $QueryID = G::$DB->get_query_id();
12
+
13
+        G::$DB->query("
11 14
       DROP TEMPORARY TABLE IF EXISTS temp_stats");
12 15
 
13
-    G::$DB->query("
16
+        G::$DB->query("
14 17
       CREATE TEMPORARY TABLE temp_stats (
15 18
         ID int(10) NOT NULL PRIMARY KEY AUTO_INCREMENT,
16 19
         Val bigint(20) NOT NULL
17 20
       );");
18 21
 
19
-    G::$DB->query("
22
+        G::$DB->query("
20 23
       INSERT INTO temp_stats (Val) ".
21 24
       $Query);
22 25
 
23
-    G::$DB->query("
26
+        G::$DB->query("
24 27
       SELECT COUNT(ID)
25 28
       FROM temp_stats");
26
-    list($UserCount) = G::$DB->next_record();
29
+        list($UserCount) = G::$DB->next_record();
27 30
 
28
-    G::$DB->query("
31
+        G::$DB->query("
29 32
       SELECT MIN(Val)
30 33
       FROM temp_stats
31 34
       GROUP BY CEIL(ID / (".(int)$UserCount." / 100));");
32 35
 
33
-    $Table = G::$DB->to_array();
36
+        $Table = G::$DB->to_array();
34 37
 
35
-    G::$DB->set_query_id($QueryID);
38
+        G::$DB->set_query_id($QueryID);
36 39
 
37
-    // Give a little variation to the cache length, so all the tables don't expire at the same time
38
-    G::$Cache->cache_value($MemKey, $Table, 3600 * 24 * rand(800, 1000) * 0.001);
40
+        // Give a little variation to the cache length, so all the tables don't expire at the same time
41
+        G::$Cache->cache_value($MemKey, $Table, 3600 * 24 * rand(800, 1000) * 0.001);
39 42
 
40
-    return $Table;
41
-  }
43
+        return $Table;
44
+    }
42 45
 
43
-  private static function table_query($TableName) {
44
-    switch ($TableName) {
46
+    private static function table_query($TableName)
47
+    {
48
+        switch ($TableName) {
45 49
       case 'uploaded':
46 50
         $Query =  "
47 51
           SELECT Uploaded
@@ -105,59 +109,57 @@ class UserRank {
105 109
           ORDER BY Artists ASC";
106 110
         break;
107 111
     }
108
-    return $Query;
109
-  }
110
-
111
-  public static function get_rank($TableName, $Value) {
112
-    if ($Value == 0) {
113
-      return 0;
112
+        return $Query;
114 113
     }
115 114
 
116
-    $Table = G::$Cache->get_value(self::PREFIX.$TableName);
117
-    if (!$Table) {
118
-      //Cache lock!
119
-      $Lock = G::$Cache->get_value(self::PREFIX.$TableName.'_lock');
120
-      if ($Lock) {
121
-        return false;
122
-      } else {
123
-        G::$Cache->cache_value(self::PREFIX.$TableName.'_lock', '1', 300);
124
-        $Table = self::build_table(self::PREFIX.$TableName, self::table_query($TableName));
125
-        G::$Cache->delete_value(self::PREFIX.$TableName.'_lock');
126
-      }
127
-    }
128
-    $LastPercentile = 0;
129
-    foreach ($Table as $Row) {
130
-      list($CurValue) = $Row;
131
-      if ($CurValue >= $Value) {
132
-        return $LastPercentile;
133
-      }
134
-      $LastPercentile++;
115
+    public static function get_rank($TableName, $Value)
116
+    {
117
+        if ($Value == 0) {
118
+            return 0;
119
+        }
120
+
121
+        $Table = G::$Cache->get_value(self::PREFIX.$TableName);
122
+        if (!$Table) {
123
+            //Cache lock!
124
+            $Lock = G::$Cache->get_value(self::PREFIX.$TableName.'_lock');
125
+            if ($Lock) {
126
+                return false;
127
+            } else {
128
+                G::$Cache->cache_value(self::PREFIX.$TableName.'_lock', '1', 300);
129
+                $Table = self::build_table(self::PREFIX.$TableName, self::table_query($TableName));
130
+                G::$Cache->delete_value(self::PREFIX.$TableName.'_lock');
131
+            }
132
+        }
133
+        $LastPercentile = 0;
134
+        foreach ($Table as $Row) {
135
+            list($CurValue) = $Row;
136
+            if ($CurValue >= $Value) {
137
+                return $LastPercentile;
138
+            }
139
+            $LastPercentile++;
140
+        }
141
+        return 100; // 100th percentile
135 142
     }
136
-    return 100; // 100th percentile
137
-  }
138 143
 
139
-  public static function overall_score($Uploaded, $Downloaded, $Uploads, $Requests, $Posts, $Bounty, $Artists, $Ratio) {
140
-    // We can do this all in 1 line, but it's easier to read this way
141
-    if ($Ratio > 1) {
142
-      $Ratio = 1;
144
+    public static function overall_score($Uploaded, $Downloaded, $Uploads, $Requests, $Posts, $Bounty, $Artists, $Ratio)
145
+    {
146
+        // We can do this all in 1 line, but it's easier to read this way
147
+        if ($Ratio > 1) {
148
+            $Ratio = 1;
149
+        }
150
+        $TotalScore = 0;
151
+        if (in_array(false, func_get_args(), true)) {
152
+            return false;
153
+        }
154
+        $TotalScore += $Uploaded * 15;
155
+        $TotalScore += $Downloaded * 8;
156
+        $TotalScore += $Uploads * 25;
157
+        $TotalScore += $Requests * 2;
158
+        $TotalScore += $Posts;
159
+        $TotalScore += $Bounty;
160
+        $TotalScore += $Artists;
161
+        $TotalScore /= (15 + 8 + 25 + 2 + 1 + 1 + 1);
162
+        $TotalScore *= $Ratio;
163
+        return $TotalScore;
143 164
     }
144
-    $TotalScore = 0;
145
-    if (in_array(false, func_get_args(), true)) {
146
-      return false;
147
-    }
148
-    $TotalScore += $Uploaded * 15;
149
-    $TotalScore += $Downloaded * 8;
150
-    $TotalScore += $Uploads * 25;
151
-    $TotalScore += $Requests * 2;
152
-    $TotalScore += $Posts;
153
-    $TotalScore += $Bounty;
154
-    $TotalScore += $Artists;
155
-    $TotalScore /= (15 + 8 + 25 + 2 + 1 + 1 + 1);
156
-    $TotalScore *= $Ratio;
157
-    return $TotalScore;
158
-  }
159
-
160 165
 }
161
-
162
-
163
-?>

+ 537
- 515
classes/users.class.php
File diff suppressed because it is too large
View File


+ 5
- 5
sections/forums/thread.php View File

@@ -169,12 +169,12 @@ if ($QuoteNotificationsCount === false || $QuoteNotificationsCount > 0) {
169 169
 }
170 170
 
171 171
 // Start printing
172
-View::show_header($ThreadInfo['Title'] . ' &lt; '.$Forums[$ForumID]['Name'].' &lt; Forums','comments,subscriptions,bbcode', $IsDonorForum ? 'donor' : '');
172
+View::show_header($ThreadInfo['Title'] . ' › '.$Forums[$ForumID]['Name'].' › Forums','comments,subscriptions,bbcode', $IsDonorForum ? 'donor' : '');
173 173
 ?>
174 174
 <div class="thin">
175 175
   <h2>
176
-    <a href="forums.php">Forums</a> &gt;
177
-    <a href="forums.php?action=viewforum&amp;forumid=<?=$ThreadInfo['ForumID']?>"><?=$ForumName?></a> &gt;
176
+    <a href="forums.php">Forums</a> 
177
+    <a href="forums.php?action=viewforum&amp;forumid=<?=$ThreadInfo['ForumID']?>"><?=$ForumName?></a> 
178 178
     <?=$ThreadTitle?>
179 179
   </h2>
180 180
   <div class="linkbox">
@@ -523,8 +523,8 @@ foreach ($Thread as $Key => $Post) {
523 523
 </table>
524 524
 <? } ?>
525 525
 <div class="breadcrumbs">
526
-  <a href="forums.php">Forums</a> &gt;
527
-  <a href="forums.php?action=viewforum&amp;forumid=<?=$ThreadInfo['ForumID']?>"><?=$ForumName?></a> &gt;
526
+  <a href="forums.php">Forums</a> 
527
+  <a href="forums.php?action=viewforum&amp;forumid=<?=$ThreadInfo['ForumID']?>"><?=$ForumName?></a> 
528 528
   <?=$ThreadTitle?>
529 529
 </div>
530 530
 <div class="linkbox">

+ 1
- 1
sections/requests/request.php View File

@@ -76,7 +76,7 @@ View::show_header("View request: $FullName", 'comments,requests,bbcode,subscript
76 76
 
77 77
 <div class="thin">
78 78
   <div class="header">
79
-    <h2><a href="requests.php">Requests</a> &gt; <?=$CategoryName?> &gt; <?=$DisplayLink?></h2>
79
+    <h2><a href="requests.php">Requests</a> › <?=$CategoryName?> › <?=$DisplayLink?></h2>
80 80
     <div class="linkbox">
81 81
 <?  if ($CanEdit) { ?>
82 82
       <a href="requests.php?action=edit&amp;id=<?=$RequestID?>" class="brackets">Edit</a>

Loading…
Cancel
Save