<?php
/* Functions for Networking */

function mask2cidr($mask)
{
    $long = ip2long($mask);
    $base = ip2long("255.255.255.255");
    return 32 - log(($long ^ $base) + 1, 2);
}

/* Functions to write ini files */

function write_php_ini($array, $file)
{
    $res = [];
    foreach ($array as $key => $val) {
        if (is_array($val)) {
            $res[] = "[$key]";
            foreach ($val as $skey => $sval) {
                $res[] =
                    "$skey = " .
                    (is_numeric($sval) ? $sval : '"' . $sval . '"');
            }
        } else {
            $res[] = "$key = " . (is_numeric($val) ? $val : '"' . $val . '"');
        }
    }
    if (safefilerewrite($file, implode("\r\n", $res))) {
        return true;
    } else {
        return false;
    }
}

function safefilerewrite($fileName, $dataToSave)
{
    if ($fp = fopen($fileName, "w")) {
        $startTime = microtime(true);
        do {
            $canWrite = flock($fp, LOCK_EX);
            // If lock not obtained sleep for 0 - 100 milliseconds, to avoid collision and CPU load
            if (!$canWrite) {
                usleep(round(rand(0, 100) * 1000));
            }
        } while (!$canWrite and microtime(true) - $startTime < 5);

        //file was locked so now we can store information
        if ($canWrite) {
            fwrite($fp, $dataToSave);
            flock($fp, LOCK_UN);
        }
        fclose($fp);
        return true;
    } else {
        return false;
    }
}

//Function to get string between used for Mobile.sh

function get_string_between($string, $start, $end)
{
    $string = " " . $string;
    $ini = strpos($string, $start);
    if ($ini == 0) {
        return "";
    }
    $ini += strlen($start);
    $len = strpos($string, $end, $ini) - $ini;
    return substr($string, $ini, $len);
}

/**
 *
 * Add CSRF Token to form
 *
 */
function CSRFToken()
{
    ?>
	<input id="csrf_token" type="hidden" name="csrf_token" value="<?php echo htmlspecialchars(
    $_SESSION[" csrf_token "],
    ENT_QUOTES
); ?>" />
	<?php
}

/**
 *
 * Validate CSRF Token
 *
 */
function CSRFValidate()
{
    if (hash_equals($_POST["csrf_token"], $_SESSION["csrf_token"])) {
        return true;
    } else {
        error_log("CSRF violation");
        return false;
    }
}

/**
 * Test whether array is associative
 */
function isAssoc($arr)
{
    return array_keys($arr) !== range(0, count($arr) - 1);
}

/**
 *
 * Display a selector field for a form. Arguments are:
 *   $name:     Field name
 *   $options:  Array of options
 *   $selected: Selected option (optional)
 *       If $options is an associative array this should be the key
 *
 */
function SelectorOptions($name, $options, $selected = null, $id = null)
{
    echo '<select class="form-control" name="' .
        htmlspecialchars($name, ENT_QUOTES) .
        '"';
    if (isset($id)) {
        echo ' id="' . htmlspecialchars($id, ENT_QUOTES) . '"';
    }

    echo ">", PHP_EOL;
    foreach ($options as $opt => $label) {
        $select = "";
        $key = isAssoc($options) ? $opt : $label;
        if ($key == $selected) {
            $select = ' selected="selected"';
        }

        echo '<option value="' .
        htmlspecialchars($key, ENT_QUOTES) .
        '"' .
        $select .
        ">" .
        htmlspecialchars($label, ENT_QUOTES) .
        "</option>",
            PHP_EOL;
    }

    echo "</select>", PHP_EOL;
}

/**
 *
 * @param string $input
 * @param string $string
 * @param int $offset
 * @param string $separator
 * @return $string
 */
function GetDistString($input, $string, $offset, $separator)
{
    $string = substr(
        $input,
        strpos($input, $string) + $offset,
        strpos(substr($input, strpos($input, $string) + $offset), $separator)
    );
    return $string;
}

/**
 *
 * @param array $arrConfig
 * @return $config
 */
function ParseConfig($arrConfig)
{
    $config = [];
    foreach ($arrConfig as $line) {
        $line = trim($line);
        if ($line != "" && $line[0] != "#") {
            $arrLine = explode("=", $line);
            $config[$arrLine[0]] = count($arrLine) > 1 ? $arrLine[1] : true;
        }
    }
    return $config;
}

/**
 *
 * @param string $freq
 * @return $channel
 */
