Allow executing program to retrieve credentials
* config / authentication: permit to call external program for getting credentials You can add into your ncspot/config.toml like this: ``` creds_username = "mylogin" creds_passeval = "pass my_pass_path_to_spot_password" ``` Or using any password manager who send your password.to stdout. If a newline is detected it will be automatically removed * Move credential commands into separate structure Also add an option for a username command * Document credential commands --------- Co-authored-by: Henrik Friedrichsen <henrik@affekt.org>
This commit is contained in:
16
README.md
16
README.md
@@ -62,6 +62,7 @@ You **must** have an existing premium Spotify subscription to use `ncspot`.
|
||||
- [Notification Formatting](#notification-formatting)
|
||||
- [Cover Drawing](#cover-drawing)
|
||||
- [Authentication](#authentication)
|
||||
- [Using a password manager](#using-a-password-manager)
|
||||
|
||||
## Resource Footprint Comparison
|
||||
|
||||
@@ -608,3 +609,18 @@ The credentials are stored in `~/.cache/ncspot/librespot/credentials.json`
|
||||
|
||||
The `logout` command can be used to remove cached credentials. See
|
||||
[Vim-Like Commands](#vim-like-commands).
|
||||
|
||||
### Using a password manager
|
||||
|
||||
If you would like ncspot to retrieve your login data from command results,
|
||||
i.e. because you use a password manager like `pass`, you can add the following
|
||||
configuration:
|
||||
|
||||
```toml
|
||||
[credentials]
|
||||
username_cmd = "echo username"
|
||||
password_cmd = "pass spotify.com/username"
|
||||
```
|
||||
|
||||
Do note that this is only required for the initial login or when your credential
|
||||
token has expired.
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::process::Command;
|
||||
|
||||
use cursive::traits::Resizable;
|
||||
use cursive::view::Nameable;
|
||||
use cursive::views::*;
|
||||
@@ -60,6 +62,38 @@ pub fn create_credentials() -> Result<RespotCredentials, String> {
|
||||
.unwrap_or_else(|| Err("Didn't obtain any credentials".to_string()))
|
||||
}
|
||||
|
||||
pub fn credentials_eval(
|
||||
username_cmd: &str,
|
||||
password_cmd: &str,
|
||||
) -> Result<RespotCredentials, String> {
|
||||
fn eval(cmd: &str) -> Result<Vec<u8>, String> {
|
||||
println!("Executing \"{}\"", cmd);
|
||||
let mut result = Command::new("sh")
|
||||
.args(["-c", cmd])
|
||||
.output()
|
||||
.map_err(|e| e.to_string())?
|
||||
.stdout;
|
||||
if let Some(&last_byte) = result.last() {
|
||||
if last_byte == 10 {
|
||||
result.pop();
|
||||
}
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
println!("Retrieving username");
|
||||
let username = String::from_utf8_lossy(&eval(username_cmd)?).into();
|
||||
println!("Retrieving password");
|
||||
let password = eval(password_cmd)?;
|
||||
|
||||
Ok(RespotCredentials {
|
||||
username,
|
||||
auth_type: AuthenticationType::AUTHENTICATION_USER_PASS,
|
||||
auth_data: password,
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct AuthResponse {
|
||||
pub credentials: RespotCredentials,
|
||||
|
||||
@@ -93,6 +93,13 @@ pub struct ConfigValues {
|
||||
pub statusbar_format: Option<String>,
|
||||
pub library_tabs: Option<Vec<LibraryTab>>,
|
||||
pub hide_display_names: Option<bool>,
|
||||
pub credentials: Option<Credentials>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Default, Clone)]
|
||||
pub struct Credentials {
|
||||
pub username_cmd: Option<String>,
|
||||
pub password_cmd: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Default, Clone)]
|
||||
|
||||
12
src/main.rs
12
src/main.rs
@@ -191,7 +191,17 @@ fn main() -> Result<(), String> {
|
||||
info!("Using cached credentials");
|
||||
c
|
||||
}
|
||||
None => credentials_prompt(None)?,
|
||||
None => {
|
||||
info!("Attempting to resolve credentials via username/password commands");
|
||||
let creds = cfg.values().credentials.clone().unwrap_or_default();
|
||||
|
||||
match (creds.username_cmd, creds.password_cmd) {
|
||||
(Some(username_cmd), Some(password_cmd)) => {
|
||||
authentication::credentials_eval(&username_cmd, &password_cmd)?
|
||||
}
|
||||
_ => credentials_prompt(None)?,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user