This commit is contained in:
@@ -75,6 +75,9 @@ if (!isset($_SESSION["logged_in"]) || $_SESSION["logged_in"] !== true) {
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link" id="message-tab" data-bs-toggle="tab" href="#message" role="tab" aria-controls="message" aria-selected="false"><span class="material-icons">message</span></a>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link" id="domains-tab" data-bs-toggle="tab" href="#domains" role="tab" aria-controls="domains" aria-selected="false"><span class="material-icons">language</span></a>
|
||||
</li>
|
||||
<?php
|
||||
if($_SESSION["permissions"][0]==="1"){
|
||||
echo('<li class="nav-item" role="presentation">
|
||||
@@ -173,6 +176,11 @@ if (!isset($_SESSION["logged_in"]) || $_SESSION["logged_in"] !== true) {
|
||||
<label class="form-check-label" for="message-switch">Enable login messages</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="domains" role="tabpanel" aria-labelledby="domains-tab">
|
||||
<p>These external domains have been approved to receive your login data. You can revoke access at any time.</p>
|
||||
<div id="confirmedDomainsList" class="list-group"></div>
|
||||
<p id="noDomainsMessage" class="text-muted mt-3" style="display:none;">No external domains approved yet.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -734,6 +742,53 @@ function generate2FAQRCode(issuer, accountName, secret) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadConfirmedDomains() {
|
||||
fetch('/api/account/manage_domains.php')
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
const list = document.getElementById('confirmedDomainsList');
|
||||
const noMsg = document.getElementById('noDomainsMessage');
|
||||
list.innerHTML = '';
|
||||
if (!data.domains || data.domains.length === 0) {
|
||||
noMsg.style.display = 'block';
|
||||
return;
|
||||
}
|
||||
noMsg.style.display = 'none';
|
||||
data.domains.forEach(d => {
|
||||
const item = document.createElement('div');
|
||||
item.className = 'list-group-item d-flex justify-content-between align-items-center';
|
||||
item.innerHTML = '<span><strong>' + d.domain + '</strong><br><small class="text-muted">Approved: ' + d.confirmed_at + '</small></span>' +
|
||||
'<button class="btn btn-sm btn-outline-danger" onclick="removeDomain(' + d.id + ')">Revoke</button>';
|
||||
list.appendChild(item);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function removeDomain(id) {
|
||||
fetch('/api/account/manage_domains.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-Token': window.csrfToken
|
||||
},
|
||||
body: JSON.stringify({ id: id })
|
||||
}).then(r => r.json()).then(data => {
|
||||
if (data.success) {
|
||||
loadConfirmedDomains();
|
||||
showSuccessModal('Domain access revoked.');
|
||||
} else {
|
||||
showErrorModal(data.message || 'Failed to revoke domain.');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const domainsTab = document.getElementById('domains-tab');
|
||||
if (domainsTab) {
|
||||
domainsTab.addEventListener('shown.bs.tab', loadConfirmedDomains);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
include "../utils/security.php";
|
||||
secure_session_start();
|
||||
header('Content-Type: application/json');
|
||||
|
||||
require_logged_in();
|
||||
|
||||
include "../../config/config.php";
|
||||
$conn = new mysqli($DB_SERVERNAME, $DB_USERNAME, $DB_PASSWORD, $DB_DATABASE);
|
||||
|
||||
$user_id = $_SESSION['id'];
|
||||
$method = $_SERVER['REQUEST_METHOD'];
|
||||
|
||||
if ($method === 'GET') {
|
||||
$sql = "SELECT id, domain, confirmed_at FROM confirmed_domains WHERE user_id = ? ORDER BY confirmed_at DESC";
|
||||
$stmt = mysqli_prepare($conn, $sql);
|
||||
mysqli_stmt_bind_param($stmt, 'i', $user_id);
|
||||
mysqli_stmt_execute($stmt);
|
||||
$result = mysqli_stmt_get_result($stmt);
|
||||
$domains = [];
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$domains[] = $row;
|
||||
}
|
||||
mysqli_stmt_close($stmt);
|
||||
echo json_encode(['success' => true, 'domains' => $domains]);
|
||||
|
||||
} elseif ($method === 'POST') {
|
||||
require_csrf_token();
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
$domain_id = (int)($input['id'] ?? 0);
|
||||
|
||||
if ($domain_id <= 0) {
|
||||
echo json_encode(['success' => false, 'message' => 'Invalid domain ID.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$sql = "DELETE FROM confirmed_domains WHERE id = ? AND user_id = ?";
|
||||
$stmt = mysqli_prepare($conn, $sql);
|
||||
mysqli_stmt_bind_param($stmt, 'ii', $domain_id, $user_id);
|
||||
mysqli_stmt_execute($stmt);
|
||||
mysqli_stmt_close($stmt);
|
||||
|
||||
echo json_encode(['success' => true, 'message' => 'Domain removed.']);
|
||||
|
||||
} else {
|
||||
echo json_encode(['success' => false, 'message' => 'Invalid request method.'], 405);
|
||||
}
|
||||
?>
|
||||
@@ -3,6 +3,27 @@ include "../utils/security.php";
|
||||
secure_session_start();
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$_SESSION["external_domain_confirmed"] = true;
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
echo json_encode(['success' => false, 'message' => 'Invalid request method.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
$domain = $input['domain'] ?? '';
|
||||
|
||||
if ($domain === '' || !isset($_SESSION['id'])) {
|
||||
echo json_encode(['success' => false, 'message' => 'Missing domain or not logged in.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
include "../../config/config.php";
|
||||
$conn = new mysqli($DB_SERVERNAME, $DB_USERNAME, $DB_PASSWORD, $DB_DATABASE);
|
||||
|
||||
$user_id = $_SESSION['id'];
|
||||
$sql = "INSERT IGNORE INTO confirmed_domains (user_id, domain) VALUES (?, ?)";
|
||||
$stmt = mysqli_prepare($conn, $sql);
|
||||
mysqli_stmt_bind_param($stmt, 'is', $user_id, $domain);
|
||||
mysqli_stmt_execute($stmt);
|
||||
mysqli_stmt_close($stmt);
|
||||
|
||||
echo json_encode(['success' => true]);
|
||||
@@ -57,7 +57,15 @@ else if ($_SESSION["needs_auth"]===false && $_SESSION["mfa_authenticated"]==1 &&
|
||||
mysqli_stmt_close($stmt);
|
||||
if(!empty($send_to)){
|
||||
$external_domain = is_external_domain($send_to);
|
||||
if ($external_domain !== null && !isset($_SESSION["external_domain_confirmed"])){
|
||||
if ($external_domain !== null){
|
||||
$sql="SELECT id FROM confirmed_domains WHERE user_id = ? AND domain = ?";
|
||||
$stmt = mysqli_prepare($conn, $sql);
|
||||
mysqli_stmt_bind_param($stmt, 'is', $user_id, $external_domain);
|
||||
mysqli_stmt_execute($stmt);
|
||||
mysqli_stmt_store_result($stmt);
|
||||
$domain_confirmed = mysqli_stmt_num_rows($stmt) > 0;
|
||||
mysqli_stmt_close($stmt);
|
||||
if (!$domain_confirmed){
|
||||
$data=[
|
||||
'message' => 'external_redirect_warning',
|
||||
'domain' => $external_domain,
|
||||
@@ -69,6 +77,12 @@ else if ($_SESSION["needs_auth"]===false && $_SESSION["mfa_authenticated"]==1 &&
|
||||
'redirect' => append_auth_token_to_redirect($send_to, $auth_token)
|
||||
];
|
||||
}
|
||||
}else{
|
||||
$data=[
|
||||
'message' => 'done',
|
||||
'redirect' => append_auth_token_to_redirect($send_to, $auth_token)
|
||||
];
|
||||
}
|
||||
}else{
|
||||
$data=[
|
||||
'message' => 'done',
|
||||
|
||||
@@ -11,7 +11,6 @@ $conn = new mysqli($DB_SERVERNAME, $DB_USERNAME, $DB_PASSWORD, $DB_DATABASE);
|
||||
check_rate_limit($conn, 'set_username', 30, 60);
|
||||
$_SESSION["needs_auth"]=true;
|
||||
$_SESSION["logged_in"]=false;
|
||||
unset($_SESSION["external_domain_confirmed"]);
|
||||
$username = strtolower((string) ($_POST["username"] ?? ""));
|
||||
$_SESSION["username"]=preg_replace("/[^a-z0-9_]/","",$username);
|
||||
session_regenerate_id(true);
|
||||
|
||||
@@ -154,6 +154,26 @@
|
||||
</div>';
|
||||
}
|
||||
|
||||
$sql="CREATE TABLE IF NOT EXISTS confirmed_domains (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
user_id INT NOT NULL,
|
||||
domain VARCHAR(255) NOT NULL,
|
||||
confirmed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY unique_user_domain (user_id, domain)
|
||||
);";
|
||||
|
||||
|
||||
if ($conn->query($sql) === TRUE) {
|
||||
echo '<br><div class="alert alert-success" role="alert">
|
||||
Table confirmed_domains created successfully!
|
||||
</div>';
|
||||
} else {
|
||||
$success=0;
|
||||
echo '<br><div class="alert alert-danger" role="alert">
|
||||
Error creating confirmed_domains: ' . $conn->error .'
|
||||
</div>';
|
||||
}
|
||||
|
||||
|
||||
|
||||
if($success!==1){
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
<script>
|
||||
const redirect_api="/api/login/redirect.php";
|
||||
let pendingRedirectUrl = null;
|
||||
let pendingDomain = null;
|
||||
|
||||
async function redirect() {
|
||||
try {
|
||||
@@ -65,6 +66,7 @@
|
||||
if (redirectUrl) {
|
||||
if (data.message === 'external_redirect_warning') {
|
||||
pendingRedirectUrl = redirectUrl;
|
||||
pendingDomain = data.domain;
|
||||
document.getElementById('externalDomainDisplay').textContent = data.domain;
|
||||
document.getElementById('loadingSpinner').style.display = 'none';
|
||||
document.getElementById('statusText').textContent = 'Login warning';
|
||||
@@ -95,7 +97,11 @@
|
||||
});
|
||||
|
||||
function confirmExternalRedirect() {
|
||||
fetch('/api/login/confirm_external_redirect.php', { method: 'POST' }).then(() => {
|
||||
fetch('/api/login/confirm_external_redirect.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ domain: pendingDomain })
|
||||
}).then(() => {
|
||||
window.location.href = pendingRedirectUrl;
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user