diff --git a/hermes_web_cli/init.py b/hermes_web_cli/init.py index eebba81..16694c7 100644 --- a/hermes_web_cli/init.py +++ b/hermes_web_cli/init.py @@ -63,6 +63,7 @@ async def get_all_services(orgid: str) -> List[Dict]: Returns: List of service dictionaries belonging to the specified organization """ + print(f"[INFO] get_all_services: orgid={orgid}") try: # Query services table with orgid filter using sqlor-database-module db = DBPools() @@ -73,9 +74,13 @@ async def get_all_services(orgid: str) -> List[Dict]: recs = await sor.sqlExe(sql_template, {'orgid': orgid}) # Convert datetime objects to ISO format strings for JSON serialization + # and decode encrypted apikey result = [] for rec in recs: - result.append(dict(rec)) + d = dict(rec) + if d.get('apikey'): + d['apikey'] = env.password_decode(d['apikey']) + result.append(d) return result @@ -96,6 +101,7 @@ async def create_service(name: str, url: str, orgid: str, description: str = "", Returns: The created service ID """ + print(f"[INFO] create_service: name={name}, url={url}, orgid={orgid}, description={description}, apikey={'***' if apikey else '(empty)'}") try: # Validate service URL if not await validate_service_url(url): @@ -103,9 +109,12 @@ async def create_service(name: str, url: str, orgid: str, description: str = "", service_id = str(uuid.uuid4()) + # Encrypt apikey before storing + env = ServerEnv() + stored_apikey = env.password_encode(apikey) if apikey else "" + # Save to database using sqlor-database-module db = DBPools() - env = ServerEnv() dbname = env.get_module_dbname('hermes-web-cli') async with db.sqlorContext(dbname) as sor: sql_template = SERVICES_CRUD['operations']['create']['sql_template'] @@ -115,7 +124,7 @@ async def create_service(name: str, url: str, orgid: str, description: str = "", 'name': name, 'service_url': url, 'description': description, - 'apikey': apikey, + 'apikey': stored_apikey, 'status': 'active' }) @@ -135,6 +144,7 @@ async def delete_service(service_id: str, orgid: str) -> bool: Returns: True if deleted successfully, False otherwise """ + print(f"[INFO] delete_service: service_id={service_id}, orgid={orgid}") try: # Verify service belongs to current org before deletion service = await get_service_by_id(service_id, orgid) @@ -174,14 +184,15 @@ async def delete_service(service_id: str, orgid: str) -> bool: async def get_service_by_id(service_id: str, orgid: str) -> Optional[Dict]: """Get service configuration by ID (only if owned by specified organization). - + Args: service_id: The ID of the service to retrieve orgid: The ID of the organization requesting the service - + Returns: Service dictionary if found and owned by org, None otherwise """ + print(f"[INFO] get_service_by_id: service_id={service_id}, orgid={orgid}") try: # Query database directly with orgid filter for security db = DBPools() @@ -193,12 +204,16 @@ async def get_service_by_id(service_id: str, orgid: str) -> Optional[Dict]: 'service_id': service_id, 'orgid': orgid }) - + if len(recs) > 0: - return dict(recs[0]) - + r = dict(recs[0]) + # Decode encrypted apikey + if r.get('apikey'): + r['apikey'] = env.password_decode(r['apikey']) + return r + return None - + except Exception as e: print(f"Error getting service: {str(e)}") return None @@ -214,6 +229,7 @@ async def test_service_connection(service_id: str, orgid: str = "") -> Tuple[boo Returns: Tuple[bool, str]: (is_connected, status_message) """ + print(f"[INFO] test_service_connection: service_id={service_id}, orgid={orgid}") try: # Get service configuration from database db = DBPools() @@ -240,13 +256,18 @@ async def test_service_connection(service_id: str, orgid: str = "") -> Tuple[boo service = dict(recs[0]) url = service["service_url"] + # Decode encrypted apikey apikey = service.get("apikey", "") + if apikey: + apikey = env.password_decode(apikey) # Prepare headers headers = {} if apikey: headers["Authorization"] = f"Bearer {apikey}" + print(f"[INFO] test_service_connection: testing {url}") + # Test the /health endpoint or similar timeout = aiohttp.ClientTimeout(total=10) async with aiohttp.ClientSession(timeout=timeout) as session: @@ -265,6 +286,7 @@ async def test_service_connection(service_id: str, orgid: str = "") -> Tuple[boo # Session management async def create_session(service_id: str, user_id: str, orgid: str, user_message: str = "") -> str: """Create a new session with a Hermes service.""" + print(f"[INFO] create_session: service_id={service_id}, user_id={user_id}, orgid={orgid}, user_message={'(empty)' if not user_message else '(has message)'}") try: # Get service configuration (verify it belongs to current org) service = await get_service_by_id(service_id, orgid) @@ -336,6 +358,7 @@ async def send_message_to_service(service_id: str, session_id: str, message: str Returns: Response from the service """ + print(f"[INFO] send_message_to_service: service_id={service_id}, session_id={session_id}, user_id={user_id}, orgid={orgid}, message_len={len(message)}") try: # Verify session belongs to current user before sending message session = await get_session_by_id(session_id, user_id) @@ -385,6 +408,7 @@ async def get_session_messages(session_id: str, user_id: str, orgid: str) -> Lis Returns: List of message dictionaries """ + print(f"[INFO] get_session_messages: session_id={session_id}, user_id={user_id}, orgid={orgid}") try: # Verify session belongs to current user before getting messages session = await get_session_by_id(session_id, user_id) @@ -451,6 +475,7 @@ async def get_active_sessions(user_id: str) -> List[Dict]: Returns: List of active session dictionaries """ + print(f"[INFO] get_active_sessions: user_id={user_id}") try: # Query the sessions table for active sessions belonging to current user using sqlor-database-module db = DBPools() @@ -481,6 +506,7 @@ async def get_recent_sessions(user_id: str, limit: int = 5) -> List[Dict]: Returns: List of recent session dictionaries """ + print(f"[INFO] get_recent_sessions: user_id={user_id}, limit={limit}") try: # Query the sessions table for recent sessions belonging to current user using sqlor-database-module db = DBPools() @@ -511,6 +537,7 @@ async def get_session_by_id(session_id: str, user_id: str) -> Optional[Dict]: Returns: Session dictionary if found and owned by user, None otherwise """ + print(f"[INFO] get_session_by_id: session_id={session_id}, user_id={user_id}") try: # Query database directly with user_id filter for security db = DBPools() @@ -554,6 +581,7 @@ async def get_setting(user_id: str) -> Dict: Returns: User settings dictionary """ + print(f"[INFO] get_setting: user_id={user_id}") import json default_settings = { @@ -612,6 +640,7 @@ async def save_setting(section: str, key: str, value, user_id: str) -> bool: Returns: True if saved successfully, False otherwise """ + print(f"[INFO] save_setting: user_id={user_id}, section={section}, key={key}") import json # Load existing settings or start with defaults