-
Notifications
You must be signed in to change notification settings - Fork 3
install_source
bitslip6 edited this page Aug 12, 2021
·
1 revision
<?php
error_clear_last();
const MISS_GZ = 2;
const WITH_ZLIB = 4;
const FAILED = 6;
const OPEN_FAIL = 8;
const MKDIR_FAIL = 10;
const WRITE_FAIL = 12;
const CHMOD_FAIL = 14;
const READ_FAIL = 16;
const CHK_FAIL = 18;
const HTTP_FAIL = 20;
const PHP_VER = 22;
const SHMOP = 24;
const APCU = 26;
const SHM = 28;
const SUCCESS = 30;
const ROOT_WRITE = 32;
const COOKIE = 34;
const NO_CACHE = 36;
const INSTALL = 38;
const ADDED = 40;
const UNIN = 42;
class Err
{
private static $_e = array();
public $title;
public $msg;
public static function new($t, ...$args)
{
$e = new Err();
$e->title = lang($t);
$e->msg = lang($t + 1);
error($e, ...$args);
self::$_e[] = $e;
}
public static function get()
{
return self::$_e;
}
}
$GLOBALS['lang'] = array("en" =>
array(
MISS_GZ => "missing gzopen",
MISS_GZ + 1 => "The PHP environment does not support gzopen. Unable to extract BitFire release. Please recompile with --with-zlib",
FAILED => "BitFire Install Failed",
FAILED + 1 => "A problem was found with your PHP environment, please check the error and visit the support center.",
INSTALL => "BitFire Installed",
INSTALL + 1 => "BitFire is already installed",
OPEN_FAIL => "Unable to open file",
OPEN_FAIL + 1 => "Error ocurred opening file [%s]",
MKDIR_FAIL => "Unable to mkdir",
MKDIR_FAIL + 1 => "Unable to create the directory [%s]",
WRITE_FAIL => "Unable to write file",
WRITE_FAIL + 1 => "Error ocurred writing to file [%s]",
CHMOD_FAIL => "Permission set error",
CHMOD_FAIL + 1 => "Unable to set the permissions on file [%s]",
READ_FAIL => "Unable to read archive",
READ_FAIL + 1 => "Unable to read archive, read %d of 512 bytes",
CHK_FAIL => "Checksum fail",
CHK_FAIL + 1 => "Archive Checksum error. expected %d, but found %d.",
HTTP_FAIL => "No HTTP Support",
HTTP_FAIL + 1 => "BitFire requires allow_url_fopen or cURL support",
PHP_VER => "PHP 7.0+",
PHP_VER + 1 => "BitFire requires PHP 7.0 or greater",
SHMOP => "SHMOP",
SHMOP + 1 => "SHMOP support found. Server cache available.",
APCU => "APCU",
APCU + 1 => "APCU support found. Server cache available.",
SHM => "SHM",
SHM + 1 => "SHM support found. Server cache available.",
SUCCESS => "SUCCESS",
SUCCESS + 1 => "BitFire installed successfully. Please visit <a style='color:#506690' href='/?BITFIRE_API=DASHBOARD' title='BitFire dashboard'>BitFire Dashboard</a><br><br>password: <span style='color:#335EEA;text-shadow:none;cursor:pointer;' onclick='copy_text(this)' id='pass'>%s</span> <small style='font-size:.8rem;color:#555;'>click to copy to clipboard</small>",
UNIN => "SUCCESS",
UNIN + 1 => "BitFire un-installed successfully. Bitfire startup removed from .htaccess. You are no longer protected",
ROOT_WRITE => "Permission error",
ROOT_WRITE + 1 => "%s must be writeable to use this install script",
COOKIE => "no cookie support",
COOKIE + 1 => "Cookie support required for browser verification",
NO_CACHE => "no cache support",
NO_CACHE + 1 => "Server cache recommended for fastest operation",
ADDED => "BitFire Startup",
ADDED + 1 => "BitFire has been added to .htaccess"
));
$GLOBALS['page2'] = <<<EOT
<!DOCTYPE html> <html lang="en"> <head>
<!-- Simple HttpErrorPages | MIT License | https://github.com/HttpErrorPages -->
<meta charset="utf-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/png" href="https://bitfire.co/assets/favicon/favicon.ico">
<title>%s</title>
<style type="text/css">/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */span.desc{text-shadow:none;color:#555;}span.title{color:#FFF;display:inline-blo0.5;text-align:left;width:150px;white-space:nowrap}html{font-family:sans-serif;line-height:1.15;-ms-text-size-adjust:100%%;-webkit-text-size-adjust:100%%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline;color:#335EEA}b,strong{font-weight:inherit}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%%}sub,sup{font-size:75%%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}template{display:none}[hidden]{display:none}/*! Simple HttpErrorPages | MIT X11 License | https://github.com/AndiDittrich/HttpErrorPages */body,html{width:100%%;height:100%%;}body.error{background-color:#21232a;}body.success{background-color:rgba(66,186,150,0.75);}body{color:#fff;text-align:center;text-shadow:0 2px 4px rgba(0,0,0,.5);padding:0;min-height:100%%;-webkit-box-shadow:inset 0 0 100px rgba(0,0,0,.8);box-shadow:inset 0 0 100px rgba(0,0,0,.8);display:table;font-family:"Open Sans",Arial,sans-serif}h1{font-family:inherit;font-weight:500;line-height:1.1;color:inherit;font-size:36px}h1 small{font-size:68%%;font-weight:400;line-height:1;color:#777}a{text-decoration:none;color:#fff;font-size:inherit;border-bottom:solid 1px #707070}.lead{color:#EEE;font-size:21px;line-height:1.4;text-shadow:none;}.cover{display:table-cell;vertical-align:middle;padding:0 20px}footer{position:fixed;width:100%%;height:40px;left:0;bottom:0;color:#a0a0a0;font-size:14px}li{list-style:none;display:flex;flex-direction:row;align-items:center;}li span{padding-left:20px;}</style>
<script> function copy_text(elm) { const text = elm.innerText; alert(text+" copied to clipboard"); const textarea = document.createElement('textarea'); textarea.value = text; textarea.setAttribute('readonly', ''); textarea.style.position = 'absolute'; textarea.style.left = '-9999px'; document.body.appendChild(textarea); textarea.select(); try { var successful = document.execCommand('copy'); this.copied = true; } catch(err) { this.copied = false; } textarea.remove(); }
</script>
</head>
<body class="%s"> <div class="cover"><h1>%s</h1><p class="lead">%s</p><ul style="width:600px;text-align:center;margin:20px auto;">%s</ul><div class="btn"><a style="position:relative;top:30px;" href="https://bitfire.co/support-center" title="">BitFire Support</a></div><br><div class="btn"><a style="position:relative;top:30px;color:#777;" href="/install.php?uninstall=1" title="">Uninstall Bitfire</a></div></div> </body> </html>
EOT;
$GLOBALS['item'] = <<<EOT
<li><img src="https://bitfire.co/assets/favicon/%s.svg" width="24px" alt="%s" /> <span class='title'> %s </span> - <span class='desc'>%s</span></li>
EOT;
$GLOBALS['list'] = '';
function lang($msg, $uc = false)
{
$l = "en";
if (isset($GLOBALS['lang'][$l]) && (isset($GLOBALS['lang'][$l][$msg]))) {
$m = $GLOBALS['lang'][$l][$msg];
return ($uc) ? ucwords($m) : $m;
}
return $msg;
}
function format_error()
{
$e = error_get_last();
if (empty($e)) {
return "";
}
error_clear_last();
return "errno: {$e['type']} line: {$e['line']} , {$e['message']}";
}
function error(Err $e, ...$args)
{
$err = format_error();
if (!empty($err)) {
$GLOBALS['list'] .= sprintf($GLOBALS['item'], "gear", "gear", 'php error', $err);
}
if (!empty($args) && strpos($e->msg, '%') !== false) {
$GLOBALS['list'] .= sprintf($GLOBALS['item'], "error", "error", $e->title, sprintf($e->msg, ...$args));
} else {
$GLOBALS['list'] .= sprintf($GLOBALS['item'], "error", "error", $e->title, $e->msg);
}
return false;
}
function debug($msg, ...$args)
{
$GLOBALS['list'] .= (is_int($msg)) ?
sprintf($GLOBALS['item'], "gear", "gear", lang($msg), ucfirst(lang($msg + 1)), ...$args) :
sprintf($GLOBALS['item'], "gear", "gear", ucwords($msg), ucfirst($args[0]));
}
function okay($msg, ...$args)
{
$GLOBALS['list'] .= sprintf($GLOBALS['item'], "okay", "okay", lang($msg, ...$args));
}
function fin($title, $success = "error", ...$args)
{
$t = lang($title, true);
$m = (empty($args)) ? lang($title + 1) : sprintf(lang($title + 1), ...$args);
$m .= ($success == "success") ? "<br><br><img width='128' src='https://bitfire.co/assets/check-mark.png'><br>" : "";
printf($GLOBALS['page2'], $t, $success, $t, $m, $GLOBALS['list']);
die();
}
class TarHeader
{
public $filename;
public $size;
public $perm;
public $checksum;
public $type;
}
function tar_read_file($fh, TarHeader $header)
{
$result = "";
$ctr = 0;
while ($header->size > 0 && $ctr++ < 20000) {
$tmp = gzread($fh, 512);
$len = strlen($tmp);
if ($len != 512) {
Err::new(READ_FAIL, "1:$len");
fin(FAILED);
}
$result .= substr($tmp, 0, min($header->size, 512));
$header->size -= strlen($tmp);
}
return $result;
}
/**
* extract tar archive into destination directory
*/
function tar_extract(string $file, string $destination = "")
{
$input = gzopen($file, 'rb');
if ($input == false) {
Err::new(OPEN_FAIL, $file);
fin(FAILED);
}
while (($header = tar_read_header($input, $destination))) {
if ($header->type == 5) {
if (!file_exists($header->filename)) {
if (!mkdir($header->filename, 0755, true)) {
Err::new(MKDIR_FAIL, $header->filename);
fin(FAILED);
}
}
}
// skip github file comments
else if ($header->type == 'g') {
} else if ($header->size > 0) {
if (!file_put_contents($header->filename, tar_read_file($input, $header), LOCK_EX)) {
Err::new(WRITE_FAIL, $header->filename);
fin(FAILED);
}
if (!chmod($header->filename, $header->perm)) {
Err::new(CHMOD_FAIL, $header->filename);
fin(FAILED);
}
}
}
return true;
}
function tar_calc_checksum(string $block)
{
$checksum = 0;
for ($i = 0; $i < 148; $i++) {
$checksum += ord($block[$i]);
}
for ($i = 156, $checksum += 256; $i < 512; $i++) {
$checksum += ord($block[$i]);
}
return $checksum;
}
function tar_read_header($fh, string $dest)
{
$block = gzread($fh, 512);
if ($block === false || strlen($block) != 512 || trim($block) === '') {
return NULL;
}
$header = new TarHeader();
$header->checksum = tar_calc_checksum($block);
$data = @unpack(
"a100filename/a8perm/a8uid/a8gid/a12size/a12mtime/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor/a155prefix",
$block
);
$uid = trim($data['uid']);
if ($uid != '' && !ctype_digit($uid)) {
return \err("error reading header file [%d]!", $uid);
}
if (!$header || ($data['checksum'] > 0 && $header->checksum != OctDec(trim($data['checksum'])))) {
Err::new(CHK_FAIL, $header->checksum, $data['checksum']);
fin(FAILED);
}
$header->filename = $dest . "/" . trim($data['filename']);
$header->perm = OctDec(trim($data['perm']));
$header->size = OctDec(trim($data['size']));
$header->type = $data['typeflag'];
return $header;
}
function map_reduce(array $map, callable $fn, $carry = "")
{
foreach ($map as $key => $value) {
$carry = $fn($key, $value, $carry);
}
return $carry;
}
function http_ctx(string $method, int $timeout)
{
return array(
'http' => array('method' => $method, 'timeout' => $timeout, 'max_redirects' => 4, 'header' => ''),
'ssl' => array('verify_peer' => false, 'allow_self_signed' => true)
);
}
function bit_curl(string $method, string $url, $data, array $optional_headers = NULL)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, ($method === "POST") ? 1 : 0);
$content = (is_array($data)) ? http_build_query($data) : $data;
curl_setopt($ch, CURLOPT_POSTFIELDS, $content);
if ($optional_headers != NULL) {
$headers = map_reduce($optional_headers, function ($key, $value, $carry) {
$carry[] = "$key: $value";
return $carry;
}, array());
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$server_output = curl_exec($ch);
if (empty($server_output)) {
Err::new(HTTP_FAIL);
fin(FAILED);
}
curl_close($ch);
return $server_output;
}
function bit_http_request($method, $url, $data)
{
// check for support...
if (!ini_get("allow_url_fopen") && function_exists('curl_init')) {
return bit_curl($method, $url, $data, $optional_headers);
}
$content = (is_array($data)) ? http_build_query($data) : $data;
$params = http_ctx($method, 2);
$url .= "?" . $content;
$url = trim($url, "?&");
$optional_headers = array('Content-Type' => "application/x-www-form-urlencoded", 'User-Agent' => "BitFire WAF https://bitslip6.com/user_agent");
$params['http']['header'] = map_reduce($optional_headers, function ($key, $value, $carry) {
return "$carry$key: $value\r\n";
}, "");
$ctx = stream_context_create($params);
$response = @file_get_contents($url, false, $ctx);
if ($response === false || strlen($response) < 5) {
Err::new(HTTP_FAIL);
fin(FAILED);
}
return $response;
}
function cookie($name, $value, $exp)
{
if (PHP_VERSION_ID < 70300) {
setcookie($name, $value, time() + $exp, '/; samesite=strict', '', false, true);
} else {
setcookie($name, $value, ['expires' => time() + $exp, 'path' => '/', 'domain' => '', 'secure' => false, 'httponly' => true, 'samesite' => 'strict']);
}
}
function uninstall($hta)
{
$root = $_SERVER['DOCUMENT_ROOT'];
$c = file_get_contents($hta);
$r = preg_replace("/\# BEGIN BitFire.*?\# END BitFire/sm", "", $c);
if (strlen($r) < strlen($c)) {
file_put_contents($hta, $r, LOCK_EX);
debug("uninstalled", "BitFire uninstalled");
fin(UNIN, "success");
} else {
debug("error uninstalling", "Unable to auto-uninstall");
fin(FAILED);
}
}
// check environment
$root = $_SERVER['DOCUMENT_ROOT'];
$hta = "$root/.htaccess";
if (PHP_VERSION_ID < 70000) {
Err::new(PHP_VER);
}
if (!function_exists('gzopen')) {
Err::new(MISS_GZ);
}
if (!ini_get("allow_url_fopen") && !function_exists('curl_init')) {
Err::new(HTTP_FAIL);
}
if (isset($_GET['uninstall']) || isset($_GET['?uninstall'])) {
uninstall($hta);
}
if (defined("WAF_DIR")) {
Err::new(INSTALL);
}
if (!empty(Err::get())) {
fin(FAILED);
}
if (!isset($_COOKIE['_bft'])) {
if (!isset($_GET['c'])) {
cookie("_bft", "bifire_test", 3600);
exit(header("location: " . $_SERVER['REQUEST_SCHEME'] . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] . "?c=1"));
}
debug(COOKIE);
}
debug("cookie", "cookie support enabled");
if (function_exists('shmop_open')) {
debug(SHMOP);
} else if (function_exists('apcu')) {
debug(APCU);
} else if (function_exists('shm')) {
debug(SHM);
} else {
debug(NO_CACHE);
}
debug("Server Software", $_SERVER['SERVER_SOFTWARE']);
if (ini_get("allow_url_fopen")) {
debug("HTTP Method", "allow_url_fopen");
} else if (function_exists('curl_init')) {
debug("HTTP Method", "cURL");
}
$ini = false;
$ini_w = false;
$writeable = (is_writeable($root));
if (!$writeable) {
Err::new(ROOT_WRITE, $root);
fin(FAILED);
}
$apache = strpos($_SERVER['SERVER_SOFTWARE'], "Apache") !== false;
if ($apache) {
if ((file_exists($hta) && is_writeable($hta)) || $writeable) {
$ini = $hta;
$ini_w = true;
}
}
if ($ini == false) {
$ini = php_ini_loaded_file();
$ini_w = is_writeable($ini);
}
if ($ini_w) {
debug("php.ini", "File is writeable");
} else {
debug("php.ini", "File is not writeable");
}
$destination = "$root/bitfire";
$release = bit_http_request("GET", "https://bitfire.co/latest-release.tar.gz", "");
$out_file = sys_get_temp_dir() . "/bitfire_release.tar.gz";
$f = file_put_contents($out_file, $release, LOCK_EX);
if ($f !== strlen($release)) {
Err::new(WRITE_FAIL);
fin(FAILED);
}
tar_extract($out_file, $root);
if (!defined("WAF_DIR")) {
define("WAF_DIR", "$root/bitfire/");
require_once "$root/bitfire/src/bitfire.php";
}
$pass = \TF\random_str(9);
\TF\file_replace("$root/bitfire/config.ini", "bitfire!", $pass);
if ($ini_w) {
$htcontent = "\n# BEGIN BitFire\n
<IfModule mod_php5.c>\n php_value auto_prepend_file '$root/bitfire/startup.php'\n</IfModule>\n
<IfModule mod_php7.c>\n php_value auto_prepend_file '$root/bitfire/startup.php'\n</IfModule>\n# END BitFire";
$lines = file($hta);
if (!in_array("# BitFire", $lines)) {
@system("rm -f $root/.htaccess.bak.*");
copy($hta, "$hta.bak." . mk_rand(10000, 99999));
$c = file_get_contents($hta);
if ($c === false) {
Err::new(ROOT_WRITE, $hta);
}
file_put_contents($hta, $htcontent, FILE_APPEND | LOCK_EX);
}
debug(ADDED);
fin(SUCCESS, "success", $pass);
}