view connectors/auth_test_page.c @ 279:b3b547563ec7

Add Google connector service and agent wiki Implement the C/Seobeo Google Drive and Gmail connector with encrypted OAuth storage, Zenbu authentication, browser testing, AI tool discovery, chunked HTTP decoding, and Bazel coverage. Consolidate repository guidance into progressive wiki documentation and enforce arena-first allocation for new first-party C code. Co-authored-by: Copilot <[email protected]> Copilot-Session: 84c338fd-0939-4bb3-b7f3-1062eb213e5d
author MrJuneJune <me@mrjunejune.com>
date Mon, 17 Aug 2026 22:22:36 -0700
parents
children
line wrap: on
line source

#include "connectors/auth_test_page.h"

const char *Connector_Auth_Test_Page(void)
{
  return
      "<!doctype html><html lang=\"en\"><head><meta charset=\"utf-8\">"
      "<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">"
      "<title>Zenbu Connector Test</title><style>"
      ":root{color-scheme:dark;font-family:system-ui,sans-serif;background:#111;"
      "color:#eee}main{max-width:820px;margin:32px auto;padding:24px}"
      "section{margin:20px 0;padding:16px;border:1px solid #444;border-radius:8px}"
      "button,a,input,textarea{margin:4px;padding:9px}input,textarea{width:95%}"
      "button,a{display:inline-block}pre{min-height:140px;padding:16px;"
      "overflow:auto;background:#1d1d1d;border:1px solid #444;border-radius:8px}"
      "</style></head><body><main><h1>Zenbu connector test</h1>"
      "<section><h2>1. Authentication</h2>"
      "<a href=\"http://127.0.0.1:6969/login\" target=\"_blank\">Zenbu login</a>"
      "<button id=\"check\">Check Zenbu session</button>"
      "<button id=\"oauth\" disabled>Connect Google account</button></section>"
      "<section><h2>2. Google account</h2>"
      "<label>Account ID<input id=\"account\" placeholder=\"google:...\"></label>"
      "<button id=\"drive-list\">List Drive files</button>"
      "<button id=\"drive-create\">Create test Google Doc</button>"
      "<button id=\"gmail-list\">List Gmail messages</button></section>"
      "<section><h2>3. Gmail write test</h2>"
      "<label>To<input id=\"to\" type=\"email\"></label>"
      "<label>Subject<input id=\"subject\" value=\"Zenbu connector test\"></label>"
      "<label>Message<textarea id=\"message\" rows=\"4\">Hello from Zenbu.</textarea></label>"
      "<button id=\"gmail-draft\">Create draft</button>"
      "<button id=\"gmail-send\">Send with confirmation</button></section>"
      "<pre id=\"output\">Check the Zenbu session first.</pre></main><script>"
      "const $=s=>document.querySelector(s),out=$('#output'),oauth=$('#oauth');"
      "let csrf='';const params=new URLSearchParams(location.search);"
      "$('#account').value=params.get('account_id')||localStorage.zenbuAccount||'';"
      "if(params.get('email'))$('#to').value=params.get('email');"
      "const show=v=>out.textContent=typeof v==='string'?v:JSON.stringify(v,null,2);"
      "const account=()=>{const v=$('#account').value.trim();"
      "if(!v)throw new Error('Connect Google or enter an account ID');"
      "if(!/^[A-Za-z0-9_.:-]+$/.test(v))throw new Error('Invalid account ID');"
      "localStorage.zenbuAccount=v;return v};"
      "async function result(response){const text=await response.text();"
      "let body;try{body=JSON.parse(text)}catch{body=text}"
      "show({status:response.status,body});return{response,body}}"
      "async function read(path){return result(await fetch(path,{credentials:'include'}))}"
      "async function mutate(path,body,key,confirmation){"
      "const headers={'Content-Type':'application/json','X-CSRF-Token':csrf,"
      "'Idempotency-Key':key};if(confirmation)"
      "headers['X-Connector-Confirmation']=confirmation;"
      "return result(await fetch(path,{method:'POST',credentials:'include',"
      "headers,body:JSON.stringify(body)}))}"
      "$('#check').onclick=async()=>{oauth.disabled=true;csrf='';"
      "const r=await read('/v1/auth/session');"
      "if(r.response.ok&&r.body.authenticated){csrf=r.body.csrfToken;"
      "oauth.disabled=false}};"
      "oauth.onclick=async()=>{const r=await result(await fetch("
      "'/v1/oauth/google/start',{method:'POST',credentials:'include',"
      "headers:{'X-CSRF-Token':csrf}}));"
      "if(r.response.ok&&r.body.authorization_url)"
      "location.assign(r.body.authorization_url)};"
      "$('#drive-list').onclick=()=>read('/v1/accounts/'+account()+"
      "'/drive/files?pageSize=10&fields=files(id,name,mimeType),nextPageToken');"
      "$('#gmail-list').onclick=()=>read('/v1/accounts/'+account()+"
      "'/gmail/messages?maxResults=10');"
      "$('#drive-create').onclick=()=>mutate('/v1/accounts/'+account()+"
      "'/drive/files',{name:'Zenbu test '+new Date().toISOString(),"
      "mimeType:'application/vnd.google-apps.document'},crypto.randomUUID());"
      "function rawMessage(){const mime='To: '+$('#to').value+'\\r\\nSubject: '+"
      "$('#subject').value+'\\r\\nContent-Type: text/plain; charset=UTF-8\\r\\n\\r\\n'+"
      "$('#message').value;const bytes=new TextEncoder().encode(mime);let binary='';"
      "for(const byte of bytes)binary+=String.fromCharCode(byte);"
      "return btoa(binary).replaceAll('+','-').replaceAll('/','_').replace(/=+$/,'')}"
      "$('#gmail-draft').onclick=()=>mutate('/v1/accounts/'+account()+"
      "'/gmail/drafts',{message:{raw:rawMessage()}},crypto.randomUUID());"
      "$('#gmail-send').onclick=async()=>{if(!csrf){show('Check session first');return}"
      "const path='/v1/accounts/'+account()+'/gmail/send',body={raw:rawMessage()},"
      "key=crypto.randomUUID();let r=await mutate(path,body,key);"
      "if(r.response.status!==409||r.body.error!=='confirmation_required')return;"
      "if(!confirm('Send this email through Gmail?'))return;"
      "const confirmation=await result(await fetch('/v1/confirmations',{"
      "method:'POST',credentials:'include',headers:{'Content-Type':'application/json',"
      "'X-CSRF-Token':csrf},body:JSON.stringify({request_digest:r.body.request_digest})}));"
      "if(!confirmation.response.ok)return;"
      "await mutate(path,body,key,confirmation.body.confirmation_token)};"
      "</script></body></html>";
}