Class: TSS::CLI

Inherits:
Thor
  • Object
show all
Includes:
Thor::Actions
Defined in:
lib/tss/cli_split.rb,
lib/tss/cli_common.rb,
lib/tss/cli_combine.rb,
lib/tss/cli_version.rb

Instance Method Summary collapse

Instance Method Details

#combineObject

rubocop:disable CyclomaticComplexity



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/tss/cli_combine.rb', line 44

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)

    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

#splitObject

rubocop:disable CyclomaticComplexity



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/tss/cli_split.rb', line 73

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[:pad_blocksize] = options[:pad_blocksize] if options[:pad_blocksize]
  args[:format]        = options[:format]        if options[:format]

  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

#versionObject



11
12
13
# File 'lib/tss/cli_version.rb', line 11

def version
  say("TSS #{TSS::VERSION}")
end