Subversion Repositories oidplus

Rev

Rev 926 | Rev 1006 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 daniel-mar 1
<?php
2
 
3
/*
4
 * OIDplus 2.0
773 daniel-mar 5
 * Copyright 2019 - 2022 Daniel Marschall, ViaThinkSoft
2 daniel-mar 6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
 
830 daniel-mar 20
function is_privatekey_encrypted($privKey) {
21
        return strpos($privKey,'BEGIN ENCRYPTED PRIVATE KEY') !== false;
22
}
23
 
74 daniel-mar 24
function verify_private_public_key($privKey, $pubKey) {
721 daniel-mar 25
        if (!function_exists('openssl_public_encrypt')) return false;
74 daniel-mar 26
        try {
27
                if (empty($privKey)) return false;
28
                if (empty($pubKey)) return false;
453 daniel-mar 29
                $data = generateRandomString(25);
386 daniel-mar 30
                $encrypted = '';
31
                $decrypted = '';
74 daniel-mar 32
                if (!@openssl_public_encrypt($data, $encrypted, $pubKey)) return false;
33
                if (!@openssl_private_decrypt($encrypted, $decrypted, $privKey)) return false;
34
                return $decrypted == $data;
35
        } catch (Exception $e) {
36
                return false;
37
        }
38
}
39
 
830 daniel-mar 40
function change_private_key_passphrase($privKeyOld, $passphrase_old, $passphrase_new) {
41
        $pkey_config = array(
42
            //"digest_alg" => "sha512",
43
            //"private_key_bits" => 2048,
44
            //"private_key_type" => OPENSSL_KEYTYPE_RSA,
45
            "config" => class_exists("OIDplus") ? OIDplus::getOpenSslCnf() : @getenv('OPENSSL_CONF')
46
        );
47
        $privKeyNew = @openssl_pkey_get_private($privKeyOld, $passphrase_old);
48
        if ($privKeyNew === false) return false;
49
        @openssl_pkey_export($privKeyNew, $privKeyNewExport, $passphrase_new, $pkey_config);
50
        if ($privKeyNewExport === false) return false;
51
        return $privKeyNewExport."";
52
}
53
 
54
function decrypt_private_key($privKey, $passphrase) {
55
        return change_private_key_passphrase($privKey, $passphrase, null);
56
}
57
 
58
function encrypt_private_key($privKey, $passphrase) {
59
        return change_private_key_passphrase($privKey, null, $passphrase);
60
}
61
 
74 daniel-mar 62
function smallhash($data) { // get 31 bits from SHA1. Values 0..2147483647
250 daniel-mar 63
        return (hexdec(substr(sha1($data),-4*2)) & 0x7FFFFFFF);
74 daniel-mar 64
}
180 daniel-mar 65
 
182 daniel-mar 66
function split_firstname_lastname($name) {
67
        $ary = explode(' ', $name);
68
        $last_name = array_pop($ary);
69
        $first_name = implode(' ', $ary);
70
        return array($first_name, $last_name);
71
}
72
 
180 daniel-mar 73
function originHeaders() {
74
        // CORS
75
        // Author: Till Wehowski
426 daniel-mar 76
        // TODO: add to class OIDplus
182 daniel-mar 77
 
180 daniel-mar 78
        header("Access-Control-Allow-Credentials: true");
79
        header("Access-Control-Allow-Origin: ".strip_tags(((isset($_SERVER['HTTP_ORIGIN'])) ? $_SERVER['HTTP_ORIGIN'] : "*")));
80
 
81
        header("Access-Control-Allow-Headers: If-None-Match, X-Requested-With, Origin, X-Frdlweb-Bugs, Etag, X-Forgery-Protection-Token, X-CSRF-Token");
82
 
83
        if (isset($_SERVER['HTTP_ORIGIN'])) {
84
                header('X-Frame-Options: ALLOW-FROM '.$_SERVER['HTTP_ORIGIN']);
85
        } else {
86
                header_remove("X-Frame-Options");
87
        }
88
 
89
        $expose = array('Etag', 'X-CSRF-Token');
90
        foreach (headers_list() as $num => $header) {
91
                $h = explode(':', $header);
92
                $expose[] = trim($h[0]);
93
        }
94
        header("Access-Control-Expose-Headers: ".implode(',',$expose));
95
 
96
        header("Vary: Origin");
97
}
236 daniel-mar 98
 
346 daniel-mar 99
if (!function_exists('mb_wordwrap')) {
100
        function mb_wordwrap($str, $width = 75, $break = "\n", $cut = false) {
101
                // https://stackoverflow.com/a/4988494/488539
102
                $lines = explode($break, $str);
103
                foreach ($lines as &$line) {
104
                        $line = rtrim($line);
105
                        if (mb_strlen($line) <= $width) {
106
                                continue;
107
                        }
108
                        $words = explode(' ', $line);
109
                        $line = '';
110
                        $actual = '';
111
                        foreach ($words as $word) {
112
                                if (mb_strlen($actual.$word) <= $width) {
113
                                        $actual .= $word.' ';
114
                                } else {
115
                                        if ($actual != '') {
116
                                                $line .= rtrim($actual).$break;
117
                                        }
118
                                        $actual = $word;
119
                                        if ($cut) {
120
                                                while (mb_strlen($actual) > $width) {
121
                                                        $line .= mb_substr($actual, 0, $width).$break;
122
                                                        $actual = mb_substr($actual, $width);
123
                                                }
124
                                        }
125
                                        $actual .= ' ';
126
                                }
127
                        }
128
                        $line .= trim($actual);
129
                }
130
                return implode($break, $lines);
131
        }
132
}
355 daniel-mar 133
 
379 daniel-mar 134
function httpOutWithETag($out, $contentType, $filename='') {
135
        $etag = md5($out);
136
        header("Etag: $etag");
137
        header("Content-MD5: $etag"); // RFC 2616 clause 14.15
138
        if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && (trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag)) {
849 daniel-mar 139
                http_response_code(304); // 304 Not Modified
379 daniel-mar 140
        } else {
141
                header("Content-Type: $contentType");
142
                if (!empty($filename)) {
143
                        header('Content-Disposition:inline; filename="'.$filename.'"');
144
                }
145
                echo $out;
146
        }
147
        die();
148
}
149
 
360 daniel-mar 150
function my_vsprintf($str, $args) {
151
        $n = 1;
152
        foreach ($args as $val) {
153
                $str = str_replace("%$n", $val, $str);
154
                $n++;
155
        }
370 daniel-mar 156
        $str = str_replace("%%", "%", $str);
360 daniel-mar 157
        return $str;
158
}
159
 
355 daniel-mar 160
function _L($str, ...$sprintfArgs) {
401 daniel-mar 161
        static $translation_array = array();
162
        static $translation_loaded = null;
163
 
506 daniel-mar 164
        $str = trim($str);
165
 
438 daniel-mar 166
        if (!class_exists('OIDplus')) {
167
                return my_vsprintf($str, $sprintfArgs);
168
        }
169
 
360 daniel-mar 170
        $lang = OIDplus::getCurrentLang();
468 daniel-mar 171
        $ta = OIDplus::getTranslationArray($lang);
172
        $res = (isset($ta[$lang]) && isset($ta[$lang][$str])) ? $ta[$lang][$str] : $str;
360 daniel-mar 173
 
174
        $res = str_replace('###', OIDplus::baseConfig()->getValue('TABLENAME_PREFIX', ''), $res);
175
 
176
        $res = my_vsprintf($res, $sprintfArgs);
177
 
178
        return $res;
370 daniel-mar 179
}
386 daniel-mar 180
 
552 daniel-mar 181
function _CheckParamExists($params, $key) {
698 daniel-mar 182
        if (class_exists('OIDplusException')) {
183
                if (!isset($params[$key])) throw new OIDplusException(_L('Parameter %1 is missing', $key));
184
        } else {
185
                if (!isset($params[$key])) throw new Exception(_L('Parameter %1 is missing', $key));
186
        }
552 daniel-mar 187
}
188
 
721 daniel-mar 189
function extractHtmlContents($cont) {
190
        // make sure the program works even if the user provided HTML is not UTF-8
191
        $cont = convert_to_utf8_no_bom($cont);
192
 
386 daniel-mar 193
        $out_js = '';
194
        $m = array();
195
        preg_match_all('@<script[^>]*>(.+)</script>@ismU', $cont, $m);
196
        foreach ($m[1] as $x) {
197
                $out_js = $x . "\n\n";
198
        }
199
 
200
        $out_css = '';
201
        $m = array();
202
        preg_match_all('@<style[^>]*>(.+)</style>@ismU', $cont, $m);
203
        foreach ($m[1] as $x) {
204
                $out_css = $x . "\n\n";
205
        }
206
 
207
        $out_html = $cont;
208
        $out_html = preg_replace('@^(.+)<body[^>]*>@isU', '', $out_html);
209
        $out_html = preg_replace('@</body>.+$@isU', '', $out_html);
210
        $out_html = preg_replace('@<title>.+</title>@isU', '', $out_html);
211
        $out_html = preg_replace('@<h1>.+</h1>@isU', '', $out_html, 1);
212
        $out_html = preg_replace('@<script[^>]*>(.+)</script>@ismU', '', $out_html);
213
        $out_html = preg_replace('@<style[^>]*>(.+)</style>@ismU', '', $out_html);
214
 
215
        return array($out_html, $out_js, $out_css);
392 daniel-mar 216
}
217
 
400 daniel-mar 218
function sha3_512($password, $raw_output=false) {
392 daniel-mar 219
        if (version_compare(PHP_VERSION, '7.1.0') >= 0) {
400 daniel-mar 220
                return hash('sha3-512', $password, $raw_output);
392 daniel-mar 221
        } else {
400 daniel-mar 222
                return bb\Sha3\Sha3::hash($password, 512, $raw_output);
392 daniel-mar 223
        }
224
}
486 daniel-mar 225
 
710 daniel-mar 226
function sha3_512_hmac($message, $key, $raw_output=false) {
227
        // RFC 2104 HMAC
847 daniel-mar 228
        if (version_compare(PHP_VERSION, '7.1.0') >= 0) {
229
                return hash_hmac('sha3-512', $message, $key, $raw_output);
230
        } else {
710 daniel-mar 231
                $blocksize = 576; // block size of sha-512!
232
 
233
                if (strlen($key) > ($blocksize/8)) {
234
                        $k_ = sha3_512($key,true);
235
                } else {
236
                        $k_ = $key;
237
                }
238
 
239
                $k_opad = str_repeat(chr(0x5C),($blocksize/8));
240
                $k_ipad = str_repeat(chr(0x36),($blocksize/8));
241
                for ($i=0; $i<strlen($k_); $i++) {
242
                        $k_opad[$i] = $k_opad[$i] ^ $k_[$i];
243
                        $k_ipad[$i] = $k_ipad[$i] ^ $k_[$i];
244
                }
245
 
847 daniel-mar 246
                return sha3_512($k_opad . sha3_512($k_ipad . $message, true), $raw_output);
247
        }
710 daniel-mar 248
}
249
 
625 daniel-mar 250
if (!function_exists('str_ends_with')) {
251
        // PHP 7.x compatibility
252
        function str_ends_with($haystack, $needle) {
253
                $length = strlen($needle);
254
                return $length > 0 ? substr($haystack, -$length) === $needle : true;
255
        }
256
}
257
 
258
if (!function_exists('str_starts_with')) {
259
        // PHP 7.x compatibility
260
        function str_starts_with($haystack, $needle) {
261
                return strpos($haystack, $needle) === 0;
262
        }
263
}
264
 
963 daniel-mar 265
function url_get_contents($url, $userAgent='ViaThinkSoft-OIDplus/2.0') {
653 daniel-mar 266
        if (function_exists('curl_init')) {
267
                $ch = curl_init();
698 daniel-mar 268
                if (class_exists('OIDplus')) {
269
                        if (ini_get('curl.cainfo') == '') curl_setopt($ch, CURLOPT_CAINFO, OIDplus::localpath() . 'vendor/cacert.pem');
270
                }
653 daniel-mar 271
                curl_setopt($ch, CURLOPT_URL, $url);
963 daniel-mar 272
                curl_setopt($ch, CURLOPT_USERAGENT, $userAgent);
653 daniel-mar 273
                curl_setopt($ch, CURLOPT_POST, 0);
274
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
275
                curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
276
                curl_setopt($ch, CURLOPT_AUTOREFERER, true);
277
                if (!($res = @curl_exec($ch))) return false;
963 daniel-mar 278
                $error_code = @curl_getinfo($ch, CURLINFO_HTTP_CODE);
279
                if ($error_code >= 400) return false;
807 daniel-mar 280
                @curl_close($ch);
653 daniel-mar 281
        } else {
963 daniel-mar 282
                // Attention: HTTPS only works if OpenSSL extension is enabled.
283
                // Our supplement does not help...
716 daniel-mar 284
                $opts = [
285
                        "http" => [
286
                                "method" => "GET",
963 daniel-mar 287
                                "header" => "User-Agent: $userAgent\r\n"
716 daniel-mar 288
                        ]
289
                ];
290
                $context = stream_context_create($opts);
291
                $res = @file_get_contents($url, false, $context);
653 daniel-mar 292
                if ($res === false) return false;
293
        }
294
        return $res;
660 daniel-mar 295
}
778 daniel-mar 296
 
297
function getSortedQuery() {
298
        // https://stackoverflow.com/a/51777249/488539
299
        $url = [];
300
        parse_str($_SERVER['QUERY_STRING'], $url);
301
        ksort($url);
302
        return http_build_query($url);
303
}