Files
openclaw/skills/gmail-reader/reauth-google-sheets.cjs
Clawd Bot ca9b510922 chore: align with upstream openclaw/openclaw and overlay local additions
- Reset master to upstream/main (16,697 commits)
- Overlay 2,271 local-only files (skills, tools, workspace, configs, apps)
- Restore IDENTITY.md and USER.md templates
- Build verified, gateway running, Discord working

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 07:40:46 +01:00

182 lines
5.7 KiB
JavaScript

#!/usr/bin/env node
const fs = require("fs");
const https = require("https");
const { homedir } = require("os");
const { join } = require("path");
const { exec } = require("child_process");
function httpsRequest(url, options = {}) {
return new Promise((resolve, reject) => {
const req = https.request(url, options, (res) => {
let data = "";
res.on("data", (chunk) => (data += chunk));
res.on("end", () => {
if (res.statusCode >= 400) {
reject(new Error(`HTTP ${res.statusCode}: ${data}`));
} else {
resolve(JSON.parse(data));
}
});
});
req.on("error", reject);
if (options.body) req.write(options.body);
req.end();
});
}
async function main() {
const credsPath = join(homedir(), ".openclaw/secrets/google-oauth.json");
const creds = JSON.parse(fs.readFileSync(credsPath, "utf8"));
console.log("🔐 Google OAuth - Udvid Scopes til Sheets/Drive\n");
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
// New scopes that include Gmail, Sheets and Drive
const scopes = [
"https://www.googleapis.com/auth/gmail.readonly",
"https://www.googleapis.com/auth/gmail.send",
"https://www.googleapis.com/auth/spreadsheets.readonly",
"https://www.googleapis.com/auth/drive.readonly",
].join(" ");
const authUrl =
`https://accounts.google.com/o/oauth2/v2/auth?` +
`client_id=${creds.client_id}&` +
`redirect_uri=http://localhost:8080&` +
`response_type=code&` +
`scope=${encodeURIComponent(scopes)}&` +
`access_type=offline&` +
`prompt=consent`;
console.log("📋 NYE SCOPES:\n");
console.log(" ✅ Gmail (readonly + send)");
console.log(" ✅ Google Sheets (readonly)");
console.log(" ✅ Google Drive (readonly)\n");
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
console.log("🌐 AUTHENTICATION URL:\n");
console.log(authUrl);
console.log("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
console.log("📝 STEPS:\n");
console.log("1. Åbn URL'en ovenfor i din browser");
console.log("2. Log ind og godkend de nye scopes");
console.log('3. Du får en "redirect error" - det er OK!');
console.log("4. Kopier HELE URL'en fra adresselinjen");
console.log('5. Find "code=" parameteren');
console.log("6. Kør: node exchange-code.cjs <din-kode>\n");
// Try to open browser automatically
try {
const openCmd =
process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
exec(`${openCmd} "${authUrl}"`, (err) => {
if (err) {
console.log("⚠️ Could not open browser automatically");
} else {
console.log("✅ Browser opened automatically!\n");
}
});
} catch (e) {
console.log("⚠️ Could not open browser automatically\n");
}
// Create exchange script
const exchangeScript = `#!/usr/bin/env node
const fs = require('fs');
const https = require('https');
const { homedir } = require('os');
const { join } = require('path');
function httpsRequest(url, options = {}) {
return new Promise((resolve, reject) => {
const req = https.request(url, options, (res) => {
let data = '';
res.on('data', (chunk) => (data += chunk));
res.on('end', () => {
if (res.statusCode >= 400) {
reject(new Error(\`HTTP \${res.statusCode}: \${data}\`));
} else {
resolve(JSON.parse(data));
}
});
});
req.on('error', reject);
if (options.body) req.write(options.body);
req.end();
});
}
async function main() {
const code = process.argv[2];
if (!code) {
console.error('❌ Usage: node exchange-code.cjs <authorization-code>');
process.exit(1);
}
const credsPath = join(homedir(), '.openclaw/secrets/google-oauth.json');
const creds = JSON.parse(fs.readFileSync(credsPath, 'utf8'));
console.log('🔄 Exchanging authorization code for tokens...\\n');
const body = new URLSearchParams({
client_id: creds.client_id,
client_secret: creds.client_secret,
code: code,
redirect_uri: 'http://localhost:8080',
grant_type: 'authorization_code',
}).toString();
const data = await httpsRequest('https://oauth2.googleapis.com/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(body),
},
body,
});
console.log('✅ Tokens received!\\n');
// Update credentials file
const newCreds = {
client_id: creds.client_id,
client_secret: creds.client_secret,
refresh_token: data.refresh_token || creds.refresh_token,
access_token: data.access_token,
expiry_date: Date.now() + (data.expires_in * 1000),
};
fs.writeFileSync(credsPath, JSON.stringify(newCreds, null, 2));
console.log('💾 Updated credentials saved to:');
console.log(\` \${credsPath}\\n\`);
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n');
console.log('🎉 Google OAuth updated successfully!\\n');
console.log('Du har nu adgang til:');
console.log(' ✅ Gmail (read + send)');
console.log(' ✅ Google Sheets (readonly)');
console.log(' ✅ Google Drive (readonly)\\n');
}
main().catch((err) => {
console.error('❌ Error:', err.message);
process.exit(1);
});
`;
const exchangePath = join(__dirname, "exchange-code.cjs");
fs.writeFileSync(exchangePath, exchangeScript);
fs.chmodSync(exchangePath, 0o755);
console.log("✅ Created helper script: exchange-code.cjs\n");
}
main().catch((err) => {
console.error("❌ Error:", err.message);
process.exit(1);
});