From 8964dfcf972ad7b60f832184eb0b054860cd57cb Mon Sep 17 00:00:00 2001 From: martbost Date: Sat, 29 Aug 2026 06:18:35 -0500 Subject: [PATCH] =?UTF-8?q?Detect=20in-app=20browsers=20=E2=80=94=20the=20?= =?UTF-8?q?actual=20reason=20#34=20could=20not=20connect?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Janie's screenshot showed the X / chevron / share / kebab chrome of TELEGRAM'S in-app browser, not Trust's DApp browser. She tapped her sponsor's link in a Telegram chat, Telegram opened it in its own webview, and that webview can never hold a wallet. The page said "no wallet in this browser", she said she was using Trust — both true, completely at cross purposes. Our advice made it worse: "open your wallet's browser and type the address" is useless to someone whose whole reason for being on the page is that they tapped a link. Now we name the browser they are actually in — Telegram, Facebook, Instagram, LINE, Messenger, X, or a generic Android WebView — say plainly that it cannot hold a wallet and that this is not their fault, and give them the one useful thing: a button that copies the address to the clipboard so they can paste it into Trust. There is an execCommand fallback because older webviews have no clipboard API, and leaving a button that silently does nothing would be worse than not having one. Detection deliberately requires the absence of window.ethereum before calling something an in-app browser: wallet browsers ARE WebViews, and those are exactly the ones that work. Verified against Telegram, Android WebView, Trust (correctly ignored) and mobile Safari (correctly ignored). This will hit far more members than Janie — every link tapped inside a chat app lands in the same trap. Co-Authored-By: Claude Fable 5 --- public/inapp-browser.js | 74 +++++++++++++++++++++++++++++++++++++++++ public/my.html | 2 +- public/my.js | 2 +- public/suite.html | 2 +- public/suite.js | 2 +- public/training.html | 2 +- 6 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 public/inapp-browser.js diff --git a/public/inapp-browser.js b/public/inapp-browser.js new file mode 100644 index 0000000..7fc7c0b --- /dev/null +++ b/public/inapp-browser.js @@ -0,0 +1,74 @@ +// Detects "in-app browsers" — the webviews Telegram, Facebook, Instagram and +// friends open when you tap a link inside them. +// +// Why this exists: a member taps their sponsor's link in a Telegram chat, +// Telegram opens it in its own webview, and that webview can never hold a +// wallet. The page correctly reported "no wallet in this browser" and the +// member correctly replied that they were using Trust — both true, and +// completely at cross purposes. The instruction to "open your wallet's browser" +// is useless when the reason they are here is that they tapped a link. +// +// So: name the actual browser they are in, and give them the one thing that +// actually helps — the address on their clipboard. +(function () { + 'use strict'; + + function detect() { + var ua = navigator.userAgent || ''; + // Telegram exposes a proxy object in its webview on Android, and the Mini + // App bridge on both. Far more reliable than sniffing its UA, which is a + // plain Chrome string. + if (window.TelegramWebviewProxy || (window.Telegram && window.Telegram.WebApp && !window.ethereum)) return 'Telegram'; + if (/FBAN|FBAV|FB_IAB/i.test(ua)) return 'Facebook'; + if (/Instagram/i.test(ua)) return 'Instagram'; + if (/\bLine\//i.test(ua)) return 'LINE'; + if (/\bMessenger\b/i.test(ua)) return 'Messenger'; + if (/\bTwitter\b/i.test(ua)) return 'X'; + // Generic Android WebView: "; wv)" is the giveaway. Only treat it as an + // in-app browser when no wallet is present, since some wallet browsers are + // themselves WebViews and those are exactly the ones that DO work. + if (/; wv\)/i.test(ua) && !window.ethereum) return 'an in-app browser'; + return null; + } + + window.RMCInApp = { + name: detect, + // Returns HTML for the wallet-error slot, or '' when this is a normal + // browser and the existing "open your wallet's browser" advice is right. + notice: function (pathForWallet) { + var w = detect(); + if (!w) return ''; + var url = 'rmcircle.team' + (pathForWallet || location.pathname); + return 'You’re in ' + w + '’s built-in browser — it can’t hold a wallet, ' + + 'so no wallet app can connect here. That’s why this isn’t working, and it’s not anything you did wrong.' + + '
' + + '
Then open Trust (or MetaMask / SafePal), find its ' + + 'Browser or DApps tab, and paste it there. Typing ' + url + ' by hand works too.
'; + }, + // Wire the copy button after the notice is inserted. + bind: function (pathForWallet) { + var btn = document.getElementById('rmcCopyAddr'); + if (!btn) return; + btn.addEventListener('click', function () { + var url = 'https://rmcircle.team' + (pathForWallet || location.pathname); + var note = document.getElementById('rmcCopiedNote'); + function ok() { if (note) note.textContent = 'Copied — now paste it in your wallet’s browser.'; } + if (navigator.clipboard && navigator.clipboard.writeText) { + navigator.clipboard.writeText(url).then(ok, function () { fallback(url, ok); }); + } else { fallback(url, ok); } + }); + function fallback(url, done) { + // Older webviews have no clipboard API — select the text so a long-press + // copy works, rather than leaving the button doing nothing. + var t = document.createElement('textarea'); + t.value = url; + t.style.cssText = 'position:fixed;left:0;top:0;opacity:0'; + document.body.appendChild(t); + t.focus(); t.select(); + try { document.execCommand('copy'); done(); } catch (e) {} + setTimeout(function () { document.body.removeChild(t); }, 100); + } + } + }; +})(); diff --git a/public/my.html b/public/my.html index 2c62a8c..91ca31e 100644 --- a/public/my.html +++ b/public/my.html @@ -31,4 +31,4 @@
All figures are read live from the RM Circle smart contract on Polygon and are historical facts, not a promise of future results. Participation involves cryptocurrency and smart-contract risk. Never use funds you cannot afford to lose.
- + diff --git a/public/my.js b/public/my.js index 31a5610..ee99b10 100644 --- a/public/my.js +++ b/public/my.js @@ -325,7 +325,7 @@ const err=document.getElementById('msgAuthErr'); try{ const eth=await window.RMCWallet.pick(); - if(!eth){err.textContent='This browser has no wallet in it. Open this page INSIDE your wallet app instead: open Trust, MetaMask, SafePal or Coinbase, find its Browser (or DApps) tab, and type rmcircle.team/my into that address bar. On iPhone, Trust no longer has a browser — use MetaMask or SafePal, or ask your sponsor to link you instead.';return;} + if(!eth){{var _ia=(window.RMCInApp&&window.RMCInApp.notice('/my'))||'';if(_ia){err.innerHTML=_ia;if(err.style)err.style.display='block';window.RMCInApp.bind('/my');}else{err.textContent='This browser has no wallet in it. Open this page INSIDE your wallet app instead: open Trust, MetaMask, SafePal or Coinbase, find its Browser (or DApps) tab, and type rmcircle.team/my into that address bar. On iPhone, Trust no longer has a browser — use MetaMask or SafePal, or ask your sponsor to link you instead.';}}return;} const accs=await eth.request({method:'eth_requestAccounts'});const account=accs[0]; // Match the wallet's active chain to the SIWE message's Chain ID (137), // or the wallet rejects the signature ("chain ID does not match"). diff --git a/public/suite.html b/public/suite.html index d5927c1..1ab1898 100644 --- a/public/suite.html +++ b/public/suite.html @@ -49,6 +49,6 @@
The Suite is included with team membership — never sold separately, never an extra cost. Tools marked "in development" ship in the order the team builds them; only what you can click today is promised today. Independent team resource · No income is guaranteed · Cryptocurrency involves risk. Level costs, straight from the contract →
- + diff --git a/public/suite.js b/public/suite.js index 4d0c05e..e98c4ee 100644 --- a/public/suite.js +++ b/public/suite.js @@ -105,7 +105,7 @@ btn.disabled = true; btn.textContent = 'Connecting…'; try { var eth = await window.RMCWallet.pick(); - if (!eth) { err.textContent = 'This browser has no wallet in it. Open this page INSIDE your wallet app instead: open Trust, MetaMask, SafePal or Coinbase, find its Browser (or DApps) tab, and type rmcircle.team/suite into that address bar. On iPhone, Trust no longer has a browser — use MetaMask or SafePal, or ask your sponsor to link you instead.'; err.style.display = 'block'; btn.disabled = false; btn.textContent = '🔑 Connect wallet — light up my tools'; return; } + if (!eth) { {var _ia=(window.RMCInApp&&window.RMCInApp.notice('/suite'))||'';if(_ia){err.innerHTML=_ia;if(err.style)err.style.display='block';window.RMCInApp.bind('/suite');}else{err.textContent = 'This browser has no wallet in it. Open this page INSIDE your wallet app instead: open Trust, MetaMask, SafePal or Coinbase, find its Browser (or DApps) tab, and type rmcircle.team/suite into that address bar. On iPhone, Trust no longer has a browser — use MetaMask or SafePal, or ask your sponsor to link you instead.';}} err.style.display = 'block'; btn.disabled = false; btn.textContent = '🔑 Connect wallet — light up my tools'; return; } var accs = await eth.request({ method: 'eth_requestAccounts' }); var account = accs[0]; try { await window.RMCWallet.ensureChain(eth); } catch (ce) {} diff --git a/public/training.html b/public/training.html index 683b93e..a9200e1 100644 --- a/public/training.html +++ b/public/training.html @@ -88,4 +88,4 @@ - +