feat(users): add account limits and API keys
All checks were successful
Build and Publish Docker Image / deploy (push) Successful in 1m43s
All checks were successful
Build and Publish Docker Image / deploy (push) Successful in 1m43s
This commit is contained in:
@@ -34,8 +34,10 @@ function setBoxOptionsLocked(locked) {
|
||||
function updateDisabledReasons() {
|
||||
if (el.startButton) {
|
||||
let reason = "";
|
||||
const policyMessage = apiKeyPolicyMessage();
|
||||
if (!uploadsEnabled) reason = "Guest uploads are disabled.";
|
||||
else if (uploadLocked) reason = "This upload already started. Press Clear to create another box.";
|
||||
else if (policyMessage) reason = policyMessage;
|
||||
else if (hasQuotaError()) reason = "Over maximum upload size. Remove highlighted files or clear some files.";
|
||||
else if (!files.length) reason = "There are no files selected. Please select files to upload.";
|
||||
el.startButton.disabled = false;
|
||||
@@ -101,6 +103,13 @@ function syncMenuChecks() {
|
||||
function syncApiKeyField() {
|
||||
const enabled = Boolean(el.apiKeyMode?.checked) && !uploadLocked;
|
||||
el.apiKeyRow?.classList.toggle("is-visible", Boolean(el.apiKeyMode?.checked));
|
||||
if (!el.apiKeyMode?.checked) {
|
||||
clearTimeout(apiKeyTimer);
|
||||
apiKeyValidationRun += 1;
|
||||
resetAccountLimits();
|
||||
updateLimitHint();
|
||||
renderFiles();
|
||||
}
|
||||
if (el.apiKeyInput) {
|
||||
el.apiKeyInput.disabled = !enabled;
|
||||
el.apiKeyInput.dataset.disabledReason = enabled ? "" : "Enable Use API key for larger quota before typing an API key.";
|
||||
@@ -115,30 +124,83 @@ function validateApiKeyField() {
|
||||
wrapper?.classList.remove("is-checking");
|
||||
|
||||
if (!el.apiKeyMode?.checked) {
|
||||
apiKeyValidationRun += 1;
|
||||
resetAccountLimits();
|
||||
el.apiKeyState.textContent = "";
|
||||
updateLimitHint();
|
||||
renderFiles();
|
||||
return;
|
||||
}
|
||||
const value = el.apiKeyInput.value.trim();
|
||||
if (!value) {
|
||||
apiKeyValidationRun += 1;
|
||||
resetAccountLimits();
|
||||
el.apiKeyState.textContent = "waiting";
|
||||
updateLimitHint();
|
||||
renderFiles();
|
||||
saveSettings();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validApiKey(value)) {
|
||||
apiKeyValidationRun += 1;
|
||||
resetAccountLimits();
|
||||
el.apiKeyInput.value = "";
|
||||
el.apiKeyState.textContent = "invalid";
|
||||
updateLimitHint();
|
||||
renderFiles();
|
||||
saveSettings();
|
||||
showToast("Invalid API key removed. Paste a valid API key to save it.", "warning");
|
||||
return;
|
||||
}
|
||||
|
||||
const runID = apiKeyValidationRun + 1;
|
||||
apiKeyValidationRun = runID;
|
||||
el.apiKeyInput.disabled = true;
|
||||
wrapper?.classList.add("is-checking");
|
||||
el.apiKeyState.textContent = "checking";
|
||||
apiKeyTimer = setTimeout(() => {
|
||||
wrapper?.classList.remove("is-checking");
|
||||
el.apiKeyInput.disabled = uploadLocked;
|
||||
if (validApiKey(value)) {
|
||||
el.apiKeyState.textContent = "saved locally";
|
||||
apiKeyTimer = setTimeout(async () => {
|
||||
try {
|
||||
const response = await fetch("/auth/me", {
|
||||
headers: { Authorization: `Bearer ${value}` },
|
||||
});
|
||||
let payload = {};
|
||||
try {
|
||||
payload = await response.json();
|
||||
} catch (_) {}
|
||||
if (runID !== apiKeyValidationRun) return;
|
||||
wrapper?.classList.remove("is-checking");
|
||||
el.apiKeyInput.disabled = uploadLocked;
|
||||
if (!response.ok || !payload.user) {
|
||||
resetAccountLimits();
|
||||
el.apiKeyInput.value = "";
|
||||
el.apiKeyState.textContent = "invalid";
|
||||
updateLimitHint();
|
||||
renderFiles();
|
||||
saveSettings();
|
||||
showToast(payload.error || "API key was not accepted.", "warning");
|
||||
return;
|
||||
}
|
||||
|
||||
applyAccountLimits(payload.user);
|
||||
const policyMessage = apiKeyPolicyMessage();
|
||||
const fileText = maxFileBytes ? formatBytes(maxFileBytes) : "unlimited";
|
||||
const boxText = maxBoxBytes ? formatBytes(maxBoxBytes) : "unlimited";
|
||||
el.apiKeyState.textContent = policyMessage ? "limited by policy" : "account limits applied";
|
||||
updateLimitHint();
|
||||
renderFiles();
|
||||
saveSettings();
|
||||
} else {
|
||||
el.apiKeyInput.value = "";
|
||||
el.apiKeyState.textContent = "invalid";
|
||||
saveSettings();
|
||||
showToast("Invalid API key removed. Paste a valid API key to save it.", "warning");
|
||||
setStatus(`${payload.user.username || payload.user.email} limits: file ${fileText}, box ${boxText}`);
|
||||
if (policyMessage) showToast(policyMessage, "warning");
|
||||
} catch (_) {
|
||||
if (runID !== apiKeyValidationRun) return;
|
||||
wrapper?.classList.remove("is-checking");
|
||||
el.apiKeyInput.disabled = uploadLocked;
|
||||
resetAccountLimits();
|
||||
updateLimitHint();
|
||||
renderFiles();
|
||||
el.apiKeyState.textContent = "check failed";
|
||||
showToast("Could not check API key limits.", "warning");
|
||||
}
|
||||
}, 650);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user