Dayon/ext/index.php
2024-08-15 16:36:58 +02:00

126 lines
4.0 KiB
PHP

<?php
define('VERSION', "v.1.2");
// name of the database file (may also be a path)
define('DB_NAME', "dayon.db");
// minimal length of the tokens to be generated (33^N-1 variants)
define('TOKEN_MIN_LENGTH', 4);
// number of seconds after which the token will be purged
define('TOKEN_LIFETIME', 604800);
// maximum number of tokens that can be generated for a single IP
define('TOKEN_LIMIT', 700);
// 8<---8<---8<---
header('Content-type: text/plain');
if (isset($_GET['port'])) {
$port = clean($_GET['port'], 6);
if (isValidPort($port)) {
$pdo = new PDO('sqlite:'.DB_NAME);
createDatabase($pdo);
echo createToken($pdo, $port),"\n";
if (rand(0, 5) == 5) {
removeOldTokens($pdo);
}
}
} else if (isset($_GET['token'])) {
$token = clean($_GET['token'], TOKEN_MIN_LENGTH * 2);
$pdo = new PDO('sqlite:'.DB_NAME);
echo readToken($token, $pdo),"\n";
updateToken($token, $_SERVER['REMOTE_ADDR'], $pdo);
} else {
echo VERSION,"\n";
}
function clean($val, $maxLen = "") {
$val = trim(strip_tags($val));
if (!empty($maxLen)) {
$val = substr($val, 0, $maxLen);
}
return $val;
}
function isValidPort($port) {
return is_numeric($port) && $port > 0 && $port < 65536;
}
function createToken($pdo, $port) {
if (checkAvailable($pdo, $_SERVER['REMOTE_ADDR']) <= 0) {
return substr(str_shuffle("ABCDEFGHJKLMNPQRSTUVWXYZ123456789"), 0, rand(4, 12))."\n";
}
$token = computeToken(TOKEN_MIN_LENGTH);
$attempt = 0;
while (!insertToken($token, $_SERVER['REMOTE_ADDR'], $port, $pdo) && $attempt < 10) {
$length = $attempt < TOKEN_MIN_LENGTH ? TOKEN_MIN_LENGTH : round(TOKEN_MIN_LENGTH+$attempt/2);
$token = computeToken($length);
$attempt++;
}
return $token;
}
function checkAvailable($pdo, $address) {
$sql = "SELECT COUNT(*) FROM tokens WHERE assistant = :address";
$stmt = $pdo->prepare($sql);
$stmt->bindParam(':address', $address, PDO::PARAM_STR);
$stmt->execute();
$stmt->bindColumn(1, $count);
$stmt->fetch(PDO::FETCH_BOUND);
return TOKEN_LIMIT - $count;
}
function computeToken($length) {
$token = substr(str_shuffle("ABCDEFGHJKLMNPQRSTUVWXYZ123456789"), 0, $length-1);
$token .= strtoupper(substr(sha1($token), -1));
return $token;
}
function insertToken($token, $address, $port, $pdo) {
$sql = "INSERT INTO tokens (token,assistant,port,ts) VALUES (:token,:address,:port,:ts)";
$ts = time();
$stmt = $pdo->prepare($sql);
$stmt->bindParam(':token', $token, PDO::PARAM_STR, 7);
$stmt->bindParam(':address', $address, PDO::PARAM_STR);
$stmt->bindParam(':port', $port, PDO::PARAM_INT);
$stmt->bindParam(':ts', $ts, PDO::PARAM_INT);
$success = $stmt->execute();
if (!$success) {
// print_r($stmt->errorInfo());
return 0;
} else {
return 1;
}
}
function removeOldTokens($pdo) {
$ts = time();
$delete = "DELETE FROM tokens WHERE ts < ?";
$stmt = $pdo->prepare($delete);
$stmt->execute(array($ts-TOKEN_LIFETIME));
}
function readToken($token, $pdo) {
$sql = "SELECT assistant,port FROM tokens WHERE token = :token";
$stmt = $pdo->prepare($sql);
if ($stmt->execute([":token" => $token])) {
$stmt->bindColumn(1, $address);
$stmt->bindColumn(2, $port);
return $stmt->fetch(PDO::FETCH_BOUND) ? "$address*$port" : "";
} else {
return "";
}
}
function updateToken($token, $address, $pdo) {
$sql = "UPDATE tokens SET assisted = :address,ts = :ts WHERE token = :token";
$ts = time();
$stmt = $pdo->prepare($sql);
$stmt->bindParam(':address', $address, PDO::PARAM_STR);
$stmt->bindParam(':ts', $ts, PDO::PARAM_INT);
$stmt->bindParam(':token', $token, PDO::PARAM_STR, 7);
$stmt->execute();
}
function createDatabase($pdo) {
$sql = "CREATE TABLE IF NOT EXISTS `tokens` (`token` TEXT,`assistant` TEXT,`port` INTEGER,`assisted` TEXT,`ts` INTEGER, PRIMARY KEY(`token`))";
$stmt = $pdo->prepare($sql);
$stmt->execute();
// print_r($stmt->errorInfo());
}
?>