TKK_E32230273/scan_here.php

148 lines
6.8 KiB
PHP

<?php
include 'koneksi.php';
$token = $_GET['token'] ?? '';
$valid = false;
$account = null;
if (!empty($token)) {
$stmt = $pdo->prepare("SELECT * FROM account WHERE code_register = ?");
$stmt->execute([$token]);
$account = $stmt->fetch(PDO::FETCH_ASSOC);
if ($account) {
$valid = true;
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Registrasi Sidik Jari</title>
<link rel="stylesheet" href="vendors/feather/feather.css">
<link rel="stylesheet" href="vendors/ti-icons/css/themify-icons.css">
<link rel="stylesheet" href="vendors/css/vendor.bundle.base.css">
<link rel="stylesheet" href="vendors/mdi/css/materialdesignicons.min.css">
<link rel="stylesheet" href="css/vertical-layout-light/style.css">
<link rel="shortcut icon" href="images/myn.png" />
<style>
body { background-color: #f8f9fa; display: flex; align-items: center; justify-content: center; min-height: 100vh; margin: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; }
.scan-card { background: #fff; padding: 25px 20px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.02); text-align: center; max-width: 320px; width: 100%; border: 1px solid #e2e8f0; }
.finger-icon { font-size: 50px; color: #4b49ac; margin-bottom: 15px; display: inline-block; }
</style>
</head>
<body>
<div class="scan-card">
<?php if ($valid && empty($account['finger_id'])): ?>
<i class="mdi mdi-fingerprint finger-icon"></i>
<h4 class="font-weight-bold mb-1" style="font-size: 18px;">Scan Fingerprint</h4>
<p class="text-muted mb-4" style="font-size:12px;">Akun: <strong><?= htmlspecialchars($account['name']); ?></strong><br>@<?= htmlspecialchars($account['username']); ?></p>
<button id="btnScan" class="btn btn-primary btn-block d-flex align-items-center justify-content-center" style="border-radius:8px; font-weight:600; padding:12px; font-size:16px;" onclick="startWebAuthnRegistration()">
<i class="mdi mdi-fingerprint mr-2" style="font-size: 20px;"></i> Scan
</button>
<div id="webAuthnStatus" class="mt-4 font-weight-bold" style="display:none; font-size:14px;"></div>
<!-- hidden fields for JS -->
<input type="hidden" id="fingerprintAccountId" value="<?= $account['id_account']; ?>">
<?php elseif ($valid && !empty($account['finger_id'])): ?>
<i class="mdi mdi-check-circle finger-icon" style="color:#28a745; text-shadow: 0 4px 10px rgba(40,167,69,0.2);"></i>
<h4 class="font-weight-bold mb-2">Sudah Terdaftar</h4>
<p class="text-muted mb-0" style="font-size:14px;">Akun: <strong><?= htmlspecialchars($account['name']); ?></strong><br>Sidik jari untuk akun ini sudah terdaftar. Maksimal 1 sidik jari per akun.</p>
<?php else: ?>
<script>window.location.href = '404.php';</script>
<?php exit; ?>
<?php endif; ?>
</div>
<script src="vendors/js/vendor.bundle.base.js"></script>
<script>
async function startWebAuthnRegistration() {
var btn = document.getElementById("btnScan");
var statusEl = document.getElementById("webAuthnStatus");
var accountId = document.getElementById("fingerprintAccountId").value;
btn.disabled = true;
statusEl.innerHTML = '<i class="mdi mdi-loading mdi-spin mr-1"></i>Menunggu Sensor...';
statusEl.className = "mt-4 text-info font-weight-bold";
statusEl.style.display = "block";
if (!window.PublicKeyCredential) {
statusEl.innerHTML = '<i class="mdi mdi-alert mr-1"></i>WebAuthn tidak didukung di browser ini.';
statusEl.className = "mt-4 text-danger font-weight-bold";
btn.disabled = false;
return;
}
try {
const challenge = new Uint8Array(32); crypto.getRandomValues(challenge);
const userId = new Uint8Array(16); crypto.getRandomValues(userId);
<?php
$stmtEx = $pdo->query("SELECT finger_id FROM account WHERE finger_id IS NOT NULL AND finger_id != ''");
$allCredsArray = $stmtEx->fetchAll(PDO::FETCH_COLUMN);
?>
const allExistingCreds = <?= json_encode($allCredsArray) ?>;
const excludeList = allExistingCreds.map(idBase64 => {
return {
type: "public-key",
id: Uint8Array.from(atob(idBase64), c => c.charCodeAt(0))
};
});
const publicKey = {
challenge: challenge,
excludeCredentials: excludeList,
rp: { name: "Identia App", id: window.location.hostname },
user: { id: userId, name: "Identia_user", displayName: "Identia_user" },
pubKeyCredParams: [{ type: "public-key", alg: -7 }, { type: "public-key", alg: -257 }],
authenticatorSelection: {
authenticatorAttachment: "platform",
userVerification: "required",
residentKey: "required",
requireResidentKey: true
},
timeout: 60000,
attestation: "none"
};
const credential = await navigator.credentials.create({ publicKey });
const rawIdBase64 = btoa(String.fromCharCode.apply(null, new Uint8Array(credential.rawId)));
statusEl.innerHTML = '<i class="mdi mdi-loading mdi-spin mr-1"></i>Menyimpan Sidik Jari...';
let fd = new FormData();
fd.append('id_account', accountId);
fd.append('credential_id', rawIdBase64);
fetch("save_fingerprint_account.php", { method: "POST", body: fd })
.then(r => r.json())
.then(d => {
if(d.status === 'success') {
statusEl.innerHTML = '<i class="mdi mdi-check-circle mr-1 text-success" style="font-size:30px; display:block; margin-bottom:10px;"></i>Sidik Jari Berhasil Disimpan!<br><small class="text-muted mt-2 d-block">Anda dapat menutup halaman ini.</small>';
statusEl.className = "mt-4 text-success font-weight-bold";
btn.style.display = 'none';
} else {
statusEl.innerHTML = '<i class="mdi mdi-alert mr-1"></i>' + (d.message || 'Gagal menyimpan ke server');
statusEl.className = "mt-4 text-danger font-weight-bold";
btn.disabled = false;
}
}).catch(e => {
statusEl.innerHTML = '<i class="mdi mdi-alert mr-1"></i>Terjadi Kesalahan Jaringan.';
statusEl.className = "mt-4 text-danger font-weight-bold";
btn.disabled = false;
});
} catch (err) {
statusEl.innerHTML = '<i class="mdi mdi-alert mr-1"></i>Pendaftaran Dibatalkan / Gagal (' + err.message + ')';
statusEl.className = "mt-4 text-danger font-weight-bold";
btn.disabled = false;
}
}
</script>
</body>
</html>