From 0f51f1db645853f2f7c4d9d6fcf888ad65c6940f Mon Sep 17 00:00:00 2001 From: Rajasegar Date: Thu, 5 Sep 2019 15:27:46 +0530 Subject: [PATCH 1/7] [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 2/7] [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 3/7] 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 b58ff3eb9dd8403af3f801be0eafcb2eb6f4ab2a Mon Sep 17 00:00:00 2001 From: Pavel Valena Date: Tue, 23 Jun 2020 15:27:16 +0200 Subject: [PATCH 4/7] 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 d854c153131d74f821b6c8b4808014067904e2ef Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Wed, 26 Aug 2020 19:27:56 -0700 Subject: [PATCH 5/7] 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 6/7] 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 7/7] 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|