diff --git a/public/s/js/settings.js b/public/s/js/settings.js
index 0a08581..242666d 100644
--- a/public/s/js/settings.js
+++ b/public/s/js/settings.js
@@ -1844,12 +1844,13 @@
// ============================================================
// Upload API Key Management
// ============================================================
- const apiKeyStatusBox = document.getElementById('api-key-status-box');
- const apiKeyRevealBox = document.getElementById('api-key-reveal');
- const apiKeyFullDisplay = document.getElementById('api-key-full-display');
- const btnCopyApiKey = document.getElementById('btn-copy-api-key');
- const btnRegenApiKey = document.getElementById('btn-regen-api-key');
- const btnRevokeApiKey = document.getElementById('btn-revoke-api-key');
+ const apiKeyStatusBox = document.getElementById('api-key-status-box');
+ const apiKeyRevealBox = document.getElementById('api-key-reveal');
+ const apiKeyFullDisplay = document.getElementById('api-key-full-display');
+ const btnCopyApiKey = document.getElementById('btn-copy-api-key');
+ const btnRegenApiKey = document.getElementById('btn-regen-api-key');
+ const btnRevokeApiKey = document.getElementById('btn-revoke-api-key');
+ const btnShareXDownload = document.getElementById('btn-sharex-download');
const apiKeyActionStatus = document.getElementById('api-key-action-status');
const showApiKeyStatus = (msg, type) => {
@@ -1866,9 +1867,11 @@
`Active key: ${escHTML(preview)}` +
`Created: ${escHTML(date)}`;
if (btnRevokeApiKey) btnRevokeApiKey.style.display = '';
+ if (btnShareXDownload) btnShareXDownload.style.display = '';
} else {
apiKeyStatusBox.innerHTML = 'No API key generated yet.';
if (btnRevokeApiKey) btnRevokeApiKey.style.display = 'none';
+ if (btnShareXDownload) btnShareXDownload.style.display = 'none';
}
};
@@ -1966,6 +1969,8 @@
const data = await res.json();
if (data.success) {
+ btnRevokeApiKey.disabled = false;
+ btnRevokeApiKey.textContent = 'Revoke Key';
renderApiKeyState(false, null, null);
if (apiKeyRevealBox) apiKeyRevealBox.style.display = 'none';
if (apiKeyFullDisplay) apiKeyFullDisplay.textContent = '';
diff --git a/src/inc/routes/apiv2/settings.mjs b/src/inc/routes/apiv2/settings.mjs
index dffbf70..5d52649 100644
--- a/src/inc/routes/apiv2/settings.mjs
+++ b/src/inc/routes/apiv2/settings.mjs
@@ -811,6 +811,51 @@ export default router => {
}
});
+ // GET /api/v2/settings/api-key/sharex-config
+ // Downloads a pre-filled ShareX custom uploader (.sxcu) for the requesting user.
+ group.get(/\/api-key\/sharex-config$/, lib.loggedin, async (req, res) => {
+ if (cfg.websrv.enable_user_api_keys === false) {
+ return res.status(403).reply({ body: 'API keys are disabled' });
+ }
+ try {
+ const row = (await db`
+ SELECT api_key FROM user_api_keys
+ WHERE user_id = ${+req.session.id}
+ LIMIT 1
+ `)[0];
+
+ if (!row) {
+ return res.status(404).reply({ body: 'No API key — generate one first in Settings.' });
+ }
+
+ const sxcu = {
+ Version: '15.0.0',
+ Name: cfg.main.url.domain,
+ DestinationType: 'ImageUploader, FileUploader',
+ RequestMethod: 'POST',
+ RequestURL: `${cfg.main.url.full}/api/v2/upload`,
+ Headers: {
+ 'X-Api-Key': row.api_key
+ },
+ Body: 'MultipartFormData',
+ FileFormName: 'file',
+ URL: '$json:url$',
+ ErrorMessage: '$json:msg$'
+ };
+
+ const filename = `${cfg.main.url.domain}.sxcu`;
+ const body = JSON.stringify(sxcu, null, 2);
+ res.writeHead(200, {
+ 'Content-Type': 'application/json; charset=utf-8',
+ 'Content-Disposition': `attachment; filename="${filename}"`,
+ 'Content-Length': Buffer.byteLength(body)
+ }).end(body);
+ } catch (e) {
+ console.error('[API KEY] ShareX config error:', e);
+ return res.status(500).reply({ body: 'Error generating config' });
+ }
+ });
+
// --- User Invite System ---
// Eligibility: ≥150 uploads, ≥30 days old, ≥66 comments, ≥200 tags
diff --git a/views/settings.html b/views/settings.html
index 34581a9..8b01926 100644
--- a/views/settings.html
+++ b/views/settings.html
@@ -567,6 +567,7 @@