OpenS3 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/bin/opens3 ADDED
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'rack'
5
+ require 'opens3/opens3'
6
+ require 'opens3/tools'
7
+ require 'opens3/rack_file'
8
+ require 'json'
9
+ require 'yaml'
10
+ require 'digest/md5'
11
+ require 'trollop'
12
+ require 'uri'
13
+ require 'digest'
14
+
15
+ opts = Trollop::options do
16
+ opt :dir, "Set OpenS3 storage directory", :short => '-d', :type => :string
17
+ opt :port, "Set OpenS3 server port", :short => '-p', :type => :int
18
+ opt :config, "Set config file", :short => '-c', :type => :string
19
+ opt :token, "Set token string", :short => '-t', :type => :string
20
+ end
21
+
22
+ if opts[:dir] and opts[:port] and opts[:token] and !opts[:config]
23
+ @port = opts[:port]
24
+ @dir = opts[:dir]
25
+ @token = opts[:token]
26
+
27
+ elsif !opts[:dir] and !opts[:token] and !opts[:port] and opts[:config]
28
+ unless !File.exists?(opts[:config])
29
+ cfg = YAML::load(File.open(opts[:config]))
30
+ @port = cfg['port']
31
+ @dir = cfg['dir']
32
+ @token = cfg['token']
33
+ end
34
+ end
35
+
36
+ if @port and @dir and @token
37
+ Rack::Handler::Thin.run OpenS3.new(@dir,@token), :Port => @port.to_i
38
+ else
39
+ puts "No port/directory/token or config file specified"
40
+ end
data/lib/opens3.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'opens3/opens3'
2
+ require 'opens3/tools'
3
+ require 'opens3/rack_file'
@@ -0,0 +1,165 @@
1
+ class OpenS3
2
+
3
+ def initialize(path, token=nil)
4
+ @file_path = path
5
+ @srv_token = token ? Digest::SHA512.hexdigest(token) : Digest::SHA512.hexdigest("OpenS3")
6
+ puts "Token: #{@srv_token}"
7
+ end
8
+
9
+ def call(env)
10
+
11
+ handle_url(env)
12
+ end
13
+
14
+ def handle_url(data)
15
+
16
+ req = Rack::Request.new(data)
17
+ @path = req.path
18
+ parsed_query = Rack::Utils.parse_nested_query(req.query_string)
19
+ get_token = parsed_query['token']
20
+ post_token = req.params['token']
21
+ if @path == '/'
22
+ [200, {"Content-Type" => "text/html"}, %{<!DOCTYPE html5><html><head><title></title></head><body><form action="http://localhost:8000/upload" enctype="multipart/form-data" method="post">Select file: <input name="file" type="file" /><br /><input type="text" name="bucket" placeholder="bucket name"/><input type="submit" value="Send" /><input type="text" name="token"></form></body></html>}]
23
+ elsif @path == '/info'
24
+ send_server_info(req)
25
+ else
26
+ if req.post?
27
+ if post_token == @srv_token
28
+ params = req.params['file']
29
+ bucket = req.params['bucket']
30
+ if !params.nil?
31
+ case @path
32
+ when '/upload'
33
+ upload_file(params, bucket)
34
+ else
35
+ send_error(:wrong_path)
36
+ end
37
+ else
38
+ send_error(:no_file)
39
+ end
40
+
41
+ else
42
+ send_error(:token_error)
43
+ end
44
+ elsif req.get?
45
+ if get_token == @srv_token
46
+ case @path
47
+
48
+ when '/file'
49
+ download_file(req.query_string)
50
+ when '/list'
51
+ send_file_list(req.query_string)
52
+
53
+ else
54
+ send_error(:wrong_path)
55
+ end
56
+ else
57
+ send_error(:token_error)
58
+ end
59
+ end
60
+
61
+
62
+ end
63
+
64
+ end
65
+
66
+ def upload_file(params, bucket)
67
+ if bucket.nil? or bucket.empty?
68
+ send_error(:bucket_not_specified)
69
+ else
70
+
71
+ f = RackFile.new(params[:tempfile], params[:filename], params[:type], bucket, @file_path).save
72
+ if f
73
+ @response = {:saved=>true, :url=>URI.escape("/file?name=#{params[:filename]}&bucket=#{bucket}")}
74
+ [200, {"Content-Type" => "application/json"}, "#{@response.to_json}"]
75
+ else
76
+ send_error(:file_already_exists)
77
+ end
78
+
79
+ end
80
+
81
+ end
82
+
83
+ def send_file_list(bucket)
84
+ query = Rack::Utils.parse_nested_query(bucket)
85
+ if query['bucket'].nil?
86
+ send_error(:bucket_not_specified)
87
+ else
88
+ if Dir.exists?("#{@file_path}/#{query['bucket']}")
89
+ files = Dir["#{@file_path}/#{query['bucket']}/*/"].map { |a| File.basename(a) }
90
+ file_names = Array.new
91
+ files.each do |d|
92
+ meta = YAML::load(File.open("#{@file_path}/#{query['bucket']}/#{d}/meta"))
93
+ file_names.push(meta['filename'])
94
+ end
95
+ [200, {"Content-Type" => "application/json"}, "#{file_names.to_json}"]
96
+ else
97
+ send_error(:bucket_not_found)
98
+ end
99
+ end
100
+
101
+ end
102
+
103
+ def download_file(query)
104
+
105
+ query = Rack::Utils.parse_nested_query(query)
106
+ file_name = query['name']
107
+ expiry = Time.at(query['expire'].to_i)
108
+ if expiry < Time.now or expiry.nil?
109
+ send_error(:expired_link)
110
+ else
111
+ if query['bucket'].nil?
112
+ send_error(:bucket_not_specified)
113
+ else
114
+ if !query['name'].nil?
115
+ if Dir.exists?("#{@file_path}/#{query['bucket']}")
116
+ files = Dir["#{@file_path}/#{query['bucket']}/*/"].map { |a| File.basename(a) }
117
+ files.each do |d|
118
+ meta = YAML::load(File.open("#{@file_path}/#{query['bucket']}/#{d}/meta"))
119
+ if meta['filename'] == file_name
120
+ @good_folder = d
121
+ @good_meta = meta
122
+ end
123
+ end
124
+ if @good_folder.nil?
125
+ send_error(:file_not_found)
126
+ else
127
+ [200, {"Content-Type" => "#{@good_meta['type']}; charset=UTF-8", "Content-Disposition" => "attachment; filename=#{@good_meta['filename']}"}, File.open("#{@file_path}/#{query['bucket']}/#{@good_folder}/content")]
128
+ end
129
+ else
130
+ send_error(:file_not_found)
131
+ end
132
+ else
133
+ [200, {"Content-Type" => "application/json"}, "#{{:error=>true}.to_json}"]
134
+ end
135
+ end
136
+ end
137
+
138
+ end
139
+
140
+ def send_error(type)
141
+ case type
142
+ when :wrong_path
143
+ [404, {"Content-Type" => "application/json"}, "#{{:error=>true, :type=>100}.to_json}"]
144
+ when :file_not_found
145
+ [404, {"Content-Type" => "application/json"}, "#{{:error=>true, :type=>101}.to_json}"]
146
+ when :file_already_exists
147
+ [200, {"Content-Type" => "application/json"}, "#{{:error=>true, :type=>102}.to_json}"]
148
+ when :bucket_not_found
149
+ [404, {"Content-Type" => "application/json"}, "#{{:error=>true, :type=>103}.to_json}"]
150
+ when :bucket_not_specified
151
+ [400, {"Content-Type" => "application/json"}, "#{{:error=>true, :type=>104}.to_json}"]
152
+ when :expired_link
153
+ [200, {"Content-Type" => "application/json"}, "#{{:error=>true, :type=>105}.to_json}"]
154
+ when :token_error
155
+ [403, {"Content-Type" => "application/json"}, "#{{:error=>true, :type=>106}.to_json}"]
156
+ when :no_file
157
+ [200, {"Content-Type" => "application/json"}, "#{{:error=>true, :type=>107}.to_json}"]
158
+ end
159
+ end
160
+
161
+ def send_server_info(request)
162
+ [200, {"Content-Type" => "application/json"}, "#{{:hostname=>request.host_with_port}.to_json}"]
163
+ end
164
+ end
165
+
@@ -0,0 +1,30 @@
1
+ class RackFile
2
+ def initialize(temp_file, filename, type, bucket, path)
3
+ @temp_file = temp_file.path
4
+ @filename = filename
5
+ @type = type
6
+ @bucket = bucket
7
+ @path = path
8
+ end
9
+
10
+ def save
11
+ begin
12
+ key = String.new.random_string
13
+ file_md5 = Digest::MD5.hexdigest(@temp_file)
14
+ folder_name = Digest::MD5.hexdigest("#{@file_md5}-#{Time.now}-#{key}")
15
+ path = "#{@path}/#{@bucket}/#{@filename}"
16
+ FileUtils.mkdir_p(path)
17
+ meta = Hash.new
18
+ meta['type']= @type
19
+ meta['md5'] = file_md5
20
+ meta['filename'] = @filename
21
+ meta = meta.to_yaml
22
+ File.open("#{path}/meta", 'w') do |out|
23
+ out.write(meta)
24
+ end
25
+ FileUtils.mv(@temp_file, "#{path}/content")
26
+ rescue SystemCallError
27
+ false
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,5 @@
1
+ class String
2
+ def random_string
3
+ (0...8).map{65.+(rand(25)).chr}.join
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: OpenS3
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Pablo Merino
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-21 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: json
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rack
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: trollop
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: Build your own storage server
63
+ email: pablo.perso1995@gmail.cin
64
+ executables:
65
+ - opens3
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - lib/opens3/opens3.rb
70
+ - lib/opens3/rack_file.rb
71
+ - lib/opens3/tools.rb
72
+ - lib/opens3.rb
73
+ - !binary |-
74
+ YmluL29wZW5zMw==
75
+ homepage: https://github.com/pablo-merino/opens3
76
+ licenses: []
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ! '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubyforge_project: nowarning
95
+ rubygems_version: 1.8.21
96
+ signing_key:
97
+ specification_version: 3
98
+ summary: A storage server
99
+ test_files: []