Save and use authentication token
This commit is contained in:
		
							parent
							
								
									3054e724fd
								
							
						
					
					
						commit
						a9c1d6ed01
					
				
					 4 changed files with 147 additions and 22 deletions
				
			
		|  | @ -7,6 +7,11 @@ edition = "2018" | |||
| # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||||
| 
 | ||||
| [dependencies] | ||||
| anyhow = "1.0" | ||||
| dirs-next = "2.0" | ||||
| iced = { git = "https://github.com/hecrj/iced", rev = "fc4270f", features = ["debug", "tokio"] } | ||||
| hostname = "0.3" | ||||
| matrix-sdk = { git = "https://github.com/matrix-org/matrix-rust-sdk", rev = "27c6f30" } | ||||
| tokio = { version = "0.2", features = ["macros"] } | ||||
| serde = { version = "1.0", features = ["derive"] } | ||||
| tokio = "0.2" | ||||
| toml = "0.5" | ||||
|  |  | |||
							
								
								
									
										17
									
								
								src/main.rs
									
										
									
									
									
								
							
							
						
						
									
										17
									
								
								src/main.rs
									
										
									
									
									
								
							|  | @ -1,9 +1,22 @@ | |||
| extern crate dirs_next as dirs; | ||||
| 
 | ||||
| use std::fs::Permissions; | ||||
| use std::os::unix::fs::PermissionsExt; | ||||
| 
 | ||||
| use iced::Application; | ||||
| 
 | ||||
| pub mod matrix; | ||||
| pub mod ui; | ||||
| 
 | ||||
