-
-
Notifications
You must be signed in to change notification settings - Fork 476
Add Castle Token support for Twitter login / onboarding #393
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Castle Token generation required for Twitter client login
Reviewer's GuideIntegrates Castle Token support by adding a new CastleToken service, extending the Client to accept and initialize an optional API key, and injecting generated tokens into the onboarding workflow. Sequence diagram for CastleToken generation and onboarding injectionsequenceDiagram
participant Client
participant CastleToken
participant HTTP
participant "Twitter Onboarding"
Client->>CastleToken: get_castle_token()
CastleToken->>CastleToken: Check cache/expiry
alt Token expired or not cached
CastleToken->>CastleToken: generate_castle_token()
CastleToken->>HTTP: POST /generate-token (with cuid, userAgent, API key)
HTTP-->>CastleToken: Castle token response
CastleToken->>CastleToken: Cache token
end
CastleToken-->>Client: Castle token
Client->>"Twitter Onboarding": Inject castle_token into subtask_inputs
Entity relationship diagram for Client and CastleTokenerDiagram
CLIENT ||--o| CASTLE_TOKEN : initializes
CLIENT {
string castle_api_key
}
CASTLE_TOKEN {
string api_key
string _castle_token
string _cuid
float _token_timestamp
}
Class diagram for CastleToken integrationclassDiagram
class Client {
+castle_api_key: str | None
+castle_token: CastleToken
}
class CastleToken {
+client: Client
+api_key: str | None
+_castle_token: str | None
+_cuid: str | None
+_token_timestamp: float | None
+_generate_cuid() str
+generate_castle_token() str
+get_castle_token() str
}
Client --> CastleToken
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
WalkthroughIntroduces CastleToken, a new class for managing castle token generation and caching for Twitter API requests, integrating it into the Client initialization and using it within the onboarding task method to conditionally inject tokens into request payloads. Changes
Sequence DiagramsequenceDiagram
participant Client
participant CastleToken
participant CastleAPI as castle.botwitter.com
participant V11 as onboarding_task
Client->>CastleToken: __init__(client, api_key)
V11->>CastleToken: get_castle_token()
alt Token cached and valid (< 60s)
CastleToken-->>V11: return cached token
else Token expired or missing
CastleToken->>CastleAPI: POST /generate-token (cuid, userAgent)
CastleAPI-->>CastleToken: token response
CastleToken->>CastleToken: cache token + timestamp
CastleToken-->>V11: return token
end
V11->>V11: inject token into settings_list['castle_token']
V11->>V11: proceed with request
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes The changes involve new CastleToken class logic with caching and timestamp management, integration into Client initialization, and conditional token injection in v11.py. While the patterns are consistent and relatively straightforward, the distributed nature across multiple files and the introduction of external API communication warrant careful review. Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey there - I've reviewed your changes - here's some feedback:
Blocking issues:
- Detected a Generic API Key, potentially exposing access to various services and sensitive operations. (link)
General comments:
- Assign the user_agent parameter to the Client instance (e.g., self._user_agent = user_agent) so generate_castle_token can reliably use it without risking undefined attributes.
- Add error handling and optional retry/backoff logic around the castle token POST request to handle HTTP failures or invalid responses gracefully instead of returning an empty string.
- Consider implementing client-side rate limiting or throttling for generate_castle_token calls to avoid exceeding the Castle API’s default quotas.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Assign the user_agent parameter to the Client instance (e.g., self._user_agent = user_agent) so generate_castle_token can reliably use it without risking undefined attributes.
- Add error handling and optional retry/backoff logic around the castle token POST request to handle HTTP failures or invalid responses gracefully instead of returning an empty string.
- Consider implementing client-side rate limiting or throttling for generate_castle_token calls to avoid exceeding the Castle API’s default quotas.
## Individual Comments
### Comment 1
<location> `twikit/castle_token/castle_token.py:78-81` </location>
<code_context>
+
+ # Extract and cache the castle token from response
+ response_data = response.json()
+ self._castle_token = response_data.get('token', '')
+ self._token_timestamp = time.time()
+
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Defaulting to an empty string for missing token may mask API errors.
Consider raising an exception or logging a warning if 'token' is missing to improve error visibility and handling.
```suggestion
# Extract and cache the castle token from response
response_data = response.json()
token = response_data.get('token')
if not token:
import logging
logging.warning("Castle token missing from response: %s", response_data)
raise ValueError("Castle token missing from API response")
self._castle_token = token
self._token_timestamp = time.time()
```
</issue_to_address>
### Comment 2
<location> `twikit/castle_token/castle_token.py:55-58` </location>
<code_context>
+ The generated Castle token
+ """
+ # Generate cuid
+ self._cuid = self._generate_cuid()
+
+ # Set __cuid cookie
+ self.client.http.cookies.set('__cuid', self._cuid)
+
+ # Prepare request data
</code_context>
<issue_to_address>
**question (bug_risk):** Setting the __cuid cookie directly may have concurrency implications.
Parallel requests sharing the same client may overwrite the __cuid cookie, causing race conditions. Evaluate statelessness or per-request cookie handling to avoid this.
</issue_to_address>
### Comment 3
<location> `twikit/client/v11.py:78-87` </location>
<code_context>
data['subtask_inputs'] = subtask_inputs
+ # Inject castle_token if settings_list is present
+ for subtask_input in subtask_inputs:
+ if isinstance(subtask_input, dict) and 'settings_list' in subtask_input:
+ castle_token = await self.base.castle_token.get_castle_token()
+ subtask_input['settings_list']['castle_token'] = castle_token
+
headers = {
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Directly mutating subtask_inputs may have unintended side effects.
Mutating subtask_inputs in place may affect other parts of the code that reference it. To avoid this, copy the dict before modifying it.
```suggestion
if subtask_inputs is not None:
new_subtask_inputs = []
# Inject castle_token if settings_list is present
for subtask_input in subtask_inputs:
if isinstance(subtask_input, dict) and 'settings_list' in subtask_input:
subtask_input_copy = subtask_input.copy()
castle_token = await self.base.castle_token.get_castle_token()
subtask_input_copy['settings_list'] = subtask_input_copy['settings_list'].copy()
subtask_input_copy['settings_list']['castle_token'] = castle_token
new_subtask_inputs.append(subtask_input_copy)
else:
new_subtask_inputs.append(subtask_input)
data['subtask_inputs'] = new_subtask_inputs
headers = {
```
</issue_to_address>
### Comment 4
<location> `twikit/client/client.py:99` </location>
<code_context>
premium_key_abc123def456ghi789
</code_context>
<issue_to_address>
**security (generic-api-key):** Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
*Source: gitleaks*
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this 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
🧹 Nitpick comments (1)
twikit/castle_token/castle_token.py (1)
24-29: Consider documenting cookie mutation side effect.The
generate_castle_tokenmethod (line 58) mutatesself.client.http.cookiesby setting the__cuidcookie. This side effect should be documented in the class or method docstring so users understand that creating a CastleToken instance will modify the client's cookie jar.class CastleToken: """ Handles Castle Token generation for Twitter API requests. The token is cached for 1 minute to avoid unnecessary API calls. + + Note: Token generation sets the '__cuid' cookie on the client's HTTP session. Parameters ---------- client : Client The Twitter client instance api_key : str | None, default=None Optional API key for castle.botwitter.com - Without API key: 3 requests/second, 100 requests/hour (default rate limits) - With API key: Custom rate limits, higher quotas, priority support """
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
twikit/castle_token/__init__.py(1 hunks)twikit/castle_token/castle_token.py(1 hunks)twikit/client/client.py(5 hunks)twikit/client/v11.py(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
twikit/client/client.py (1)
twikit/castle_token/castle_token.py (1)
CastleToken(9-102)
twikit/castle_token/__init__.py (1)
twikit/castle_token/castle_token.py (1)
CastleToken(9-102)
twikit/client/v11.py (1)
twikit/castle_token/castle_token.py (1)
get_castle_token(85-102)
twikit/castle_token/castle_token.py (1)
twikit/client/client.py (2)
Client(66-4336)get(221-223)
🪛 Gitleaks (8.28.0)
twikit/client/client.py
[high] 99-99: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
🔇 Additional comments (4)
twikit/castle_token/__init__.py (1)
1-3: LGTM!Clean package initialization following Python conventions.
twikit/castle_token/castle_token.py (1)
85-102: LGTM! Well-implemented token caching.The caching logic correctly handles token expiration (60 seconds) and regenerates when needed. The implementation efficiently avoids unnecessary API calls.
twikit/client/client.py (2)
61-61: LGTM! Clean integration of Castle Token support.The CastleToken integration is well-structured:
- Parameter added to
__init__with proper documentation- Instance always created (simplifies usage in v11.py)
- Example usage provided in docstring
The approach of always instantiating
CastleToken(even without an API key) is reasonable since the token generation will still work with default rate limits, and it simplifies the code inonboarding_task.Also applies to: 83-86, 98-99, 108-108, 125-125
99-99: Static analysis false positive - ignore Gitleaks warning.The Gitleaks tool flagged line 99 as potentially containing an API key, but this is simply a docstring example (
'premium_key_abc123def456ghi789'). This is not a real credential and is clearly示范性的 示例代码.
|
This need a pay method, not recommended |
Castle Token generation required for Twitter client login
Summary by Sourcery
Add Castle Token support to the Twikit Client by exposing user_agent and castle_api_key options, introducing the CastleToken helper for fetching and caching tokens, and injecting those tokens into onboarding tasks.
New Features:
Summary by CodeRabbit