feat: make authfile reloading a command

This commit is contained in:
Himadri Bhattacharjee
2025-05-02 19:09:43 +05:30
parent 510ffd3fb6
commit 23d6bb6ab1
2 changed files with 23 additions and 34 deletions

View File

@@ -37,7 +37,6 @@ Here, the private key file is named `op`.
### Roadmap
- [x] SSH authentication and authorization
- [x] Ability for admins to reload Authfile with `Ctrl` `r`
- [x] Emacs-like shortcuts for textarea
- [x] multiline support with `Alt` `Return`
- [x] Adjustable parameters:
@@ -45,6 +44,7 @@ Here, the private key file is named `op`.
- [x] Authfile path
- [x] Listening port number
- [x] `/add` command to add new keys
- [x] `/reload` command to reload the Authfile
- [x] `/rename` command
- [x] `/commit` command to commit in-memory changes to Authfile
- [ ] `#mention` tags

View File

@@ -163,13 +163,6 @@ impl AppServer {
Ok(())
}
async fn check_role_and_reload(&mut self) -> Result<(), Error> {
if self.entity().await.role().await != entity::Role::Admin {
return Err(Error::NotAnAdmin(self.entity().await.name().await));
}
self.reload().await
}
async fn reload(&mut self) -> Result<(), Error> {
let new_keychain = authfile::read(Path::new(&self.args.authfile)).await?;
@@ -265,7 +258,7 @@ impl AppServer {
});
}
async fn run_command(&self, command: Command) -> Result<(), Error> {
async fn run_command(&mut self, command: Command) -> Result<(), Error> {
match command {
Command::Add(entity) => {
log::debug!("attempting to add {:#?}", entity);
@@ -415,6 +408,7 @@ fingerprint: {}
clients.remove(&id);
}
}
Command::Reload => self.reload().await?,
}
Ok(())
}
@@ -629,10 +623,6 @@ impl Handler for AppServer {
};
match ratatui::termion::event::parse_event(first, &mut iterator) {
// Press `Ctrl-r` to reload the authorization file
Ok(Event::Key(Key::Ctrl('r'))) => {
self.check_role_and_reload().await?;
}
Ok(keycode) => {
let mut clients = self.clients.write().await;
let Some(client) = clients.get_mut(&self.id) else {
@@ -758,34 +748,33 @@ pub enum Command {
Commit,
Info(lookup::EntityLookup),
Ban(lookup::EntityLookup),
Reload,
}
impl Command {
fn parse(text: &str, role: entity::Role, name: String) -> Result<Option<Self>, Error> {
if text == "/commit" {
return Ok(Some(Self::Commit));
}
let split = text.split_once(char::is_whitespace);
let split: Vec<&str> = text.split(char::is_whitespace).collect();
let is_admin = role == entity::Role::Admin;
if !is_admin && matches!(split, Some(("/add" | "/rename" | "/ban", _))) {
return Err(Error::NotAnAdmin(name));
}
Ok(Some(match split {
Some(("/add", payload)) => Self::Add(payload.parse()?),
Some(("/rename", payload)) => {
let split_payload: Vec<&str> = payload.split_whitespace().collect();
match split_payload.as_slice() {
[from, to] => Self::Rename {
to: to.to_string(),
from: from.to_string(),
},
_ => return Err(Error::CommandParse(text.to_string())),
}
Ok(Some(match &split[..] {
["/info", payload] => Self::Info(payload.parse()?),
["/add" | "/rename" | "/ban" | "/commit" | "/reload", ..] if !is_admin => {
return Err(Error::NotAnAdmin(name));
}
["/add", payload] => Self::Add(payload.parse()?),
["/ban", payload] => Self::Ban(payload.parse()?),
["/commit"] => Self::Commit,
["/reload"] => Self::Reload,
["/rename", from, to] => Self::Rename {
to: to.to_string(),
from: from.to_string(),
},
[
"/info" | "/add" | "/rename" | "/ban" | "/commit" | "/reload",
..,
] => {
return Err(Error::CommandParse(text.to_string()));
}
Some(("/info", payload)) => Self::Info(payload.parse()?),
Some(("/ban", payload)) => Self::Ban(payload.parse()?),
_ => return Ok(None),
}))
}