icsp 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ICSP
4
+ module Commands
5
+ class CreateHash < ::ICSP::Commands::BaseCommand
6
+ def cryptcp
7
+ @cryptcp ||= @config.cryptcp
8
+ end
9
+
10
+ def execute
11
+ input_file = arguments.first
12
+ result = ::ICSP::Shell.new("#{cryptcp} -hash -hex #{input_file}", convert_to_utf8: false).execute
13
+ exit(result.exit_code) unless result.ok
14
+
15
+ puts result
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ICSP
4
+ module Commands
5
+ class CreateSignature < ::ICSP::Commands::BaseCommand
6
+ def cryptcp
7
+ @cryptcp ||= @config.cryptcp
8
+ end
9
+
10
+ def execute
11
+ input_file = arguments.first
12
+ thumbprint = selected_certificate
13
+
14
+ result = ::ICSP::Shell.new("#{cryptcp} -signf -thumbprint '#{thumbprint}' #{input_file}",
15
+ convert_to_utf8: false, fork: false).execute
16
+ exit(result.exit_code) unless result.ok
17
+
18
+ puts result
19
+ end
20
+
21
+ def selected_certificate
22
+ ::ICSP::Commands::Certificate::List.new(config: config, options: options, arguments: arguments).select
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ICSP
4
+ module Commands
5
+ class DecryptFile < ::ICSP::Commands::BaseCommand
6
+ def cryptcp
7
+ @cryptcp ||= @config.cryptcp
8
+ end
9
+
10
+ def execute
11
+ input_file = arguments.first
12
+ output_file = arguments.last
13
+ result = ::ICSP::Shell.new(
14
+ "#{cryptcp} -decr -f '#{options[:certificate_file]}' -start #{input_file} #{output_file}", convert_to_utf8: false
15
+ ).execute
16
+ exit(result.exit_code) unless result.ok
17
+
18
+ puts result
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ICSP
4
+ module Commands
5
+ class EncryptFile < ::ICSP::Commands::BaseCommand
6
+ def cryptcp
7
+ @cryptcp ||= @config.cryptcp
8
+ end
9
+
10
+ def execute
11
+ input_file = arguments.first
12
+ output_file = arguments.last
13
+ result = ::ICSP::Shell.new(
14
+ "#{cryptcp} -encr -thumbprint '#{options[:certificate_file]}' #{input_file} #{output_file}", convert_to_utf8: false
15
+ ).execute
16
+ exit(result.exit_code) unless result.ok
17
+
18
+ puts result
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ICSP
4
+ module Commands
5
+ module Hardware
6
+ class List < ::ICSP::Commands::BaseCommand
7
+ def cpconfig
8
+ @cpconfig ||= @config.cpconfig
9
+ end
10
+
11
+ def execute
12
+ type = options[:type] || 'reader'
13
+ result = ::ICSP::Shell.new("#{cpconfig} -hardware #{type} -view").execute
14
+ exit(result.exit_code) unless result.ok
15
+
16
+ puts result
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ICSP
4
+ module Commands
5
+ module License
6
+ class Set < ::ICSP::Commands::BaseCommand
7
+ def cpconfig
8
+ @cpconfig ||= @config.cpconfig
9
+ end
10
+
11
+ def execute
12
+ result = ::ICSP::Shell.new("#{cpconfig} -license -set #{arguments.first}").execute
13
+ exit(result.exit_code) unless result.ok
14
+
15
+ puts result
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ICSP
4
+ module Commands
5
+ module License
6
+ class View < ::ICSP::Commands::BaseCommand
7
+ def cpconfig
8
+ @cpconfig ||= @config.cpconfig
9
+ end
10
+
11
+ def execute
12
+ result = ::ICSP::Shell.new("#{cpconfig} -license -view").execute
13
+ exit(result.exit_code) unless result.ok
14
+
15
+ puts result
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ICSP
4
+ module Commands
5
+ class VerifyHash < ::ICSP::Commands::BaseCommand
6
+ def cryptcp
7
+ @cryptcp ||= @config.cryptcp
8
+ end
9
+
10
+ def execute
11
+ input_file = arguments.first
12
+ result = ::ICSP::Shell.new("#{cryptcp} -vhash -hex #{input_file}", convert_to_utf8: false).execute
13
+ exit(result.exit_code) unless result.ok
14
+
15
+ puts result
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ICSP
4
+ module Commands
5
+ class VerifySignature < ::ICSP::Commands::BaseCommand
6
+ def cryptcp
7
+ @cryptcp ||= @config.cryptcp
8
+ end
9
+
10
+ def execute
11
+ input_file = arguments.first
12
+ thumbprint = selected_certificate
13
+
14
+ result = ::ICSP::Shell.new("#{cryptcp} -vsignf -thumbprint '#{thumbprint}' #{input_file}",
15
+ convert_to_utf8: false, fork: false).execute
16
+ exit(result.exit_code) unless result.ok
17
+
18
+ puts result
19
+ end
20
+
21
+ def selected_certificate
22
+ ::ICSP::Commands::Certificate::List.new(config: config, options: options, arguments: arguments).select
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,3 @@
1
+ module ICSP
2
+ VERSION = "0.1.0"
3
+ end
data/lib/csp.rb ADDED
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'logger'
5
+ require 'optionparser'
6
+ require 'ostruct'
7
+ require 'yaml'
8
+
9
+ require 'os'
10
+ require 'tty-prompt'
11
+
12
+ require_relative '../config/config'
13
+ require_relative '../config/environment'
14
+ require_relative '../lib/csp_option_parser'
15
+ require_relative '../lib/commands/base_command'
16
+ require_relative '../lib/shell'
17
+ require_relative '../lib/shell_result'
18
+
19
+ require_relative '../lib/commands/certificate/delete'
20
+ require_relative '../lib/commands/certificate/install'
21
+ require_relative '../lib/commands/certificate/list'
22
+ require_relative '../lib/commands/certificate/view'
23
+ require_relative '../lib/commands/container/check'
24
+ require_relative '../lib/commands/container/list'
25
+ require_relative '../lib/commands/hardware/list'
26
+ require_relative '../lib/commands/license/view'
27
+ require_relative '../lib/commands/license/set'
28
+ require_relative '../lib/commands/create_hash'
29
+ require_relative '../lib/commands/verify_hash'
30
+ require_relative '../lib/commands/encrypt_file'
31
+ require_relative '../lib/commands/decrypt_file'
32
+ require_relative '../lib/commands/create_signature'
33
+ require_relative '../lib/commands/verify_signature'
34
+
35
+ # CryptoPro CSP
36
+ module ICSP
37
+ def self.to_camel_case(string)
38
+ string.to_s.split('_').map(&:capitalize).join
39
+ end
40
+
41
+ def self.run
42
+ parsed = ::ICSP::Services::OptionParserService.new.parse
43
+ command_parts = %w[::ICSP Commands]
44
+ command_parts << to_camel_case(parsed.command) if parsed.command
45
+ command_parts << to_camel_case(parsed.subcommand) if parsed.subcommand
46
+ command = Object.const_get(command_parts.join('::'))
47
+ .new(config: config, options: parsed.options, arguments: parsed.arguments)
48
+ command.respond_to?(:print) ? command.print : command.execute
49
+ rescue StandardError => e
50
+ puts 'Application aborted with error:'
51
+ raise e
52
+ end
53
+
54
+ run
55
+ end
@@ -0,0 +1,224 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ICSP
4
+ module Services
5
+ # OptionParserService
6
+ class OptionParserService
7
+ APP_HELP = <<~HELP
8
+ Available commands are:
9
+ certificate Manage certificates
10
+ container Manage containers
11
+ hardware Manage hardware
12
+ license Manage license
13
+ -----
14
+ sign_file
15
+ verify_signature
16
+ encrypt_file
17
+ decrypt_file
18
+
19
+ See 'icsp COMMAND --help' for more information on a specific command.
20
+ For full documentation, see: https://github.com/denblackstache/cryptopro-cli#readme
21
+ HELP
22
+
23
+ def parse
24
+ command = parse_command
25
+ unless command
26
+ puts 'No command passed'
27
+ exit
28
+ end
29
+
30
+ subcommand_result = parse_subcommand(command)
31
+ OpenStruct.new(
32
+ command: command,
33
+ subcommand: subcommand_result[:subcommand],
34
+ arguments: subcommand_result[:arguments],
35
+ options: subcommand_result[:options]
36
+ )
37
+ end
38
+
39
+ private
40
+
41
+ def parse_command
42
+ global = OptionParser.new do |opts|
43
+ opts.banner = 'Usage: icsp [command] [subcommand] [options]'
44
+ opts.separator('')
45
+ opts.separator(APP_HELP)
46
+ end
47
+ global.order!
48
+ ARGV.shift.to_sym unless ARGV.empty?
49
+ end
50
+
51
+ def parse_subcommand(command)
52
+ options = {}
53
+ subcommands = {
54
+ encrypt_file: encrypt_file_option_parser(options),
55
+ decrypt_file: decrypt_file_option_parser(options),
56
+ create_hash: create_hash_option_parser(options),
57
+ verify_hash: verify_hash_option_parser(options),
58
+ create_signature: create_signature_option_parser(options),
59
+ verify_signature: verify_signature_option_parser(options),
60
+ certificate: {
61
+ delete: certificate_delete_option_parser(options),
62
+ install: certificate_install_option_parser(options),
63
+ list: certificate_list_option_parser(options),
64
+ view: certificate_list_option_parser(options)
65
+ },
66
+ container: {
67
+ check: container_check_option_parser(options),
68
+ list: container_list_option_parser(options)
69
+ },
70
+ hardware: {
71
+ list: hardware_list_option_parser(options)
72
+ },
73
+ license: {
74
+ view: license_view_option_parser(options),
75
+ set: license_set_option_parser(options)
76
+ }
77
+ }
78
+
79
+ is_management_command = subcommands[command].is_a?(Hash)
80
+ subcommand = ARGV.shift.to_sym if is_management_command && !ARGV.empty?
81
+
82
+ subcommand_option_parser = is_management_command ? subcommands[command][subcommand] : subcommands[command]
83
+ subcommand_option_parser.parse!
84
+
85
+ { subcommand: subcommand, arguments: ARGV.dup, options: options }
86
+ end
87
+
88
+ def encrypt_file_option_parser(options)
89
+ OptionParser.new do |opts|
90
+ opts.banner = 'Usage: icsp encrypt_file [options]'
91
+ opts.on('-f certificate_file', '--file certificate_file', String,
92
+ 'certificate file path') do |certificate_file|
93
+ options[:certificate_file] = certificate_file
94
+ end
95
+ opts.separator('')
96
+ opts.separator('description')
97
+ end
98
+ end
99
+
100
+ def decrypt_file_option_parser(options)
101
+ OptionParser.new do |opts|
102
+ opts.banner = 'Usage: icsp decrypt_file [options]'
103
+ opts.on('-f certificate_file', '--file certificate_file', String,
104
+ 'certificate file path') do |certificate_file|
105
+ options[:certificate_file] = certificate_file
106
+ end
107
+ opts.separator('')
108
+ opts.separator('description')
109
+ end
110
+ end
111
+
112
+ def create_hash_option_parser(_options)
113
+ OptionParser.new do |opts|
114
+ opts.banner = 'Usage: icsp create_hash [options]'
115
+ opts.separator('')
116
+ opts.separator('description')
117
+ end
118
+ end
119
+
120
+ def verify_hash_option_parser(_options)
121
+ OptionParser.new do |opts|
122
+ opts.banner = 'Usage: icsp verify_hash [options]'
123
+ opts.separator('')
124
+ opts.separator('description')
125
+ end
126
+ end
127
+
128
+ def create_signature_option_parser(_options)
129
+ OptionParser.new do |opts|
130
+ opts.banner = 'Usage: icsp create_signature [options]'
131
+ opts.separator('')
132
+ opts.separator('description')
133
+ end
134
+ end
135
+
136
+ def verify_signature_option_parser(_options)
137
+ OptionParser.new do |opts|
138
+ opts.banner = 'Usage: icsp verify_signature [options]'
139
+ opts.separator('')
140
+ opts.separator('description')
141
+ end
142
+ end
143
+
144
+ def certificate_delete_option_parser(_options)
145
+ OptionParser.new do |opts|
146
+ opts.banner = 'Usage: icsp certificate delete [options]'
147
+ opts.separator('')
148
+ opts.separator('description')
149
+ end
150
+ end
151
+
152
+ def certificate_install_option_parser(options)
153
+ OptionParser.new do |opts|
154
+ opts.banner = 'Usage: icsp certificate install [options]'
155
+ opts.on('-f file', '--file file', String, 'file path') do |file|
156
+ options[:file] = file
157
+ end
158
+ opts.separator('')
159
+ opts.separator('description')
160
+ end
161
+ end
162
+
163
+ def certificate_list_option_parser(_options)
164
+ OptionParser.new do |opts|
165
+ opts.banner = 'Usage: icsp certificate list [options]'
166
+ opts.separator('')
167
+ opts.separator('description')
168
+ end
169
+ end
170
+
171
+ def certificate_view_option_parser(_options)
172
+ OptionParser.new do |opts|
173
+ opts.banner = 'Usage: icsp certificate view [options]'
174
+ opts.separator('')
175
+ opts.separator('description')
176
+ end
177
+ end
178
+
179
+ def container_check_option_parser(_options)
180
+ OptionParser.new do |opts|
181
+ opts.banner = 'Usage: icsp container check [options]'
182
+ opts.separator('')
183
+ opts.separator('description')
184
+ end
185
+ end
186
+
187
+ def container_list_option_parser(_options)
188
+ OptionParser.new do |opts|
189
+ opts.banner = 'Usage: icsp container list [options]'
190
+ opts.separator('')
191
+ opts.separator('description')
192
+ end
193
+ end
194
+
195
+ def hardware_list_option_parser(options)
196
+ OptionParser.new do |opts|
197
+ opts.banner = 'Usage: icsp hardware list [options]'
198
+ opts.on('-t hardware_type', '--type hardware_type', String,
199
+ 'hardware_type - reader (default) | rndm | media') do |hardware_type|
200
+ options[:type] = hardware_type
201
+ end
202
+ opts.separator('')
203
+ opts.separator('Review of the installed readers, generators of random numbers and media')
204
+ end
205
+ end
206
+
207
+ def license_view_option_parser(_options)
208
+ OptionParser.new do |opts|
209
+ opts.banner = 'Usage: icsp license view'
210
+ opts.separator('')
211
+ opts.separator('description')
212
+ end
213
+ end
214
+
215
+ def license_set_option_parser(_options)
216
+ OptionParser.new do |opts|
217
+ opts.banner = 'Usage: icsp license set'
218
+ opts.separator('')
219
+ opts.separator('description')
220
+ end
221
+ end
222
+ end
223
+ end
224
+ end
data/lib/shell.rb ADDED
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ICSP
4
+ # Shell
5
+ class Shell
6
+ def initialize(command, split: true, convert_to_utf8: true, fork: true)
7
+ @command = command
8
+ @split = split
9
+ @convert_to_utf8 = convert_to_utf8
10
+ @fork = fork
11
+ end
12
+
13
+ def execute
14
+ ::ICSP.logger.info("command: #{@command}")
15
+ unless @fork
16
+ exec(@command)
17
+ return
18
+ end
19
+
20
+ raw_output = `#{@command}`
21
+ exec_success = $CHILD_STATUS.success?
22
+ exit_code = $CHILD_STATUS.exitstatus
23
+
24
+ output = @convert_to_utf8 ? raw_output.force_encoding('cp1251').encode('utf-8', undef: :replace) : raw_output
25
+ csp_error_code = ''
26
+ output_lines = []
27
+
28
+ if @split
29
+ output_lines = output.split("\n")
30
+ csp_error_code_line = output_lines.find { |l| l.include?('ErrorCode') }
31
+ csp_error_code = /0x0*[1-9a-fA-F][0-9a-fA-F]*/.match(csp_error_code_line).to_s
32
+ end
33
+
34
+ shell_result = ::ICSP::ShellResult.new(
35
+ output: output,
36
+ output_lines: output_lines,
37
+ csp_error_code: csp_error_code,
38
+ ok: exec_success && csp_error_code == '',
39
+ exit_code: exit_code
40
+ )
41
+
42
+ ::ICSP.logger.debug("ok: #{shell_result.ok}")
43
+ shell_result
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ICSP
4
+ # ShellResult
5
+ class ShellResult
6
+ def initialize(ok:, exit_code:, output:, output_lines:, csp_error_code:)
7
+ @ok = ok
8
+ @exit_code = exit_code
9
+ @output = output
10
+ @output_lines = output_lines
11
+ @csp_error_code = csp_error_code
12
+ end
13
+
14
+ attr_reader :ok, :exit_code, :output, :output_lines, :csp_error_code
15
+
16
+ def to_s
17
+ output
18
+ end
19
+ end
20
+ end
metadata ADDED
@@ -0,0 +1,118 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: icsp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Denis Semenenko
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2022-11-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: os
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: tty-prompt
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.23.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.23.1
41
+ description: |-
42
+ An interactive CryptoPro CSP shell that tries to imitate its GUI counterpart on the Windows platform.
43
+ Built for macOS and Linux daily use by wrapping a set of CryptoPro CLI tools: cryptcp, certmgr, csptest, cpconfig, etc.
44
+ email:
45
+ - hypercoderx@gmail.com
46
+ executables:
47
+ - icsp
48
+ extensions: []
49
+ extra_rdoc_files: []
50
+ files:
51
+ - ".gitignore"
52
+ - ".rspec"
53
+ - ".rubocop.yml"
54
+ - ".ruby-version"
55
+ - Gemfile
56
+ - Gemfile.lock
57
+ - LICENSE
58
+ - README.md
59
+ - Rakefile
60
+ - bin/console
61
+ - bin/setup
62
+ - config/config.rb
63
+ - config/environment.rb
64
+ - exe/icsp
65
+ - icsp.gemspec
66
+ - lib/commands/base_command.rb
67
+ - lib/commands/certificate/delete.rb
68
+ - lib/commands/certificate/install.rb
69
+ - lib/commands/certificate/list.rb
70
+ - lib/commands/certificate/view.rb
71
+ - lib/commands/container/change_pin_code.rb
72
+ - lib/commands/container/check.rb
73
+ - lib/commands/container/copy.rb
74
+ - lib/commands/container/delete.rb
75
+ - lib/commands/container/forget_all_pin_codes.rb
76
+ - lib/commands/container/list.rb
77
+ - lib/commands/container/view.rb
78
+ - lib/commands/create_hash.rb
79
+ - lib/commands/create_signature.rb
80
+ - lib/commands/decrypt_file.rb
81
+ - lib/commands/encrypt_file.rb
82
+ - lib/commands/hardware/list.rb
83
+ - lib/commands/license/set.rb
84
+ - lib/commands/license/view.rb
85
+ - lib/commands/verify_hash.rb
86
+ - lib/commands/verify_signature.rb
87
+ - lib/csp.rb
88
+ - lib/csp/version.rb
89
+ - lib/csp_option_parser.rb
90
+ - lib/shell.rb
91
+ - lib/shell_result.rb
92
+ homepage: https://github.com/denblackstache/icsp
93
+ licenses:
94
+ - MIT
95
+ metadata:
96
+ allowed_push_host: https://rubygems.org
97
+ homepage_uri: https://github.com/denblackstache/icsp
98
+ source_code_uri: https://github.com/denblackstache/icsp
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: 2.7.0
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubygems_version: 3.1.6
115
+ signing_key:
116
+ specification_version: 4
117
+ summary: An interactive CryptoPro CSP shell
118
+ test_files: []