| #[tokio::main] | ||||
| async fn main() { | ||||
| fn main() -> Result<(), Box<dyn std::error::Error>> { | ||||
|     let config_dir = dirs::config_dir().unwrap().join("retrix"); | ||||
|     // Make sure config dir exists and is not accessible by other users.
 | ||||
|     if !config_dir.is_dir() { | ||||
|         std::fs::create_dir(&config_dir)?; | ||||
|         std::fs::set_permissions(&config_dir, Permissions::from_mode(0o700))?; | ||||
|     } | ||||
| 
 | ||||
|     ui::Retrix::run(iced::Settings::default()); | ||||
| 
 | ||||
|     Ok(()) | ||||
| } | ||||
|  |  | |||
|  | @ -1,6 +1,38 @@ | |||
| use matrix_sdk::{reqwest::Url, Client, Session, SyncSettings}; | ||||
| use matrix_sdk::{ | ||||
|     identifiers::DeviceId, identifiers::UserId, reqwest::Url, Client, ClientConfig, Session, | ||||
|     SyncSettings, | ||||
| }; | ||||
| use serde::{Deserialize, Serialize}; | ||||
| 
 | ||||
| pub type Error = Box<dyn std::error::Error>; | ||||
| pub type Error = anyhow::Error; | ||||
| 
 | ||||
| // Needed to be able to serialize `Session`s. Should be done with serde remote.
 | ||||
| #[derive(Debug, Clone, Deserialize, Serialize)] | ||||
| pub struct SessionWrapper { | ||||
|     access_token: String, | ||||
|     user_id: UserId, | ||||
|     device_id: Box<DeviceId>, | ||||
| } | ||||
| 
 | ||||
| impl From<SessionWrapper> for Session { | ||||
|     fn from(s: SessionWrapper) -> Self { | ||||
|         Self { | ||||
|             access_token: s.access_token, | ||||
|             user_id: s.user_id, | ||||
|             device_id: s.device_id, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl From<Session> for SessionWrapper { | ||||
|     fn from(s: Session) -> Self { | ||||
|         Self { | ||||
|             access_token: s.access_token, | ||||
|             user_id: s.user_id, | ||||
|             device_id: s.device_id, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub async fn login( | ||||
|     username: &str, | ||||
|  | @ -8,17 +40,57 @@ pub async fn login( | |||
|     server: &str, | ||||
| ) -> Result<(Client, Session), Error> { | ||||
|     let url = Url::parse(server)?; | ||||
|     let client = Client::new(url)?; | ||||
|     let config = ClientConfig::new().store_path(&dirs::config_dir().unwrap().join("retrix")); | ||||
|     let client = Client::new_with_config(url, config)?; | ||||
| 
 | ||||
|     let response = client | ||||
|         .login(username, password, None, Some("retrix")) | ||||
|         .await?; | ||||
|     let session = Session { | ||||
|         access_token: response.access_token, | ||||
|         user_id: response.user_id, | ||||
|         device_id: response.device_id, | ||||
|     let session = match get_session()? { | ||||
|         Some(session) => { | ||||
|             client.restore_login(session.clone()).await?; | ||||
|             session | ||||
|         } | ||||
|         None => { | ||||
|             let response = client | ||||
|                 .login(username, password, None, Some("retrix")) | ||||
|                 .await?; | ||||
|             let session = Session { | ||||
|                 access_token: response.access_token, | ||||
|                 user_id: response.user_id, | ||||
|                 device_id: response.device_id, | ||||
|             }; | ||||
|             write_session(session.clone())?; | ||||
|             session | ||||
|         } | ||||
|     }; | ||||
|     client.sync(SyncSettings::new()).await; | ||||
|     client.sync_once(SyncSettings::new()).await?; | ||||
| 
 | ||||
|     Ok((client, session)) | ||||
| } | ||||
| 
 | ||||
| /// File path to store session data in
 | ||||
| fn session_path() -> std::path::PathBuf { | ||||
|     dirs::config_dir() | ||||
|         .unwrap() | ||||
|         .join("retrix") | ||||
|         .join("session.toml") | ||||
| } | ||||
| 
 | ||||
| /// Read session data from config file
 | ||||
| fn get_session() -> Result<Option<Session>, Error> { | ||||
|     let path = session_path(); | ||||
|     if !path.is_file() { | ||||
|         return Ok(None); | ||||
|     } | ||||
|     let session: SessionWrapper = toml::from_slice(&std::fs::read(path)?)?; | ||||
|     Ok(Some(session.into())) | ||||
| } | ||||
| 
 | ||||
| /// Save session data to config file
 | ||||
| fn write_session(session: Session) -> Result<(), Error> { | ||||
|     let session: SessionWrapper = session.into(); | ||||
|     let path = session_path(); | ||||
| 
 | ||||
|     let serialized = toml::to_string(&session)?; | ||||
|     std::fs::write(path, serialized)?; | ||||
| 
 | ||||
|     Ok(()) | ||||
| } | ||||
|  |  | |||
							
								
								
									
										51
									
								
								src/ui.rs
									
										
									
									
									
								
							
							
						
						
									
										51
									
								
								src/ui.rs
									
										
									
									
									
								
							|  | @ -1,6 +1,6 @@ | |||
| use iced::{ | ||||
|     text_input::{self, TextInput}, | ||||
|     Application, Button, Column, Command, Container, Element, Text, | ||||
|     Application, Button, Column, Command, Container, Element, Length, Row, Text, | ||||
| }; | ||||
| 
 | ||||
| use crate::matrix; | ||||
|  | @ -21,17 +21,23 @@ pub enum Retrix { | |||
|     LoggedIn { | ||||
|         client: matrix_sdk::Client, | ||||
|         session: matrix_sdk::Session, | ||||
| 
 | ||||
|         rooms: Vec<matrix_sdk::Room>, | ||||
|     }, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub enum Message { | ||||
|     // Login form messages
 | ||||
|     SetUser(String), | ||||
|     SetPassword(String), | ||||
|     SetServer(String), | ||||
|     Login, | ||||
|     LoggedIn(matrix_sdk::Client, matrix_sdk::Session), | ||||
|     SetError(String), | ||||
| 
 | ||||
|     // Main state messages
 | ||||
|     ResetRooms(Vec<matrix_sdk::Room>), | ||||
| } | ||||
| 
 | ||||
| impl Application for Retrix { | ||||
|  | @ -83,10 +89,32 @@ impl Application for Retrix { | |||
|                         }, | ||||
|                     ); | ||||
|                 } | ||||
|                 Message::LoggedIn(client, session) => *self = Retrix::LoggedIn { client, session }, | ||||
|                 Message::LoggedIn(client, session) => { | ||||
|                     *self = Retrix::LoggedIn { | ||||
|                         client: client.clone(), | ||||
|                         session, | ||||
|                         rooms: Vec::new(), | ||||
|                     }; | ||||
|                     let client = client.clone(); | ||||
|                     Command::perform( | ||||
|                         async move { | ||||
|                             let mut list = Vec::new(); | ||||
|                             for (id, room) in client.joined_rooms().read().await.iter() { | ||||
|                                 let room = room.read().await; | ||||
|                                 list.push(room.clone()); | ||||
|                             } | ||||
|                             list | ||||
|                         }, | ||||
|                         |rooms| Message::ResetRooms(rooms), | ||||
|                     ); | ||||
|                 } | ||||
|                 _ => (), | ||||
|             }, | ||||
|             _ => (), | ||||
|         } | ||||
|             Retrix::LoggedIn { ref mut rooms, .. } => match message { | ||||
|                 Message::ResetRooms(r) => *rooms = r, | ||||
|                 _ => (), | ||||
|             }, | ||||
|         }; | ||||
|         Command::none() | ||||
|     } | ||||
| 
 | ||||
|  | @ -102,6 +130,7 @@ impl Application for Retrix { | |||
|                 ref server, | ||||
|                 ref error, | ||||
|             } => { | ||||
|                 // Login form
 | ||||
|                 let mut content = Column::new() | ||||
|                     .width(500.into()) | ||||
|                     .push(Text::new("Username")) | ||||
|  | @ -136,10 +165,16 @@ impl Application for Retrix { | |||
|                     .height(iced::Length::Fill) | ||||
|                     .into() | ||||
|             } | ||||
|             Retrix::LoggedIn { | ||||
|                 ref client, | ||||
|                 ref session, | ||||
|             } => Text::new(format!("Logged in to {}", session.user_id)).into(), | ||||
|             Retrix::LoggedIn { ref rooms, .. } => { | ||||
|                 //let mut root_row = Row::new().width(Length::Fill).height(Length::Fill);
 | ||||
|                 let mut room_col = Column::new().width(400.into()).height(Length::Fill); | ||||
|                 for room in rooms { | ||||
|                     room_col = room_col.push(Text::new(room.display_name())); | ||||
|                 } | ||||
|                 room_col.into() | ||||
|                 //root_row = root_row.push(room_col);
 | ||||
|                 //root_row.into()
 | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue