PHP WebShell
Текущая директория: /var/www/bitcardoApp/user/security
Просмотр файла: limits.php
<?php
// user/security/limits.php
require_once __DIR__ . '/../../config/bootstrap.php';
if (empty($_SESSION['user_id'])) {
header("Location: /login.php");
exit();
}
$userId = (int)$_SESSION['user_id'];
/**
* ============================================
* Page Lock: Require password before access
* ============================================
* - Stores a short-lived "reauth" stamp in session
* - TTL default: 10 minutes
*/
$REAUTH_TTL = 10 * 60; // 10 minutes
$REAUTH_KEY = 'reauth_limits_ts';
$lockError = '';
if (empty($_SESSION['csrf_limits'])) {
$_SESSION['csrf_limits'] = bin2hex(random_bytes(16));
}
function get_user_password_hash($conn, int $userId): ?string {
$hash = null;
if ($st = $conn->prepare("SELECT password_hash FROM users WHERE user_id=? LIMIT 1")) {
$st->bind_param('i', $userId);
$st->execute();
$st->bind_result($hash);
$st->fetch();
$st->close();
}
return $hash ?: null;
}
function needs_reauth(int $ttl, string $key): bool {
if (empty($_SESSION[$key])) return true;
$ts = (int)$_SESSION[$key];
return ($ts <= 0) || ((time() - $ts) > $ttl);
}
// Handle re-auth submit
if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'reauth_limits') {
$csrf = (string)($_POST['csrf'] ?? '');
$pwd = (string)($_POST['password'] ?? '');
if (!hash_equals((string)($_SESSION['csrf_limits'] ?? ''), $csrf)) {
$lockError = "Security check failed. Please try again.";
} else {
$hash = get_user_password_hash($conn, $userId);
if (!$hash) {
$lockError = "Unable to verify your account right now.";
} elseif (!password_verify($pwd, $hash)) {
$lockError = "Incorrect password. Please try again.";
} else {
// OK
$_SESSION[$REAUTH_KEY] = time();
// Redirect back (preserve wallet_id if present)
$wallet_id = isset($_GET['wallet_id']) ? (int)$_GET['wallet_id'] : 0;
$redirect = "/user/security/limits.php";
if ($wallet_id > 0) $redirect .= "?wallet_id=" . $wallet_id;
header("Location: " . $redirect);
exit();
}
}
}
// Gate: if not recently authenticated, show password prompt and exit
if (needs_reauth($REAUTH_TTL, $REAUTH_KEY)) {
$wallet_id = isset($_GET['wallet_id']) ? (int)$_GET['wallet_id'] : 0;
$actionUrl = "/user/security/limits.php" . ($wallet_id > 0 ? "?wallet_id=" . $wallet_id : "");
include '../common/header.php';
?>
<div class="container mt-3">
<div class="row">
<? include '../common/nav.php'; ?>
<main class="col-md-9 col-lg-10 px-md-5 mb-5">
<? include '../common/page-header.php'; ?>
<div class="container my-5 px-md-5 ms-md-4">
<div class="row justify-content-center">
<div class="col-12 col-md-7 col-lg-5">
<div class="card-soft">
<div class="d-flex align-items-center justify-content-between mb-2">
<div>
<h5 class="mb-0">Confirm it’s you</h5>
<div class="text-muted small">Enter your password to view and manage withdrawal limits.</div>
</div>
<a href="/user/security/security_privacy.php" class="btn btn-outline-secondary" style="padding:4px 10px;font-size:.80rem;border-radius:10px;">
<i class="bi bi-arrow-left"></i> Back
</a>
</div>
<?php if ($lockError): ?>
<div class="alert alert-danger mt-3 mb-0"><?= htmlspecialchars($lockError) ?></div>
<?php endif; ?>
<form method="post" action="<?= htmlspecialchars($actionUrl) ?>" class="mt-3">
<input type="hidden" name="action" value="reauth_limits">
<input type="hidden" name="csrf" value="<?= htmlspecialchars((string)$_SESSION['csrf_limits']) ?>">
<label class="form-label">Password</label>
<input type="password" name="password" class="form-control" placeholder="Enter your password" required>
<button type="submit" class="btn btn-dark w-100 mt-3">
Continue
</button>
<div class="text-muted small mt-2">
This step helps keep your account safe.
</div>
</form>
</div>
</div>
</div>
</div>
</main>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/owl.carousel.min.js"></script>
<? include '../common/footer.php'; ?>
<?php
exit();
}
/**
* ============================================
* Normal page code starts here (authenticated)
* ============================================
*/
$errors = [];
$success = '';
if (!empty($_GET['saved'])) {
$success = "Withdrawal limits saved successfully.";
}
// ------------------------------------
// Fetch user level caps + level_name
// ------------------------------------
$levelName = 'Starter';
$cap_withdraw_usd = 0.00;
$cap_daily_usd = 0.00;
$cap_withdraw_ngn = 0.00;
$cap_daily_ngn = 0.00;
$sqlCaps = "
SELECT
COALESCE(ul.level_name, 'Starter') AS level_name,
COALESCE(ul.withdraw_limit, 0) AS withdraw_limit_usd,
COALESCE(ul.daily_withdraw_limit, 0) AS daily_withdraw_limit_usd,
COALESCE(ul.withdraw_limit_ngn, 0) AS withdraw_limit_ngn,
COALESCE(ul.daily_withdraw_limit_ngn, 0) AS daily_withdraw_limit_ngn
FROM users u
LEFT JOIN user_level ul ON ul.level_id = u.level_id
WHERE u.user_id = ?
LIMIT 1
";
if ($st = $conn->prepare($sqlCaps)) {
$st->bind_param('i', $userId);
$st->execute();
$st->bind_result($levelName, $cap_withdraw_usd, $cap_daily_usd, $cap_withdraw_ngn, $cap_daily_ngn);
$st->fetch();
$st->close();
}
$cap_withdraw_usd = (float)$cap_withdraw_usd;
$cap_daily_usd = (float)$cap_daily_usd;
$cap_withdraw_ngn = (float)$cap_withdraw_ngn;
$cap_daily_ngn = (float)$cap_daily_ngn;
// ------------------------------------
// Fetch user's wallets
// ------------------------------------
$wallets = [];
$sqlWallets = "
SELECT wallet_id, coin, label, wallet_add,
COALESCE(withdraw_single_limit, 0) AS withdraw_single_limit,
COALESCE(withdraw_daily_limit, 0) AS withdraw_daily_limit
FROM user_wallets
WHERE user_id = ?
ORDER BY
CASE WHEN coin='NGN' THEN 0 ELSE 1 END,
coin ASC,
wallet_id DESC
";
if ($st = $conn->prepare($sqlWallets)) {
$st->bind_param('i', $userId);
$st->execute();
$res = $st->get_result();
while ($row = $res->fetch_assoc()) {
$wallets[] = $row;
}
$st->close();
}
// Build summary: all wallets with any limit set
$setLimits = [];
foreach ($wallets as $w) {
$s = (float)($w['withdraw_single_limit'] ?? 0);
$d = (float)($w['withdraw_daily_limit'] ?? 0);
if ($s > 0 || $d > 0) {
$setLimits[] = $w;
}
}
// Determine selected wallet (GET only)
$selectedWalletId = 0;
if (isset($_GET['wallet_id']) && is_numeric($_GET['wallet_id'])) {
$selectedWalletId = (int)$_GET['wallet_id'];
}
// Dropdown: remove ANY wallet where a limit is already set (single>0 OR daily>0)
$dropdownWallets = [];
foreach ($wallets as $w) {
$s = (float)($w['withdraw_single_limit'] ?? 0);
$d = (float)($w['withdraw_daily_limit'] ?? 0);
if (!($s > 0 || $d > 0)) {
$dropdownWallets[] = $w;
}
}
// Allowed selected wallet must be from dropdownWallets
$selectedWalletIdAllowed = 0;
if (!empty($dropdownWallets)) {
$selectedWalletIdAllowed = (int)$dropdownWallets[0]['wallet_id'];
if ($selectedWalletId > 0) {
foreach ($dropdownWallets as $w) {
if ((int)$w['wallet_id'] === $selectedWalletId) {
$selectedWalletIdAllowed = $selectedWalletId;
break;
}
}
}
}
// Load selected wallet (only from allowed list)
$sel = null;
if ($selectedWalletIdAllowed > 0) {
$sqlSel = "
SELECT wallet_id, coin, label, wallet_add,
COALESCE(withdraw_single_limit, 0) AS withdraw_single_limit,
COALESCE(withdraw_daily_limit, 0) AS withdraw_daily_limit
FROM user_wallets
WHERE wallet_id = ? AND user_id = ?
LIMIT 1
";
if ($st = $conn->prepare($sqlSel)) {
$st->bind_param('ii', $selectedWalletIdAllowed, $userId);
$st->execute();
$res = $st->get_result();
$sel = $res ? $res->fetch_assoc() : null;
$st->close();
}
}
// Handle SAVE (POST only)
if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'save_limit') {
$postWalletId = (isset($_POST['wallet_id']) && is_numeric($_POST['wallet_id'])) ? (int)$_POST['wallet_id'] : 0;
// Must be in dropdownWallets (i.e., no limits set yet)
$allowed = false;
foreach ($dropdownWallets as $w) {
if ((int)$w['wallet_id'] === $postWalletId) {
$allowed = true;
break;
}
}
if (!$allowed) {
$errors[] = "This wallet is not eligible for setting a new limit.";
} else {
$selPost = null;
$sqlSel2 = "SELECT wallet_id, coin FROM user_wallets WHERE wallet_id=? AND user_id=? LIMIT 1";
if ($st = $conn->prepare($sqlSel2)) {
$st->bind_param('ii', $postWalletId, $userId);
$st->execute();
$res = $st->get_result();
$selPost = $res ? $res->fetch_assoc() : null;
$st->close();
}
if (!$selPost) {
$errors[] = "Please select a valid wallet.";
} else {
$coin = strtoupper(trim((string)($selPost['coin'] ?? '')));
$single = isset($_POST['withdraw_single_limit']) ? (float)$_POST['withdraw_single_limit'] : -1;
$daily = isset($_POST['withdraw_daily_limit']) ? (float)$_POST['withdraw_daily_limit'] : -1;
if ($single < 0) $errors[] = "Single transfer limit must be 0 or higher.";
if ($daily < 0) $errors[] = "Daily limit must be 0 or higher.";
if ($single >= 0 && $daily >= 0 && $daily > 0 && $single > $daily) {
$errors[] = "Daily limit must be equal to or greater than single transfer limit.";
}
if (empty($errors)) {
if ($coin === 'NGN') {
if ($single > $cap_withdraw_ngn) $errors[] = "Single transfer limit cannot exceed your level cap (" . number_format($cap_withdraw_ngn, 2) . " NGN).";
if ($daily > $cap_daily_ngn) $errors[] = "Daily limit cannot exceed your level cap (" . number_format($cap_daily_ngn, 2) . " NGN).";
} else {
if ($single > $cap_withdraw_usd) $errors[] = "Single transfer limit cannot exceed your level cap (" . number_format($cap_withdraw_usd, 2) . " USD).";
if ($daily > $cap_daily_usd) $errors[] = "Daily limit cannot exceed your level cap (" . number_format($cap_daily_usd, 2) . " USD).";
}
}
if (empty($errors)) {
$sqlUp = "
UPDATE user_wallets
SET withdraw_single_limit = ?, withdraw_daily_limit = ?, updated_at = CURRENT_TIMESTAMP
WHERE wallet_id = ? AND user_id = ?
LIMIT 1
";
if ($up = $conn->prepare($sqlUp)) {
$up->bind_param('ddii', $single, $daily, $postWalletId, $userId);
if ($up->execute()) {
header("Location: /user/security/limits.php?saved=1");
exit();
} else {
$errors[] = "Unable to save limits. Please try again.";
}
$up->close();
} else {
$errors[] = "Unable to save limits right now.";
}
}
}
}
}
// UI values
$selectedCoin = $sel ? strtoupper(trim((string)($sel['coin'] ?? ''))) : '';
$unit = ($selectedCoin === 'NGN') ? 'NGN' : 'USD';
$capSingle = ($selectedCoin === 'NGN') ? $cap_withdraw_ngn : $cap_withdraw_usd;
$capDaily = ($selectedCoin === 'NGN') ? $cap_daily_ngn : $cap_daily_usd;
$currentSingle = $sel ? (float)($sel['withdraw_single_limit'] ?? 0) : 0.00;
$currentDaily = $sel ? (float)($sel['withdraw_daily_limit'] ?? 0) : 0.00;
include '../common/header.php';
?>
<style>
.btn-xxs{
padding: 1px 6px;
font-size: .70rem;
line-height: 1.1;
border-radius: 999px;
}
.limits-card{
padding: 10px 12px !important;
border-radius: 14px;
}
.limits-card hr{
margin: 8px 0;
opacity: .20;
}
.limits-title{
font-size: .92rem;
font-weight: 700;
}
.limit-label{
font-size: .72rem;
color: rgba(85, 84, 84, 0.7);
margin-bottom: 2px;
display: block;
}
.limit-amount{
font-size: .82rem;
font-weight: 600;
line-height: 1.1;
}
.back-btn-sm{
padding: 4px 10px;
font-size: .80rem;
border-radius: 10px;
}
</style>
<div class="container mt-3">
<div class="row">
<? include '../common/nav.php'; ?>
<main class="col-md-9 col-lg-10 px-md-5 mb-5">
<? include '../common/page-header.php'; ?>
<div class="container my-5 px-md-5 ms-md-4">
<div class="d-flex align-items-center justify-content-between mb-3">
<div>
<h5 class="mb-0">Withdrawal limit</h5>
<div class="text-muted small">Set single transfer and daily withdrawal limits per wallet.</div>
</div>
<a href="/user/security/security_privacy.php" class="btn btn-sm btn-outline-secondary back-btn-sm">
<i class="bi bi-arrow-left"></i> Back
</a>
</div>
<?php if ($success): ?>
<div class="alert alert-success"><?= htmlspecialchars($success) ?></div>
<?php endif; ?>
<?php if (!empty($errors)): ?>
<div class="alert alert-danger">
<strong>Please fix the following:</strong>
<ul class="mb-0">
<?php foreach ($errors as $e): ?><li><?= htmlspecialchars($e) ?></li><?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<div class="mb-3 text-muted small">
<strong>Account level:</strong> <?= htmlspecialchars((string)$levelName) ?> <br>
<span class="ms-2">
<strong>USD caps:</strong> Single <?= number_format($cap_withdraw_usd, 2) ?>, Daily <?= number_format($cap_daily_usd, 2) ?>
</span> <br>
<span class="ms-2">
<strong>NGN caps:</strong> Single <?= number_format($cap_withdraw_ngn, 2) ?>, Daily <?= number_format($cap_daily_ngn, 2) ?>
</span>
</div>
<?php if (empty($wallets)): ?>
<div class="card-soft">
<div class="text-muted">No wallet found for your account.</div>
</div>
<?php else: ?>
<?php if (!empty($setLimits)): ?>
<h6 class="section-title">Your set limits</h6>
<div class="row g-2 mb-3">
<?php foreach ($setLimits as $w): ?>
<?php
$wid = (int)$w['wallet_id'];
$coin = strtoupper(trim((string)($w['coin'] ?? '')));
$u = ($coin === 'NGN') ? 'NGN' : 'USD';
$single = (float)($w['withdraw_single_limit'] ?? 0);
$daily = (float)($w['withdraw_daily_limit'] ?? 0);
?>
<div class="col-12 col-md-6 col-lg-4">
<div class="card-soft limits-card h-100">
<div class="d-flex justify-content-between align-items-start">
<div class="limits-title"><?= htmlspecialchars($coin) ?> Wallet</div>
<a class="btn btn-outline-secondary btn-xxs"
href="/user/security/limits.php?wallet_id=<?= $wid ?>">
Edit
</a>
</div>
<hr>
<div class="d-flex justify-content-between">
<div>
<span class="limit-label">Single transfer</span>
<div class="limit-amount"><?= number_format($single, 2) ?> <?= htmlspecialchars($u) ?></div>
</div>
<div class="text-end">
<span class="limit-label">Daily limit</span>
<div class="limit-amount"><?= number_format($daily, 2) ?> <?= htmlspecialchars($u) ?></div>
</div>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
<h6 class="section-title">Set limits</h6>
<div class="card-soft">
<div class="mb-3">
<label class="form-label">Select wallet</label>
<select class="form-select" onchange="if(this.value){window.location='?wallet_id='+this.value;}">
<option value="">Choose a wallet</option>
<?php foreach ($dropdownWallets as $w): ?>
<?php
$wid = (int)$w['wallet_id'];
$coin = strtoupper((string)($w['coin'] ?? ''));
$lab = trim((string)($w['label'] ?? ''));
$addr = trim((string)($w['wallet_add'] ?? ''));
$title = $coin . ($lab ? " • " . $lab : "") . ($addr ? " • " . substr($addr, 0, 10) . "..." : "");
?>
<option value="<?= $wid ?>" <?= ($selectedWalletIdAllowed === $wid) ? 'selected' : '' ?>>
<?= htmlspecialchars($title) ?>
</option>
<?php endforeach; ?>
</select>
<div class="form-text">
NGN wallet uses NGN values. Other wallets use USD values.
</div>
<?php if (empty($dropdownWallets)): ?>
<div class="text-muted small mt-2">
All wallets already have withdrawal limits set.
</div>
<?php endif; ?>
</div>
<?php if (!$sel): ?>
<div class="text-muted">Select a wallet to set limits.</div>
<?php else: ?>
<form method="post" action="">
<input type="hidden" name="action" value="save_limit">
<input type="hidden" name="wallet_id" value="<?= (int)$selectedWalletIdAllowed ?>">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label">Single transfer limit (<?= htmlspecialchars($unit) ?>)</label>
<input
type="number"
step="0.01"
min="0"
name="withdraw_single_limit"
class="form-control"
value="<?= htmlspecialchars(number_format($currentSingle, 2, '.', '')) ?>"
placeholder="0.00"
required
>
<div class="form-text">Cap: <?= number_format($capSingle, 2) ?> <?= htmlspecialchars($unit) ?></div>
</div>
<div class="col-md-6">
<label class="form-label">Daily limit (<?= htmlspecialchars($unit) ?>)</label>
<input
type="number"
step="0.01"
min="0"
name="withdraw_daily_limit"
class="form-control"
value="<?= htmlspecialchars(number_format($currentDaily, 2, '.', '')) ?>"
placeholder="0.00"
required
>
<div class="form-text">Cap: <?= number_format($capDaily, 2) ?> <?= htmlspecialchars($unit) ?></div>
</div>
<div class="col-12 mt-2">
<button type="submit" class="btn btn-dark">
<i class="bi bi-save2"></i> Save limits
</button>
</div>
</div>
</form>
<?php endif; ?>
</div>
<?php endif; ?>
</div>
</main>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/owl.carousel.min.js"></script>
<? include '../common/footer.php'; ?>
Выполнить команду
Для локальной разработки. Не используйте в интернете!