Skip to content

Commit c8a001d

Browse files
committed
remove dependency on shared library openssl
1 parent 39244aa commit c8a001d

File tree

6 files changed

+350
-254
lines changed

6 files changed

+350
-254
lines changed

tmc-langs-core/Cargo.toml

+4-2
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ edition = "2018"
66

77
[dependencies]
88
tmc-langs-util = { path = "../tmc-langs-util" }
9-
reqwest = { version = "0.10", features = ["blocking", "json"] }
9+
reqwest = { version = "0.10", default-features = false, features = ["blocking", "json", "rustls-tls"] }
1010
thiserror = "1"
1111
serde = { version = "1", features = ["derive"] }
12+
http = "0.2"
13+
http1 = { package = "http", version = "0.1" }
1214
url = "2"
1315
url1 = { package = "url", version = "1" }
1416
log = "0.4"
15-
oauth2 = "2"
17+
oauth2 = { version = "3", default-features = false }
1618
tempfile = "3"
1719
dirs = "2"
1820
regex = "1"

tmc-langs-core/src/error.rs

+23-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ use thiserror::Error;
77
use url::Url;
88

99
pub(crate) type Result<T> = std::result::Result<T, CoreError>;
10+
type TokenError = oauth2::RequestTokenError<
11+
CoreError,
12+
oauth2::StandardErrorResponse<oauth2::basic::BasicErrorResponseType>,
13+
>;
1014

