Spaces:
Paused
Paused
Upload 2 files
Browse files- src/main.rs +110 -4
src/main.rs
CHANGED
|
@@ -1180,6 +1180,60 @@ async fn gw_fetch_arl(
|
|
| 1180 |
Err(format!("getArl:{last_err}"))
|
| 1181 |
}
|
| 1182 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1183 |
async fn oauth_access_token(
|
| 1184 |
client: &reqwest::Client,
|
| 1185 |
email: &str,
|
|
@@ -1819,13 +1873,49 @@ async fn pair_oauth(State(state): State<AppState>, Json(req): Json<PairOauthReq>
|
|
| 1819 |
return json_error(StatusCode::BAD_REQUEST, "code/access_token required");
|
| 1820 |
}
|
| 1821 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1822 |
let mut map = state.pair.write().await;
|
| 1823 |
let Some(sess) = map.get_mut(&code) else {
|
| 1824 |
return json_error(StatusCode::NOT_FOUND, "no such code");
|
| 1825 |
};
|
| 1826 |
sess.access_token = Some(access_token);
|
| 1827 |
-
if
|
| 1828 |
-
sess.user_id = Some(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1829 |
}
|
| 1830 |
sess.error = None;
|
| 1831 |
drop(map);
|
|
@@ -2008,6 +2098,22 @@ async fn pair_complete(State(state): State<AppState>, Form(f): Form<PairComplete
|
|
| 2008 |
Html(format!("<h3>Ошибка входа</h3><pre>{}</pre>", htmlesc(&e))).into_response()
|
| 2009 |
}
|
| 2010 |
Ok(login) => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2011 |
let mut map = state.pair.write().await;
|
| 2012 |
if let Some(s) = map.get_mut(&code) {
|
| 2013 |
s.arl = login.arl.clone();
|
|
@@ -2020,7 +2126,7 @@ async fn pair_complete(State(state): State<AppState>, Form(f): Form<PairComplete
|
|
| 2020 |
if !login.uid.is_empty() {
|
| 2021 |
s.user_id = Some(login.uid.clone());
|
| 2022 |
}
|
| 2023 |
-
s.email = Some(email);
|
| 2024 |
s.error = None;
|
| 2025 |
}
|
| 2026 |
drop(map);
|
|
@@ -2169,7 +2275,7 @@ async fn oauth_arl(Json(req): Json<OauthArlReq>) -> impl IntoResponse {
|
|
| 2169 |
Ok((arl, _, _)) if arl.len() >= 20 => {
|
| 2170 |
(StatusCode::OK, Json(json!({ "arl": arl }))).into_response()
|
| 2171 |
}
|
| 2172 |
-
Err(e) => json_error(StatusCode::SERVICE_UNAVAILABLE, e),
|
| 2173 |
}
|
| 2174 |
}
|
| 2175 |
|
|
|
|
| 1180 |
Err(format!("getArl:{last_err}"))
|
| 1181 |
}
|
| 1182 |
|
| 1183 |
+
async fn try_fetch_arl_for_token(
|
| 1184 |
+
access_token: &str,
|
| 1185 |
+
user_id: Option<&str>,
|
| 1186 |
+
) -> (Option<String>, Option<String>) {
|
| 1187 |
+
let jar = Arc::new(Jar::default());
|
| 1188 |
+
let url_deezer = match "https://www.deezer.com".parse::<Url>() {
|
| 1189 |
+
Ok(u) => u,
|
| 1190 |
+
Err(_) => return (None, None),
|
| 1191 |
+
};
|
| 1192 |
+
jar.add_cookie_str("comeback=1; Domain=.deezer.com; Path=/", &url_deezer);
|
| 1193 |
+
|
| 1194 |
+
let client = match reqwest::Client::builder()
|
| 1195 |
+
.no_proxy()
|
| 1196 |
+
.cookie_provider(jar.clone())
|
| 1197 |
+
.timeout(std::time::Duration::from_secs(20))
|
| 1198 |
+
.build()
|
| 1199 |
+
{
|
| 1200 |
+
Ok(c) => c,
|
| 1201 |
+
Err(_) => return (None, None),
|
| 1202 |
+
};
|
| 1203 |
+
|
| 1204 |
+
let _ = client
|
| 1205 |
+
.get("https://www.deezer.com/")
|
| 1206 |
+
.header(ACCEPT, "*/*")
|
| 1207 |
+
.header("User-Agent", gw_browser_ua())
|
| 1208 |
+
.send()
|
| 1209 |
+
.await;
|
| 1210 |
+
|
| 1211 |
+
if ensure_anonymous_sid(&client, &jar).await.is_err() {
|
| 1212 |
+
return (None, None);
|
| 1213 |
+
}
|
| 1214 |
+
|
| 1215 |
+
establish_oauth_session(&client, &jar, access_token).await;
|
| 1216 |
+
|
| 1217 |
+
let uid = if let Some(uid) = user_id.filter(|s| !s.trim().is_empty()) {
|
| 1218 |
+
Some(uid.to_string())
|
| 1219 |
+
} else {
|
| 1220 |
+
api_deezer_get(&client, "/user/me", access_token, &[])
|
| 1221 |
+
.await
|
| 1222 |
+
.ok()
|
| 1223 |
+
.and_then(|v| v.get("id").and_then(|x| x.as_i64()))
|
| 1224 |
+
.filter(|id| *id > 0)
|
| 1225 |
+
.map(|id| id.to_string())
|
| 1226 |
+
};
|
| 1227 |
+
|
| 1228 |
+
match gw_fetch_arl(&client, "", "", uid.as_deref()).await {
|
| 1229 |
+
Ok((arl, token, _)) if arl.len() >= 20 => {
|
| 1230 |
+
let gw_token = if token.is_empty() { None } else { Some(token) };
|
| 1231 |
+
(Some(arl), gw_token)
|
| 1232 |
+
}
|
| 1233 |
+
_ => (None, None),
|
| 1234 |
+
}
|
| 1235 |
+
}
|
| 1236 |
+
|
| 1237 |
async fn oauth_access_token(
|
| 1238 |
client: &reqwest::Client,
|
| 1239 |
email: &str,
|
|
|
|
| 1873 |
return json_error(StatusCode::BAD_REQUEST, "code/access_token required");
|
| 1874 |
}
|
| 1875 |
|
| 1876 |
+
let http = reqwest::Client::builder()
|
| 1877 |
+
.no_proxy()
|
| 1878 |
+
.timeout(std::time::Duration::from_secs(15))
|
| 1879 |
+
.build()
|
| 1880 |
+
.unwrap();
|
| 1881 |
+
let email = api_deezer_get(&http, "/user/me", &access_token, &[])
|
| 1882 |
+
.await
|
| 1883 |
+
.ok()
|
| 1884 |
+
.and_then(|v| v.get("email").and_then(|x| x.as_str()).map(|s| s.to_string()));
|
| 1885 |
+
|
| 1886 |
+
let uid_from_api = if user_id.is_empty() {
|
| 1887 |
+
api_deezer_get(&http, "/user/me", &access_token, &[])
|
| 1888 |
+
.await
|
| 1889 |
+
.ok()
|
| 1890 |
+
.and_then(|v| v.get("id").and_then(|x| x.as_i64()))
|
| 1891 |
+
.filter(|id| *id > 0)
|
| 1892 |
+
.map(|id| id.to_string())
|
| 1893 |
+
} else {
|
| 1894 |
+
Some(user_id.clone())
|
| 1895 |
+
};
|
| 1896 |
+
|
| 1897 |
+
let (arl_opt, token_opt) = try_fetch_arl_for_token(
|
| 1898 |
+
&access_token,
|
| 1899 |
+
uid_from_api.as_deref(),
|
| 1900 |
+
)
|
| 1901 |
+
.await;
|
| 1902 |
+
|
| 1903 |
let mut map = state.pair.write().await;
|
| 1904 |
let Some(sess) = map.get_mut(&code) else {
|
| 1905 |
return json_error(StatusCode::NOT_FOUND, "no such code");
|
| 1906 |
};
|
| 1907 |
sess.access_token = Some(access_token);
|
| 1908 |
+
if let Some(uid) = uid_from_api {
|
| 1909 |
+
sess.user_id = Some(uid);
|
| 1910 |
+
}
|
| 1911 |
+
if let Some(arl) = arl_opt {
|
| 1912 |
+
sess.arl = Some(arl);
|
| 1913 |
+
}
|
| 1914 |
+
if let Some(token) = token_opt {
|
| 1915 |
+
sess.token = Some(token);
|
| 1916 |
+
}
|
| 1917 |
+
if let Some(email) = email {
|
| 1918 |
+
sess.email = Some(email);
|
| 1919 |
}
|
| 1920 |
sess.error = None;
|
| 1921 |
drop(map);
|
|
|
|
| 2098 |
Html(format!("<h3>Ошибка входа</h3><pre>{}</pre>", htmlesc(&e))).into_response()
|
| 2099 |
}
|
| 2100 |
Ok(login) => {
|
| 2101 |
+
let email_from_api = {
|
| 2102 |
+
let http = reqwest::Client::builder()
|
| 2103 |
+
.no_proxy()
|
| 2104 |
+
.timeout(std::time::Duration::from_secs(10))
|
| 2105 |
+
.build()
|
| 2106 |
+
.ok();
|
| 2107 |
+
if let Some(http) = http {
|
| 2108 |
+
api_deezer_get(&http, "/user/me", &login.access_token, &[])
|
| 2109 |
+
.await
|
| 2110 |
+
.ok()
|
| 2111 |
+
.and_then(|v| v.get("email").and_then(|x| x.as_str()).map(|s| s.to_string()))
|
| 2112 |
+
} else {
|
| 2113 |
+
None
|
| 2114 |
+
}
|
| 2115 |
+
};
|
| 2116 |
+
|
| 2117 |
let mut map = state.pair.write().await;
|
| 2118 |
if let Some(s) = map.get_mut(&code) {
|
| 2119 |
s.arl = login.arl.clone();
|
|
|
|
| 2126 |
if !login.uid.is_empty() {
|
| 2127 |
s.user_id = Some(login.uid.clone());
|
| 2128 |
}
|
| 2129 |
+
s.email = email_from_api.or(Some(email));
|
| 2130 |
s.error = None;
|
| 2131 |
}
|
| 2132 |
drop(map);
|
|
|
|
| 2275 |
Ok((arl, _, _)) if arl.len() >= 20 => {
|
| 2276 |
(StatusCode::OK, Json(json!({ "arl": arl }))).into_response()
|
| 2277 |
}
|
| 2278 |
+
Err(e) => json_error(StatusCode::SERVICE_UNAVAILABLE, format!("oauth_arl:{e}")),
|
| 2279 |
}
|
| 2280 |
}
|
| 2281 |
|