From 98a84f3aa735f31b08e807c8a4f0549742cbd1b0 Mon Sep 17 00:00:00 2001
From: RaindropsSys <contact@minteck.org>
Date: Tue, 16 May 2023 22:17:15 +0200
Subject: Updated 8 files (automated)

---
 includes/external/pair/index.js |   2 +-
 includes/util/session.inc       |  39 +++++++++----
 pages/api/money/account.php     |   2 +-
 pages/api/money/accounts.php    |   4 +-
 pages/api/rename.php            |  26 ++++++++-
 pages/api/session.php           |   5 +-
 pages/money.inc                 | 124 +++++++++++++++++++++++++++++++++++++++-
 pages/pair.inc                  |   2 +-
 8 files changed, 181 insertions(+), 23 deletions(-)

diff --git a/includes/external/pair/index.js b/includes/external/pair/index.js
index af7c3e4..f933232 100644
--- a/includes/external/pair/index.js
+++ b/includes/external/pair/index.js
@@ -90,7 +90,7 @@ wss.on('connection', (ws, req) => {
                     } else {
                         clients[ws.code] = {
                             socket: ws,
-                            name: (typeof data.name === "string" && data.name.length > 2 && data.name.length < 50) ? data.name : "<Unknown client>"
+                            name: (typeof data.name === "string" && data.name.length > 2 && data.name.length < 100) ? data.name : "<Unknown client>"
                         }
 
                         ws.send(JSON.stringify({
diff --git a/includes/util/session.inc b/includes/util/session.inc
index 81192b9..74f16ba 100644
--- a/includes/util/session.inc
+++ b/includes/util/session.inc
@@ -15,19 +15,38 @@ if (!function_exists("formatPonypush")) {
     }
 }
 
-if (isset($_COOKIE['PEH2_SESSION_TOKEN'])) {
-    if (!(str_contains($_COOKIE['PEH2_SESSION_TOKEN'], "/") || trim($_COOKIE["PEH2_SESSION_TOKEN"]) === "" || trim($_COOKIE["PEH2_SESSION_TOKEN"]) === "." || trim($_COOKIE["PEH2_SESSION_TOKEN"]) === "..")) {
-        if (file_exists($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . str_replace("/", "", $_COOKIE['PEH2_SESSION_TOKEN']))) {
-            $data = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . str_replace("/", "", $_COOKIE['PEH2_SESSION_TOKEN'])), true);
+$authorization = null;
+$post = null;
+
+if ($_SERVER['REQUEST_METHOD'] === "POST") {
+    $request_raw = file_get_contents('php://input');
+    $json_object = $data = json_decode($request_raw, true);
+
+    if (json_last_error() === JSON_ERROR_NONE) {
+        $post = $data["_session"];
+    }
+}
+
+if (isset($_SERVER['HTTP_AUTHORIZATION']) && str_starts_with(trim($_SERVER['HTTP_AUTHORIZATION']), "Bearer ")) {
+    $authorization = trim(substr($_SERVER['HTTP_AUTHORIZATION'], 7));
+}
+
+$token = $authorization ?? $post ?? $_POST["_session"] ?? $_GET["_session"] ?? $_COOKIE['PEH2_SESSION_TOKEN'] ?? null;
+
+if (isset($token)) {
+    if (!(str_contains($token, "/") || trim($token) === "" || trim($token) === "." || trim($token) === "..")) {
+        if (file_exists($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . str_replace("/", "", $token))) {
+            $data = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . str_replace("/", "", $token)), true);
 
             if (isset($data["profile"])) {
                 $_PROFILE = $data["profile"];
                 $data["last"] = time();
+                if (!isset($data["addresses"])) $data["addresses"] = [];
                 $data["addresses"][$_SERVER["HTTP_X_FORWARDED_FOR"] ?? $_SERVER["REMOTE_ADDR"]] = time();
-                file_put_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . str_replace("/", "", $_COOKIE['PEH2_SESSION_TOKEN']), json_encode($data));
+                file_put_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . str_replace("/", "", $token), json_encode($data));
 
                 if (time() - $data["last"] > 86400 * 30) {
-                    unlink($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . str_replace("/", "", $_COOKIE['PEH2_SESSION_TOKEN']));
+                    unlink($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . str_replace("/", "", $token));
                     unset($_PROFILE);
                     $isLoggedIn = false;
                     $isLowerLoggedIn = false;
@@ -42,17 +61,17 @@ if (isset($_COOKIE['PEH2_SESSION_TOKEN'])) {
             }
 
             $isLoggedIn = true;
-        } elseif (file_exists($_SERVER['DOCUMENT_ROOT'] . "/includes/lowertokens/" . str_replace("/", "", $_COOKIE['PEH2_SESSION_TOKEN']))) {
-            $data = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/lowertokens/" . str_replace("/", "", $_COOKIE['PEH2_SESSION_TOKEN'])), true);
+        } elseif (file_exists($_SERVER['DOCUMENT_ROOT'] . "/includes/lowertokens/" . str_replace("/", "", $token))) {
+            $data = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/lowertokens/" . str_replace("/", "", $token)), true);
 
             if (isset($data["profile"])) {
                 $_PROFILE = $data["profile"];
                 $data["last"] = time();
                 $data["addresses"][$_SERVER["HTTP_X_FORWARDED_FOR"] ?? $_SERVER["REMOTE_ADDR"]] = time();
-                file_put_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . str_replace("/", "", $_COOKIE['PEH2_SESSION_TOKEN']), json_encode($data));
+                file_put_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . str_replace("/", "", $token), json_encode($data));
 
                 if (time() - $data["last"] > 86400 * 30) {
-                    unlink($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . str_replace("/", "", $_COOKIE['PEH2_SESSION_TOKEN']));
+                    unlink($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . str_replace("/", "", $token));
                     unset($_PROFILE);
                     $isLoggedIn = false;
                     $isLowerLoggedIn = false;
diff --git a/pages/api/money/account.php b/pages/api/money/account.php
index 6620733..1801b28 100644
--- a/pages/api/money/account.php
+++ b/pages/api/money/account.php
@@ -29,7 +29,7 @@ foreach ($accounts as $account) {
         $acc["total"] = round(calculateFullAmount($account, true), 2);
         $acc["interests"] = $account["interests"];
         $acc["max"] = $account["max"];
-        $acc["used_percentage"] = isset($account["max"]) ? (calculateFullAmount($account, true) / $account["max"]) * 100 : null;
+        $acc["used_percentage"] = isset($account["max"]) ? round((calculateFullAmount($account, true) / $account["max"]) * 100, 2) : null;
         $acc["transactions"] = [];
 
         foreach ($account["transactions"] as $index => $transaction) {
diff --git a/pages/api/money/accounts.php b/pages/api/money/accounts.php
index 22d8c77..9f85323 100644
--- a/pages/api/money/accounts.php
+++ b/pages/api/money/accounts.php
@@ -58,7 +58,7 @@ foreach ($accounts as $index => $account) {
         $acc["total"] = round(calculateFullAmount($account, true), 2);
         $acc["interests"] = $account["interests"];
         $acc["max"] = $account["max"];
-        $acc["used_percentage"] = isset($account["max"]) ? (calculateFullAmount($account, true) / $account["max"]) * 100 : null;
+        $acc["used_percentage"] = isset($account["max"]) ? round((calculateFullAmount($account, true) / $account["max"]) * 100, 2) : null;
 
         $obj["users"]["cloudburst"]["accounts"][] = $acc;
     }
@@ -84,7 +84,7 @@ foreach ($accounts as $index => $account) {
         $acc["total"] = round(calculateFullAmount($account, true), 2);
         $acc["interests"] = $account["interests"];
         $acc["max"] = $account["max"];
-        $acc["used_percentage"] = isset($account["max"]) ? (calculateFullAmount($account, true) / $account["max"]) * 100 : null;
+        $acc["used_percentage"] = isset($account["max"]) ? round((calculateFullAmount($account, true) / $account["max"]) * 100, 2) : null;
         $acc["transactions"] = null;
 
         $obj["users"]["raindrops"]["accounts"][] = $acc;
diff --git a/pages/api/rename.php b/pages/api/rename.php
index d450557..abec81e 100644
--- a/pages/api/rename.php
+++ b/pages/api/rename.php
@@ -10,8 +10,28 @@ if (!$isLoggedIn || $isLowerLoggedIn) {
     die();
 }
 
-$data = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . str_replace("/", "", $_COOKIE['PEH2_SESSION_TOKEN'])), true);
+$obj = [
+    "success" => true
+];
 
-$data["name"] = $_GET["name"] ?? $data["name"];
+global $token;
+$data = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . str_replace("/", "", $token)), true);
 
-file_put_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . str_replace("/", "", $_COOKIE['PEH2_SESSION_TOKEN']), json_encode($data));
\ No newline at end of file
+$data["name"] = $_POST["name"] ?? $_GET["name"] ?? $data["name"];
+$obj["pre_name"] = $data["name"];
+
+$request_raw = file_get_contents('php://input');
+$json_object = json_decode($request_raw, true);
+
+if (json_last_error() === JSON_ERROR_NONE) {
+    $obj["json_error"] = [ json_last_error(), json_last_error_msg() ];
+    if (isset($json_object["name"])) {
+        $data["name"] = $json_object["name"];
+        $obj["json_name"] = $json_object["name"];
+    }
+}
+
+$obj["new_name"] = $data["name"];
+
+file_put_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . str_replace("/", "", $token), json_encode($data));
+die(json_encode($obj));
\ No newline at end of file
diff --git a/pages/api/session.php b/pages/api/session.php
index f91288e..53e1845 100644
--- a/pages/api/session.php
+++ b/pages/api/session.php
@@ -14,11 +14,12 @@ if (!$isLoggedIn || $isLowerLoggedIn) {
     ], JSON_PRETTY_PRINT));
 }
 
