This repository has been archived by the owner on Nov 1, 2017. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 168
/
upload.rb
120 lines (95 loc) · 3.85 KB
/
upload.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#!/usr/bin/env ruby
require "net/http"
require 'net/https'
require "rubygems"
require 'xmlsimple'
require "time"
require 'mime/types'
module Net
class HTTP
def urlencode(str)
str.gsub(/[^a-zA-Z0-9_\.\-]/n) {|s| sprintf('%%%02x', s[0]) }
end
def post_form(path, params)
req = Net::HTTP::Post.new(path)
req.body = params.map {|k,v| "#{urlencode(k.to_s)}=#{urlencode(v.to_s)}" }.join('&')
req.content_type = 'application/x-www-form-urlencoded'
self.request req
end
def post_multipart(path, params)
boundary = "#{rand(1000000)}boundryofdoomydoom#{rand(1000000)}"
fp = []
files = []
params.each do |k,v|
if v.respond_to?(:path) and v.respond_to?(:read) then
filename = v.path
content = v.read
mime_type = MIME::Types.type_for(filename)[0] || MIME::Types["application/octet-stream"][0]
fp.push(prepare_param("Content-Type", mime_type.simplified))
files.push("Content-Disposition: form-data; name=\"#{urlencode(k.to_s)}\"; filename=\"#{ filename }\"\r\nContent-Type: #{ mime_type.simplified }\r\n\r\n#{ content }\r\n")
else
fp.push(prepare_param(k,v))
end
end
self.post(path, "--#{boundary}\r\n" + (fp + files).join("--#{boundary}\r\n") + "--#{boundary}--", {
"Content-Type" => "multipart/form-data; boundary=#{boundary}",
"User-Agent" => "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/523.10.6 (KHTML, like Gecko) Version/3.0.4 Safari/523.10.6"
})
end
def prepare_param(name, value)
"Content-Disposition: form-data; name=\"#{urlencode(name.to_s)}\"\r\n\r\n#{value}\r\n"
end
end
end
def die(message, with_usage = false)
puts "ERROR: #{message}"
puts %Q|Usage: #{__FILE__} file_to_upload [repo]
file_to_upload: File to be uploaded.
repo: GitHub repo to upload to. Ex: "tekkub/sandbox". If omitted, the repo from `git remote show origin` will be used.| if with_usage
exit 1
end
user = `git config --global github.user`.strip
token = `git config --global github.token`.strip
die "Cannot find login credentials" if user.empty? || token.empty?
die "No file specified", true unless filename = ARGV[0]
die "Target file does not exist" unless File.size?(filename)
repo = ARGV[1]
repo = $1 if repo.nil? && `git remote show origin` =~ /[email protected]:(.+?)\.git/
die("Unable to find GitHub repo", true) if repo.nil?
file = File.new(filename)
mime_type = MIME::Types.type_for(filename)[0] || MIME::Types["application/octet-stream"][0]
# Check for conflict
url = URI.parse "https://github.com/"
http = Net::HTTP.new url.host, url.port
http.use_ssl = url.scheme == 'https'
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
res = http.get("/#{repo}/downloads?login=#{user}&token=#{token}")
die "File has already been uploaded" if res.body =~ /<td><a href="https?:\/\/s3.amazonaws.com\/github\/downloads\/#{repo.gsub(/\//, "\/")}\/#{filename}.+">#{filename}<\/a><\/td>/
# Get the info we need from GitHub to post to S3
res = http.post_form("/#{repo}/downloads", {
:file_size => File.size(filename),
:content_type => mime_type.simplified,
:file_name => filename,
:description => '',
:login => user,
:token => token,
})
die "Repo not found" if res.class == Net::HTTPNotFound
date = res["Date"]
data = XmlSimple.xml_in(res.body)
die "Unable to authorize upload" if data["signature"].nil?
# Post to S3
url = URI.parse "http://github.s3.amazonaws.com/"
http = Net::HTTP.new url.host, url.port
res = http.post_multipart("/", {
:key => "#{data["prefix"].first}#{filename}",
:Filename => filename,
:policy => data["policy"].first,
:AWSAccessKeyId => data["accesskeyid"].first,
:signature => data["signature"].first,
:acl => data["acl"].first,
:file => file,
:success_action_status => 201
})
die "File upload failed" unless res.class == Net::HTTPCreated
puts "File uploaded successfully"