impl auth

This commit is contained in:
sim1222 2024-07-19 16:24:13 +09:00
parent 1e31d74904
commit e47b29da21
Signed by: sim1222
GPG Key ID: D1AE30E316E44E5D
6 changed files with 92 additions and 9 deletions

1
Cargo.lock generated
View File

@ -1668,6 +1668,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"tokio", "tokio",
"url",
] ]
[[package]] [[package]]

View File

@ -17,3 +17,4 @@ reqwest = { version = "0.12.5", features = ["json"] }
serde = { version = "1.0.204", features = ["derive"] } serde = { version = "1.0.204", features = ["derive"] }
serde_json = "1.0.120" serde_json = "1.0.120"
tokio = { version = "1.38.0", features = ["full"] } tokio = { version = "1.38.0", features = ["full"] }
url = "2.5.2"

View File

@ -79,7 +79,9 @@ impl Client {
} }
} }
pub async fn get_upload_token(&self) -> anyhow::Result<types::response::GetFileLinkTokenResponse> { pub async fn get_upload_token(
&self,
) -> anyhow::Result<types::response::GetFileLinkTokenResponse> {
if self.last_refresh.read().await.elapsed().as_secs() > self.token_valid_time.into() { if self.last_refresh.read().await.elapsed().as_secs() > self.token_valid_time.into() {
self.refresh_token().await?; self.refresh_token().await?;
} }
@ -162,12 +164,10 @@ impl Client {
match serde_json::from_str(&text) { match serde_json::from_str(&text) {
std::result::Result::Ok(json) => Ok(json), std::result::Result::Ok(json) => Ok(json),
Err(err) => { Err(err) => match serde_json::from_str::<types::response::SendyError>(&text) {
match serde_json::from_str::<types::response::SendyError>(&text) { std::result::Result::Ok(json) => Err(anyhow::anyhow!("{:?}", json)),
std::result::Result::Ok(json) => Err(anyhow::anyhow!("{:?}", json)), Err(_) => Err(anyhow::Error::new(err).context(text.trim().to_string())),
Err(_) => Err(anyhow::Error::new(err).context(text.trim().to_string())), },
}
}
} }
} }
@ -302,6 +302,39 @@ pub async fn refresh_token(
// .map_err(Into::into) // .map_err(Into::into)
} }
pub async fn rid_token_auth(rid_code: &str) -> anyhow::Result<types::response::RIDTokenResponse> {
let client = reqwest::Client::new();
let request = client
.get(format!("https://www.rakuten-drive.com/api/v1/auth/rd/custom/token?rid_code={}&is_extension=false", rid_code))
.send()
.await?;
let text = request.text().await?;
let json: types::response::RIDTokenResponse = serde_json::from_str(&text)?;
Ok(json)
}
pub async fn get_refresh_token(
token: &str,
) -> anyhow::Result<types::response::VerifyCustomTokenResponse> {
let client = reqwest::Client::new();
let req = types::request::VerifyCustomTokenRequest {
token: token.to_string(),
return_secure_token: true,
};
let request = client
.post("https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyCustomToken?key=AIzaSyDyp5IGr4nXbYin_oduNGi6ci-AnWcuAYE")
.json(&req)
.send()
.await?;
let text = request.text().await?;
let json: types::response::VerifyCustomTokenResponse = serde_json::from_str(&text)?;
Ok(json)
}
// https://www.rakuten-drive.com/api/account/refreshtoken POST RefreshTokenRequest RefreshTokenResponse // https://www.rakuten-drive.com/api/account/refreshtoken POST RefreshTokenRequest RefreshTokenResponse
// https://forest.sendy.jp/cloud/service/file/v1/file POST FileDetailRequest FileDetailResponse // https://forest.sendy.jp/cloud/service/file/v1/file POST FileDetailRequest FileDetailResponse
// https://forest.sendy.jp/cloud/service/file/v1/files POST ListFilesRequest ListFilesResponse // https://forest.sendy.jp/cloud/service/file/v1/files POST ListFilesRequest ListFilesResponse

View File

@ -106,6 +106,7 @@ enum Commands {
}, },
#[clap(about = "Print file detail")] #[clap(about = "Print file detail")]
Info { path: String }, Info { path: String },
Auth {},
} }
#[tokio::main] #[tokio::main]
@ -140,8 +141,8 @@ async fn main() -> anyhow::Result<()> {
Commands::Mkdir { name, path } => { Commands::Mkdir { name, path } => {
client.mkdir(name, path.as_deref()).await.unwrap(); client.mkdir(name, path.as_deref()).await.unwrap();
} }
Commands::Copy { src: _, dest: _ } => { Commands::Copy { src, dest } => {
todo!("Copy"); client.copy(src, dest).await.unwrap();
} }
Commands::Rename { path, name } => { Commands::Rename { path, name } => {
client.rename(path, name).await.unwrap(); client.rename(path, name).await.unwrap();
@ -149,6 +150,29 @@ async fn main() -> anyhow::Result<()> {
Commands::Info { path } => { Commands::Info { path } => {
client.info(path).await.unwrap(); client.info(path).await.unwrap();
} }
Commands::Auth {} => {
println!("Click the link below to authorize the app:\n");
let link = "https://login.account.rakuten.com/sso/authorize?response_type=code&client_id=rakuten_drive_web&redirect_uri=https://www.rakuten-drive.com/oauth-callback&scope=openid+profile+email&prompt=login&ui_locales=en";
println!("{}\n", link);
println!("Paste the URL you were redirected to:");
let mut auth_url = String::new();
std::io::stdin().read_line(&mut auth_url).unwrap();
let auth_url = url::Url::parse(auth_url.trim())?;
let params = auth_url.query_pairs().collect::<Vec<_>>();
let rid_code = params
.iter()
.find(|(key, _)| key == "code")
.map(|(_, value)| value.to_string())
.ok_or_else(|| anyhow::anyhow!("Code not found in URL"))?;
let rid_token_auth_res = client::rid_token_auth(rid_code.as_str()).await?;
let token_verify_res = client::get_refresh_token(&rid_token_auth_res.custom_token).await?;
println!("Refresh token: {}", token_verify_res.refresh_token);
}
} }
Ok(()) Ok(())

View File

@ -152,3 +152,10 @@ pub struct CopyFileRequestFile {
pub size: i64, pub size: i64,
pub version_id: String, pub version_id: String,
} }
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct VerifyCustomTokenRequest {
pub return_secure_token: bool,
pub token: String,
}

View File

@ -176,3 +176,20 @@ pub enum SendyErrorType {
SendyErrShareUpwardShareExist, SendyErrShareUpwardShareExist,
SendyErrShareFolderIncludedOrInclude, SendyErrShareFolderIncludedOrInclude,
} }
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct RIDTokenResponse {
pub custom_token: String,
pub is_new_user: String, // "false"
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct VerifyCustomTokenResponse {
pub kind: String,
pub id_token: String,
pub refresh_token: String,
pub expires_in: String,
pub is_new_user: bool,
}