gist 4.5.0 → 6.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +75 -23
- data/bin/gist +28 -12
- data/gist.gemspec +1 -1
- data/lib/gist.rb +140 -34
- data/spec/auth_token_file_spec.rb +2 -2
- data/spec/ghe_spec.rb +12 -5
- data/spec/rawify_spec.rb +10 -1
- data/spec/shorten_spec.rb +17 -4
- data/spec/spec_helper.rb +1 -1
- metadata +3 -8
- data/.gitignore +0 -8
- data/build/gist +0 -2034
- data/build/gist.1 +0 -230
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 78e3d009d0e3e3a535d20e8d7e0582705c6ea61308958c3f59a4d4a2e365fa3c
|
4
|
+
data.tar.gz: 23df778298090151ce7e2b8f3dbb8f97786bc7d576f218be1aeb454123090e91
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70506cc45562b725085e2f10d5627a3ac4c700fa6e599e39a6625629fbd2c63903b2d42a4a95d9642f0ac01893bd8de27d72acb7e4622eaa44ab4ea96b08840c
|
7
|
+
data.tar.gz: b3476f46cb844603a169e3a67fae3bb37e5399494ddec6c78178f4bb664a90cda642c5be780ea007d12e96cc96312f695b86827872bc4947603c092a4e3d6774
|
data/README.md
CHANGED
@@ -21,6 +21,11 @@ upload content to https://gist.github.com/.
|
|
21
21
|
|
22
22
|
brew install gist
|
23
23
|
|
24
|
+
For FreeBSD, gist lives in ports
|
25
|
+
|
26
|
+
pkg install gist
|
27
|
+
|
28
|
+
|
24
29
|
## Command
|
25
30
|
|
26
31
|
To upload the contents of `a.rb` just:
|
@@ -70,30 +75,88 @@ upload content to https://gist.github.com/.
|
|
70
75
|
gist -l : all gists for authed user
|
71
76
|
gist -l defunkt : list defunkt's public gists
|
72
77
|
|
78
|
+
To read a gist and print it to STDOUT
|
79
|
+
|
80
|
+
gist -r GIST_ID
|
81
|
+
gist -r 374130
|
82
|
+
|
73
83
|
See `gist --help` for more detail.
|
74
84
|
|
75
85
|
## Login
|
76
86
|
|
77
|
-
|
78
|
-
|
79
|
-
an
|
87
|
+
Before you use `gist` for the first time you will need to log in. There are two supported login flows:
|
88
|
+
|
89
|
+
1. The Github device-code Oauth flow. This is the default for authenticating to github.com, and can be enabled for Github Enterprise by creating an Oauth app, and exporting the environment variable `GIST_CLIENT_ID` with the client id of the Oauth app.
|
90
|
+
2. The (deprecated) username and password token exchange flow. This is the default for GitHub Enterprise, and can be used to log into github.com by exporting the environment variable `GIST_USE_USERNAME_AND_PASSWORD`.
|
91
|
+
|
92
|
+
### The device-code flow
|
93
|
+
|
94
|
+
This flow allows you to obtain a token by logging into GitHub in the browser and typing a verification code. This is the preferred mechanism.
|
80
95
|
|
81
96
|
gist --login
|
82
|
-
|
97
|
+
Requesting login parameters...
|
98
|
+
Please sign in at https://github.com/login/device
|
99
|
+
and enter code: XXXX-XXXX
|
100
|
+
Success! https://github.com/settings/connections/applications/4f7ec0d4eab38e74384e
|
101
|
+
|
102
|
+
The returned access_token is stored in `~/.gist` and used for all future gisting. If you need to you can revoke access from https://github.com/settings/connections/applications/4f7ec0d4eab38e74384e.
|
103
|
+
|
104
|
+
### The username-password flow
|
105
|
+
|
106
|
+
This flow asks for your GitHub username and password (and 2FA code), and exchanges them for a token with the "gist" permission (your username and password are not stored). This mechanism is deprecated by GitHub, but may still work with GitHub Enterprise.
|
107
|
+
|
108
|
+
gist --login
|
109
|
+
Obtaining OAuth2 access_token from GitHub.
|
83
110
|
GitHub username: ConradIrwin
|
84
111
|
GitHub password:
|
85
112
|
2-factor auth code:
|
86
|
-
Success! https://github.com/settings/
|
113
|
+
Success! https://github.com/settings/tokens
|
87
114
|
|
88
115
|
This token is stored in `~/.gist` and used for all future gisting. If you need to
|
89
|
-
you can revoke it from https://github.com/settings/
|
90
|
-
file.
|
91
|
-
|
92
|
-
|
116
|
+
you can revoke it from https://github.com/settings/tokens, or just delete the
|
117
|
+
file.
|
118
|
+
|
119
|
+
#### Password-less login
|
120
|
+
|
121
|
+
If you have a complicated authorization requirement you can manually create a
|
122
|
+
token file by pasting a GitHub token with `gist` scope (and maybe the `user:email`
|
123
|
+
for GitHub Enterprise) into a file called `~/.gist`. You can create one from
|
124
|
+
https://github.com/settings/tokens
|
125
|
+
|
126
|
+
This file should contain only the token (~40 hex characters), and to make it
|
127
|
+
easier to edit, can optionally have a final newline (`\n` or `\r\n`).
|
93
128
|
|
94
|
-
|
129
|
+
For example, one way to create this file would be to run:
|
95
130
|
|
96
|
-
|
131
|
+
(umask 0077 && echo MY_SECRET_TOKEN > ~/.gist)
|
132
|
+
|
133
|
+
The `umask` ensures that the file is only accessible from your user account.
|
134
|
+
|
135
|
+
### GitHub Enterprise
|
136
|
+
|
137
|
+
If you'd like `gist` to use your locally installed [GitHub Enterprise](https://enterprise.github.com/),
|
138
|
+
you need to export the `GITHUB_URL` environment variable (usually done in your `~/.bashrc`).
|
139
|
+
|
140
|
+
export GITHUB_URL=http://github.internal.example.com/
|
141
|
+
|
142
|
+
Once you've done this and restarted your terminal (or run `source ~/.bashrc`), gist will
|
143
|
+
automatically use GitHub Enterprise instead of the public github.com
|
144
|
+
|
145
|
+
Your token for GitHub Enterprise will be stored in `.gist.<protocol>.<server.name>[.<port>]` (e.g.
|
146
|
+
`~/.gist.http.github.internal.example.com` for the GITHUB_URL example above) instead of `~/.gist`.
|
147
|
+
|
148
|
+
If you have multiple servers or use Enterprise and public GitHub often, you can work around this by creating scripts
|
149
|
+
that set the env var and then run `gist`. Keep in mind that to use the public GitHub you must unset the env var. Just
|
150
|
+
setting it to the public URL will not work. Use `unset GITHUB_URL`
|
151
|
+
|
152
|
+
### Token file format
|
153
|
+
|
154
|
+
If you cannot use passwords, as most Enterprise installations do, you can generate the token via the web interface
|
155
|
+
and then simply save the string in the correct file. Avoid line breaks or you might see:
|
156
|
+
```
|
157
|
+
$ gist -l
|
158
|
+
Error: Bad credentials
|
159
|
+
```
|
97
160
|
|
98
161
|
# Library
|
99
162
|
|
@@ -108,11 +171,10 @@ If you need more advanced features you can also pass:
|
|
108
171
|
* `:public` if you want your gist to have a guessable url.
|
109
172
|
* `:description` to add a description to your gist.
|
110
173
|
* `:update` to update an existing gist (can be a URL or an id).
|
111
|
-
* `:anonymous` to submit an anonymous gist (default is false).
|
112
174
|
* `:copy` to copy the resulting URL to the clipboard (default is false).
|
113
175
|
* `:open` to open the resulting URL in a browser (default is false).
|
114
176
|
|
115
|
-
NOTE: The access_token must have the
|
177
|
+
NOTE: The access_token must have the `gist` scope and may also require the `user:email` scope.
|
116
178
|
|
117
179
|
If you want to upload multiple files in the same gist, you can:
|
118
180
|
|
@@ -126,16 +188,6 @@ NOTE: The access_token must have the "gist" scope.
|
|
126
188
|
This will take them through the process of obtaining an OAuth2 token, and storing it
|
127
189
|
in `~/.gist`, where it can later be read by `Gist.gist`
|
128
190
|
|
129
|
-
## GitHub enterprise
|
130
|
-
|
131
|
-
If you'd like `gist` to use your locally installed [GitHub Enterprise](https://enterprise.github.com/),
|
132
|
-
you need to export the `GITHUB_URL` environment variable in your `~/.bashrc`.
|
133
|
-
|
134
|
-
export GITHUB_URL=http://github.internal.example.com/
|
135
|
-
|
136
|
-
Once you've done this and restarted your terminal (or run `source ~/.bashrc`), gist will
|
137
|
-
automatically use github enterprise instead of the public github.com
|
138
|
-
|
139
191
|
## Configuration
|
140
192
|
|
141
193
|
If you'd like `-o` or `-c` to be the default when you use the gist executable, add an
|
data/bin/gist
CHANGED
@@ -24,16 +24,12 @@ specified STDIN will be read. The default filename for STDIN is "a.rb", and all
|
|
24
24
|
filenames can be overridden by repeating the "-f" flag. The most useful reason
|
25
25
|
to do this is to change the syntax highlighting.
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
Oauth2 access token. This is stored and used by gist in the future.
|
27
|
+
All gists must to be associated with a GitHub account, so you will need to login with
|
28
|
+
`gist --login` to obtain an OAuth2 access token. This is stored and used by gist in the future.
|
30
29
|
|
31
30
|
Private gists do not have guessable URLs and can be created with "-p", you can
|
32
31
|
also set the description at the top of the gist by passing "-d".
|
33
32
|
|
34
|
-
Anonymous gists are not associated with your GitHub account, they can be created
|
35
|
-
with "-a" even after you have used "gist --login".
|
36
|
-
|
37
33
|
If you would like to shorten the resulting gist URL, use the -s flag. This will
|
38
34
|
use GitHub's URL shortener, git.io. You can also use -R to get the link to the
|
39
35
|
raw gist.
|
@@ -47,7 +43,11 @@ Instead of creating a new gist, you can update an existing one by passing its ID
|
|
47
43
|
or URL with "-u". For this to work, you must be logged in, and have created the
|
48
44
|
original gist with the same GitHub account.
|
49
45
|
|
50
|
-
|
46
|
+
If you want to skip empty files, use the --skip-empty flag. If all files are
|
47
|
+
empty no gist will be created.
|
48
|
+
|
49
|
+
Usage: #{executable_name} [-o|-c|-e] [-p] [-s] [-R] [-d DESC] [-u URL]
|
50
|
+
[--skip-empty] [-P] [-f NAME|-t EXT]* FILE*
|
51
51
|
#{executable_name} --login
|
52
52
|
#{executable_name} [-l|-r]
|
53
53
|
|
@@ -88,10 +88,6 @@ Usage: #{executable_name} [-o|-c|-e] [-p] [-s] [-R] [-d DESC] [-a] [-u URL] [-P]
|
|
88
88
|
options[:update] = update
|
89
89
|
end
|
90
90
|
|
91
|
-
opts.on("-a", "--anonymous", "Create an anonymous gist.") do
|
92
|
-
options[:anonymous] = true
|
93
|
-
end
|
94
|
-
|
95
91
|
opts.on("-c", "--copy", "Copy the resulting URL to the clipboard") do
|
96
92
|
options[:copy] = true
|
97
93
|
end
|
@@ -107,6 +103,10 @@ Usage: #{executable_name} [-o|-c|-e] [-p] [-s] [-R] [-d DESC] [-a] [-u URL] [-P]
|
|
107
103
|
|
108
104
|
opts.on("--no-open")
|
109
105
|
|
106
|
+
opts.on("--skip-empty", "Skip gisting empty files") do
|
107
|
+
options[:skip_empty] = true
|
108
|
+
end
|
109
|
+
|
110
110
|
opts.on("-P", "--paste", "Paste from the clipboard to gist") do
|
111
111
|
options[:paste] = true
|
112
112
|
end
|
@@ -123,6 +123,10 @@ Usage: #{executable_name} [-o|-c|-e] [-p] [-s] [-R] [-d DESC] [-a] [-u URL] [-P]
|
|
123
123
|
options[:read] = id
|
124
124
|
end
|
125
125
|
|
126
|
+
opts.on("--delete [ URL | ID ]", "Delete a gist") do |id|
|
127
|
+
options[:delete] = id
|
128
|
+
end
|
129
|
+
|
126
130
|
opts.on_tail("-h","--help", "Show this message.") do
|
127
131
|
puts opts
|
128
132
|
exit
|
@@ -136,6 +140,12 @@ Usage: #{executable_name} [-o|-c|-e] [-p] [-s] [-R] [-d DESC] [-a] [-u URL] [-P]
|
|
136
140
|
end.parse!
|
137
141
|
|
138
142
|
begin
|
143
|
+
if Gist.auth_token.nil?
|
144
|
+
puts 'Please log in with `gist --login`. ' \
|
145
|
+
'(GitHub now requires credentials to gist https://bit.ly/2GBBxKw)'
|
146
|
+
exit(1)
|
147
|
+
end
|
148
|
+
|
139
149
|
options[:output] = if options[:embed] && options[:shorten]
|
140
150
|
raise Gist::Error, "--embed does not make sense with --shorten"
|
141
151
|
elsif options[:embed]
|
@@ -167,6 +177,11 @@ begin
|
|
167
177
|
exit
|
168
178
|
end
|
169
179
|
|
180
|
+
if options.key? :delete
|
181
|
+
Gist.delete_gist(options[:delete])
|
182
|
+
exit
|
183
|
+
end
|
184
|
+
|
170
185
|
if options[:paste]
|
171
186
|
puts Gist.gist(Gist.paste, options)
|
172
187
|
else
|
@@ -186,7 +201,8 @@ begin
|
|
186
201
|
end
|
187
202
|
end
|
188
203
|
|
189
|
-
|
204
|
+
output = Gist.multi_gist(files, options)
|
205
|
+
puts output if output
|
190
206
|
end
|
191
207
|
|
192
208
|
rescue Gist::Error => e
|
data/gist.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.email = ['conrad.irwin@gmail.com', 'rkingist@sharpsaw.org']
|
10
10
|
s.authors = ['Conrad Irwin', '☈king']
|
11
11
|
s.license = 'MIT'
|
12
|
-
s.files = `git ls-files`.split("\n")
|
12
|
+
s.files = `git ls-files`.split("\n") - Dir.glob("build/*") - [".gitignore"]
|
13
13
|
s.require_paths = ["lib"]
|
14
14
|
|
15
15
|
s.executables << 'gist'
|
data/lib/gist.rb
CHANGED
@@ -12,23 +12,27 @@ end
|
|
12
12
|
module Gist
|
13
13
|
extend self
|
14
14
|
|
15
|
-
VERSION = '
|
15
|
+
VERSION = '6.0.0'
|
16
16
|
|
17
17
|
# A list of clipboard commands with copy and paste support.
|
18
18
|
CLIPBOARD_COMMANDS = {
|
19
|
+
'pbcopy' => 'pbpaste',
|
19
20
|
'xclip' => 'xclip -o',
|
20
21
|
'xsel -i' => 'xsel -o',
|
21
|
-
'
|
22
|
-
'putclip' => 'getclip'
|
22
|
+
'putclip' => 'getclip',
|
23
23
|
}
|
24
24
|
|
25
25
|
GITHUB_API_URL = URI("https://api.github.com/")
|
26
|
-
|
26
|
+
GITHUB_URL = URI("https://github.com/")
|
27
|
+
GIT_IO_URL = URI("https://git.io")
|
27
28
|
|
28
29
|
GITHUB_BASE_PATH = ""
|
29
30
|
GHE_BASE_PATH = "/api/v3"
|
30
31
|
|
32
|
+
GITHUB_CLIENT_ID = '4f7ec0d4eab38e74384e'
|
33
|
+
|
31
34
|
URL_ENV_NAME = "GITHUB_URL"
|
35
|
+
CLIENT_ID_ENV_NAME = "GIST_CLIENT_ID"
|
32
36
|
|
33
37
|
USER_AGENT = "gist/#{VERSION} (Net::HTTP, #{RUBY_DESCRIPTION})"
|
34
38
|
|
@@ -44,7 +48,7 @@ module Gist
|
|
44
48
|
module AuthTokenFile
|
45
49
|
def self.filename
|
46
50
|
if ENV.key?(URL_ENV_NAME)
|
47
|
-
File.expand_path "~/.gist.#{ENV[URL_ENV_NAME].gsub(/[^a-
|
51
|
+
File.expand_path "~/.gist.#{ENV[URL_ENV_NAME].gsub(/:/, '.').gsub(/[^a-z0-9.-]/, '')}"
|
48
52
|
else
|
49
53
|
File.expand_path "~/.gist"
|
50
54
|
end
|
@@ -76,10 +80,14 @@ module Gist
|
|
76
80
|
#
|
77
81
|
# @see http://developer.github.com/v3/gists/
|
78
82
|
def gist(content, options = {})
|
79
|
-
filename = options[:filename] ||
|
83
|
+
filename = options[:filename] || default_filename
|
80
84
|
multi_gist({filename => content}, options)
|
81
85
|
end
|
82
86
|
|
87
|
+
def default_filename
|
88
|
+
"gistfile1.txt"
|
89
|
+
end
|
90
|
+
|
83
91
|
# Upload a gist to https://gist.github.com
|
84
92
|
#
|
85
93
|
# @param [Hash] files the code you'd like to gist: filename => content
|
@@ -92,6 +100,7 @@ module Gist
|
|
92
100
|
# @option options [String] :update the URL or id of a gist to update
|
93
101
|
# @option options [Boolean] :copy (false) Copy resulting URL to clipboard, if successful.
|
94
102
|
# @option options [Boolean] :open (false) Open the resulting URL in a browser.
|
103
|
+
# @option options [Boolean] :skip_empty (false) Skip gisting empty files.
|
95
104
|
# @option options [Symbol] :output (:all) The type of return value you'd like:
|
96
105
|
# :html_url gives a String containing the url to the gist in a browser
|
97
106
|
# :short_url gives a String contianing a git.io url that redirects to html_url
|
@@ -103,6 +112,13 @@ module Gist
|
|
103
112
|
#
|
104
113
|
# @see http://developer.github.com/v3/gists/
|
105
114
|
def multi_gist(files, options={})
|
115
|
+
if options[:anonymous]
|
116
|
+
raise 'Anonymous gists are no longer supported. Please log in with `gist --login`. ' \
|
117
|
+
'(GitHub now requires credentials to gist https://bit.ly/2GBBxKw)'
|
118
|
+
else
|
119
|
+
access_token = (options[:access_token] || auth_token())
|
120
|
+
end
|
121
|
+
|
106
122
|
json = {}
|
107
123
|
|
108
124
|
json[:description] = options[:description] if options[:description]
|
@@ -110,22 +126,23 @@ module Gist
|
|
110
126
|
json[:files] = {}
|
111
127
|
|
112
128
|
files.each_pair do |(name, content)|
|
113
|
-
|
114
|
-
|
129
|
+
if content.to_s.strip == ""
|
130
|
+
raise "Cannot gist empty files" unless options[:skip_empty]
|
131
|
+
else
|
132
|
+
name = name == "-" ? default_filename : File.basename(name)
|
133
|
+
json[:files][name] = {:content => content}
|
134
|
+
end
|
115
135
|
end
|
116
136
|
|
137
|
+
return if json[:files].empty? && options[:skip_empty]
|
138
|
+
|
117
139
|
existing_gist = options[:update].to_s.split("/").last
|
118
|
-
if options[:anonymous]
|
119
|
-
access_token = nil
|
120
|
-
else
|
121
|
-
access_token = (options[:access_token] || auth_token())
|
122
|
-
end
|
123
140
|
|
124
141
|
url = "#{base_path}/gists"
|
125
142
|
url << "/" << CGI.escape(existing_gist) if existing_gist.to_s != ''
|
126
|
-
url << "?access_token=" << CGI.escape(access_token) if access_token.to_s != ''
|
127
143
|
|
128
144
|
request = Net::HTTP::Post.new(url)
|
145
|
+
request['Authorization'] = "token #{access_token}" if access_token.to_s != ''
|
129
146
|
request.body = JSON.dump(json)
|
130
147
|
request.content_type = 'application/json'
|
131
148
|
|
@@ -161,9 +178,10 @@ module Gist
|
|
161
178
|
if user == ""
|
162
179
|
access_token = auth_token()
|
163
180
|
if access_token.to_s != ''
|
164
|
-
url << "/gists
|
181
|
+
url << "/gists"
|
165
182
|
|
166
183
|
request = Net::HTTP::Get.new(url)
|
184
|
+
request['Authorization'] = "token #{access_token}"
|
167
185
|
response = http(api_url, request)
|
168
186
|
|
169
187
|
pretty_gist(response)
|
@@ -186,24 +204,21 @@ module Gist
|
|
186
204
|
url = "#{base_path}"
|
187
205
|
|
188
206
|
if user == ""
|
189
|
-
|
190
|
-
if access_token.to_s != ''
|
191
|
-
url << "/gists?per_page=100&access_token=" << CGI.escape(access_token)
|
192
|
-
get_gist_pages(url)
|
193
|
-
else
|
194
|
-
raise Error, "Not authenticated. Use 'gist --login' to login or 'gist -l username' to view public gists."
|
195
|
-
end
|
196
|
-
|
207
|
+
url << "/gists?per_page=100"
|
197
208
|
else
|
198
209
|
url << "/users/#{user}/gists?per_page=100"
|
199
|
-
get_gist_pages(url)
|
200
210
|
end
|
201
211
|
|
212
|
+
get_gist_pages(url, auth_token())
|
202
213
|
end
|
203
214
|
|
204
215
|
def read_gist(id, file_name=nil)
|
205
216
|
url = "#{base_path}/gists/#{id}"
|
217
|
+
|
218
|
+
access_token = auth_token()
|
219
|
+
|
206
220
|
request = Net::HTTP::Get.new(url)
|
221
|
+
request['Authorization'] = "token #{access_token}" if access_token.to_s != ''
|
207
222
|
response = http(api_url, request)
|
208
223
|
|
209
224
|
if response.code == '200'
|
@@ -223,9 +238,30 @@ module Gist
|
|
223
238
|
end
|
224
239
|
end
|
225
240
|
|
226
|
-
def
|
241
|
+
def delete_gist(id)
|
242
|
+
id = id.split("/").last
|
243
|
+
url = "#{base_path}/gists/#{id}"
|
244
|
+
|
245
|
+
access_token = auth_token()
|
246
|
+
if access_token.to_s != ''
|
247
|
+
request = Net::HTTP::Delete.new(url)
|
248
|
+
request["Authorization"] = "token #{access_token}"
|
249
|
+
response = http(api_url, request)
|
250
|
+
else
|
251
|
+
raise Error, "Not authenticated. Use 'gist --login' to login."
|
252
|
+
end
|
253
|
+
|
254
|
+
if response.code == '204'
|
255
|
+
puts "Deleted!"
|
256
|
+
else
|
257
|
+
raise Error, "Gist with id of #{id} does not exist."
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def get_gist_pages(url, access_token = "")
|
227
262
|
|
228
263
|
request = Net::HTTP::Get.new(url)
|
264
|
+
request['Authorization'] = "token #{access_token}" if access_token.to_s != ''
|
229
265
|
response = http(api_url, request)
|
230
266
|
pretty_gist(response)
|
231
267
|
|
@@ -233,7 +269,7 @@ module Gist
|
|
233
269
|
|
234
270
|
if link_header
|
235
271
|
links = Hash[ link_header.gsub(/(<|>|")/, "").split(',').map { |link| link.split('; rel=') } ].invert
|
236
|
-
get_gist_pages(links['next']) if links['next']
|
272
|
+
get_gist_pages(links['next'], access_token) if links['next']
|
237
273
|
end
|
238
274
|
|
239
275
|
end
|
@@ -263,10 +299,12 @@ module Gist
|
|
263
299
|
# @param [String] url
|
264
300
|
# @return [String] shortened url, or long url if shortening fails
|
265
301
|
def shorten(url)
|
266
|
-
request = Net::HTTP::Post.new("/")
|
302
|
+
request = Net::HTTP::Post.new("/create")
|
267
303
|
request.set_form_data(:url => url)
|
268
304
|
response = http(GIT_IO_URL, request)
|
269
305
|
case response.code
|
306
|
+
when "200"
|
307
|
+
URI.join(GIT_IO_URL, response.body).to_s
|
270
308
|
when "201"
|
271
309
|
response['Location']
|
272
310
|
else
|
@@ -295,16 +333,72 @@ module Gist
|
|
295
333
|
|
296
334
|
# Log the user into gist.
|
297
335
|
#
|
336
|
+
def login!(credentials={})
|
337
|
+
if (login_url == GITHUB_URL || ENV.key?(CLIENT_ID_ENV_NAME)) && credentials.empty? && !ENV.key?('GIST_USE_USERNAME_AND_PASSWORD')
|
338
|
+
device_flow_login!
|
339
|
+
else
|
340
|
+
access_token_login!(credentials)
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
def device_flow_login!
|
345
|
+
puts "Requesting login parameters..."
|
346
|
+
request = Net::HTTP::Post.new("/login/device/code")
|
347
|
+
request.body = JSON.dump({
|
348
|
+
:scope => 'gist',
|
349
|
+
:client_id => client_id,
|
350
|
+
})
|
351
|
+
request.content_type = 'application/json'
|
352
|
+
request['accept'] = "application/json"
|
353
|
+
response = http(login_url, request)
|
354
|
+
|
355
|
+
if response.code != '200'
|
356
|
+
raise Error, "HTTP #{response.code}: #{response.body}"
|
357
|
+
end
|
358
|
+
|
359
|
+
body = JSON.parse(response.body)
|
360
|
+
|
361
|
+
puts "Please sign in at #{body['verification_uri']}"
|
362
|
+
puts " and enter code: #{body['user_code']}"
|
363
|
+
device_code = body['device_code']
|
364
|
+
interval = body['interval']
|
365
|
+
|
366
|
+
loop do
|
367
|
+
sleep(interval.to_i)
|
368
|
+
request = Net::HTTP::Post.new("/login/oauth/access_token")
|
369
|
+
request.body = JSON.dump({
|
370
|
+
:client_id => client_id,
|
371
|
+
:grant_type => 'urn:ietf:params:oauth:grant-type:device_code',
|
372
|
+
:device_code => device_code
|
373
|
+
})
|
374
|
+
request.content_type = 'application/json'
|
375
|
+
request['Accept'] = 'application/json'
|
376
|
+
response = http(login_url, request)
|
377
|
+
if response.code != '200'
|
378
|
+
raise Error, "HTTP #{response.code}: #{response.body}"
|
379
|
+
end
|
380
|
+
body = JSON.parse(response.body)
|
381
|
+
break unless body['error'] == 'authorization_pending'
|
382
|
+
end
|
383
|
+
|
384
|
+
if body['error']
|
385
|
+
raise Error, body['error_description']
|
386
|
+
end
|
387
|
+
|
388
|
+
AuthTokenFile.write JSON.parse(response.body)['access_token']
|
389
|
+
|
390
|
+
puts "Success! #{ENV[URL_ENV_NAME] || "https://github.com/"}settings/connections/applications/#{client_id}"
|
391
|
+
end
|
392
|
+
|
393
|
+
# Logs the user into gist.
|
394
|
+
#
|
298
395
|
# This method asks the user for a username and password, and tries to obtain
|
299
396
|
# and OAuth2 access token, which is then stored in ~/.gist
|
300
397
|
#
|
301
398
|
# @raise [Gist::Error] if something went wrong
|
302
|
-
# @param [Hash] credentials login details
|
303
|
-
# @option credentials [String] :username
|
304
|
-
# @option credentials [String] :password
|
305
399
|
# @see http://developer.github.com/v3/oauth/
|
306
|
-
def
|
307
|
-
puts "Obtaining OAuth2 access_token from
|
400
|
+
def access_token_login!(credentials={})
|
401
|
+
puts "Obtaining OAuth2 access_token from GitHub."
|
308
402
|
loop do
|
309
403
|
print "GitHub username: "
|
310
404
|
username = credentials[:username] || $stdin.gets.strip
|
@@ -339,7 +433,7 @@ module Gist
|
|
339
433
|
|
340
434
|
if Net::HTTPCreated === response
|
341
435
|
AuthTokenFile.write JSON.parse(response.body)['token']
|
342
|
-
puts "Success! #{ENV[URL_ENV_NAME] || "https://github.com/"}settings/
|
436
|
+
puts "Success! #{ENV[URL_ENV_NAME] || "https://github.com/"}settings/tokens"
|
343
437
|
return
|
344
438
|
elsif Net::HTTPUnauthorized === response
|
345
439
|
puts "Error: #{JSON.parse(response.body)['message']}"
|
@@ -360,7 +454,11 @@ module Gist
|
|
360
454
|
env = ENV['http_proxy'] || ENV['HTTP_PROXY']
|
361
455
|
connection = if env
|
362
456
|
proxy = URI(env)
|
363
|
-
|
457
|
+
if proxy.user
|
458
|
+
Net::HTTP::Proxy(proxy.host, proxy.port, proxy.user, proxy.password).new(uri.host, uri.port)
|
459
|
+
else
|
460
|
+
Net::HTTP::Proxy(proxy.host, proxy.port).new(uri.host, uri.port)
|
461
|
+
end
|
364
462
|
else
|
365
463
|
Net::HTTP.new(uri.host, uri.port)
|
366
464
|
end
|
@@ -514,11 +612,19 @@ Could not find copy command, tried:
|
|
514
612
|
ENV.key?(URL_ENV_NAME) ? GHE_BASE_PATH : GITHUB_BASE_PATH
|
515
613
|
end
|
516
614
|
|
615
|
+
def login_url
|
616
|
+
ENV.key?(URL_ENV_NAME) ? URI(ENV[URL_ENV_NAME]) : GITHUB_URL
|
617
|
+
end
|
618
|
+
|
517
619
|
# Get the API URL
|
518
620
|
def api_url
|
519
621
|
ENV.key?(URL_ENV_NAME) ? URI(ENV[URL_ENV_NAME]) : GITHUB_API_URL
|
520
622
|
end
|
521
623
|
|
624
|
+
def client_id
|
625
|
+
ENV.key?(CLIENT_ID_ENV_NAME) ? URI(ENV[CLIENT_ID_ENV_NAME]) : GITHUB_CLIENT_ID
|
626
|
+
end
|
627
|
+
|
522
628
|
def legacy_private_gister?
|
523
629
|
return unless which('git')
|
524
630
|
`git config --global gist.private` =~ /\Ayes|1|true|on\z/i
|