icsp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: []