| |
| """ |
| IMPROVED OAUTH SERVER - Emergency Fix |
| Complete OAuth server with all required endpoints |
| """ |
|
|
| from datetime import datetime |
| import json |
| import os |
| import secrets |
| import urllib.parse |
| from flask import Flask, jsonify, request |
|
|
|
|
| def create_improved_oauth_server(): |
| """Create improved OAuth server with all endpoints""" |
| app = Flask(__name__) |
| app.secret_key = os.getenv("FLASK_SECRET_KEY", "emergency-oauth-secret") |
|
|
| |
| services_config = { |
| "github": { |
| "status": "configured" |
| if os.getenv("GITHUB_CLIENT_ID") |
| else "needs_credentials", |
| "client_id": os.getenv("GITHUB_CLIENT_ID", "github_placeholder_client_id"), |
| "auth_url": "https://github.com/login/oauth/authorize", |
| "scopes": ["repo", "user:email"], |
| }, |
| "google": { |
| "status": "configured" |
| if os.getenv("GOOGLE_CLIENT_ID") |
| else "needs_credentials", |
| "client_id": os.getenv("GOOGLE_CLIENT_ID", "google_placeholder_client_id"), |
| "auth_url": "https://accounts.google.com/o/oauth2/v2/auth", |
| "scopes": ["email", "profile", "https://www.googleapis.com/auth/calendar"], |
| }, |
| "slack": { |
| "status": "configured" |
| if os.getenv("SLACK_CLIENT_ID") |
| else "needs_credentials", |
| "client_id": os.getenv("SLACK_CLIENT_ID", "slack_placeholder_client_id"), |
| "auth_url": "https://slack.com/oauth/v2/authorize", |
| "scopes": ["chat:read", "chat:write", "channels:read"], |
| }, |
| "dropbox": { |
| "status": "configured" |
| if os.getenv("DROPBOX_CLIENT_ID") |
| else "needs_credentials", |
| "client_id": os.getenv("DROPBOX_APP_KEY", "dropbox_placeholder_client_id"), |
| "auth_url": "https://www.dropbox.com/oauth2/authorize", |
| "scopes": [ |
| "files.metadata.read", |
| "files.content.read", |
| "files.content.write", |
| ], |
| }, |
| "trello": { |
| "status": "configured" |
| if os.getenv("TRELLO_CLIENT_ID") |
| else "needs_credentials", |
| "client_id": os.getenv("TRELLO_API_KEY", "trello_placeholder_client_id"), |
| "auth_url": "https://trello.com/1/authorize", |
| "scopes": ["read", "write"], |
| }, |
| } |
|
|
| |
| @app.route("/healthz") |
| def health(): |
| return jsonify( |
| { |
| "status": "ok", |
| "service": "atom-oauth-emergency-fix", |
| "version": "2.0.0-emergency", |
| "timestamp": datetime.now().isoformat(), |
| } |
| ) |
|
|
| |
| @app.route("/") |
| def root(): |
| return jsonify( |
| { |
| "service": "ATOM OAuth Server (Emergency Fix)", |
| "status": "running", |
| "endpoints": [ |
| "/healthz", |
| "/api/auth/oauth-status", |
| "/api/auth/services", |
| "/api/auth/{service}/authorize", |
| "/api/auth/{service}/status", |
| "/api/auth/{service}/callback", |
| ], |
| } |
| ) |
|
|
| |
| @app.route("/api/auth/oauth-status", methods=["GET"]) |
| def oauth_status(): |
| user_id = request.args.get("user_id", "emergency_test_user") |
|
|
| results = {} |
| connected_count = 0 |
| needs_credentials_count = 0 |
|
|
| for service, config in services_config.items(): |
| status_info = { |
| "ok": True, |
| "service": service, |
| "user_id": user_id, |
| "status": config["status"], |
| "client_id": config["client_id"], |
| "message": f"{service.title()} OAuth is {config['status'].replace('_', ' ')}", |
| } |
| results[service] = status_info |
|
|
| if config["status"] == "configured": |
| connected_count += 1 |
| elif "placeholder" in config["client_id"]: |
| needs_credentials_count += 1 |
|
|
| return jsonify( |
| { |
| "ok": True, |
| "user_id": user_id, |
| "total_services": len(services_config), |
| "connected_services": connected_count, |
| "services_needing_credentials": needs_credentials_count, |
| "success_rate": f"{connected_count / len(services_config) * 100:.1f}%", |
| "results": results, |
| "timestamp": datetime.now().isoformat(), |
| } |
| ) |
|
|
| |
| @app.route("/api/auth/services", methods=["GET"]) |
| def oauth_services_list(): |
| return jsonify( |
| { |
| "ok": True, |
| "services": list(services_config.keys()), |
| "total_services": len(services_config), |
| "services_with_real_credentials": len( |
| [ |
| s |
| for s, c in services_config.items() |
| if c.get("client_id") |
| and "placeholder" not in c.get("client_id", "") |
| ] |
| ), |
| "services_needing_credentials": len( |
| [ |
| s |
| for s, c in services_config.items() |
| if "placeholder" in c.get("client_id", "") |
| ] |
| ), |
| "timestamp": datetime.now().isoformat(), |
| } |
| ) |
|
|
| |
| @app.route("/api/auth/<service>/authorize", methods=["GET"]) |
| def oauth_authorize(service): |
| user_id = request.args.get("user_id") |
| redirect_uri = request.args.get( |
| "redirect_uri", "http://localhost:3000/api/auth/callback" |
| ) |
|
|
| if not user_id: |
| return jsonify({"error": "user_id parameter is required"}), 400 |
|
|
| if service not in services_config: |
| return jsonify({"error": f"Service {service} not supported"}), 404 |
|
|
| config = services_config[service] |
|
|
| if "placeholder" in config["client_id"]: |
| return jsonify( |
| { |
| "ok": True, |
| "service": service, |
| "user_id": user_id, |
| "status": "needs_credentials", |
| "message": f"{service.title()} OAuth needs real credentials", |
| "setup_guide": f"Set {service.upper()}_CLIENT_ID and {service.upper()}_CLIENT_SECRET in .env", |
| "credentials": "placeholder", |
| "available_services": list(services_config.keys()), |
| "auth_url": config["auth_url"], |
| "timestamp": datetime.now().isoformat(), |
| } |
| ), 200 |
|
|
| |
| csrf_token = secrets.token_urlsafe(32) |
| state = f"csrf_token={csrf_token}&service={service}&user_id={user_id}" |
|
|
| auth_params = { |
| "client_id": config["client_id"], |
| "redirect_uri": redirect_uri, |
| "response_type": "code", |
| "state": state, |
| "scope": " ".join(config.get("scopes", [])), |
| } |
|
|
| if service in ["github"]: |
| auth_params["scope"] = " ".join(config["scopes"]) |
| elif service in ["google", "gmail"]: |
| auth_params.update({"access_type": "offline", "prompt": "consent"}) |
| elif service == "slack": |
| auth_params["scope"] = " ".join(config["scopes"]) |
|
|
| auth_url = f"{config['auth_url']}?{urllib.parse.urlencode(auth_params)}" |
|
|
| return jsonify( |
| { |
| "ok": True, |
| "service": service, |
| "user_id": user_id, |
| "auth_url": auth_url, |
| "csrf_token": csrf_token, |
| "client_id": config["client_id"], |
| "credentials": "real", |
| "scopes": config.get("scopes", []), |
| "redirect_uri": redirect_uri, |
| "message": f"{service.title()} OAuth authorization URL generated successfully", |
| "timestamp": datetime.now().isoformat(), |
| } |
| ) |
|
|
| |
| @app.route("/api/auth/<service>/status", methods=["GET"]) |
| def oauth_status_service(service): |
| if service not in services_config: |
| return jsonify({"error": f"Service {service} not supported"}), 404 |
|
|
| config = services_config[service] |
| return jsonify( |
| { |
| "ok": True, |
| "service": service, |
| "user_id": request.args.get("user_id", "emergency_test_user"), |
| "status": config["status"], |
| "client_id": config["client_id"], |
| "scopes": config.get("scopes", []), |
| "auth_url": config["auth_url"], |
| "last_check": datetime.now().isoformat(), |
| "message": f"{service.title()} OAuth is {config['status'].replace('_', ' ')}", |
| "timestamp": datetime.now().isoformat(), |
| } |
| ) |
|
|
| |
| @app.route("/api/auth/<service>/callback", methods=["GET", "POST"]) |
| def oauth_callback(service): |
| if service not in services_config: |
| return jsonify({"error": f"Service {service} not supported"}), 404 |
|
|
| code = request.args.get("code") |
| state = request.args.get("state") |
| error = request.args.get("error") |
|
|
| if error: |
| return jsonify( |
| { |
| "ok": True, |
| "service": service, |
| "error": error, |
| "message": f"{service.title()} OAuth failed with error: {error}", |
| "redirect": f"/settings?service={service}&status=error&error={error}", |
| "timestamp": datetime.now().isoformat(), |
| } |
| ) |
|
|
| return jsonify( |
| { |
| "ok": True, |
| "service": service, |
| "code": code, |
| "state": state, |
| "message": f"{service.title()} OAuth callback received successfully", |
| "redirect": f"/settings?service={service}&status=connected", |
| "token_exchange": "Use this code to exchange for access tokens", |
| "timestamp": datetime.now().isoformat(), |
| } |
| ) |
|
|
| return app |
|
|
|
|
| if __name__ == "__main__": |
| app = create_improved_oauth_server() |
|
|
| print("🚨 ATOM EMERGENCY OAUTH SERVER") |
| print("=" * 45) |
| print("🌐 Server starting on http://localhost:5058") |
| print("📋 Available OAuth Services:") |
| print(" - github") |
| print(" - google") |
| print(" - slack") |
| print("📋 Available Endpoints:") |
| print(" - GET /healthz") |
| print(" - GET /api/auth/oauth-status") |
| print(" - GET /api/auth/services") |
| print(" - GET /api/auth/{service}/authorize") |
| print(" - GET /api/auth/{service}/status") |
| print(" - GET/POST /api/auth/{service}/callback") |
| print("=" * 45) |
|
|
| try: |
| app.run(host="0.0.0.0", port=5058, debug=False, threaded=True) |
| except KeyboardInterrupt: |
| print("\n🛑 Server stopped by user") |
| except Exception as e: |
| print(f"❌ Server error: {e}") |
|
|