mamanegoryu1

exonum/src/helpers/fabric/password.rs

May 21st, 2020
353
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // Copyright 2019 The Exonum Team
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. //   http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14.  
  15. //! This module contains utilities for passphrase entry.
  16.  
  17. use failure::bail;
  18. use rpassword::read_password_from_tty;
  19.  
  20. use std::{env, io, str::FromStr};
  21.  
  22. use crate::helpers::ZeroizeOnDrop;
  23.  
  24. /// Passphrase input methods
  25. #[derive(Debug, Serialize, Deserialize, PartialEq)]
  26. pub enum PassInputMethod {
  27.     /// Prompt passphrase from terminal.
  28.     Terminal,
  29.     /// Get passphrase from environment variable (default if `None`).
  30.     EnvVariable(Option<String>),
  31.     /// Passphrase is passed as a command line parameter.
  32.     CmdLineParameter(ZeroizeOnDrop<String>),
  33. }
  34.  
  35. /// Secret key types.
  36. #[derive(Copy, Clone)]
  37. pub enum SecretKeyType {
  38.     Consensus,
  39.     Service,
  40. }
  41.  
  42. impl PassInputMethod {
  43.     /// Get passphrase using selected method.
  44.     /// Details of this process differs for different secret key types and whether we run node
  45.     /// or generate config files.
  46.     pub fn get_passphrase(self, key_type: SecretKeyType, node_run: bool) -> ZeroizeOnDrop<String> {
  47.         match self {
  48.             PassInputMethod::Terminal => {
  49.                 let prompt = match key_type {
  50.                     SecretKeyType::Consensus => "Enter consensus key passphrase",
  51.                     SecretKeyType::Service => "Enter service key passphrase",
  52.                 };
  53.                 prompt_passphrase(prompt, node_run).expect("Failed to read password from stdin")
  54.             }
  55.             PassInputMethod::EnvVariable(name) => {
  56.                 let var = if let Some(ref name) = name {
  57.                     name
  58.                 } else {
  59.                     match key_type {
  60.                         SecretKeyType::Consensus => "EXONUM_CONSENSUS_PASS",
  61.                         SecretKeyType::Service => "EXONUM_SERVICE_PASS",
  62.                     }
  63.                 };
  64.                 ZeroizeOnDrop(env::var(var).unwrap_or_else(|e| {
  65.                     panic!("Failed to get password from env variable: {}, {}", var, e)
  66.                 }))
  67.             }
  68.             PassInputMethod::CmdLineParameter(pass) => pass,
  69.         }
  70.     }
  71. }
  72.  
  73. impl Default for PassInputMethod {
  74.     fn default() -> Self {
  75.         PassInputMethod::Terminal
  76.     }
  77. }
  78.  
  79. impl FromStr for PassInputMethod {
  80.     type Err = failure::Error;
  81.  
  82.     fn from_str(s: &str) -> Result<Self, Self::Err> {
  83.         if s.is_empty() {
  84.             return Ok(Default::default());
  85.         }
  86.  
  87.         if s == "stdin" {
  88.             return Ok(PassInputMethod::Terminal);
  89.         }
  90.  
  91.         if s.starts_with("env") {
  92.             let env_var = s.split(':').nth(1).map(String::from);
  93.             return Ok(PassInputMethod::EnvVariable(env_var));
  94.         }
  95.  
  96.         if s.starts_with("pass") {
  97.             let pass = s.split(':').nth(1).unwrap_or_default();
  98.             return Ok(PassInputMethod::CmdLineParameter(ZeroizeOnDrop(
  99.                 pass.to_owned(),
  100.             )));
  101.         }
  102.  
  103.         bail!("Failed to parse passphrase input method")
  104.     }
  105. }
  106.  
  107. fn prompt_passphrase(prompt: &str, node_run: bool) -> io::Result<ZeroizeOnDrop<String>> {
  108.     if node_run {
  109.         return Ok(ZeroizeOnDrop(read_password_from_tty(Some(prompt))?));
  110.     }
  111.  
  112.     loop {
  113.         let password = ZeroizeOnDrop(read_password_from_tty(Some(prompt))?);
  114.         if password.is_empty() {
  115.             eprintln!("Passphrase must not be empty. Try again.");
  116.             continue;
  117.         }
  118.  
  119.         let confirmation = ZeroizeOnDrop(read_password_from_tty(Some(
  120.             "Enter same passphrase again: ",
  121.         ))?);
  122.  
  123.         if password == confirmation {
  124.             return Ok(password);
  125.         } else {
  126.             eprintln!("Passphrases do not match. Try again.");
  127.         }
  128.     }
  129. }
  130.  
  131. #[cfg(test)]
  132. mod tests {
  133.     use std::str::FromStr;
  134.  
  135.     use super::PassInputMethod;
  136.     use crate::helpers::ZeroizeOnDrop;
  137.  
  138.     #[test]
  139.     fn test_pass_input_method_parse() {
  140.         let correct_cases = vec![
  141.             ("", <PassInputMethod as Default>::default()),
  142.             ("stdin", PassInputMethod::Terminal),
  143.             ("env", PassInputMethod::EnvVariable(None)),
  144.             (
  145.                 "env:VAR",
  146.                 PassInputMethod::EnvVariable(Some("VAR".to_owned())),
  147.             ),
  148.             (
  149.                 "pass",
  150.                 PassInputMethod::CmdLineParameter(ZeroizeOnDrop("".to_owned())),
  151.             ),
  152.             (
  153.                 "pass:PASS",
  154.                 PassInputMethod::CmdLineParameter(ZeroizeOnDrop("PASS".to_owned())),
  155.             ),
  156.         ];
  157.  
  158.         for (inp, out) in correct_cases {
  159.             let method = <PassInputMethod as FromStr>::from_str(inp);
  160.             assert!(method.is_ok());
  161.             assert_eq!(method.unwrap(), out)
  162.         }
  163.     }
  164. }
RAW Paste Data

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×