glogin 0.16.5 → 0.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +14 -30
- data/Gemfile.lock +125 -0
- data/LICENSES/MIT.txt +21 -0
- data/README.md +20 -20
- data/REUSE.toml +36 -0
- data/Rakefile +8 -37
- data/glogin.gemspec +5 -21
- data/lib/glogin/auth.rb +64 -28
- data/lib/glogin/codec.rb +93 -29
- data/lib/glogin/cookie.rb +131 -43
- data/lib/glogin/version.rb +13 -21
- data/lib/glogin.rb +27 -22
- metadata +22 -28
- data/.0pdd.yml +0 -25
- data/.gitattributes +0 -7
- data/.github/workflows/actionlint.yml +0 -41
- data/.github/workflows/codecov.yml +0 -40
- data/.github/workflows/copyrights.yml +0 -30
- data/.github/workflows/markdown-lint.yml +0 -38
- data/.github/workflows/pdd.yml +0 -34
- data/.github/workflows/rake.yml +0 -43
- data/.github/workflows/xcop.yml +0 -30
- data/.gitignore +0 -7
- data/.pdd +0 -7
- data/.rubocop.yml +0 -52
- data/.rultor.yml +0 -42
- data/.simplecov +0 -41
- data/renovate.json +0 -6
- data/test/glogin/test_auth.rb +0 -82
- data/test/glogin/test_codec.rb +0 -89
- data/test/glogin/test_cookie.rb +0 -106
- data/test/test__helper.rb +0 -30
- data/test/test_glogin.rb +0 -35
data/lib/glogin/codec.rb
CHANGED
|
@@ -1,53 +1,93 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
-
# of this software and associated documentation files (the 'Software'), to deal
|
|
8
|
-
# in the Software without restriction, including without limitation the rights
|
|
9
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
-
# copies of the Software, and to permit persons to whom the Software is
|
|
11
|
-
# furnished to do so, subject to the following conditions:
|
|
12
|
-
#
|
|
13
|
-
# The above copyright notice and this permission notice shall be included in all
|
|
14
|
-
# copies or substantial portions of the Software.
|
|
15
|
-
#
|
|
16
|
-
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
-
# SOFTWARE.
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2017-2025 Yegor Bugayenko
|
|
4
|
+
# SPDX-License-Identifier: MIT
|
|
23
5
|
|
|
24
|
-
require 'securerandom'
|
|
25
|
-
require 'openssl'
|
|
26
|
-
require 'digest/sha1'
|
|
27
6
|
require 'base58'
|
|
28
7
|
require 'base64'
|
|
8
|
+
require 'digest/sha1'
|
|
9
|
+
require 'openssl'
|
|
10
|
+
require 'securerandom'
|
|
29
11
|
|
|
30
12
|
# Codec.
|
|
31
13
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
32
14
|
# Copyright:: Copyright (c) 2017-2025 Yegor Bugayenko
|
|
33
15
|
# License:: MIT
|
|
34
16
|
module GLogin
|
|
35
|
-
# The codec
|
|
17
|
+
# The codec for encrypting and decrypting text.
|
|
18
|
+
#
|
|
19
|
+
# This class provides symmetric encryption using AES-256-CBC. It can encode
|
|
20
|
+
# text using either Base64 or Base58 encoding. A random salt is added to
|
|
21
|
+
# each encryption to ensure that the same plaintext produces different
|
|
22
|
+
# ciphertexts each time.
|
|
23
|
+
#
|
|
24
|
+
# @example Basic encryption and decryption
|
|
25
|
+
# codec = GLogin::Codec.new('my-secret-key')
|
|
26
|
+
# encrypted = codec.encrypt('sensitive data')
|
|
27
|
+
# decrypted = codec.decrypt(encrypted)
|
|
28
|
+
# # => "sensitive data"
|
|
29
|
+
#
|
|
30
|
+
# @example Using Base64 encoding
|
|
31
|
+
# codec = GLogin::Codec.new('secret', base64: true)
|
|
32
|
+
# encrypted = codec.encrypt('hello world')
|
|
33
|
+
# # => "U29tZUJhc2U2NEVuY29kZWRTdHJpbmc="
|
|
34
|
+
#
|
|
35
|
+
# @example Test mode without encryption
|
|
36
|
+
# codec = GLogin::Codec.new('') # Empty secret
|
|
37
|
+
# encrypted = codec.encrypt('plaintext')
|
|
38
|
+
# # => "plaintext" (no encryption in test mode)
|
|
36
39
|
class Codec
|
|
37
|
-
#
|
|
40
|
+
# Raised when decryption fails.
|
|
41
|
+
#
|
|
42
|
+
# This can happen when:
|
|
43
|
+
# - The encrypted text is corrupted
|
|
44
|
+
# - The wrong secret key is used
|
|
45
|
+
# - The text is not properly encoded (Base64/Base58)
|
|
38
46
|
class DecodingError < StandardError; end
|
|
39
47
|
|
|
40
|
-
#
|
|
41
|
-
#
|
|
42
|
-
#
|
|
48
|
+
# Creates a new codec instance.
|
|
49
|
+
#
|
|
50
|
+
# @param secret [String] The secret key for encryption. If empty, no encryption is performed (test mode)
|
|
51
|
+
# @param base64 [Boolean] Whether to use Base64 encoding (true) or Base58 encoding (false)
|
|
52
|
+
# @raise [RuntimeError] if secret is nil
|
|
53
|
+
# @example Create codec with Base58 encoding (default)
|
|
54
|
+
# codec = GLogin::Codec.new('my-secret-key')
|
|
55
|
+
#
|
|
56
|
+
# @example Create codec with Base64 encoding
|
|
57
|
+
# codec = GLogin::Codec.new('my-secret-key', base64: true)
|
|
58
|
+
#
|
|
59
|
+
# @example Create codec in test mode (no encryption)
|
|
60
|
+
# codec = GLogin::Codec.new('')
|
|
43
61
|
def initialize(secret = '', base64: false)
|
|
44
62
|
raise 'Secret can\'t be nil' if secret.nil?
|
|
45
63
|
@secret = secret
|
|
46
64
|
@base64 = base64
|
|
47
65
|
end
|
|
48
66
|
|
|
67
|
+
# Decrypts an encrypted text string.
|
|
68
|
+
#
|
|
69
|
+
# @param text [String] The encrypted text to decrypt
|
|
70
|
+
# @return [String] The decrypted plaintext
|
|
71
|
+
# @raise [RuntimeError] if text is nil
|
|
72
|
+
# @raise [DecodingError] if decryption fails due to:
|
|
73
|
+
# - Invalid Base64/Base58 encoding
|
|
74
|
+
# - Wrong secret key
|
|
75
|
+
# - Corrupted ciphertext
|
|
76
|
+
# - Missing or invalid salt
|
|
77
|
+
# @example Decrypt a Base58-encoded string
|
|
78
|
+
# codec = GLogin::Codec.new('secret')
|
|
79
|
+
# plaintext = codec.decrypt('3Hs9k2LgU...')
|
|
80
|
+
# # => "hello world"
|
|
81
|
+
#
|
|
82
|
+
# @example Handle decryption errors
|
|
83
|
+
# begin
|
|
84
|
+
# plaintext = codec.decrypt(corrupted_text)
|
|
85
|
+
# rescue GLogin::Codec::DecodingError => e
|
|
86
|
+
# puts "Decryption failed: #{e.message}"
|
|
87
|
+
# end
|
|
49
88
|
def decrypt(text)
|
|
50
89
|
raise 'Text can\'t be nil' if text.nil?
|
|
90
|
+
text = text.to_s.encode('UTF-8', invalid: :replace, undef: :replace, replace: '?')
|
|
51
91
|
if @secret.empty?
|
|
52
92
|
text
|
|
53
93
|
else
|
|
@@ -73,6 +113,30 @@ module GLogin
|
|
|
73
113
|
raise DecodingError, e.message
|
|
74
114
|
end
|
|
75
115
|
|
|
116
|
+
# Encrypts a plaintext string.
|
|
117
|
+
#
|
|
118
|
+
# The method adds a random salt to the text before encryption to ensure
|
|
119
|
+
# that encrypting the same text multiple times produces different results.
|
|
120
|
+
# The encrypted output is encoded using either Base64 or Base58.
|
|
121
|
+
#
|
|
122
|
+
# @param text [String] The plaintext to encrypt
|
|
123
|
+
# @return [String] The encrypted and encoded text
|
|
124
|
+
# @raise [RuntimeError] if text is nil
|
|
125
|
+
# @example Encrypt with Base58 encoding
|
|
126
|
+
# codec = GLogin::Codec.new('secret')
|
|
127
|
+
# encrypted = codec.encrypt('sensitive data')
|
|
128
|
+
# # => "3Hs9k2LgU..." (Base58 encoded)
|
|
129
|
+
#
|
|
130
|
+
# @example Encrypt with Base64 encoding
|
|
131
|
+
# codec = GLogin::Codec.new('secret', base64: true)
|
|
132
|
+
# encrypted = codec.encrypt('sensitive data')
|
|
133
|
+
# # => "U29tZUJhc2U2NC..." (Base64 encoded)
|
|
134
|
+
#
|
|
135
|
+
# @example Multiple encryptions produce different results
|
|
136
|
+
# codec = GLogin::Codec.new('secret')
|
|
137
|
+
# enc1 = codec.encrypt('hello')
|
|
138
|
+
# enc2 = codec.encrypt('hello')
|
|
139
|
+
# enc1 != enc2 # => true (due to random salt)
|
|
76
140
|
def encrypt(text)
|
|
77
141
|
raise 'Text can\'t be nil' if text.nil?
|
|
78
142
|
if @secret.empty?
|
|
@@ -91,7 +155,7 @@ module GLogin
|
|
|
91
155
|
private
|
|
92
156
|
|
|
93
157
|
def digest(len)
|
|
94
|
-
Digest::SHA1.hexdigest(@secret)[0..len - 1]
|
|
158
|
+
Digest::SHA1.hexdigest(@secret)[0..(len - 1)]
|
|
95
159
|
end
|
|
96
160
|
|
|
97
161
|
def cipher
|
data/lib/glogin/cookie.rb
CHANGED
|
@@ -1,29 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
-
# of this software and associated documentation files (the 'Software'), to deal
|
|
8
|
-
# in the Software without restriction, including without limitation the rights
|
|
9
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
-
# copies of the Software, and to permit persons to whom the Software is
|
|
11
|
-
# furnished to do so, subject to the following conditions:
|
|
12
|
-
#
|
|
13
|
-
# The above copyright notice and this permission notice shall be included in all
|
|
14
|
-
# copies or substantial portions of the Software.
|
|
15
|
-
#
|
|
16
|
-
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
-
# SOFTWARE.
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2017-2025 Yegor Bugayenko
|
|
4
|
+
# SPDX-License-Identifier: MIT
|
|
23
5
|
|
|
24
|
-
require 'openssl'
|
|
25
|
-
require 'digest/sha1'
|
|
26
6
|
require 'base64'
|
|
7
|
+
require 'digest/sha1'
|
|
8
|
+
require 'openssl'
|
|
27
9
|
require_relative 'codec'
|
|
28
10
|
|
|
29
11
|
# GLogin main module.
|
|
@@ -34,18 +16,59 @@ module GLogin
|
|
|
34
16
|
# Split symbol inside the cookie text
|
|
35
17
|
SPLIT = '|'
|
|
36
18
|
|
|
19
|
+
# Secure cookie management for user sessions.
|
|
20
|
+
#
|
|
21
|
+
# This class provides two nested classes for handling cookies:
|
|
22
|
+
# - Cookie::Open: Creates encrypted cookies from user data
|
|
23
|
+
# - Cookie::Closed: Decrypts and validates existing cookies
|
|
37
24
|
#
|
|
38
|
-
#
|
|
25
|
+
# The cookie format stores user ID, login, avatar URL, and an optional
|
|
26
|
+
# context string for additional security validation.
|
|
39
27
|
#
|
|
28
|
+
# @example Creating and reading a cookie
|
|
29
|
+
# # After successful authentication
|
|
30
|
+
# user_data = auth.user(code)
|
|
31
|
+
# cookie = GLogin::Cookie::Open.new(user_data, 'secret-key')
|
|
32
|
+
# response.set_cookie('glogin', cookie.to_s)
|
|
33
|
+
#
|
|
34
|
+
# # When reading the cookie
|
|
35
|
+
# cookie_text = request.cookies['glogin']
|
|
36
|
+
# closed = GLogin::Cookie::Closed.new(cookie_text, 'secret-key')
|
|
37
|
+
# user = closed.to_user
|
|
38
|
+
# # => {"id"=>"123", "login"=>"username", "avatar_url"=>"https://..."}
|
|
40
39
|
class Cookie
|
|
41
|
-
# Closed cookie.
|
|
40
|
+
# Closed cookie for reading existing cookies.
|
|
42
41
|
#
|
|
43
42
|
# An instance of this class is created when a cookie arrives
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
#
|
|
47
|
-
#
|
|
43
|
+
# from the client. The encrypted cookie text is decrypted to
|
|
44
|
+
# retrieve the original user information.
|
|
45
|
+
#
|
|
46
|
+
# @example Read a cookie from HTTP request
|
|
47
|
+
# cookie_text = request.cookies['glogin']
|
|
48
|
+
# closed = GLogin::Cookie::Closed.new(cookie_text, ENV['SECRET'])
|
|
49
|
+
#
|
|
50
|
+
# begin
|
|
51
|
+
# user = closed.to_user
|
|
52
|
+
# session[:user_id] = user['id']
|
|
53
|
+
# rescue GLogin::Codec::DecodingError
|
|
54
|
+
# # Invalid cookie - redirect to login
|
|
55
|
+
# redirect '/login'
|
|
56
|
+
# end
|
|
57
|
+
#
|
|
58
|
+
# @example Using context for additional security
|
|
59
|
+
# closed = GLogin::Cookie::Closed.new(
|
|
60
|
+
# cookie_text,
|
|
61
|
+
# ENV['SECRET'],
|
|
62
|
+
# request.ip # Validate against IP address
|
|
63
|
+
# )
|
|
64
|
+
# user = closed.to_user
|
|
48
65
|
class Closed
|
|
66
|
+
# Creates a new closed cookie instance.
|
|
67
|
+
#
|
|
68
|
+
# @param text [String] The encrypted cookie text to decrypt
|
|
69
|
+
# @param secret [String] The secret key used for decryption
|
|
70
|
+
# @param context [String] Optional context string for validation
|
|
71
|
+
# @raise [RuntimeError] if any parameter is nil
|
|
49
72
|
def initialize(text, secret, context = '')
|
|
50
73
|
raise 'Text can\'t be nil' if text.nil?
|
|
51
74
|
@text = text
|
|
@@ -55,14 +78,27 @@ module GLogin
|
|
|
55
78
|
@context = context.to_s
|
|
56
79
|
end
|
|
57
80
|
|
|
58
|
-
#
|
|
81
|
+
# Decrypts and returns the user information from the cookie.
|
|
59
82
|
#
|
|
60
|
-
#
|
|
61
|
-
#
|
|
83
|
+
# @return [Hash] User information with keys 'id', 'login', and 'avatar_url'
|
|
84
|
+
# @raise [GLogin::Codec::DecodingError] if:
|
|
85
|
+
# - The cookie is corrupted or tampered with
|
|
86
|
+
# - The wrong secret key is used
|
|
87
|
+
# - The context doesn't match (if provided)
|
|
88
|
+
# @example Basic usage
|
|
89
|
+
# user = closed.to_user
|
|
90
|
+
# # => {"id"=>"123", "login"=>"octocat", "avatar_url"=>"https://..."}
|
|
62
91
|
#
|
|
63
|
-
#
|
|
64
|
-
#
|
|
65
|
-
#
|
|
92
|
+
# @example Error handling
|
|
93
|
+
# begin
|
|
94
|
+
# user = closed.to_user
|
|
95
|
+
# puts "Welcome, #{user['login']}!"
|
|
96
|
+
# rescue GLogin::Codec::DecodingError => e
|
|
97
|
+
# puts "Invalid session: #{e.message}"
|
|
98
|
+
# redirect_to_login
|
|
99
|
+
# end
|
|
100
|
+
#
|
|
101
|
+
# @note If the secret is empty (test mode), the text is used as-is without decryption
|
|
66
102
|
def to_user
|
|
67
103
|
plain = Codec.new(@secret).decrypt(@text)
|
|
68
104
|
id, login, avatar_url, ctx = plain.split(GLogin::SPLIT, 5)
|
|
@@ -76,18 +112,50 @@ module GLogin
|
|
|
76
112
|
end
|
|
77
113
|
end
|
|
78
114
|
|
|
79
|
-
# Open
|
|
115
|
+
# Open cookie for creating new cookies.
|
|
116
|
+
#
|
|
117
|
+
# This class takes user information from GitHub authentication
|
|
118
|
+
# and creates an encrypted cookie that can be sent to the client.
|
|
119
|
+
#
|
|
120
|
+
# @example Create a cookie after successful authentication
|
|
121
|
+
# user_data = auth.user(code)
|
|
122
|
+
# open = GLogin::Cookie::Open.new(user_data, ENV['SECRET'])
|
|
123
|
+
#
|
|
124
|
+
# # Set cookie with options
|
|
125
|
+
# response.set_cookie('glogin', {
|
|
126
|
+
# value: open.to_s,
|
|
127
|
+
# expires: 1.week.from_now,
|
|
128
|
+
# httponly: true,
|
|
129
|
+
# secure: true
|
|
130
|
+
# })
|
|
131
|
+
#
|
|
132
|
+
# @example Using context for IP-based validation
|
|
133
|
+
# open = GLogin::Cookie::Open.new(
|
|
134
|
+
# user_data,
|
|
135
|
+
# ENV['SECRET'],
|
|
136
|
+
# request.ip # Bind cookie to IP address
|
|
137
|
+
# )
|
|
138
|
+
# response.set_cookie('glogin', open.to_s)
|
|
80
139
|
class Open
|
|
81
140
|
attr_reader :id, :login, :avatar_url
|
|
82
141
|
|
|
83
|
-
#
|
|
142
|
+
# Creates a new open cookie from user data.
|
|
84
143
|
#
|
|
85
|
-
#
|
|
86
|
-
#
|
|
87
|
-
#
|
|
88
|
-
#
|
|
89
|
-
#
|
|
90
|
-
#
|
|
144
|
+
# @param json [Hash] User data from Auth#user, must contain 'id' key
|
|
145
|
+
# @param secret [String] Secret key for encryption
|
|
146
|
+
# @param context [String] Optional context for additional validation
|
|
147
|
+
# @raise [RuntimeError] if json is nil or missing 'id' key
|
|
148
|
+
# @raise [RuntimeError] if secret or context is nil
|
|
149
|
+
# @example
|
|
150
|
+
# user_data = {
|
|
151
|
+
# 'id' => '123456',
|
|
152
|
+
# 'login' => 'octocat',
|
|
153
|
+
# 'avatar_url' => 'https://github.com/octocat.png'
|
|
154
|
+
# }
|
|
155
|
+
# open = GLogin::Cookie::Open.new(user_data, 'secret-key')
|
|
156
|
+
# puts open.id # => "123456"
|
|
157
|
+
# puts open.login # => "octocat"
|
|
158
|
+
# puts open.avatar_url # => "https://github.com/octocat.png"
|
|
91
159
|
def initialize(json, secret, context = '')
|
|
92
160
|
raise 'JSON can\'t be nil' if json.nil?
|
|
93
161
|
raise 'JSON must contain "id" key' if json['id'].nil?
|
|
@@ -101,7 +169,27 @@ module GLogin
|
|
|
101
169
|
@context = context.to_s
|
|
102
170
|
end
|
|
103
171
|
|
|
104
|
-
#
|
|
172
|
+
# Generates the encrypted cookie string.
|
|
173
|
+
#
|
|
174
|
+
# This method encrypts the user information (id, login, avatar_url, and context)
|
|
175
|
+
# into a string that can be sent as an HTTP cookie. The encryption ensures
|
|
176
|
+
# the cookie cannot be tampered with.
|
|
177
|
+
#
|
|
178
|
+
# @return [String] The encrypted cookie value
|
|
179
|
+
# @example Generate cookie for HTTP response
|
|
180
|
+
# open = GLogin::Cookie::Open.new(user_data, secret)
|
|
181
|
+
# cookie_value = open.to_s
|
|
182
|
+
# # => "3Hs9k2LgU..." (encrypted string)
|
|
183
|
+
#
|
|
184
|
+
# # Use with Sinatra
|
|
185
|
+
# response.set_cookie('glogin', cookie_value)
|
|
186
|
+
#
|
|
187
|
+
# # Use with Rails
|
|
188
|
+
# cookies[:glogin] = {
|
|
189
|
+
# value: cookie_value,
|
|
190
|
+
# expires: 1.week.from_now,
|
|
191
|
+
# httponly: true
|
|
192
|
+
# }
|
|
105
193
|
def to_s
|
|
106
194
|
Codec.new(@secret).encrypt(
|
|
107
195
|
[
|
data/lib/glogin/version.rb
CHANGED
|
@@ -1,30 +1,22 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
-
# of this software and associated documentation files (the 'Software'), to deal
|
|
8
|
-
# in the Software without restriction, including without limitation the rights
|
|
9
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
-
# copies of the Software, and to permit persons to whom the Software is
|
|
11
|
-
# furnished to do so, subject to the following conditions:
|
|
12
|
-
#
|
|
13
|
-
# The above copyright notice and this permission notice shall be included in all
|
|
14
|
-
# copies or substantial portions of the Software.
|
|
15
|
-
#
|
|
16
|
-
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
-
# SOFTWARE.
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2017-2025 Yegor Bugayenko
|
|
4
|
+
# SPDX-License-Identifier: MIT
|
|
23
5
|
|
|
24
6
|
# GLogin main module.
|
|
25
7
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
26
8
|
# Copyright:: Copyright (c) 2017-2025 Yegor Bugayenko
|
|
27
9
|
# License:: MIT
|
|
28
10
|
module GLogin
|
|
29
|
-
|
|
11
|
+
# Current version of the GLogin gem.
|
|
12
|
+
#
|
|
13
|
+
# @example Check the gem version
|
|
14
|
+
# puts GLogin::VERSION
|
|
15
|
+
# # => "0.17.1"
|
|
16
|
+
#
|
|
17
|
+
# @example Version comparison
|
|
18
|
+
# if Gem::Version.new(GLogin::VERSION) >= Gem::Version.new('0.1.0')
|
|
19
|
+
# puts "Using GLogin version 0.1.0 or newer"
|
|
20
|
+
# end
|
|
21
|
+
VERSION = '0.17.1'
|
|
30
22
|
end
|
data/lib/glogin.rb
CHANGED
|
@@ -1,32 +1,37 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
-
# of this software and associated documentation files (the 'Software'), to deal
|
|
8
|
-
# in the Software without restriction, including without limitation the rights
|
|
9
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
-
# copies of the Software, and to permit persons to whom the Software is
|
|
11
|
-
# furnished to do so, subject to the following conditions:
|
|
12
|
-
#
|
|
13
|
-
# The above copyright notice and this permission notice shall be included in all
|
|
14
|
-
# copies or substantial portions of the Software.
|
|
15
|
-
#
|
|
16
|
-
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
-
# SOFTWARE.
|
|
3
|
+
# SPDX-FileCopyrightText: Copyright (c) 2017-2025 Yegor Bugayenko
|
|
4
|
+
# SPDX-License-Identifier: MIT
|
|
23
5
|
|
|
24
|
-
require 'nokogiri'
|
|
25
|
-
require_relative 'glogin/version'
|
|
26
6
|
require_relative 'glogin/auth'
|
|
27
7
|
require_relative 'glogin/cookie'
|
|
8
|
+
require_relative 'glogin/version'
|
|
28
9
|
|
|
29
10
|
# GLogin main module.
|
|
11
|
+
#
|
|
12
|
+
# GLogin is a Ruby gem that provides OAuth integration with GitHub. It simplifies
|
|
13
|
+
# the process of authenticating users through GitHub and managing their sessions
|
|
14
|
+
# using secure cookies.
|
|
15
|
+
#
|
|
16
|
+
# @example Basic usage with Sinatra
|
|
17
|
+
# require 'sinatra'
|
|
18
|
+
# require 'glogin'
|
|
19
|
+
#
|
|
20
|
+
# configure do
|
|
21
|
+
# set :glogin, GLogin::Auth.new(
|
|
22
|
+
# ENV['GITHUB_CLIENT_ID'],
|
|
23
|
+
# ENV['GITHUB_CLIENT_SECRET'],
|
|
24
|
+
# 'http://localhost:4567/auth'
|
|
25
|
+
# )
|
|
26
|
+
# end
|
|
27
|
+
#
|
|
28
|
+
# get '/auth' do
|
|
29
|
+
# user = settings.glogin.user(params[:code])
|
|
30
|
+
# cookie = GLogin::Cookie::Open.new(user, ENV['ENCRYPTION_SECRET'])
|
|
31
|
+
# response.set_cookie('glogin', cookie.to_s)
|
|
32
|
+
# redirect '/'
|
|
33
|
+
# end
|
|
34
|
+
#
|
|
30
35
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
31
36
|
# Copyright:: Copyright (c) 2017-2025 Yegor Bugayenko
|
|
32
37
|
# License:: MIT
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: glogin
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.17.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yegor Bugayenko
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: base58
|
|
@@ -24,6 +23,20 @@ dependencies:
|
|
|
24
23
|
- - ">="
|
|
25
24
|
- !ruby/object:Gem::Version
|
|
26
25
|
version: '0.2'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: base64
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '0.2'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '0.2'
|
|
27
40
|
- !ruby/object:Gem::Dependency
|
|
28
41
|
name: openssl
|
|
29
42
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -43,26 +56,15 @@ email: yegor256@gmail.com
|
|
|
43
56
|
executables: []
|
|
44
57
|
extensions: []
|
|
45
58
|
extra_rdoc_files:
|
|
46
|
-
- README.md
|
|
47
59
|
- LICENSE.txt
|
|
60
|
+
- README.md
|
|
48
61
|
files:
|
|
49
|
-
- ".0pdd.yml"
|
|
50
|
-
- ".gitattributes"
|
|
51
|
-
- ".github/workflows/actionlint.yml"
|
|
52
|
-
- ".github/workflows/codecov.yml"
|
|
53
|
-
- ".github/workflows/copyrights.yml"
|
|
54
|
-
- ".github/workflows/markdown-lint.yml"
|
|
55
|
-
- ".github/workflows/pdd.yml"
|
|
56
|
-
- ".github/workflows/rake.yml"
|
|
57
|
-
- ".github/workflows/xcop.yml"
|
|
58
|
-
- ".gitignore"
|
|
59
|
-
- ".pdd"
|
|
60
|
-
- ".rubocop.yml"
|
|
61
|
-
- ".rultor.yml"
|
|
62
|
-
- ".simplecov"
|
|
63
62
|
- Gemfile
|
|
63
|
+
- Gemfile.lock
|
|
64
64
|
- LICENSE.txt
|
|
65
|
+
- LICENSES/MIT.txt
|
|
65
66
|
- README.md
|
|
67
|
+
- REUSE.toml
|
|
66
68
|
- Rakefile
|
|
67
69
|
- glogin.gemspec
|
|
68
70
|
- lib/glogin.rb
|
|
@@ -71,18 +73,11 @@ files:
|
|
|
71
73
|
- lib/glogin/cookie.rb
|
|
72
74
|
- lib/glogin/version.rb
|
|
73
75
|
- logo.svg
|
|
74
|
-
|
|
75
|
-
- test/glogin/test_auth.rb
|
|
76
|
-
- test/glogin/test_codec.rb
|
|
77
|
-
- test/glogin/test_cookie.rb
|
|
78
|
-
- test/test__helper.rb
|
|
79
|
-
- test/test_glogin.rb
|
|
80
|
-
homepage: http://github.com/yegor256/glogin
|
|
76
|
+
homepage: https://github.com/yegor256/glogin
|
|
81
77
|
licenses:
|
|
82
78
|
- MIT
|
|
83
79
|
metadata:
|
|
84
80
|
rubygems_mfa_required: 'true'
|
|
85
|
-
post_install_message:
|
|
86
81
|
rdoc_options:
|
|
87
82
|
- "--charset=UTF-8"
|
|
88
83
|
require_paths:
|
|
@@ -98,8 +93,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
98
93
|
- !ruby/object:Gem::Version
|
|
99
94
|
version: '0'
|
|
100
95
|
requirements: []
|
|
101
|
-
rubygems_version: 3.
|
|
102
|
-
signing_key:
|
|
96
|
+
rubygems_version: 3.6.9
|
|
103
97
|
specification_version: 4
|
|
104
98
|
summary: Login/logout via GitHub OAuth for your web app
|
|
105
99
|
test_files: []
|
data/.0pdd.yml
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2017-2025 Yegor Bugayenko
|
|
2
|
-
#
|
|
3
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
-
# of this software and associated documentation files (the 'Software'), to deal
|
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
|
8
|
-
# furnished to do so, subject to the following conditions:
|
|
9
|
-
#
|
|
10
|
-
# The above copyright notice and this permission notice shall be included in all
|
|
11
|
-
# copies or substantial portions of the Software.
|
|
12
|
-
#
|
|
13
|
-
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
-
# SOFTWARE.
|
|
20
|
-
---
|
|
21
|
-
errors:
|
|
22
|
-
- yegor256@gmail.com
|
|
23
|
-
# alerts:
|
|
24
|
-
# github:
|
|
25
|
-
# - yegor256
|
data/.gitattributes
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2017-2025 Yegor Bugayenko
|
|
2
|
-
#
|
|
3
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
-
# of this software and associated documentation files (the 'Software'), to deal
|
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
|
8
|
-
# furnished to do so, subject to the following conditions:
|
|
9
|
-
#
|
|
10
|
-
# The above copyright notice and this permission notice shall be included in all
|
|
11
|
-
# copies or substantial portions of the Software.
|
|
12
|
-
#
|
|
13
|
-
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
-
# SOFTWARE.
|
|
20
|
-
---
|
|
21
|
-
name: actionlint
|
|
22
|
-
'on':
|
|
23
|
-
push:
|
|
24
|
-
branches:
|
|
25
|
-
- master
|
|
26
|
-
pull_request:
|
|
27
|
-
branches:
|
|
28
|
-
- master
|
|
29
|
-
jobs:
|
|
30
|
-
actionlint:
|
|
31
|
-
runs-on: ubuntu-24.04
|
|
32
|
-
steps:
|
|
33
|
-
- uses: actions/checkout@v4
|
|
34
|
-
- name: Download actionlint
|
|
35
|
-
id: get_actionlint
|
|
36
|
-
# yamllint disable-line rule:line-length
|
|
37
|
-
run: bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
|
|
38
|
-
shell: bash
|
|
39
|
-
- name: Check workflow files
|
|
40
|
-
run: ${{ steps.get_actionlint.outputs.executable }} -color
|
|
41
|
-
shell: bash
|