1115
#[derive(Debug, Error)]
1216
pub enum CoreError {
@@ -21,7 +25,7 @@ pub enum CoreError {
2125
#[error("HTTP error for {0}: {1}")]
2226
HttpStatus(Url, StatusCode),
2327
#[error("OAuth2 password exchange error: {0}")]
24-
Token(oauth2::RequestTokenError<oauth2::basic::BasicErrorResponseType>),
28+
Token(Box<TokenError>),
2529
#[error("OAuth2 unexpected token response {1}: {0}")]
2630
TokenParse(serde_json::error::Error, String),
2731
#[error("Already authenticated")]
@@ -31,6 +35,18 @@ pub enum CoreError {
3135
#[error("Failed to find cache directory")]
3236
CacheDir,
3337

38+
#[error(transparent)]
39+
InvalidMethod(#[from] http::method::InvalidMethod),
40+
#[error(transparent)]
41+
InvalidHeaderName(#[from] http::header::InvalidHeaderName),
42+
#[error(transparent)]
43+
InvalidHeaderValue(#[from] http::header::InvalidHeaderValue),
44+
#[error(transparent)]
45+
InvalidStatusCode(#[from] http1::status::InvalidStatusCode),
46+
#[error(transparent)]
47+
InvalidHeaderName1(#[from] http1::header::InvalidHeaderName),
48+
#[error(transparent)]
49+
InvalidHeaderValue1(#[from] http1::header::InvalidHeaderValue),
3450
#[error(transparent)]
3551
TmcLangs(#[from] tmc_langs_util::Error),
3652
#[error(transparent)]
@@ -46,3 +62,9 @@ pub enum CoreError {
4662
#[error(transparent)]
4763
SystemTime(#[from] std::time::SystemTimeError),
4864
}
65+
66+
impl From<TokenError> for CoreError {
67+
fn from(err: TokenError) -> Self {
68+
Self::Token(Box::new(err))
69+
}
70+
}

tmc-langs-core/src/tmc_core.rs

+71-14
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use crate::response::{Course, CourseDetails, Organization};
77
use crate::{Language, RunResult, ValidationResult};
88

99
use oauth2::basic::BasicClient;
10-
use oauth2::prelude::*;
1110
use oauth2::{
1211
AuthUrl, ClientId, ClientSecret, ResourceOwnerPassword, ResourceOwnerUsername, TokenUrl,
1312
};
@@ -18,7 +17,6 @@ use std::path::Path;
1817
use std::path::PathBuf;
1918
use tempfile::NamedTempFile;
2019
use tmc_langs_util::task_executor;
21-
use url1::Url as Url1;
2220

2321
pub type Token =
2422
oauth2::StandardTokenResponse<oauth2::EmptyExtraTokenFields, oauth2::basic::BasicTokenType>;
@@ -42,7 +40,10 @@ impl TmcCore {
4240
///
4341
/// # Examples
4442
/// ```rust,no_run
45-
/// let core = TmcCore::new(Path::new("./config"), "https://tmc.mooc.fi".to_string()).unwrap();
43+
/// use tmc_langs_core::TmcCore;
44+
/// use std::path::PathBuf;
45+
///
46+
/// let core = TmcCore::new(PathBuf::from("./config"), "https://tmc.mooc.fi".to_string()).unwrap();
4647
/// ```
4748
pub fn new(config_dir: PathBuf, root_url: String) -> Result<Self> {
4849
// guarantee a trailing slash, otherwise join will drop the last component
@@ -70,6 +71,8 @@ impl TmcCore {
7071
///
7172
/// # Examples
7273
/// ```rust,no_run
74+
/// use tmc_langs_core::TmcCore;
75+
///
7376
/// let core = TmcCore::new_in_config("https://tmc.mooc.fi".to_string()).unwrap();
7477
/// ```
7578
pub fn new_in_config(root_url: String) -> Result<Self> {
@@ -87,6 +90,8 @@ impl TmcCore {
8790
///
8891
/// # Examples
8992
/// ```rust,no_run
93+
/// use tmc_langs_core::TmcCore;
94+
///
9095
/// let mut core = TmcCore::new_in_config("https://tmc.mooc.fi".to_string()).unwrap();
9196
/// core.authenticate("client", "user".to_string(), "pass".to_string()).unwrap();
9297
/// ```
@@ -96,6 +101,59 @@ impl TmcCore {
96101
email: String,
97102
password: String,
98103
) -> Result<()> {
104+
// required until oauth 4.x.x
105+
fn custom_client<'a>(
106+
client: &'a Client,
107+
) -> impl FnOnce(oauth2::HttpRequest) -> Result<oauth2::HttpResponse> + 'a {
108+
move |req| {
109+
// convert httprequest fields
110+
let method = http::method::Method::from_bytes(req.method.as_str().as_bytes())?;
111+
let mut headers = http::HeaderMap::new();
112+
let mut next_key = None;
113+
for (key, val) in req.headers {
114+
// if key is none, keep using previous next key
115+
if key.is_some() {
116+
// update next key
117+
next_key = key;
118+
}
119+
let header_name = if let Some(name) = next_key.as_ref() {
120+
// use next key
121+
name
122+
} else {
123+
log::error!("invalid header map, found None key first");
124+
continue;
125+
};
126+
let header_name =
127+
http::header::HeaderName::from_bytes(header_name.as_str().as_bytes())?;
128+
let header_value = http::header::HeaderValue::from_bytes(val.as_bytes())?;
129+
headers.insert(header_name, header_value);
130+
}
131+
let res = client
132+
.request(method, req.url)
133+
.headers(headers)
134+
.body(req.body)
135+
.send()?;
136+
137+
// convert response to httpresponse
138+
let status_code = http1::StatusCode::from_bytes(res.status().as_str().as_bytes())?;
139+
let mut headers = http1::HeaderMap::new();
140+
for (key, val) in res.headers() {
141+
let header_name =
142+
http1::header::HeaderName::from_bytes(key.as_str().as_bytes())?;
143+
let header_value = http1::header::HeaderValue::from_bytes(val.as_bytes())?;
144+
headers.insert(header_name, header_value);
145+
}
146+
let body = res.bytes()?.to_vec();
147+
let res = oauth2::HttpResponse {
148+
status_code,
149+
headers,
150+
body,
151+
};
152+
153+
Ok(res)
154+
}
155+
}
156+
99157
if self.token.is_some() {
100158
return Err(CoreError::AlreadyAuthenticated);
101159
}
@@ -105,26 +163,20 @@ impl TmcCore {
105163
.join(&format!("application/{}/credentials", client_name))?;
106164
let credentials: Credentials = self.get_json_from_url(url)?;
107165

108-
let auth_url = Url1::parse(self.auth_url.as_str())?;
109-
log::debug!("authenticating at {}", auth_url);
166+
log::debug!("authenticating at {}", self.auth_url);
110167
let client = BasicClient::new(
111168
ClientId::new(credentials.application_id),
112169
Some(ClientSecret::new(credentials.secret)),
113-
AuthUrl::new(auth_url.clone()), // not used in the Resource Owner Password Credentials Grant
114-
Some(TokenUrl::new(auth_url)),
170+
AuthUrl::new(self.auth_url.as_str().to_string())?, // not used in the Resource Owner Password Credentials Grant
171+
Some(TokenUrl::new(self.auth_url.as_str().to_string())?),
115172
);
116173

117174
let token = client
118175
.exchange_password(
119176
&ResourceOwnerUsername::new(email),
120177
&ResourceOwnerPassword::new(password),
121178
)
122-
.map_err(|e| match e {
123-
oauth2::RequestTokenError::Parse(e, msg) => {
124-
CoreError::TokenParse(e, String::from_utf8_lossy(&msg).into_owned())
125-
}
126-
_ => CoreError::Token(e),
127-
})?;
179+
.request(custom_client(&self.client))?;
128180
self.token = Some(token);
129181
log::debug!("authenticated");
130182
Ok(())
@@ -152,6 +204,9 @@ impl TmcCore {
152204
///
153205
/// # Examples
154206
/// ```rust,no_run
207+
/// use tmc_langs_core::TmcCore;
208+
/// use std::path::Path;
209+
///
155210
/// let core = TmcCore::new_in_config("https://tmc.mooc.fi".to_string()).unwrap();
156211
/// // authenticate
157212
/// core.download_or_update_exercises(vec![
@@ -274,10 +329,12 @@ impl TmcCore {
274329
///
275330
/// # Examples
276331
/// ```rust,no_run
332+
/// use tmc_langs_core::TmcCore;
333+
///
277334
/// let core = TmcCore::new_in_config("https://tmc.mooc.fi".to_string()).unwrap();
278335
/// // authenticate
279336
/// let mut checksums = std::collections::HashMap::new();
280-
/// checksums.insert(1234, "exercisechecksum");
337+
/// checksums.insert(1234, "exercisechecksum".to_string());
281338
/// let update_result = core.get_exercise_updates(600, checksums).unwrap();
282339
/// ```
283340
pub fn get_exercise_updates(

tmc-langs-core/src/tmc_core/api.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::{
99
SubmissionFeedbackResponse, TmcCore, User,
1010
};
1111

12-
use oauth2::{prelude::SecretNewType, TokenResponse};
12+
use oauth2::TokenResponse;
1313
use reqwest::blocking::{multipart::Form, RequestBuilder, Response as ReqwestResponse};
1414
use serde::de::DeserializeOwned;
1515
use serde_json::Value;

0 commit comments

Comments
 (0)