function ConvertToChannel($freq)
{
    if ($freq >= 2412 && $freq <= 2484) {
        $channel = ($freq - 2407) / 5;
    } elseif ($freq >= 4915 && $freq <= 4980) {
        $channel = ($freq - 4910) / 5 + 182;
    } elseif ($freq >= 5035 && $freq <= 5865) {
        $channel = ($freq - 5030) / 5 + 6;
    } else {
        $channel = -1;
    }
    if ($channel >= 1 && $channel <= 196) {
        return $channel;
    } else {
        return "Invalid Channel";
    }
}

/**
 * Converts WPA security string to readable format
 * @param string $security
 * @return string
 */
function ConvertToSecurity($security)
{
    $options = [];
    preg_match_all("/\[([^\]]+)\]/s", $security, $matches);
    foreach ($matches[1] as $match) {
        if (preg_match("/^(WPA\d?)/", $match, $protocol_match)) {
            $protocol = $protocol_match[1];
            $matchArr = explode("-", $match);
            if (count($matchArr) > 2) {
                $options[] = htmlspecialchars(
                    $protocol . " (" . $matchArr[2] . ")",
                    ENT_QUOTES
                );
            } else {
                $options[] = htmlspecialchars($protocol, ENT_QUOTES);
            }
        }
    }

    if (count($options) === 0) {
        // This could also be WEP but wpa_supplicant doesn't have a way to determine
        // this.
        // And you shouldn't be using WEP these days anyway.
        return "Open";
    } else {
        return implode("<br />", $options);
    }
}

/**
 *
 *
 */
/*LOKINET FUNCTIONS ADDED HERE*/

