Browse Source

Add $ENV->convert, update readme and config template, add more Twig templates, etc.

biotorrents 4 years ago
parent
commit
f397d945f4

+ 1
- 0
.gitignore View File

33
 /static/common/badges/**
33
 /static/common/badges/**
34
 /static/styles/**/*.css
34
 /static/styles/**/*.css
35
 /static/styles/assets/fonts/**
35
 /static/styles/assets/fonts/**
36
+fonts.tgz

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

168
         $this->URL .= "&chl=".implode('|', $Labels).'&chd=e:'.implode('', $Data);
168
         $this->URL .= "&chl=".implode('|', $Labels).'&chd=e:'.implode('', $Data);
169
     }
169
     }
170
 }
170
 }
171
-
172
-/*
173
-class LOG_BAR_GRAPH extends GOOGLE_CHARTS
174
-{
175
-    // todo: Finish
176
-    public function __construct($Base, $Width, $Height, $Options = [])
177
-    {
178
-        parent::__construct('lc', $Width, $Height, $Options);
179
-    }
180
-
181
-    public function color($Color)
182
-    {
183
-        $this->URL .= '&chco='.$Color.'&chm=B,'.$Color.'50,0,0,0';
184
-    }
185
-
186
-    public function generate()
187
-    {
188
-        $Max = max($this->Data);
189
-        $Min = ((isset($this->Options['Break'])) ? $Min = min($this->Data) : 0);
190
-        $Data = [];
191
-
192
-        foreach ($this->Data as $Value) {
193
-            $Data[] = $this->encode((($Value - $Min) / ($Max - $Min)) * 4095);
194
-        }
195
-        $this->URL .= "&chxt=y,x&chxs=0,h&chxl=1:|".implode('|', $this->Labels).'&chxr=0,'.$Min.','.($Max-$Min).'&chd=e:'.implode('', $Data);
196
-    }
197
-}
198
-*/
199
-
200
-/*
201
-class POLL_GRAPH extends GOOGLE_CHARTS
202
-{
203
-    public function __construct()
204
-    {
205
-        $this->URL .= '?cht=bhg';
206
-    }
207
-
208
-    public function add($Label, $Data)
209
-    {
210
-        if ($Label !== false) {
211
-            $this->Labels[] = Format::cut_string($Label, 35);
212
-        }
213
-        $this->Data[] = $Data;
214
-    }
215
-
216
-    public function generate()
217
-    {
218
-        $Count = count($this->Data);
219
-        $Height = (30 * $Count) + 20;
220
-        $Max = max($this->Data);
221
-        $Sum = array_sum($this->Data);
222
-        $Increment = ($Max / $Sum) * 25; // * 100% / 4divisions
223
-        $Data = [];
224
-        $Labels = [];
225
-
226
-        foreach ($this->Data as $Key => $Value) {
227
-            $Data[] = $this->encode(($Value / $Max) * 4095);
228
-            $Labels[] = '@t'.str_replace(array(' ', ','), array('+', '\,'), $this->Labels[$Key]).',000000,1,'.round((($Key + 1) / $Count) - (12 / $Height), 2).':0,12';
229
-        }
230
-        $this->URL .= "&chbh=25,0,5&chs=214x$Height&chl=0%|".round($Increment, 1)."%|".round($Increment * 2, 1)."%|".round($Increment * 3, 1)."%|".round($Increment * 4, 1)."%&chm=".implode('|', $Labels).'&chd=e:'.implode('', $Data);
231
-    }
232
-}
233
-*/

+ 32
- 24
classes/config.template.php View File

1
+
1
 <?php
2
 <?php
2
 declare(strict_types=1);
3
 declare(strict_types=1);
3
 
4
 
19
  *   $LongArray = [];
20
  *   $LongArray = [];
20
  *   ENV::setPub(
21
  *   ENV::setPub(
21
  *     'CONFIG',
22
  *     'CONFIG',
22
- *     new RecursiveArrayObject($LongArray)
23
+ *     $ENV->convert($LongArray)
23
  *   );
24
  *   );
24
  *
25
  *
25
  *   $ENV = ENV::go();
26
  *   $ENV = ENV::go();
32
  *
33
  *
33
  *   var_dump(
34
  *   var_dump(
34
  *     $ENV->dedupe(
35
  *     $ENV->dedupe(
35
- *       $ENV->CATS->SEQ->Platforms,
36
- *       $ENV->CATS->IMG->Platforms->toArray(),
37
- *       [$MapVectorFormats, $MapRasterFormats, $PlainFormats]
36
+ *       $ENV->META->Formats->Sequences,
37
+ *       $ENV->META->Formats->Proteins->toArray()
38
  *     )
38
  *     )
39
  *   );
39
  *   );
40
  */
40
  */
42
 # Initialize
42
 # Initialize
43
 require_once 'env.class.php';
43
 require_once 'env.class.php';
44
 $ENV = ENV::go();
44
 $ENV = ENV::go();
45
+
46
+# Basic info
45
 ENV::setPub('PHP_MIN', '7.4.0');
47
 ENV::setPub('PHP_MIN', '7.4.0');
46
 ENV::setPub('DEV', true);
48
 ENV::setPub('DEV', true);
47
 
49
 
132
 ];
134
 ];
