返回提交历史
Modified
g4f/Provider/Copilot.py
+66
-14
XFEstudio/gpt4free
Add random cookie generation and enhance authentication flow in Copilot
cf4ab392
代码差异
1 个文件
+66
-14
@@ -4,6 +4,9 @@ import os
4
4
import json
5
5
import asyncio
6
6
import base64
7
import random
8
import string
9
import urllib.parse
7
10
from typing import AsyncIterator
8
11
from urllib.parse import quote
9
12
@@ -25,7 +28,7 @@ from ..typing import AsyncResult, Messages, MediaListType
25
28
from ..errors import MissingRequirementsError, NoValidHarFileError, MissingAuthError
26
29
from ..providers.response import *
27
30
from ..tools.media import merge_media
28
from ..requests import get_nodriver
31
from ..requests import get_nodriver, DEFAULT_HEADERS
29
32
from ..image import to_bytes, is_accepted_format
30
33
from .helper import get_last_user_message
31
34
from ..files import get_bucket_dir
@@ -52,6 +55,24 @@ def extract_bucket_items(messages: Messages) -> list[dict]:
52
55
bucket_items = []
53
56
return bucket_items
54
57
58
def random_hex(length):
59
return ''.join(random.choices('0123456789ABCDEF', k=length))
60
61
def random_base64(length):
62
chars = string.ascii_letters + string.digits + '+/='
63
return ''.join(random.choices(chars, k=length))
64
65
def get_fake_cookie():
66
return {
67
"_C_ETH": "1",
68
"_C_Auth": "",
69
"MUID": random_hex(32),
70
"MUIDB": random_hex(32),
71
"_EDGE_S": f"F=1&SID={random_hex(32)}",
72
"_EDGE_V": "1",
73
"ak_bmsc": f"{random_hex(32)}~{'0'*48}~{urllib.parse.quote(random_base64(300))}"
74
}
75
55
76
class Copilot(AsyncAuthedProvider, ProviderModelMixin):
56
77
label = "Microsoft Copilot"
57
78
url = "https://copilot.microsoft.com"
@@ -76,12 +97,8 @@ class Copilot(AsyncAuthedProvider, ProviderModelMixin):
76
97
conversation_url = f"{url}/c/api/conversations"
77
98
78
99
@classmethod
79
async def on_auth_async(cls, cookies: dict = None, api_key: str = None, proxy: str = None, **kwargs) -> AsyncIterator:
80
if api_key:
81
if not cookies:
82
cookies = {}
83
cookies[cls.anon_cookie_name] = api_key
84
elif cookies is None:
100
async def on_auth_async(cls, cookies: dict = None, proxy: str = None, **kwargs) -> AsyncIterator:
101
if cookies is None:
85
102
cookies = get_cookies(cls.cookie_domain, False, cache_result=False)
86
103
access_token = None
87
104
useridentitytype = None
@@ -119,10 +136,12 @@ class Copilot(AsyncAuthedProvider, ProviderModelMixin):
119
136
raise MissingRequirementsError('Install or update "curl_cffi" package | pip install -U curl_cffi')
120
137
model = cls.get_model(model)
121
138
websocket_url = cls.websocket_url
122
headers = None
139
headers = DEFAULT_HEADERS.copy()
140
headers["origin"] = cls.url
141
headers["referer"] = cls.url + "/"
123
142
if getattr(auth_result, "access_token", None):
124
143
websocket_url = f"{websocket_url}&accessToken={quote(auth_result.access_token)}" + (f"&X-UserIdentityType={quote(auth_result.useridentitytype)}" if getattr(auth_result, "useridentitytype", None) else "")
125
headers = {"authorization": f"Bearer {auth_result.access_token}"}
144
headers["authorization"] = f"Bearer {auth_result.access_token}"
126
145
127
146
async with AsyncSession(
128
147
timeout=timeout,
@@ -170,12 +189,14 @@ class Copilot(AsyncAuthedProvider, ProviderModelMixin):
170
189
if response.status_code == 401:
171
190
raise MissingAuthError("Status 401: Invalid session")
172
191
response.raise_for_status()
192
debug.log(f"Copilot: Update cookies: [{', '.join(key for key in response.cookies)}]")
193
auth_result.cookies.update({key: value for key, value in response.cookies.items()})
194
if not cls.needs_auth and cls.anon_cookie_name not in auth_result.cookies:
195
raise MissingAuthError(f"Missing cookie: {cls.anon_cookie_name}")
173
196
conversation = Conversation(response.json().get("currentConversationId"))
174
197
debug.log(f"Copilot: Created conversation: {conversation.conversation_id}")
175
198
else:
176
199
debug.log(f"Copilot: Use conversation: {conversation.conversation_id}")
177
if return_conversation:
178
yield conversation
179
200
180
201
# response = await session.get("https://copilot.microsoft.com/c/api/user?api-version=4", headers={"x-useridentitytype": useridentitytype} if cls._access_token else {})
181
202
# if response.status_code == 401:
@@ -298,6 +319,8 @@ class Copilot(AsyncAuthedProvider, ProviderModelMixin):
298
319
debug.log(f"Copilot Message: {msg_txt[:100]}...")
299
320
if not done:
300
321
raise MissingAuthError(f"Invalid response: {last_msg}")
322
if return_conversation:
323
yield conversation
301
324
if sources:
302
325
yield Sources(sources.values())
303
326
if not wss.closed:
@@ -338,6 +361,19 @@ async def get_access_token_and_cookies(url: str, proxy: str = None, needs_auth:
338
361
break
339
362
if not needs_auth:
340
363
break
364
if not needs_auth:
365
textarea = await page.select("textarea")
366
if textarea is not None:
367
await textarea.send_keys("Hello")
368
await asyncio.sleep(1)
369
button = await page.select("[data-testid=\"submit-button\"]")
370
if button:
371
await button.click()
372
turnstile = await page.select('#cf-turnstile', 300)
373
if turnstile:
374
debug.log("Found Element: 'cf-turnstile'")
375
await asyncio.sleep(3)
376
await click_trunstile(page)
341
377
cookies = {}
342
378
while Copilot.anon_cookie_name not in cookies:
343
379
await asyncio.sleep(2)
@@ -369,7 +405,23 @@ def readHAR(url: str):
369
405
useridentitytype = v_headers["x-useridentitytype"]
370
406
if v['request']['cookies']:
371
407
cookies = {c['name']: c['value'] for c in v['request']['cookies']}
372
if api_key is None:
373
raise NoValidHarFileError("No access token found in .har files")
408
if not cookies:
409
raise NoValidHarFileError("No session found in .har files")
410
411
return api_key, useridentitytype, cookies
374
412
375
return api_key, useridentitytype, cookies
413
if has_nodriver:
414
async def click_trunstile(page: nodriver.Tab, element='document.getElementById("cf-turnstile")'):
415
for _ in range(3):
416
size = None
417
for idx in range(15):
418
size = await page.js_dumps(f'{element}?.getBoundingClientRect()||{{}}')
419
debug.log(f"Found size: {size.get('x'), size.get('y')}")
420
if "x" not in size:
421
break
422
await page.flash_point(size.get("x") + idx * 3, size.get("y") + idx * 3)
423
await page.mouse_click(size.get("x") + idx * 3, size.get("y") + idx * 3)
424
await asyncio.sleep(2)
425
if "x" not in size:
426
break
427
debug.log("Finished clicking trunstile.")