exportation 0.1.0 → 0.2.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.
- checksums.yaml +4 -4
- data/README.md +69 -0
- data/bin/exportation +71 -24
- data/lib/exportation.rb +18 -19
- metadata +31 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fa309452b28fa8fe7c2459cdd8adc644c09dbfc0
|
4
|
+
data.tar.gz: 67696b8b638f49165d57ccad2369acd3bab94921
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 666f9867ff1e4754cd2d5ea93152cbcb31bf2bd3f7febe7a42784b4f2e9309af2ef328a931affce03e6e16962999bb08d5fee44e2ab9f96d49c32da1ebdc70c8
|
7
|
+
data.tar.gz: b129a2ff9826990e9c86439b32348132580232c79815ad4c7bb4a0edb93a2d17f1aa4984637342307a9cd2d5e3497ddbee5a05ce87462115cd6082b06efdf47d
|
data/README.md
CHANGED
@@ -1,10 +1,71 @@
|
|
1
1
|
# exportation
|
2
2
|
CLI tool of easy exporting, encrypting, and decrypting of certificates and private keys.
|
3
3
|
|
4
|
+
**Important:** The `export` command will take control of your "Keychain Access" app so keep all hands off your computer while that command runs
|
5
|
+
|
6
|
+
### Example usage (with prompt)
|
7
|
+
```sh
|
8
|
+
$: exportation export
|
9
|
+
Name: RokkinCat LLC
|
10
|
+
Path to save to (default: './'): ./examples
|
11
|
+
Filename to save as (default: 'export'): dist
|
12
|
+
Password for private key (default: ''): shhh
|
13
|
+
Info Take all hands off your computer! exportation is going to take control of 'Keychain Access'
|
14
|
+
```
|
15
|
+
|
16
|
+

