(status)
| 129 | } |
| 130 | |
| 131 | function wirePersistentTokensKeyWarningActions(status) { |
| 132 | const btn = document.getElementById('frRotatePersistentTokensKeyBtn'); |
| 133 | const statusEl = document.getElementById('frRotatePersistentTokensKeyStatus'); |
| 134 | if (!btn || btn.__wired) return; |
| 135 | |
| 136 | btn.__wired = true; |
| 137 | btn.addEventListener('click', async () => { |
| 138 | const source = String(status?.source || '').trim(); |
| 139 | if (source === 'env') { |
| 140 | showToast('Persistent tokens key rotation is blocked while PERSISTENT_TOKENS_KEY is controlled by env.', 'error'); |
| 141 | return; |
| 142 | } |
| 143 | |
| 144 | const ok = await showCustomConfirmModal( |
| 145 | 'FileRise will generate a new persistent tokens key, re-encrypt stored secrets, and expire all remember-me sessions. Existing browser sessions stay signed in, but remember-me cookies will stop working. Run this during a quiet maintenance window. Continue?' |
| 146 | ); |
| 147 | if (!ok) { |
| 148 | return; |
| 149 | } |
| 150 | |
| 151 | try { |
| 152 | btn.disabled = true; |
| 153 | if (statusEl) { |
| 154 | statusEl.textContent = 'Rotating key and re-encrypting stored secrets...'; |
| 155 | } |
| 156 | |
| 157 | const res = await fetch(withBase('/api/admin/rotatePersistentTokensKey.php'), { |
| 158 | method: 'POST', |
| 159 | credentials: 'include', |
| 160 | headers: { |
| 161 | 'Content-Type': 'application/json', |
| 162 | 'X-CSRF-Token': window.csrfToken || '' |
| 163 | }, |
| 164 | body: JSON.stringify({ |
| 165 | confirmRememberMeExpiry: true, |
| 166 | confirmMaintenanceWindow: true |
| 167 | }) |
| 168 | }); |
| 169 | |
| 170 | const text = await res.text(); |
| 171 | let body = null; |
| 172 | try { body = text ? JSON.parse(text) : null; } catch (e) { /* ignore */ } |
| 173 | if (!res.ok || !body?.ok) { |
| 174 | throw new Error(body?.message || body?.error || `HTTP ${res.status}`); |
| 175 | } |
| 176 | |
| 177 | showToast(body.message || 'Persistent tokens key rotated.'); |
| 178 | |
| 179 | const cfgRes = await fetch(withBase('/api/admin/getConfig.php?ts=' + Date.now()), { |
| 180 | credentials: 'include', |
| 181 | cache: 'no-store', |
| 182 | headers: { 'Cache-Control': 'no-store' } |
| 183 | }); |
| 184 | const nextConfig = await safeJson(cfgRes); |
| 185 | const nextStatus = (nextConfig && typeof nextConfig === 'object' && nextConfig.persistentTokensKeyStatus && typeof nextConfig.persistentTokensKeyStatus === 'object') |
| 186 | ? nextConfig.persistentTokensKeyStatus |
| 187 | : null; |
| 188 | const host = document.getElementById('adminSecurityWarnings'); |
no test coverage detected