Mercurial
view connectors/main.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/connector.h" #include "connectors/auth_http_adapter.h" #include <openssl/crypto.h> #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { char database[1024]; char auth_database[1024]; char auth_cookie_secret_hex[AUTH_CRYPTO_COOKIE_SECRET_MAX_BYTES * 2 + 1]; int64 auth_session_idle_ttl; char bind[128]; char port[16]; char static_dir[1024]; char client_id[1024]; char client_secret[2048]; char redirect_uri[2048]; char master_key[256]; uint32 master_key_version; } Service_Config; static boolean set_value(Service_Config *config, const char *key, const char *value) { #define SET(name, field) if (!strcmp(key, name)) { \ if (strlen(value) >= sizeof(config->field)) return FALSE; \ strcpy(config->field, value); return TRUE; \ } SET("DATABASE", database) SET("DB_PATH", database) SET("database", database) SET("AUTH_DATABASE", auth_database) SET("AUTH_DB_PATH", auth_database) SET("auth_database", auth_database) SET("AUTH_COOKIE_SECRET", auth_cookie_secret_hex) SET("AUTH_COOKIE_SECRET_HEX", auth_cookie_secret_hex) SET("auth_cookie_secret_hex", auth_cookie_secret_hex) SET("BIND", bind) SET("SERVER_HOST", bind) SET("bind", bind) SET("PORT", port) SET("SERVER_PORT", port) SET("port", port) SET("STATIC_DIR", static_dir) SET("static_dir", static_dir) SET("GOOGLE_CLIENT_ID", client_id) SET("google_client_id", client_id) SET("GOOGLE_CLIENT_SECRET", client_secret) SET("google_client_secret", client_secret) SET("GOOGLE_REDIRECT_URI", redirect_uri) SET("google_redirect_uri", redirect_uri) SET("MASTER_KEY_BASE64URL", master_key) SET("master_key_base64url", master_key) if (!strcmp(key, "MASTER_KEY_VERSION") || !strcmp(key, "master_key_version")) { config->master_key_version = (uint32)strtoul(value, NULL, 10); return config->master_key_version > 0; } if (!strcmp(key, "AUTH_SESSION_IDLE_TTL") || !strcmp(key, "auth_session_idle_ttl")) { char *end = NULL; long long parsed = strtoll(value, &end, 10); if (!end || *end || parsed <= 0) return FALSE; config->auth_session_idle_ttl = (int64)parsed; return TRUE; } #undef SET return TRUE; } static boolean load_config(const char *path, Service_Config *config) { FILE *file = fopen(path, "r"); char workspace_path[2048] = {0}; if (!file) { const char *workspace = getenv("BUILD_WORKSPACE_DIRECTORY"); if (workspace && workspace[0]) { int written = snprintf( workspace_path, sizeof(workspace_path), "%s/%s", workspace, path); if (written > 0 && (size_t)written < sizeof(workspace_path)) file = fopen(workspace_path, "r"); } } if (!file) return FALSE; memset(config, 0, sizeof(*config)); strcpy(config->bind, "127.0.0.1"); strcpy(config->port, "6981"); strcpy(config->static_dir, "connectors"); config->auth_session_idle_ttl = 604800; char line[4096]; boolean ok = TRUE; while (ok && fgets(line, sizeof(line), file)) { char *newline = strpbrk(line, "\r\n"); if (newline) *newline = '\0'; if (!line[0] || line[0] == '#') continue; char *equals = strchr(line, '='); if (!equals) { ok = FALSE; break; } *equals = '\0'; ok = set_value(config, line, equals + 1); } fclose(file); return ok && config->database[0] && config->auth_database[0] && config->auth_cookie_secret_hex[0] && config->client_id[0] && config->client_secret[0] && config->redirect_uri[0] && config->master_key[0] && config->master_key_version; } int main(int argc, char **argv) { const char *config_path = argc > 1 ? argv[1] : getenv("CONNECTOR_CONFIG_PATH"); if (!config_path || !config_path[0]) config_path = "connectors/.config"; Service_Config service; if (!load_config(config_path, &service)) { fprintf(stderr, "Invalid connector config: %s\n", config_path); return 1; } Connector_Master_Key key = {.version = service.master_key_version}; size_t key_length = 0; if (!Connector_Base64Url_Decode( service.master_key, key.key, sizeof(key.key), &key_length) || key_length != sizeof(key.key)) { fprintf(stderr, "MASTER_KEY_BASE64URL must decode to 32 bytes\n"); return 1; } Connector_Store store; if (!Connector_Store_Open(&store, service.database, &key)) { fprintf(stderr, "Unable to open connector database\n"); return 1; } Connector_Auth_HTTP_Context auth_context; if (!Connector_Auth_HTTP_Init( &auth_context, service.auth_database, service.auth_cookie_secret_hex, service.auth_session_idle_ttl)) { OPENSSL_cleanse( service.auth_cookie_secret_hex, sizeof(service.auth_cookie_secret_hex)); fprintf(stderr, "Unable to initialize shared HTTP authentication\n"); Connector_Store_Close(&store); return 1; } OPENSSL_cleanse( service.auth_cookie_secret_hex, sizeof(service.auth_cookie_secret_hex)); Connector_Google_Config google = { .client_id = service.client_id, .client_secret = service.client_secret, .redirect_uri = service.redirect_uri, .oauth_authorize_url = "https://accounts.google.com/o/oauth2/v2/auth", .oauth_token_url = "https://oauth2.googleapis.com/token", .oauth_revoke_url = "https://oauth2.googleapis.com/revoke", .identity_url = "https://openidconnect.googleapis.com/v1/userinfo", .drive_api_url = "https://www.googleapis.com", .drive_upload_url = "https://www.googleapis.com", .gmail_api_url = "https://gmail.googleapis.com" }; Connector_Auth_Adapter auth = Connector_Auth_HTTP_Create_Adapter(&auth_context); Connector_Service_Configure(&store, &google, auth); Seobeo_Router_Init(); Connector_Service_Register_Routes(); int result = Seobeo_Web_Server_Start_On( service.bind, service.static_dir, service.port, SEOBEO_MODE_EDGE, 4); Seobeo_Router_Destroy(); Connector_Auth_HTTP_Destroy(&auth_context); Connector_Store_Close(&store); return result; }