-$data = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . str_replace("/", "", $_COOKIE['PEH2_SESSION_TOKEN'])), true);
+global $token;
+$data = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/tokens/" . str_replace("/", "", $token)), true);
 
 die(json_encode([
     "name" => $data["name"],
     "created" => date('c', $data["created"]),
     "last_seen" => date('c', $data["last"]),
-    "seen_at" => array_keys($data["addresses"])
+    "seen_at" => array_keys($data["addresses"] ?? [])
 ], JSON_PRETTY_PRINT));
\ No newline at end of file
diff --git a/pages/money.inc b/pages/money.inc
index 4d93398..1338a3a 100644
--- a/pages/money.inc
+++ b/pages/money.inc
@@ -100,6 +100,76 @@ if ((isset($_GET["create"]) || isset($_GET["delete"])) && isset($parts[2])) {
 $rate = (float)trim(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/exchange.txt"));
 
 require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/components/header.inc';
+$transactionMonths = [];
+
+foreach ($accounts as $account) {
+    array_push($transactionMonths, ...array_map(function ($i) { return date('Y-m', strtotime($i["date"])); }, array_filter($account["transactions"], function ($i) { return !isset($i["initial"]) || !$i["initial"]; })));
+}
+
+$months = [
+    ...[
+        "2022-12", "2022-11", "2022-10", "2022-09",
+        "2022-08", "2022-07", "2022-06"
+    ],
+    ...array_values(array_filter(array_unique(array_reduce($transactionMonths, function ($a, $b) {
+        return [...$a, $b];
+    }, [])), function ($i) {
+        return $i !== date('Y-m');
+    }))
+];
+
+$monthlyCloudburst = [];
+$monthlyRaindrops = [];
+
+$bits = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/bits.json"), true);
+$projects = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/includes/data/projects.json"), true);
+
+foreach ($bits["cloudburst"] as $month => $value) {
+    $monthlyCloudburst[$month] = $value;
+}
+
+foreach ($bits["raindrops"] as $month => $value) {
+    $monthlyRaindrops[$month] = $value;
+}
+
+foreach ($months as $month) {
+    $gainedCloudburst = $monthlyCloudburst[$month] ?? 0;
+    $gainedRaindrops = $monthlyRaindrops[$month] ?? 0;
+
+    foreach ($accounts as $account) {
+        foreach ($account["transactions"] as $transaction) {
+            if (isset($transaction["initial"]) && $transaction["initial"]) continue;
+            if (date('Y-m', strtotime($transaction["date"])) !== $month) continue;
+
+            if ($account["owner"] === "raindrops") {
+                $gainedRaindrops += $transaction["amount"];
+            } else {
+                $gainedCloudburst += $transaction["amount"];
+            }
+        }
+    }
+
+    $monthlyCloudburst[$month] = $gainedCloudburst;
+    $monthlyRaindrops[$month] = $gainedRaindrops;
+}
+
+uksort($monthlyCloudburst, function ($k1, $k2) {
+    return strtotime($k2) - strtotime($k1);
+});
+
+uksort($monthlyRaindrops, function ($k1, $k2) {
+    return strtotime($k2) - strtotime($k1);
+});
+
+function getMonthlyEarnings(): array {
+    global $monthlyRaindrops;
+    global $monthlyCloudburst;
+
+    return [
+        "cloudburst" => array_sum(array_values($monthlyCloudburst)) / count($monthlyCloudburst),
+        "raindrops" => array_sum(array_values($monthlyRaindrops)) / count($monthlyRaindrops)
+    ];
+}
 
 ?>
 
@@ -267,7 +337,21 @@ require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/components/header.inc';
                 return $a + $b;
             });
 