133
 ENV::setPub(
135
 ENV::setPub(
134
     'HELP',
136
     'HELP',
135
-    new RecursiveArrayObject($TechSupport)
137
+    $ENV->convert($TechSupport)
136
 );
138
 );
137
 
139
 
138
 
140
 
180
 #ENV::setPriv('SQLSOCK', '/var/run/mysqld/mysqld.sock');
182
 #ENV::setPriv('SQLSOCK', '/var/run/mysqld/mysqld.sock');
181
 
183
 
182
 # TLS client certs
184
 # TLS client certs
183
-ENV::setPriv('SQL_CERT', "/var/www/sql-keys/client-cert.pem");
184
-ENV::setPriv('SQL_KEY', "/var/www/sql-keys/client-key.pem");
185
-ENV::setPriv('SQL_CA', "/var/www/sql-keys/ca.pem");
185
+ENV::setPriv('SQL_CERT', "$ENV->WEB_ROOT/sql-keys/client-cert.pem");
186
+ENV::setPriv('SQL_KEY', "$ENV->WEB_ROOT/sql-keys/client-key.pem");
187
+ENV::setPriv('SQL_CA', "$ENV->WEB_ROOT/sql-keys/ca.pem");
186
 
188
 
187
  # Production
189
  # Production
188
  if (!$ENV->DEV) {
190
  if (!$ENV->DEV) {
251
     ];
253
     ];
252
     ENV::setPub(
254
     ENV::setPub(
253
         'ANNOUNCE_URLS',
255
         'ANNOUNCE_URLS',
254
-        new RecursiveArrayObject($AnnounceURLs)
256
+        $ENV->convert($AnnounceURLs)
255
     );
257
     );
256
 }
258
 }
257
 
259
 
270
     ];
272
     ];
271
     ENV::setPub(
273
     ENV::setPub(
272
         'ANNOUNCE_URLS',
274
         'ANNOUNCE_URLS',
273
-        new RecursiveArrayObject($AnnounceURLs)
275
+        $ENV->convert($AnnounceURLs)
274
     );
276
     );
275
 }
277
 }
276
 
278
 
378
 # (should only be used for initial setup)
380
 # (should only be used for initial setup)
379
 ENV::setPub('FEATURE_SET_ENC_KEY_PUBLIC', false);
381
 ENV::setPub('FEATURE_SET_ENC_KEY_PUBLIC', false);
380
 
382
 
383
+# Attempt to support the Seqhash algorithm
384
+# https://blog.libredna.org/post/seqhash/
385
+ENV::setPub('FEATURE_SEQHASH', true);
386
+
381
 
387
 
382
 /**
388
 /**
383
  * Settings
389
  * Settings
592
 ];
598
 ];
593
 ENV::setPub(
599
 ENV::setPub(
594
     'AUTOMATED_BADGE_IDS',
600
     'AUTOMATED_BADGE_IDS',
595
-    new RecursiveArrayObject($AutomatedBadgeIDs)
601
+    $ENV->convert($AutomatedBadgeIDs)
596
 );
602
 );
597
 
603
 
598
 
604
 
822
     'picture' => ['name' => 'Picture', 'desc' => 'A meaningful picture, e.g., the specimen or a thumbnail'],
828
     'picture' => ['name' => 'Picture', 'desc' => 'A meaningful picture, e.g., the specimen or a thumbnail'],
823
 
829
 
824
     # From the non-renamed `torrents` table
830
     # From the non-renamed `torrents` table
825
-    'version' => ['name' => 'Version', 'desc' => 'Start with 0.1.0', 'note' => 'Please see <a href="https://semver.org target=" _blank">Semantic Versioning</a>'],
831
+    'version' => ['name' => 'Version', 'desc' => 'Start with 0.1.0', 'note' => 'Please see <a href="https://semver.org" target="_blank">Semantic Versioning</a>'],
832
+    'license' => ['name' => 'License', 'desc' => '', 'note' => 'Please see <a href="http://www.dcc.ac.uk/resources/how-guides/license-research-data" target="_blank">How to License Research Data</a>'],
833
+    'mirrors' => ['name' => 'Mirrors', 'desc' => 'Up to two FTP/HTTP addresses that either point directly to a file, or for multi-file torrents, to the enclosing folder'],
826
 ];
834
 ];
827
 ENV::setPub(
835
 ENV::setPub(
828
     'DB',
836
     'DB',
829
-    new RecursiveArrayObject($DB)
837
+    $ENV->convert($DB)
830
 );
838
 );
831
 
839
 
832
 
840
 
947
             'Binary',
955
             'Binary',
948
             'Text',
956
             'Text',
949
         ],
957
         ],
950
-    ], # End $this->META->Platforms
958
+    ], # End $ENV->META->Platforms
951
 
959
 
952
     /**
960
     /**
953
      * 1.
961
      * 1.
1172
             'Jupyter'      => ['ipynb'],
1180
             'Jupyter'      => ['ipynb'],
1173
             'Ontology'     => ['cgif', 'cl', 'clif', 'csv', 'htm', 'html', 'kif', 'obo', 'owl', 'rdf', 'rdfa', 'rdfs', 'rif', 'tsv', 'xcl', 'xht', 'xhtml', 'xml'],
1181
             'Ontology'     => ['cgif', 'cl', 'clif', 'csv', 'htm', 'html', 'kif', 'obo', 'owl', 'rdf', 'rdfa', 'rdfs', 'rif', 'tsv', 'xcl', 'xht', 'xhtml', 'xml'],
1174
         ],
1182
         ],
1175
-    ], # End $this->META->Formats
1183
+    ], # End $ENV->META->Formats
1176
 
1184
 
1177
 
1185
 
1178
     /**
1186
     /**
1268
             'Velocity',
1276
             'Velocity',
1269
             'Weight',
1277
             'Weight',
1270
         ],
1278
         ],
1271
-    ], # End $this->META->Scopes
1279
+    ], # End $ENV->META->Scopes
1272
 
1280
 
1273
     /**
1281
     /**
1274
      * 1.
1282
      * 1.
1294
         'OpenMTA',
1302
         'OpenMTA',
1295
         'Public Domain',
1303
         'Public Domain',
1296
         'Unspecified',
1304
         'Unspecified',
1297
-    ], # End $this->META->Licenses
1305
+    ], # End $ENV->META->Licenses
1298
 ];
1306
 ];
1299
 ENV::setPub(
1307
 ENV::setPub(
1300
     'META',
1308
     'META',
1301
-    new RecursiveArrayObject($META)
1309
+    $ENV->convert($META)
1302
 );
1310
 );
1303
 
1311
 
1304
 
1312
 
1322
         'Icon' => "$CatIcons/sequences.png",
1330
         'Icon' => "$CatIcons/sequences.png",
1323
         'Description' => "For data that's ACGT, ACGU, amino acid letters on disk.",
1331
         'Description' => "For data that's ACGT, ACGU, amino acid letters on disk.",
1324
         'Platforms' => $ENV->META->Platforms->Sequences,
1332
         'Platforms' => $ENV->META->Platforms->Sequences,
1325
-        'Formats' => [
1326
-            $ENV->META->Formats->Sequences,
1327
-            $ENV->META->Formats->Proteins,
1328
-            $ENV->META->Formats->Plain,
1333
+        'Formats' => array_merge([
1329
             /*
1334
             /*
1330
             'Sequences' => $ENV->META->Formats->Sequences,
1335
             'Sequences' => $ENV->META->Formats->Sequences,
1331
             'Proteins' => $ENV->META->Formats->Proteins,
1336
             'Proteins' => $ENV->META->Formats->Proteins,
1332
             'Plain' => $ENV->META->Formats->Plain,
1337
             'Plain' => $ENV->META->Formats->Plain,
1333
             */
