Sign-in: stop telling a fast returning member off for being fast

The email-code endpoint refuses a request that arrives within two seconds of
the page loading, because a script fills a form instantly and a person does
not. A member whose email is already filled in by the browser has nothing to
type, taps straight away, and gets "Give the page a second, then tap again."

The page now waits out the remainder itself and sends when the window has
passed, so the person sees the normal sending state instead of an error.
The server check is untouched, so anything posting at the endpoint without a
page behind it still fails exactly as before.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-09-23 05:50:34 -05:00
parent 286ac9207a
commit 489d832546
17 changed files with 28 additions and 16 deletions
+1 -1
View File
@@ -492,7 +492,7 @@
</div> </div>
</div> </div>
<script src="/assets/common.js?v=20260916a"></script> <script src="/assets/common.js?v=20260923b"></script>
<script src="/assets/admin.js?v=20260923a"></script> <script src="/assets/admin.js?v=20260923a"></script>
</body> </body>
</html> </html>
+12
View File
@@ -172,9 +172,21 @@ window.IAP = (function () {
} }
armHoneypots(); document.addEventListener('DOMContentLoaded', armHoneypots); armHoneypots(); document.addEventListener('DOMContentLoaded', armHoneypots);
const hpValue = el => (el && el.dataset.touched === '1') ? (el.value || '') : ''; const hpValue = el => (el && el.dataset.touched === '1') ? (el.value || '') : '';
// The server refuses a code request that arrives within a couple of seconds of the page loading,
// because a script fills a form instantly and a person does not. A returning member whose email
// is already autofilled has nothing to type, taps straight away, and gets told off for being
// quick (Marty, 2026-09-23). So the page waits out the remainder itself: the person sees the
// normal sending state, and anything posting at the endpoint without a page behind it still
// fails the same check.
const MIN_FORM_MS = 2400; // the server wants 2000; leave headroom for clock skew in transit
function formSettled() {
const left = MIN_FORM_MS - (Date.now() - FORM_TS);
return left > 0 ? new Promise(r => setTimeout(r, left)) : Promise.resolve();
}
async function requestCode(email, opts) { async function requestCode(email, opts) {
const o = opts || {}; const o = opts || {};
let pick = null; let pick = null;
await formSettled();
for (let i = 0; i < 4; i++) { for (let i = 0; i < 4; i++) {
const r = await (await fetch('/api/auth/email/start', { method: 'POST', headers: { 'Content-Type': 'application/json' }, const r = await (await fetch('/api/auth/email/start', { method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, fts: FORM_TS, hp_field_x9: hpValue(o.honeypot), pick }) })).json(); body: JSON.stringify({ email, fts: FORM_TS, hp_field_x9: hpValue(o.honeypot), pick }) })).json();
+1 -1
View File
@@ -141,7 +141,7 @@
<div class="small">Advertising services with a performance referral program. Not an investment product; no income guarantees. Crypto transactions are irreversible. Never spend what you cannot afford.</div> <div class="small">Advertising services with a performance referral program. Not an investment product; no income guarantees. Crypto transactions are irreversible. Never spend what you cannot afford.</div>
</footer> </footer>
</div> </div>
<script src="/assets/common.js?v=20260916a"></script> <script src="/assets/common.js?v=20260923b"></script>
<script src="/assets/contract.js?v=20260908p"></script> <script src="/assets/contract.js?v=20260908p"></script>
<script src="/assets/chat.js?v=20260906m"></script> <script src="/assets/chat.js?v=20260906m"></script>
</body> </body>
+1 -1
View File
@@ -26,7 +26,7 @@
<p class="muted small">You decide whether, and how much, to spend. Never spend more than you can afford to lose.</p> <p class="muted small">You decide whether, and how much, to spend. Never spend more than you can afford to lose.</p>
</div> </div>
</div></section> </div></section>
<script src="/assets/common.js?v=20260916a"></script> <script src="/assets/common.js?v=20260923b"></script>
<script src="/assets/legal.js?v=20260908a"></script> <script src="/assets/legal.js?v=20260908a"></script>
</body> </body>
</html> </html>
+1 -1
View File
@@ -83,6 +83,6 @@
<div class="small">Advertising services with a performance referral program. Not an investment product; no income guarantees.</div> <div class="small">Advertising services with a performance referral program. Not an investment product; no income guarantees.</div>
</footer> </footer>
</div> </div>
<script src="/assets/common.js?v=20260916a"></script> <script src="/assets/common.js?v=20260923b"></script>
</body> </body>
</html> </html>
+1 -1
View File
@@ -495,7 +495,7 @@
</div> </div>
</section> </section>
<script src="/assets/common.js?v=20260916a"></script> <script src="/assets/common.js?v=20260923b"></script>
<script src="/assets/wallet.js?v=20260909c"></script> <script src="/assets/wallet.js?v=20260909c"></script>
<script src="/assets/home.js?v=20260920fdf"></script> <script src="/assets/home.js?v=20260920fdf"></script>
<script src="/assets/chat.js?v=20260906m"></script> <script src="/assets/chat.js?v=20260906m"></script>
+1 -1
View File
@@ -157,7 +157,7 @@
InstantAdPay · <a href="/contract">Contract</a> · <a href="/terms">Terms</a> · <a href="/privacy">Privacy</a> · <a href="/disclaimer">Disclaimer</a> InstantAdPay · <a href="/contract">Contract</a> · <a href="/terms">Terms</a> · <a href="/privacy">Privacy</a> · <a href="/disclaimer">Disclaimer</a>
</div> </div>
</div> </div>
<script src="/assets/common.js?v=20260916a"></script> <script src="/assets/common.js?v=20260923b"></script>
<script src="/assets/join.js?v=20260914a"></script> <script src="/assets/join.js?v=20260914a"></script>
</body> </body>
</html> </html>
+1 -1
View File
@@ -104,7 +104,7 @@
<div class="small">Advertising services with a performance referral program. Not an investment product; no income guarantees.</div> <div class="small">Advertising services with a performance referral program. Not an investment product; no income guarantees.</div>
</footer> </footer>
</div> </div>
<script src="/assets/common.js?v=20260916a"></script> <script src="/assets/common.js?v=20260923b"></script>
<script src="/assets/launch.js?v=20260915b"></script> <script src="/assets/launch.js?v=20260915b"></script>
</body> </body>
</html> </html>
+1 -1
View File
@@ -39,7 +39,7 @@
<div>InstantAdPay · <a href="/">how it works</a> · <a id="contractLink" href="#" target="_blank" rel="noopener">contract source ↗</a></div> <div>InstantAdPay · <a href="/">how it works</a> · <a id="contractLink" href="#" target="_blank" rel="noopener">contract source ↗</a></div>
</footer> </footer>
</div> </div>
<script src="/assets/common.js?v=20260916a"></script> <script src="/assets/common.js?v=20260923b"></script>
<script src="/assets/ledger.js?v=20260906m"></script> <script src="/assets/ledger.js?v=20260906m"></script>
<script src="https://polhunter.com/embed.js" data-slots="1" async></script> <script src="https://polhunter.com/embed.js" data-slots="1" async></script>
<script src="/assets/chat.js?v=20260906m"></script> <script src="/assets/chat.js?v=20260906m"></script>
+1 -1
View File
@@ -1067,7 +1067,7 @@
</div> </div>
</div> </div>
</div> </div>
<script src="/assets/common.js?v=20260916a"></script> <script src="/assets/common.js?v=20260923b"></script>
<script src="/assets/wallet.js?v=20260911a"></script> <script src="/assets/wallet.js?v=20260911a"></script>
<script src="/assets/promo.js?v=20260921d"></script> <script src="/assets/promo.js?v=20260921d"></script>
<script src="/assets/my.js?v=20260922v"></script> <script src="/assets/my.js?v=20260922v"></script>
+1 -1
View File
@@ -128,7 +128,7 @@
<div class="small">Advertising services with a performance referral program. Not an investment product; no income guarantees. Crypto transactions are irreversible. Never spend what you cannot afford to lose.</div> <div class="small">Advertising services with a performance referral program. Not an investment product; no income guarantees. Crypto transactions are irreversible. Never spend what you cannot afford to lose.</div>
</footer> </footer>
</div> </div>
<script src="/assets/common.js?v=20260916a"></script> <script src="/assets/common.js?v=20260923b"></script>
<script src="/assets/partners.js?v=20260914a"></script> <script src="/assets/partners.js?v=20260914a"></script>
</body> </body>
</html> </html>
+1 -1
View File
@@ -192,7 +192,7 @@
<div class="small">Advertising services with a performance referral program. Not an investment product; no income guarantees. Crypto transactions are irreversible. Never spend what you cannot afford.</div> <div class="small">Advertising services with a performance referral program. Not an investment product; no income guarantees. Crypto transactions are irreversible. Never spend what you cannot afford.</div>
</footer> </footer>
</div> </div>
<script src="/assets/common.js?v=20260916a"></script> <script src="/assets/common.js?v=20260923b"></script>
<script src="/assets/plays.js?v=20260910b"></script> <script src="/assets/plays.js?v=20260910b"></script>
</body> </body>
</html> </html>
+1 -1
View File
@@ -29,7 +29,7 @@
<p class="muted small">We use reasonable safeguards, but no system is perfectly secure. Protect your email and your wallet.</p> <p class="muted small">We use reasonable safeguards, but no system is perfectly secure. Protect your email and your wallet.</p>
</div> </div>
</div></section> </div></section>
<script src="/assets/common.js?v=20260916a"></script> <script src="/assets/common.js?v=20260923b"></script>
<script src="/assets/legal.js?v=20260908a"></script> <script src="/assets/legal.js?v=20260908a"></script>
</body> </body>
</html> </html>
+1 -1
View File
@@ -37,7 +37,7 @@
<p class="muted small" style="margin-top:18px">See also the <a href="/disclaimer">Disclaimer</a> and <a href="/privacy">Privacy Policy</a>.</p> <p class="muted small" style="margin-top:18px">See also the <a href="/disclaimer">Disclaimer</a> and <a href="/privacy">Privacy Policy</a>.</p>
</div> </div>
</div></section> </div></section>
<script src="/assets/common.js?v=20260916a"></script> <script src="/assets/common.js?v=20260923b"></script>
<script src="/assets/legal.js?v=20260908a"></script> <script src="/assets/legal.js?v=20260908a"></script>
</body> </body>
</html> </html>
+1 -1
View File
@@ -34,7 +34,7 @@
<p><a href="/ledger">← Back to the live ledger</a> · <a href="/contract">Read the contract review</a></p> <p><a href="/ledger">← Back to the live ledger</a> · <a href="/contract">Read the contract review</a></p>
</div> </div>
</section> </section>
<script src="/assets/common.js?v=20260916a"></script> <script src="/assets/common.js?v=20260923b"></script>
<script src="/assets/tx.js?v=20260906m"></script> <script src="/assets/tx.js?v=20260906m"></script>
</body> </body>
</html> </html>
+1 -1
View File
@@ -47,7 +47,7 @@
</div> </div>
</div> </div>
</section> </section>
<script src="/assets/common.js?v=20260916a"></script> <script src="/assets/common.js?v=20260923b"></script>
<script src="/assets/wall.js?v=20260911v"></script> <script src="/assets/wall.js?v=20260911v"></script>
</body> </body>
</html> </html>
+1 -1
View File
@@ -121,7 +121,7 @@
<div class="small">Advertising services with a performance referral program. Not an investment product; no income guarantees. Crypto transactions are irreversible. Never share your recovery phrase.</div> <div class="small">Advertising services with a performance referral program. Not an investment product; no income guarantees. Crypto transactions are irreversible. Never share your recovery phrase.</div>
</footer> </footer>
</div> </div>
<script src="/assets/common.js?v=20260916a"></script> <script src="/assets/common.js?v=20260923b"></script>
<script src="/assets/wallets.js?v=20260911b"></script> <script src="/assets/wallets.js?v=20260911b"></script>
</body> </body>
</html> </html>