Skip to content

Feat/session token account#155

Merged
james-6-23 merged 5 commits into
james-6-23:mainfrom
abwuge:feat/session-token-account
May 23, 2026
Merged

Feat/session token account#155
james-6-23 merged 5 commits into
james-6-23:mainfrom
abwuge:feat/session-token-account

Conversation

@abwuge
Copy link
Copy Markdown
Contributor

@abwuge abwuge commented May 22, 2026

简单修复session token需要过盾,以及前端不支持session token导入的问题

不过ip不干净仍然会导入失败

Summary by CodeRabbit

  • New Features

    • Session token support for adding/importing accounts: modal UI, batch import (single or line-matched), client-side validation and updated modal layout/controls.
    • Upgraded auth networking: more browser-like request headers, uTLS-based TLS fingerprinting, HTTP/2 connection pooling and proxy support for auth calls.
  • Bug Fixes

    • Enforced batch-size/format validation and preserved full credential sets when creating accounts.
  • Localization

    • Added English and Chinese strings for the Session Token flow.

Review Change Stack

Copilot AI review requested due to automatic review settings May 22, 2026 23:27
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 22, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

Adds session_token as an alternative credential end-to-end: request types and admin handler accept session_token and batch per-account seeds; uTLS HTTP/2 transport with proxy support is added and used for session refreshes with browser-like headers; frontend UI, form handling, and i18n support session-token input.

Changes

Session Token Authentication Support

Layer / File(s) Summary
Type contracts and request schema
frontend/src/types.ts, admin/handler.go
AddAccountRequest makes refresh_token optional and adds session_token; backend request struct and a line-splitting helper are added.
Backend request validation and batch logic
admin/handler.go
Handler validates at least one token is provided, splits credentials by line, enforces session_token line-count compatibility (single or matching), enforces max batch size, and builds per-account credential seeds.
DB insertion and in-memory account init
admin/handler.go
Per-account names for batched inserts are generated; each account is persisted with InsertAccountWithCredentials using tokenCredentialMap(seed); hot-loading derives full account via accountFromCredentialSeed.
uTLS HTTP client infrastructure
auth/utls_client.go
New transport implements uTLS-backed HTTP/2 RoundTripper with per-host connection pooling, concurrent-creation coordination, HTTP CONNECT and SOCKS5 proxy dialers, and TTL-based client pool eviction.
Session token refresh with uTLS and browser headers
auth/token.go
RefreshWithSessionToken sets browser-like headers (User-Agent, Accept-Language, Sec-Fetch-*) and uses buildUTLSHTTPClient for non-Resin refresh requests.
Frontend form state and submission
frontend/src/pages/Accounts.tsx
Form state adds session_token, addMethod includes "st", and handleAdd builds/validates and submits AddAccountRequest for the selected credential, resetting state on success.
Frontend UI components for session token
frontend/src/pages/Accounts.tsx
Modal width increased, tab switcher converted to grid; new "Session Token" tab with Cookie icon, session-token textarea and proxy input in the "st" branch; submit button branches on token type.
Internationalization for session token UI
frontend/src/locales/en.json, frontend/src/locales/zh.json
Locale keys added for the session token method label, bulk-paste placeholder, and optional fallback placeholder.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Poem

🐰 I nibbled lines of tokens in the night,
A cookie clasped where headers shine,
Chrome footsteps whisper through the stream,
Seeds of accounts wake from a dream,
The rabbit hops — the connections light.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Feat/session token account' is directly related to the main changes, which add session token support to account creation/import across backend and frontend.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds support for adding accounts via Session Token and improves session-token refresh robustness against Cloudflare-protected endpoints by introducing a uTLS + HTTP/2 client.

Changes:

  • Frontend: add a “Session Token” add method/tab, form fields, and i18n strings.
  • Backend: accept session_token in add-account API (including batch rules) and store credentials via a credentials map.
  • Auth: introduce a uTLS-based HTTP client pool and use it for session-token refresh requests.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
