Basic password changing with prompt.

This commit is contained in:
Vivianne 2023-06-30 17:57:38 -07:00
commit 1ed21658e6
4 changed files with 1502 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
/target
.env

1371
Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

17
Cargo.toml Normal file
View file

@ -0,0 +1,17 @@
[package]
name = "matrix-dendrite-admin"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
text_io = "0.1.12"
dotenvy = "0.15.7"
rustify = "0.5.3"
rustify_derive = "0.5.2"
http = "0.2.9"
derive_builder = "0.12.0"
serde = "1.0.164"
tokio = { version = "1.29.1", features = ["rt-multi-thread", "macros"] }
serde_json = "1.0.99"

112
src/main.rs Normal file
View file

@ -0,0 +1,112 @@
use derive_builder::Builder;
use dotenvy::dotenv;
use http::Request;
use rustify::{errors::ClientError, Client, Endpoint, MiddleWare};
use rustify_derive::Endpoint;
use serde::{Deserialize, Serialize};
use std::env;
use std::io::{stdout, Write};
use std::str;
use text_io::read;
#[derive(Debug, Builder, Default, Endpoint, Serialize)]
#[endpoint(
path = "_dendrite/admin/resetPassword/{self.user_id}",
method = "POST",
response = "ResetPasswordResponse",
builder = "true"
)]
struct ResetPasswordRequest {
#[endpoint(skip)]
pub user_id: String,
pub password: String,
pub logout_devices: bool,
}
#[derive(Debug, Deserialize)]
#[allow(dead_code)]
struct ResetPasswordResponse {
pub password_updated: bool,
}
struct AdminMiddleware {
pub access_token: String,
}
impl AdminMiddleware {
pub fn new(access_token: String) -> Self {
AdminMiddleware { access_token }
}
}
#[derive(Debug, Deserialize)]
#[allow(dead_code)]
struct DendriteError {
pub errcode: String,
pub error: String,
}
impl MiddleWare for AdminMiddleware {
fn request<E: Endpoint>(
&self,
_endpoint: &E,
req: &mut Request<Vec<u8>>,
) -> Result<(), rustify::errors::ClientError> {
req.headers_mut().append(
"Authorization",
http::HeaderValue::from_str(&format!("Bearer {}", self.access_token)).unwrap(),
);
Ok(())
}
fn response<E: Endpoint>(
&self,
_endpoint: &E,
_resp: &mut http::Response<Vec<u8>>,
) -> Result<(), rustify::errors::ClientError> {
Ok(())
}
}
#[tokio::main]
async fn main() {
dotenv().ok();
let token = env::var("ACCESS_TOKEN").expect("ACCESS_TOKEN is a required env setting");
let instance = env::var("INSTANCE_URL").expect("INSTANCE_URL is a required env setting");
let domain = env::var("INSTANCE_DOMAIN").expect("INSTANCE_DOMAIN is a required env setting");
let middleware = AdminMiddleware::new(token);
let client = Client::default(&instance);
print!("Enter local user id for {} account: @", domain);
let _ = stdout().flush();
let username: String = read!("{}\n");
print!("Enter new pass for @{}:{}: ", username, domain);
let _ = stdout().flush();
let pass: String = read!("{}\n");
let endpoint = ResetPasswordRequest::builder()
.user_id(format!("@{}:{}", username, domain))
.password(pass)
.logout_devices(false)
.build()
.unwrap();
match endpoint.with_middleware(&middleware).exec(&client).await {
Ok(result) => {
println!("{:#?}", result.parse().unwrap());
}
Err(ClientError::ServerResponseError { content, .. }) => {
println!(
"{:#?}",
serde_json::from_str::<DendriteError>(&content.unwrap()).unwrap()
);
}
e => {
e.unwrap();
}
}
}