startapp 0.1.6

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.
Files changed (156) hide show
  1. checksums.yaml +7 -0
  2. data/COPYRIGHT +1 -0
  3. data/LICENSE +11 -0
  4. data/README.md +95 -0
  5. data/Rakefile +6 -0
  6. data/autocomplete/rhc_bash +1672 -0
  7. data/bin/app +37 -0
  8. data/conf/express.conf +8 -0
  9. data/features/assets/deploy.tar.gz +0 -0
  10. data/features/core_feature.rb +191 -0
  11. data/features/deployments_feature.rb +129 -0
  12. data/features/domains_feature.rb +58 -0
  13. data/features/keys_feature.rb +37 -0
  14. data/features/members_feature.rb +166 -0
  15. data/lib/rhc/auth/basic.rb +64 -0
  16. data/lib/rhc/auth/token.rb +102 -0
  17. data/lib/rhc/auth/token_store.rb +53 -0
  18. data/lib/rhc/auth.rb +5 -0
  19. data/lib/rhc/autocomplete.rb +66 -0
  20. data/lib/rhc/autocomplete_templates/bash.erb +39 -0
  21. data/lib/rhc/cartridge_helpers.rb +118 -0
  22. data/lib/rhc/cli.rb +40 -0
  23. data/lib/rhc/command_runner.rb +185 -0
  24. data/lib/rhc/commands/account.rb +25 -0
  25. data/lib/rhc/commands/alias.rb +124 -0
  26. data/lib/rhc/commands/app.rb +726 -0
  27. data/lib/rhc/commands/apps.rb +20 -0
  28. data/lib/rhc/commands/authorization.rb +115 -0
  29. data/lib/rhc/commands/base.rb +174 -0
  30. data/lib/rhc/commands/cartridge.rb +329 -0
  31. data/lib/rhc/commands/clone.rb +66 -0
  32. data/lib/rhc/commands/configure.rb +20 -0
  33. data/lib/rhc/commands/create.rb +100 -0
  34. data/lib/rhc/commands/delete.rb +19 -0
  35. data/lib/rhc/commands/deploy.rb +32 -0
  36. data/lib/rhc/commands/deployment.rb +82 -0
  37. data/lib/rhc/commands/domain.rb +172 -0
  38. data/lib/rhc/commands/env.rb +142 -0
  39. data/lib/rhc/commands/force_stop.rb +17 -0
  40. data/lib/rhc/commands/git_clone.rb +34 -0
  41. data/lib/rhc/commands/logout.rb +51 -0
  42. data/lib/rhc/commands/logs.rb +21 -0
  43. data/lib/rhc/commands/member.rb +148 -0
  44. data/lib/rhc/commands/port_forward.rb +197 -0
  45. data/lib/rhc/commands/reload.rb +17 -0
  46. data/lib/rhc/commands/restart.rb +17 -0
  47. data/lib/rhc/commands/scp.rb +54 -0
  48. data/lib/rhc/commands/server.rb +40 -0
  49. data/lib/rhc/commands/setup.rb +60 -0
  50. data/lib/rhc/commands/show.rb +43 -0
  51. data/lib/rhc/commands/snapshot.rb +137 -0
  52. data/lib/rhc/commands/ssh.rb +51 -0
  53. data/lib/rhc/commands/sshkey.rb +97 -0
  54. data/lib/rhc/commands/start.rb +17 -0
  55. data/lib/rhc/commands/stop.rb +17 -0
  56. data/lib/rhc/commands/tail.rb +47 -0
  57. data/lib/rhc/commands/threaddump.rb +14 -0
  58. data/lib/rhc/commands/tidy.rb +17 -0
  59. data/lib/rhc/commands.rb +396 -0
  60. data/lib/rhc/config.rb +321 -0
  61. data/lib/rhc/context_helper.rb +121 -0
  62. data/lib/rhc/core_ext.rb +202 -0
  63. data/lib/rhc/coverage_helper.rb +33 -0
  64. data/lib/rhc/deployment_helpers.rb +111 -0
  65. data/lib/rhc/exceptions.rb +256 -0
  66. data/lib/rhc/git_helpers.rb +106 -0
  67. data/lib/rhc/help_formatter.rb +55 -0
  68. data/lib/rhc/helpers.rb +481 -0
  69. data/lib/rhc/highline_extensions.rb +479 -0
  70. data/lib/rhc/json.rb +51 -0
  71. data/lib/rhc/output_helpers.rb +260 -0
  72. data/lib/rhc/rest/activation.rb +11 -0
  73. data/lib/rhc/rest/alias.rb +42 -0
  74. data/lib/rhc/rest/api.rb +87 -0
  75. data/lib/rhc/rest/application.rb +348 -0
  76. data/lib/rhc/rest/attributes.rb +36 -0
  77. data/lib/rhc/rest/authorization.rb +8 -0
  78. data/lib/rhc/rest/base.rb +79 -0
  79. data/lib/rhc/rest/cartridge.rb +162 -0
  80. data/lib/rhc/rest/client.rb +650 -0
  81. data/lib/rhc/rest/deployment.rb +18 -0
  82. data/lib/rhc/rest/domain.rb +98 -0
  83. data/lib/rhc/rest/environment_variable.rb +15 -0
  84. data/lib/rhc/rest/gear_group.rb +16 -0
  85. data/lib/rhc/rest/httpclient.rb +145 -0
  86. data/lib/rhc/rest/key.rb +44 -0
  87. data/lib/rhc/rest/membership.rb +105 -0
  88. data/lib/rhc/rest/mock.rb +1042 -0
  89. data/lib/rhc/rest/user.rb +32 -0
  90. data/lib/rhc/rest.rb +148 -0
  91. data/lib/rhc/scp_helpers.rb +27 -0
  92. data/lib/rhc/ssh_helpers.rb +380 -0
  93. data/lib/rhc/tar_gz.rb +51 -0
  94. data/lib/rhc/usage_templates/command_help.erb +51 -0
  95. data/lib/rhc/usage_templates/command_syntax_help.erb +11 -0
  96. data/lib/rhc/usage_templates/help.erb +61 -0
  97. data/lib/rhc/usage_templates/missing_help.erb +1 -0
  98. data/lib/rhc/usage_templates/options_help.erb +12 -0
  99. data/lib/rhc/vendor/okjson.rb +600 -0
  100. data/lib/rhc/vendor/parseconfig.rb +178 -0
  101. data/lib/rhc/vendor/sshkey.rb +253 -0
  102. data/lib/rhc/vendor/zliby.rb +628 -0
  103. data/lib/rhc/version.rb +5 -0
  104. data/lib/rhc/wizard.rb +637 -0
  105. data/lib/rhc.rb +34 -0
  106. data/spec/coverage_helper.rb +82 -0
  107. data/spec/direct_execution_helper.rb +339 -0
  108. data/spec/keys/example.pem +23 -0
  109. data/spec/keys/example_private.pem +27 -0
  110. data/spec/keys/server.pem +19 -0
  111. data/spec/rest_spec_helper.rb +31 -0
  112. data/spec/rhc/assets/cert.crt +22 -0
  113. data/spec/rhc/assets/cert_key_rsa +27 -0
  114. data/spec/rhc/assets/empty.txt +0 -0
  115. data/spec/rhc/assets/env_vars.txt +7 -0
  116. data/spec/rhc/assets/env_vars_2.txt +1 -0
  117. data/spec/rhc/assets/foo.txt +1 -0
  118. data/spec/rhc/assets/targz_corrupted.tar.gz +1 -0
  119. data/spec/rhc/assets/targz_sample.tar.gz +0 -0
  120. data/spec/rhc/auth_spec.rb +442 -0
  121. data/spec/rhc/cli_spec.rb +186 -0
  122. data/spec/rhc/command_spec.rb +435 -0
  123. data/spec/rhc/commands/account_spec.rb +42 -0
  124. data/spec/rhc/commands/alias_spec.rb +333 -0
  125. data/spec/rhc/commands/app_spec.rb +777 -0
  126. data/spec/rhc/commands/apps_spec.rb +39 -0
  127. data/spec/rhc/commands/authorization_spec.rb +157 -0
  128. data/spec/rhc/commands/cartridge_spec.rb +665 -0
  129. data/spec/rhc/commands/clone_spec.rb +41 -0
  130. data/spec/rhc/commands/deployment_spec.rb +327 -0
  131. data/spec/rhc/commands/domain_spec.rb +401 -0
  132. data/spec/rhc/commands/env_spec.rb +493 -0
  133. data/spec/rhc/commands/git_clone_spec.rb +102 -0
  134. data/spec/rhc/commands/logout_spec.rb +86 -0
  135. data/spec/rhc/commands/member_spec.rb +247 -0
  136. data/spec/rhc/commands/port_forward_spec.rb +217 -0
  137. data/spec/rhc/commands/scp_spec.rb +77 -0
  138. data/spec/rhc/commands/server_spec.rb +69 -0
  139. data/spec/rhc/commands/setup_spec.rb +118 -0
  140. data/spec/rhc/commands/snapshot_spec.rb +179 -0
  141. data/spec/rhc/commands/ssh_spec.rb +163 -0
  142. data/spec/rhc/commands/sshkey_spec.rb +188 -0
  143. data/spec/rhc/commands/tail_spec.rb +81 -0
  144. data/spec/rhc/commands/threaddump_spec.rb +84 -0
  145. data/spec/rhc/config_spec.rb +407 -0
  146. data/spec/rhc/helpers_spec.rb +531 -0
  147. data/spec/rhc/highline_extensions_spec.rb +314 -0
  148. data/spec/rhc/json_spec.rb +30 -0
  149. data/spec/rhc/rest_application_spec.rb +258 -0
  150. data/spec/rhc/rest_client_spec.rb +752 -0
  151. data/spec/rhc/rest_spec.rb +740 -0
  152. data/spec/rhc/targz_spec.rb +55 -0
  153. data/spec/rhc/wizard_spec.rb +756 -0
  154. data/spec/spec_helper.rb +575 -0
  155. data/spec/wizard_spec_helper.rb +330 -0
  156. metadata +469 -0