1338
             */
1334
-        ],
1339
+            $ENV->META->Formats->Sequences,
1340
+            $ENV->META->Formats->Proteins,
1341
+            $ENV->META->Formats->Plain,
1342
+        ]),
1335
     ],
1343
     ],
1336
 
1344
 
1337
     2 => [
1345
     2 => [
1481
 ];
1489
 ];
1482
 ENV::setPub(
1490
 ENV::setPub(
1483
     'CATS',
1491
     'CATS',
1484
-    new RecursiveArrayObject($CATS)
1492
+    $ENV->convert($CATS)
1485
 );
1493
 );
1486
 
1494
 
1487
 
1495
 

+ 44
- 39
classes/env.class.php View File

43
     # Prevents multiple instances
43
     # Prevents multiple instances
44
     public function __clone()
44
     public function __clone()
45
     {
45
     {
46
-        return trigger_error(
47
-            'clone() not allowed',
48
-            E_USER_ERROR
49
-        );
46
+        return error('clone() not allowed.');
50
     }
47
     }
51
 
48
 
52
     # Prevents unserializing
49
     # Prevents unserializing
53
     public function __wakeup()
50
     public function __wakeup()
54
     {
51
     {
55
-        return trigger_error(
56
-            'wakeup() not allowed',
57
-            E_USER_ERROR
58
-        );
52
+        return error('wakeup() not allowed.');
59
     }
53
     }
60
 
54
 
61
     # $this->key returns public->key
55
     # $this->key returns public->key
112
     }
106
     }
113
 
107
 
114
 
108
 
109
+    /**
110
+     * convert
111
+     *
112
+     * Take a mixed input and returns a RecursiveArrayObject.
113
+     * This function is the sausage grinder, so to speak.
114
+     */
115
+    public function convert($obj)
116
+    {
117
+        switch (gettype($obj)) {
118
+            case 'string':
119
+                $out = json_decode($obj, true);
120
+                return (json_last_error() === JSON_ERROR_NONE)
121
+                    ? new RecursiveArrayObject($out)
122
+                    : error('json_last_error_msg(): ' . json_last_error_msg());
123
+                break;
124
+            
125
+            case 'array':
126
+            case 'object':
127
+                return new RecursiveArrayObject($obj);
128
+            
129
+            default:
130
+                return error('$ENV->convert() expects a JSON string, array, or object.');
131
+                break;
132
+        }
133
+    }
134
+
135
+
115
     /**
136
     /**
116
      * toArray
137
      * toArray
138
+     *
139
+     * Takes an object and returns an array.
117
      * @see https://ben.lobaugh.net/blog/567/php-recursively-convert-an-object-to-an-array
140
      * @see https://ben.lobaugh.net/blog/567/php-recursively-convert-an-object-to-an-array
118
      */
141
      */
