geminabox 0.9.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of geminabox might be problematic. Click here for more details.

@@ -4,6 +4,7 @@ require 'builder'
4
4
  require 'sinatra/base'
5
5
  require 'rubygems/builder'
6
6
  require 'rubygems/indexer'
7
+ require 'rubygems/package'
7
8
  require 'hostess'
8
9
  require 'geminabox/version'
9
10
  require 'rss/atom'
@@ -36,6 +37,7 @@ class Geminabox < Sinatra::Base
36
37
  autoload :GemVersionCollection, "geminabox/gem_version_collection"
37
38
  autoload :GemVersion, "geminabox/gem_version"
38
39
  autoload :DiskCache, "geminabox/disk_cache"
40
+ autoload :IncomingGem, "geminabox/incoming_gem"
39
41
 
40
42
  before do
41
43
  headers 'X-Powered-By' => "geminabox #{GeminaboxVersion}"
@@ -96,58 +98,40 @@ class Geminabox < Sinatra::Base
96
98
  end
97
99
 
98
100
  post '/upload' do
99
- if File.exists? Geminabox.data
100
- error_response( 500, "Please ensure #{File.expand_path(Geminabox.data)} is a directory." ) unless File.directory? Geminabox.data
101
- error_response( 500, "Please ensure #{File.expand_path(Geminabox.data)} is writable by the geminabox web server." ) unless File.writable? Geminabox.data
102
- else
103
- begin
104
- FileUtils.mkdir_p(settings.data)
105
- rescue Errno::EACCES, Errno::ENOENT, RuntimeError => e
106
- error_response( 500, "Could not create #{File.expand_path(Geminabox.data)}.\n#{e}\n#{e.message}" )
107
- end
108
- end
109
-
110
- unless params[:file] && (tmpfile = params[:file][:tempfile]) && (name = params[:file][:filename])
101
+ unless params[:file] && params[:file][:filename] && (tmpfile = params[:file][:tempfile])
111
102
  @error = "No file selected"
112
103
  halt [400, erb(:upload)]
113
104
  end
105
+ handle_incoming_gem(IncomingGem.new(tmpfile))
106
+ end
114
107
 
115
- FileUtils.mkdir_p(File.join(settings.data, "gems"))
116
-
117
- tmpfile.binmode
118
-
119
- gem_name = File.basename(name)
120
- dest_filename = File.join(settings.data, "gems", gem_name)
121
-
122
- if Geminabox.disallow_replace? and File.exist?(dest_filename)
123
- existing_file_digest = Digest::SHA1.file(dest_filename).hexdigest
124
- tmpfile_digest = Digest::SHA1.file(tmpfile.path).hexdigest
125
-
126
- if existing_file_digest != tmpfile_digest
127
- error_response(409, "Updating an existing gem is not permitted.\nYou should either delete the existing version, or change your version number.")
128
- else
129
- error_response(200, "Ignoring upload, you uploaded the same thing previously.")
108
+ post '/api/v1/gems' do
109
+ begin
110
+ handle_incoming_gem(IncomingGem.new(request.body))
111
+ rescue Object => o
112
+ File.open "/tmp/debug.txt", "a" do |io|
113
+ io.puts o, o.backtrace
130
114
  end
131
115
  end
116
+ end
132
117
 
133
- atomic_write(dest_filename) do |f|
134
- while blk = tmpfile.read(65536)
135
- f << blk
136
- end
137
- end
138
- reindex
118
+ private
119
+
120
+ def handle_incoming_gem(gem)
121
+ prepare_data_folders
122
+ error_response(400, "Cannot process gem") unless gem.valid?
123
+ handle_replacement(gem)
124
+ write_and_index(gem)
139
125
 
140
126
  if api_request?
141
- "Gem #{gem_name} received and indexed."
127
+ "Gem #{gem.name} received and indexed."
142
128
  else
143
129
  redirect url("/")
144
130
  end
145
131
  end
146
132
 
147
- private
148
-
149
133
  def api_request?
150
- request.accept.first == "text/plain"
134
+ request.accept.first != "text/html"
151
135
  end
152
136
 
153
137
  def error_response(code, message)
@@ -164,6 +148,43 @@ HTML
164
148
  halt [code, html]
165
149
  end
166
150
 