-            ?>£<?= number_format($allAccounts, 2, '.', ',') ?>)</h4>
+            ?>£<?= number_format($allAccounts, 2, '.', ',') ?>, earning £<?= number_format(getMonthlyEarnings()["cloudburst"], 2, '.', ',') ?>/month)</h4>
+        <div class="list-group">
+            <details class="list-group-item list-group-item-action" style="margin-bottom: 10px;">
+                <summary>Show monthly earnings</summary>
+
+                <table style="margin-top: 10px;">
+                    <?php foreach ($monthlyCloudburst as $month => $value): ?>
+                        <tr>
+                            <td style="padding-right: 20px;"><b><?= date('F Y', strtotime($month)) ?>:</b></td>
+                            <td class="text-<?= $value > 0 ? "success" : ($value === 0 ? "warning" : "danger") ?>">£<?= number_format($value, 2, '.', ',') ?></td>
+                        </tr>
+                    <?php endforeach; ?>
+                </table>
+            </details>
+        </div>
         <div style="display: grid; grid-template-columns: repeat(3, 1fr); grid-gap: 20px;">
             <?php foreach ($accounts as $index => $account): if ($account["owner"] === "cloudburst"): ?>
                 <a style="color: white; text-decoration: none;" href="/-/money/<?= $account["_name"] ?>">
