Class: Uniring

Inherits:
Object
  • Object
show all
Includes:
UniversaTools, UniversaTools::Commons
Defined in:
lib/universa_tools/uniring.rb

Overview

Show help it nothing to do ARGV << “-h” if ARGV == []

Constant Summary

Constants included from UniversaTools

UniversaTools::VERSION

Constants included from UniversaTools::Commons

UniversaTools::Commons::ALNUMS, UniversaTools::Commons::NUMBERS

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from UniversaTools::Commons

#create_temp_file_name, #error, #error_style, #human_to_i, #load_contract, #load_private_key, #run_options_parser, #seconds_to_hms, #success_style, #todo!, #warning_style

Constructor Details

#initialize(&block) ⇒ Uniring

Returns a new instance of Uniring.



22
23
24
25
26
27
28
29
# File 'lib/universa_tools/uniring.rb', line 22

def initialize(&block)
  @main_password = nil
  @keyring_path = File.expand_path("~/.universa/main_keyring")
  @tasks = []
  @commands = {}
  @term_width = ANSI::Terminal.terminal_width
  init_opts &block
end

Instance Attribute Details

#option_parserObject (readonly)

Returns the value of attribute option_parser.



20
21
22
# File 'lib/universa_tools/uniring.rb', line 20

def option_parser
  @option_parser
end

Instance Method Details

#init_opts(&initializer) ⇒ Object



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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/universa_tools/uniring.rb', line 44

def init_opts &initializer
  @option_parser = OptionParser.new { |opts|
    opts.banner = <<-End
#{ANSI.bold { "\nUniversa KeyRing tool #{UniversaTools::VERSION}, Universa core #{Universa::VERSION}" }}
    End
    @usage = <<-End
    
Usage:

#{sample "uniring [options] command [arguments]"}

#{sample "uniring -h"}

#{sample "uniring help"}
    End
    opts.separator ""

    # opts.on("--term-with SIZE", "override terminal width to specified size when formatting output, default is taken from the terminal and is currently #@term_width.") { |size|
    #   @term_width = size
    # }

    opts.on("--all", "allow delete/update more than one key at a time") {
      @allow_all = true
    }

    opts.on("-p PASSWORD", "--password PASSWORD", "specify keyring password in the command line") { |x|
      @password = x
    }

    opts.on("-a [TAG,]KEY_FILE", "--add [TAG,]KEYFILE", Array, "add key from a file, with optional tag",
            "tag could be used to select keys in extract/sign/delete operations") { |tag, file_name|
      task {
        if !file_name
          tag, file_name = file_name, tag
        end
        file_name, password = file_name.split(':', 2)
        begin
          # TODO: REQUIRE TAG
          # TODO: REQUIRE FORCE or prompt to update tag
          # TODO: separate tag from this parameter - too hard to use
          keyring.add_key load_key(file_name, password), tag
          puts success_style("\nKey added\n")
        rescue ArgumentError
          error "key already in ring"
        end
      }
    }

    opts.on("-d prefix", "--delete prefix", "delete key by beginning of its key address or a tag",
            "this method prompts confirmation works only if exactly one",
            "matching key exists") { |part| task {
      keys = keyring.matching_records(part)
      case keys.size
        when 0
          error "no matching keys found"
        when 1
          delete_keys(keys)
        else
          if @allow_all
            delete_keys(keys)
          else
            puts error_style("\nMore than one key matches the criteria:")
            keys.each { |kr| show_record kr }
            error "Only one key could be deleted unless --all is specified"
          end
      end
    } }

    opts.on("-l", "--list", "show keys in a ring") {
      task {
        keyring # this may ask for password so do it first
        puts "--" * 40
        puts ANSI.yellow { "KeyRing v.#{keyring.version.to_s}: " } + ANSI.bold { @keyring_path }
        puts ANSI.yellow { "fingerprint:     " } + ANSI.bold{ ANSI.green { keyring.fingerprint } }
        puts "--" * 40
        keyring.keys.sort_by { |x| x&.tag || '' }.each(&method(:show_record))
        if (keyring.keys.size > 0)
          puts "--" * 40
          puts "#{keyring.keys.size} key(s)\n"
        else
          puts "\nno keys\n"
        end
      }
    }

    opts.on("-x", "--change-password [NEW_PASSWORD]",
            "change password. if the password it not specified, it ",
            "will be requested. Don't forget to use -- to separate",
            "this option from the repository name when needed") { |np|
      task {
        kr = keyring
        new_password = np || request_password2("enter new password")
        kr.change_password new_password
        puts "password has been changed"
      }
    }

    opts.on("--init", "-i", "initialize new keyring. Does not change any existing keyring") {
      task {
        @keyring = KeyRing.new(@keyring_path, password: @password, password_proc: ->(x) { self.request_password2 x },
                               generate: true, override: @force_init)
        puts success_style("keyring has been created")
      }
    }

    opts.on("--force", "with --init, deletes existing reing if exists") {
      @force_init = true
    }

    initializer&.call(opts)

  }
end

#keyringObject



158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/universa_tools/uniring.rb', line 158

def keyring
  @keyring ||=
      begin
        print ANSI.faint { "trying to open keyring #{@keyring_path}" }
        KeyRing.new(@keyring_path, password: @password, password_proc: -> (x) { self.request_password(x) } )
      rescue Farcall::RemoteError => e
        if e.message =~ /HMAC authentication failed/
          error("wrong keyring password or broken ring")
        else
          raise e
        end
      ensure
        print "\r" + ' ' * 20 + "\r"
      end
end

#keyring_passwordObject



174
175
176
# File 'lib/universa_tools/uniring.rb', line 174

def keyring_password
  @keyring_password
end

#request_password(prompt) ⇒ Object



189
190
191
192
193
194
195
# File 'lib/universa_tools/uniring.rb', line 189

def request_password(prompt)
  clearstring
  print prompt + ' '
  STDIN.noecho { |x| x.gets.chomp }
ensure
  clearstring
end

#request_password2(prompt) ⇒ Object



178
179
180
181
182
183
184
185
186
187
# File 'lib/universa_tools/uniring.rb', line 178

def request_password2(prompt)
  loop do
    psw1 = request_password prompt
    psw2 = request_password "please re-enter the password"
    return psw1 if psw1 == psw2
    puts error_style("passwords do not much. try again")
  end
ensure
  clearstring
end

#runObject



31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/universa_tools/uniring.rb', line 31

def run
  run_options_parser @option_parser, tasks_before_commands: false do
    case ARGV.length
      when 0
        # OK, run as usual
      when 1
        @keyring_path = ARGV[0]
      else
        error("illegal arguments")
    end
  end
end