Skip to content

Commit

Permalink
Merge pull request #281 from funkeleinhorn/passwords-from-files
Browse files Browse the repository at this point in the history
Make passwords readable from file
  • Loading branch information
casperstorm authored Mar 29, 2024
2 parents 930293c + 1aa1db7 commit 4c33d59
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 7 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Added:

- Configuration to adjust WHO polling for servers without away-notify (see [server configuration](https://halloy.squidowl.org/configuration/servers.html))
- Display current version, and latest remote version in command bar
- Allow reading passwords from files in server configuration.

Fixed:

Expand Down
11 changes: 7 additions & 4 deletions book/src/configuration/servers.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ channels = ["#halloy"]
| :--------------------------------- | :-------------------------------------------------------------------------------------------------- | :---------- |
| `nickname` | The client's nickname. | `""` |
| `nick_password` | The client's NICKSERV password. | `""` |
| `nick_password_file` | Alternatively read `nick_password` from the file at the given path. | `""` |
| `alt_nicks` | Alternative nicknames for the client, if the default is taken. | `[""]` |
| `username` | The client's username. | `""` |
| `realname` | The client's real name. | `""` |
| `server` | The server to connect to. | `""` |
| `port` | The port to connect on. | `6697` |
| `password` | The password to connect to the server. | `""` |
| `password_file` | Alternatively read `password` from the file at the given path. | `""` |
| `channels` | A list of channels to join on connection. | `[""]` |
| `channel_keys` | A mapping of channel names to keys for join-on-connect. | `{}` |
| `ping_time` | The amount of inactivity in seconds before the client will ping the server. | `180` |
Expand Down Expand Up @@ -48,10 +50,11 @@ username = "<string>"
password = "<string>"
```

| Key | Description | Default |
| :--------- | :---------------------------------------------------------------- | :------ |
| `username` | The account name used for authentication. | `""` |
| `password` | The password associated with the account used for authentication. | `""` |
| Key | Description | Default |
| :---------------| :---------------------------------------------------------------- | :------ |
| `username` | The account name used for authentication. | `""` |
| `password` | The password associated with the account used for authentication. | `""` |
| `password_file` | Alternatively read `password` from the file at the given path. | `""` |


### `[sasl.external]`
Expand Down
4 changes: 3 additions & 1 deletion data/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ impl Config {

let Configuration {
theme,
servers,
mut servers,
font,
scale_factor,
buffer,
Expand All @@ -141,6 +141,8 @@ impl Config {
notifications,
} = toml::from_str(content.as_ref()).map_err(|e| Error::Parse(e.to_string()))?;

servers.read_password_files()?;

let themes = Self::load_themes(&theme).unwrap_or_default();

Ok(Config {
Expand Down
13 changes: 11 additions & 2 deletions data/src/config/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ pub struct Server {
pub nickname: String,
/// The client's NICKSERV password.
pub nick_password: Option<String>,
/// The client's NICKSERV password file.
pub nick_password_file: Option<String>,
/// Alternative nicknames for the client, if the default is taken.
#[serde(default)]
pub alt_nicks: Vec<String>,
Expand All @@ -25,6 +27,8 @@ pub struct Server {
pub port: u16,
/// The password to connect to the server.
pub password: Option<String>,
/// The file with the password to connect to the server.
pub password_file: Option<String>,
/// A list of channels to join on connection.
#[serde(default)]
pub channels: Vec<String>,
Expand Down Expand Up @@ -108,7 +112,9 @@ pub enum Sasl {
/// Account name
username: String,
/// Account password,
password: String,
password: Option<String>,
/// Account password file
password_file: Option<String>
},
External {
/// The path to PEM encoded X509 user certificate for external auth
Expand All @@ -128,8 +134,11 @@ impl Sasl {

pub fn param(&self) -> String {
match self {
Sasl::Plain { username, password } => {
Sasl::Plain { username, password, .. } => {
use base64::engine::Engine;

let password = password.as_ref().expect("SASL password must exist at this point!");

base64::engine::general_purpose::STANDARD
.encode(format!("{username}\x00{username}\x00{password}"))
}
Expand Down
35 changes: 35 additions & 0 deletions data/src/server.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use std::collections::BTreeMap;
use std::fmt;
use std::fs;

use serde::{Deserialize, Serialize};

use crate::config;
use crate::config::Error;
use crate::config::server::Sasl;

#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Server(String);
Expand Down Expand Up @@ -46,4 +49,36 @@ impl Map {
pub fn entries(&self) -> impl Iterator<Item = Entry> + '_ {
self.0.iter().map(Entry::from)
}

pub fn read_password_files(&mut self) -> Result<(), Error> {
for (_, config) in self.0.iter_mut() {
if let Some(pass_file) = &config.password_file {
if config.password.is_some() {
return Err(Error::Parse("Only one of password and password_file can be set.".to_string()));
}
let pass = fs::read_to_string(pass_file)?;
config.password = Some(pass);
}
if let Some(nick_pass_file) = &config.nick_password_file {
if config.nick_password.is_some() {
return Err(Error::Parse("Only one of nick_password and nick_password_file can be set.".to_string()));
}
let nick_pass = fs::read_to_string(nick_pass_file)?;
config.nick_password = Some(nick_pass);
}
if let Some(sasl) = &mut config.sasl {
match sasl {
Sasl::Plain { password: password @ None, password_file: Some(pass_file), .. } => {
let pass = fs::read_to_string(pass_file)?;
*password = Some(pass);
},
Sasl::Plain { password: Some(_), password_file: None, .. } => {},
_ => {
return Err(Error::Parse("Exactly one of sasl.plain.password or sasl.plain.password_file must be set.".to_string()));
}
}
}
}
Ok(())
}
}

0 comments on commit 4c33d59

Please sign in to comment.