@@ -385,7 +469,21 @@ require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/components/header.inc';
                 return $a + $b;
             });
 
-            ?>€<?= number_format($allAccounts, 2, '.', ',') ?>)</h4>
+            ?>€<?= number_format($allAccounts, 2, '.', ',') ?>, earning €<?= number_format(getMonthlyEarnings()["raindrops"], 2, '.', ',') ?>/month)</h4>
+        <div class="list-group">
+            <details class="list-group-item list-group-item-action" style="margin-bottom: 10px;">
+                <summary>Show monthly earnings</summary>
+
+                <table style="margin-top: 10px;">
+                    <?php foreach ($monthlyRaindrops as $month => $value): ?>
+                        <tr>
+                            <td style="padding-right: 20px;"><b><?= date('F Y', strtotime($month)) ?>:</b></td>
+                            <td class="text-<?= $value > 0 ? "success" : ($value === 0 ? "warning" : "danger") ?>">€<?= number_format($value, 2, '.', ',') ?></td>
+                        </tr>
+                    <?php endforeach; ?>
+                </table>
+            </details>
+        </div>
         <div style="display: grid; grid-template-columns: repeat(3, 1fr); grid-gap: 20px;">
             <?php foreach ($accounts as $index => $account): if ($account["owner"] === "raindrops"): ?>
                 <a style="color: white; text-decoration: none;" href="/-/money/<?= $account["_name"] ?>">
@@ -423,6 +521,26 @@ require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/components/header.inc';
         </div>
         <p style="text-align: center; margin-top: 5px;" class="<?= $allAccounts > $minimumRaindrops ? "" : "bold text-danger" ?>">€<?= number_format($difference, 2, '.', ',') ?><?php if ($allAccounts > $minimumRaindrops): ?> (<?= round($part2 * 100, 2) ?>%)<?php endif; ?> <?= $allAccounts > $minimumRaindrops ? "over" : "under" ?> the minimum</p>
 
+        <?php if (isset($projects["raindrops"]) && $projects["raindrops"]["enable"]): ?>
+        <div class="grid" style="margin-bottom: 10px; display: grid; grid-template-columns: 25% 1fr; grid-gap: 20px;">
+            <div style="width: 100%; display: flex; align-items: center; justify-content: center;">
+                <img src="<?= $projects["raindrops"]["image"] ?>" style="width: 100%;">
+            </div>
+            <div style="display: flex; align-items: center;">
+                <div style="width: 100%;">
+                    <h2><?= strip_tags($projects["raindrops"]["name"]) ?></h2>
+                    <div class="progress" style="margin-top: 20px; margin-bottom: 20px; width: 100%; background-color: #222;">
+                        <div class="progress-bar bg-success" style="width: <?= ($allAccounts - $minimumRaindrops >= 0) ? (($allAccounts - $minimumRaindrops) / $projects["raindrops"]["cost"]) * 100 : 0 ?>%"></div>
+                    </div>
+                    <?php $missing = $projects["raindrops"]["cost"] - ($allAccounts - $minimumRaindrops); if ($missing > 0): $months = ceil($missing / getMonthlyEarnings()["raindrops"]); ?>
+                    <div>Costs €<?= number_format($projects["raindrops"]["cost"], 2, '.', ',') ?> · Missing €<?= number_format($missing, 2, '.', ',') ?> · Can afford it in <?= date('F Y', time() + ($months * 2678400)) ?> (in <?= $months ?> month<?= $months > 1 ? "s" : "" ?>)</div>
+                    <?php elseif ($missing === 0): ?><div>You can afford it now, this will take you to the minimum.</div>
+                    <?php else: ?><div>You can afford it now, this will take you €<?= -$missing ?> above the minimum.</div><?php endif; ?>
+                </div>
+            </div>
+        </div>
+        <?php endif; ?>
+
         <canvas id="history-raindrops" style="margin-top: 10px; width: 100%; height: 200px; max-height: 100%;"></canvas>
         <?php
 
