mirror of
https://github.com/shadowsocks/shadowsocks-rust.git
synced 2026-02-09 01:59:16 +08:00
Reading password from environment variable or TTY
- servers creating from command line options would use TTY,
SS_SERVER_PASSWORD and SS_SERVER_${SERVER_ADDR}_PASSWORD environment
variables
- servers in configuration file "password" would allow ${VAR_NAME} to
read from environment variable VAR_NAME
fixes #419
This commit is contained in:
11
Cargo.lock
generated
11
Cargo.lock
generated
@@ -1381,6 +1381,16 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rpassword"
|
||||
version = "5.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffc936cf8a7ea60c58f030fd36a612a48f440610214dc54bc36431f9ea0c3efb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rpmalloc"
|
||||
version = "0.2.2"
|
||||
@@ -1673,6 +1683,7 @@ dependencies = [
|
||||
"log4rs",
|
||||
"mimalloc",
|
||||
"qrcode",
|
||||
"rpassword",
|
||||
"rpmalloc",
|
||||
"shadowsocks-service",
|
||||
"snmalloc-rs",
|
||||
|
||||
@@ -130,6 +130,7 @@ exitcode = "1"
|
||||
build-time = "0.1"
|
||||
directories = "4.0"
|
||||
xdg = "2.4"
|
||||
rpassword = "5.0.1"
|
||||
|
||||
futures = "0.3"
|
||||
tokio = { version = "1", features = ["rt", "signal"] }
|
||||
|
||||
10
README.md
10
README.md
@@ -522,6 +522,14 @@ Example configuration:
|
||||
// The higher weight, the server may rank higher.
|
||||
"tcp_weight": 1.0,
|
||||
"udp_weight": 1.0,
|
||||
},
|
||||
{
|
||||
// Same key as basic format "server" and "server_port"
|
||||
"server": "0.0.0.0",
|
||||
"server_port": 8388,
|
||||
"method": "chacha20-ietf-poly1305",
|
||||
// Read the actual password from environment variable PASSWORD_FROM_ENV
|
||||
"password": "${PASSWORD_FROM_ENV}"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -583,6 +591,8 @@ Example configuration:
|
||||
|
||||
- `SS_LOG_VERBOSE_LEVEL`: Logging level for binaries (`sslocal`, `ssserver` and `ssmanager`). It is valid only when command line argument `-v` is not applied. Example: `SS_LOG_VERBOSE_LEVEL=1`
|
||||
- `SS_LOG_WITHOUT_TIME`: Logging format for binaries (`sslocal`, `ssserver` and `ssmanager`). It is valid only when command line argument `--log-without-time` is not applied. Example `SS_LOG_WITHOUT_TIME=1`
|
||||
- `SS_SERVER_PASSWORD`: A default password for servers that created from command line argument (`--server-addr`)
|
||||
- `SS_SERVER_${SERVER_ADDR}_PASSWORD`: A default password for server with address `$SERVER_ADDR` that created from command line argument (`--server-addr`)
|
||||
|
||||
## Supported Ciphers
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//! Common configuration utilities
|
||||
|
||||
use directories::ProjectDirs;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
//! Shadowsocks service command line utilities
|
||||
|
||||
pub mod allocator;
|
||||
pub mod config;
|
||||
#[cfg(unix)]
|
||||
pub mod daemonize;
|
||||
#[cfg(feature = "logging")]
|
||||
pub mod logging;
|
||||
pub mod monitor;
|
||||
pub mod password;
|
||||
pub mod validator;
|
||||
pub mod config;
|
||||
|
||||
pub const EXIT_CODE_SERVER_EXIT_UNEXPECTEDLY: i32 = exitcode::SOFTWARE;
|
||||
pub const EXIT_CODE_SERVER_ABORTED: i32 = exitcode::SOFTWARE;
|
||||
|
||||
33
bin/common/password.rs
Normal file
33
bin/common/password.rs
Normal file
@@ -0,0 +1,33 @@
|
||||
//! Common password utilities
|
||||
|
||||
use std::{env, io};
|
||||
|
||||
use log::debug;
|
||||
|
||||
/// Read server's password from environment variable or TTY
|
||||
pub fn read_server_password(server_name: &str) -> io::Result<String> {
|
||||
// specific SS_SERVER_${server_name}_PASSWORD
|
||||
let key = format!("SS_SERVER_{}_PASSWORD", server_name);
|
||||
if let Ok(pwd) = env::var(&key) {
|
||||
debug!("got server {} password from environment variable {}", server_name, key);
|
||||
return Ok(pwd);
|
||||
}
|
||||
|
||||
// common SS_SERVER_PASSWORD
|
||||
if let Ok(pwd) = env::var("SS_SERVER_PASSWORD") {
|
||||
debug!(
|
||||
"got server {} password from environment variable SS_SERVER_PASSWORD",
|
||||
server_name
|
||||
);
|
||||
return Ok(pwd);
|
||||
}
|
||||
|
||||
// read from TTY
|
||||
let tty_prompt = format!("({}) Password: ", server_name);
|
||||
if let Ok(pwd) = rpassword::read_password_from_tty(Some(&tty_prompt)) {
|
||||
debug!("got server {} password from tty prompt", server_name);
|
||||
return Ok(pwd);
|
||||
}
|
||||
|
||||
Err(io::Error::new(io::ErrorKind::Other, "no server password found"))
|
||||
}
|
||||
@@ -227,7 +227,19 @@ fn main() {
|
||||
};
|
||||
|
||||
if let Some(svr_addr) = matches.value_of("SERVER_ADDR") {
|
||||
let password = matches.value_of("PASSWORD").expect("password");
|
||||
let password = match matches.value_of("PASSWORD") {
|
||||
Some(pwd) => pwd.to_owned(),
|
||||
None => {
|
||||
// NOTE: svr_addr should have been checked by common::validator
|
||||
match common::password::read_server_password(svr_addr) {
|
||||
Ok(pwd) => pwd,
|
||||
Err(..) => {
|
||||
panic!("missing server's password");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let method = matches
|
||||
.value_of("ENCRYPT_METHOD")
|
||||
.expect("encrypt-method")
|
||||
@@ -240,7 +252,7 @@ fn main() {
|
||||
.map(|t| t.parse::<u64>().expect("timeout"))
|
||||
.map(Duration::from_secs);
|
||||
|
||||
let mut sc = ServerConfig::new(svr_addr, password.to_owned(), method);
|
||||
let mut sc = ServerConfig::new(svr_addr, password, method);
|
||||
if let Some(timeout) = timeout {
|
||||
sc.set_timeout(timeout);
|
||||
}
|
||||
|
||||
@@ -151,7 +151,19 @@ fn main() {
|
||||
};
|
||||
|
||||
if let Some(svr_addr) = matches.value_of("SERVER_ADDR") {
|
||||
let password = matches.value_of("PASSWORD").expect("password");
|
||||
let password = match matches.value_of("PASSWORD") {
|
||||
Some(pwd) => pwd.to_owned(),
|
||||
None => {
|
||||
// NOTE: svr_addr should have been checked by common::validator
|
||||
match common::password::read_server_password(svr_addr) {
|
||||
Ok(pwd) => pwd,
|
||||
Err(..) => {
|
||||
panic!("missing server's password");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let method = matches
|
||||
.value_of("ENCRYPT_METHOD")
|
||||
.expect("encrypt-method")
|
||||
|
||||
@@ -42,8 +42,10 @@
|
||||
//! These defined server will be used with a load balancing algorithm.
|
||||
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
convert::{From, Infallible},
|
||||
default::Default,
|
||||
env,
|
||||
fmt::{self, Debug, Display, Formatter},
|
||||
fs::OpenOptions,
|
||||
io::Read,
|
||||
@@ -58,6 +60,7 @@ use std::{
|
||||
use cfg_if::cfg_if;
|
||||
#[cfg(feature = "local-tun")]
|
||||
use ipnet::IpNet;
|
||||
use log::warn;
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(any(feature = "local-tunnel", feature = "local-dns"))]
|
||||
use shadowsocks::relay::socks5::Address;
|
||||
@@ -1392,7 +1395,10 @@ impl Config {
|
||||
}
|
||||
};
|
||||
|
||||
let mut nsvr = ServerConfig::new(addr, pwd, method);
|
||||
// Only "password" support getting from environment variable.
|
||||
let password = get_variable_field_value(&pwd);
|
||||
|
||||
let mut nsvr = ServerConfig::new(addr, password, method);
|
||||
nsvr.set_mode(global_mode);
|
||||
|
||||
if let Some(ref p) = config.plugin {
|
||||
@@ -1459,7 +1465,10 @@ impl Config {
|
||||
}
|
||||
};
|
||||
|
||||
let mut nsvr = ServerConfig::new(addr, svr.password, method);
|
||||
// Only "password" support getting from environment variable.
|
||||
let password = get_variable_field_value(&svr.password);
|
||||
|
||||
let mut nsvr = ServerConfig::new(addr, password, method);
|
||||
|
||||
match svr.mode {
|
||||
Some(mode) => match mode.parse::<Mode>() {
|
||||
@@ -2216,3 +2225,24 @@ impl fmt::Display for Config {
|
||||
write!(f, "{}", json5::to_string(&jconf).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
fn get_variable_field_value(value: &str) -> Cow<'_, str> {
|
||||
if let Some(left_over) = value.strip_prefix("${") {
|
||||
if let Some(var_name) = left_over.strip_suffix("}") {
|
||||
return match env::var(var_name) {
|
||||
Ok(value) => value.into(),
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"couldn't read password from environemnt variable {}, error: {}",
|
||||
var_name, err
|
||||
);
|
||||
|
||||
// NOTE: Just like shell, if environment variable not found, then the value of it is an empty string.
|
||||
"".into()
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
value.into()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user