function DisplayLokinetConfig()
{
    exec("pidof lokinet | wc -l", $lokinetstatus);
    if ($lokinetstatus[0] != 0) {
        $exitstatus = exec("lokinet-vpn --status");
    } else {
        $exitstatus = "no exits";
    }
    $rulestate = exec(
        "ip rule show default | grep lokinet | awk {'print $5'}",
        $output
    );
    $lokiversion = exec("dpkg -s lokinet | grep '^Version:'", $output);
    ?>
		<div class="row">
			<div class="col-lg-12">
				<div class="panel panel-primary">
					<div class="panel-heading"><i class="fa fa-eye-slash fa-fw"></i> Configure Lokinet</div>
					<!-- /.panel-heading -->
					<div class="panel-body">
						<!-- Nav tabs -->
						<ul class="nav nav-tabs">
							<li class="active"><a href="#basic" data-toggle="tab">Exit Node Settings</a> </li>
							<li><a href="#Mobile" data-toggle="tab">Mobile APN</a> </li>
							<li><a href="#whois" data-toggle="tab">WHOIS</a> </li>
						</ul>
						<!-- Tab panes -->
						<div class="tab-content">
							<p>
								<?php echo $status; ?>
							</p>
							<p>
								<?php echo "Current Lokinet $lokiversion"; ?>
							</p>
							<div class="tab-pane fade in active" id="basic">
								<form role="form" action="?page=save_hostapd_conf" method="POST">
									<h5>Enter Exit Node Data to activate:</h5>
									<label for="exitaddress">Exit:</label>
									<input type="text" class="form-control" list="exitaddresses" placeholder="enter exit address here" id="exitaddress" name="exitaddress" onchange="OnSelectionChange()">
									<?php $api_url = 'https://my-json-server.typicode.com/necro-nemesis/exits-api/exits';
			// Read JSON file
			$json_data = file_get_contents($api_url);
			// Decode JSON data into PHP array
			$response_data = json_decode($json_data,true);
			?>
										<datalist id="exitaddresses">
											<?php foreach($response_data as $response){
					$listedexits = '<option value=\''.$response['exit'].'\'>';
					echo $listedexits;
					}
				?>
										</datalist>
										<script>
										//JSON Authentication Token Handler
										async function OnSelectionChange() {
											var selection = document.getElementById("exitaddress").value;
											const endpoint = 'https://my-json-server.typicode.com/necro-nemesis/exits-api/db';
											const response = await fetch(endpoint);
											const data = await response.json();
											for(var i = 0; i < data['exits'].length; i++) {
												if(data['exits'][i]['exit'] == selection) {
													const {
														exit, auth, geo, rate
													} = data['exits'][i];
													console.log('Exit name : ' + exit);
													console.log('Exit token : ' + auth);
													console.log('Exit location : ' + geo);
													console.log('Exit rate : ' + rate);
													console.log('Dropdown selection : ' + selection);
													alert('EXIT NODE INFORMATION\r\rExit Address : ' + exit + '\rExit Location : ' + geo + '\rExit Autorization Key : ' + auth + '\rMonthly Rate : ' + rate);
													document.getElementById("auth").value = auth;
													break;
												}
											}
										}
										</script>
										<label for="exitkey">Exit Key: (optional)</label>
										<input type="text" class="form-control" id="auth" placeholder="optional exit authorization key" id="exitkey" name="exitkey">
										<br/>
										<input type="reset" class="btn btn-default" value="Clear">
										<?php
                if ($exitstatus != "no exits") {
                    echo '<input type="submit" class="btn btn-danger" name="StopExit" value="Stop Exit" />', PHP_EOL;
                } else {
                    echo '<input type="submit" class="btn btn-success" name="StartExit" value="Start Exit" />', PHP_EOL;
                }
                if ($lokinetstatus[0] == 0) {
                    echo '<input type="submit" class="btn btn-success" name="StartDaemon" value="Start Daemon" />', PHP_EOL;
                } else {
                    echo '<input type="submit" class="btn btn-danger" name="StopDaemon" value="Stop Daemon" />', PHP_EOL;
                }
		?>
											<!-- Trigger the modal with a button -->
											<button type="button" class="btn btn-default" data-toggle="modal" data-target="#myModal">About</button>
											<!-- Modal -->
											<div id="myModal" class="modal fade" role="dialog">
												<div class="modal-dialog">
													<div class="modal-dialog modal-lg">
														<!-- Modal content-->
														<div class="modal-content">
															<div class="modal-header">
																<button type="button" class="close" data-dismiss="modal">&times;</button>
																<h4 class="modal-title">About</h4> <img class="img-responsive" src="img/about_img.png"> </div>
															<div class="modal-body">
																<p>LabyrinthAP is open source software offered under GNU General Public License v3.0. Ongoing development is reliant on voluntary financial support through donations to the project. I hope that you find using LabyrithAP beneficial and also hope there's sufficient widespread support for it to financially support it's future. Seeing support for it will assist in continued improvements as well as adapting it to future requirements.</p>
																<p>LabyrinthAP was initially conceived to provide users with a platform agnostic way to connect networked devices to Lokinet without the need to install and configure Lokinet applications on individual systems. From initial research on compiling Lokinet for ARM, it was demonstrated that it could be feasibile to use SBC's to create access points which could encrypt, decrypt, route and onion route traffic over Lokinet while managing dns requirements. In addition it could provide a means to select and connect to various exits located all around the globe. Through utilizing various robust packages and coding custom networking configurations LabyrinthAP utilizing Lokinet is able to achieve all this.</p>
																<p>This early research and further development led to the current version of LabyrithAP which provides a solution which is able to connect virtually any networked device to Lokinet without the device needing to have Lokinet installed, configured or running the application natively. The devices need only to connect to LabyrinthAP and it will handle the rest of Lokinet's connection requirements.</p>
																<p>If you wish to donate to this development the Oxen wallet for LabyrinthAP is: LA8VDcoJgiv2bSiVqyaT6hJ67LXbnQGpf9Uk3zh9ikUKPJUWeYbgsd9gxQ5ptM2hQNSsCaRETQ3GM9FLDe7BGqcm4ve69bh</p>
																<p> Additional information can be found on the github repo located at: https://github.com/necro-nemesis/LabyrinthAP. Further discussions and assistance with using Lokinet is provided on Session in the Lokinet open group.</p>
																<p> I hope that LabyrinthAP will continue to service your needs for gaining access to Lokinet.</p>
																<p>Thank-you for using LabyrinthAP,</p>
																<p>Technical Tumbleweed</p>
															</div>
															<div class="modal-footer">
																<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
															</div>
														</div>
													</div>
												</div>
											</div>
											<h5><?php echo "Your development support is greatly appreciated <br>Independent LabyrinthAP developer TechnicalTumbleweed's OXEN wallet address:"; ?></h5>
											<h5><pre><?php echo "LA8VDcoJgiv2bSiVqyaT6hJ67LXbnQGpf9Uk3zh9ikUKPJUWeYbgsd9gxQ5ptM2hQNSsCaRETQ3GM9FLDe7BGqcm4ve69bh"; ?></pre></h5> </div>
							<div class="tab-pane fade" id="Mobile">
								<form role="form" action="?page=save_hostapd_conf" method="POST">
									<h5>Enter mobile provider apn:</h5>
									<label for="apn">Mobile Provider APN:</label>
									<input type="text" class="form-control" placeholder="enter apn address here" id="apn" name="apn">
									<br/>
									<?php echo '<input type="submit" class="btn btn-success" name="apnaddress" value="Set APN" />',
		PHP_EOL; ?>
										<h5><?php echo "Your development support is greatly appreciated <br>Independent LabyrinthAP developer TechnicalTumbleweed's OXEN wallet address:"; ?></h5>
										<h5><pre><?php echo "LA8VDcoJgiv2bSiVqyaT6hJ67LXbnQGpf9Uk3zh9ikUKPJUWeYbgsd9gxQ5ptM2hQNSsCaRETQ3GM9FLDe7BGqcm4ve69bh"; ?></pre></h5> </div>
							<div class="tab-pane fade" id="whois">
								<form role="form" action="?page=save_hostapd_conf" method="POST">
									<h5>Enter .loki Address:</h5>
									<label for="lokiaddress">Loki Address:</label>
									<input type="text" class="form-control" placeholder="enter lokinet address here" id="lokiaddress" name="lokiaddress">
									<br/>
									<?php echo '<input type="submit" class="btn btn-success" name="checkaddress" value="Submit" />',
		PHP_EOL; ?>
										<h5><?php echo "Your development support is greatly appreciated <br>Independent LabyrinthAP developer TechnicalTumbleweed's OXEN wallet address:"; ?></h5>
										<h5><pre><?php echo "LA8VDcoJgiv2bSiVqyaT6hJ67LXbnQGpf9Uk3zh9ikUKPJUWeYbgsd9gxQ5ptM2hQNSsCaRETQ3GM9FLDe7BGqcm4ve69bh"; ?></pre></h5> </div>
    <?php
}