@@ -0,0 +1,178 @@
1
+ # modified version of parseconfig rubygem module
2
+ #
3
+ # Author:: BJ Dierkes <derks@bjdierkes.com>
4
+ # Copyright:: Copyright (c) 2006,2012 BJ Dierkes
5
+ # License:: MIT
6
+ # URL:: https://github.com/derks/ruby-parseconfig
7
+ #
8
+
9
+ # This class was written to simplify the parsing of configuration
10
+ # files in the format of "param = value". Please review the
11
+ # demo files included with this package.
12
+ #
13
+ # For further information please refer to the './doc' directory
14
+ # as well as the ChangeLog and README files included.
15
+ #
16
+
17
+ # Note: A group is a set of parameters defined for a subpart of a
18
+ # config file
19
+
20
+ module RHC
21
+ module Vendor
22
+ class ParseConfig
23
+
24
+ Version = '1.0.2'
25
+
26
+ attr_accessor :config_file, :params, :groups
27
+
28
+ # Initialize the class with the path to the 'config_file'
29
+ # The class objects are dynamically generated by the
30
+ # name of the 'param' in the config file. Therefore, if
31
+ # the config file is 'param = value' then the itializer
32
+ # will eval "@param = value"
33
+ #
34
+ def initialize(config_file=nil)
35
+ @config_file = config_file
36
+ @params = {}
37
+ @groups = []
38
+
39
+ if(self.config_file)
40
+ self.validate_config()
41
+ self.import_config()
42
+ end
43
+ end
44
+
45
+ # Validate the config file, and contents
46
+ def validate_config()
47
+ if !File.readable?(self.config_file)
48
+ raise Errno::EACCES, "#{self.config_file} is not readable"
49
+ end
50
+
51
+ # FIX ME: need to validate contents/structure?
52
+ end
53
+
54
+ # Import data from the config to our config object.
55
+ def import_config()
56
+ # The config is top down.. anything after a [group] gets added as part
57
+ # of that group until a new [group] is found.
58
+ group = nil
59
+ File.open(self.config_file) { |f| f.each do |line|
60
+ line.strip!
61
+ unless (/^\#/.match(line))
62
+ if(/\s*=\s*/.match(line))
63
+ param, value = line.split(/\s*=\s*/, 2)
64
+ var_name = "#{param}".chomp.strip
65
+ value = value.chomp.strip
66
+ new_value = ''
67
+ if (value)
68
+ if value =~ /^['"](.*)['"]$/
69
+ new_value = $1
70
+ else
71
+ new_value = value
72
+ end
73
+ else
74
+ new_value = ''
75
+ end
76
+
77
+ if group
78
+ self.add_to_group(group, var_name, new_value)
79
+ else
80
+ self.add(var_name, new_value)
81
+ end
82
+
83
+ elsif(/^\[(.+)\]$/.match(line).to_a != [])
84
+ group = /^\[(.+)\]$/.match(line).to_a[1]
85
+ self.add(group, {})
86
+
87
+ end
88
+ end
89
+ end }
90
+ end
91
+
92
+ # This method will provide the value held by the object "@param"
93
+ # where "@param" is actually the name of the param in the config
94
+ # file.
95
+ #
96
+ # DEPRECATED - will be removed in future versions
97
+ #
98
+ def get_value(param)
99
+ puts "ParseConfig Deprecation Warning: get_value() is deprecated. Use " + \
100
+ "config['param'] or config['group']['param'] instead."
101
+ return self.params[param]
102
+ end
103
+
104
+ # This method is a shortcut to accessing the @params variable
105
+ def [](param)
106
+ return self.params[param]
107
+ end
108
+
109
+ # This method returns all parameters/groups defined in a config file.
110
+ def get_params()
111
+ return self.params.keys
112
+ end
113
+
114
+ # List available sub-groups of the config.
115
+ def get_groups()
116
+ return self.groups
117
+ end
118
+
119
+ # This method adds an element to the config object (not the config file)
120
+ # By adding a Hash, you create a new group
121
+ def add(param_name, value)
122
+ if value.class == Hash
123
+ if self.params.has_key?(param_name)
124
+ if self.params[param_name].class == Hash
125
+ self.params[param_name].merge!(value)
126
+ elsif self.params.has_key?(param_name)
127
+ if self.params[param_name].class != value.class
128
+ raise ArgumentError, "#{param_name} already exists, and is of different type!"
129
+ end
130
+ end
131
+ else
132
+ self.params[param_name] = value
133
+ end
134
+ if ! self.groups.include?(param_name)
135
+ self.groups.push(param_name)
136
+ end
137
+ else
138
+ self.params[param_name] = value
139
+ end
140
+ end
141
+
142
+ # Add parameters to a group. Note that parameters with the same name
143
+ # could be placed in different groups
144
+ def add_to_group(group, param_name, value)
145
+ if ! self.groups.include?(group)
146
+ self.add(group, {})
147
+ end
148
+ self.params[group][param_name] = value
149
+ end
150
+
151
+ # Writes out the config file to output_stream
152
+ def write(output_stream=STDOUT)
153
+ self.params.each do |name,value|
154
+ if value.class.to_s != 'Hash'
155
+ if value.scan(/\w+/).length > 1
156
+ output_stream.puts "#{name} = \"#{value}\""
157
+ else
158
+ output_stream.puts "#{name} = #{value}"
159
+ end
160
+ end
161
+ end
162
+ output_stream.puts "\n"
163
+
164
+ self.groups.each do |group|
165
+ output_stream.puts "[#{group}]"
166
+ self.params[group].each do |param, value|
167
+ if value.scan(/\w+/).length > 1
168
+ output_stream.puts "#{param} = \"#{value}\""
169
+ else
170
+ output_stream.puts "#{param} = #{value}"
171
+ end
172
+ end
173
+ output_stream.puts "\n"
174
+ end
175
+ end
176
+ end
177
+ end
178
+ end
@@ -0,0 +1,253 @@
1
+ # modified version of SSHKey rubygem module
2
+ # https://github.com/bensie/sshkey
3
+ #
4
+ # Copyright (c) 2011 James Miller
5
+
6
+ # Permission is hereby granted, free of charge, to any person obtaining
7
+ # a copy of this software and associated documentation files (the
8
+ # "Software"), to deal in the Software without restriction, including
9
+ # without limitation the rights to use, copy, modify, merge, publish,
10
+ # distribute, sublicense, and/or sell copies of the Software, and to
11
+ # permit persons to whom the Software is furnished to do so, subject to
12
+ # the following conditions:
13
+
14
+ # The above copyright notice and this permission notice shall be
15
+ # included in all copies or substantial portions of the Software.
16
+
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
+
25
+ require 'openssl'
26
+ require 'base64'
27
+ require 'digest/md5'
28
+ require 'digest/sha1'
29
+
30
+ module RHC
31
+ module Vendor
32
+ class SSHKey
33
+ SSH_TYPES = {"rsa" => "ssh-rsa", "dsa" => "ssh-dss"}
34
+ SSH_CONVERSION = {"rsa" => ["e", "n"], "dsa" => ["p", "q", "g", "pub_key"]}
35
+
36
+ attr_reader :key_object, :comment, :type
37
+ attr_accessor :passphrase
38
+
39
+ class << self
40
+ # Generate a new keypair and return an SSHKey object
41
+ #
42
+ # The default behavior when providing no options will generate a 2048-bit RSA
43
+ # keypair.
44
+ #
45
+ # ==== Parameters
46
+ # * options<~Hash>:
47
+ # * :type<~String> - "rsa" or "dsa", "rsa" by default
48
+ # * :bits<~Integer> - Bit length
49
+ # * :comment<~String> - Comment to use for the public key, defaults to ""
50
+ # * :passphrase<~String> - Encrypt the key with this passphrase
51
+ #
52
+ def generate(options = {})
53
+ type = options[:type] || "rsa"
54
+
55
+ # JRuby modulus size must range from 512 to 1024
56
+ default_bits = type == "rsa" ? 2048 : 1024
57
+
58
+ bits = options[:bits] || default_bits
59
+ cipher = OpenSSL::Cipher::Cipher.new("AES-128-CBC") if options[:passphrase]
60
+
61
+ case type.downcase
62
+ when "rsa" then new(OpenSSL::PKey::RSA.generate(bits).to_pem(cipher, options[:passphrase]), options)
63
+ when "dsa" then new(OpenSSL::PKey::DSA.generate(bits).to_pem(cipher, options[:passphrase]), options)
64
+ else
65
+ raise "Unknown key type: #{type}"
66
+ end
67
+ end
68
+
69
+ # Validate an existing SSH public key
70
+ #
71
+ # Returns true or false depending on the validity of the public key provided
72
+ #
73
+ # ==== Parameters
74
+ # * ssh_public_key<~String> - "ssh-rsa AAAAB3NzaC1yc2EA...."
75
+ #
76
+ def valid_ssh_public_key?(ssh_public_key)
77
+ ssh_type, encoded_key = ssh_public_key.split(" ")
78
+ type = SSH_TYPES.invert[ssh_type]
79
+ prefix = [0,0,0,7].pack("C*")
80
+ decoded = Base64.decode64(encoded_key)
81
+
82
+ # Base64 decoding is too permissive, so we should validate if encoding is correct
83
+ return false unless Base64.encode64(decoded).gsub("\n", "") == encoded_key
84
+ return false unless decoded.sub!(/^#{prefix}#{ssh_type}/, "")
85
+
86
+ unpacked = decoded.unpack("C*")
87
+ data = []
88
+ index = 0
89
+ until unpacked[index].nil?
90
+ datum_size = from_byte_array unpacked[index..index+4-1], 4
91
+ index = index + 4
92
+ datum = from_byte_array unpacked[index..index+datum_size-1], datum_size
93
+ data << datum
94
+ index = index + datum_size
95
+ end
96
+
97
+ SSH_CONVERSION[type].size == data.size
98
+ rescue
99
+ false
100
+ end
101
+
102
+ # Fingerprints
103
+ #
104
+ # Accepts either a public or private key
105
+ #
106
+ # MD5 fingerprint for the given SSH key
107
+ def md5_fingerprint(key)
108
+ if key.match(/PRIVATE/)
109
+ new(key).md5_fingerprint
110
+ else
111
+ Digest::MD5.hexdigest(decoded_key(key)).gsub(fingerprint_regex, '\1:\2')
112
+ end
113
+ end
114
+ alias_method :fingerprint, :md5_fingerprint
115
+
116
+ # SHA1 fingerprint for the given SSH key
117
+ def sha1_fingerprint(key)
118
+ if key.match(/PRIVATE/)
119
+ new(key).sha1_fingerprint
120
+ else
121
+ Digest::SHA1.hexdigest(decoded_key(key)).gsub(fingerprint_regex, '\1:\2')
122
+ end
123
+ end
124
+
125
+ private
126
+
127
+ def from_byte_array(byte_array, expected_size = nil)
128
+ num = 0
129
+ raise "Byte array too short" if !expected_size.nil? && expected_size != byte_array.size
130
+ byte_array.reverse.each_with_index do |item, index|
131
+ num += item * 256**(index)
132
+ end
133
+ num
134
+ end
135
+
136
+ def decoded_key(key)
137
+ Base64.decode64(key.chomp.gsub(/ssh-[dr]s[as] /, ''))
138
+ end
139
+
140
+ def fingerprint_regex
141
+ /(.{2})(?=.)/
142
+ end
143
+ end
144
+
145
+ # Create a new SSHKey object
146
+ #
147
+ # ==== Parameters
148
+ # * private_key - Existing RSA or DSA private key
149
+ # * options<~Hash>
150
+ # * :comment<~String> - Comment to use for the public key, defaults to ""
151
+ # * :passphrase<~String> - If the key is encrypted, supply the passphrase
152
+ #
153
+ def initialize(private_key, options = {})
154
+ @passphrase = options[:passphrase]
155
+ @comment = options[:comment] || ""
156
+ begin
157
+ @key_object = OpenSSL::PKey::RSA.new(private_key, passphrase)
158
+ @type = "rsa"
159
+ rescue
160
+ @key_object = OpenSSL::PKey::DSA.new(private_key, passphrase)
161
+ @type = "dsa"
162
+ end
163
+ end
164
+
165
+ # Fetch the RSA/DSA private key
166
+ #
167
+ # rsa_private_key and dsa_private_key are aliased for backward compatibility
168
+ def private_key
169
+ key_object.to_pem
170
+ end
171
+ alias_method :rsa_private_key, :private_key
172
+ alias_method :dsa_private_key, :private_key
173
+
174
+ # Fetch the encrypted RSA/DSA private key using the passphrase provided
175
+ #
176
+ # If no passphrase is set, returns the unencrypted private key
177
+ def encrypted_private_key
178
+ return private_key unless passphrase
179
+ key_object.to_pem(OpenSSL::Cipher::Cipher.new("AES-128-CBC"), passphrase)
180
+ end
181
+
182
+ # Fetch the RSA/DSA public key
183
+ #
184
+ # rsa_public_key and dsa_public_key are aliased for backward compatibility
185
+ def public_key
186
+ key_object.public_key.to_pem
187
+ end
188
+ alias_method :rsa_public_key, :public_key
189
+ alias_method :dsa_public_key, :public_key
190
+
191
+ # SSH public key
192
+ def ssh_public_key
193
+ [SSH_TYPES[type], Base64.encode64(ssh_public_key_conversion).gsub("\n", ""), comment].join(" ").strip
194
+ end
195
+
196
+ # Fingerprints
197
+ #
198
+ # MD5 fingerprint for the given SSH public key
199
+ def md5_fingerprint
200
+ Digest::MD5.hexdigest(ssh_public_key_conversion).gsub(/(.{2})(?=.)/, '\1:\2')
201
+ end
202
+ alias_method :fingerprint, :md5_fingerprint
203
+
204
+ # SHA1 fingerprint for the given SSH public key
205
+ def sha1_fingerprint
206
+ Digest::SHA1.hexdigest(ssh_public_key_conversion).gsub(/(.{2})(?=.)/, '\1:\2')
207
+ end
208
+
209
+ private
210
+
211
+ # SSH Public Key Conversion
212
+ #
213
+ # All data type encoding is defined in the section #5 of RFC #4251.
214
+ # String and mpint (multiple precision integer) types are encoded this way:
215
+ # 4-bytes word: data length (unsigned big-endian 32 bits integer)
216
+ # n bytes: binary representation of the data
217
+
218
+ # For instance, the "ssh-rsa" string is encoded as the following byte array
219
+ # [0, 0, 0, 7, 's', 's', 'h', '-', 'r', 's', 'a']
220
+ def ssh_public_key_conversion
221
+ out = [0,0,0,7].pack("C*")
222
+ out += SSH_TYPES[type]
223
+
224
+ SSH_CONVERSION[type].each do |method|
225
+ byte_array = to_byte_array(key_object.public_key.send(method).to_i)
226
+ out += encode_unsigned_int_32(byte_array.length).pack("c*")
227
+ out += byte_array.pack("C*")
228
+ end
229
+
230
+ return out
231
+ end
232
+
233
+ def encode_unsigned_int_32(value)
234
+ out = []
235
+ out[0] = value >> 24 & 0xff
236
+ out[1] = value >> 16 & 0xff
237
+ out[2] = value >> 8 & 0xff
238
+ out[3] = value & 0xff
239
+ return out
240
+ end
241
+
242
+ def to_byte_array(num)
243
+ result = []
244
+ begin
245
+ result << (num & 0xff)
246
+ num >>= 8
247
+ end until (num == 0 || num == -1) && (result.last[7] == num[7])
248
+ result.reverse
249
+ end
250
+
251
+ end
252
+ end
253
+ end