Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ node_modules/
*.log
auth.json
deepseek-auth.json
# Runtime-added auth files contain secrets — keep the dir, ignore its contents.
data/accounts/*.json
.chrome-profile-deepseek/
.chrome-for-testing-profile-deepseek/
.chrome-for-testing-profile-deepseek.stale-*/
Expand Down
31 changes: 31 additions & 0 deletions chrome-extension/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# DeepSeek → FreeDeepseekAPI (расширение)

Добавляет аккаунт DeepSeek в локальный FreeDeepseekAPI **одним кликом**:
перехватывает заголовки реального запроса к `chat.deepseek.com/api/...`
(`token` из `Authorization`, все cookie, `hif_*`) и отправляет на
`http://localhost:9655/api/accounts/import`.

Работает в Firefox и Chrome/Edge (Manifest V3).

## Установка

**Firefox**
1. Откройте `about:debugging#/runtime/this-firefox`
2. «Загрузить временное дополнение» → выберите `manifest.json` из этой папки.
(Временное дополнение: после перезапуска Firefox установить заново.)

**Chrome / Edge**
1. Откройте `chrome://extensions`
2. Включите «Режим разработчика».
3. «Загрузить распакованное» → выберите эту папку.

## Использование
1. Запустите FreeDeepseekAPI (порт 9655).
2. Откройте `chat.deepseek.com` и войдите в нужный аккаунт.
3. **Отправьте любое сообщение** (например `ok`) — чтобы прошёл запрос, из которого берутся креды.
4. Клик по иконке расширения → **«➕ Добавить в FreeDeepseekAPI»**.

Для нескольких аккаунтов повторите из разных профилей/логинов браузера.

Вспомогательные кнопки: «Собрать» (показать креды), «Копировать JSON»,
«Скачать файл» (`deepseek-auth.json`) — на случай ручного импорта через дашборд.
138 changes: 43 additions & 95 deletions chrome-extension/background.js
Original file line number Diff line number Diff line change
@@ -1,97 +1,45 @@
// DeepSeek Auth Exporter — Background Service Worker
// Reads cookies from Chrome, forwards content-script localStorage data.

const STORAGE_KEY = 'deepseek_auth';

// Read all needed cookies from chat.deepseek.com
async function readCookies() {
const needed = ['token', 'ds_session_id', 'smidV2'];
const results = {};
for (const name of needed) {
const cookie = await new Promise((resolve) =>
chrome.cookies.get({ url: 'https://chat.deepseek.com', name }, resolve)
);
results[name] = cookie ? cookie.value : '';
}

// Build cookie header string
const parts = [];
if (results.ds_session_id) parts.push(`ds_session_id=${results.ds_session_id}`);
if (results.smidV2) parts.push(`smidV2=${results.smidV2}`);
results.cookie = parts.join('; ');

return results;
}