|
17
|
+
|
18
|
+
### Why
|
19
|
+
- Export **and** encrypt certificates **and** private keys **into** repos
|
20
|
+
- CI tools (may need these to distrubute builds to Apple TestFlight Beta :apple:)
|
21
|
+
- For other developers (for when you are on vacation and they need to make a distribution build :grimacing:)
|
22
|
+
|
23
|
+
### How
|
24
|
+
- Makes use of AppleScript to control "Keychain Access"
|
25
|
+
- Opens "Keychain Access"
|
26
|
+
- Selects "Login" and "Certificates" for the left side
|
27
|
+
- Searches for the certificate you are looking for from `--name`
|
28
|
+
- Exports private key
|
29
|
+
- Right clicks it and selects export
|
30
|
+
- Changes the save path to your current directory (by default) or what was passed in through `--path`
|
31
|
+
- Saves the file to `exported.p12`
|
32
|
+
- Enters a blank password (by default) or what was passed in through `--password`
|
33
|
+
- Saves
|
34
|
+
- Exports certificate
|
35
|
+
- Right clicks it and selects export
|
36
|
+
- Changes the save path to your current directory (by default) or what was passed in through `--path`
|
37
|
+
- Saves the file to `exported.cer`
|
38
|
+
- Saves
|
39
|
+
|
4
40
|
### Features in progress
|
5
41
|
- Integrate with [fastlane](https://github.com/KrauseFx/fastlane) :rocket:
|
6
42
|
- Create a separate keychain with the certificates and private keys for use on CI systems :grinning:
|
7
43
|
|
44
|
+
### Caveats
|
45
|
+
- Some phases of the script might run slow due to using AppleScript
|
46
|
+
- Initial load may take up to 5ish seconds
|
47
|
+
- Waiting for private key password to be entered may take up to 7ish seconds
|
48
|
+
- May need to give "Accessibility" access to **ARDAgent** and **Terminal**
|
49
|
+
|
50
|
+
## Installation
|
51
|
+
|
52
|
+
### Install gem
|
53
|
+
```sh
|
54
|
+
gem install exportation
|
55
|
+
```
|
56
|
+
|
57
|
+
### Give "Accessibility" access
|
58
|
+
- Open up "Security & Privacy" preferences
|
59
|
+
- Select "Accessibility"
|
60
|
+
- Add **ARDAgent** and **Terminal**
|
61
|
+
- Click "+"
|
62
|
+
- Press CMD+SHIT+G (to go to specific folder)
|
63
|
+
- **ARDAgent** should be under `/System/Library/CoreServices/RemoteManagement/`
|
64
|
+
- **Terminal** should be under `/Applications/Utilities/`
|
65
|
+
|
66
|
+

|
67
|
+
**You won't need to give Heroes, Script Editor, or Steam permissions for exportation** :wink:
|
68
|
+
|
8
69
|
## Commands
|
9
70
|
Exportation has three different commands: `export`, `encrypt`, and `decrypt`.
|
10
71
|
|
@@ -41,3 +102,11 @@ Always put all for arguments in strings because I don't do AppleScript well :gri
|
|
41
102
|
```sh
|
42
103
|
osascript applescript/exportation.scpt "~/directory_you_want_to_export_to/" "dist" "iPhone Distribution: Your Company LLC" "thepassword"
|
43
104
|
```
|
105
|
+
|
106
|
+
## Author
|
107
|
+
|
108
|
+
Josh Holtz, me@joshholtz.com, [@joshdholtz](https://twitter.com/joshdholtz)
|
109
|
+
|
110
|
+
## License
|
111
|
+
|
112
|
+
exportation is available under the MIT license. See the LICENSE file for more info.
|
data/bin/exportation
CHANGED
@@ -6,10 +6,16 @@ require 'exportation'
|
|
6
6
|
|
7
7
|
require 'rubygems'
|
8
8
|
require 'commander'
|
9
|
+
require 'colorize'
|
10
|
+
require 'terminal-notifier'
|
9
11
|
|
10
12
|
class ExportationApplication
|
11
13
|
include Commander::Methods
|
12
14
|
|
15
|
+
def is_empty?(str)
|
16
|
+
str.nil? || str.length == 0
|
17
|
+
end
|
18
|
+
|
13
19
|
def run
|
14
20
|
program :name, 'Exportation'
|
15
21
|
program :version, '0.1.0'
|
@@ -22,57 +28,98 @@ class ExportationApplication
|
|
22
28
|
c.option '--filename STRING', String, 'File name to save certificate and private key as'
|
23
29
|
c.option '--name STRING', String, 'Common name of the cert as it is displayed in Keychain Access'
|
24
30
|
c.option '--password STRING', String, 'Password to use for the private key'
|
31
|
+
c.option '--noprompt', 'Do not prompt for missing options'
|
25
32
|
c.action do |args, options|
|
26
|
-
options.default path: "./", filename:"exported", password: ""
|
27
|
-
|
28
|
-
raise "--name is required" unless options.name
|
29
33
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
34
|
+
begin
|
35
|
+
unless options.noprompt
|
36
|
+
options.name = ask("Name: ") unless options.name
|
37
|
+
options.path = ask("Path to save to (default: './'): ") unless options.path
|
38
|
+
options.filename = ask("Filename to save as (default: 'export'): ") unless options.filename
|
39
|
+
options.password = ask("Password for private key (default: ''): ") unless options.password
|
40
|
+
end
|
41
|
+
|
42
|
+
options.path = './' if is_empty?(options.path)
|
43
|
+
options.filename = 'exported' if is_empty?(options.filename)
|
44
|
+
options.password = '' if is_empty?(options.password)
|
45
|
+
|
46
|
+
raise "'name' is required" if is_empty?(options.name)
|
47
|
+
log "Info".blue, "Take all hands off your computer! exportation is going to take control of 'Keychain Access'".blue
|
48
|
+
|
49
|
+
Exportation::Export.new(
|
50
|
+
path: options.path,
|
51
|
+
filename: options.filename,
|
52
|
+
name: options.name,
|
53
|
+
password: options.password
|
54
|
+
).run
|
55
|
+
|
56
|
+
TerminalNotifier.notify('Certificate and private key exported!', title: 'exportation')
|
57
|
+
rescue Exception => e
|
58
|
+
TerminalNotifier.notify('Export failed :(', title: 'exportation')
|
59
|
+
log "Error".red, e.message.red
|
60
|
+
end
|
36
61
|
|
37
62
|
end
|
38
63
|
end
|
39
64
|
|
40
65
|
command :encrypt do |c|
|
41
|
-
c.syntax = 'exportation encrypt [options]'
|
66
|
+
c.syntax = 'exportation encrypt [file_path1] [file_path2] ... [options]'
|
42
67
|
c.description = 'Encrypts certificates, private keys, and provisioning profiles with AES'
|
43
68
|
c.option '--password STRING', String, 'Password to use for the encryption'
|
44
69
|
c.option '--output STRING', String, 'Output directory for files (defaults to where original files are located)'
|
45
70
|
c.option '--force', 'Forces all files to decrypted (will encrypt decrypted files)'
|
71
|
+
c.option '--noprompt', 'Do not prompt for missing options'
|
46
72
|
c.action do |args, options|
|
47
73
|
options.default output: nil
|
48
74
|
|
49
|
-
|
75
|
+
begin
|
76
|
+
unless options.noprompt
|
77
|
+
options.password = ask("Password: ") unless options.password
|
78
|
+
options.output= ask("Output path (default: location of unencrypted files): ") unless options.output
|
79
|
+
end
|
50
80
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
81
|
+
raise "no files were passed through arguments" if args.empty?
|
82
|
+
raise "'password' is required" if is_empty?(options.password)
|
83
|
+
|
84
|
+
Exportation::Crypter.new(
|
85
|
+
files: args,
|
86
|
+
password: options.password,
|
87
|
+
output: options.output
|
88
|
+
).run :en, options.force
|
89
|
+
rescue Exception => e
|
90
|
+
log "Error".red, e.message.red
|
91
|
+
end
|
56
92
|
|
57
93
|
end
|
58
94
|
end
|
59
95
|
|
60
96
|
command :decrypt do |c|
|
61
|
-
c.syntax = 'exportation decrypt [options]'
|
97
|
+
c.syntax = 'exportation decrypt [file_path1] [file_path2] ... [options]'
|
62
98
|
c.description = 'Decrypts certificates, private keys, and provisioning profiles with AES'
|
63
99
|
c.option '--password STRING', String, 'Password to use for the decryption'
|
64
100
|
c.option '--output STRING', String, 'Output directory for files (defaults to where original files are located)'
|
65
101
|
c.option '--force', 'Forces all files to decrypted (will encrypt decrypted files)'
|
102
|
+
c.option '--noprompt', 'Do not prompt for missing options'
|
66
103
|
c.action do |args, options|
|
67
104
|
options.default output: nil
|
68
105
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
106
|
+
begin
|
107
|
+
unless options.noprompt
|
108
|
+
options.password = ask("Password: ") unless options.password
|
109
|
+
options.output= ask("Output path (default: location of encrypted files): ") unless options.output
|
110
|
+
end
|
111
|
+
|
112
|
+
raise "no files were passed through arguments" if args.empty?
|
113
|
+
raise "'password' is required" if is_empty?(options.password)
|
114
|
+
|
115
|
+
Exportation::Crypter.new(
|
116
|
+
files: args,
|
117
|
+
password: options.password,
|
118
|
+
output: options.output
|
119
|
+
).run :de, options.force
|
120
|
+
rescue Exception => e
|
121
|
+
log "Error".red, e.message.red
|
122
|
+
end
|
76
123
|
|
77
124
|
end
|
78
125
|
end
|
data/lib/exportation.rb
CHANGED
@@ -2,10 +2,8 @@ module Exportation
|
|
2
2
|
|
3
3
|
def self.gem_path
|
4
4
|
if Gem::Specification::find_all_by_name('exportation').any?
|
5
|
-
puts "looking in gem specification - #{Gem::Specification.find_by_name('exportation').gem_dir}"
|
6
5
|
return Gem::Specification.find_by_name('exportation').gem_dir
|
7
6
|
else
|
8
|
-
puts "using current directory"
|
9
7
|
return './'
|
10
8
|
end
|
11
9
|
end
|
@@ -71,24 +69,25 @@ module Exportation
|
|
71
69
|
|
72
70
|
# Does the stuff
|
73
71
|
files.each do |file|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
if crypt == :en
|
81
|
-
output_file += '.enc'
|
82
|
-
elsif crypt == :de
|
83
|
-
output_file = output_file.gsub('.enc','')
|
84
|
-
end
|
85
|
-
|
86
|
-
bash = "openssl aes-256-cbc -k \"#{password}\" -in #{file} -out #{output_file} -a"
|
87
|
-
puts "Running: #{bash}"
|
88
|
-
`#{bash}`
|
89
|
-
else
|
90
|
-
puts "File does not exist - #{file}"
|
72
|
+
file = './' + file unless file.start_with? '/'
|
73
|
+
if File.exists? file
|
74
|
+
output_file = file
|
75
|
+
if !output.nil? && output.length > 0
|
76
|
+
output_file = File.join(output, File.basename(file))
|
91
77
|
end
|
78
|
+
|
79
|
+
if crypt == :en
|
80
|
+
output_file += '.enc'
|
81
|
+
elsif crypt == :de
|
82
|
+
output_file = output_file.gsub('.enc','')
|
83
|
+
end
|
84
|
+
|
85
|
+
bash = "openssl aes-256-cbc -k \"#{password}\" -in #{file} -out #{output_file} -a"
|
86
|
+
puts "Running: #{bash}"
|
87
|
+
`#{bash}`
|
88
|
+
else
|
89
|
+
puts "File does not exist - #{file}"
|
90
|
+
end
|
92
91
|
end
|
93
92
|
|
94
93
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: exportation
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Josh Holtz
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-03-
|
11
|
+
date: 2015-03-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dotenv
|
@@ -38,6 +38,34 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '4.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: colorize
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.7'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.7'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: terminal-notifier
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.6'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.6'
|
41
69
|
description: CLI tool of easy exporting, encrypting, and decrypting of certificates
|
42
70
|
and private keys using Keychain Acess and openssl
|
43
71
|
email: me@joshholtz.com
|
@@ -51,7 +79,7 @@ files:
|
|
51
79
|
- applescript/exportation.scpt
|
52
80
|
- bin/exportation
|
53
81
|
- lib/exportation.rb
|
54
|
-
homepage: https://github.com/joshdholtz/
|
82
|
+
homepage: https://github.com/joshdholtz/exportation
|
55
83
|
licenses:
|
56
84
|
- MIT
|
57
85
|
metadata: {}
|