From d442d4385305c17a62e496f157f357687db7dc13 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Tue, 16 May 2017 23:55:10 -0700 Subject: [PATCH 01/31] v4.6.1 --- build/gist | 16 +++++++++------- lib/gist.rb | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/build/gist b/build/gist index d137968..1e2bc1c 100755 --- a/build/gist +++ b/build/gist @@ -1318,18 +1318,18 @@ end module Gist extend self - VERSION = '4.6.0' + VERSION = '4.6.1' # A list of clipboard commands with copy and paste support. CLIPBOARD_COMMANDS = { + 'pbcopy' => 'pbpaste', 'xclip' => 'xclip -o', 'xsel -i' => 'xsel -o', - 'pbcopy' => 'pbpaste', - 'putclip' => 'getclip' + 'putclip' => 'getclip', } GITHUB_API_URL = URI("https://api.github.com/") - GIT_IO_URL = URI("http://git.io/") + GIT_IO_URL = URI("https://git.io/") GITHUB_BASE_PATH = "" GHE_BASE_PATH = "/api/v3" @@ -1350,7 +1350,7 @@ module Gist module AuthTokenFile def self.filename if ENV.key?(URL_ENV_NAME) - File.expand_path "~/.gist.#{ENV[URL_ENV_NAME].gsub(/[^a-z.]/, '')}" + File.expand_path "~/.gist.#{ENV[URL_ENV_NAME].gsub(/:/, '.').gsub(/[^a-z0-9.]/, '')}" else File.expand_path "~/.gist" end @@ -1590,10 +1590,12 @@ module Gist # @param [String] url # @return [String] shortened url, or long url if shortening fails def shorten(url) - request = Net::HTTP::Post.new("/") + request = Net::HTTP::Post.new("/create") request.set_form_data(:url => url) response = http(GIT_IO_URL, request) case response.code + when "200" + URI.join(GIT_IO_URL, response.body).to_s when "201" response['Location'] else @@ -1666,7 +1668,7 @@ module Gist if Net::HTTPCreated === response AuthTokenFile.write JSON.parse(response.body)['token'] - puts "Success! #{ENV[URL_ENV_NAME] || "https://github.com/"}settings/applications" + puts "Success! #{ENV[URL_ENV_NAME] || "https://github.com/"}settings/tokens" return elsif Net::HTTPUnauthorized === response puts "Error: #{JSON.parse(response.body)['message']}" diff --git a/lib/gist.rb b/lib/gist.rb index b52580c..bbc63e7 100644 --- a/lib/gist.rb +++ b/lib/gist.rb @@ -12,7 +12,7 @@ module Gist extend self - VERSION = '4.6.0' + VERSION = '4.6.1' # A list of clipboard commands with copy and paste support. CLIPBOARD_COMMANDS = { From 0ad83ca286ba5443eb02f3bb862ce6c4e06668c3 Mon Sep 17 00:00:00 2001 From: Jos Boumans Date: Thu, 29 Jun 2017 13:47:54 -0700 Subject: [PATCH 02/31] * unless you supply the access token, you are limited to 60 requests/hour --- lib/gist.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/gist.rb b/lib/gist.rb index bbc63e7..88198e3 100644 --- a/lib/gist.rb +++ b/lib/gist.rb @@ -203,6 +203,12 @@ def list_all_gists(user = "") def read_gist(id, file_name=nil) url = "#{base_path}/gists/#{id}" + + access_token = auth_token() + if access_token.to_s != '' + url << "?access_token=" << CGI.escape(access_token) + end + request = Net::HTTP::Get.new(url) response = http(api_url, request) From 87b076b7106f464473c755e2b0efbb4f0beb23f1 Mon Sep 17 00:00:00 2001 From: Jason Karns Date: Thu, 7 Sep 2017 11:30:23 -0400 Subject: [PATCH 03/31] readme typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f69302c..5dd6639 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,7 @@ Once you've done this and restarted your terminal (or run `source ~/.bashrc`), g automatically use github enterprise instead of the public github.com Your token for GitHub Enterprise will be stored in `.gist..[.]` (e.g. -`~.gist.http.github.internal.example.com` for the GITHUB_URL example above) instead of `~/.gist`. +`~/.gist.http.github.internal.example.com` for the GITHUB_URL example above) instead of `~/.gist`. If you have multiple servers or use Enterprise and public GitHub often, you can work around this by creating scripts 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 From bd98d7bf0072aaafd387ee4bce387c40f9d3ebf8 Mon Sep 17 00:00:00 2001 From: Philip Hallstrom Date: Sat, 7 Oct 2017 10:11:47 -0700 Subject: [PATCH 04/31] add --skip-empty to skip gisting empty files fixes #208 Option --skip-empty will skip any zero length files passes to gist. If all files are empty no gist will be created at all. test plan: - create two empty files 'empty1' and 'empty2'. - create a third file with some content 'content1'. % bin/gist empty1 empty2 content1 # should return error about an empty file % bin/gist --skip-empty empty1 empty2 content1 # should create gist with single file 'content1' % bin/gist --skip-empty empty1 empty2 # should return error/notice about all files empty no gist created % date | bin/gist # should create gist with date string --- bin/gist | 10 +++++++++- lib/gist.rb | 10 ++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/bin/gist b/bin/gist index c88f623..7071b60 100755 --- a/bin/gist +++ b/bin/gist @@ -47,7 +47,11 @@ Instead of creating a new gist, you can update an existing one by passing its ID or URL with "-u". For this to work, you must be logged in, and have created the original gist with the same GitHub account. -Usage: #{executable_name} [-o|-c|-e] [-p] [-s] [-R] [-d DESC] [-a] [-u URL] [-P] [-f NAME|-t EXT]* FILE* +If you want to skip empty files, use the --skip-empty flag. If all files are +empty no gist will be created. + +Usage: #{executable_name} [-o|-c|-e] [-p] [-s] [-R] [-d DESC] [-a] [-u URL] + [--skip-empty] [-P] [-f NAME|-t EXT]* FILE* #{executable_name} --login #{executable_name} [-l|-r] @@ -107,6 +111,10 @@ Usage: #{executable_name} [-o|-c|-e] [-p] [-s] [-R] [-d DESC] [-a] [-u URL] [-P] opts.on("--no-open") + opts.on("--skip-empty", "Skip gisting empty files") do + options[:skip_empty] = true + end + opts.on("-P", "--paste", "Paste from the clipboard to gist") do options[:paste] = true end diff --git a/lib/gist.rb b/lib/gist.rb index 88198e3..ce60973 100644 --- a/lib/gist.rb +++ b/lib/gist.rb @@ -92,6 +92,7 @@ def gist(content, options = {}) # @option options [String] :update the URL or id of a gist to update # @option options [Boolean] :copy (false) Copy resulting URL to clipboard, if successful. # @option options [Boolean] :open (false) Open the resulting URL in a browser. + # @option options [Boolean] :skip_empty (false) Skip gisting empty files. # @option options [Symbol] :output (:all) The type of return value you'd like: # :html_url gives a String containing the url to the gist in a browser # :short_url gives a String contianing a git.io url that redirects to html_url @@ -110,10 +111,15 @@ def multi_gist(files, options={}) json[:files] = {} files.each_pair do |(name, content)| - raise "Cannot gist empty files" if content.to_s.strip == "" - json[:files][File.basename(name)] = {:content => content} + if content.to_s.strip == "" + raise "Cannot gist empty files" unless options[:skip_empty] + else + json[:files][File.basename(name)] = {:content => content} + end end + raise "All files were empty. No gist created." if json[:files].empty? && options[:skip_empty] + existing_gist = options[:update].to_s.split("/").last if options[:anonymous] access_token = nil From 9c934a9a14c4f101b31c594fbb881e6b8ca4216c Mon Sep 17 00:00:00 2001 From: Philip Hallstrom Date: Mon, 9 Oct 2017 09:41:59 -0700 Subject: [PATCH 05/31] exit silently if --skip-empty and all files are empty --- bin/gist | 3 ++- lib/gist.rb | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/bin/gist b/bin/gist index 7071b60..c4848c7 100755 --- a/bin/gist +++ b/bin/gist @@ -203,7 +203,8 @@ begin end end - puts Gist.multi_gist(files, options) + output = Gist.multi_gist(files, options) + puts output if output end rescue Gist::Error => e diff --git a/lib/gist.rb b/lib/gist.rb index ce60973..f6e2d2d 100644 --- a/lib/gist.rb +++ b/lib/gist.rb @@ -118,7 +118,7 @@ def multi_gist(files, options={}) end end - raise "All files were empty. No gist created." if json[:files].empty? && options[:skip_empty] + return if json[:files].empty? && options[:skip_empty] existing_gist = options[:update].to_s.split("/").last if options[:anonymous] From fc87a5a02dc60c7f478785b1456f9ad37a94fa21 Mon Sep 17 00:00:00 2001 From: Philip Hallstrom Date: Sat, 7 Oct 2017 09:56:17 -0700 Subject: [PATCH 06/31] when gisting stdin default to filename 'gistfile1.txt' instead of '-' fixes #235 test plan: ``` - ensure you're signed in (ie. have a token) % gist Gemfile # check gist, filename should be 'Gemfile' % jot 5 | gist # check gist, filename should be 'gistfile1.txt' % jot 5 | gist Gemfile - # check gist, filenames should be 'Gemfile' and 'gistfile1.txt' ``` --- lib/gist.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/gist.rb b/lib/gist.rb index f6e2d2d..9f3df43 100644 --- a/lib/gist.rb +++ b/lib/gist.rb @@ -76,10 +76,14 @@ def auth_token # # @see http://developer.github.com/v3/gists/ def gist(content, options = {}) - filename = options[:filename] || "a.rb" + filename = options[:filename] || default_filename multi_gist({filename => content}, options) end + def default_filename + "gistfile1.txt" + end + # Upload a gist to https://gist.github.com # # @param [Hash] files the code you'd like to gist: filename => content @@ -114,7 +118,8 @@ def multi_gist(files, options={}) if content.to_s.strip == "" raise "Cannot gist empty files" unless options[:skip_empty] else - json[:files][File.basename(name)] = {:content => content} + name = name == "-" ? default_filename : File.basename(name) + json[:files][name] = {:content => content} end end From 83c91b27aeda6308d9c768004756820bc7c7bde6 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Mon, 20 Nov 2017 09:37:08 -0800 Subject: [PATCH 07/31] Add instructions for password-less login --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 5dd6639..7c31de7 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,19 @@ file. gist -a a.rb +#### Password-less login + +If you have a complicated authorization requirement you can manually create a +token file by pasting a Github token with only the `gist` permission into a +file called `~/.gist`. You can create one from https://github.com/settings/tokens + +This file should contain only the token (~40 hex characters), and to make it +easier to edit, can optionally have a final newline (\n or \r\n). + +For example, one way to create this file would be to run: + + echo MY_SECRET_TOKEN > ~/.gist + ### GitHub Enterprise If you'd like `gist` to use your locally installed [GitHub Enterprise](https://enterprise.github.com/), From 249fb99541e10b6af26f469b7a97b44282a16387 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Tue, 9 Jan 2018 10:22:06 -0800 Subject: [PATCH 08/31] v4.6.2 --- build/gist | 38 ++++++++++++++++++++++++++++++++------ build/gist.1 | 23 +++++++++++++++++++++-- lib/gist.rb | 2 +- 3 files changed, 54 insertions(+), 9 deletions(-) diff --git a/build/gist b/build/gist index 1e2bc1c..cf36422 100755 --- a/build/gist +++ b/build/gist @@ -1318,7 +1318,7 @@ end module Gist extend self - VERSION = '4.6.1' + VERSION = '4.6.2' # A list of clipboard commands with copy and paste support. CLIPBOARD_COMMANDS = { @@ -1382,10 +1382,14 @@ module Gist # # @see http://developer.github.com/v3/gists/ def gist(content, options = {}) - filename = options[:filename] || "a.rb" + filename = options[:filename] || default_filename multi_gist({filename => content}, options) end + def default_filename + "gistfile1.txt" + end + # Upload a gist to https://gist.github.com # # @param [Hash] files the code you'd like to gist: filename => content @@ -1398,6 +1402,7 @@ module Gist # @option options [String] :update the URL or id of a gist to update # @option options [Boolean] :copy (false) Copy resulting URL to clipboard, if successful. # @option options [Boolean] :open (false) Open the resulting URL in a browser. + # @option options [Boolean] :skip_empty (false) Skip gisting empty files. # @option options [Symbol] :output (:all) The type of return value you'd like: # :html_url gives a String containing the url to the gist in a browser # :short_url gives a String contianing a git.io url that redirects to html_url @@ -1416,10 +1421,16 @@ module Gist json[:files] = {} files.each_pair do |(name, content)| - raise "Cannot gist empty files" if content.to_s.strip == "" - json[:files][File.basename(name)] = {:content => content} + if content.to_s.strip == "" + raise "Cannot gist empty files" unless options[:skip_empty] + else + name = name == "-" ? default_filename : File.basename(name) + json[:files][name] = {:content => content} + end end + return if json[:files].empty? && options[:skip_empty] + existing_gist = options[:update].to_s.split("/").last if options[:anonymous] access_token = nil @@ -1509,6 +1520,12 @@ module Gist def read_gist(id, file_name=nil) url = "#{base_path}/gists/#{id}" + + access_token = auth_token() + if access_token.to_s != '' + url << "?access_token=" << CGI.escape(access_token) + end + request = Net::HTTP::Get.new(url) response = http(api_url, request) @@ -1909,7 +1926,11 @@ Instead of creating a new gist, you can update an existing one by passing its ID or URL with "-u". For this to work, you must be logged in, and have created the original gist with the same GitHub account. -Usage: #{executable_name} [-o|-c|-e] [-p] [-s] [-R] [-d DESC] [-a] [-u URL] [-P] [-f NAME|-t EXT]* FILE* +If you want to skip empty files, use the --skip-empty flag. If all files are +empty no gist will be created. + +Usage: #{executable_name} [-o|-c|-e] [-p] [-s] [-R] [-d DESC] [-a] [-u URL] + [--skip-empty] [-P] [-f NAME|-t EXT]* FILE* #{executable_name} --login #{executable_name} [-l|-r] @@ -1969,6 +1990,10 @@ Usage: #{executable_name} [-o|-c|-e] [-p] [-s] [-R] [-d DESC] [-a] [-u URL] [-P] opts.on("--no-open") + opts.on("--skip-empty", "Skip gisting empty files") do + options[:skip_empty] = true + end + opts.on("-P", "--paste", "Paste from the clipboard to gist") do options[:paste] = true end @@ -2057,7 +2082,8 @@ begin end end - puts Gist.multi_gist(files, options) + output = Gist.multi_gist(files, options) + puts output if output end rescue Gist::Error => e diff --git a/build/gist.1 b/build/gist.1 index 3a77667..f3932d2 100644 --- a/build/gist.1 +++ b/build/gist.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "GIST" "1" "May 2017" "" "Gist manual" +.TH "GIST" "1" "January 2018" "" "Gist manual" . .SH "NAME" \fBgist\fR \- upload code to https://gist\.github\.com @@ -149,6 +149,25 @@ gist \-a a\.rb . .IP "" 0 . +.P +If you have a complicated authorization requirement you can manually create a token file by pasting a Github token with only the \fBgist\fR permission into a file called \fB~/\.gist\fR\. You can create one from https://github\.com/settings/tokens +. +.P +This file should contain only the token (~40 hex characters), and to make it easier to edit, can optionally have a final newline (\en or \er\en)\. +. +.P +For example, one way to create this file would be to run: +. +.IP "" 4 +. +.nf + +echo MY_SECRET_TOKEN > ~/\.gist +. +.fi +. +.IP "" 0 +. .SS "GitHub Enterprise" If you\'d like \fBgist\fR to use your locally installed GitHub Enterprise \fIhttps://enterprise\.github\.com/\fR, you need to export the \fBGITHUB_URL\fR environment variable (usually done in your \fB~/\.bashrc\fR)\. . @@ -166,7 +185,7 @@ export GITHUB_URL=http://github\.internal\.example\.com/ Once you\'ve done this and restarted your terminal (or run \fBsource ~/\.bashrc\fR), gist will automatically use github enterprise instead of the public github\.com . .P -Your token for GitHub Enterprise will be stored in \fB\.gist\.\.[\.]\fR (e\.g\. \fB~\.gist\.http\.github\.internal\.example\.com\fR for the GITHUB_URL example above) instead of \fB~/\.gist\fR\. +Your token for GitHub Enterprise will be stored in \fB\.gist\.\.[\.]\fR (e\.g\. \fB~/\.gist\.http\.github\.internal\.example\.com\fR for the GITHUB_URL example above) instead of \fB~/\.gist\fR\. . .P If you have multiple servers or use Enterprise and public GitHub often, you can work around this by creating scripts that set the env var and then run \fBgist\fR\. Keep in mind that to use the public GitHub you must unset the env var\. Just setting it to the public URL will not work\. Use \fBunset GITHUB_URL\fR diff --git a/lib/gist.rb b/lib/gist.rb index 9f3df43..c38fa42 100644 --- a/lib/gist.rb +++ b/lib/gist.rb @@ -12,7 +12,7 @@ module Gist extend self - VERSION = '4.6.1' + VERSION = '4.6.2' # A list of clipboard commands with copy and paste support. CLIPBOARD_COMMANDS = { From c8ab65546a8cfbc7423503e0e361144a7de6dc05 Mon Sep 17 00:00:00 2001 From: esteban zapata Date: Fri, 18 May 2018 10:38:22 -0500 Subject: [PATCH 09/31] Remove anonymous support due to deprecation. Fixes https://github.com/defunkt/gist/issues/275 This change is needed due to the deprecation warning/removal made by Github on the gist tool. See https://blog.github.com/2018-02-18-deprecation-notice-removing-anonymous-gist-creation/ for more info. --- lib/gist.rb | 3 ++- spec/rawify_spec.rb | 11 ++++++++++- spec/shorten_spec.rb | 13 +++++++++++-- spec/spec_helper.rb | 2 +- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/lib/gist.rb b/lib/gist.rb index c38fa42..0102f54 100644 --- a/lib/gist.rb +++ b/lib/gist.rb @@ -127,7 +127,8 @@ def multi_gist(files, options={}) existing_gist = options[:update].to_s.split("/").last if options[:anonymous] - access_token = nil + raise 'Anonymous gist support has been removed by Github. ' \ + 'See: https://blog.github.com/2018-02-18-deprecation-notice-removing-anonymous-gist-creation/' else access_token = (options[:access_token] || auth_token()) end diff --git a/spec/rawify_spec.rb b/spec/rawify_spec.rb index b4703cf..143ee46 100644 --- a/spec/rawify_spec.rb +++ b/spec/rawify_spec.rb @@ -6,7 +6,16 @@ end it "should return the raw file url" do - Gist.gist("Test gist", :output => :raw_url, :anonymous => true).should == "https://gist.github.com/anonymous/XXXXXX/raw" + Gist.gist("Test gist", :output => :raw_url, :anonymous => false).should == "https://gist.github.com/anonymous/XXXXXX/raw" + end + + it 'should raise an error when trying to do operations without being logged in' do + error_msg = 'Anonymous gist support has been removed by Github. ' \ + 'See: https://blog.github.com/2018-02-18-deprecation-notice-removing-anonymous-gist-creation/' + + expect do + Gist.gist("Test gist", output: :raw_url, anonymous: true) + end.to raise_error(StandardError, error_msg) end end diff --git a/spec/shorten_spec.rb b/spec/shorten_spec.rb index b65d705..00b2bfa 100644 --- a/spec/shorten_spec.rb +++ b/spec/shorten_spec.rb @@ -5,11 +5,20 @@ it "should return a shortened version of the URL when response is 200" do stub_request(:post, "https://git.io/create").to_return(:status => 200, :body => 'XXXXXX') - Gist.gist("Test gist", :output => :short_url, :anonymous => true).should == "https://git.io/XXXXXX" + Gist.gist("Test gist", :output => :short_url, anonymous: false).should == "https://git.io/XXXXXX" end it "should return a shortened version of the URL when response is 201" do stub_request(:post, "https://git.io/create").to_return(:status => 201, :headers => { 'Location' => 'https://git.io/XXXXXX' }) - Gist.gist("Test gist", :output => :short_url, :anonymous => true).should == "https://git.io/XXXXXX" + Gist.gist("Test gist", :output => :short_url, anonymous: false).should == "https://git.io/XXXXXX" + end + + it 'should raise an error when trying to get short urls without being logged in' do + error_msg = 'Anonymous gist support has been removed by Github. ' \ + 'See: https://blog.github.com/2018-02-18-deprecation-notice-removing-anonymous-gist-creation/' + + expect do + Gist.gist("Test gist", output: :short_url, anonymous: true) + end.to raise_error(StandardError, error_msg) end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 504a277..37dbef0 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -11,7 +11,7 @@ mocks.syntax = :should end config.expect_with :rspec do |expectations| - expectations.syntax = :should + expectations.syntax = [:should, :expect] end end From 4fce19e1697d8bc4d36f8691bf982db81a5e153b Mon Sep 17 00:00:00 2001 From: esteban zapata Date: Tue, 22 May 2018 10:04:42 -0500 Subject: [PATCH 10/31] gist: Update raise message. --- lib/gist.rb | 13 +++++++------ spec/rawify_spec.rb | 4 ++-- spec/shorten_spec.rb | 4 ++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/gist.rb b/lib/gist.rb index 0102f54..8acaed4 100644 --- a/lib/gist.rb +++ b/lib/gist.rb @@ -108,6 +108,13 @@ def default_filename # # @see http://developer.github.com/v3/gists/ def multi_gist(files, options={}) + if options[:anonymous] + raise 'Anonymous gists are no longer supported. Please log in with `gist --login`. ' \ + '(Github now requires credentials to gist https://bit.ly/2GBBxKw)' + else + access_token = (options[:access_token] || auth_token()) + end + json = {} json[:description] = options[:description] if options[:description] @@ -126,12 +133,6 @@ def multi_gist(files, options={}) return if json[:files].empty? && options[:skip_empty] existing_gist = options[:update].to_s.split("/").last - if options[:anonymous] - raise 'Anonymous gist support has been removed by Github. ' \ - 'See: https://blog.github.com/2018-02-18-deprecation-notice-removing-anonymous-gist-creation/' - else - access_token = (options[:access_token] || auth_token()) - end url = "#{base_path}/gists" url << "/" << CGI.escape(existing_gist) if existing_gist.to_s != '' diff --git a/spec/rawify_spec.rb b/spec/rawify_spec.rb index 143ee46..8fc21a7 100644 --- a/spec/rawify_spec.rb +++ b/spec/rawify_spec.rb @@ -10,8 +10,8 @@ end it 'should raise an error when trying to do operations without being logged in' do - error_msg = 'Anonymous gist support has been removed by Github. ' \ - 'See: https://blog.github.com/2018-02-18-deprecation-notice-removing-anonymous-gist-creation/' + error_msg = 'Anonymous gists are no longer supported. Please log in with `gist --login`. ' \ + '(Github now requires credentials to gist https://bit.ly/2GBBxKw)' expect do Gist.gist("Test gist", output: :raw_url, anonymous: true) diff --git a/spec/shorten_spec.rb b/spec/shorten_spec.rb index 00b2bfa..4191779 100644 --- a/spec/shorten_spec.rb +++ b/spec/shorten_spec.rb @@ -14,8 +14,8 @@ end it 'should raise an error when trying to get short urls without being logged in' do - error_msg = 'Anonymous gist support has been removed by Github. ' \ - 'See: https://blog.github.com/2018-02-18-deprecation-notice-removing-anonymous-gist-creation/' + error_msg = 'Anonymous gists are no longer supported. Please log in with `gist --login`. ' \ + '(Github now requires credentials to gist https://bit.ly/2GBBxKw)' expect do Gist.gist("Test gist", output: :short_url, anonymous: true) From 09813a332d320c4c507d41a68f1f28948f4ccbc2 Mon Sep 17 00:00:00 2001 From: esteban zapata Date: Tue, 22 May 2018 10:52:44 -0500 Subject: [PATCH 11/31] gist: Validate auth token existence before any action. --- bin/gist | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bin/gist b/bin/gist index c4848c7..c354ae6 100755 --- a/bin/gist +++ b/bin/gist @@ -148,6 +148,12 @@ Usage: #{executable_name} [-o|-c|-e] [-p] [-s] [-R] [-d DESC] [-a] [-u URL] end.parse! begin + if Gist.auth_token.nil? + puts 'Please log in with `gist --login`. ' \ + '(Github now requires credentials to gist https://bit.ly/2GBBxKw)' + exit(1) + end + options[:output] = if options[:embed] && options[:shorten] raise Gist::Error, "--embed does not make sense with --shorten" elsif options[:embed] From 9e63eed3c7ac0a434c74929024d966b0e185de78 Mon Sep 17 00:00:00 2001 From: esteban zapata Date: Tue, 22 May 2018 10:53:15 -0500 Subject: [PATCH 12/31] gist: Remove anonymous option. --- bin/gist | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/bin/gist b/bin/gist index c354ae6..6de9db1 100755 --- a/bin/gist +++ b/bin/gist @@ -24,16 +24,12 @@ specified STDIN will be read. The default filename for STDIN is "a.rb", and all filenames can be overridden by repeating the "-f" flag. The most useful reason to do this is to change the syntax highlighting. -If you'd like your gists to be associated with your GitHub account, so that you -can edit them and find them in future, first use `gist --login` to obtain an -Oauth2 access token. This is stored and used by gist in the future. +All gists must to be associated with a GitHub account, so you will need to login with +`gist --login` to obtain an Oauth2 access token. This is stored and used by gist in the future. Private gists do not have guessable URLs and can be created with "-p", you can also set the description at the top of the gist by passing "-d". -Anonymous gists are not associated with your GitHub account, they can be created -with "-a" even after you have used "gist --login". - If you would like to shorten the resulting gist URL, use the -s flag. This will use GitHub's URL shortener, git.io. You can also use -R to get the link to the raw gist. @@ -50,7 +46,7 @@ original gist with the same GitHub account. If you want to skip empty files, use the --skip-empty flag. If all files are empty no gist will be created. -Usage: #{executable_name} [-o|-c|-e] [-p] [-s] [-R] [-d DESC] [-a] [-u URL] +Usage: #{executable_name} [-o|-c|-e] [-p] [-s] [-R] [-d DESC] [-u URL] [--skip-empty] [-P] [-f NAME|-t EXT]* FILE* #{executable_name} --login #{executable_name} [-l|-r] @@ -92,10 +88,6 @@ Usage: #{executable_name} [-o|-c|-e] [-p] [-s] [-R] [-d DESC] [-a] [-u URL] options[:update] = update end - opts.on("-a", "--anonymous", "Create an anonymous gist.") do - options[:anonymous] = true - end - opts.on("-c", "--copy", "Copy the resulting URL to the clipboard") do options[:copy] = true end From 9c047578ebefcd04fe8eb1c9ad01346038ca2fd4 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Tue, 22 May 2018 22:55:39 -0700 Subject: [PATCH 13/31] v5.0.0 --- build/gist | 34 +++++++++++++++++----------------- build/gist.1 | 2 +- lib/gist.rb | 2 +- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/build/gist b/build/gist index cf36422..3f32dcd 100755 --- a/build/gist +++ b/build/gist @@ -1318,7 +1318,7 @@ end module Gist extend self - VERSION = '4.6.2' + VERSION = '5.0.0' # A list of clipboard commands with copy and paste support. CLIPBOARD_COMMANDS = { @@ -1414,6 +1414,13 @@ module Gist # # @see http://developer.github.com/v3/gists/ def multi_gist(files, options={}) + if options[:anonymous] + raise 'Anonymous gists are no longer supported. Please log in with `gist --login`. ' \ + '(Github now requires credentials to gist https://bit.ly/2GBBxKw)' + else + access_token = (options[:access_token] || auth_token()) + end + json = {} json[:description] = options[:description] if options[:description] @@ -1432,11 +1439,6 @@ module Gist return if json[:files].empty? && options[:skip_empty] existing_gist = options[:update].to_s.split("/").last - if options[:anonymous] - access_token = nil - else - access_token = (options[:access_token] || auth_token()) - end url = "#{base_path}/gists" url << "/" << CGI.escape(existing_gist) if existing_gist.to_s != '' @@ -1903,16 +1905,12 @@ specified STDIN will be read. The default filename for STDIN is "a.rb", and all filenames can be overridden by repeating the "-f" flag. The most useful reason to do this is to change the syntax highlighting. -If you'd like your gists to be associated with your GitHub account, so that you -can edit them and find them in future, first use `gist --login` to obtain an -Oauth2 access token. This is stored and used by gist in the future. +All gists must to be associated with a GitHub account, so you will need to login with +`gist --login` to obtain an Oauth2 access token. This is stored and used by gist in the future. Private gists do not have guessable URLs and can be created with "-p", you can also set the description at the top of the gist by passing "-d". -Anonymous gists are not associated with your GitHub account, they can be created -with "-a" even after you have used "gist --login". - If you would like to shorten the resulting gist URL, use the -s flag. This will use GitHub's URL shortener, git.io. You can also use -R to get the link to the raw gist. @@ -1929,7 +1927,7 @@ original gist with the same GitHub account. If you want to skip empty files, use the --skip-empty flag. If all files are empty no gist will be created. -Usage: #{executable_name} [-o|-c|-e] [-p] [-s] [-R] [-d DESC] [-a] [-u URL] +Usage: #{executable_name} [-o|-c|-e] [-p] [-s] [-R] [-d DESC] [-u URL] [--skip-empty] [-P] [-f NAME|-t EXT]* FILE* #{executable_name} --login #{executable_name} [-l|-r] @@ -1971,10 +1969,6 @@ Usage: #{executable_name} [-o|-c|-e] [-p] [-s] [-R] [-d DESC] [-a] [-u URL] options[:update] = update end - opts.on("-a", "--anonymous", "Create an anonymous gist.") do - options[:anonymous] = true - end - opts.on("-c", "--copy", "Copy the resulting URL to the clipboard") do options[:copy] = true end @@ -2027,6 +2021,12 @@ Usage: #{executable_name} [-o|-c|-e] [-p] [-s] [-R] [-d DESC] [-a] [-u URL] end.parse! begin + if Gist.auth_token.nil? + puts 'Please log in with `gist --login`. ' \ + '(Github now requires credentials to gist https://bit.ly/2GBBxKw)' + exit(1) + end + options[:output] = if options[:embed] && options[:shorten] raise Gist::Error, "--embed does not make sense with --shorten" elsif options[:embed] diff --git a/build/gist.1 b/build/gist.1 index f3932d2..66fb503 100644 --- a/build/gist.1 +++ b/build/gist.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "GIST" "1" "January 2018" "" "Gist manual" +.TH "GIST" "1" "May 2018" "" "Gist manual" . .SH "NAME" \fBgist\fR \- upload code to https://gist\.github\.com diff --git a/lib/gist.rb b/lib/gist.rb index 8acaed4..7825ca3 100644 --- a/lib/gist.rb +++ b/lib/gist.rb @@ -12,7 +12,7 @@ module Gist extend self - VERSION = '4.6.2' + VERSION = '5.0.0' # A list of clipboard commands with copy and paste support. CLIPBOARD_COMMANDS = { From 0d59657bd27d7fa64a1079091c8a908d8725b498 Mon Sep 17 00:00:00 2001 From: Alex Malinovich Date: Tue, 3 Jul 2018 17:07:55 -0700 Subject: [PATCH 14/31] Fix capitalization of GitHub and OAuth in messages --- README.md | 6 +++--- bin/gist | 4 ++-- lib/gist.rb | 4 ++-- spec/rawify_spec.rb | 2 +- spec/shorten_spec.rb | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 7c31de7..7953531 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ with gist. It doesn't store your username and password, it just uses them to get an OAuth2 token (with the "gist" permission). gist --login - Obtaining OAuth2 access_token from github. + Obtaining OAuth2 access_token from GitHub. GitHub username: ConradIrwin GitHub password: 2-factor auth code: @@ -101,7 +101,7 @@ file. #### Password-less login If you have a complicated authorization requirement you can manually create a -token file by pasting a Github token with only the `gist` permission into a +token file by pasting a GitHub token with only the `gist` permission into a file called `~/.gist`. You can create one from https://github.com/settings/tokens This file should contain only the token (~40 hex characters), and to make it @@ -119,7 +119,7 @@ you need to export the `GITHUB_URL` environment variable (usually done in your ` export GITHUB_URL=http://github.internal.example.com/ Once you've done this and restarted your terminal (or run `source ~/.bashrc`), gist will -automatically use github enterprise instead of the public github.com +automatically use GitHub Enterprise instead of the public github.com Your token for GitHub Enterprise will be stored in `.gist..[.]` (e.g. `~/.gist.http.github.internal.example.com` for the GITHUB_URL example above) instead of `~/.gist`. diff --git a/bin/gist b/bin/gist index 6de9db1..5618d08 100755 --- a/bin/gist +++ b/bin/gist @@ -25,7 +25,7 @@ filenames can be overridden by repeating the "-f" flag. The most useful reason to do this is to change the syntax highlighting. All gists must to be associated with a GitHub account, so you will need to login with -`gist --login` to obtain an Oauth2 access token. This is stored and used by gist in the future. +`gist --login` to obtain an OAuth2 access token. This is stored and used by gist in the future. Private gists do not have guessable URLs and can be created with "-p", you can also set the description at the top of the gist by passing "-d". @@ -142,7 +142,7 @@ end.parse! begin if Gist.auth_token.nil? puts 'Please log in with `gist --login`. ' \ - '(Github now requires credentials to gist https://bit.ly/2GBBxKw)' + '(GitHub now requires credentials to gist https://bit.ly/2GBBxKw)' exit(1) end diff --git a/lib/gist.rb b/lib/gist.rb index 7825ca3..c49b1dd 100644 --- a/lib/gist.rb +++ b/lib/gist.rb @@ -110,7 +110,7 @@ def default_filename def multi_gist(files, options={}) if options[:anonymous] raise 'Anonymous gists are no longer supported. Please log in with `gist --login`. ' \ - '(Github now requires credentials to gist https://bit.ly/2GBBxKw)' + '(GitHub now requires credentials to gist https://bit.ly/2GBBxKw)' else access_token = (options[:access_token] || auth_token()) end @@ -346,7 +346,7 @@ def rawify(url) # @option credentials [String] :password # @see http://developer.github.com/v3/oauth/ def login!(credentials={}) - puts "Obtaining OAuth2 access_token from github." + puts "Obtaining OAuth2 access_token from GitHub." loop do print "GitHub username: " username = credentials[:username] || $stdin.gets.strip diff --git a/spec/rawify_spec.rb b/spec/rawify_spec.rb index 8fc21a7..10f25d6 100644 --- a/spec/rawify_spec.rb +++ b/spec/rawify_spec.rb @@ -11,7 +11,7 @@ it 'should raise an error when trying to do operations without being logged in' do error_msg = 'Anonymous gists are no longer supported. Please log in with `gist --login`. ' \ - '(Github now requires credentials to gist https://bit.ly/2GBBxKw)' + '(GitHub now requires credentials to gist https://bit.ly/2GBBxKw)' expect do Gist.gist("Test gist", output: :raw_url, anonymous: true) diff --git a/spec/shorten_spec.rb b/spec/shorten_spec.rb index 4191779..a7a0f45 100644 --- a/spec/shorten_spec.rb +++ b/spec/shorten_spec.rb @@ -15,7 +15,7 @@ it 'should raise an error when trying to get short urls without being logged in' do error_msg = 'Anonymous gists are no longer supported. Please log in with `gist --login`. ' \ - '(Github now requires credentials to gist https://bit.ly/2GBBxKw)' + '(GitHub now requires credentials to gist https://bit.ly/2GBBxKw)' expect do Gist.gist("Test gist", output: :short_url, anonymous: true) From 5e6e7f4edfd26b1904e10771232b870d3af4a563 Mon Sep 17 00:00:00 2001 From: JBallin Date: Sun, 22 Jul 2018 12:01:21 -0700 Subject: [PATCH 15/31] Remove "gist-a a.rb" --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index 7953531..743fc80 100644 --- a/README.md +++ b/README.md @@ -94,10 +94,6 @@ This token is stored in `~/.gist` and used for all future gisting. If you need t you can revoke it from https://github.com/settings/tokens, or just delete the file. -‌After you've done this, you can still upload gists anonymously with `-a`. - - gist -a a.rb - #### Password-less login If you have a complicated authorization requirement you can manually create a From 13c6720bf925a9dac7f3fa217cb04d4b714c327e Mon Sep 17 00:00:00 2001 From: JBallin Date: Sun, 22 Jul 2018 12:02:51 -0700 Subject: [PATCH 16/31] Remove :anonymous from Library --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 743fc80..1aff28e 100644 --- a/README.md +++ b/README.md @@ -146,7 +146,6 @@ If you need more advanced features you can also pass: * `:public` if you want your gist to have a guessable url. * `:description` to add a description to your gist. * `:update` to update an existing gist (can be a URL or an id). -* `:anonymous` to submit an anonymous gist (default is false). * `:copy` to copy the resulting URL to the clipboard (default is false). * `:open` to open the resulting URL in a browser (default is false). From 59911bcb10342bb9c4628053c82be5498c8cea2a Mon Sep 17 00:00:00 2001 From: Mateusz Piotrowski <0mp@FreeBSD.org> Date: Sun, 23 Jun 2019 02:08:35 +0200 Subject: [PATCH 17/31] Add FreeBSD installation instructions --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 1aff28e..5df2c2c 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,11 @@ upload content to https://gist.github.com/. brew install gist +‌For FreeBSD, gist lives in ports + + pkg install gist + + ## Command ‌To upload the contents of `a.rb` just: From c025ada88ac032f382087d802af849052c349555 Mon Sep 17 00:00:00 2001 From: Clyde Law Date: Thu, 29 Aug 2019 11:54:01 -0700 Subject: [PATCH 18/31] README update: Use umask when creating token file The originally suggested command in the README for manually setting up the `~/.gist` token file does not ensure that the correct file permissions are set on the file, which may expose the token to other user accounts on the system. I'm changing to the documentation to instead suggest running `umask 0077` before creating the file to ensure that no other user accounts on the system will have access to it. In addition, by putting the entire command in parentheses, the command is executed within a subshell so that the umask is only set temporarily for the purposes of creating the file: ```sh (umask 0077 && echo MY_SECRET_TOKEN > ~/.gist) ``` --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5df2c2c..a2c1f60 100644 --- a/README.md +++ b/README.md @@ -106,11 +106,13 @@ token file by pasting a GitHub token with only the `gist` permission into a file called `~/.gist`. You can create one from https://github.com/settings/tokens This file should contain only the token (~40 hex characters), and to make it -easier to edit, can optionally have a final newline (\n or \r\n). +easier to edit, can optionally have a final newline (`\n` or `\r\n`). For example, one way to create this file would be to run: - echo MY_SECRET_TOKEN > ~/.gist + (umask 0077 && echo MY_SECRET_TOKEN > ~/.gist) + +The `umask` ensures that the file is only accessible from your user account. ### GitHub Enterprise From 0f51f1db645853f2f7c4d9d6fcf888ad65c6940f Mon Sep 17 00:00:00 2001 From: Rajasegar Date: Thu, 5 Sep 2019 15:27:46 +0530 Subject: [PATCH 19/31] [BUGFIX] read_gist to behave like api --- bin/gist | 3 ++- lib/gist.rb | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/bin/gist b/bin/gist index 5618d08..f513187 100755 --- a/bin/gist +++ b/bin/gist @@ -173,7 +173,8 @@ begin if options.key? :read file_name = ARGV.first - Gist.read_gist(options[:read], file_name) + output = Gist.read_gist(options[:read], file_name) + puts output if output exit end diff --git a/lib/gist.rb b/lib/gist.rb index c49b1dd..7fa511f 100644 --- a/lib/gist.rb +++ b/lib/gist.rb @@ -236,7 +236,7 @@ def read_gist(id, file_name=nil) file = files.values.first end - puts file["content"] + file["content"] else raise Error, "Gist with id of #{id} does not exist." end From e4cbdd6988615c6b31b5a51ae3b67694c93a0b92 Mon Sep 17 00:00:00 2001 From: Rajasegar Date: Thu, 5 Sep 2019 16:04:41 +0530 Subject: [PATCH 20/31] [CHORE] Adding access token via options for read_gist --- lib/gist.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/gist.rb b/lib/gist.rb index 7fa511f..c412ee0 100644 --- a/lib/gist.rb +++ b/lib/gist.rb @@ -214,10 +214,10 @@ def list_all_gists(user = "") end - def read_gist(id, file_name=nil) + def read_gist(id, file_name=nil, options={}) url = "#{base_path}/gists/#{id}" - access_token = auth_token() + access_token = (options[:access_token] || auth_token()) if access_token.to_s != '' url << "?access_token=" << CGI.escape(access_token) end From 417cd00d40c247e4ab6f897af4c10ea7d2791c5c Mon Sep 17 00:00:00 2001 From: Hideaki Igarashi Date: Tue, 10 Dec 2019 18:22:40 +0900 Subject: [PATCH 21/31] Supports proxy authentication --- lib/gist.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/gist.rb b/lib/gist.rb index c49b1dd..9584807 100644 --- a/lib/gist.rb +++ b/lib/gist.rb @@ -402,7 +402,11 @@ def http_connection(uri) env = ENV['http_proxy'] || ENV['HTTP_PROXY'] connection = if env proxy = URI(env) - Net::HTTP::Proxy(proxy.host, proxy.port).new(uri.host, uri.port) + if proxy.user + Net::HTTP::Proxy(proxy.host, proxy.port, proxy.user, proxy.password).new(uri.host, uri.port) + else + Net::HTTP::Proxy(proxy.host, proxy.port).new(uri.host, uri.port) + end else Net::HTTP.new(uri.host, uri.port) end From 635b1437a513e9a13367827ee3f74fbbdaa54aa8 Mon Sep 17 00:00:00 2001 From: Andrew Mayorov Date: Tue, 4 Feb 2020 14:25:54 +0300 Subject: [PATCH 22/31] Supply access token through Authorization header Instead of through query parameter, since that method is being actively deprecated. * https://developer.github.com/changes/2019-11-05-deprecated-passwords-and-authorizations-api/#authenticating-using-query-parameters * https://developer.github.com/v3/#oauth2-token-sent-in-a-header --- build/gist | 29 ++++++++++++++--------------- lib/gist.rb | 21 ++++++++++----------- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/build/gist b/build/gist index 3f32dcd..6f59dd3 100755 --- a/build/gist +++ b/build/gist @@ -1416,7 +1416,7 @@ module Gist def multi_gist(files, options={}) if options[:anonymous] raise 'Anonymous gists are no longer supported. Please log in with `gist --login`. ' \ - '(Github now requires credentials to gist https://bit.ly/2GBBxKw)' + '(GitHub now requires credentials to gist https://bit.ly/2GBBxKw)' else access_token = (options[:access_token] || auth_token()) end @@ -1442,9 +1442,9 @@ module Gist url = "#{base_path}/gists" url << "/" << CGI.escape(existing_gist) if existing_gist.to_s != '' - url << "?access_token=" << CGI.escape(access_token) if access_token.to_s != '' request = Net::HTTP::Post.new(url) + request['Authorization'] = "token #{access_token}" if access_token.to_s != '' request.body = JSON.dump(json) request.content_type = 'application/json' @@ -1480,9 +1480,10 @@ module Gist if user == "" access_token = auth_token() if access_token.to_s != '' - url << "/gists?access_token=" << CGI.escape(access_token) + url << "/gists" request = Net::HTTP::Get.new(url) + request['Authorization'] = "token #{access_token}" response = http(api_url, request) pretty_gist(response) @@ -1507,8 +1508,8 @@ module Gist if user == "" access_token = auth_token() if access_token.to_s != '' - url << "/gists?per_page=100&access_token=" << CGI.escape(access_token) - get_gist_pages(url) + url << "/gists?per_page=100" + get_gist_pages(url, access_token) else raise Error, "Not authenticated. Use 'gist --login' to login or 'gist -l username' to view public gists." end @@ -1524,11 +1525,9 @@ module Gist url = "#{base_path}/gists/#{id}" access_token = auth_token() - if access_token.to_s != '' - url << "?access_token=" << CGI.escape(access_token) - end request = Net::HTTP::Get.new(url) + request['Authorization'] = "token #{access_token}" if access_token.to_s != '' response = http(api_url, request) if response.code == '200' @@ -1554,9 +1553,8 @@ module Gist access_token = auth_token() if access_token.to_s != '' - url << "?access_token=" << CGI.escape(access_token) - request = Net::HTTP::Delete.new(url) + request["Authorization"] = "token #{access_token}" response = http(api_url, request) else raise Error, "Not authenticated. Use 'gist --login' to login." @@ -1569,9 +1567,10 @@ module Gist end end - def get_gist_pages(url) + def get_gist_pages(url, access_token = "") request = Net::HTTP::Get.new(url) + request['Authorization'] = "token #{access_token}" if access_token.to_s != '' response = http(api_url, request) pretty_gist(response) @@ -1579,7 +1578,7 @@ module Gist if link_header links = Hash[ link_header.gsub(/(<|>|")/, "").split(',').map { |link| link.split('; rel=') } ].invert - get_gist_pages(links['next']) if links['next'] + get_gist_pages(links['next'], access_token) if links['next'] end end @@ -1652,7 +1651,7 @@ module Gist # @option credentials [String] :password # @see http://developer.github.com/v3/oauth/ def login!(credentials={}) - puts "Obtaining OAuth2 access_token from github." + puts "Obtaining OAuth2 access_token from GitHub." loop do print "GitHub username: " username = credentials[:username] || $stdin.gets.strip @@ -1906,7 +1905,7 @@ filenames can be overridden by repeating the "-f" flag. The most useful reason to do this is to change the syntax highlighting. All gists must to be associated with a GitHub account, so you will need to login with -`gist --login` to obtain an Oauth2 access token. This is stored and used by gist in the future. +`gist --login` to obtain an OAuth2 access token. This is stored and used by gist in the future. Private gists do not have guessable URLs and can be created with "-p", you can also set the description at the top of the gist by passing "-d". @@ -2023,7 +2022,7 @@ end.parse! begin if Gist.auth_token.nil? puts 'Please log in with `gist --login`. ' \ - '(Github now requires credentials to gist https://bit.ly/2GBBxKw)' + '(GitHub now requires credentials to gist https://bit.ly/2GBBxKw)' exit(1) end diff --git a/lib/gist.rb b/lib/gist.rb index c49b1dd..848a87e 100644 --- a/lib/gist.rb +++ b/lib/gist.rb @@ -136,9 +136,9 @@ def multi_gist(files, options={}) url = "#{base_path}/gists" url << "/" << CGI.escape(existing_gist) if existing_gist.to_s != '' - url << "?access_token=" << CGI.escape(access_token) if access_token.to_s != '' request = Net::HTTP::Post.new(url) + request['Authorization'] = "token #{access_token}" if access_token.to_s != '' request.body = JSON.dump(json) request.content_type = 'application/json' @@ -174,9 +174,10 @@ def list_gists(user = "") if user == "" access_token = auth_token() if access_token.to_s != '' - url << "/gists?access_token=" << CGI.escape(access_token) + url << "/gists" request = Net::HTTP::Get.new(url) + request['Authorization'] = "token #{access_token}" response = http(api_url, request) pretty_gist(response) @@ -201,8 +202,8 @@ def list_all_gists(user = "") if user == "" access_token = auth_token() if access_token.to_s != '' - url << "/gists?per_page=100&access_token=" << CGI.escape(access_token) - get_gist_pages(url) + url << "/gists?per_page=100" + get_gist_pages(url, access_token) else raise Error, "Not authenticated. Use 'gist --login' to login or 'gist -l username' to view public gists." end @@ -218,11 +219,9 @@ def read_gist(id, file_name=nil) url = "#{base_path}/gists/#{id}" access_token = auth_token() - if access_token.to_s != '' - url << "?access_token=" << CGI.escape(access_token) - end request = Net::HTTP::Get.new(url) + request['Authorization'] = "token #{access_token}" if access_token.to_s != '' response = http(api_url, request) if response.code == '200' @@ -248,9 +247,8 @@ def delete_gist(id) access_token = auth_token() if access_token.to_s != '' - url << "?access_token=" << CGI.escape(access_token) - request = Net::HTTP::Delete.new(url) + request["Authorization"] = "token #{access_token}" response = http(api_url, request) else raise Error, "Not authenticated. Use 'gist --login' to login." @@ -263,9 +261,10 @@ def delete_gist(id) end end - def get_gist_pages(url) + def get_gist_pages(url, access_token = "") request = Net::HTTP::Get.new(url) + request['Authorization'] = "token #{access_token}" if access_token.to_s != '' response = http(api_url, request) pretty_gist(response) @@ -273,7 +272,7 @@ def get_gist_pages(url) if link_header links = Hash[ link_header.gsub(/(<|>|")/, "").split(',').map { |link| link.split('; rel=') } ].invert - get_gist_pages(links['next']) if links['next'] + get_gist_pages(links['next'], access_token) if links['next'] end end From ab14e2719bd35f28d9ab786dd7dde66a051326a6 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Thu, 6 Feb 2020 22:48:23 -0800 Subject: [PATCH 23/31] v5.1.0 --- build/gist | 2 +- lib/gist.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/gist b/build/gist index 6f59dd3..36870d0 100755 --- a/build/gist +++ b/build/gist @@ -1318,7 +1318,7 @@ end module Gist extend self - VERSION = '5.0.0' + VERSION = '5.1.0' # A list of clipboard commands with copy and paste support. CLIPBOARD_COMMANDS = { diff --git a/lib/gist.rb b/lib/gist.rb index 848a87e..bfab531 100644 --- a/lib/gist.rb +++ b/lib/gist.rb @@ -12,7 +12,7 @@ module Gist extend self - VERSION = '5.0.0' + VERSION = '5.1.0' # A list of clipboard commands with copy and paste support. CLIPBOARD_COMMANDS = { From b58ff3eb9dd8403af3f801be0eafcb2eb6f4ab2a Mon Sep 17 00:00:00 2001 From: Pavel Valena Date: Tue, 23 Jun 2020 15:27:16 +0200 Subject: [PATCH 24/31] Do not package build/* and ".gitignore" Resolves #317. --- gist.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gist.gemspec b/gist.gemspec index 3367e55..4d7a2f3 100644 --- a/gist.gemspec +++ b/gist.gemspec @@ -9,7 +9,7 @@ Gem::Specification.new do |s| s.email = ['conrad.irwin@gmail.com', 'rkingist@sharpsaw.org'] s.authors = ['Conrad Irwin', '☈king'] s.license = 'MIT' - s.files = `git ls-files`.split("\n") + s.files = `git ls-files`.split("\n") - Dir.glob("build/*") - [".gitignore"] s.require_paths = ["lib"] s.executables << 'gist' From 4e163584f32a5145144b9ac65eced4985e9ef895 Mon Sep 17 00:00:00 2001 From: Lucas Magasweran Date: Fri, 24 Jul 2020 20:19:31 +0200 Subject: [PATCH 25/31] Allow hyphens in GITHUB_URL The parsing of the `GITHUB_URL` should support hyphens in host names to comply with https://tools.ietf.org/html/rfc952 . Otherwise `gist` will fail to find the corresponding `.gist` token file if the server contains a hyphen. For example, `https://github.my-corp.com/`. Signed-off-by: Lucas Magasweran --- lib/gist.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gist.rb b/lib/gist.rb index bfab531..cb4c628 100644 --- a/lib/gist.rb +++ b/lib/gist.rb @@ -44,7 +44,7 @@ class ClipboardError < RuntimeError; include Error end module AuthTokenFile def self.filename if ENV.key?(URL_ENV_NAME) - File.expand_path "~/.gist.#{ENV[URL_ENV_NAME].gsub(/:/, '.').gsub(/[^a-z0-9.]/, '')}" + File.expand_path "~/.gist.#{ENV[URL_ENV_NAME].gsub(/:/, '.').gsub(/[^a-z0-9.-]/, '')}" else File.expand_path "~/.gist" end From 00c0fdd2e24a79e48dc22f4a423aebc18ca92a42 Mon Sep 17 00:00:00 2001 From: Lucas Magasweran Date: Fri, 24 Jul 2020 20:45:54 +0200 Subject: [PATCH 26/31] docs: note the potential requirement for `user:email` scope Some GitHub Enterprise setups may require the additional `user:email` scope. Signed-off-by: Lucas Magasweran --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a2c1f60..a22ffcb 100644 --- a/README.md +++ b/README.md @@ -102,8 +102,9 @@ file. #### Password-less login If you have a complicated authorization requirement you can manually create a -token file by pasting a GitHub token with only the `gist` permission into a -file called `~/.gist`. You can create one from https://github.com/settings/tokens +token file by pasting a GitHub token with `gist` scope (and maybe the `user:email` +for GitHub Enterprise) into a file called `~/.gist`. You can create one from +https://github.com/settings/tokens This file should contain only the token (~40 hex characters), and to make it easier to edit, can optionally have a final newline (`\n` or `\r\n`). @@ -156,7 +157,7 @@ If you need more advanced features you can also pass: * `:copy` to copy the resulting URL to the clipboard (default is false). * `:open` to open the resulting URL in a browser (default is false). -NOTE: The access_token must have the "gist" scope. +NOTE: The access_token must have the `gist` scope and may also require the `user:email` scope. ‌If you want to upload multiple files in the same gist, you can: From e7bab05ef5740615a7ca83799c0092492be72b95 Mon Sep 17 00:00:00 2001 From: Lucas Magasweran Date: Mon, 27 Jul 2020 09:32:03 +0200 Subject: [PATCH 27/31] Always pass the auth token when listing all gists --- lib/gist.rb | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/lib/gist.rb b/lib/gist.rb index bfab531..93acbb4 100644 --- a/lib/gist.rb +++ b/lib/gist.rb @@ -200,19 +200,12 @@ def list_all_gists(user = "") url = "#{base_path}" if user == "" - access_token = auth_token() - if access_token.to_s != '' - url << "/gists?per_page=100" - get_gist_pages(url, access_token) - else - raise Error, "Not authenticated. Use 'gist --login' to login or 'gist -l username' to view public gists." - end - + url << "/gists?per_page=100" else url << "/users/#{user}/gists?per_page=100" - get_gist_pages(url) end + get_gist_pages(url, auth_token()) end def read_gist(id, file_name=nil) From 894693a22e025320d1007a21856d37ee7a8c7831 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Wed, 29 Jul 2020 23:46:38 -0700 Subject: [PATCH 28/31] Use new Oauth flow The username/password exchange mechanism is (rightfully) deprecated, the device flow is now in beta, and seems to be the perfect replacement. This change includes a best-guess of how this might work with GitHub Enterprise but I haven't tested that, so GitHub Enterprise will continue to default to the deprecated flow. Fixes #315 --- README.md | 23 ++++++++++++-- lib/gist.rb | 78 ++++++++++++++++++++++++++++++++++++++++++++---- spec/ghe_spec.rb | 17 +++++++---- 3 files changed, 105 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index a22ffcb..c55f322 100644 --- a/README.md +++ b/README.md @@ -84,9 +84,26 @@ To read a gist and print it to STDOUT ## Login -If you want to associate your gists with your GitHub account, you need to login -with gist. It doesn't store your username and password, it just uses them to get -an OAuth2 token (with the "gist" permission). +Before you use `gist` for the first time you will need to log in. There are two supported login flows: + +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. +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`. + +### The device-code flow + +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. + + gist --login + Requesting login parameters... + Please sign in at https://github.com/login/device + and enter code: XXXX-XXXX + Success! https://github.com/settings/connections/applications/4f7ec0d4eab38e74384e + +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. + +### The username-password flow + +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. gist --login Obtaining OAuth2 access_token from GitHub. diff --git a/lib/gist.rb b/lib/gist.rb index b96d05d..869a303 100644 --- a/lib/gist.rb +++ b/lib/gist.rb @@ -12,7 +12,7 @@ module Gist extend self - VERSION = '5.1.0' + VERSION = '6.0.0' # A list of clipboard commands with copy and paste support. CLIPBOARD_COMMANDS = { @@ -23,12 +23,16 @@ module Gist } GITHUB_API_URL = URI("https://api.github.com/") + GITHUB_URL = URI("https://github.com/") GIT_IO_URL = URI("https://git.io/") GITHUB_BASE_PATH = "" GHE_BASE_PATH = "/api/v3" + GITHUB_CLIENT_ID = '4f7ec0d4eab38e74384e' + URL_ENV_NAME = "GITHUB_URL" + CLIENT_ID_ENV_NAME = "GIST_CLIENT_ID" USER_AGENT = "gist/#{VERSION} (Net::HTTP, #{RUBY_DESCRIPTION})" @@ -329,15 +333,71 @@ def rawify(url) # Log the user into gist. # + def login!(credentials={}) + if (login_url == GITHUB_URL || ENV.key?(CLIENT_ID_ENV_NAME)) && credentials.empty? && !ENV.key?('GIST_USE_USERNAME_AND_PASSWORD') + device_flow_login! + else + access_token_login!(credentials) + end + end + + def device_flow_login! + puts "Requesting login parameters..." + request = Net::HTTP::Post.new("/login/device/code") + request.body = JSON.dump({ + :scope => 'gist', + :client_id => client_id, + }) + request.content_type = 'application/json' + request['accept'] = "application/json" + response = http(login_url, request) + + if response.code != '200' + raise Error, "HTTP #{response.code}: #{response.body}" + end + + body = JSON.parse(response.body) + + puts "Please sign in at #{body['verification_uri']}" + puts " and enter code: #{body['user_code']}" + device_code = body['device_code'] + interval = body['interval'] + + loop do + sleep(interval.to_i) + request = Net::HTTP::Post.new("/login/oauth/access_token") + request.body = JSON.dump({ + :client_id => client_id, + :grant_type => 'urn:ietf:params:oauth:grant-type:device_code', + :device_code => device_code + }) + request.content_type = 'application/json' + request['Accept'] = 'application/json' + response = http(login_url, request) + if response.code != '200' + raise Error, "HTTP #{response.code}: #{response.body}" + end + body = JSON.parse(response.body) + break unless body['error'] == 'authorization_pending' + end + + if body['error'] + raise Error, body['error_description'] + end + + AuthTokenFile.write JSON.parse(response.body)['access_token'] + + puts "Success! #{ENV[URL_ENV_NAME] || "https://github.com/"}settings/connections/applications/#{client_id}" + end + + # Logs the user into gist. + # # This method asks the user for a username and password, and tries to obtain # and OAuth2 access token, which is then stored in ~/.gist # # @raise [Gist::Error] if something went wrong - # @param [Hash] credentials login details - # @option credentials [String] :username - # @option credentials [String] :password # @see http://developer.github.com/v3/oauth/ - def login!(credentials={}) + def access_token_login!(credentials={}) puts "Obtaining OAuth2 access_token from GitHub." loop do print "GitHub username: " @@ -548,11 +608,19 @@ def base_path ENV.key?(URL_ENV_NAME) ? GHE_BASE_PATH : GITHUB_BASE_PATH end + def login_url + ENV.key?(URL_ENV_NAME) ? URI(ENV[URL_ENV_NAME]) : GITHUB_URL + end + # Get the API URL def api_url ENV.key?(URL_ENV_NAME) ? URI(ENV[URL_ENV_NAME]) : GITHUB_API_URL end + def client_id + ENV.key?(CLIENT_ID_ENV_NAME) ? URI(ENV[CLIENT_ID_ENV_NAME]) : GITHUB_CLIENT_ID + end + def legacy_private_gister? return unless which('git') `git config --global gist.private` =~ /\Ayes|1|true|on\z/i diff --git a/spec/ghe_spec.rb b/spec/ghe_spec.rb index 5d88a2f..9279915 100644 --- a/spec/ghe_spec.rb +++ b/spec/ghe_spec.rb @@ -5,10 +5,10 @@ MOCK_USER = 'foo' MOCK_PASSWORD = 'bar' - MOCK_AUTHZ_GHE_URL = "#{MOCK_GHE_PROTOCOL}://#{MOCK_USER}:#{MOCK_PASSWORD}@#{MOCK_GHE_HOST}/api/v3/" + MOCK_AUTHZ_GHE_URL = "#{MOCK_GHE_PROTOCOL}://#{MOCK_GHE_HOST}/api/v3/" MOCK_GHE_URL = "#{MOCK_GHE_PROTOCOL}://#{MOCK_GHE_HOST}/api/v3/" - MOCK_AUTHZ_GITHUB_URL = "https://#{MOCK_USER}:#{MOCK_PASSWORD}@api.github.com/" MOCK_GITHUB_URL = "https://api.github.com/" + MOCK_LOGIN_URL = "https://github.com/" before do @saved_env = ENV[Gist::URL_ENV_NAME] @@ -20,8 +20,15 @@ # stub requests for /authorizations stub_request(:post, /#{MOCK_AUTHZ_GHE_URL}authorizations/). to_return(:status => 201, :body => '{"token": "asdf"}') - stub_request(:post, /#{MOCK_AUTHZ_GITHUB_URL}authorizations/). + stub_request(:post, /#{MOCK_GITHUB_URL}authorizations/). + with(headers: {'Authorization'=>'Basic Zm9vOmJhcg=='}). to_return(:status => 201, :body => '{"token": "asdf"}') + + stub_request(:post, /#{MOCK_LOGIN_URL}login\/device\/code/). + to_return(:status => 200, :body => '{"interval": "0.1", "user_code":"XXXX-XXXX", "device_code": "xxxx", "verification_uri": "https://github.com/login/device"}') + + stub_request(:post, /#{MOCK_LOGIN_URL}login\/oauth\/access_token/). + to_return(:status => 200, :body => '{"access_token":"zzzz"}') end after do @@ -48,7 +55,7 @@ Gist.login! - assert_requested(:post, /#{MOCK_AUTHZ_GITHUB_URL}authorizations/) + assert_requested(:post, /#{MOCK_LOGIN_URL}login\/oauth\/access_token/) end it "should access to #{MOCK_GHE_HOST} when $#{Gist::URL_ENV_NAME} was set" do @@ -65,7 +72,7 @@ $stdin = StringIO.new "#{MOCK_USER}_wrong\n#{MOCK_PASSWORD}_wrong\n" Gist.login! :username => MOCK_USER, :password => MOCK_PASSWORD - assert_requested(:post, /#{MOCK_AUTHZ_GITHUB_URL}authorizations/) + assert_requested(:post, /#{MOCK_GITHUB_URL}authorizations/) end end From d854c153131d74f821b6c8b4808014067904e2ef Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Wed, 26 Aug 2020 19:27:56 -0700 Subject: [PATCH 29/31] Build v6.0.0 --- build/gist | 97 +++++++++++++++++++++++++++++++++++++++++++--------- build/gist.1 | 67 ++++++++++++++++++++++++++---------- 2 files changed, 129 insertions(+), 35 deletions(-) diff --git a/build/gist b/build/gist index 36870d0..0f65a4a 100755 --- a/build/gist +++ b/build/gist @@ -1318,7 +1318,7 @@ end module Gist extend self - VERSION = '5.1.0' + VERSION = '6.0.0' # A list of clipboard commands with copy and paste support. CLIPBOARD_COMMANDS = { @@ -1329,12 +1329,16 @@ module Gist } GITHUB_API_URL = URI("https://api.github.com/") + GITHUB_URL = URI("https://github.com/") GIT_IO_URL = URI("https://git.io/") GITHUB_BASE_PATH = "" GHE_BASE_PATH = "/api/v3" + GITHUB_CLIENT_ID = '4f7ec0d4eab38e74384e' + URL_ENV_NAME = "GITHUB_URL" + CLIENT_ID_ENV_NAME = "GIST_CLIENT_ID" USER_AGENT = "gist/#{VERSION} (Net::HTTP, #{RUBY_DESCRIPTION})" @@ -1350,7 +1354,7 @@ module Gist module AuthTokenFile def self.filename if ENV.key?(URL_ENV_NAME) - File.expand_path "~/.gist.#{ENV[URL_ENV_NAME].gsub(/:/, '.').gsub(/[^a-z0-9.]/, '')}" + File.expand_path "~/.gist.#{ENV[URL_ENV_NAME].gsub(/:/, '.').gsub(/[^a-z0-9.-]/, '')}" else File.expand_path "~/.gist" end @@ -1506,19 +1510,12 @@ module Gist url = "#{base_path}" if user == "" - access_token = auth_token() - if access_token.to_s != '' - url << "/gists?per_page=100" - get_gist_pages(url, access_token) - else - raise Error, "Not authenticated. Use 'gist --login' to login or 'gist -l username' to view public gists." - end - + url << "/gists?per_page=100" else url << "/users/#{user}/gists?per_page=100" - get_gist_pages(url) end + get_gist_pages(url, auth_token()) end def read_gist(id, file_name=nil) @@ -1642,15 +1639,71 @@ module Gist # Log the user into gist. # + def login!(credentials={}) + if (login_url == GITHUB_URL || ENV.key?(CLIENT_ID_ENV_NAME)) && credentials.empty? && !ENV.key?('GIST_USE_USERNAME_AND_PASSWORD') + device_flow_login! + else + access_token_login!(credentials) + end + end + + def device_flow_login! + puts "Requesting login parameters..." + request = Net::HTTP::Post.new("/login/device/code") + request.body = JSON.dump({ + :scope => 'gist', + :client_id => client_id, + }) + request.content_type = 'application/json' + request['accept'] = "application/json" + response = http(login_url, request) + + if response.code != '200' + raise Error, "HTTP #{response.code}: #{response.body}" + end + + body = JSON.parse(response.body) + + puts "Please sign in at #{body['verification_uri']}" + puts " and enter code: #{body['user_code']}" + device_code = body['device_code'] + interval = body['interval'] + + loop do + sleep(interval.to_i) + request = Net::HTTP::Post.new("/login/oauth/access_token") + request.body = JSON.dump({ + :client_id => client_id, + :grant_type => 'urn:ietf:params:oauth:grant-type:device_code', + :device_code => device_code + }) + request.content_type = 'application/json' + request['Accept'] = 'application/json' + response = http(login_url, request) + if response.code != '200' + raise Error, "HTTP #{response.code}: #{response.body}" + end + body = JSON.parse(response.body) + break unless body['error'] == 'authorization_pending' + end + + if body['error'] + raise Error, body['error_description'] + end + + AuthTokenFile.write JSON.parse(response.body)['access_token'] + + puts "Success! #{ENV[URL_ENV_NAME] || "https://github.com/"}settings/connections/applications/#{client_id}" + end + + # Logs the user into gist. + # # This method asks the user for a username and password, and tries to obtain # and OAuth2 access token, which is then stored in ~/.gist # # @raise [Gist::Error] if something went wrong - # @param [Hash] credentials login details - # @option credentials [String] :username - # @option credentials [String] :password # @see http://developer.github.com/v3/oauth/ - def login!(credentials={}) + def access_token_login!(credentials={}) puts "Obtaining OAuth2 access_token from GitHub." loop do print "GitHub username: " @@ -1707,7 +1760,11 @@ module Gist env = ENV['http_proxy'] || ENV['HTTP_PROXY'] connection = if env proxy = URI(env) - Net::HTTP::Proxy(proxy.host, proxy.port).new(uri.host, uri.port) + if proxy.user + Net::HTTP::Proxy(proxy.host, proxy.port, proxy.user, proxy.password).new(uri.host, uri.port) + else + Net::HTTP::Proxy(proxy.host, proxy.port).new(uri.host, uri.port) + end else Net::HTTP.new(uri.host, uri.port) end @@ -1861,11 +1918,19 @@ Could not find copy command, tried: ENV.key?(URL_ENV_NAME) ? GHE_BASE_PATH : GITHUB_BASE_PATH end + def login_url + ENV.key?(URL_ENV_NAME) ? URI(ENV[URL_ENV_NAME]) : GITHUB_URL + end + # Get the API URL def api_url ENV.key?(URL_ENV_NAME) ? URI(ENV[URL_ENV_NAME]) : GITHUB_API_URL end + def client_id + ENV.key?(CLIENT_ID_ENV_NAME) ? URI(ENV[CLIENT_ID_ENV_NAME]) : GITHUB_CLIENT_ID + end + def legacy_private_gister? return unless which('git') `git config --global gist.private` =~ /\Ayes|1|true|on\z/i diff --git a/build/gist.1 b/build/gist.1 index 66fb503..850c556 100644 --- a/build/gist.1 +++ b/build/gist.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "GIST" "1" "May 2018" "" "Gist manual" +.TH "GIST" "1" "August 2020" "" "Gist manual" . .SH "NAME" \fBgist\fR \- upload code to https://gist\.github\.com @@ -29,6 +29,12 @@ For OS X, gist lives in Homebrew .IP brew install gist . +.IP "\(bu" 4 +For FreeBSD, gist lives in ports +. +.IP +pkg install gist +. .IP "" 0 . .SH "Command" @@ -121,14 +127,45 @@ See \fBgist \-\-help\fR for more detail\. .IP "" 0 . .SH "Login" -If you want to associate your gists with your GitHub account, you need to login with gist\. It doesn\'t store your username and password, it just uses them to get an OAuth2 token (with the "gist" permission)\. +Before you use \fBgist\fR for the first time you will need to log in\. There are two supported login flows: +. +.IP "1." 4 +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 \fBGIST_CLIENT_ID\fR with the client id of the Oauth app\. +. +.IP "2." 4 +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 \fBGIST_USE_USERNAME_AND_PASSWORD\fR\. +. +.IP "" 0 +. +.SS "The device\-code flow" +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\. +. +.IP "" 4 +. +.nf + +gist \-\-login +Requesting login parameters\.\.\. +Please sign in at https://github\.com/login/device + and enter code: XXXX\-XXXX +Success! https://github\.com/settings/connections/applications/4f7ec0d4eab38e74384e +. +.fi +. +.IP "" 0 +. +.P +The returned access_token is stored in \fB~/\.gist\fR and used for all future gisting\. If you need to you can revoke access from https://github\.com/settings/connections/applications/4f7ec0d4eab38e74384e\. +. +.SS "The username\-password flow" +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\. . .IP "" 4 . .nf gist \-\-login -Obtaining OAuth2 access_token from github\. +Obtaining OAuth2 access_token from GitHub\. GitHub username: ConradIrwin GitHub password: 2\-factor auth code: @@ -141,19 +178,11 @@ Success! https://github\.com/settings/tokens .P This token is stored in \fB~/\.gist\fR and used for all future gisting\. If you need to you can revoke it from https://github\.com/settings/tokens, or just delete the file\. . -.IP "\(bu" 4 -After you\'ve done this, you can still upload gists anonymously with \fB\-a\fR\. -. -.IP -gist \-a a\.rb -. -.IP "" 0 -. .P -If you have a complicated authorization requirement you can manually create a token file by pasting a Github token with only the \fBgist\fR permission into a file called \fB~/\.gist\fR\. You can create one from https://github\.com/settings/tokens +If you have a complicated authorization requirement you can manually create a token file by pasting a GitHub token with \fBgist\fR scope (and maybe the \fBuser:email\fR for GitHub Enterprise) into a file called \fB~/\.gist\fR\. You can create one from https://github\.com/settings/tokens . .P -This file should contain only the token (~40 hex characters), and to make it easier to edit, can optionally have a final newline (\en or \er\en)\. +This file should contain only the token (~40 hex characters), and to make it easier to edit, can optionally have a final newline (\fB\en\fR or \fB\er\en\fR)\. . .P For example, one way to create this file would be to run: @@ -162,12 +191,15 @@ For example, one way to create this file would be to run: . .nf -echo MY_SECRET_TOKEN > ~/\.gist +(umask 0077 && echo MY_SECRET_TOKEN > ~/\.gist) . .fi . .IP "" 0 . +.P +The \fBumask\fR ensures that the file is only accessible from your user account\. +. .SS "GitHub Enterprise" If you\'d like \fBgist\fR to use your locally installed GitHub Enterprise \fIhttps://enterprise\.github\.com/\fR, you need to export the \fBGITHUB_URL\fR environment variable (usually done in your \fB~/\.bashrc\fR)\. . @@ -182,7 +214,7 @@ export GITHUB_URL=http://github\.internal\.example\.com/ .IP "" 0 . .P -Once you\'ve done this and restarted your terminal (or run \fBsource ~/\.bashrc\fR), gist will automatically use github enterprise instead of the public github\.com +Once you\'ve done this and restarted your terminal (or run \fBsource ~/\.bashrc\fR), gist will automatically use GitHub Enterprise instead of the public github\.com . .P Your token for GitHub Enterprise will be stored in \fB\.gist\.\.[\.]\fR (e\.g\. \fB~/\.gist\.http\.github\.internal\.example\.com\fR for the GITHUB_URL example above) instead of \fB~/\.gist\fR\. @@ -218,9 +250,6 @@ If you need more advanced features you can also pass: \fB:update\fR to update an existing gist (can be a URL or an id)\. . .IP "\(bu" 4 -\fB:anonymous\fR to submit an anonymous gist (default is false)\. -. -.IP "\(bu" 4 \fB:copy\fR to copy the resulting URL to the clipboard (default is false)\. . .IP "\(bu" 4 @@ -229,7 +258,7 @@ If you need more advanced features you can also pass: .IP "" 0 . .P -NOTE: The access_token must have the "gist" scope\. +NOTE: The access_token must have the \fBgist\fR scope and may also require the \fBuser:email\fR scope\. . .IP "\(bu" 4 If you want to upload multiple files in the same gist, you can: From f969b4f6cc925468616f26e706c311f17d5b234e Mon Sep 17 00:00:00 2001 From: Lucas Magasweran Date: Mon, 14 Sep 2020 12:44:26 +0200 Subject: [PATCH 30/31] docs: Debian package renamed binary to `gist-paste` --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index a2c1f60..57d0e1d 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,11 @@ upload content to https://gist.github.com/. pkg install gist +<200c>For Ubuntu/Debian + + apt install gist + +Note: Debian renames the binary to `gist-paste` to avoid a name conflict. ## Command From 573a359d952a25ac3ac6a987dd096b22cf1e703f Mon Sep 17 00:00:00 2001 From: Edward Betts Date: Fri, 27 May 2022 17:57:04 +0200 Subject: [PATCH 31/31] Correct spelling mistakes --- build/gist | 4 ++-- lib/gist.rb | 2 +- vendor/json.rb | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/gist b/build/gist index 0f65a4a..40fb605 100755 --- a/build/gist +++ b/build/gist @@ -52,7 +52,7 @@ module JSON /(?=\*/) # single slash before this comment's end )* \*/ # the End of this comment - |[ \t\r\n]+ # whitespaces: space, horicontal tab, lf, cr + |[ \t\r\n]+ # whitespaces: space, horizontal tab, lf, cr )+ )mx @@ -72,7 +72,7 @@ module JSON # (keys) in a JSON object. Otherwise strings are returned, which is also # the default. # * *create_additions*: If set to false, the Parser doesn't create - # additions even if a matchin class and create_id was found. This option + # additions even if a matching class and create_id was found. This option # defaults to true. # * *object_class*: Defaults to Hash # * *array_class*: Defaults to Array diff --git a/lib/gist.rb b/lib/gist.rb index 09d31cf..dac1b33 100644 --- a/lib/gist.rb +++ b/lib/gist.rb @@ -103,7 +103,7 @@ def default_filename # @option options [Boolean] :skip_empty (false) Skip gisting empty files. # @option options [Symbol] :output (:all) The type of return value you'd like: # :html_url gives a String containing the url to the gist in a browser - # :short_url gives a String contianing a git.io url that redirects to html_url + # :short_url gives a String containing a git.io url that redirects to html_url # :javascript gives a String containing a script tag suitable for embedding the gist # :all gives a Hash containing the parsed json response from the server # diff --git a/vendor/json.rb b/vendor/json.rb index 578791f..35e060b 100644 --- a/vendor/json.rb +++ b/vendor/json.rb @@ -1265,7 +1265,7 @@ def j(*objs) nil end - # Ouputs _objs_ to STDOUT as JSON strings in a pretty format, with + # Outputs _objs_ to STDOUT as JSON strings in a pretty format, with # indentation and over many lines. def jj(*objs) objs.each do |obj|