1
0

Bootstrap.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. <?php
  2. use PrivateBin\Persistence\ServerSalt;
  3. use Eris\Generator;
  4. error_reporting(E_ALL | E_STRICT);
  5. // change this, if your php files and data is outside of your webservers document root
  6. if (!defined('PUBLIC_PATH')) {
  7. define('PUBLIC_PATH', '..');
  8. }
  9. if (!defined('PATH')) {
  10. define('PATH', '..' . DIRECTORY_SEPARATOR);
  11. }
  12. if (!defined('CONF')) {
  13. define('CONF', PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini');
  14. }
  15. if (!is_file(CONF)) {
  16. copy(CONF . '.sample', CONF);
  17. }
  18. require PATH . 'vendor/autoload.php';
  19. Helper::updateSubresourceIntegrity();
  20. class Helper
  21. {
  22. /**
  23. * example ID of a paste
  24. *
  25. * @var string
  26. */
  27. private static $pasteid = '5e9bc25c89fb3bf9';
  28. /**
  29. * example paste
  30. *
  31. * @var array
  32. */
  33. private static $paste = array(
  34. 'data' => '{"iv":"EN39/wd5Nk8HAiSG2K5AsQ","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"QKN1DBXe5PI","ct":"8hA83xDdXjD7K2qfmw5NdA"}',
  35. 'attachment' => '{"iv":"Pd4pOKWkmDTT9uPwVwd5Ag","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"ZIUhFTliVz4","ct":"6nOCU3peNDclDDpFtJEBKA"}',
  36. 'attachmentname' => '{"iv":"76MkAtOGC4oFogX/aSMxRA","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"ZIUhFTliVz4","ct":"b6Ae/U1xJdsX/+lATud4sQ"}',
  37. 'meta' => array(
  38. 'formatter' => 'plaintext',
  39. 'postdate' => 1344803344,
  40. 'opendiscussion' => true,
  41. ),
  42. );
  43. /**
  44. * example ID of a comment
  45. *
  46. * @var string
  47. */
  48. private static $commentid = '5a52eebf11c4c94b';
  49. /**
  50. * example comment
  51. *
  52. * @var array
  53. */
  54. private static $comment = array(
  55. 'data' => '{"iv":"Pd4pOKWkmDTT9uPwVwd5Ag","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"ZIUhFTliVz4","ct":"6nOCU3peNDclDDpFtJEBKA"}',
  56. 'meta' => array(
  57. 'nickname' => '{"iv":"76MkAtOGC4oFogX/aSMxRA","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"ZIUhFTliVz4","ct":"b6Ae/U1xJdsX/+lATud4sQ"}',
  58. 'vizhash' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGUlEQVQokWOsl5/94983CNKQMjnxaOePf98MeKwPfNjkLZ3AgARab6b9+PeNEVnDj3/ff/z7ZiHnzsDA8Pv7H2TVPJw8EAYLAwb48OaVgIgYKycLsrYv378wMDB8//qdCVMDRA9EKSsnCwRBxNsepaLboMFlyMDAICAi9uHNK24GITQ/MDAwoNhgIGMLtwGrzegaLjw5jMz9+vUdnN17uwDCQDhJgk0O07yvX9+teDX1x79v6DYIsIjgcgMaYGFgYOBg4kJx2JejkAiBxAw+PzAwMNz4dp6wDXDw4MdNNOl0rWYsNkD89OLXI/xmo9sgzatJjAYmBgYGDiauD3/ePP18nVgb4MF89+M5ZX6js293wUMpnr8KTQMAxsCJnJ30apMAAAAASUVORK5CYII=',
  59. 'postdate' => 1344803528,
  60. ),
  61. );
  62. /**
  63. * JS files and their SRI hashes
  64. *
  65. * @var array
  66. */
  67. private static $hashes = array();
  68. /**
  69. * get example paste ID
  70. *
  71. * @return string
  72. */
  73. public static function getPasteId()
  74. {
  75. return self::$pasteid;
  76. }
  77. /**
  78. * get example paste
  79. *
  80. * @return array
  81. */
  82. public static function getPaste($meta = array())
  83. {
  84. $example = self::getPasteWithAttachment($meta);
  85. unset($example['attachment'], $example['attachmentname']);
  86. return $example;
  87. }
  88. /**
  89. * get example paste
  90. *
  91. * @return array
  92. */
  93. public static function getPasteWithAttachment($meta = array())
  94. {
  95. $example = self::$paste;
  96. $example['meta']['salt'] = ServerSalt::generate();
  97. $example['meta'] = array_merge($example['meta'], $meta);
  98. return $example;
  99. }
  100. /**
  101. * get example paste as JSON
  102. *
  103. * @return array
  104. */
  105. public static function getPasteAsJson($meta = array())
  106. {
  107. $example = self::getPaste();
  108. // the JSON shouldn't contain the salt
  109. unset($example['meta']['salt']);
  110. if (count($meta)) {
  111. $example['meta'] = $meta;
  112. }
  113. $example['comments'] = array();
  114. $example['comment_count'] = 0;
  115. $example['comment_offset'] = 0;
  116. $example['@context'] = 'js/paste.jsonld';
  117. return json_encode($example);
  118. }
  119. /**
  120. * get paste generator
  121. *
  122. * @return array
  123. */
  124. public static function getPasteGenerator($meta = array(), $withAttachment = false)
  125. {
  126. $generatedMeta = array(
  127. 'salt' => ServerSalt::generate(),
  128. 'formatter' => Generator\elements('plaintext', 'syntaxhighlighting', 'markdown'),
  129. 'postdate' => Generator\int(),
  130. 'opendiscussion' => Generator\elements(true, false),
  131. );
  132. $generatedMeta = array_merge($generatedMeta, $meta);
  133. $example = array(
  134. 'data' => Generator\associative(array(
  135. 'iv' => Generator\vector(16, Generator\byte()),
  136. 'v' => 1,
  137. 'iter' => Generator\choose(100, 100000),
  138. 'ks' => Generator\elements(128, 192, 256),
  139. 'ts' => Generator\elements(64, 96, 128),
  140. 'mode' => Generator\elements('ccm', 'ocb2', 'gcm'),
  141. 'adata' => Generator\string(),
  142. 'cipher'=> 'aes',
  143. 'salt' => Generator\vector(8, Generator\byte()),
  144. 'ct' => Generator\seq(Generator\byte()),
  145. )),
  146. 'meta' => Generator\associative($generatedMeta),
  147. );
  148. if ($withAttachment) {
  149. $example['attachment'] = $example['attachmentname'] = $example['data'];
  150. }
  151. return Generator\associative($example);
  152. }
  153. /**
  154. * get paste from generated random array
  155. *
  156. * @return array
  157. */
  158. public static function getPasteFromGeneratedArray($paste)
  159. {
  160. $paste['data']['iv'] = self::byteArray2Base64($paste['data']['iv']);
  161. $paste['data']['salt'] = self::byteArray2Base64($paste['data']['salt']);
  162. // deflate cipher text to maximize entropy
  163. $paste['data']['ct'] = self::byteArray2Base64($paste['data']['ct'], true);
  164. $paste['data'] = json_encode($paste['data']);
  165. if (array_key_exists('attachment', $paste)) {
  166. $paste['attachment']['iv'] = self::byteArray2Base64($paste['attachment']['iv']);
  167. $paste['attachment']['salt'] = self::byteArray2Base64($paste['attachment']['salt']);
  168. $paste['attachment']['ct'] = self::byteArray2Base64($paste['attachment']['ct'], true);
  169. $paste['attachment'] = json_encode($paste['attachment']);
  170. }
  171. if (array_key_exists('attachmentname', $paste)) {
  172. $paste['attachmentname']['iv'] = self::byteArray2Base64($paste['attachmentname']['iv']);
  173. $paste['attachmentname']['salt'] = self::byteArray2Base64($paste['attachmentname']['salt']);
  174. $paste['attachmentname']['ct'] = self::byteArray2Base64($paste['attachmentname']['ct'], true);
  175. $paste['attachmentname'] = json_encode($paste['attachmentname']);
  176. }
  177. return $paste;
  178. }
  179. /**
  180. * get example paste ID
  181. *
  182. * @return string
  183. */
  184. public static function getCommentId()
  185. {
  186. return self::$commentid;
  187. }
  188. /**
  189. * get example comment
  190. *
  191. * @return array
  192. */
  193. public static function getComment($meta = array())
  194. {
  195. $example = self::$comment;
  196. $example['meta'] = array_merge($example['meta'], $meta);
  197. return $example;
  198. }
  199. /**
  200. * get example comment
  201. *
  202. * @return array
  203. */
  204. public static function getCommentPost($meta = array())
  205. {
  206. $example = self::getComment($meta);
  207. $example['nickname'] = $example['meta']['nickname'];
  208. unset($example['meta']['nickname']);
  209. return $example;
  210. }
  211. /**
  212. * delete directory and all its contents recursively
  213. *
  214. * @param string $path
  215. * @throws Exception
  216. */
  217. public static function rmDir($path)
  218. {
  219. $path .= DIRECTORY_SEPARATOR;
  220. $dir = dir($path);
  221. while (false !== ($file = $dir->read())) {
  222. if ($file != '.' && $file != '..') {
  223. if (is_dir($path . $file)) {
  224. self::rmDir($path . $file);
  225. } elseif (is_file($path . $file)) {
  226. if (!unlink($path . $file)) {
  227. throw new Exception('Error deleting file "' . $path . $file . '".');
  228. }
  229. }
  230. }
  231. }
  232. $dir->close();
  233. if (!rmdir($path)) {
  234. throw new Exception('Error deleting directory "' . $path . '".');
  235. }
  236. }
  237. /**
  238. * create a backup of the config file
  239. *
  240. * @return void
  241. */
  242. public static function confBackup()
  243. {
  244. if (!is_file(CONF . '.bak') && is_file(CONF)) {
  245. rename(CONF, CONF . '.bak');
  246. }
  247. }
  248. /**
  249. * restor backup of the config file
  250. *
  251. * @return void
  252. */
  253. public static function confRestore()
  254. {
  255. if (is_file(CONF . '.bak')) {
  256. rename(CONF . '.bak', CONF);
  257. }
  258. }
  259. /**
  260. * create ini file
  261. *
  262. * @param string $pathToFile
  263. * @param array $values
  264. */
  265. public static function createIniFile($pathToFile, $values)
  266. {
  267. if (count($values)) {
  268. @unlink($pathToFile);
  269. $ini = fopen($pathToFile, 'a');
  270. foreach ($values as $section => $options) {
  271. fwrite($ini, "[$section]" . PHP_EOL);
  272. foreach ($options as $option => $setting) {
  273. if (is_null($setting)) {
  274. continue;
  275. } elseif (is_string($setting)) {
  276. $setting = '"' . $setting . '"';
  277. } elseif (is_array($setting)) {
  278. foreach ($setting as $key => $value) {
  279. if (is_null($value)) {
  280. $value = 'null';
  281. } elseif (is_string($value)) {
  282. $value = '"' . $value . '"';
  283. } else {
  284. $value = var_export($value, true);
  285. }
  286. fwrite($ini, $option . "[$key] = $value" . PHP_EOL);
  287. }
  288. continue;
  289. } else {
  290. $setting = var_export($setting, true);
  291. }
  292. fwrite($ini, "$option = $setting" . PHP_EOL);
  293. }
  294. fwrite($ini, PHP_EOL);
  295. }
  296. fclose($ini);
  297. }
  298. }
  299. /**
  300. * a var_export that returns arrays without line breaks
  301. * by linus@flowingcreativity.net via php.net
  302. *
  303. * @param mixed $var
  304. * @param bool $return
  305. * @return void|string
  306. */
  307. public static function varExportMin($var, $return = false)
  308. {
  309. if (is_array($var)) {
  310. $toImplode = array();
  311. foreach ($var as $key => $value) {
  312. $toImplode[] = var_export($key, true) . ' => ' . self::varExportMin($value, true);
  313. }
  314. $code = 'array(' . implode(', ', $toImplode) . ')';
  315. if ($return) {
  316. return $code;
  317. } else {
  318. echo $code;
  319. }
  320. } else {
  321. return var_export($var, $return);
  322. }
  323. }
  324. /**
  325. * get example paste ID
  326. *
  327. * @param array $bytes
  328. * @return string
  329. */
  330. public static function byteArray2Base64($bytes, $deflate = false)
  331. {
  332. $string = implode(
  333. array_map('chr', $bytes)
  334. );
  335. // optional deflate to maximize entropy
  336. if ($deflate) {
  337. $string = gzdeflate($string);
  338. }
  339. return base64_encode($string);
  340. }
  341. /**
  342. * update all templates with the latest SRI hashes for all JS files
  343. *
  344. * @return void
  345. */
  346. public static function updateSubresourceIntegrity()
  347. {
  348. $dir = dir(PATH . 'js');
  349. while (false !== ($file = $dir->read())) {
  350. if (substr($file, -3) === '.js') {
  351. self::$hashes[$file] = base64_encode(
  352. hash('sha512', file_get_contents(
  353. PATH . 'js' . DIRECTORY_SEPARATOR . $file
  354. ), true)
  355. );
  356. }
  357. }
  358. $dir = dir(PATH . 'tpl');
  359. while (false !== ($file = $dir->read())) {
  360. if (substr($file, -4) === '.php') {
  361. $content = file_get_contents(
  362. PATH . 'tpl' . DIRECTORY_SEPARATOR . $file
  363. );
  364. $content = preg_replace_callback(
  365. '#<script type="text/javascript" src="js/([a-z0-9.-]+.js)([^"]*)"( integrity="[^"]+" crossorigin="[^"]+")?></script>#',
  366. function ($matches) {
  367. if (array_key_exists($matches[1], Helper::$hashes)) {
  368. return '<script type="text/javascript" src="js/' .
  369. $matches[1] . $matches[2] .
  370. '" integrity="sha512-' . Helper::$hashes[$matches[1]] .
  371. '" crossorigin="anonymous"></script>';
  372. } else {
  373. return $matches[0];
  374. }
  375. },
  376. $content
  377. );
  378. file_put_contents(
  379. PATH . 'tpl' . DIRECTORY_SEPARATOR . $file,
  380. $content
  381. );
  382. }
  383. }
  384. }
  385. }