|
|
<?php |
|
|
ini_set('display_errors', 1); |
|
|
ini_set('display_startup_errors', 1); |
|
|
error_reporting(E_ALL); |
|
|
|
|
|
session_start(); |
|
|
if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true) { |
|
|
header('Location: ../../index.php'); |
|
|
exit; |
|
|
} |
|
|
|
|
|
|
|
|
require_once '../models/TokenManager.php'; |
|
|
$tokenManager = new TokenManager(); |
|
|
|
|
|
|
|
|
$user_id = $_SESSION['user_id'] ?? 1; |
|
|
$username = $_SESSION['username'] ?? 'User'; |
|
|
$email = $_SESSION['email'] ?? ''; |
|
|
$tier = $_SESSION['tier'] ?? 'Standard'; |
|
|
$package = $_SESSION['package'] ?? ''; |
|
|
$balance = $_SESSION['balance'] ?? 0; |
|
|
$total_deposits = $_SESSION['total_deposits'] ?? 0; |
|
|
$total_withdrawals = $_SESSION['total_withdrawals'] ?? 0; |
|
|
$rewards = $_SESSION['rewards'] ?? 0; |
|
|
$earnings = $total_deposits - $total_withdrawals; |
|
|
|
|
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') { |
|
|
if (isset($_POST['generate_token'])) { |
|
|
$token_name = $_POST['token_name']; |
|
|
$expiry_days = $_POST['token_expiry']; |
|
|
$permissions = []; |
|
|
|
|
|
if (isset($_POST['permission_read'])) $permissions[] = 'read'; |
|
|
if (isset($_POST['permission_write'])) $permissions[] = 'write'; |
|
|
if (isset($_POST['permission_delete'])) $permissions[] = 'delete'; |
|
|
if (isset($_POST['permission_admin'])) $permissions[] = 'admin'; |
|
|
|
|
|
$ip_restrictions = !empty($_POST['token_ip']) ? $_POST['token_ip'] : null; |
|
|
|
|
|
$result = $tokenManager->createToken($user_id, $token_name, $permissions, $expiry_days, $ip_restrictions); |
|
|
|
|
|
if ($result['success']) { |
|
|
$_SESSION['new_token'] = $result['token']; |
|
|
$_SESSION['token_details'] = [ |
|
|
'name' => $token_name, |
|
|
'expiry' => $expiry_days == 0 ? 'Never' : $expiry_days . ' days', |
|
|
'permissions' => implode(', ', $permissions) |
|
|
]; |
|
|
header('Location: access-token.php?success=1'); |
|
|
exit; |
|
|
} |
|
|
} |
|
|
|
|
|
if (isset($_POST['revoke_token'])) { |
|
|
$token_id = $_POST['token_id']; |
|
|
$tokenManager->revokeToken($token_id, $user_id); |
|
|
header('Location: access-token.php?revoked=1'); |
|
|
exit; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
$user_tokens = $tokenManager->getUserTokens($user_id); |
|
|
$active_tokens_count = count($user_tokens); |
|
|
$token_limit = 5; |
|
|
|
|
|
|
|
|
$realtime_stats = $tokenManager->getRealtimeStats($user_id, 24); |
|
|
?> |
|
|
|
|
|
<!DOCTYPE html> |
|
|
<html lang="en"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title>Japanese Motors — Access Token</title> |
|
|
<script src="https://cdn.tailwindcss.com"></script> |
|
|
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700;800&display=swap" rel="stylesheet"> |
|
|
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script> |
|
|
<style> |
|
|
:root { |
|
|
--bg: |
|
|
--card: |
|
|
--card-2: |
|
|
--accent: |
|
|
--muted: rgba(255,255,255,0.6); |
|
|
--glass: rgba(255,255,255,0.04); |
|
|
--promo-gradient: linear-gradient(180deg,#a13df0 0%, #ff2a79 50%, #d70b1a 100%); |
|
|
font-family: 'Poppins', system-ui, Arial; |
|
|
--banner-gradient-start: |
|
|
--banner-gradient-end: |
|
|
--spacing-unit: 1rem; |
|
|
--accent-primary: |
|
|
--accent-secondary: |
|
|
--shadow-hover: 0 6px 18px rgba(0, 0, 0, 0.1); |
|
|
--premium-gold: |
|
|
} |
|
|
|
|
|
body { |
|
|
background: var(--bg); |
|
|
font-family: 'Poppins', sans-serif; |
|
|
transition: all 0.3s ease; |
|
|
min-height: 100vh; |
|
|
margin: 0; |
|
|
padding: 0; |
|
|
} |
|
|
|
|
|
.sidebar { |
|
|
width: 250px; |
|
|
height: 100vh; |
|
|
background: |
|
|
color: |
|
|
position: fixed; |
|
|
top: 0; |
|
|
left: -250px; |
|
|
transition: all 0.3s ease; |
|
|
z-index: 1000; |
|
|
overflow-y: auto; |
|
|
} |
|
|
|
|
|
.sidebar.active { |
|
|
left: 0; |
|
|
} |
|
|
|
|
|
|
|
|
margin-left: 0; |
|
|
transition: all 0.3s ease; |
|
|
width: 100%; |
|
|
min-height: 100vh; |
|
|
} |
|
|
|
|
|
.content-shifted { |
|
|
margin-left: 250px; |
|
|
width: calc(100% - 250px); |
|
|
} |
|
|
|
|
|
header { |
|
|
background: |
|
|
color: white; |
|
|
padding: 15px 20px; |
|
|
display: flex; |
|
|
justify-content: space-between; |
|
|
align-items: center; |
|
|
position: relative; |
|
|
z-index: 900; |
|
|
transition: all 0.3s ease; |
|
|
width: 100%; |
|
|
} |
|
|
|
|
|
.menu-toggle { |
|
|
background: transparent; |
|
|
border: none; |
|
|
color: white; |
|
|
font-size: 1.5rem; |
|
|
cursor: pointer; |
|
|
z-index: 1001; |
|
|
} |
|
|
|
|
|
.logo-section { |
|
|
padding: 15px; |
|
|
border-bottom: 1px solid |
|
|
display: flex; |
|
|
align-items: center; |
|
|
gap: 10px; |
|
|
} |
|
|
|
|
|
.brand { |
|
|
font-size: 1.2rem; |
|
|
font-weight: 700; |
|
|
color: |
|
|
} |
|
|
|
|
|
.subtitle { |
|
|
font-size: 0.75rem; |
|
|
color: |
|
|
} |
|
|
|
|
|
.menu { |
|
|
list-style: none; |
|
|
padding: 0; |
|
|
margin: 0; |
|
|
} |
|
|
|
|
|
.menu li a { |
|
|
display: flex; |
|
|
align-items: center; |
|
|
padding: 12px 20px; |
|
|
color: white; |
|
|
text-decoration: none; |
|
|
transition: background 0.3s; |
|
|
border-left: 4px solid transparent; |
|
|
} |
|
|
|
|
|
.menu li a:hover { |
|
|
background: |
|
|
} |
|
|
|
|
|
.menu li a.active-page { |
|
|
background: |
|
|
border-left-color: var(--accent); |
|
|
} |
|
|
|
|
|
.menu li a i { |
|
|
margin-right: 12px; |
|
|
width: 16px; |
|
|
text-align: center; |
|
|
} |
|
|
|
|
|
.user-footer { |
|
|
padding: 15px; |
|
|
background: |
|
|
display: flex; |
|
|
align-items: center; |
|
|
gap: 10px; |
|
|
position: sticky; |
|
|
bottom: 0; |
|
|
} |
|
|
|
|
|
.avatar { |
|
|
width: 35px; |
|
|
height: 35px; |
|
|
background: |
|
|
border-radius: 50%; |
|
|
display: flex; |
|
|
align-items: center; |
|
|
justify-content: center; |
|
|
font-weight: bold; |
|
|
color: white; |
|
|
} |
|
|
|
|
|
.banner { |
|
|
max-width: 450px; |
|
|
margin: 0 auto 2rem; |
|
|
background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary)); |
|
|
border-radius: 12px; |
|
|
padding: 1.5rem; |
|
|
text-align: center; |
|
|
box-shadow: var(--shadow-hover); |
|
|
animation: fadeIn 0.5s ease; |
|
|
} |
|
|
|
|
|
@keyframes fadeIn { |
|
|
from { opacity: 0; transform: translateY(20px); } |
|
|
to { opacity: 1; transform: translateY(0); } |
|
|
} |
|
|
|
|
|
.banner .title { |
|
|
font-size: 1.25rem; |
|
|
margin-bottom: 1rem; |
|
|
color: |
|
|
font-weight: 700; |
|
|
} |
|
|
|
|
|
.banner p { |
|
|
font-size: 0.95rem; |
|
|
line-height: 1.6; |
|
|
margin-bottom: 1rem; |
|
|
color: var(--premium-gold); |
|
|
} |
|
|
|
|
|
.banner .footer { |
|
|
font-size: 0.75rem; |
|
|
color: rgba(255, 255, 255, 0.9); |
|
|
font-style: italic; |
|
|
} |
|
|
|
|
|
.card { |
|
|
background: var(--card); |
|
|
border-radius: 12px; |
|
|
padding: 1.5rem; |
|
|
color: white; |
|
|
box-shadow: 0 6px 0 rgba(0,0,0,0.08) inset; |
|
|
} |
|
|
|
|
|
.balance { |
|
|
background: rgba(255,255,255,0.03); |
|
|
padding: 1rem; |
|
|
border-radius: 10px; |
|
|
margin: 1rem 0; |
|
|
display: flex; |
|
|
align-items: center; |
|
|
justify-content: space-between; |
|
|
} |
|
|
|
|
|
.form-group { |
|
|
margin: 1rem 0; |
|
|
} |
|
|
|
|
|
label { |
|
|
display: block; |
|
|
margin-bottom: 0.5rem; |
|
|
color: rgba(255,255,255,0.85); |
|
|
} |
|
|
|
|
|
input, select, textarea { |
|
|
width: 100%; |
|
|
padding: 0.75rem; |
|
|
border-radius: 10px; |
|
|
border: 1px solid rgba(255,255,255,0.1); |
|
|
background: rgba(255,255,255,0.05); |
|
|
color: white; |
|
|
box-sizing: border-box; |
|
|
} |
|
|
|
|
|
input:focus, select:focus, textarea:focus { |
|
|
outline: none; |
|
|
border-color: var(--accent); |
|
|
} |
|
|
|
|
|
.btn { |
|
|
display: inline-block; |
|
|
padding: 0.75rem 1.5rem; |
|
|
border-radius: 10px; |
|
|
background: var(--accent); |
|
|
color: |
|
|
font-weight: 700; |
|
|
border: none; |
|
|
cursor: pointer; |
|
|
width: 100%; |
|
|
transition: all 0.3s ease; |
|
|
} |
|
|
|
|
|
.btn:hover { |
|
|
transform: translateY(-2px); |
|
|
box-shadow: 0 4px 12px rgba(0,0,0,0.2); |
|
|
} |
|
|
|
|
|
.btn-outline { |
|
|
background: transparent; |
|
|
border: 2px solid var(--accent); |
|
|
color: var(--accent); |
|
|
} |
|
|
|
|
|
.btn-disabled { |
|
|
background: rgba(255,255,255,0.1); |
|
|
color: rgba(255,255,255,0.5); |
|
|
cursor: not-allowed; |
|
|
} |
|
|
|
|
|
.btn-disabled:hover { |
|
|
transform: none; |
|
|
box-shadow: none; |
|
|
} |
|
|
|
|
|
.dashboard-card { |
|
|
background: rgba(0,0,0,0.2); |
|
|
border-radius: 12px; |
|
|
padding: 1.5rem; |
|
|
margin-bottom: 1.5rem; |
|
|
} |
|
|
|
|
|
.stat-card { |
|
|
background: rgba(0,0,0,0.15); |
|
|
border-radius: 10px; |
|
|
padding: 1rem; |
|
|
margin-bottom: 1rem; |
|
|
transition: transform 0.3s ease; |
|
|
} |
|
|
|
|
|
.stat-card:hover { |
|
|
transform: translateY(-2px); |
|
|
} |
|
|
|
|
|
.faq-item { |
|
|
background: rgba(0,0,0,0.15); |
|
|
border-radius: 10px; |
|
|
padding: 1rem; |
|
|
margin-bottom: 1rem; |
|
|
cursor: pointer; |
|
|
transition: all 0.3s ease; |
|
|
} |
|
|
|
|
|
.faq-item:hover { |
|
|
background: rgba(0,0,0,0.25); |
|
|
} |
|
|
|
|
|
.faq-answer { |
|
|
display: none; |
|
|
padding-top: 0.75rem; |
|
|
color: var(--muted); |
|
|
} |
|
|
|
|
|
.confirmation-modal { |
|
|
display: none; |
|
|
position: fixed; |
|
|
top: 0; |
|
|
left: 0; |
|
|
width: 100%; |
|
|
height: 100%; |
|
|
background: rgba(0,0,0,0.7); |
|
|
z-index: 2000; |
|
|
justify-content: center; |
|
|
align-items: center; |
|
|
} |
|
|
|
|
|
.modal-content { |
|
|
background: var(--card); |
|
|
border-radius: 12px; |
|
|
padding: 2rem; |
|
|
width: 90%; |
|
|
max-width: 500px; |
|
|
color: white; |
|
|
margin: 1rem; |
|
|
} |
|
|
|
|
|
.token-display { |
|
|
background: rgba(0,0,0,0.2); |
|
|
border-radius: 10px; |
|
|
padding: 1rem; |
|
|
margin: 1rem 0; |
|
|
font-family: monospace; |
|
|
display: flex; |
|
|
justify-content: space-between; |
|
|
align-items: center; |
|
|
word-break: break-all; |
|
|
} |
|
|
|
|
|
.copy-btn { |
|
|
background: var(--accent); |
|
|
color: |
|
|
border: none; |
|
|
border-radius: 5px; |
|
|
padding: 0.5rem 1rem; |
|
|
cursor: pointer; |
|
|
font-weight: 600; |
|
|
transition: all 0.3s ease; |
|
|
white-space: nowrap; |
|
|
margin-left: 1rem; |
|
|
} |
|
|
|
|
|
.copy-btn:hover { |
|
|
transform: translateY(-1px); |
|
|
} |
|
|
|
|
|
.overlay { |
|
|
display: none; |
|
|
position: fixed; |
|
|
top: 0; |
|
|
left: 0; |
|
|
width: 100%; |
|
|
height: 100%; |
|
|
background: rgba(0,0,0,0.5); |
|
|
z-index: 999; |
|
|
} |
|
|
|
|
|
.overlay.active { |
|
|
display: block; |
|
|
} |
|
|
|
|
|
@media (max-width: 768px) { |
|
|
.sidebar { |
|
|
width: 100%; |
|
|
left: -100%; |
|
|
} |
|
|
|
|
|
.sidebar.active { |
|
|
left: 0; |
|
|
} |
|
|
|
|
|
.content-shifted { |
|
|
margin-left: 0; |
|
|
width: 100%; |
|
|
} |
|
|
|
|
|
.overlay.active { |
|
|
display: block; |
|
|
} |
|
|
|
|
|
.grid-cols-1.md\:grid-cols-3 { |
|
|
grid-template-columns: 1fr; |
|
|
} |
|
|
|
|
|
.dashboard-card.md\:col-span-2 { |
|
|
grid-column: 1; |
|
|
} |
|
|
} |
|
|
|
|
|
@media (min-width: 769px) { |
|
|
.overlay { |
|
|
display: none !important; |
|
|
} |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body> |
|
|
<!-- Overlay for mobile --> |
|
|
<div class="overlay" id="overlay"></div> |
|
|
|
|
|
<!-- Sidebar --> |
|
|
<aside class="sidebar" id="sidebar"> |
|
|
<div class="logo-section"> |
|
|
<i data-feather="zap" class="text-yellow-400"></i> |
|
|
<div> |
|
|
<h2 class="brand">JMOTORS</h2> |
|
|
<p class="subtitle">Marketing Platform</p> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<ul class="menu"> |
|
|
<li><a href="index.php"><i data-feather="home"></i> Dashboard</a></li> |
|
|
<li><a href="meta-uploads.php"><i data-feather="upload"></i> Meta Uploads</a></li> |
|
|
<li><a href="transactions.php"><i data-feather="repeat"></i> Transactions</a></li> |
|
|
<li><a href="transfer.php"><i data-feather="send"></i> Transfer</a></li> |
|
|
<li><a href="daily-product.php"><i data-feather="shopping-bag"></i> Daily Product</a></li> |
|
|
<li><a href="withdraw.php"><i data-feather="dollar-sign"></i> Withdraw</a></li> |
|
|
<li><a href="packages.php"><i data-feather="package"></i> Packages</a></li> |
|
|
<li><a href="loan.php"><i data-feather="credit-card"></i> Loan</a></li> |
|
|
<li><a href="recharge.php"><i data-feather="battery-charging"></i> Recharge</a></li> |
|
|
<li><a href="agent-approval.php"><i data-feather="user-check"></i> Agent Approval</a></li> |
|
|
<li><a href="access-token.php" class="active-page"><i data-feather="key"></i> Access Token</a></li> |
|
|
<li><a href="agent-claim.php"><i data-feather="tag"></i> Agent Claim</a></li> |
|
|
<li><a href="team.php"><i data-feather="users"></i> Team</a></li> |
|
|
</ul> |
|
|
|
|
|
<ul class="menu"> |
|
|
<li><a href="profile.php"><i data-feather="user"></i> Profile</a></li> |
|
|
<li><a href="settings.php"><i data-feather="settings"></i> Settings</a></li> |
|
|
<li><a href="whatsapp-channel.php"><i data-feather="message-square"></i> Whatsapp Channel</a></li> |
|
|
<li><a href="customer-care.php"><i data-feather="headphones"></i> Customer Care</a></li> |
|
|
</ul> |
|
|
|
|
|
<div class="user-footer"> |
|
|
<div class="avatar"><?php echo substr($username, 0, 2); ?></div> |
|
|
<div> |
|
|
<h4><?php echo htmlspecialchars($username); ?></h4> |
|
|
<p><?php echo htmlspecialchars($tier); ?> - Marketer</p> |
|
|
</div> |
|
|
</div> |
|
|
</aside> |
|
|
|
|
|
<!-- Main Content --> |
|
|
<div id="content"> |
|
|
<header class="bg-gray-800 text-white p-4"> |
|
|
<div class="flex items-center"> |
|
|
<button class="menu-toggle" id="menu-toggle"> |
|
|
<i data-feather="menu"></i> |
|
|
</button> |
|
|
<div class="ml-4 font-bold text-xl">jmotors</div> |
|
|
</div> |
|
|
<nav class="flex items-center space-x-6"> |
|
|
<a href="transfer.php" class="hover:text-yellow-300">Transfer</a> |
|
|
<a href="loan.php" class="hover:text-yellow-300">Loans</a> |
|
|
<a href="daily-product.php" class="hover:text-yellow-300">New Product</a> |
|
|
<div class="w-9 h-9 rounded-full bg-gradient-to-r from-yellow-300 to-orange-400 flex items-center justify-center font-bold"> |
|
|
<?php echo substr($username, 0, 1); ?> |
|
|
</div> |
|
|
</nav> |
|
|
</header> |
|
|
|
|
|
<main class="p-4"> |
|
|
<!-- Success/Error Messages --> |
|
|
<?php if (isset($_GET['success'])): ?> |
|
|
<div class="bg-green-500 text-white p-3 rounded-lg mb-4"> |
|
|
Token generated successfully! |
|
|
</div> |
|
|
<?php endif; ?> |
|
|
|
|
|
<?php if (isset($_GET['revoked'])): ?> |
|
|
<div class="bg-yellow-500 text-white p-3 rounded-lg mb-4"> |
|
|
Token revoked successfully! |
|
|
</div> |
|
|
<?php endif; ?> |
|
|
|
|
|
<div class="banner"> |
|
|
<div class="title">🔑 API Access Tokens</div> |
|
|
<p>Generate and manage access tokens for API integration and secure authentication</p> |
|
|
<div class="footer">⚡ Secure authentication • API integration • Developer tools</div> |
|
|
</div> |
|
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mt-6"> |
|
|
<div class="dashboard-card md:col-span-2"> |
|
|
<h3 class="text-lg font-bold mb-4 flex items-center gap-2"> |
|
|
<i data-feather="key" class="text-blue-400"></i> Generate New Token |
|
|
</h3> |
|
|
|
|
|
<div class="balance"> |
|
|
<div> |
|
|
<p class="text-sm">Active Tokens</p> |
|
|
<h3 class="text-xl font-bold"><?php echo $active_tokens_count; ?>/<?php echo $token_limit; ?></h3> |
|
|
</div> |
|
|
<div class="text-right"> |
|
|
<p class="text-sm">Token Limit</p> |
|
|
<p class="font-bold"><?php echo $token_limit; ?> Maximum</p> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<?php if ($active_tokens_count >= $token_limit): ?> |
|
|
<div class="bg-red-500 bg-opacity-20 p-3 rounded-lg mb-4"> |
|
|
<i data-feather="alert-triangle" class="text-red-400 mr-2 inline"></i> |
|
|
You've reached the maximum number of active tokens. Please revoke an existing token to create a new one. |
|
|
</div> |
|
|
<?php else: ?> |
|
|
<form id="token-form" method="POST" action=""> |
|
|
<input type="hidden" name="generate_token" value="1"> |
|
|
|
|
|
<div class="form-group"> |
|
|
<label for="token-name">Token Name</label> |
|
|
<input type="text" id="token-name" name="token_name" placeholder="e.g., My App Integration" required> |
|
|
<p class="text-xs text-gray-400 mt-1">Use a descriptive name to identify this token's purpose</p> |
|
|
</div> |
|
|
|
|
|
<div class="form-group"> |
|
|
<label for="token-expiry">Expiration Period</label> |
|
|
<select id="token-expiry" name="token_expiry" required> |
|
|
<option value="7">7 days</option> |
|
|
<option value="30" selected>30 days</option> |
|
|
<option value="90">90 days</option> |
|
|
<option value="365">1 year</option> |
|
|
<option value="0">Never expire</option> |
|
|
</select> |
|
|
</div> |
|
|
|
|
|
<div class="form-group"> |
|
|
<label for="token-permissions">Permissions</label> |
|
|
<div class="grid grid-cols-2 gap-3 mt-2"> |
|
|
<div class="flex items-center"> |
|
|
<input type="checkbox" id="permission-read" name="permission_read" class="w-4 h-4 mr-2" checked> |
|
|
<label for="permission-read" class="mb-0 text-sm">Read</label> |
|
|
</div> |
|
|
<div class="flex items-center"> |
|
|
<input type="checkbox" id="permission-write" name="permission_write" class="w-4 h-4 mr-2"> |
|
|
<label for="permission-write" class="mb-0 text-sm">Write</label> |
|
|
</div> |
|
|
<div class="flex items-center"> |
|
|
<input type="checkbox" id="permission-delete" name="permission_delete" class="w-4 h-4 mr-2"> |
|
|
<label for="permission-delete" class="mb-0 text-sm">Delete</label> |
|
|
</div> |
|
|
<div class="flex items-center"> |
|
|
<input type="checkbox" id="permission-admin" name="permission_admin" class="w-4 h-4 mr-2"> |
|
|
<label for="permission-admin" class="mb-0 text-sm">Admin</label> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="form-group"> |
|
|
<label for="token-ip">IP Restrictions (Optional)</label> |
|
|
<input type="text" id="token-ip" name="token_ip" placeholder="192.168.1.1, 10.0.0.0/24"> |
|
|
<p class="text-xs text-gray-400 mt-1">Comma-separated list of IP addresses or ranges</p> |
|
|
</div> |
|
|
|
|
|
<div class="form-group flex items-center"> |
|
|
<input type="checkbox" id="confirm-generation" class="w-5 h-5 mr-2" required> |
|
|
<label for="confirm-generation" class="mb-0">I understand that this token will have access to my account data</label> |
|
|
</div> |
|
|
|
|
|
<div class="bg-yellow-400 bg-opacity-20 p-3 rounded-lg mt-4 flex items-start"> |
|
|
<i data-feather="info" class="text-yellow-400 mr-2 mt-1"></i> |
|
|
<p class="text-sm">Keep your tokens secure and never share them publicly. Each token will be shown only once after generation.</p> |
|
|
</div> |
|
|
|
|
|
<button type="submit" class="btn mt-4" id="generate-btn">Generate Token</button> |
|
|
</form> |
|
|
<?php endif; ?> |
|
|
</div> |
|
|
|
|
|
<div class="dashboard-card"> |
|
|
<h3 class="text-lg font-bold mb-4 flex items-center gap-2"> |
|
|
<i data-feather="list" class="text-green-400"></i> Active Tokens |
|
|
</h3> |
|
|
|
|
|
<!-- Real-time Stats --> |
|
|
<div class="stat-card mb-4"> |
|
|
<h4 class="font-bold mb-2">Last 24 Hours</h4> |
|
|
<div class="grid grid-cols-2 gap-2 text-sm"> |
|
|
<div> |
|
|
<p class="text-gray-400">API Calls</p> |
|
|
<p class="font-bold" id="total-calls"><?php echo $realtime_stats['total_calls'] ?? 0; ?></p> |
|
|
</div> |
|
|
<div> |
|
|
<p class="text-gray-400">Avg. Response</p> |
|
|
<p class="font-bold" id="avg-response"><?php echo round($realtime_stats['avg_response_time'] ?? 0, 2); ?>ms</p> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<?php if (empty($user_tokens)): ?> |
|
|
<div class="text-center py-8" id="no-tokens"> |
|
|
<i data-feather="key" class="mx-auto text-gray-400 text-4xl"></i> |
|
|
<p class="mt-2 text-gray-400">No active tokens</p> |
|
|
</div> |
|
|
<?php else: ?> |
|
|
<div id="token-list"> |
|
|
<?php foreach ($user_tokens as $token): ?> |
|
|
<div class="stat-card"> |
|
|
<div class="flex justify-between items-center"> |
|
|
<div> |
|
|
<h4 class="font-bold"><?php echo htmlspecialchars($token['token_name']); ?></h4> |
|
|
<p class="text-sm"><?php echo implode(', ', $token['permissions'] ?? []); ?> permissions</p> |
|
|
</div> |
|
|
<div class="text-right"> |
|
|
<p class="text-xs <?php echo ($token['is_expired'] ?? false) ? 'text-red-400' : 'text-green-400'; ?>"> |
|
|
<?php echo ($token['is_expired'] ?? false) ? 'Expired' : 'Active'; ?> |
|
|
</p> |
|
|
<p class="text-xs text-gray-400"> |
|
|
<?php echo $token['expires_at'] ? 'Expires: ' . date('d M Y', strtotime($token['expires_at'])) : 'Never expires'; ?> |
|
|
</p> |
|
|
</div> |
|
|
</div> |
|
|
<div class="flex justify-between items-center mt-2"> |
|
|
<p class="text-xs">Created: <?php echo date('d M Y', strtotime($token['created_at'])); ?></p> |
|
|
<p class="text-xs">Used: <?php echo $token['usage_count'] ?? 0; ?> times</p> |
|
|
</div> |
|
|
<form method="POST" action="" class="mt-2"> |
|
|
<input type="hidden" name="token_id" value="<?php echo $token['id']; ?>"> |
|
|
<button type="submit" name="revoke_token" class="text-xs text-red-400 hover:text-red-300" |
|
|
onclick="return confirm('Are you sure you want to revoke this token?')"> |
|
|
Revoke |
|
|
</button> |
|
|
</form> |
|
|
</div> |
|
|
<?php endforeach; ?> |
|
|
</div> |
|
|
<?php endif; ?> |
|
|
|
|
|
<button class="btn btn-outline mt-4" id="refresh-btn"> |
|
|
<i data-feather="refresh-cw" class="w-4 h-4 mr-2"></i> Refresh Stats |
|
|
</button> |
|
|
|
|
|
<div class="mt-6"> |
|
|
<h4 class="font-bold mb-3 flex items-center gap-2"> |
|
|
<i data-feather="shield" class="text-purple-400"></i> Token Security |
|
|
</h4> |
|
|
<ul class="text-sm space-y-2"> |
|
|
<li class="flex items-start"> |
|
|
<i data-feather="check-circle" class="text-green-400 mr-2 mt-1"></i> |
|
|
<span>Never share tokens in public repositories</span> |
|
|
</li> |
|
|
<li class="flex items-start"> |
|
|
<i data-feather="check-circle" class="text-green-400 mr-2 mt-1"></i> |
|
|
<span>Rotate tokens regularly</span> |
|
|
</li> |
|
|
<li class="flex items-start"> |
|
|
<i data-feather="check-circle" class="text-green-400 mr-2 mt-1"></i> |
|
|
<span>Use IP restrictions when possible</span> |
|
|
</li> |
|
|
</ul> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="dashboard-card mt-8"> |
|
|
<h3 class="text-lg font-bold mb-4 flex items-center gap-2"> |
|
|
<i data-feather="help-circle" class="text-purple-400"></i> Token Information |
|
|
</h3> |
|
|
|
|
|
<div class="faq-item"> |
|
|
<div class="flex justify-between items-center"> |
|
|
<h4 class="font-bold">What are access tokens used for?</h4> |
|
|
<i data-feather="chevron-down" class="faq-toggle"></i> |
|
|
</div> |
|
|
<div class="faq-answer"> |
|
|
<p>Access tokens allow third-party applications to interact with the Jmotors API on your behalf. They provide a secure way to authenticate requests without sharing your password.</p> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="faq-item"> |
|
|
<div class="flex justify-between items-center"> |
|
|
<h4 class="font-bold">How do I use an access token?</h4> |
|
|
<i data-feather="chevron-down" class="faq-toggle"></i> |
|
|
</div> |
|
|
<div class="faq-answer"> |
|
|
<p>Include the token in the Authorization header: <code>Authorization: Bearer YOUR_TOKEN_HERE</code>. Always use HTTPS for security.</p> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="faq-item"> |
|
|
<div class="flex justify-between items-center"> |
|
|
<h4 class="font-bold">What if my token is compromised?</h4> |
|
|
<i data-feather="chevron-down" class="faq-toggle"></i> |
|
|
</div> |
|
|
<div class="faq-answer"> |
|
|
<p>Revoke it immediately from this page and generate a new one. Monitor your account for suspicious activity.</p> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</main> |
|
|
</div> |
|
|
|
|
|
<!-- Token Display Modal --> |
|
|
<?php if (isset($_SESSION['new_token'])): ?> |
|
|
<div class="confirmation-modal" id="token-modal" style="display: flex;"> |
|
|
<div class="modal-content"> |
|
|
<h3 class="text-xl font-bold mb-4 flex items-center gap-2"> |
|
|
<i data-feather="key" class="text-green-400"></i> New Access Token Created |
|
|
</h3> |
|
|
|
|
|
<div class="bg-gray-700 p-4 rounded-lg mb-4"> |
|
|
<p class="text-sm mb-2">Please copy your token now. You won't be able to see it again!</p> |
|
|
|
|
|
<div class="token-display"> |
|
|
<span id="token-value"><?php echo $_SESSION['new_token']; ?></span> |
|
|
<button class="copy-btn" id="copy-token"> |
|
|
<i data-feather="copy" class="w-4 h-4"></i> Copy |
|
|
</button> |
|
|
</div> |
|
|
|
|
|
<div class="text-xs text-gray-400 mt-2"> |
|
|
<p>Name: <span id="token-detail-name"><?php echo $_SESSION['token_details']['name']; ?></span></p> |
|
|
<p>Expires: <span id="token-detail-expiry"><?php echo $_SESSION['token_details']['expiry']; ?></span></p> |
|
|
<p>Permissions: <span id="token-detail-perms"><?php echo $_SESSION['token_details']['permissions']; ?></span></p> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="bg-red-400 bg-opacity-20 p-3 rounded-lg flex items-start mb-4"> |
|
|
<i data-feather="alert-triangle" class="text-red-400 mr-2 mt-1"></i> |
|
|
<p class="text-sm">For security reasons, this token will only be displayed once. Please store it in a secure location.</p> |
|
|
</div> |
|
|
|
|
|
<button class="btn" id="close-modal">I've Saved My Token</button> |
|
|
</div> |
|
|
</div> |
|
|
<?php |
|
|
unset($_SESSION['new_token']); |
|
|
unset($_SESSION['token_details']); |
|
|
?> |
|
|
<?php endif; ?> |
|
|
|
|
|
<script> |
|
|
// Initialize feather icons |
|
|
feather.replace(); |
|
|
|
|
|
// Sidebar functionality |
|
|
const toggleBtn = document.getElementById('menu-toggle'); |
|
|
const sidebar = document.getElementById('sidebar'); |
|
|
const content = document.getElementById('content'); |
|
|
const overlay = document.getElementById('overlay'); |
|
|
|
|
|
function toggleSidebar() { |
|
|
sidebar.classList.toggle('active'); |
|
|
content.classList.toggle('content-shifted'); |
|
|
overlay.classList.toggle('active'); |
|
|
} |
|
|
|
|
|
toggleBtn.addEventListener('click', toggleSidebar); |
|
|
overlay.addEventListener('click', toggleSidebar); |
|
|
|
|
|
|
|
|
document.querySelectorAll('.faq-item').forEach(item => { |
|
|
item.addEventListener('click', function() { |
|
|
const answer = this.querySelector('.faq-answer'); |
|
|
const icon = this.querySelector('.faq-toggle'); |
|
|
|
|
|
if (answer.style.display === 'block') { |
|
|
answer.style.display = 'none'; |
|
|
icon.setAttribute('data-feather', 'chevron-down'); |
|
|
} else { |
|
|
answer.style.display = 'block'; |
|
|
icon.setAttribute('data-feather', 'chevron-up'); |
|
|
} |
|
|
feather.replace(); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
const tokenForm = document.getElementById('token-form'); |
|
|
const confirmCheckbox = document.getElementById('confirm-generation'); |
|
|
const generateBtn = document.getElementById('generate-btn'); |
|
|
|
|
|
function checkFormValidity() { |
|
|
if (tokenForm && tokenForm.checkValidity() && confirmCheckbox && confirmCheckbox.checked) { |
|
|
if (generateBtn) { |
|
|
generateBtn.classList.remove('btn-disabled'); |
|
|
generateBtn.disabled = false; |
|
|
} |
|
|
} else { |
|
|
if (generateBtn) { |
|
|
generateBtn.classList.add('btn-disabled'); |
|
|
generateBtn.disabled = true; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
if (tokenForm && confirmCheckbox) { |
|
|
tokenForm.addEventListener('input', checkFormValidity); |
|
|
confirmCheckbox.addEventListener('change', checkFormValidity); |
|
|
checkFormValidity(); |
|
|
} |
|
|
|
|
|
|
|
|
document.getElementById('refresh-btn')?.addEventListener('click', function() { |
|
|
location.reload(); |
|
|
}); |
|
|
|
|
|
|
|
|
const tokenModal = document.getElementById('token-modal'); |
|
|
const copyTokenBtn = document.getElementById('copy-token'); |
|
|
const closeModalBtn = document.getElementById('close-modal'); |
|
|
|
|
|
if (copyTokenBtn) { |
|
|
copyTokenBtn.addEventListener('click', function() { |
|
|
const tokenValue = document.getElementById('token-value'); |
|
|
if (tokenValue) { |
|
|
navigator.clipboard.writeText(tokenValue.textContent).then(() => { |
|
|
const originalHtml = copyTokenBtn.innerHTML; |
|
|
copyTokenBtn.innerHTML = '<i data-feather="check" class="w-4 h-4"></i> Copied!'; |
|
|
feather.replace(); |
|
|
|
|
|
setTimeout(() => { |
|
|
copyTokenBtn.innerHTML = originalHtml; |
|
|
feather.replace(); |
|
|
}, 2000); |
|
|
}); |
|
|
} |
|
|
}); |
|
|
} |
|
|
|
|
|
if (closeModalBtn) { |
|
|
closeModalBtn.addEventListener('click', function() { |
|
|
if (tokenModal) { |
|
|
tokenModal.style.display = 'none'; |
|
|
} |
|
|
window.location.href = 'access-token.php'; |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
document.addEventListener('keydown', function(e) { |
|
|
if (e.key === 'Escape' && tokenModal && tokenModal.style.display === 'flex') { |
|
|
tokenModal.style.display = 'none'; |
|
|
window.location.href = 'access-token.php'; |
|
|
} |
|
|
}); |
|
|
</script> |
|
|
</body> |
|
|
</html> |