@@ -582,7 +700,7 @@ require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/components/header.inc';
     <div class="list-group">
         <a href="#" data-bs-toggle="modal" data-bs-target="#create" class="list-group-item list-group-item-action" style="display: grid; grid-template-columns: max-content 1fr;"><img src="/assets/icons/add.svg" style="filter: invert(1); margin-right: 10px; height: 32px; width: 32px;"><div style="display: flex; align-items: center;"><b>Add new transaction</b></div></a>
         <?php foreach ($account["transactions"] as $index => $transaction): $member = getMemberWithoutSystem($transaction["author"]) ?? getMemberWithoutSystem("zdtsg"); ?>
-            <a id="transaction-<?= $index ?>" onclick="deleteTransaction(<?= $index ?>)" class="list-group-item list-group-item-action" style="display: grid; grid-template-columns: max-content 1fr;cursor:pointer;"><div style="display: flex; align-items: center;"><img src="<?= getAsset($member["_system"], $member["id"]) ?>" style="border-radius: 999px; width: 32px; height: 32px; margin-right: 10px;"></div><div style="display: flex; align-items: center;"><div><b><?= $member["display_name"] ?? $member["name"] ?></b><?= $transaction["amount"] < 0 ? " removed" : " added" ?>&nbsp;<span class="<?= $transaction["amount"] < 0 ? "text-danger" : "text-success" ?>"><?= $account["currency"] === "gbp" ? "£" : "€" ?><?= number_format(abs($transaction["amount"]), 2, '.', ',') ?>&nbsp;</span><?= timeAgo($transaction["date"]) ?><?php if (isset($transaction["description"]) && trim($transaction["description"]) !== ""): ?>: <?= strip_tags(trim($transaction["description"])) ?><?php endif; ?></div></div></a>
+            <a id="transaction-<?= $index ?>" onclick="deleteTransaction(<?= $index ?>)" class="list-group-item list-group-item-action" style="display: grid; grid-template-columns: max-content 1fr;cursor:pointer;"><div style="display: flex; align-items: center;"><img src="<?= getAsset($member["_system"], $member["id"]) ?>" style="border-radius: 999px; width: 32px; height: 32px; margin-right: 10px;"></div><div style="display: flex; align-items: center;"><div><b><?= $member["display_name"] ?? $member["name"] ?></b><?= $transaction["amount"] < 0 ? " removed" : " added" ?>&nbsp;<span class="<?= $transaction["amount"] < 0 ? "text-danger" : "text-success" ?>"><?= $account["currency"] === "gbp" ? "£" : "€" ?><?= number_format(abs($transaction["amount"]), 2, '.', ',') ?>&nbsp;</span><?= timeAgo($transaction["date"]) ?><?php if (isset($transaction["description"]) && trim($transaction["description"]) !== "" && (!isset($transaction["initial"]) || !$transaction["initial"])): ?>: <?= strip_tags(trim($transaction["description"])) ?><?php endif; ?><?php if (isset($transaction["initial"]) && $transaction["initial"]): ?> <span class="badge bg-secondary rounded-pill">Initial amount</span><?php endif; ?></div></div></a>
         <?php endforeach; ?>
     </div>
 
diff --git a/pages/pair.inc b/pages/pair.inc
index fa301ad..2fafc31 100644
--- a/pages/pair.inc
+++ b/pages/pair.inc
@@ -89,7 +89,7 @@ require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/components/header.inc'; glob
     const modal = new bootstrap.Modal(document.getElementById("confirm"));
 
     function getIconForName(name) {
-        if (name.startsWith("Luna Desktop ")) {
+        if (name.startsWith("Luna Desktop ") || name.startsWith("Luna Mobile ")) {
             return "https://git.equestria.dev/equestria.dev/luna/raw/branch/mane/icons/logo.png";
         }
 
-- 
cgit