maya-token-bridge / index.html
delta
v3: bookmarklet token extractor - works from phone
f47576c
Raw
History Blame Contribute Delete
11.4 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Maya Token Extract</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
background: #0d0d0d; color: #e0e0e0;
font-family: 'Courier New', monospace;
min-height: 100vh; padding: 20px;
}
.container { max-width: 600px; margin: 0 auto; }
h1 { color: #ff6b9d; font-size: 1.1rem; margin-bottom: 16px; letter-spacing: 2px; }
.step {
background: #111; border: 1px solid #222; border-radius: 6px;
padding: 14px; margin-bottom: 12px;
}
.step-num { color: #ff6b9d; font-weight: bold; font-size: 1.1rem; }
.step p { margin-top: 6px; font-size: 0.82rem; line-height: 1.6; color: #bbb; }
.code-box {
background: #0a1510; border: 1px solid #1e4d2a; padding: 10px;
border-radius: 4px; word-break: break-all; font-size: 0.55rem;
color: #4daa72; margin: 8px 0; line-height: 1.4;
user-select: all; cursor: pointer; max-height: 100px; overflow-y: auto;
}
.btn {
background: #ff6b9d; color: #000; border: none;
padding: 12px 20px; font-family: monospace; font-size: 0.85rem;
font-weight: bold; border-radius: 4px; cursor: pointer;
letter-spacing: 1px; width: 100%; margin-top: 8px;
}
.btn:active { opacity: 0.7; }
.btn-alt { background: #1a3d28; color: #4daa72; }
.status {
margin-top: 12px; padding: 10px; border-radius: 4px;
font-size: 0.78rem; display: none;
}
.ok { background: #0a1f13; border: 1px solid #1e5c35; color: #4daa72; display: block; }
.err { background: #1f0a0a; border: 1px solid #5c1e1e; color: #aa4d4d; display: block; }
.info { background: #0a0f1f; border: 1px solid #1e2f5c; color: #4d72aa; display: block; }
.hidden { display: none; }
textarea {
width: 100%; background: #161616; border: 1px solid #2a2a2a;
color: #e0e0e0; padding: 10px; font-family: monospace;
font-size: 0.8rem; border-radius: 4px; resize: vertical;
min-height: 80px;
}
.or-line { text-align: center; color: #333; font-size: 0.7rem; margin: 16px 0; letter-spacing: 3px; }
.result-box { display: none; margin-top: 16px; }
.result-box.show { display: block; }
.token-preview {
background: #0a1510; border: 1px solid #1e4d2a; padding: 8px;
border-radius: 4px; font-size: 0.55rem; color: #4daa72;
word-break: break-all; max-height: 60px; overflow: hidden;
}
</style>
</head>
<body>
<div class="container">
<h1>◈ MAYA TOKEN EXTRACT v3</h1>
<!-- Check if we received a token via URL param -->
<div id="receivedToken" class="hidden">
<div class="step">
<span class="step-num">TOKEN RECEIVED!</span>
<div class="token-preview" id="receivedPreview"></div>
<button class="btn" onclick="processReceivedToken()">SAVE TO BRIDGE + TEST</button>
<div class="status" id="receivedStatus"></div>
</div>
</div>
<!-- METHOD 1: Paste token directly -->
<div id="mainUI">
<div class="step">
<span class="step-num">STEP 1</span>
<p>Open <b>sesameai.app</b> in your browser. Sign in with Google normally.</p>
<a href="https://sesameai.app" target="_blank" class="btn" style="display:block;text-align:center;text-decoration:none;margin-top:8px;">OPEN SESAMEAI.APP</a>
</div>
<div class="step">
<span class="step-num">STEP 2</span>
<p>After signing in, tap the button below to copy the extractor script. Then create a <b>new bookmark</b> in your browser, edit it, and paste the script as the URL.</p>
<button class="btn btn-alt" onclick="copyBookmarklet()">COPY EXTRACTOR SCRIPT</button>
<p style="margin-top:8px;font-size:0.7rem;color:#666;">
Android Chrome: Menu → Bookmarks → ⋮ → Edit → replace URL with copied script<br>
Then go to sesameai.app and tap the bookmark from address bar
</p>
</div>
<div class="step">
<span class="step-num">STEP 3</span>
<p>OR: After signing in to sesameai.app, paste this in the browser console (if you can access it):</p>
<div class="code-box" id="consoleScript" onclick="copyConsole()"></div>
<button class="btn btn-alt" onclick="copyConsole()">COPY CONSOLE SCRIPT</button>
</div>
<div class="or-line">— OR PASTE TOKEN DIRECTLY —</div>
<div class="step">
<span class="step-num">MANUAL</span>
<p>If you have the Firebase ID token from DevTools or any other source, paste it here:</p>
<textarea id="manualToken" placeholder="paste Firebase ID token here..."></textarea>
<button class="btn" onclick="processManualToken()">SAVE + TEST TOKEN</button>
</div>
<div class="status" id="mainStatus"></div>
<div class="result-box" id="results">
<div class="code-box" id="resultsText" style="max-height:300px;font-size:0.6rem;"></div>
</div>
</div>
</div>
<script>
const HF_REPO = 'Melofhell00/maya-memory';
const HF_TOKEN = atob('aGZfRmVtSHJndHhwcGVQZ3BYblF5eVFsSUlISUVvTXJOQmdPZA==');
const FK = 'AIzaSyDtC7Uwb5pGAsdmrH2T4Gqdk5Mga07jYPM';
const THIS_URL = window.location.origin + window.location.pathname;
// Bookmarklet: extracts token from IndexedDB and redirects here with it
const extractorCode = `
(async()=>{
try{
const db=await new Promise((r,j)=>{const q=indexedDB.open('firebaseLocalStorageDb');q.onsuccess=e=>r(e.target.result);q.onerror=j});
const s=db.transaction('firebaseLocalStorage','readonly').objectStore('firebaseLocalStorage');
const d=await new Promise((r,j)=>{const q=s.getAll();q.onsuccess=e=>r(e.target.result);q.onerror=j});
let t='',rt='';
for(const i of d){
const m=i&&i.value&&i.value.stsTokenManager;
if(m&&m.accessToken){t=m.accessToken;rt=m.refreshToken||'';break}
}
if(t){
window.location='${THIS_URL}?t='+encodeURIComponent(t)+'&rt='+encodeURIComponent(rt);
}else{
alert('No token found in IndexedDB. Are you signed in?');
}
}catch(e){alert('Error: '+e.message)}
})()
`.trim().replace(/\n/g,'');
const bookmarkletURL = 'javascript:void(' + encodeURIComponent(extractorCode) + ')';
// Console-friendly version
const consoleCode = `
(async()=>{
const db=await new Promise(r=>{const q=indexedDB.open('firebaseLocalStorageDb');q.onsuccess=e=>r(e.target.result)});
const s=db.transaction('firebaseLocalStorage','readonly').objectStore('firebaseLocalStorage');
const d=await new Promise(r=>{const q=s.getAll();q.onsuccess=e=>r(e.target.result)});
for(const i of d){
const m=i?.value?.stsTokenManager;
if(m?.accessToken){
console.log('TOKEN:',m.accessToken);
console.log('REFRESH:',m.refreshToken);
prompt('Copy this token:',m.accessToken);
return;
}
}
console.log('No token found');
})()
`.trim();
document.getElementById('consoleScript').textContent = consoleCode;
function copyBookmarklet() {
// For mobile, copy the javascript: URL
copyText(bookmarkletURL);
setStatus('mainStatus', 'Copied! Create a bookmark and paste this as the URL.', 'ok');
}
function copyConsole() {
copyText(consoleCode);
setStatus('mainStatus', 'Copied! Paste in browser console on sesameai.app', 'ok');
}
function copyText(text) {
if (navigator.clipboard) {
navigator.clipboard.writeText(text).catch(() => fallbackCopy(text));
} else {
fallbackCopy(text);
}
}
function fallbackCopy(text) {
const ta = document.createElement('textarea');
ta.value = text;
ta.style.position = 'fixed';
ta.style.left = '-9999px';
document.body.appendChild(ta);
ta.select();
document.execCommand('copy');
document.body.removeChild(ta);
}
function setStatus(id, msg, type) {
const el = document.getElementById(id);
el.textContent = msg;
el.className = 'status ' + type;
}
// Check URL params for received token
const params = new URLSearchParams(window.location.search);
const receivedT = params.get('t');
const receivedRT = params.get('rt');
if (receivedT) {
document.getElementById('receivedToken').classList.remove('hidden');
document.getElementById('mainUI').style.display = 'none';
document.getElementById('receivedPreview').textContent = receivedT.substring(0, 100) + '...';
// Clean URL
window.history.replaceState({}, '', window.location.pathname);
}
async function processReceivedToken() {
await processToken(receivedT, receivedRT);
}
async function processManualToken() {
const token = document.getElementById('manualToken').value.trim();
if (!token) {
setStatus('mainStatus', 'Paste a token first', 'err');
return;
}
await processToken(token, '');
}
async function processToken(idToken, refreshToken) {
const statusId = receivedT ? 'receivedStatus' : 'mainStatus';
setStatus(statusId, 'Processing...', 'info');
// Decode JWT
try {
const payload = JSON.parse(atob(idToken.split('.')[1] + '==='));
const provider = payload?.firebase?.sign_in_provider || 'unknown';
const email = payload?.email || 'unknown';
const uid = payload?.sub || 'unknown';
const exp = new Date(payload.exp * 1000).toLocaleString();
let info = `provider: ${provider} | email: ${email} | uid: ${uid} | expires: ${exp}`;
if (provider !== 'google.com') {
setStatus(statusId, `WARNING: provider is "${provider}" not "google.com" — Sesame will reject this token`, 'err');
return;
}
setStatus(statusId, info, 'ok');
} catch(e) {
setStatus(statusId, 'Failed to decode token: ' + e.message, 'err');
return;
}
// Save to HF bridge
try {
const state = {
refresh_token: refreshToken || '',
last_id_token: idToken.substring(0, 50) + '...',
last_updated: new Date().toISOString(),
source: 'token-extract-v3-bookmarklet',
full_id_token: idToken
};
const resp = await fetch(
`https://huggingface.co/api/datasets/${HF_REPO}/commit/main`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${HF_TOKEN}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
summary: 'token from bookmarklet ' + new Date().toISOString(),
operations: [{
op: 'upload',
path_in_repo: 'state.json',
content: btoa(unescape(encodeURIComponent(JSON.stringify(state, null, 2))))
}]
})
}
);
if (resp.ok) {
appendResult('Saved to HF bridge ✓');
} else {
appendResult('HF save failed: ' + resp.status);
}
} catch(e) {
appendResult('HF save error: ' + e.message);
}
// Test Sesame endpoints
for (const path of ['agents', 'user']) {
try {
const resp = await fetch(`https://sesameai.app/external/${path}`, {
headers: { 'Authorization': 'Bearer ' + idToken }
});
const text = await resp.text();
appendResult(`/${path} [${resp.status}]: ${text.substring(0, 500)}`);
} catch(e) {
appendResult(`/${path} error: ${e.message}`);
}
}
// Show full token for copying to Claude
appendResult('\n--- FULL TOKEN (copy to Claude) ---\n' + idToken);
}
function appendResult(text) {
const el = document.getElementById(receivedT ? 'receivedStatus' : 'results');
if (el.id === 'results') {
el.classList.add('show');
document.getElementById('resultsText').textContent += text + '\n';
} else {
el.textContent += '\n' + text;
el.style.whiteSpace = 'pre-wrap';
el.style.maxHeight = '400px';
el.style.overflowY = 'auto';
}
}
</script>
</body>
</html>