From 096611aaa2ce0388a70e7a0348923c1a69557252 Mon Sep 17 00:00:00 2001 From: kanak8278 Date: Wed, 17 Jul 2024 14:06:26 +0530 Subject: [PATCH 1/9] added uuid secret to frontent --- api/app/routers/v1/__init__.py | 6 ++++++ frontend/src/pages/home/home.tsx | 19 ++++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/api/app/routers/v1/__init__.py b/api/app/routers/v1/__init__.py index 73c2d33e..46554c1d 100644 --- a/api/app/routers/v1/__init__.py +++ b/api/app/routers/v1/__init__.py @@ -1,4 +1,5 @@ from fastapi import APIRouter, HTTPException, Request +import uuid from ...crud import get_chat_history, get_bot_list, get_bot_chat_sessions from ...handlers.v1 import handle_callback, handle_webhook from ...handlers.v1.bot_handlers import ( @@ -30,6 +31,10 @@ async def get_bots(): bot.status = status return bots +@router.get("/secret") +async def generate_secret(): + secret = str(uuid.uuid4()) + return {"secret": secret} @router.post("/bot/install") async def install_bot(install_content: JBBotCode): @@ -94,6 +99,7 @@ async def add_bot_configuraton(bot_id: str, request: Request): # get all messages related to a session @router.get("/chats/{bot_id}/sessions/{session_id}") async def get_session(bot_id: str, session_id: str): + print("session_id", session_id) sessions = await get_bot_chat_sessions(bot_id, session_id) return sessions diff --git a/frontend/src/pages/home/home.tsx b/frontend/src/pages/home/home.tsx index 24abc594..c8b22779 100644 --- a/frontend/src/pages/home/home.tsx +++ b/frontend/src/pages/home/home.tsx @@ -12,6 +12,21 @@ interface props { } +async function fetchAndCopySecret() { + const url = `${APIHOST}/v1/secret`; + try { + const response = await fetch(url); + const data = await response.json(); + const secret = data.secret; + await navigator.clipboard.writeText(secret); + alert("JB Manager secret copied!"); + } catch (error) { + console.error("Error fetching secret:", error); + alert("Failed to copy secret"); + } +} + + export const Home:React.FunctionComponent = (props:props) => { const [refreshBots, incrementrefreshBots] = React.useState(0); const [projects, setProjects] = React.useState([]); @@ -103,17 +118,19 @@ export const Home:React.FunctionComponent = (props:props) => {
-
{ navigator.clipboard.writeText("https://bandhujbstorage.z29.web.core.windows.net/"); alert("Installation URL copied") }}> +
{ navigator.clipboard.writeText(import.meta.env.VITE_SERVER_HOST + "/install"); alert("Installation URL copied") }}> {import.meta.env.VITE_SERVER_HOST+"/install"}
+
{ fetchAndCopySecret()}}> *************************** +
From bf1685e5edf42dc28d0c87e19c6a62a321024098 Mon Sep 17 00:00:00 2001 From: kanak8278 Date: Wed, 17 Jul 2024 14:56:00 +0530 Subject: [PATCH 2/9] updated the routes for secret generation and refresh --- api/app/crud.py | 40 ++++++++++++++++++++++++++++++++++ api/app/routers/v1/__init__.py | 26 ++++++++++++++++++---- jb-lib/lib/models/__init__.py | 8 +++++++ 3 files changed, 70 insertions(+), 4 deletions(-) diff --git a/api/app/crud.py b/api/app/crud.py index c3cc39fa..ee80863c 100644 --- a/api/app/crud.py +++ b/api/app/crud.py @@ -2,6 +2,7 @@ import uuid from sqlalchemy import select, update from sqlalchemy.orm import joinedload +from sqlalchemy.sql import func from lib.db_session_handler import DBSessionHandler from lib.models import ( @@ -242,3 +243,42 @@ async def update_channel_by_bot_id(bot_id: str, data): await session.execute(stmt) await session.commit() return bot_id + +async def create_secret(secret_value): + async with DBSessionHandler.get_async_session() as session: + async with session.begin(): + new_secret = JBSecret( + id=str(uuid.uuid4()), + secret_value=secret_value + ) + session.add(new_secret) + await session.commit() + return new_secret.id + + +async def check_secret_key(secret_key): + async with DBSessionHandler.get_async_session() as session: + query = select(JBSecret).filter_by(id=secret_key) + result = await session.execute(query) + matched_secret = await result.fetchone() + return matched_secret is not None + return False + +async def update_secret(new_secret_value): + async with DBSessionHandler.get_async_session() as session: + async with session.begin(): + latest_secret = await get_latest_secret() + if latest_secret: + latest_secret.secret_value = new_secret_value + latest_secret.created_at = func.now() + await session.commit() + return True + return False + +async def get_latest_secret_key(): + async with DBSessionHandler.get_async_session() as session: + query = select(JBSecret.id).order_by(JBSecret.created_at.desc()).limit(1) + result = await session.execute(query) + latest_secret_key = await result.scalar_one() + return latest_secret_key + return None \ No newline at end of file diff --git a/api/app/routers/v1/__init__.py b/api/app/routers/v1/__init__.py index 46554c1d..2ce64c3a 100644 --- a/api/app/routers/v1/__init__.py +++ b/api/app/routers/v1/__init__.py @@ -1,6 +1,6 @@ from fastapi import APIRouter, HTTPException, Request import uuid -from ...crud import get_chat_history, get_bot_list, get_bot_chat_sessions +from ...crud import get_chat_history, get_bot_list, get_bot_chat_sessions, create_secret, update_secret, get_latest_secret_key from ...handlers.v1 import handle_callback, handle_webhook from ...handlers.v1.bot_handlers import ( handle_activate_bot, @@ -32,9 +32,27 @@ async def get_bots(): return bots @router.get("/secret") -async def generate_secret(): - secret = str(uuid.uuid4()) - return {"secret": secret} +async def get_uuid(): + key = get_latest_secret_key() + if key is None: + key = str(uuid.uuid4()) + try: + create_secret(key) + except Exception as e: + raise HTTPException( + status_code=500, detail=f"Error adding secret: {e}" + ) from e + return {"secret": key} + +@router.put("/refresh-key") +async def refresh_secret_key(): + secret_value = str(uuid.uuid4()) + success = await update_secret(secret_value) + + if not success: + raise HTTPException(status_code=500, detail="Failed to update secret key") + + return {"status": "success"} @router.post("/bot/install") async def install_bot(install_content: JBBotCode): diff --git a/jb-lib/lib/models/__init__.py b/jb-lib/lib/models/__init__.py index 143eb813..d44c770e 100644 --- a/jb-lib/lib/models/__init__.py +++ b/jb-lib/lib/models/__init__.py @@ -293,6 +293,14 @@ class JBForm(Base): onupdate=func.now(), ) +class JBSecret(Base): + __tablename__ = "jb_secret" + + id = Column(String, primary_key=True) + secret_value = Column(String, nullable=False) + created_at = Column( + TIMESTAMP(timezone=True), server_default=func.now(), nullable=False + ) # class LangchainPgCollection(Base): # __tablename__ = 'langchain_pg_collection' From 2a4efda3052f80c9d228323be0e3c20005e00fa0 Mon Sep 17 00:00:00 2001 From: kanak8278 Date: Thu, 18 Jul 2024 10:59:26 +0530 Subject: [PATCH 3/9] corrected the installation endpoint and secret key --- frontend/src/pages/home/home.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/pages/home/home.tsx b/frontend/src/pages/home/home.tsx index c8b22779..771753f1 100644 --- a/frontend/src/pages/home/home.tsx +++ b/frontend/src/pages/home/home.tsx @@ -118,11 +118,11 @@ export const Home:React.FunctionComponent = (props:props) => {
-
{ navigator.clipboard.writeText(import.meta.env.VITE_SERVER_HOST + "/install"); alert("Installation URL copied") }}> +
{ navigator.clipboard.writeText(import.meta.env.VITE_SERVER_HOST+"/v1/bot/install"); alert("Installation URL copied") }}> - {import.meta.env.VITE_SERVER_HOST+"/install"} + {import.meta.env.VITE_SERVER_HOST+"/v1/bot/install"}
{ fetchAndCopySecret()}}> From ef9ee8ce3b132729773f012583a7d23baaa86f32 Mon Sep 17 00:00:00 2001 From: kanak8278 Date: Thu, 18 Jul 2024 11:31:43 +0530 Subject: [PATCH 4/9] publish w/o authentication working --- api/app/crud.py | 41 +--------------------------------- api/app/routers/v1/__init__.py | 32 +++++++++++++------------- 2 files changed, 16 insertions(+), 57 deletions(-) diff --git a/api/app/crud.py b/api/app/crud.py index ee80863c..c27789b1 100644 --- a/api/app/crud.py +++ b/api/app/crud.py @@ -242,43 +242,4 @@ async def update_channel_by_bot_id(bot_id: str, data): stmt = update(JBChannel).where(JBChannel.bot_id == bot_id).values(**data) await session.execute(stmt) await session.commit() - return bot_id - -async def create_secret(secret_value): - async with DBSessionHandler.get_async_session() as session: - async with session.begin(): - new_secret = JBSecret( - id=str(uuid.uuid4()), - secret_value=secret_value - ) - session.add(new_secret) - await session.commit() - return new_secret.id - - -async def check_secret_key(secret_key): - async with DBSessionHandler.get_async_session() as session: - query = select(JBSecret).filter_by(id=secret_key) - result = await session.execute(query) - matched_secret = await result.fetchone() - return matched_secret is not None - return False - -async def update_secret(new_secret_value): - async with DBSessionHandler.get_async_session() as session: - async with session.begin(): - latest_secret = await get_latest_secret() - if latest_secret: - latest_secret.secret_value = new_secret_value - latest_secret.created_at = func.now() - await session.commit() - return True - return False - -async def get_latest_secret_key(): - async with DBSessionHandler.get_async_session() as session: - query = select(JBSecret.id).order_by(JBSecret.created_at.desc()).limit(1) - result = await session.execute(query) - latest_secret_key = await result.scalar_one() - return latest_secret_key - return None \ No newline at end of file + return bot_id \ No newline at end of file diff --git a/api/app/routers/v1/__init__.py b/api/app/routers/v1/__init__.py index 2ce64c3a..d26afc0c 100644 --- a/api/app/routers/v1/__init__.py +++ b/api/app/routers/v1/__init__.py @@ -17,6 +17,7 @@ tags=["v1"], ) +JBMANAGER_KEY = str(uuid.uuid4()) @router.get("/bots") async def get_bots(): @@ -33,29 +34,26 @@ async def get_bots(): @router.get("/secret") async def get_uuid(): - key = get_latest_secret_key() - if key is None: - key = str(uuid.uuid4()) - try: - create_secret(key) - except Exception as e: - raise HTTPException( - status_code=500, detail=f"Error adding secret: {e}" - ) from e - return {"secret": key} + return {"secret": JBMANAGER_KEY} + @router.put("/refresh-key") async def refresh_secret_key(): - secret_value = str(uuid.uuid4()) - success = await update_secret(secret_value) - - if not success: - raise HTTPException(status_code=500, detail="Failed to update secret key") - + JBMANAGER_KEY = str(uuid.uuid4()) return {"status": "success"} @router.post("/bot/install") -async def install_bot(install_content: JBBotCode): +async def install_bot(request:Request, install_content: JBBotCode): + try: + request_body = await request.json() + print(f"request_body: {request_body}") + except Exception as e: + print(f"Error: {e}") + + # request_body bearer token + # match with JBMANAGER_KEY + # if match, proceed + flow_input = await handle_install_bot(install_content) try: produce_message(flow_input) From 0ba8a69eb580993c84683bef90506f34551cdd2d Mon Sep 17 00:00:00 2001 From: kanak8278 Date: Thu, 18 Jul 2024 11:34:59 +0530 Subject: [PATCH 5/9] removed undefined crud functions import --- api/app/routers/v1/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/app/routers/v1/__init__.py b/api/app/routers/v1/__init__.py index d26afc0c..67679cd4 100644 --- a/api/app/routers/v1/__init__.py +++ b/api/app/routers/v1/__init__.py @@ -1,6 +1,6 @@ from fastapi import APIRouter, HTTPException, Request import uuid -from ...crud import get_chat_history, get_bot_list, get_bot_chat_sessions, create_secret, update_secret, get_latest_secret_key +from ...crud import get_chat_history, get_bot_list, get_bot_chat_sessions from ...handlers.v1 import handle_callback, handle_webhook from ...handlers.v1.bot_handlers import ( handle_activate_bot, From b201274097c955953f8851746b9d660decb3e37c Mon Sep 17 00:00:00 2001 From: kanak8278 Date: Thu, 18 Jul 2024 15:37:46 +0530 Subject: [PATCH 6/9] authorization enabled for bot installation --- api/app/routers/v1/__init__.py | 15 ++++++--------- frontend/src/components/settings-model/index.tsx | 10 ++++++++++ frontend/src/pages/home/home.tsx | 16 +++++++++++----- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/api/app/routers/v1/__init__.py b/api/app/routers/v1/__init__.py index 67679cd4..66f36562 100644 --- a/api/app/routers/v1/__init__.py +++ b/api/app/routers/v1/__init__.py @@ -44,15 +44,12 @@ async def refresh_secret_key(): @router.post("/bot/install") async def install_bot(request:Request, install_content: JBBotCode): - try: - request_body = await request.json() - print(f"request_body: {request_body}") - except Exception as e: - print(f"Error: {e}") - - # request_body bearer token - # match with JBMANAGER_KEY - # if match, proceed + headers = dict(request.headers) + authorization = headers.get("authorization") + if authorization is None: + raise HTTPException(status_code=400, detail="Authorization header not provided") + if authorization != f"Bearer {JBMANAGER_KEY}": + raise HTTPException(status_code=401, detail="Unauthorized") flow_input = await handle_install_bot(install_content) try: diff --git a/frontend/src/components/settings-model/index.tsx b/frontend/src/components/settings-model/index.tsx index 69eb8a14..8f4143b6 100644 --- a/frontend/src/components/settings-model/index.tsx +++ b/frontend/src/components/settings-model/index.tsx @@ -1,6 +1,7 @@ import React, { useState, useEffect } from 'react'; import './settings-model.css'; import { sendRequest } from '@/api'; +import { fetchAndCopySecret } from '@/pages/home/home'; interface InputConfig { value: string | number | boolean; @@ -47,6 +48,7 @@ const SettingsModal: React.FC = ({ botId, isOpen, onClose, inputs, modelT const handleSubmit = async () => { let data:any = {}; let apiEndpoint = ''; + let accessToken = null; if (modelType === 'credentials') { apiEndpoint = `${APIHOST}/v1/bot/${botId}/configure`; let credentials:any = {}; @@ -73,6 +75,13 @@ const SettingsModal: React.FC = ({ botId, isOpen, onClose, inputs, modelT data['channels']['whatsapp'] = inputElements['whatsapp'].value; } else if (modelType === 'install') { apiEndpoint = `${APIHOST}/v1/bot/install`; + try { + accessToken = await fetchAndCopySecret(); + } catch (error) { + console.error("Failed to fetch the access token:", error); + alert("Failed to fetch the access token"); + return; + } for (let key in inputElements) { if (inputElements[key].required === true && !inputElements[key].value.toString().trim()) { alert(`${key} is required`); @@ -89,6 +98,7 @@ const SettingsModal: React.FC = ({ botId, isOpen, onClose, inputs, modelT await sendRequest({ url: apiEndpoint, method: 'POST', + accessToken: accessToken, body: JSON.stringify(data ), headers: { 'Content-Type': 'application/json', diff --git a/frontend/src/pages/home/home.tsx b/frontend/src/pages/home/home.tsx index 771753f1..ef6ece0c 100644 --- a/frontend/src/pages/home/home.tsx +++ b/frontend/src/pages/home/home.tsx @@ -12,21 +12,20 @@ interface props { } -async function fetchAndCopySecret() { +export async function fetchAndCopySecret() { const url = `${APIHOST}/v1/secret`; try { const response = await fetch(url); const data = await response.json(); const secret = data.secret; await navigator.clipboard.writeText(secret); - alert("JB Manager secret copied!"); + return secret; // Return the secret explicitly } catch (error) { console.error("Error fetching secret:", error); - alert("Failed to copy secret"); + throw error; // Throw error to handle it later } } - export const Home:React.FunctionComponent = (props:props) => { const [refreshBots, incrementrefreshBots] = React.useState(0); const [projects, setProjects] = React.useState([]); @@ -125,7 +124,14 @@ export const Home:React.FunctionComponent = (props:props) => { {import.meta.env.VITE_SERVER_HOST+"/v1/bot/install"}
-
{ fetchAndCopySecret()}}> +
{ + try { + await fetchAndCopySecret(); + alert("JB Manager secret copied!"); + } catch (error) { + alert("Failed to copy secret"); + } + }}> From 840f2802f39311caf8f4cab365eb461202a0069f Mon Sep 17 00:00:00 2001 From: kanak8278 Date: Thu, 18 Jul 2024 15:40:39 +0530 Subject: [PATCH 7/9] removed unnecessary import and JBSecret table --- api/app/crud.py | 1 - jb-lib/lib/models/__init__.py | 9 --------- 2 files changed, 10 deletions(-) diff --git a/api/app/crud.py b/api/app/crud.py index c27789b1..9bb8c1c9 100644 --- a/api/app/crud.py +++ b/api/app/crud.py @@ -2,7 +2,6 @@ import uuid from sqlalchemy import select, update from sqlalchemy.orm import joinedload -from sqlalchemy.sql import func from lib.db_session_handler import DBSessionHandler from lib.models import ( diff --git a/jb-lib/lib/models/__init__.py b/jb-lib/lib/models/__init__.py index d44c770e..46c31f97 100644 --- a/jb-lib/lib/models/__init__.py +++ b/jb-lib/lib/models/__init__.py @@ -293,15 +293,6 @@ class JBForm(Base): onupdate=func.now(), ) -class JBSecret(Base): - __tablename__ = "jb_secret" - - id = Column(String, primary_key=True) - secret_value = Column(String, nullable=False) - created_at = Column( - TIMESTAMP(timezone=True), server_default=func.now(), nullable=False - ) - # class LangchainPgCollection(Base): # __tablename__ = 'langchain_pg_collection' From f0d07e5c8c7255764461fe6327d0e13986063f6d Mon Sep 17 00:00:00 2001 From: kanak8278 Date: Thu, 18 Jul 2024 15:51:38 +0530 Subject: [PATCH 8/9] resolve comments --- api/app/routers/v1/__init__.py | 5 ++--- jb-lib/lib/models/__init__.py | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/api/app/routers/v1/__init__.py b/api/app/routers/v1/__init__.py index 66f36562..a8f9c4cc 100644 --- a/api/app/routers/v1/__init__.py +++ b/api/app/routers/v1/__init__.py @@ -33,7 +33,7 @@ async def get_bots(): return bots @router.get("/secret") -async def get_uuid(): +async def get_secret_key(): return {"secret": JBMANAGER_KEY} @@ -47,7 +47,7 @@ async def install_bot(request:Request, install_content: JBBotCode): headers = dict(request.headers) authorization = headers.get("authorization") if authorization is None: - raise HTTPException(status_code=400, detail="Authorization header not provided") + raise HTTPException(status_code=401, detail="Authorization header not provided") if authorization != f"Bearer {JBMANAGER_KEY}": raise HTTPException(status_code=401, detail="Unauthorized") @@ -112,7 +112,6 @@ async def add_bot_configuraton(bot_id: str, request: Request): # get all messages related to a session @router.get("/chats/{bot_id}/sessions/{session_id}") async def get_session(bot_id: str, session_id: str): - print("session_id", session_id) sessions = await get_bot_chat_sessions(bot_id, session_id) return sessions diff --git a/jb-lib/lib/models/__init__.py b/jb-lib/lib/models/__init__.py index 46c31f97..143eb813 100644 --- a/jb-lib/lib/models/__init__.py +++ b/jb-lib/lib/models/__init__.py @@ -293,6 +293,7 @@ class JBForm(Base): onupdate=func.now(), ) + # class LangchainPgCollection(Base): # __tablename__ = 'langchain_pg_collection' From ccff84fd3ed85b295aa4b203aa5c0328aab6211c Mon Sep 17 00:00:00 2001 From: kanak8278 Date: Thu, 18 Jul 2024 16:00:00 +0530 Subject: [PATCH 9/9] modified the fetchAndCopy function to fetch only and decoupled the copy to clipboard from function --- frontend/src/components/settings-model/index.tsx | 4 ++-- frontend/src/pages/home/home.tsx | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/settings-model/index.tsx b/frontend/src/components/settings-model/index.tsx index 8f4143b6..65fb48fd 100644 --- a/frontend/src/components/settings-model/index.tsx +++ b/frontend/src/components/settings-model/index.tsx @@ -1,7 +1,7 @@ import React, { useState, useEffect } from 'react'; import './settings-model.css'; import { sendRequest } from '@/api'; -import { fetchAndCopySecret } from '@/pages/home/home'; +import { fetchSecret } from '@/pages/home/home'; interface InputConfig { value: string | number | boolean; @@ -76,7 +76,7 @@ const SettingsModal: React.FC = ({ botId, isOpen, onClose, inputs, modelT } else if (modelType === 'install') { apiEndpoint = `${APIHOST}/v1/bot/install`; try { - accessToken = await fetchAndCopySecret(); + accessToken = await fetchSecret(); } catch (error) { console.error("Failed to fetch the access token:", error); alert("Failed to fetch the access token"); diff --git a/frontend/src/pages/home/home.tsx b/frontend/src/pages/home/home.tsx index ef6ece0c..cc6345b0 100644 --- a/frontend/src/pages/home/home.tsx +++ b/frontend/src/pages/home/home.tsx @@ -12,13 +12,12 @@ interface props { } -export async function fetchAndCopySecret() { +export async function fetchSecret() { const url = `${APIHOST}/v1/secret`; try { const response = await fetch(url); const data = await response.json(); const secret = data.secret; - await navigator.clipboard.writeText(secret); return secret; // Return the secret explicitly } catch (error) { console.error("Error fetching secret:", error); @@ -126,7 +125,8 @@ export const Home:React.FunctionComponent = (props:props) => {
{ try { - await fetchAndCopySecret(); + const secret = await fetchSecret(); + await navigator.clipboard.writeText(secret); alert("JB Manager secret copied!"); } catch (error) { alert("Failed to copy secret");