151
+ def prepare_data_folders
152
+ if File.exists? Geminabox.data
153
+ error_response( 500, "Please ensure #{File.expand_path(Geminabox.data)} is a directory." ) unless File.directory? Geminabox.data
154
+ error_response( 500, "Please ensure #{File.expand_path(Geminabox.data)} is writable by the geminabox web server." ) unless File.writable? Geminabox.data
155
+ else
156
+ begin
157
+ FileUtils.mkdir_p(settings.data)
158
+ rescue Errno::EACCES, Errno::ENOENT, RuntimeError => e
159
+ error_response( 500, "Could not create #{File.expand_path(Geminabox.data)}.\n#{e}\n#{e.message}" )
160
+ end
161
+ end
162
+
163
+ FileUtils.mkdir_p(File.join(settings.data, "gems"))
164
+ end
165
+
166
+ def handle_replacement(gem)
167
+ if Geminabox.disallow_replace? and File.exist?(gem.dest_filename)
168
+ existing_file_digest = Digest::SHA1.file(gem.dest_filename).hexdigest
169
+
170
+ if existing_file_digest != gem.hexdigest
171
+ error_response(409, "Updating an existing gem is not permitted.\nYou should either delete the existing version, or change your version number.")
172
+ else
173
+ error_response(200, "Ignoring upload, you uploaded the same thing previously.")
174
+ end
175
+ end
176
+ end
177
+
178
+ def write_and_index(gem)
179
+ tmpfile = gem.gem_data
180
+ atomic_write(gem.dest_filename) do |f|
181
+ while blk = tmpfile.read(65536)
182
+ f << blk
183
+ end
184
+ end
185
+ reindex
186
+ end
187
+
167
188
  def reindex(force_rebuild = false)
168
189
  Geminabox.fixup_bundler_rubygems!
169
190
  force_rebuild = true unless settings.incremental_updates
@@ -0,0 +1,49 @@
1
+ class Geminabox::IncomingGem
2
+ def initialize(gem_data, root_path = Geminabox.settings.data)
3
+ unless gem_data.respond_to? :read
4
+ raise ArgumentError, "Expected an instance of IO"
5
+ end
6
+
7
+ digest = Digest::SHA1.new
8
+ @tempfile = Tempfile.new("gem", :encoding => 'binary')
9
+ while data = gem_data.read(1024**2)
10
+ @tempfile.write data
11
+ digest << data
12
+ end
13
+ @tempfile.close
14
+ @sha1 = digest.hexdigest
15
+
16
+ @root_path = root_path
17
+ end
18
+
19
+ def gem_data
20
+ File.open(@tempfile.path, "rb")
21
+ end
22
+
23
+ def valid?
24
+ spec && spec.name && spec.version
25
+ rescue Gem::Package::Error
26
+ false
27
+ end
28
+
29
+ def spec
30
+ unless @spec
31
+ Gem::Package.open(gem_data, "r", nil) do |pkg|
32
+ @spec = pkg.metadata
33
+ end
34
+ end
35
+ @spec
36
+ end
37
+
38
+ def name
39
+ "#{spec.name}-#{spec.version}.gem"
40
+ end
41
+
42
+ def dest_filename
43
+ File.join(@root_path, "gems", name)
44
+ end
45
+
46
+ def hexdigest
47
+ @sha1
48
+ end
49
+ end
@@ -1 +1 @@
1
- GeminaboxVersion = '0.9.0' unless defined? GeminaboxVersion
1
+ GeminaboxVersion = '0.10.0' unless defined? GeminaboxVersion
@@ -10,7 +10,8 @@ class GeminaboxClient
10
10
  @http_client.set_auth(url_for(:upload), @username, @password) if @username or @password
11
11
  @http_client.www_auth.basic_auth.challenge(url_for(:upload)) # Workaround: https://github.com/nahi/httpclient/issues/63
12
12
  @http_client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
13
- @http_client.send_timeout = 600
13
+ @http_client.send_timeout = 0
14
+ @http_client.receive_timeout = 0
14
15
  end
15
16
 
16
17
  def extract_username_and_password_from_url!(url)
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: geminabox
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.9.0
5
+ version: 0.10.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Tom Lea
@@ -166,6 +166,7 @@ files:
166
166
  - lib/geminabox/disk_cache.rb
167
167
  - lib/geminabox/gem_version.rb
168
168
  - lib/geminabox/gem_version_collection.rb
169
+ - lib/geminabox/incoming_gem.rb
169
170
  - lib/geminabox/indexer.rb
170
171
  - lib/geminabox/version.rb
171
172
  - lib/geminabox.rb
@@ -197,7 +198,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
197
198
  - !ruby/object:Gem::Version
198
199
  segments:
199
200
  - 0
200
- hash: 332321015016906523
201
+ hash: 1008215541658349139
201
202
  version: '0'
202
203
  required_rubygems_version: !ruby/object:Gem::Requirement
203
204
  none: false
@@ -206,7 +207,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
206
207
  - !ruby/object:Gem::Version
207
208
  segments:
208
209
  - 0
209
- hash: 332321015016906523
210
+ hash: 1008215541658349139
210
211
  version: '0'
211
212
  requirements: []
212
213
  rubyforge_project: