feat(security): implement dynamic tactical license gate, instant key revocation, and clean hardcoded credentials

This commit is contained in:
Hamza-Ayed
2026-08-18 13:46:02 +03:00
parent 8375773898
commit cb384765fb
17 changed files with 439 additions and 38 deletions
+31 -3
View File
@@ -328,9 +328,14 @@ const app = {
</div>
</td>
<td class="px-6 py-6 text-right">
<button class="p-2 text-slate-500 hover:text-white" onclick="app.fetchData()">
<i data-lucide="refresh-cw" class="w-4 h-4"></i>
</button>
<div class="flex items-center justify-end gap-1">
<button class="p-2 text-slate-500 hover:text-white" title="Refresh" onclick="app.fetchData()">
<i data-lucide="refresh-cw" class="w-4 h-4"></i>
</button>
<button class="p-2 text-slate-500 hover:text-red-400 transition-colors" title="Revoke Key" onclick="app.deleteKey('${key.id}', '${key.name}')">
<i data-lucide="trash-2" class="w-4 h-4"></i>
</button>
</div>
</td>
</tr>
`;
@@ -339,6 +344,29 @@ const app = {
lucide.createIcons();
},
deleteKey: async (keyId, keyName) => {
if (!confirm(`Are you sure you want to revoke the API key "${keyName || 'Production Key'}"? This action cannot be undone.`)) {
return;
}
try {
const res = await fetch(`/api/auth/management/keys/${keyId}`, {
method: 'DELETE',
headers: auth.getAuthHeader()
});
if (res.ok) {
await app.fetchData();
} else {
const data = await res.json().catch(() => ({}));
alert(data.message || 'Failed to revoke API key');
}
} catch (e) {
console.error('Delete key failed:', e);
alert('Failed to revoke API key');
}
},
toggleKeyVisibility: (id) => {
app.state.showKeys[id] = !app.state.showKeys[id];
app.renderKeysTable();
+22 -4
View File
@@ -6,6 +6,7 @@ import {
Eye,
EyeOff,
RefreshCw,
Trash2,
ShieldCheck,
Globe,
Zap,
@@ -53,7 +54,7 @@ const DashboardHome = ({ tenant, keys, loading, onRefresh }: DashboardHomeProps)
const createKey = async (name: string, limit: number) => {
if (!tenant) return;
try {
await axios.post(`/api/auth/management/keys/${tenant.id}`, {
await axios.post(`/api/auth/management/keys`, {
name,
rateLimit: limit
});
@@ -65,6 +66,18 @@ const DashboardHome = ({ tenant, keys, loading, onRefresh }: DashboardHomeProps)
}
};
const deleteKey = async (keyId: string, keyName: string) => {
if (!window.confirm(`Are you sure you want to revoke the API key "${keyName || 'Production Key'}"? This action cannot be undone.`)) {
return;
}
try {
await axios.delete(`/api/auth/management/keys/${keyId}`);
onRefresh();
} catch (e) {
alert('Failed to revoke key');
}
};
return (
<div className="animate-in fade-in slide-in-from-bottom-4 duration-700">
{/* Hero Section */}
@@ -264,9 +277,14 @@ const DashboardHome = ({ tenant, keys, loading, onRefresh }: DashboardHomeProps)
</div>
</td>
<td className="px-6 py-6 text-right">
<button className="p-2 text-slate-500 hover:text-white" onClick={onRefresh}>
<RefreshCw size={16} />
</button>
<div className="flex items-center justify-end gap-1">
<button className="p-2 text-slate-500 hover:text-white" title="Refresh" onClick={onRefresh}>
<RefreshCw size={16} />
</button>
<button className="p-2 text-slate-500 hover:text-red-400 transition-colors" title="Revoke Key" onClick={() => deleteKey(apiKey.id, apiKey.name)}>
<Trash2 size={16} />
</button>
</div>
</td>
</tr>
))}