// Read localStorage values via content script injection
async function readLocalStorage(tabId) {
const keys = ['hif_dliq', 'hif_leim'];
try {
const results = await new Promise((resolve, reject) => {
chrome.tabs.sendMessage(
tabId,
{ action: 'readLocalStorage', keys },
(response) => {
if (chrome.runtime.lastError) reject(chrome.runtime.lastError.message);
else resolve(response.data || {});
// DeepSeek → FreeDeepseekAPI — перехват заголовков реального запроса.
// token (Authorization: Bearer), cookie (все), hif (x-hif-*) берутся из
// настоящего запроса к chat.deepseek.com/api/... — как в HAR/cURL.

const WASM_DEFAULT = 'https://fe-static.deepseek.com/chat/static/sha3_wasm_bg.7b9ca65ddd.wasm';
const KEY = 'deepseek_capture';

// extraHeaders нужен Chrome для доступа к Cookie/Authorization; Firefox даёт их без него.
const opts = ['requestHeaders'];
try {
if (chrome.webRequest.OnBeforeSendHeadersOptions &&
chrome.webRequest.OnBeforeSendHeadersOptions.EXTRA_HEADERS) {
opts.push('extraHeaders');
}
} catch (e) { /* Firefox: опции нет — это нормально */ }

chrome.webRequest.onBeforeSendHeaders.addListener(
(details) => {
const h = {};
for (const x of (details.requestHeaders || [])) h[x.name.toLowerCase()] = x.value;
const auth = h['authorization'] || '';
const token = /^bearer\s+\S/i.test(auth) ? auth.replace(/^bearer\s+/i, '').trim() : '';
const cookie = h['cookie'] || '';
if (token && cookie) {
const cap = {
token,
cookie,
hif_dliq: h['x-hif-dliq'] || '',
hif_leim: h['x-hif-leim'] || '',
wasmUrl: WASM_DEFAULT,
_t: Date.now(),
};
chrome.storage.local.set({ [KEY]: cap });
}
);
});
return results;
} catch (e) {
return {};
}
}

// Find an open DeepSeek tab
function findDeepSeekTab() {
return new Promise((resolve) => {
chrome.tabs.query(
{ url: 'https://chat.deepseek.com/*' },
(tabs) => resolve(tabs.length > 0 ? tabs[0] : null)
);
});
}

async function collectAndStore(tabId) {
const cookies = await readCookies();
let ls = {};
if (tabId) ls = await readLocalStorage(tabId);

const merged = {
token: cookies.token || '',
ds_session_id: cookies.ds_session_id || '',
smidV2: cookies.smidV2 || '',
cookie: cookies.cookie || '',
hif_dliq: ls.hif_dliq || '',
hif_leim: ls.hif_leim || '',
_lastUpdated: new Date().toISOString(),
};

await new Promise((resolve) =>
chrome.storage.local.set({ [STORAGE_KEY]: merged }, resolve)
);
return merged;
}

// Message handler — popup requests
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === 'collect') {
findDeepSeekTab().then(async (tab) => {
if (!tab) {
sendResponse({ success: false, error: 'No DeepSeek tab open' });
return;
}
const auth = await collectAndStore(tab.id);
sendResponse({ success: true, auth });
});
return true; // keep channel open for async
}

if (request.action === 'export') {
chrome.storage.local.get(STORAGE_KEY, (result) => {
sendResponse({ success: true, auth: result[STORAGE_KEY] || {} });
});
return true;
}
},
{ urls: ['https://chat.deepseek.com/api/*'] },
opts
);

