Spaces:
Running
Running
File size: 6,356 Bytes
f49d1e7 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
// API Keys management
let apiKeys = [];
// Initialize API Keys page
document.addEventListener('DOMContentLoaded', function() {
loadSampleApiKeys();
renderApiKeysTable();
});
// Load sample API keys
function loadSampleApiKeys() {
apiKeys = [
{
id: 1,
name: 'Production Key',
key: 'sk_live_51HvK2rKRtimDvy4kF8h4gF2j3k5l6m7n8o9p0q1r2s3t4u5v6w7x8y9z0',
createdAt: new Date('2024-01-15'),
lastUsed: new Date('2024-01-20'),
status: 'active'
},
{
id: 2,
name: 'Development Key',
key: 'sk_test_1HvK2rKRtimDvy4kF8h4gF2j3k5l6m7n8o9p0q1r2s3t4u5v6w7x8y9z0',
createdAt: new Date('2024-01-10'),
lastUsed: new Date('2024-01-18'),
status: 'active'
},
{
id: 3,
name: 'CI/CD Pipeline',
key: 'sk_live_2HvK2rKRtimDvy4kF8h4gF2j3k5l6m7n8o9p0q1r2s3t4u5v6w7x8y9z0',
createdAt: new Date('2024-01-05'),
lastUsed: new Date('2024-01-12'),
status: 'revoked'
}
];
}
// Render API keys table
function renderApiKeysTable() {
const tableBody = document.getElementById('api-keys-table');
tableBody.innerHTML = apiKeys.map(key => {
const maskedKey = maskApiKey(key.key);
const timeAgo = getTimeAgo(key.lastUsed);
const createdAgo = getTimeAgo(key.createdAt);
const statusClass = key.status === 'active' ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800';
return `
<tr class="hover:bg-gray-50">
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-sm font-medium text-gray-900">${key.name}</div>
<div class="text-sm text-gray-500">${key.status === 'active' ? 'Active' : 'Revoked'}</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex items-center">
<code class="text-sm font-mono text-gray-900 bg-gray-100 px-2 py-1 rounded">${maskedKey}</code>
<button onclick="copyApiKey('${key.key}')" class="ml-2 text-gray-400 hover:text-gray-600">
<i data-feather="copy" class="w-4 h-4"></i>
</button>
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
${createdAgo}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
${timeAgo}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
<div class="flex space-x-2">
<button onclick="showKeyDetails('${key.id}')" class="text-primary-600 hover:text-primary-700">View</button>
${key.status === 'active' ? `
<button onclick="revokeKey('${key.id}')" class="text-red-600 hover:text-red-700">Revoke</button>
` : `
<button onclick="deleteKey('${key.id}')" class="text-red-600 hover:text-red-700">Delete</button>
`}
</div>
</td>
</tr>
`;
}).join('');
feather.replace();
}
// Mask API key for display
function maskApiKey(key) {
const prefix = key.substring(0, 12);
const suffix = key.substring(key.length - 8);
return `${prefix}...${suffix}`;
}
// Copy API key to clipboard
function copyApiKey(key) {
navigator.clipboard.writeText(key).then(() => {
Wash.showNotification('API key copied to clipboard', 'success');
});
}
// Create new API key
function createNewKey() {
const name = prompt('Enter a name for the new API key:');
if (!name) return;
const newKey = {
id: Date.now(),
name: name,
key: generateApiKey(),
createdAt: new Date(),
lastUsed: null,
status: 'active'
};
apiKeys.unshift(newKey);
renderApiKeysTable();
Wash.showNotification('New API key created successfully', 'success');
}
// Generate a random API key
function generateApiKey() {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = 'sk_live_';
for (let i = 0; i < 48; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
}
// Revoke API key
function revokeKey(keyId) {
if (confirm('Are you sure you want to revoke this API key? This action cannot be undone.')) {
const key = apiKeys.find(k => k.id == keyId);
if (key) {
key.status = 'revoked';
renderApiKeysTable();
Wash.showNotification('API key revoked successfully', 'success');
}
}
}
// Delete API key
function deleteKey(keyId) {
if (confirm('Are you sure you want to delete this API key? This action cannot be undone.')) {
apiKeys = apiKeys.filter(k => k.id != keyId);
renderApiKeysTable();
Wash.showNotification('API key deleted successfully', 'success');
}
}
// Show key details
function showKeyDetails(keyId) {
const key = apiKeys.find(k => k.id == keyId);
if (!key) return;
const details = `
Key Details:
Name: ${key.name}
Key: ${key.key}
Status: ${key.status}
Created: ${key.createdAt.toLocaleDateString()}
Last Used: ${key.lastUsed ? key.lastUsed.toLocaleDateString() : 'Never'}
Usage Example:
curl -X POST https://api.wash.dev/v1/clean \\
-H "Authorization: Bearer ${key.key}" \\
-F "file=@document.pdf"
`;
alert(details);
}
// Get time ago string
function getTimeAgo(date) {
if (!date) return 'Never';
const now = new Date();
const diff = now - date;
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
const hours = Math.floor(diff / (1000 * 60 * 60));
const minutes = Math.floor(diff / (1000 * 60));
if (days > 0) {
return `${days} day${days > 1 ? 's' : ''} ago`;
} else if (hours > 0) {
return `${hours} hour${hours > 1 ? 's' : ''} ago`;
} else if (minutes > 0) {
return `${minutes} minute${minutes > 1 ? 's' : ''} ago`;
} else {
return 'Just now';
}
} |