- Implemented.
Rebuilt embed-example.html with inline, full-screen, and popup examples. Fixed host-page/frame scrolling and contained reply navigation. New logins now transactionally replace prior sessions; displaced clients return to login. Added per-user session/IP locking with automatic SQLite migration. Added modular Spam Control dashboard for locks, honeypot, and CAPTCHA settings. Moved CAPTCHA controls out of Plans & Platform.
This commit is contained in:
@@ -4,33 +4,10 @@ function handleAdminPlatformAction(string $action): ?string {
|
||||
if ($action === 'save_platform_services') {
|
||||
$voiceProfile = (string)($_POST['voice_transcoding_profile'] ?? 'm4a_aac');
|
||||
if (!in_array($voiceProfile, ['m4a_aac', 'mp4_h264_aac'], true)) $voiceProfile = 'm4a_aac';
|
||||
$captchaVersion = (string)($_POST['captcha_google_version'] ?? 'v2');
|
||||
if (!in_array($captchaVersion, ['v2', 'v3'], true)) $captchaVersion = 'v2';
|
||||
$captchaDifficulty = (string)($_POST['captcha_internal_difficulty'] ?? 'easy');
|
||||
if (!in_array($captchaDifficulty, ['easy', 'medium'], true)) $captchaDifficulty = 'easy';
|
||||
$captchaGoogleEnabled = !empty($_POST['captcha_google_enabled']);
|
||||
$captchaGoogleSiteKey = trim((string)($_POST['captcha_google_site_key'] ?? ''));
|
||||
$captchaGoogleSecretKey = trim((string)($_POST['captcha_google_secret_key'] ?? ''));
|
||||
if ($captchaGoogleEnabled && ($captchaGoogleSiteKey === '' || $captchaGoogleSecretKey === '')) {
|
||||
throw new RuntimeException('Google reCAPTCHA requires both a site key and secret key.');
|
||||
}
|
||||
setConfigValues([
|
||||
'subscriptions.enabled' => !empty($_POST['subscriptions_enabled']),
|
||||
'chat.replies_enabled' => !empty($_POST['replies_enabled']),
|
||||
'chat.reply_max_depth' => max(1, min(20, (int)($_POST['reply_max_depth'] ?? 4))),
|
||||
'security.captcha.registration_enabled' => !empty($_POST['captcha_registration_enabled']),
|
||||
'security.captcha.login_enabled' => !empty($_POST['captcha_login_enabled']),
|
||||
'security.captcha.honeypot.enabled' => !empty($_POST['captcha_honeypot_enabled']),
|
||||
'security.captcha.internal.enabled' => !empty($_POST['captcha_internal_enabled']),
|
||||
'security.captcha.internal.difficulty' => $captchaDifficulty,
|
||||
'security.captcha.internal.ttl_seconds' => max(60, min(1800, (int)($_POST['captcha_internal_ttl'] ?? 300))),
|
||||
'security.captcha.internal.max_attempts' => max(1, min(10, (int)($_POST['captcha_internal_attempts'] ?? 3))),
|
||||
'security.captcha.google.enabled' => $captchaGoogleEnabled,
|
||||
'security.captcha.google.version' => $captchaVersion,
|
||||
'security.captcha.google.site_key' => $captchaGoogleSiteKey,
|
||||
'security.captcha.google.secret_key' => $captchaGoogleSecretKey,
|
||||
'security.captcha.google.v3_min_score' => max(0.0, min(1.0, (float)($_POST['captcha_google_v3_score'] ?? 0.5))),
|
||||
'security.captcha.google.hostname' => trim((string)($_POST['captcha_google_hostname'] ?? '')),
|
||||
'mailgun.api_key' => trim((string)($_POST['mailgun_api_key'] ?? '')),
|
||||
'mailgun.domain' => trim((string)($_POST['mailgun_domain'] ?? '')),
|
||||
'mailgun.from' => trim((string)($_POST['mailgun_from'] ?? '')),
|
||||
@@ -182,55 +159,6 @@ function renderAdminPlatformTab(): void {
|
||||
</div>
|
||||
</div></div>
|
||||
|
||||
<div class="panel"><div class="panel-head"><span class="panel-title">// REGISTRATION / LOGIN CAPTCHA</span></div><div class="panel-body">
|
||||
<p class="dim">CAPTCHA checks apply only to initial registration and password login. Email 2FA verification is not challenged.</p>
|
||||
<div class="form-row">
|
||||
<label class="cb-row"><input type="checkbox" name="captcha_registration_enabled"
|
||||
<?= getConfigVal('security.captcha.registration_enabled', true) ? 'checked' : '' ?>><span>Protect registration</span></label>
|
||||
<label class="cb-row"><input type="checkbox" name="captcha_login_enabled"
|
||||
<?= getConfigVal('security.captcha.login_enabled', true) ? 'checked' : '' ?>><span>Protect login</span></label>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label class="cb-row"><input type="checkbox" name="captcha_honeypot_enabled"
|
||||
<?= getConfigVal('security.captcha.honeypot.enabled', true) ? 'checked' : '' ?>>
|
||||
<span>Invisible honeypot fields that deny bot-like submissions</span></label>
|
||||
<label class="cb-row"><input type="checkbox" name="captcha_internal_enabled"
|
||||
<?= getConfigVal('security.captcha.internal.enabled', true) ? 'checked' : '' ?>>
|
||||
<span>Internal arithmetic challenge</span></label>
|
||||
</div>
|
||||
<div class="form-row3">
|
||||
<div class="field"><label>Internal Difficulty</label><select name="captcha_internal_difficulty">
|
||||
<?php $captchaDifficulty = getConfigVal('security.captcha.internal.difficulty', 'easy'); ?>
|
||||
<option value="easy" <?= $captchaDifficulty === 'easy' ? 'selected' : '' ?>>Easy (1-9)</option>
|
||||
<option value="medium" <?= $captchaDifficulty === 'medium' ? 'selected' : '' ?>>Medium (1-25)</option>
|
||||
</select></div>
|
||||
<div class="field"><label>Challenge TTL (seconds)</label><input type="number" min="60" max="1800"
|
||||
name="captcha_internal_ttl" value="<?= (int)getConfigVal('security.captcha.internal.ttl_seconds', 300) ?>"></div>
|
||||
<div class="field"><label>Maximum Attempts</label><input type="number" min="1" max="10"
|
||||
name="captcha_internal_attempts" value="<?= (int)getConfigVal('security.captcha.internal.max_attempts', 3) ?>"></div>
|
||||
</div>
|
||||
<label class="cb-row"><input type="checkbox" name="captcha_google_enabled"
|
||||
<?= getConfigVal('security.captcha.google.enabled', false) ? 'checked' : '' ?>>
|
||||
<span>Also require Google reCAPTCHA</span></label>
|
||||
<div class="form-row3">
|
||||
<div class="field"><label>Google Version</label><select name="captcha_google_version">
|
||||
<?php $captchaVersion = getConfigVal('security.captcha.google.version', 'v2'); ?>
|
||||
<option value="v2" <?= $captchaVersion === 'v2' ? 'selected' : '' ?>>v2 checkbox</option>
|
||||
<option value="v3" <?= $captchaVersion === 'v3' ? 'selected' : '' ?>>v3 score</option>
|
||||
</select></div>
|
||||
<div class="field"><label>Site Key</label><input name="captcha_google_site_key"
|
||||
value="<?= esc(getConfigVal('security.captcha.google.site_key', '')) ?>"></div>
|
||||
<div class="field"><label>Secret Key</label><input type="password" name="captcha_google_secret_key"
|
||||
value="<?= esc(getConfigVal('security.captcha.google.secret_key', '')) ?>"></div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="field"><label>v3 Minimum Score</label><input type="number" min="0" max="1" step="0.1"
|
||||
name="captcha_google_v3_score" value="<?= esc(getConfigVal('security.captcha.google.v3_min_score', 0.5)) ?>"></div>
|
||||
<div class="field"><label>Expected Hostname (optional)</label><input name="captcha_google_hostname"
|
||||
value="<?= esc(getConfigVal('security.captcha.google.hostname', '')) ?>" placeholder="chat.example.com"></div>
|
||||
</div>
|
||||
</div></div>
|
||||
|
||||
<div class="panel"><div class="panel-head"><span class="panel-title">// MAILGUN</span></div><div class="panel-body">
|
||||
<div class="form-row3">
|
||||
<div class="field"><label>API Key</label><input type="password" name="mailgun_api_key" value="<?= esc(getConfigVal('mailgun.api_key', '')) ?>"></div>
|
||||
|
||||
Reference in New Issue
Block a user