Can set Matrix access token

This commit is contained in:
2025-01-23 21:28:33 +01:00
parent 78700d0be5
commit bfbc2a690b
9 changed files with 206 additions and 10 deletions

View File

@ -1,9 +1,135 @@
use crate::app_config::AppConfig;
use crate::utils::curr_time;
use s3::error::S3Error;
use s3::request::ResponseData;
use s3::{Bucket, BucketConfiguration};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum UserError {
#[error("failed to fetch user configuration: {0}")]
FetchUserConfig(S3Error),
}
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
pub struct UserID(pub String);
impl UserID {
fn conf_path_in_bucket(&self) -> String {
format!("confs/{}.json", urlencoding::encode(&self.0))
}
}
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
pub struct User {
pub id: UserID,
pub name: String,
pub email: String,
}
#[derive(serde::Serialize, serde::Deserialize)]
pub struct UserConfig {
/// Target user ID
pub user_id: UserID,
/// Configuration creation time
pub created: u64,
/// Configuration last update time
pub updated: u64,
/// Current user matrix token
pub matrix_token: String,
}
impl UserConfig {
/// Create S3 bucket if required
pub async fn create_bucket_if_required() -> anyhow::Result<()> {
if AppConfig::get().s3_skip_auto_create_bucket {
log::debug!("Skipping bucket existence check");
return Ok(());
}
let bucket = AppConfig::get().s3_bucket()?;
match bucket.location().await {
Ok(_) => {
log::debug!("The bucket already exists.");
return Ok(());
}
Err(S3Error::HttpFailWithBody(404, s)) if s.contains("<Code>NoSuchKey</Code>") => {
log::warn!("Failed to fetch bucket location, but it seems that bucket exists.");
return Ok(());
}
Err(S3Error::HttpFailWithBody(404, s)) if s.contains("<Code>NoSuchBucket</Code>") => {
log::warn!("The bucket does not seem to exists, trying to create it!")
}
Err(e) => {
log::error!("Got unexpected error when querying bucket info: {}", e);
return Err(e.into());
}
}
Bucket::create_with_path_style(
&bucket.name,
bucket.region,
AppConfig::get().s3_credentials()?,
BucketConfiguration::private(),
)
.await?;
Ok(())
}
/// Get current user configuration
pub async fn load(user_id: &UserID) -> anyhow::Result<Self> {
let res: Result<ResponseData, S3Error> = AppConfig::get()
.s3_bucket()?
.get_object(user_id.conf_path_in_bucket())
.await;
match res {
Ok(res) => Ok(serde_json::from_slice(res.as_slice())?),
Err(S3Error::HttpFailWithBody(404, _)) => {
log::warn!("User configuration does not exists, generating a new one...");
Ok(Self {
user_id: user_id.clone(),
created: curr_time()?,
updated: curr_time()?,
matrix_token: "".to_string(),
})
}
Err(e) => Err(UserError::FetchUserConfig(e).into()),
}
}
/// Set user configuration
pub async fn save(&mut self) -> anyhow::Result<()> {
log::info!("Saving new configuration for user {:?}", self.user_id);
self.updated = curr_time()?;
// Save updated configuration
AppConfig::get()
.s3_bucket()?
.put_object(
self.user_id.conf_path_in_bucket(),
&serde_json::to_vec(self)?,
)
.await?;
Ok(())
}
/// Get current user matrix token, in an obfuscated form
pub fn obfuscated_matrix_token(&self) -> String {
self.matrix_token
.chars()
.enumerate()
.map(|(num, c)| match num {
0 | 1 => c,
_ => 'X',
})
.collect()
}
}