chrome.runtime.onMessage.addListener((req, sender, sendResponse) => {
if (req.action === 'get') {
chrome.storage.local.get(KEY, (r) => sendResponse({ success: true, cap: r[KEY] || null }));
return true; // async
}
});
Binary file added chrome-extension/icons/icon128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added chrome-extension/icons/icon16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added chrome-extension/icons/icon48.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 20 additions & 17 deletions chrome-extension/manifest.json
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
{
"manifest_version": 3,
"name": "DeepSeek Auth Exporter",
"version": "1.0",
"description": "Extract DeepSeek Chat credentials from cookies + localStorage for use with the web API proxy",
"permissions": ["cookies", "storage", "downloads"],
"host_permissions": ["https://chat.deepseek.com/*"],
"content_scripts": [
{
"matches": ["https://chat.deepseek.com/*"],
"js": ["content.js"],
"run_at": "document_idle"
"name": "DeepSeek → FreeDeepseekAPI",
"version": "1.4",
"description": "Добавляет аккаунт DeepSeek в локальный FreeDeepseekAPI одним кликом. Перехватывает заголовки запроса chat.deepseek.com (token + cookie + hif).",
"author": "FreeDeepseekAPI",
"browser_specific_settings": {
"gecko": {
"id": "freedeepseek-auth@forgetmeai",
"strict_min_version": "121.0",
"data_collection_permissions": { "required": ["none"] }
}
},
"permissions": ["webRequest", "storage"],
"host_permissions": [
"https://chat.deepseek.com/*",
"http://localhost:9655/*",
"http://127.0.0.1:9655/*"
],
"background": {
"service_worker": "background.js"
"service_worker": "background.js",
"scripts": ["background.js"]
},
"action": {
"default_popup": "popup.html",
"default_icon": {
"48": "icon.png"
}
"default_title": "DeepSeek → FreeDeepseekAPI",
"default_icon": { "16": "icons/icon16.png", "48": "icons/icon48.png", "128": "icons/icon128.png" }
},
"icons": {
"48": "icon.png"
}
"icons": { "16": "icons/icon16.png", "48": "icons/icon48.png", "128": "icons/icon128.png" }
}
57 changes: 52 additions & 5 deletions chrome-extension/popup.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,54 @@
.json-display { background: #0d1117; border: 1px solid #333; border-radius: 4px; padding: 8px; font-size: 10px; font-family: 'Courier New', monospace; color: #7ee787; white-space: pre-wrap; word-break: break-all; max-height: 180px; overflow-y: auto; margin-bottom: 8px; }
.field label { display: block; font-size: 11px; color: #999; margin-bottom: 4px; }
.detail { font-size: 10px; color: #666; text-align: center; }
.pool-section { margin-top: 14px; border-top: 1px solid #333; padding-top: 10px; }
.pool-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; }
.pool-header .title { font-size: 12px; color: #4fc3f7; font-weight: 600; }
.link-btn { background: none; border: 1px solid #444; color: #9ccc65; border-radius: 5px; padding: 4px 8px; font-size: 11px; cursor: pointer; }
.link-btn:hover { background: #ffffff10; }
.link-btn:disabled { opacity: 0.5; cursor: default; }
.pool-list { display: flex; flex-direction: column; gap: 4px; max-height: 220px; overflow-y: auto; }
.pool-row { display: flex; align-items: center; gap: 6px; padding: 6px 8px; background: #0d1117; border: 1px solid #2a2a3a; border-radius: 5px; font-size: 11px; }
.pool-row .id { color: #888; font-family: 'Courier New', monospace; min-width: 40px; }
.pool-row .email { flex: 1; color: #ccc; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.badge { padding: 2px 7px; border-radius: 10px; font-size: 10px; font-weight: 600; white-space: nowrap; }
.badge.ok { background: #1b5e2033; color: #66bb6a; border: 1px solid #2e7d32; }
.badge.invalid { background: #b71c1c33; color: #ef5350; border: 1px solid #c62828; }
.badge.wait { background: #e6510033; color: #ff9800; border: 1px solid #e65100; }
.badge.expired { background: #44444433; color: #999; border: 1px solid #555; }
.badge.checking { background: #1565c033; color: #4fc3f7; border: 1px solid #1565c0; }
.row-actions { display: flex; gap: 4px; }
.acc-btn { background: #ffffff0d; border: 1px solid #444; color: #ddd; border-radius: 4px; padding: 3px 7px; font-size: 11px; cursor: pointer; }
.acc-btn:hover { background: #ffffff1a; }
.acc-btn.danger:hover { background: #b71c1c44; color: #ef5350; }
.acc-btn.confirm { background: #b71c1c; color: #fff; border-color: #c62828; }
.pool-empty { color: #666; font-size: 11px; text-align: center; padding: 10px; }
.hdr { display: flex; align-items: center; justify-content: space-between; margin-bottom: 4px; }
.hdr h1 { margin: 0; }
.srv-dot { width: 9px; height: 9px; border-radius: 50%; background: #666; flex: none; }
.srv-dot.online { background: #66bb6a; box-shadow: 0 0 5px #2e7d32; }
.srv-dot.offline { background: #ef5350; box-shadow: 0 0 5px #c62828; }
.btn-row button:disabled { opacity: 0.45; cursor: default; }
.pool-row .email { cursor: pointer; }
.pool-row .email:hover { color: #4fc3f7; }
</style>
</head>
<body>
<h1>🔑 DeepSeek Auth Exporter</h1>
<div class="sub">Export credentials for <code>FreeDeepseekAPI</code></div>
<div class="hdr">
<h1>🔑 DeepSeek → FreeDeepseekAPI</h1>
<span id="srvDot" class="srv-dot" title="Статус сервера FreeDeepseekAPI"></span>
</div>
<div class="sub">Откройте <code>chat.deepseek.com</code>, <b>отправьте любое сообщение</b>, затем нажмите кнопку</div>

<div id="status" class="status warn">⏳ Loading...</div>

<div class="btn-row">
<button id="btnCollect" class="btn-primary">🔄 Collect from Tab</button>
<button id="btnCopy" class="btn-success">📋 Copy JSON</button>
<button id="btnSave" class="btn-warn">💾 Download File</button>
<button id="btnAdd" class="btn-primary" style="font-size:13px;padding:11px">➕ Добавить в FreeDeepseekAPI</button>
</div>
<div class="btn-row">
<button id="btnCollect" class="btn-success">🔄 Собрать</button>
<button id="btnCopy" class="btn-success">📋 Копировать JSON</button>
<button id="btnSave" class="btn-warn">💾 Скачать файл</button>
</div>

<div class="field">
Expand All @@ -43,6 +79,17 @@ <h1>🔑 DeepSeek Auth Exporter</h1>

<div class="detail" id="detail">Open chat.deepseek.com, then click Collect</div>

<div class="pool-section">
<div class="pool-header">
<span class="title" id="poolTitle">Пул аккаунтов</span>
<span style="display:flex; gap:6px">
<button id="btnDashboard" class="link-btn">🖥 Дашборд</button>
<button id="btnCheckAll" class="link-btn">↻ Проверить все</button>
</span>
</div>
<div id="pool" class="pool-list"></div>
</div>

<script src="popup.js"></script>
</body>
</html>
Loading