function ActivateLokinetConfig()
{
    /* Lokinet script commands start HERE
        ////
        //// LOKINET
        ////
        //*/

    //START
    if (isset($_POST["StartDaemon"])) {
        exec("sudo /var/lib/lokinet/lokilaunch.sh start");
        DisplayLokinetConfig();

        //STOP
    } elseif (isset($_POST["StopDaemon"])) {
        exec("sudo /var/lib/lokinet/lokilaunch.sh exitdown");
        exec("sudo /var/lib/lokinet/lokilaunch.sh stop");
        DisplayLokinetConfig();

        //START EXIT
    } elseif (isset($_POST["StartExit"])) {
        $exit = $_POST["exitaddress"];
        $token = $_POST["exitkey"];
        $exit = str_replace("'", "", $exit);
        $token = str_replace("'", "", $token);
        $output = shell_exec(
            "sudo /var/lib/lokinet/lokilaunch.sh exitup '" .
                $exit .
                "' '" .
                $token .
                "'"
        );
	$exitstatus = exec("lokinet-vpn --status");
	if ($exitstatus != "no exits") {
	?>
							<div class="alert alert-info">
								<?php
	echo "Exit Enabled";
	?>
							</div>
							<?php
	} else {
	?>
								<div class="alert alert-danger">
									<?php
	echo "WARNING EXIT DID NOT CONNECT";
	?>
								</div>
								<?php
	}
        echo "<pre><strong>$output</strong></pre>";
        ?>
									<form method="post">
										<?php
	echo '<input type="submit" class="btn btn-success" name="Return" value="Return" />', PHP_EOL;
	echo "\n";
	?>
											<form>
												<br/>
												<?php

        //STOP EXIT
    } elseif (isset($_POST["StopExit"])) {
        exec("sudo /var/lib/lokinet/lokilaunch.sh exitdown");
        DisplayLokinetConfig();

        //WHOIS
    } elseif (isset($_POST["checkaddress"])) {
        $address = $_POST["lokiaddress"];
        $output = shell_exec("sudo /var/lib/lokinet/lokilaunch.sh whois " . $address . "");
        echo "<pre><strong>$output</strong></pre>";
        ?>
													<form method="post">
														<?php
	echo '<input type="submit" class="btn btn-success" name="Return" value="Return" />', PHP_EOL;
	echo "\n";
	?>
															<form>
																<br/>
																<?php

        //Mobile
    } elseif (isset($_POST["apnaddress"])) {
        $apnvalue = $_POST["apn"];
        $file = "/var/lib/lokinet/mobile.sh";
        $input = file_get_contents($file);
        $parsed = get_string_between($input, "apn='", "',ip");
        $output = str_replace($parsed, $apnvalue, $input);
        file_put_contents($file, $output);
        echo "<pre><strong>Reboot required to start mobile. Reboot now?</strong></pre>";
        ?>
																	<form method="post">
																		<?php
	echo '<input type="submit" class="btn btn-success" name="Return" value="Reboot Later" />', PHP_EOL;
	echo '<input type="submit" class="btn btn-success" name="Reboot" value="Activate Now" />', PHP_EOL;
	echo "\n";
	?>
																			<form>
																				<br/>
																				<?php
	} elseif (isset($_POST["Return"])) {
        DisplayLokinetConfig();
	} elseif (isset($_POST["Reboot"])) {
        shell_exec("sudo reboot now");
	}
}