frontend/src/types.ts Extends add-account request typing to include optional session_token and makes refresh_token optional.
frontend/src/pages/Accounts.tsx Adds UI flow for session-token based account creation and adjusts payload validation/submission.
frontend/src/locales/en.json Adds English labels/placeholders for Session Token add method.
frontend/src/locales/zh.json Adds Chinese labels/placeholders for Session Token add method.
auth/utls_client.go New uTLS + HTTP/2 round-tripper, proxy dialers, and pooled client with TTL eviction.
auth/token.go Uses uTLS client for session-token refresh and adds browser-like request headers.
admin/handler.go Accepts session_token, supports batch parsing/mapping, and inserts accounts with credential maps.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread auth/utls_client.go
Comment on lines +166 to +169
case "http", "https":
return buildAuthHTTPProxyDialer(u)
case "socks5", "socks5h":
return buildAuthSOCKS5Dialer(u)
Comment thread auth/utls_client.go
Comment on lines +30 to +44
func newUTLSAuthTransport(proxyURL string) http.RoundTripper {
var dialer xproxy.Dialer = xproxy.Direct
if proxyURL != "" {
d, err := buildAuthProxyDialer(proxyURL)
if err != nil {
dialer = xproxy.Direct
} else {
dialer = d
}
}
return &utlsAuthRoundTripper{
connections: make(map[string]*http2.ClientConn),
pending: make(map[string]*sync.Cond),
dialer: dialer,
}
Comment thread auth/utls_client.go
}