119
-    public function toArray($obj)
142
+    public function toArray(object $obj)
120
     {
143
     {
121
         if (is_object($obj)) {
144
         if (is_object($obj)) {
122
             $obj = (array) $obj;
145
             $obj = (array) $obj;
135
     }
158
     }
136
 
159
 
137
 
160
 
138
-    /**
139
-     * fromJson
140
-     *
141
-     * @param string $JSON Valid JavaScript object string
142
-     * @return RecursiveArrayObject Not stdClass as in json_decode()
143
-     */
144
-
145
-    public function fromJson($str)
146
-    {
147
-        if (!is_string($str) || is_empty($str)) {
148
-            error('$ENV->fromJson() expects a string.');
149
-        }
150
-
151
-        $json = json_decode($str, true);
152
-        
153
-        if (json_last_error() === JSON_ERROR_NONE) {
154
-            # Decode to array and construct RAO
155
-            return new RecursiveArrayObject($json);
156
-        } else {
157
-            error('Unable to parse JSON in $ENV->fromJson().');
158
-        }
159
-    }
160
-
161
-
162
     /**
161
     /**
163
      * dedupe
162
      * dedupe
164
      *
163
      *
181
     /**
180
     /**
182
      * flatten
181
      * flatten
183
      *
182
      *
184
-     * Takes an $ENV node (Recursive ArrayObject)
183
+     * Takes an $ENV node or array of them
185
      * and flattens out the multi-dimensionality.
184
      * and flattens out the multi-dimensionality.
186
-     * Returns a single, non-deduplicated array.
185
+     * It returns a flat array with keys intact.
187
      */
186
      */
188
-    public function flatten($arr)
187
+    public function flatten($arr, int $lvl = null)
189
     {
188
     {
189
+        if (!is_array($arr) && !is_object($arr)) {
190
+            return error('$ENV->flatten() expects an array or object, got ' . gettype($arr));
191
+        }
192
+
190
         $new = array();
193
         $new = array();
191
 
194
 
192
         foreach ($arr as $k => $v) {
195
         foreach ($arr as $k => $v) {
193
-            if (is_object($v)) {
196
+            /*
197
+             if (is_object($v)) {
194
                 $v = $this->toArray($v);
198
                 $v = $this->toArray($v);
195
             }
199
             }
200
+            */
196
     
201
     
197
             if (is_array($v)) {
202
             if (is_array($v)) {
198
                 $new = array_merge($new, $this->flatten($v));
203
                 $new = array_merge($new, $this->flatten($v));
212
      * Maps a callback (or default) to an object.
217
      * Maps a callback (or default) to an object.
213
      *
218
      *
214
      * Example output:
219
      * Example output:
215
-     * $Hashes = $ENV->map('md5', $ENV->CATS->SEQ);
220
+     * $Hashes = $ENV->map('md5', $ENV->CATS->{6});
216
      *
221
      *
217
      * var_dump($Hashes);
222
      * var_dump($Hashes);
218
      * object(RecursiveArrayObject)#324 (1) {
223
      * object(RecursiveArrayObject)#324 (1) {
240
      * @param object $obj Object to operate on
245
      * @param object $obj Object to operate on
241
      * @return object $RAO Mapped RecursiveArrayObject
246
      * @return object $RAO Mapped RecursiveArrayObject
242
      */
247
      */
243
-    public function map($fn = '', $obj = null)
248
+    public function map(string $fn = '', object $obj = null)
244
     {
249
     {
245
         # Set a default function if desired
250
         # Set a default function if desired
246
         if (empty($fn) && !is_object($fn)) {
251
         if (empty($fn) && !is_object($fn)) {

+ 0
- 44
classes/input.class.php View File

1
-<?php
2
-declare(strict_types=1);
3
-
4
-/**
5
- * Input class
6
- * 
7
- * An attempt to normalize and secure form inputs.
8
- */
9
-
10
-class Input {
11
-
12
-    /**
13
-     * passphrase
14
-     */
15
-    function passphrase(
16
-        string $Name = 'password',
17
-        string $ID = 'password',
18
-        string $Placeholder = 'Passphrase',
19
-        bool $Advice = false) {
20
-        $ENV = ENV::go();
21
-
22
-        # Input validation
23
-        if (!is_string($Name) || empty($Name)) {
24
-            error("Expected non-empty string, got \$Name = $Name in Input::passphrase.");
25
-        }
26
-
27
-        if (!empty($Advice) && $Advice !== true || $Advice !== false) {
28
-            error("Expected true|false, got \$Advice = $Advice in Input::passphrase.");
29
-        }
30
-
31
-        $Field = <<<HTML
32
-        <input type="password" name="$Name" id="$ID" placeholder="$Placeholder"
33
-          minlength="$ENV->PW_MIN" maxlength="$ENV->PW_MAX"
34
-          class="inputtext" autocomplete="off" required="required" />
35
-HTML;
36
-
37
-if ($Advice) {
38
-    return $Field . $ENV->PW_ADVICE;
39
-} else {
40
-    return $Field;
41
-}
42
-
43
-    }
44
-}

+ 21
- 6
classes/security.class.php View File

39
     {
39
     {
40
         $ENV = ENV::go();
40
         $ENV = ENV::go();
41
 
41
 
42
+        # Bad PHP version
43
+        if (version_compare(PHP_VERSION, $ENV->PHP_MIN, '<')) {
44
+            error("Gazelle requires PHP > $ENV->PHP_MIN.");
45
+        }
46
+
42
         # short_open_tag
47
         # short_open_tag
43
         if (!ini_get('short_open_tag')) {
48
         if (!ini_get('short_open_tag')) {
44
-            error('short_open_tag != On in php.ini');
49
+            error('short_open_tag != On in php.ini.');
45
         }
50
         }
46
 
51
 
47
         # apcu
52
         # apcu
48
         if (!extension_loaded('apcu')) {
53
         if (!extension_loaded('apcu')) {
49
-            error('APCu extension not loaded');
54
+            error('APCu extension php-apcu not loaded.');
50
         }
55
         }
51
 
56
 
52
-        # Bad PHP version
53
-        if (version_compare($ENV->PHP_MIN, '7.4.0', '<')) {
54
-            error("Gazelle requires PHP > $ENV->PHP_MIN.");
57
+        # mbstring
58
+        if (!extension_loaded('mbstring')) {
59
+            error('Multibyte string extension php-mbstring not loaded.');
60
+        }
61
+
62
+        # memcache
63
+        if (!extension_loaded('memcache')) {
64
+            error('memcached extension php-memcache not loaded.');
65
+        }
66
+
67
+        # blake3
68
+        if ($ENV->FEATURE_SEQHASH && !extension_loaded('blake3')) {
69
+            error('Please install and enable the php-blake3 extension.');
55
         }
70
         }
56
 
71
 
57
         # Deal with dumbasses
72
         # Deal with dumbasses
58
-        if (isset($_REQUEST['info_hash']) && isset($_REQUEST['peer_id'])) {
73
+        if (isset($_REQUEST['info_hash']) || isset($_REQUEST['peer_id'])) {
59
             error(
74
             error(
60
                 'd14:failure reason40:Invalid .torrent, try downloading again.e',
75
                 'd14:failure reason40:Invalid .torrent, try downloading again.e',
61
                 $NoHTML = true,
76
                 $NoHTML = true,

+ 24
- 46
classes/torrent_form.class.php View File

444
         $Version = display_str($Torrent['Version']);
444
         $Version = display_str($Torrent['Version']);
445
 
445
 
446
         echo $Twig->render(
446
         echo $Twig->render(
447
-            'torrent_form/identifier.html',
447
+            'torrent_form/version.html',
448
             [
448
             [
449
               'db' => $ENV->DB->version,
449
               'db' => $ENV->DB->version,
450
               'version' => $Version,
450
               'version' => $Version,
583
             'torrent_form/year.html',
583
             'torrent_form/year.html',
584
             [
584
             [
585
             'db' => $ENV->DB->year,
585
             'db' => $ENV->DB->year,
586
-            'location' => $TorrentYear,
586
+            'year' => $TorrentYear,
587
           ]
587
           ]
588
         );
588
         );
589
 
589
 
699
                 $trID = 'media_tr',
699
                 $trID = 'media_tr',
700
                 $Label = 'Platform',
700
                 $Label = 'Platform',
701
                 $Torrent = $Torrent,
701
                 $Torrent = $Torrent,
702
-                $Media = $ENV->META->Platforms->Sequences
702
+                $Media = $ENV->CATS->{1}->Platforms
703
             );
703
             );
704
             
704
             
705
 
705
 
710
                 $trID = 'media_graphs_tr',
710
                 $trID = 'media_graphs_tr',
711
                 $Label = 'Platform',
711
                 $Label = 'Platform',
712
                 $Torrent = $Torrent,
712
                 $Torrent = $Torrent,
713
-                $Media = $ENV->flatten([
714
-                    $ENV->META->Platforms->Graphs,
715
-                    $ENV->META->Platforms->Sequences
716
-                ])
713
+                $Media = $ENV->CATS->{2}->Platforms
717
             );
714
             );
718
             
715
             
719
 
716
 
724
                 $trID = 'media_scalars_vectors_tr',
721
                 $trID = 'media_scalars_vectors_tr',
725
                 $Label = 'Platform',
722
                 $Label = 'Platform',
726
                 $Torrent = $Torrent,
723
                 $Torrent = $Torrent,
727
-                $Media = $ENV->flatten([
728
-                    $ENV->META->Platforms->Graphs,
729
-                    $ENV->META->Platforms->Images
730
-                ])
724
+                $Media = $ENV->CATS->{5}->Platforms
731
             );
725
             );
732
 
726
 
733
 
727
 
738
                 $trID = 'media_images_tr',
732
                 $trID = 'media_images_tr',
739
                 $Label = 'Platform',
733
                 $Label = 'Platform',
740
                 $Torrent = $Torrent,
734
                 $Torrent = $Torrent,
741
-                $Media = $ENV->META->Platforms->Images
735
+                $Media = $ENV->CATS->{8}->Platforms
742
             );
736
             );
743
 
737
 
744
 
738
 
749
                 $trID = 'media_documents_tr',
743
                 $trID = 'media_documents_tr',
750
                 $Label = 'Platform',
744
                 $Label = 'Platform',
751
                 $Torrent = $Torrent,
745
                 $Torrent = $Torrent,
752
-                $Media = $ENV->META->Platforms->Documents
746
+                $Media = $ENV->CATS->{11}->Platforms
753
             );
747
             );
754
 
748
 
755
 
749
 
760
                 $trID = 'media_machine_data_tr',
754
                 $trID = 'media_machine_data_tr',
761
                 $Label = 'Platform',
755
                 $Label = 'Platform',
762
                 $Torrent = $Torrent,
756
                 $Torrent = $Torrent,
763
-                $Media = $ENV->META->Platforms->Raw
757
+                $Media = $ENV->CATS->{12}->Platforms
764
             );
758
             );
765
         } # fi NewTorrent
759
         } # fi NewTorrent
766
         else {
760
         else {
826
             $trID = 'container_tr',
820
             $trID = 'container_tr',
827
             $Label = 'Format',
821
             $Label = 'Format',
828
             $Torrent = $Torrent,
822
             $Torrent = $Torrent,
829
-            $FileTypes = array_merge(($ENV->CATS->{1}->Formats))
823
+            $FileTypes = $ENV->CATS->{1}->Formats
830
         );
824
         );
831
         
825
         
832
 
826
 
837
             $trID = 'container_graphs_tr',
831
             $trID = 'container_graphs_tr',
838
             $Label = 'Format',
832
             $Label = 'Format',
839
             $Torrent = $Torrent,
833
             $Torrent = $Torrent,
840
-            $FileTypes = array_merge($this->GraphXmlFormats, $this->GraphTxtFormats, $this->SeqFormats, $this->ProtFormats, $this->PlainFormats)
834
+            #$FileTypes = array_column($ENV->META, $Formats)
841
         );
835
         );
842
 
836
 
843
 
837
 
1030
             $TorrentImage = display_str($Torrent['Image']);
1024
             $TorrentImage = display_str($Torrent['Image']);
1031
             $Disabled = $this->Disabled;
1025
             $Disabled = $this->Disabled;
1032
 
1026
 
1033
-            echo <<<HTML
1034
-            <tr id="cover_tr">
1035
-            <td>
1036
-              <label for="image">
1037
-                Picture
1038
-              </label>
1039
-            </td>
1040
-            
1041
-            <td>
1042
-              <input type="text" id="image" name="image" size="60"
1043
-                placeholder="A meaningful picture, e.g., the specimen or a thumbnail"
1044
-                value="$TorrentImage" $Disabled? />
1045
-            </td>
1046
-          </tr>
1047
-HTML;
1027
+            echo $Twig->render(
1028
+                'torrent_form/picture.html',
1029
+                [
1030
+                    'db' => $ENV->DB->picture,
1031
+                    'picture' => $TorrentImage,
1032
+                ]
1033
+            );
1048
         }
1034
         }
1049
 
1035
 
1050
 
1036
 
1056
          */
1042
          */
1057
         if (!$this->DisabledFlag && $this->NewTorrent) {
1043
         if (!$this->DisabledFlag && $this->NewTorrent) {
1058
             $TorrentMirrors = display_str($Torrent['Mirrors']);
1044
             $TorrentMirrors = display_str($Torrent['Mirrors']);
1059
-            echo <<<HTML
1060
-            <tr id="mirrors_tr">
1061
-              <td>
1062
-                <label for="mirrors">
1063
-                  Mirrors
1064
-                </label>
1065
-              </td>
1066
-              
1067
-              <td>
1068
-                <!-- Needs to be all on one line -->
1069
-                <textarea rows="2" name="mirrors" id="mirrors"
1070
-                  placeholder="Up to two FTP/HTTP addresses that either point directly to a file, or for multi-file torrents, to the enclosing folder">$TorrentMirrors</textarea>
1071
-              </td>
1072
-            </tr>
1073
-HTML;
1045
+            echo $Twig->render(
1046
+                'torrent_form/mirrors.html',
1047
+                [
1048
+                  'db' => $ENV->DB->mirrors,
1049
+                  'mirrors' => $TorrentMirrors,
1050
+              ]
1051
+            );
1074
         }
1052
         }
1075
 
1053
 
1076
 
1054
 

+ 5
- 2
classes/twig.class.php View File

60
     private static function factory(): \Twig\Environment
60
     private static function factory(): \Twig\Environment
61
     {
61
     {
62
         $ENV = ENV::go();
62
         $ENV = ENV::go();
63
+
64
+        # https://twig.symfony.com/doc/3.x/api.html
63
         $Twig = new \Twig\Environment(
65
         $Twig = new \Twig\Environment(
64
             new \Twig\Loader\FilesystemLoader("$ENV->SERVER_ROOT/templates"),
66
             new \Twig\Loader\FilesystemLoader("$ENV->SERVER_ROOT/templates"),
65
             [
67
             [
66
                 'auto_reload' => true,
68
                 'auto_reload' => true,
67
-                'autoescape' => 'html',
68
-                'cache' => "$ENV->WEB_ROOT/cache/twig"
69
+                'autoescape' => 'name',
70
+                'cache' => "$ENV->WEB_ROOT/cache/twig",
69
                 #'debug' => DEBUG_MODE,
71
                 #'debug' => DEBUG_MODE,
72
+                'strict_variables' => true,
70
         ]
73
         ]
71
         );
74
         );
72
 
75
 

+ 39
- 20
readme.md View File

1
 # BioTorrents.de Gazelle
1
 # BioTorrents.de Gazelle
2
 
2
 
3
 This software is twice removed from the original
3
 This software is twice removed from the original
4
-[What.cd Gazelle](https://github.com/WhatCD/Gazelle):
5
-it's based on the security hardened PHP7 fork
4
+[What.cd Gazelle](https://github.com/WhatCD/Gazelle).
5
+It's based on the security hardened PHP7 fork
6
 [Oppaitime Gazelle](https://git.oppaiti.me/Oppaitime/Gazelle).
6
 [Oppaitime Gazelle](https://git.oppaiti.me/Oppaitime/Gazelle).
7
+It shares several features with
8
+[Orpheus Gazelle](https://github.com/OPSnet/Gazelle).
7
 The goal is to organize a functional database with pleasant interfaces,
9
 The goal is to organize a functional database with pleasant interfaces,
8
 and render insightful views using data from robust external sources.
10
 and render insightful views using data from robust external sources.
9
 
11
 
23
 with the appropriate bold/italic glyphs and monospace.
25
 with the appropriate bold/italic glyphs and monospace.
24
 These options are available to every theme.
26
 These options are available to every theme.
25
 Font Awesome 5 is also universally available.
27
 Font Awesome 5 is also universally available.
28
+[Download the fonts](https://docs.biotorrents.de/dl/fonts.tgz).
26
 
29
 
27
 ## Markdown support
30
 ## Markdown support
28
 
31
 
36
 ## $ENV recursive singleton
39
 ## $ENV recursive singleton
37
 
40
 
38
 [The site configuration](classes/config.template.php)
41
 [The site configuration](classes/config.template.php)
39
-is being migrated to a format govered by
40
-[the ENV special class](classes/env.class.php)
41
-for modified ArrayObjects.
42
-This is useful for several reasons:
43
-
44
-- prevents multiple configs loaded in memory;
45
-- ensures the config's immutability;
46
-- doesn't pollute the constants table;
47
-- allows public (echoed) and private (accessed) values;
48
-- supports large, nested static metadata structures;
49
-- able to scope access to the function level;
50
-- easy to extend ENV with new class methods;
51
-- good interoperability potential with JSON; and
52
-- native PHP ArrayObject support with Array compatibility.
42
+is being migrated to a format govered by the
43
+[ENV special class](classes/env.class.php)
44
+for modified recursive ArrayObjects.
53
 
45
 
54
 ## Twig template system
46
 ## Twig template system
55
 
47
 
56
-Similar to ENV,
57
-[the Twig interface](classes/twig.class.php)
48
+Similar to ENV, the
49
+[Twig interface](classes/twig.class.php)
58
 operates as a singleton because it's an external module with its own cache.
50
 operates as a singleton because it's an external module with its own cache.
59
 Twig provides a security benefit by escaping rendered output,
51
 Twig provides a security benefit by escaping rendered output,
60
 and a secondary benefit of clarifying the PHP running the site sections.
52
 and a secondary benefit of clarifying the PHP running the site sections.
61
-Several custom filters are available from
62
-[Orpheus Gazelle](https://github.com/OPSnet/Gazelle).
53
+Several custom filters are available from OPS.
54
+
55
+## Active data minimization
56
+
57
+BioTorrents.de has
58
+[real lawyer-vetted policies](templates/legal).
59
+In the process of matching the tech to the legal word,
60
+we dropped support for a number of compromising features:
61
+
62
+- Bitcoin, PayPal, and currency exchange API and system calls;
63
+- Bitcoin addresses, user donation history, and similar metadata; and
64
+- IP address and geolocation, email address, passphrase, and passkey history.
65
+
66
+Besides that, BioTorrents has several passive developments in progress:
67
+
68
+- prepare all queries with parameterized statements;
69
+- declare strict mode at the top of every PHP and JS file;
70
+- check strict equality and strong typing, including function arguments;
71
+- run all files through generic formatters such as PHP-CS-Fixer; and
72
+- move all external libraries to uncomplicated package management.
73
+
74
+## Minor changes
75
+
76
+- Database crypto bumped up to AES-256
77
+- Good subresource integrity support
78
+- Configurable HTTP status code errors
79
+- Integrated diceware passphrase generator
80
+- TLS database connections
81
+- Semantic HTML5 themes (WIP)
63
 
82
 
64
 # Changelog: WCD → OT
83
 # Changelog: WCD → OT
65
 
84
 

+ 14
- 3
sections/login/login.php View File

1
 <?php
1
 <?php
2
 declare(strict_types=1);
2
 declare(strict_types=1);
3
 
3
 
4
+$ENV = ENV::go();
5
+$Twig = Twig::go();
6
+
4
 View::show_header('Login'); ?>
7
 View::show_header('Login'); ?>
5
 
8
 
6
 <p class="center mouseless">
9
 <p class="center mouseless">
47
 
50
 
48
     <tr>
51
     <tr>
49
       <td>
52
       <td>
50
-        <?= Input::passphrase() ?>
53
+        <?=
54
+        $Twig->render('input/passphrase.html', [
55
+          'name' => 'password',
56
+          'id' => 'password',
57
+          'placeholder' => 'Passphrase',
58
+          'pw_min' => $ENV->PW_MIN,
59
+          'pw_max' => $ENV->PW_MAX,
60
+          'advice' => false,
61
+        ]) ?>
51
       </td>
62
       </td>
52
 
63
 
53
       <td>
64
       <td>
76
 
87
 
77
 if ($Attempts > 0) { ?>
88
 if ($Attempts > 0) { ?>
78
 <p class="center">
89
 <p class="center">
79
-  Forgot your password?
80
-  <a href="login.php?act=recover" class="tooltip" title="Recover your password">Reset it here!</a>
90
+  Forgot your passphrase?
91
+  <a href="login.php?act=recover" class="tooltip" title="Recover your passphrase">Reset it here!</a>
81
 </p>
92
 </p>
82
 
93
 
83
 <?php
94
 <?php

+ 14
- 11
sections/login/recover_step2.php View File

2
 declare(strict_types=1);
2
 declare(strict_types=1);
3
 
3
 
4
 $ENV = ENV::go();
4
 $ENV = ENV::go();
5
-View::show_header('Recover Password', 'validate,password_validate');
5
+$Twig = Twig::go();
6
 
6
 
7
+View::show_header('Recover Password', 'validate,password_validate');
7
 echo '<h2>Reset your password</h2>';
8
 echo '<h2>Reset your password</h2>';
8
 
9
 
9
 if (empty($PassWasReset)) {
10
 if (empty($PassWasReset)) {
22
       </td>
23
       </td>
23
 
24
 
24
       <td>
25
       <td>
25
-        <?= Input::passphrase($Name = 'password', $ID='new_pass_1', $Placeholder = 'New passphrase') ?>
26
-        <!--
27
-        <input type="password" minlength="15" name="password" id="new_pass_1" class="inputtext" size="40"
28
-          placeholder="New Password" pattern=".{15,307200}" required style="width: 250px !important;">
29
-        -->
26
+        <?=
27
+        $Twig->render('input/passphrase.html', [
28
+          'name' => 'password',
29
+          'id' => 'new_pass_1',
30
+          'placeholder' => 'New passphrase'
31
+        ]) ?>
30
       </td>
32
       </td>
31
     </tr>
33
     </tr>
32
 
34
 
35
         <strong id="pass_match"></strong>
37
         <strong id="pass_match"></strong>
36
       </td>
38
       </td>
37
       <td>
39
       <td>
38
-        <?= Input::passphrase($Name = 'verifypassword', $ID='new_pass_2', $Placeholder = 'Confirm passphrase') ?>
39
-        <!--
40
-        <input type="password" minlength="15" name="verifypassword" id="new_pass_2" class="inputtext" size="40"
41
-          placeholder="Confirm Password" pattern=".{15,307200}" required style="width: 250px !important;">
42
-        -->
40
+      <?=
41
+        $Twig->render('input/passphrase.html', [
42
+          'name' => 'verifypassword',
43
+          'id' => 'new_pass_2',
44
+          'placeholder' => 'Confirm passphrase'
45
+        ]) ?>
43
       </td>
46
       </td>
44
     </tr>
47
     </tr>
45
 
48
 

+ 24
- 0
templates/input/passphrase.html View File

1
+<input
2
+  type="password"
3
+  name="{{ name|default('password') }}"
4
+  id="{{ id|default('password') }}"
5
+  placeholder="{{ placeholder|default('passphrase') }}"
6
+  minlength="{{ pw_min|default('15') }}"
7
+  maxlength="{{ pw_max|default('10000') }}"
8
+  pattern=".{ {{ pw_min }},{{ pw_max }} }"
9
+  class="inputtext"
10
+  autocomplete="off"
11
+  required="required"
12
+/>
13
+
14
+<strong id="pass_match"></strong>
15
+
16
+{% if advice == true %}
17
+<p>
18
+  Any password {{ pw_min }} characters or longer is accepted, but a strong password
19
+  <ul>
20
+    <li>is a pass<em>phrase</em> of mixed case with many small words,</li>
21
+    <li>that contains complex characters including Unicode and emoji.</li>
22
+  </ul>
23
+</p>
24
+{% endif %}

+ 14
- 0
templates/torrent_form/mirrors.html View File

1
+<tr id="mirrors_tr">
2
+  <td>
3
+    <label for="mirrors">{{ db.name }}</label>
4
+  </td>
5
+
6
+  <td>
7
+    <textarea
8
+      rows="2"
9
+      name="mirrors"
10
+      id="mirrors"
11
+      {# Needs to be all on one line #}
12
+      placeholder="{{ db.desc }}">{{ mirrors }}</textarea>
13
+  </td>
14
+</tr>

+ 16
- 0
templates/torrent_form/picture.html View File

1
+<tr id="cover_tr">
2
+  <td>
3
+    <label for="image">{{db.name }}</label>
4
+  </td>
5
+
6
+  <td>
7
+    <input
8
+      type="text"
9
+      id="image"
10
+      name="image"
11
+      size="60"
12
+      placeholder="{{ db.desc }}"
13
+      value="{{ picture }}"
14
+    />
15
+  </td>
16
+</tr>

+ 2
- 2
templates/torrent_form/version.html View File

10
       name="version"
10
       name="version"
11
       size="12"
11
       size="12"
12
       pattern="\d+\.*\d*\.*\d*"
12
       pattern="\d+\.*\d*\.*\d*"
13
-      placeholder="{{ db.desc}}"
13
+      placeholder="{{ db.desc }}"
14
       value="{{ version }}"
14
       value="{{ version }}"
15
     />
15
     />
16
 
16
 
17
-    <p>{{ note }}</p>
17
+    <p>{{ db.note|raw }}</p>
18
   </td>
18
   </td>
19
 </tr>
19
 </tr>

Loading…
Cancel
Save