This skill implements enterprise-grade security protections for Google Workspace APIs:
CRITICAL SECURITY REQUIREMENTS:
# NEVER store these in openclaw.json or any config file
export GOOGLE_API_KEY="your-api-key"
export GOOGLE_CLIENT_ID="your-client-id"
export GOOGLE_CLIENT_SECRET="your-client-secret"
export GOOGLE_REDIRECT_URI="http://localhost:8080/callback"
cd /data/.openclaw/workspace/skills/google-services-secure
./scripts/validate-setup.sh
# Generate OAuth URL and authenticate
./scripts/auth-google.sh
# Add to ~/.bashrc or /etc/environment
export GOOGLE_API_KEY="your-api-key"
export GOOGLE_CLIENT_ID="your-client-id.apps.googleusercontent.com"
export GOOGLE_CLIENT_SECRET="your-client-secret"
export GOOGLE_REDIRECT_URI="http://localhost:8080/callback"
# Reload shell
source ~/.bashrc
cd /data/.openclaw/workspace/skills/google-services-secure
./scripts/validate-setup.sh
This will:
cd /data/.openclaw/workspace/skills/google-services-secure
./scripts/auth-google.sh
This will:
curl -s "https://gmail.googleapis.com/gmail/v1/users/me/messages?maxResults=10" \
-H "Authorization: Bearer $ACCESS_TOKEN"
-H "Content-Type: application/json"
❌ NEVER do this:
{
"env": {
"GOOGLE_API_KEY": "AIza...", // ❌ INSECURE
"GOOGLE_CLIENT_ID": "...apps.googleusercontent.com", // ❌ INSECURE
"GOOGLE_CLIENT_SECRET": "..." // ❌ CRITICAL SECURITY ISSUE
}
}
✅ CORRECT approach:
# Set at system level, never in files
export GOOGLE_API_KEY="your-api-key"
export GOOGLE_CLIENT_ID="your-client-id.apps.googleusercontent.com"
export GOOGLE_CLIENT_SECRET="your-client-secret"
Step 1: Generate Authorization URL
https://accounts.google.com/o/oauth2/v2/auth?client_id=$GOOGLE_CLIENT_ID \
&redirect_uri=$GOOGLE_REDIRECT_URI \
&response_type=code \
&scope=https://www.googleapis.com/auth/gmail.readonly,https://www.googleapis.com/auth/drive.readonly
Step 2: Exchange Code for Token
curl -X POST https://oauth2.googleapis.com/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=$GOOGLE_CLIENT_ID" \
-d "client_secret=$GOOGLE_CLIENT_SECRET" \
-d "code=$AUTHORIZATION_CODE" \
-d "redirect_uri=$GOOGLE_REDIRECT_URI" \
-d "grant_type=authorization_code"
The skill operates in three permission modes:
| Mode | Read | Write | Delete | Share | Risk Level |
|---|---|---|---|---|---|
| ------- | ------ | ------- | --------- | ------- | ------------- |
readonly | ✅ | ❌ | ❌ | ❌ | 🟢 LOW |
restricted | ✅ | ✅* | ❌ | ❌ | 🟡 MEDIUM |
full | ✅ | ✅ | ✅* | ✅* | 🔴 HIGH |
Default mode: readonly
To change mode:
export GOOGLE_PERMISSION_MODE="readonly" # Recommended for production
All actions are logged to:
/data/.openclaw/logs/google-services-audit.log
Log format:
{
"timestamp": "2024-04-04T00:30:45.123Z",
"user": "nelson",
"service": "gmail",
"action": "LIST_MESSAGES",
"status": "success",
"messageCount": 10,
"durationMs": 234,
"permissionMode": "readonly"
}
Default limits (configurable):
| Service | Limit | Window |
|---|---|---|
| --------- | ------- | --------- |
| Gmail API | 100 | per minute |
| Drive API | 500 | per minute |
| Calendar API | 100 | per minute |
| Sheets API | 100 | per minute |
| Contacts API | 50 | per minute |
Customize limits:
export GOOGLE_RATE_LIMIT_GMAIL="100/minute"
export GOOGLE_RATE_LIMIT_DRIVE="500/minute"
curl -s "https://gmail.googleapis.com/gmail/v1/users/me/messages?maxResults=10" \
-H "Authorization: Bearer $ACCESS_TOKEN"
curl -s "https://gmail.googleapis.com/gmail/v1/users/me/messages/$MESSAGE_ID" \
-H "Authorization: Bearer $ACCESS_TOKEN"
⚠️ Confirmation required before sending
curl -X POST "https://gmail.googleapis.com/gmail/v1/users/me/messages/send" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"raw": "From: me@example.com\r\nTo: recipient@example.com\r\nSubject: Test\r\n\r\nTest message body"
}'
curl -s "https://www.googleapis.com/drive/v3/files?pageSize=10" \
-H "Authorization: Bearer $ACCESS_TOKEN"
⚠️ Confirmation required before uploading
curl -X POST "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-F "metadata={\"name\":\"test.txt\"};type=application/json; charset=UTF-8" \
-F "file=@test.txt"
curl -s "https://www.googleapis.com/drive/v3/files/$FILE_ID?alt=media" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-O downloaded_file.txt
curl -s "https://www.googleapis.com/calendar/v3/calendars/primary/events?maxResults=10" \
-H "Authorization: Bearer $ACCESS_TOKEN"
⚠️ Confirmation required before creating
curl -X POST "https://www.googleapis.com/calendar/v3/calendars/primary/events" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"summary": "Meeting",
"start": {"dateTime": "2024-04-04T10:00:00Z"},
"end": {"dateTime": "2024-04-04T11:00:00Z"}
}'
curl -s "https://sheets.googleapis.com/v4/spreadsheets" \
-H "Authorization: Bearer $ACCESS_TOKEN"
curl -s "https://sheets.googleapis.com/v4/spreadsheets/$SPREADSHEET_ID/values/Sheet1!A1:B10" \
-H "Authorization: Bearer $ACCESS_TOKEN"
⚠️ Confirmation required before updating
curl -X PUT "https://sheets.googleapis.com/v4/spreadsheets/$SPREADSHEET_ID/values/Sheet1!A1:B10" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"values": [["New Value"]]
}'
curl -s "https://www.googleapis.com/drive/v3/files?q=mimeType%3D'application/vnd.google-apps.document'" \
-H "Authorization: Bearer $ACCESS_TOKEN"
curl -s "https://www.googleapis.com/drive/v3/files/$DOC_ID/export?mimeType=text/plain" \
-H "Authorization: Bearer $ACCESS_TOKEN"
curl -s "https://people.googleapis.com/v1/people/me/connections?personFields=names,emailAddresses" \
-H "Authorization: Bearer $ACCESS_TOKEN"
⚠️ Confirmation required before creating
curl -X POST "https://people.googleapis.com/v1/people:createContact" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"emailAddresses": [{"value": "new@example.com"}],
"names": [{"givenName": "John", "familyName": "Doe"}]
}'
function validateEmail(email) {
// Must be valid email format
if (!email.match(/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/)) {
throw new Error('Invalid email format');
}
// No dangerous characters
if (email.match(/<script|javascript:|onerror|onload/i)) {
throw new Error('Email contains dangerous patterns');
}
return email;
}
function validateFilePath(path) {
// Prevent directory traversal
if (path.includes('..') || path.includes('~')) {
throw new Error('Invalid file path');
}
// Validate file extension
const allowedExtensions = ['.txt', '.pdf', '.doc', '.docx', '.xls', '.xlsx'];
const extension = path.slice(-5);
if (!allowedExtensions.includes(extension)) {
throw new Error('File type not allowed');
}
return path;
}
function sanitizeData(data) {
const sensitive = ['password', 'apiKey', 'secret', 'token', 'credential'];
const sanitized = JSON.parse(JSON.stringify(data));
function clean(obj) {
for (const key in obj) {
if (sensitive.some(s => key.toLowerCase().includes(s))) {
obj[key] = '***REDACTED***';
} else if (typeof obj[key] === 'object') {
clean(obj[key]);
} else if (typeof obj[key] === 'string') {
// Remove potential HTML/Script tags
obj[key] = obj[key].replace(/<[^>]*>/g, '');
}
}
}
clean(sanitized);
return sanitized;
}
#!/bin/bash
# Send automated email notifications
EMAIL_SUBJECT="Daily Report"
RECIPIENT="manager@example.com"
MESSAGE_BODY="Daily report attached."
curl -X POST "https://gmail.googleapis.com/gmail/v1/users/me/messages/send" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"raw\": \"From: me@example.com\\r\\nTo: $RECIPIENT\\r\\nSubject: $EMAIL_SUBJECT\\r\\n\\r\\n$MESSAGE_BODY\"
}"
#!/bin/bash
# Backup files from Drive to local storage
curl -s "https://www.googleapis.com/drive/v3/files?pageSize=100" \
-H "Authorization: Bearer $ACCESS_TOKEN" | \
jq -r '.files[] | "\(.id) \t \(.name)"' | \
while read id name; do
curl -s "https://www.googleapis.com/drive/v3/files/$id?alt=media" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-O "backups/$name"
done
#!/bin/bash
# Schedule automated calendar events
EVENT_SUMMARY="Weekly Meeting"
START_TIME=$(date -u +"%Y-%m-%dT%H:%M:00Z")
END_TIME=$(date -u -d +1hour +"%Y-%m-%dT%H:%M:00Z")
curl -X POST "https://www.googleapis.com/calendar/v3/calendars/primary/events" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"summary\": \"$EVENT_SUMMARY\",
\"start\": {\"dateTime\": \"$START_TIME\"},
\"end\": {\"dateTime\": \"$END_TIME\"}
}"
# Set environment variables at system level
export GOOGLE_API_KEY="your-api-key"
export GOOGLE_CLIENT_ID="your-client-id.apps.googleusercontent.com"
export GOOGLE_CLIENT_SECRET="your-client-secret"
# Use readonly mode in production
export GOOGLE_PERMISSION_MODE="readonly"
# Review audit logs regularly
tail -100 /data/.openclaw/logs/google-services-audit.log
# Validate setup before use
./scripts/validate-setup.sh
# NEVER store credentials in config files
{
"env": {
"GOOGLE_CLIENT_SECRET": "..." # ❌ CRITICAL SECURITY ISSUE
}
}
# NEVER use HTTP (unencrypted)
export GOOGLE_API_KEY="http://..." # ❌ INSECURE
# NEVER share access tokens
echo "$ACCESS_TOKEN" # ❌ LEAKS CREDENTIALS
Error: Invalid Credentials
Solution:
Error: Invalid grant
Solution:
Error: User Rate Limit Exceeded
Solution:
Error: 403 Forbidden
Solution:
Before using this skill in production, verify:
{
"agents": {
"google-services": {
"id": "google-services",
"name": "Google Services (Secure)",
"skills": ["google-services-secure"],
"sandbox": "require",
"tools": {
"allowlist": ["curl", "read", "write"],
"denylist": ["exec", "eval", "shell"]
},
"maxConcurrent": 1
}
}
}
# Add skill to main agent
openclaw agent add-skill main google-services-secure
# Or create dedicated agent
openclaw agent create google-services \
--skills google-services-secure \
--sandbox require \
--max-concurrent 1
references/security.md - Complete security guidescripts/validate-setup.sh - Setup verificationscripts/auth-google.sh - OAuth 2.0 flowMIT License - See LICENSE.md for details
Security is top priority. All contributions must:
references/ directory⚠️ IMPORTANT: This skill prioritizes security over convenience. Read-only operations work immediately. Dangerous operations require explicit confirmation and appropriate permission levels.
Note: This skill uses OAuth 2.0 flow for secure authorization. Never share your access tokens or store them in files.
共 1 个版本