func (d *authHTTPConnectDialer) Dial(network, addr string) (net.Conn, error) {
conn, err := net.DialTimeout("tcp", d.proxyAddr, 10*time.Second)
Comment thread auth/utls_client.go
Comment on lines +274 to +289
var utlsAuthClientPoolStop = make(chan struct{})

func init() {
go func() {
ticker := time.NewTicker(utlsAuthClientPoolCleanupInterval)
defer ticker.Stop()
for {
select {
case <-ticker.C:
evictExpiredUTLSAuthClients()
case <-utlsAuthClientPoolStop:
return
}
}
}()
}
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@auth/utls_client.go`:
- Around line 55-66: The waiter loop can deadlock on an old cond when another
goroutine replaces t.pending[host]; to fix it, capture the current cond (e.g.
cur := cond) before calling cur.Wait() and after being signaled check that
t.pending[host] still equals that same cur (pointer equality); if it does not,
stop waiting on the old cond (break/return to re-evaluate) so you never call
Wait() again on a stale condition variable. Ensure these checks reference
t.pending, the local cond variable, and the same mutex t.mu surrounding
Wait/inspection, and keep the existing checks for t.connections[host] and
CanTakeNewRequest().
- Around line 30-45: In newUTLSAuthTransport, do not silently ignore errors from
buildAuthProxyDialer; when buildAuthProxyDialer(proxyURL) returns an error, log
the error and the proxyURL before falling back to xproxy.Direct so configuration
issues are visible. Update the error branch in newUTLSAuthTransport to call the
package logger (or standard log) with a clear message including the error and
proxyURL, then set dialer = xproxy.Direct; keep the rest of the function and
utlsAuthRoundTripper initialization unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b06c22f2-3de7-4d15-87a1-5cbeb5cbfa80

📥 Commits

Reviewing files that changed from the base of the PR and between 0627e0b and 5b739a0.

📒 Files selected for processing (7)
  • admin/handler.go
  • auth/token.go
  • auth/utls_client.go
  • frontend/src/locales/en.json
  • frontend/src/locales/zh.json
  • frontend/src/pages/Accounts.tsx
  • frontend/src/types.ts

Comment thread auth/utls_client.go
Comment on lines +30 to +45
func newUTLSAuthTransport(proxyURL string) http.RoundTripper {
var dialer xproxy.Dialer = xproxy.Direct
if proxyURL != "" {
d, err := buildAuthProxyDialer(proxyURL)
if err != nil {
dialer = xproxy.Direct
} else {
dialer = d
}
}
return &utlsAuthRoundTripper{
connections: make(map[string]*http2.ClientConn),
pending: make(map[string]*sync.Cond),
dialer: dialer,
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Proxy dialer errors are silently swallowed, masking configuration issues.

When buildAuthProxyDialer fails (e.g., malformed proxy URL), the code falls back to direct connection without any logging or error indication. Users won't know their proxy configuration is being ignored.

Proposed fix: Log the error before falling back
 func newUTLSAuthTransport(proxyURL string) http.RoundTripper {
 	var dialer xproxy.Dialer = xproxy.Direct
 	if proxyURL != "" {
 		d, err := buildAuthProxyDialer(proxyURL)
 		if err != nil {
+			log.Printf("[utls] failed to build proxy dialer for %q, falling back to direct: %v", proxyURL, err)
 			dialer = xproxy.Direct
 		} else {
 			dialer = d
 		}
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@auth/utls_client.go` around lines 30 - 45, In newUTLSAuthTransport, do not
silently ignore errors from buildAuthProxyDialer; when
buildAuthProxyDialer(proxyURL) returns an error, log the error and the proxyURL
before falling back to xproxy.Direct so configuration issues are visible. Update
the error branch in newUTLSAuthTransport to call the package logger (or standard
log) with a clear message including the error and proxyURL, then set dialer =
xproxy.Direct; keep the rest of the function and utlsAuthRoundTripper
initialization unchanged.

Comment thread auth/utls_client.go
Comment on lines +55 to +66
if cond, ok := t.pending[host]; ok {
for {
cond.Wait()
if h2Conn, ok := t.connections[host]; ok && h2Conn.CanTakeNewRequest() {
t.mu.Unlock()
return h2Conn, nil
}
if _, still := t.pending[host]; !still {
break
}
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Race condition: waiters can deadlock on stale condition variable.

When multiple goroutines wait for a connection and the creator fails:

  1. Thread A creates cond, adds to pending[host], starts creating connection
  2. Threads B and C see pending[host], both capture cond and call Wait()
  3. A fails, broadcasts, deletes pending[host]
  4. B wakes first, sees no pending, breaks loop at line 64, creates a new cond and stores it in pending[host]
  5. C wakes, checks pending[host] at line 62 — sees B's new cond exists (still = true)
  6. C loops back to Wait() on A's old cond, which will never signal again → deadlock

The fix is to detect when the condition variable has been replaced:

Proposed fix
 	if cond, ok := t.pending[host]; ok {
 		for {
 			cond.Wait()
 			if h2Conn, ok := t.connections[host]; ok && h2Conn.CanTakeNewRequest() {
 				t.mu.Unlock()
 				return h2Conn, nil
 			}
-			if _, still := t.pending[host]; !still {
+			newCond, still := t.pending[host]
+			if !still {
 				break
 			}
+			if newCond != cond {
+				cond = newCond // switch to the replacement condition variable
+			}
 		}
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@auth/utls_client.go` around lines 55 - 66, The waiter loop can deadlock on an
old cond when another goroutine replaces t.pending[host]; to fix it, capture the
current cond (e.g. cur := cond) before calling cur.Wait() and after being
signaled check that t.pending[host] still equals that same cur (pointer
equality); if it does not, stop waiting on the old cond (break/return to
re-evaluate) so you never call Wait() again on a stale condition variable.
Ensure these checks reference t.pending, the local cond variable, and the same
mutex t.mu surrounding Wait/inspection, and keep the existing checks for
t.connections[host] and CanTakeNewRequest().

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/src/pages/Accounts.tsx (1)

749-757: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep the RT + session-token fallback path reachable from the UI.

This change makes refresh_token and session_token mutually exclusive: handleAdd blanks the other field before POSTing, and the RT tab no longer exposes the optional session-token input. admin/handler.go:1100-1163 still supports paired RT/ST batches and a shared ST fallback, so that flow is now unreachable from the frontend.

Also applies to: 3193-3263

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/pages/Accounts.tsx` around lines 749 - 757, handleAdd currently
forces refresh_token and session_token to be mutually exclusive by blanking the
other field and the RT UI no longer exposes the optional session_token, which
prevents sending paired RT+ST batches that the backend (admin/handler.go
handlers) still supports; fix by changing payload construction in handleAdd
(function name handleAdd, type AddAccountRequest, and source object addForm) to
include both refresh_token and session_token from addForm without overwriting
one with an empty string, keep the existing validation that at least one token
is non-empty, and restore or ensure the RT tab UI still exposes an optional
session_token input so the frontend can submit RT+ST together when provided.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@frontend/src/pages/Accounts.tsx`:
- Around line 749-757: handleAdd currently forces refresh_token and
session_token to be mutually exclusive by blanking the other field and the RT UI
no longer exposes the optional session_token, which prevents sending paired
RT+ST batches that the backend (admin/handler.go handlers) still supports; fix
by changing payload construction in handleAdd (function name handleAdd, type
AddAccountRequest, and source object addForm) to include both refresh_token and
session_token from addForm without overwriting one with an empty string, keep
the existing validation that at least one token is non-empty, and restore or
ensure the RT tab UI still exposes an optional session_token input so the
frontend can submit RT+ST together when provided.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 46f4774c-e360-4bc1-99a0-2b44fe7fd19c

📥 Commits

Reviewing files that changed from the base of the PR and between 5b739a0 and 72c1c36.

📒 Files selected for processing (1)
  • frontend/src/pages/Accounts.tsx

@james-6-23 james-6-23 merged commit 2cb2f6a into james-6-23:main May 23, 2026
5 of 6 checks passed
@abwuge abwuge deleted the feat/session-token-account branch May 23, 2026 06:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants