diff --git a/.env.example b/.env.example index d88025c..1344028 100644 --- a/.env.example +++ b/.env.example @@ -16,3 +16,27 @@ BACKEND_URL=http://localhost:11081 # 브라우저 언어 설정 LANG=en_US + + +# provider 계정 (본인이 사용하지 않는 계정 권장) (Github, apple, kakao등 다른 계정 추가 가능) +# PROVIDOR_CREDENTIALS_IN_LLM는 True로 설정시, 아래 계정 정보가 LLM에 포함되어 사용됩니다. +# 쿠키와 로컬스토리지 사용은 제외됩니다. +PROVIDOR_CREDENTIALS_IN_LLM=False + +GOOGLE_ID= +GOOGLE_PASSWORD= + +NAVER_ID= +NAVER_PASSWORD= + +FACEBOOK_ID= +FACEBOOK_PASSWORD= + +GITGUB_ID= +GITHUB_PASSWORD= + +LinkedIn_ID= +LinkedIn_PASSWORD= + +Microsoft_ID= +Microsoft_PASSWORD= \ No newline at end of file diff --git a/lib/prompt/__init__.py b/lib/prompt/__init__.py new file mode 100644 index 0000000..faed89b --- /dev/null +++ b/lib/prompt/__init__.py @@ -0,0 +1,13 @@ +from dotenv import load_dotenv +import os + +from lib.prompt import session +from lib.prompt import llm_login + +load_dotenv(override=True) + +def extend_planner_system_message(): + if os.getenv("PROVIDOR_CREDENTIALS_IN_LLM", "False").lower() == "true": + return llm_login.extend_planner_system_message + else: + return session.extend_planner_system_message \ No newline at end of file diff --git a/lib/prompt.py b/lib/prompt/llm_login.py similarity index 86% rename from lib/prompt.py rename to lib/prompt/llm_login.py index e20c58c..630f606 100644 --- a/lib/prompt.py +++ b/lib/prompt/llm_login.py @@ -1,5 +1,21 @@ +from dotenv import load_dotenv +import os + +load_dotenv(override=True) +google_id = os.getenv("GOOGLE_ID", "") +google_password = os.getenv("GOOGLE_PASSWORD", "") + +naver_id = os.getenv("NAVER_ID", "") +naver_password = os.getenv("NAVER_PASSWORD", "") + +facebook_id = os.getenv("FACEBOOK_ID", "") +facebook_password = os.getenv("FACEBOOK_PASSWORD", "") + +github_id = os.getenv("GITHUB_ID", "") +github_password = os.getenv("GITHUB_PASSWORD", "") + # Extended planner prompt -extend_planner_system_message = """ +extend_planner_system_message = f""" 🎯 Mission: Collect Initial SSO Redirect URLs (For Browser Automation) ※ **모든 STEP에서 구글 검색, Bing 검색 등 어떤 외부 검색 기능도 절대 사용하지 않고, 초기에 주어진 URL에서 탐색하세요.** @@ -40,8 +56,7 @@ extend_planner_system_message = """ - Naver → `{naver_id}` / `{naver_password}` - GitHub → `{github_id}` / `{github_password}` - 자격증명이 주어진 SSO 버튼인 경우 로그인 과정을 꼭 진행합니다. - - 로그인 과정이 모두 끝난 경우 세션 및 쿠키를 모두 삭제하고 페이지를 새로고침합니다. - - 로그인 시도를 우선으로 해주세요. 하지만 계정 정보를 가지고 있지 않거나 로그인이 되어 있지 않은 경우, 로그인은 건너뛰고 다음 단계로 진행합니다. + - 로그인 과정이 모두 끝나거나 로그인이 되지 않는 경우 세션 및 쿠키를 모두 삭제하고 페이지를 새로고침합니다. - 아직 로그인을 시도하지 않은 SSO 버튼이 있다면 이전 단계인 1. **로그인 페이지 탐색**, 2. **SSO 버튼 식별**, 3. **SSO 버튼 클릭 및 로그인 시도** 로 돌아가 절차를 반복합니다. - 최종 결과는 다음과 같이 기록합니다: ```json diff --git a/lib/prompt/session.py b/lib/prompt/session.py new file mode 100644 index 0000000..28a003f --- /dev/null +++ b/lib/prompt/session.py @@ -0,0 +1,107 @@ +# Extended planner prompt +extend_planner_system_message = """ +🎯 목적: 웹 자동화를 위한 **SSO 로그인 리디렉션 URL 수집** + +📌 주의사항 (전제 조건) +- **검색 엔진(Google, Bing 등) 사용 금지.** +- **초기 제공된 URL 내에서만 탐색.** +- **실제로 로드된 URL 외, 직접 이동하거나 추측한 링크는 클릭 금지.** +- 추측한 URL은 대답하지도 직접 이동하지도 않습니다. + +--- + +## 🧩 Step 0: 페이지 차단(Block) 여부 확인 + +- 초기에 주어진 로그인 페이지에 접속 시 다음 중 하나라도 발생하면 즉시 중단: + - 페이지 차단됨 (Firewall, Access Denied 등) + - CAPTCHA는 직접적으로 진행해도 괜찮습니다. + - 정상적으로 로그인 UI가 로드되지 않음 + +🔚 종료 시 반환: +```json +[ + { + "provider": "Blocked", + "oauth_uri": "-" + } +] +```` + +--- + +## 🔍 Step 1: 로그인 페이지 탐색 + +* **초기 URL에서 클라이언트용 로그인 페이지로 직접 이동.** +* 쿠키/개인정보 팝업 등이 있으면 무시하거나 닫고 계속 진행. +* 페이지가 정상 로드되었다고 가정. + +--- + +## 👀 Step 2: SSO 로그인 버튼 식별 + +* 로그인 화면에서 다음 **OAuth 기반 SSO 버튼**들을 찾는다: + + * Google, GitHub, Facebook, LinkedIn, Microsoft, Naver +* ✅ 유효한 버튼: **OAuth 인증 흐름을 트리거하는 실제 버튼** +* ❌ 제외 대상: + + * Passkey, 휴대폰 인증, 이메일 인증, 인증서 기반, 일반 아이디/비밀번호 로그인 + +--- + +## ✅ Step 3: SSO 버튼 클릭 및 로그인 시도 + +각 SSO 버튼에 대해 다음 절차를 반복: + +1. 버튼 클릭 +2. \*\*처음 리디렉션된 URL(쿼리스트링 포함)\*\*을 기록 → `oauth_uri` +3. 공급자 페이지가 열리면 로그인 시도: + + * 브라우저 쿠키와 로컬 스토리지는 로그인 상태 유지 중 + * 계정 인증, 권한 부여, authorize 버튼 클릭 등 수행 +4. 로그인 완료 후: + + * 세션/쿠키 삭제 + * 페이지 새로고침 +5. 아직 로그인하지 않은 다른 SSO 버튼이 있다면 **Step 2로 돌아감** + +📝 결과 저장 형식 (예시): + +```json +[ + { + "provider": "Google", + "oauth_uri": "https://example.com/auth/google?client_id=..." + }, + { + "provider": "Naver", + "oauth_uri": "https://example.com/auth/naver?client_id=..." + } +] +``` + +--- + +## 🚫 Step 4: 버튼 없음 또는 예외 발생 시 + +* 유효한 SSO 버튼이 **전혀 없음** +* 예외/에러 발생 시 + +🔚 즉시 중단 및 다음 반환: + +```json +[] +``` + +--- + +## 📎 중요 규칙 요약 + +* **단계를 반드시 순서대로 진행.** +* 예외 발생 시, 지정된 JSON 형식으로만 반환. +* **반복 탐색/비정상 행동 감지 시 빈 배열 반환.** +* 로그인을 직접 입력하지 말고, 저장된 세션/쿠키를 사용. +* 한 번에 하나씩 탐색하며, 조건 불충분 시 **다음 버튼으로 진행.** + +--- +""" \ No newline at end of file diff --git a/main.py b/main.py index f0af03e..c403edc 100644 --- a/main.py +++ b/main.py @@ -204,7 +204,7 @@ async def scan_one_url(url: str, skip_html_check: bool = False): llm=CreateChatGoogleGenerativeAI(os.getenv("GOOGLE_MODEL") or "fallback"), planner_llm=CreateChatGoogleGenerativeAI(os.getenv("GOOGLE_PLANNER_MODEL") or "fallback"), controller=controller, - extend_planner_system_message=extend_planner_system_message, + extend_planner_system_message=extend_planner_system_message(), ) response = await agent.run() final_result = response.final_result()