Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 7a5ee20

Browse files
committed
feat: Add cookie check
1 parent 6576333 commit 7a5ee20

File tree

4 files changed

+243
-16
lines changed

4 files changed

+243
-16
lines changed

‎src/lib.rs

Lines changed: 144 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use std::error::Error;
22

33
use reqwest::header::{HeaderMap, HeaderValue};
4-
use serde_json::json;
5-
use source::{descr::TaskData, taskfulldata::TaskFullData};
4+
use serde_json::{json,Value};
5+
use source::{cookie::CookieData,descr::TaskData, taskfulldata::TaskFullData};
66
use task_actions::Task;
77
use task_build::{Filters, TaskBuilder};
88

@@ -16,19 +16,11 @@ pub struct UserApi {
1616

1717
#[allow(unused)]
1818
impl UserApi {
19-
pub fn new(cookie: &str) -> Self {
19+
pub asyncfn new(cookie: &str) -> Result<Self,Box<dynError>> {
2020
let mut headers = HeaderMap::new();
21-
let token = String::from(
22-
cookie
23-
.strip_prefix("csrftoken=")
24-
.and_then(|val| Some(&val[..64]))
25-
.unwrap_or(""),
26-
);
2721

2822
headers.insert("Host", HeaderValue::from_static("leetcode.com"));
2923
headers.insert("User-Agent", HeaderValue::from_static("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36"));
30-
headers.insert("Cookie", HeaderValue::from_str(&cookie).unwrap());
31-
headers.insert("x-csrftoken", HeaderValue::from_str(&token).unwrap());
3224
headers.insert("Origin", HeaderValue::from_static("https://leetcode.com"));
3325
headers.insert("Referer", HeaderValue::from_static("https://leetcode.com/"));
3426
headers.insert("content-type", HeaderValue::from_static("application/json"));
@@ -37,12 +29,151 @@ impl UserApi {
3729
headers.insert("Sec-Fetch-Mode", HeaderValue::from_static("cors"));
3830
headers.insert("Sec-Fetch-Site", HeaderValue::from_static("same-origin"));
3931

32+
let valid_data = Self::valid_check(headers.clone(), &cookie).await?;
33+
34+
let cookie = if valid_data.0 {
35+
cookie
36+
} else {
37+
return Err("Cookie is invalid or User not signed".into());
38+
};
39+
40+
let token = valid_data.1;
41+
42+
headers.insert("Cookie", HeaderValue::from_str(&cookie).unwrap());
43+
headers.insert("x-csrftoken", HeaderValue::from_str(&token).unwrap());
44+
4045
let client = reqwest::Client::builder()
4146
.default_headers(headers)
4247
.build()
4348
.unwrap();
4449

45-
Self { client }
50+
Ok(Self { client })
51+
}
52+
53+
async fn valid_check(
54+
mut headers: HeaderMap,
55+
cookie: &str,
56+
) -> Result<(bool, String), Box<dyn Error>> {
57+
let token = if let Some(cookie) = cookie
58+
.strip_prefix("csrftoken=")
59+
.and_then(|val| Some(&val[..64]))
60+
{
61+
cookie
62+
} else {
63+
return Err("cannot take token from cookie".into());
64+
};
65+
headers.insert("Cookie", HeaderValue::from_str(&cookie).unwrap());
66+
headers.insert("x-csrftoken", HeaderValue::from_str(&token).unwrap());
67+
68+
let operation_name = "globalData";
69+
let variables: Value = json!({});
70+
71+
let query = r#"
72+
query globalData {
73+
feature {
74+
questionTranslation
75+
subscription
76+
signUp
77+
discuss
78+
mockInterview
79+
contest
80+
store
81+
chinaProblemDiscuss
82+
socialProviders
83+
studentFooter
84+
enableChannels
85+
dangerZone
86+
enableSharedWorker
87+
enableRecaptchaV3
88+
enableDebugger
89+
enableDebuggerPremium
90+
enableAutocomplete
91+
enableAutocompletePremium
92+
enableAllQuestionsRaw
93+
autocompleteLanguages
94+
enableIndiaPricing
95+
enableReferralDiscount
96+
maxTimeTravelTicketCount
97+
enableStoreShippingForm
98+
enableCodingChallengeV2
99+
__typename
100+
}
101+
streakCounter {
102+
streakCount
103+
daysSkipped
104+
currentDayCompleted
105+
__typename
106+
}
107+
currentTimestamp
108+
userStatus {
109+
isSignedIn
110+
isAdmin
111+
isStaff
112+
isSuperuser
113+
isMockUser
114+
isTranslator
115+
isPremium
116+
isVerified
117+
checkedInToday
118+
username
119+
realName
120+
avatar
121+
optedIn
122+
requestRegion
123+
region
124+
activeSessionId
125+
permissions
126+
notificationStatus {
127+
lastModified
128+
numUnread
129+
__typename
130+
}
131+
completedFeatureGuides
132+
__typename
133+
}
134+
siteRegion
135+
chinaHost
136+
websocketUrl
137+
recaptchaKey
138+
recaptchaKeyV2
139+
sitewideAnnouncement
140+
userCountryCode
141+
}
142+
"#;
143+
144+
let json_data = json!({
145+
"operationName": operation_name,
146+
"variables": variables,
147+
"query": query,
148+
});
149+
150+
let query = serde_json::to_string(&json_data).unwrap();
151+
152+
let client = reqwest::Client::new();
153+
154+
let cookie_info = match client
155+
.post("https://leetcode.com/graphql/")
156+
.body(query)
157+
.headers(headers)
158+
.send()
159+
.await
160+
.unwrap()
161+
.text()
162+
.await
163+
{
164+
Ok(data) => data,
165+
Err(_err) => return Err("Can't take cookie info".into()),
166+
};
167+
168+
if serde_json::from_str::<CookieData>(&cookie_info)?
169+
.data
170+
.userStatus
171+
.isSignedIn
172+
{
173+
return Ok((true, String::from(token)));
174+
}
175+
176+
Ok((false, String::from(token)))
46177
}
47178

48179
pub async fn set_task(&self, task: &str) -> Result<Task, Box<dyn Error>> {
@@ -121,7 +252,7 @@ impl UserApi {
121252
.await;
122253

123254
if let Err(_err) = task_info {
124-
return Err("Task does not found".into());
255+
return Err("Problem does not found".into());
125256
}
126257

127258
Ok(serde_json::from_str::<TaskData>(&task_info.unwrap())?)

‎src/source/cookie.rs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
use serde::{Deserialize, Serialize};
2+
3+
#[allow(non_snake_case)]
4+
#[derive(Debug, Deserialize, Serialize)]
5+
pub struct Feature {
6+
pub questionTranslation: bool,
7+
pub subscription: bool,
8+
pub signUp: bool,
9+
pub discuss: bool,
10+
pub mockInterview: bool,
11+
pub contest: bool,
12+
pub store: bool,
13+
pub chinaProblemDiscuss: bool,
14+
pub socialProviders: String,
15+
pub studentFooter: bool,
16+
pub enableChannels: bool,
17+
pub dangerZone: bool,
18+
pub enableSharedWorker: bool,
19+
pub enableRecaptchaV3: bool,
20+
pub enableDebugger: bool,
21+
pub enableDebuggerPremium: bool,
22+
pub enableAutocomplete: bool,
23+
pub enableAutocompletePremium: bool,
24+
pub enableAllQuestionsRaw: bool,
25+
pub autocompleteLanguages: String,
26+
pub enableIndiaPricing: bool,
27+
pub enableReferralDiscount: bool,
28+
pub maxTimeTravelTicketCount: i32,
29+
pub enableStoreShippingForm: bool,
30+
pub enableCodingChallengeV2: bool,
31+
pub __typename: String,
32+
}
33+
34+
#[allow(non_snake_case)]
35+
#[derive(Debug, Deserialize, Serialize)]
36+
pub struct StreakCounter {
37+
pub streakCount: i32,
38+
pub daysSkipped: i32,
39+
pub currentDayCompleted: bool,
40+
pub __typename: String,
41+
}
42+
43+
#[allow(non_snake_case)]
44+
#[derive(Debug, Deserialize, Serialize)]
45+
pub struct NotificationStatus {
46+
pub lastModified: i64,
47+
pub numUnread: i32,
48+
pub __typename: String,
49+
}
50+
51+
#[allow(non_snake_case)]
52+
#[derive(Debug, Deserialize, Serialize)]
53+
pub struct UserStatus {
54+
pub isSignedIn: bool,
55+
pub isAdmin: bool,
56+
pub isStaff: bool,
57+
pub isSuperuser: bool,
58+
pub isMockUser: bool,
59+
pub isTranslator: bool,
60+
pub isPremium: bool,
61+
pub isVerified: bool,
62+
pub checkedInToday: bool,
63+
pub username: String,
64+
pub realName: String,
65+
pub avatar: String,
66+
pub optedIn: bool,
67+
pub requestRegion: String,
68+
pub region: String,
69+
pub activeSessionId: i32,
70+
pub permissions: Vec<String>,
71+
pub notificationStatus: NotificationStatus,
72+
pub completedFeatureGuides: Vec<String>,
73+
pub __typename: String,
74+
}
75+
76+
#[allow(non_snake_case)]
77+
#[derive(Debug, Deserialize, Serialize)]
78+
pub struct GlobalData {
79+
pub feature: Feature,
80+
pub streakCounter: StreakCounter,
81+
pub currentTimestamp: f64,
82+
pub userStatus: UserStatus,
83+
pub siteRegion: String,
84+
pub chinaHost: String,
85+
pub websocketUrl: String,
86+
pub recaptchaKey: String,
87+
pub recaptchaKeyV2: String,
88+
pub sitewideAnnouncement: Option<String>,
89+
pub userCountryCode: String,
90+
}
91+
92+
#[derive(Debug, Deserialize, Serialize)]
93+
pub struct CookieData {
94+
pub data: GlobalData,
95+
}

‎src/source/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
pub mod cookie;
12
pub mod descr;
23
pub mod subm_send;
34
pub mod subm_show;

‎src/task_build.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,9 @@ impl TaskBuilder {
6161

6262
pub fn set_status(mut self, status: Status) -> TaskBuilder {
6363
match status {
64-
Status::Todo => self.filters.difficulty = String::from("NOT_STARTED"),
65-
Status::Solved => self.filters.difficulty = String::from("AC"),
66-
Status::Attempted => self.filters.difficulty = String::from("TRIED"),
64+
Status::Todo => self.filters.status = String::from("NOT_STARTED"),
65+
Status::Solved => self.filters.status = String::from("AC"),
66+
Status::Attempted => self.filters.status = String::from("TRIED"),
6767
}
6868
self
6969
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /