class TSS::CLI
Public Instance Methods
combine()
click to toggle source
rubocop:disable CyclomaticComplexity
# File lib/tss/cli_combine.rb, line 51 def combine log('Starting combine') log("options : #{options.inspect}") shares = [] # There are three ways to pass in shares. STDIN, by specifying # `--input-file`, and in response to being prompted and entering shares # line by line. # STDIN # Usage : echo 'foo bar baz' | bundle exec bin/tss split | bundle exec bin/tss combine unless STDIN.tty? $stdin.each_line do |line| line = line.strip exit_if_binary!(line) if line.start_with?('tss~') && line.match(Util::HUMAN_SHARE_RE) shares << line else log("Skipping invalid share file line : #{line}") end end end # Read from an Input File if STDIN.tty? && options[:input_file] log("Input file specified : #{options[:input_file]}") if File.exist?(options[:input_file]) log("Input file found : #{options[:input_file]}") file = File.open(options[:input_file], 'r') while !file.eof? line = file.readline.strip exit_if_binary!(line) if line.start_with?('tss~') && line.match(Util::HUMAN_SHARE_RE) shares << line else log("Skipping invalid share file line : #{line}") end end else err("Filename '#{options[:input_file]}' does not exist.") exit(1) end end # Enter shares in response to a prompt. if STDIN.tty? && options[:input_file].blank? say('Enter shares, one per line, and a dot (.) on a line by itself to finish :') last_ans = nil until last_ans == '.' last_ans = ask('share> ').strip exit_if_binary!(last_ans) if last_ans != '.' && last_ans.start_with?('tss~') && last_ans.match(Util::HUMAN_SHARE_RE) shares << last_ans end end end begin sec = TSS.combine(shares: shares, padding: options[:padding]) say('') say('RECOVERED SECRET METADATA') say('*************************') say("hash : #{sec[:hash]}") say("hash_alg : #{sec[:hash_alg]}") say("identifier : #{sec[:identifier]}") say("process_time : #{sec[:process_time]}ms") say("threshold : #{sec[:threshold]}") # Write the secret to a file or STDOUT. The hash of the file checked # using sha1sum or sha256sum should match the hash of the original # secret when it was split. if options[:output_file].present? say("secret file : [#{options[:output_file]}]") File.open(options[:output_file], 'w'){ |somefile| somefile.puts sec[:secret] } else say('secret :') say(sec[:secret]) end rescue TSS::Error => e err("#{e.class} : #{e.message}") end end
err(str)
click to toggle source
# File lib/tss/cli_common.rb, line 32 def err(str) say_status(:error, "#{Time.now.utc.iso8601} : #{str}", :red) end
exit_if_binary!(str)
click to toggle source
rubocop:disable CyclomaticComplexity
# File lib/tss/cli_common.rb, line 10 def exit_if_binary!(str) str.each_byte { |c| # OK, 9 (TAB), 10 (CR), 13 (LF), >=32 for normal ASCII # Usage of anything other than 10, 13, and 32-126 ASCII decimal codes # looks as though contents are binary and not standard text. if c < 9 || (c > 10 && c < 13) || (c > 13 && c < 32) || c == 127 err('STDIN secret appears to contain binary data.') exit(1) end } unless ['UTF-8', 'US-ASCII'].include?(str.encoding.name) err('STDIN secret has a non UTF-8 or US-ASCII encoding.') exit(1) end end
log(str)
click to toggle source
rubocop:enable CyclomaticComplexity
# File lib/tss/cli_common.rb, line 28 def log(str) say_status(:log, "#{Time.now.utc.iso8601} : #{str}", :white) if options[:verbose] end
split()
click to toggle source
rubocop:disable CyclomaticComplexity
# File lib/tss/cli_split.rb, line 74 def split log('Starting split') log('options : ' + options.inspect) args = {} # There are three ways to pass in the secret. STDIN, by specifying # `--input-file`, and after being prompted and entering your secret # line by line. # STDIN # Usage : echo 'foo bar baz' | bundle exec bin/tss split unless STDIN.tty? secret = $stdin.read exit_if_binary!(secret) end # Read from an Input File if STDIN.tty? && options[:input_file].present? log("Input file specified : #{options[:input_file]}") if File.exist?(options[:input_file]) log("Input file found : #{options[:input_file]}") secret = File.open(options[:input_file], 'r'){ |file| file.read } exit_if_binary!(secret) else err("Filename '#{options[:input_file]}' does not exist.") exit(1) end end # Enter a secret in response to a prompt. if STDIN.tty? && options[:input_file].blank? say('Enter your secret, enter a dot (.) on a line by itself to finish :') last_ans = nil secret = [] while last_ans != '.' last_ans = ask('secret > ') secret << last_ans unless last_ans == '.' end # Strip whitespace from the leading and trailing edge of the secret. # Separate each line of the secret with newline, and add a trailing # newline so the hash of a secret when it is created will match # the hash of a file output when recombinging shares. secret = secret.join("\n").strip + "\n" exit_if_binary!(secret) end args[:secret] = secret args[:threshold] = options[:threshold] if options[:threshold] args[:num_shares] = options[:num_shares] if options[:num_shares] args[:identifier] = options[:identifier] if options[:identifier] args[:hash_alg] = options[:hash_alg] if options[:hash_alg] args[:format] = options[:format] if options[:format] args[:padding] = options[:padding] begin log("Calling : TSS.split(#{args.inspect})") shares = TSS.split(args) if options[:output_file].present? file_header = "# THRESHOLD SECRET SHARING SHARES\n" file_header << "# #{Time.now.utc.iso8601}\n" file_header << "# https://github.com/grempe/tss-rb\n" file_header << "\n\n" File.open(options[:output_file], 'w') do |somefile| somefile.puts file_header + shares.join("\n") end log("Process complete : Output file written : #{options[:output_file]}") else $stdout.puts shares.join("\n") log('Process complete') end rescue TSS::Error => e err("#{e.class} : #{e.message}") end end
version()
click to toggle source
# File lib/tss/cli_version.rb, line 11 def version say("TSS #{TSS::VERSION}") end