Refactor to use OpenID Connect OmniAuth gem instead of plain OAuth2
Right, I didn't totally connect the dots that there's some OpenID features in the mix here for how we expect to identify the user once they authenticate. It requires looking up the provider's public key, and validating the JWT they sent us. This gem does all that for us! I don't actually know what a real NeoPass `id_token` looks like yet? But I'll fill in some placeholder stuff for now, and use that for initializing the account!
This commit is contained in:
parent
ffcfce2eb8
commit
9cbeee0acd
26 changed files with 89 additions and 88 deletions
2
Gemfile
2
Gemfile
|
@ -27,7 +27,7 @@ gem 'devise', '~> 4.9', '>= 4.9.2'
|
||||||
gem 'devise-encryptable', '~> 0.2.0'
|
gem 'devise-encryptable', '~> 0.2.0'
|
||||||
gem 'omniauth', '~> 2.1'
|
gem 'omniauth', '~> 2.1'
|
||||||
gem 'omniauth-rails_csrf_protection', '~> 1.0'
|
gem 'omniauth-rails_csrf_protection', '~> 1.0'
|
||||||
gem 'omniauth-oauth2', '~> 1.8'
|
gem "omniauth_openid_connect", "~> 0.7.1"
|
||||||
|
|
||||||
# For pagination UI.
|
# For pagination UI.
|
||||||
gem 'will_paginate', '~> 4.0'
|
gem 'will_paginate', '~> 4.0'
|
||||||
|
|
65
Gemfile.lock
65
Gemfile.lock
|
@ -83,6 +83,7 @@ GEM
|
||||||
tzinfo (~> 2.0)
|
tzinfo (~> 2.0)
|
||||||
addressable (2.8.6)
|
addressable (2.8.6)
|
||||||
public_suffix (>= 2.0.2, < 6.0)
|
public_suffix (>= 2.0.2, < 6.0)
|
||||||
|
aes_key_wrap (1.1.0)
|
||||||
async (2.8.1)
|
async (2.8.1)
|
||||||
console (~> 1.10)
|
console (~> 1.10)
|
||||||
fiber-annotation
|
fiber-annotation
|
||||||
|
@ -105,6 +106,7 @@ GEM
|
||||||
async
|
async
|
||||||
async-pool (0.4.0)
|
async-pool (0.4.0)
|
||||||
async (>= 1.25)
|
async (>= 1.25)
|
||||||
|
attr_required (1.0.2)
|
||||||
babel-source (5.8.35)
|
babel-source (5.8.35)
|
||||||
babel-transpiler (0.7.0)
|
babel-transpiler (0.7.0)
|
||||||
babel-source (>= 4.0, < 6)
|
babel-source (>= 4.0, < 6)
|
||||||
|
@ -112,6 +114,7 @@ GEM
|
||||||
base64 (0.2.0)
|
base64 (0.2.0)
|
||||||
bcrypt (3.1.20)
|
bcrypt (3.1.20)
|
||||||
bigdecimal (3.1.6)
|
bigdecimal (3.1.6)
|
||||||
|
bindata (2.5.0)
|
||||||
bindex (0.8.1)
|
bindex (0.8.1)
|
||||||
bootsnap (1.18.3)
|
bootsnap (1.18.3)
|
||||||
msgpack (~> 1.2)
|
msgpack (~> 1.2)
|
||||||
|
@ -140,6 +143,8 @@ GEM
|
||||||
drb (2.2.0)
|
drb (2.2.0)
|
||||||
ruby2_keywords
|
ruby2_keywords
|
||||||
e2mmap (0.1.0)
|
e2mmap (0.1.0)
|
||||||
|
email_validator (2.2.4)
|
||||||
|
activemodel
|
||||||
erubi (1.12.0)
|
erubi (1.12.0)
|
||||||
execjs (2.9.1)
|
execjs (2.9.1)
|
||||||
falcon (0.43.0)
|
falcon (0.43.0)
|
||||||
|
@ -157,6 +162,8 @@ GEM
|
||||||
samovar (~> 2.1)
|
samovar (~> 2.1)
|
||||||
faraday (2.9.0)
|
faraday (2.9.0)
|
||||||
faraday-net_http (>= 2.0, < 3.2)
|
faraday-net_http (>= 2.0, < 3.2)
|
||||||
|
faraday-follow_redirects (0.3.0)
|
||||||
|
faraday (>= 1, < 3)
|
||||||
faraday-net_http (3.1.0)
|
faraday-net_http (3.1.0)
|
||||||
net-http
|
net-http
|
||||||
ffi (1.16.3)
|
ffi (1.16.3)
|
||||||
|
@ -183,8 +190,13 @@ GEM
|
||||||
jsbundling-rails (1.3.0)
|
jsbundling-rails (1.3.0)
|
||||||
railties (>= 6.0.0)
|
railties (>= 6.0.0)
|
||||||
json (2.7.1)
|
json (2.7.1)
|
||||||
jwt (2.8.1)
|
json-jwt (1.16.6)
|
||||||
|
activesupport (>= 4.2)
|
||||||
|
aes_key_wrap
|
||||||
base64
|
base64
|
||||||
|
bindata
|
||||||
|
faraday (~> 2.0)
|
||||||
|
faraday-follow_redirects
|
||||||
launchy (2.5.2)
|
launchy (2.5.2)
|
||||||
addressable (~> 2.8)
|
addressable (~> 2.8)
|
||||||
letter_opener (1.9.0)
|
letter_opener (1.9.0)
|
||||||
|
@ -223,23 +235,29 @@ GEM
|
||||||
nokogiri (1.16.2)
|
nokogiri (1.16.2)
|
||||||
mini_portile2 (~> 2.8.2)
|
mini_portile2 (~> 2.8.2)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
oauth2 (2.0.9)
|
|
||||||
faraday (>= 0.17.3, < 3.0)
|
|
||||||
jwt (>= 1.0, < 3.0)
|
|
||||||
multi_xml (~> 0.5)
|
|
||||||
rack (>= 1.2, < 4)
|
|
||||||
snaky_hash (~> 2.0)
|
|
||||||
version_gem (~> 1.1)
|
|
||||||
omniauth (2.1.2)
|
omniauth (2.1.2)
|
||||||
hashie (>= 3.4.6)
|
hashie (>= 3.4.6)
|
||||||
rack (>= 2.2.3)
|
rack (>= 2.2.3)
|
||||||
rack-protection
|
rack-protection
|
||||||
omniauth-oauth2 (1.8.0)
|
|
||||||
oauth2 (>= 1.4, < 3)
|
|
||||||
omniauth (~> 2.0)
|
|
||||||
omniauth-rails_csrf_protection (1.0.1)
|
omniauth-rails_csrf_protection (1.0.1)
|
||||||
actionpack (>= 4.2)
|
actionpack (>= 4.2)
|
||||||
omniauth (~> 2.0)
|
omniauth (~> 2.0)
|
||||||
|
omniauth_openid_connect (0.7.1)
|
||||||
|
omniauth (>= 1.9, < 3)
|
||||||
|
openid_connect (~> 2.2)
|
||||||
|
openid_connect (2.3.0)
|
||||||
|
activemodel
|
||||||
|
attr_required (>= 1.0.0)
|
||||||
|
email_validator
|
||||||
|
faraday (~> 2.0)
|
||||||
|
faraday-follow_redirects
|
||||||
|
json-jwt (>= 1.16)
|
||||||
|
mail
|
||||||
|
rack-oauth2 (~> 2.2)
|
||||||
|
swd (~> 2.0)
|
||||||
|
tzinfo
|
||||||
|
validate_url
|
||||||
|
webfinger (~> 2.0)
|
||||||
openssl (3.2.0)
|
openssl (3.2.0)
|
||||||
orm_adapter (0.5.0)
|
orm_adapter (0.5.0)
|
||||||
parallel (1.24.0)
|
parallel (1.24.0)
|
||||||
|
@ -265,6 +283,13 @@ GEM
|
||||||
rack (>= 1.0, < 4)
|
rack (>= 1.0, < 4)
|
||||||
rack-mini-profiler (3.3.1)
|
rack-mini-profiler (3.3.1)
|
||||||
rack (>= 1.2.0)
|
rack (>= 1.2.0)
|
||||||
|
rack-oauth2 (2.2.1)
|
||||||
|
activesupport
|
||||||
|
attr_required
|
||||||
|
faraday (~> 2.0)
|
||||||
|
faraday-follow_redirects
|
||||||
|
json-jwt (>= 1.11.0)
|
||||||
|
rack (>= 2.1.0)
|
||||||
rack-protection (4.0.0)
|
rack-protection (4.0.0)
|
||||||
base64 (>= 0.1.0)
|
base64 (>= 0.1.0)
|
||||||
rack (>= 3.0.0, < 4)
|
rack (>= 3.0.0, < 4)
|
||||||
|
@ -349,9 +374,6 @@ GEM
|
||||||
shell (0.8.1)
|
shell (0.8.1)
|
||||||
e2mmap
|
e2mmap
|
||||||
sync
|
sync
|
||||||
snaky_hash (2.0.1)
|
|
||||||
hashie
|
|
||||||
version_gem (~> 1.1, >= 1.1.1)
|
|
||||||
sprockets (4.2.1)
|
sprockets (4.2.1)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
rack (>= 2.2.4, < 4)
|
rack (>= 2.2.4, < 4)
|
||||||
|
@ -363,6 +385,11 @@ GEM
|
||||||
mini_portile2 (~> 2.8.0)
|
mini_portile2 (~> 2.8.0)
|
||||||
stackprof (0.2.26)
|
stackprof (0.2.26)
|
||||||
stringio (3.1.0)
|
stringio (3.1.0)
|
||||||
|
swd (2.0.3)
|
||||||
|
activesupport (>= 3)
|
||||||
|
attr_required (>= 0.0.5)
|
||||||
|
faraday (~> 2.0)
|
||||||
|
faraday-follow_redirects
|
||||||
sync (0.5.0)
|
sync (0.5.0)
|
||||||
temple (0.10.3)
|
temple (0.10.3)
|
||||||
terser (1.2.0)
|
terser (1.2.0)
|
||||||
|
@ -380,7 +407,9 @@ GEM
|
||||||
tzinfo (2.0.6)
|
tzinfo (2.0.6)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
uri (0.13.0)
|
uri (0.13.0)
|
||||||
version_gem (1.1.3)
|
validate_url (1.0.15)
|
||||||
|
activemodel (>= 3.0.0)
|
||||||
|
public_suffix
|
||||||
warden (1.2.9)
|
warden (1.2.9)
|
||||||
rack (>= 2.0.9)
|
rack (>= 2.0.9)
|
||||||
web-console (4.2.1)
|
web-console (4.2.1)
|
||||||
|
@ -388,6 +417,10 @@ GEM
|
||||||
activemodel (>= 6.0.0)
|
activemodel (>= 6.0.0)
|
||||||
bindex (>= 0.4.0)
|
bindex (>= 0.4.0)
|
||||||
railties (>= 6.0.0)
|
railties (>= 6.0.0)
|
||||||
|
webfinger (2.1.3)
|
||||||
|
activesupport
|
||||||
|
faraday (~> 2.0)
|
||||||
|
faraday-follow_redirects
|
||||||
webrick (1.8.1)
|
webrick (1.8.1)
|
||||||
websocket-driver (0.7.6)
|
websocket-driver (0.7.6)
|
||||||
websocket-extensions (>= 0.1.0)
|
websocket-extensions (>= 0.1.0)
|
||||||
|
@ -417,8 +450,8 @@ DEPENDENCIES
|
||||||
mysql2 (~> 0.5.5)
|
mysql2 (~> 0.5.5)
|
||||||
nokogiri (~> 1.15, >= 1.15.3)
|
nokogiri (~> 1.15, >= 1.15.3)
|
||||||
omniauth (~> 2.1)
|
omniauth (~> 2.1)
|
||||||
omniauth-oauth2 (~> 1.8)
|
|
||||||
omniauth-rails_csrf_protection (~> 1.0)
|
omniauth-rails_csrf_protection (~> 1.0)
|
||||||
|
omniauth_openid_connect (~> 0.7.1)
|
||||||
parallel (~> 1.23)
|
parallel (~> 1.23)
|
||||||
rack-attack (~> 6.7)
|
rack-attack (~> 6.7)
|
||||||
rack-mini-profiler (~> 3.1)
|
rack-mini-profiler (~> 3.1)
|
||||||
|
|
|
@ -3,14 +3,14 @@
|
||||||
* A test NeoPass server! This is a very lean, hacky implementation, designed
|
* A test NeoPass server! This is a very lean, hacky implementation, designed
|
||||||
* to just see the basic OAuth interactions Work At All.
|
* to just see the basic OAuth interactions Work At All.
|
||||||
*
|
*
|
||||||
* First, we have a "backing server", which is a `oauth2-mock-server` instance
|
* This server is an `oauth2-mock-server` instance that's easy to spin up and
|
||||||
* that's easy to spin up and have perform OAuth for us. We give it a hardcoded
|
* have perform OAuth for us. We give it a hardcoded development-only key, and
|
||||||
* development-only key, and it just auto-grants permissions!
|
* it just auto-grants permissions!
|
||||||
*
|
*
|
||||||
* We also have a "main server", which obeys the actual NeoPass API: the
|
* It slightly differs from the NeoPass spec, in that it uses different paths
|
||||||
* backing server isn't configurable with stuff like paths, so we use the main
|
* for its endpoints, but that's okay: DTI will use OpenID's "discovery"
|
||||||
* server to proxy from the paths in the NeoPass spec to the paths the backing
|
* feature to discover those endpoints via a single well-known path, without
|
||||||
* server uses.
|
* needing them hardcoded.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const fs = require("node:fs/promises");
|
const fs = require("node:fs/promises");
|
||||||
|
@ -67,7 +67,7 @@ async function ensureCertsExist() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function startBackingServer(port) {
|
async function startServer(port) {
|
||||||
const server = new OAuth2Server(
|
const server = new OAuth2Server(
|
||||||
keyPath,
|
keyPath,
|
||||||
certPath,
|
certPath,
|
||||||
|
@ -90,53 +90,12 @@ async function startBackingServer(port) {
|
||||||
});
|
});
|
||||||
|
|
||||||
await server.start(port, "localhost");
|
await server.start(port, "localhost");
|
||||||
console.log(`Started NeoPass backing server at: ${server.issuer.url}`);
|
console.log(`Started NeoPass development server at: ${server.issuer.url}`);
|
||||||
}
|
|
||||||
|
|
||||||
async function startMainServer(port) {
|
|
||||||
const fetch = (await import("node-fetch")).default;
|
|
||||||
|
|
||||||
const app = express();
|
|
||||||
app.use(express.text({ type: "*/*" }));
|
|
||||||
|
|
||||||
app.get("/", (req, res) => res.end("NeoPass development server for DTI!"));
|
|
||||||
|
|
||||||
app.get("/oauth2/auth", (req, res) => {
|
|
||||||
const query = urlLib.parse(req.url).query;
|
|
||||||
res.redirect(`http://localhost:8686/authorize?${query}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/oauth2/token", async (req, res) => {
|
|
||||||
try {
|
|
||||||
// For POST requests, the HTTP spec doesn't allow a redirect to a
|
|
||||||
// POST, so we proxy the request instead.
|
|
||||||
const backingRes = await fetch("http://localhost:8686/token", {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": req.get("Content-Type"),
|
|
||||||
},
|
|
||||||
body: req.body,
|
|
||||||
});
|
|
||||||
if (!backingRes.ok) {
|
|
||||||
throw new Error(`backing server returned status ${res.status}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
res.set("Content-Type", backingRes.headers.get("Content-Type"));
|
|
||||||
return res.end(await backingRes.text());
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
return res.end(error.message);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await new Promise((resolve) => app.listen(port, resolve));
|
|
||||||
console.log(`Started NeoPass main server at: http://localhost:${port}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
await ensureCertsExist();
|
await ensureCertsExist();
|
||||||
await startBackingServer(8686);
|
await startServer(8585);
|
||||||
await startMainServer(8585);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch((error) => {
|
main().catch((error) => {
|
||||||
|
|
|
@ -121,5 +121,9 @@ Rails.application.configure do
|
||||||
config.neopass_access_secret = "1"
|
config.neopass_access_secret = "1"
|
||||||
|
|
||||||
# Use the local NeoPass development server.
|
# Use the local NeoPass development server.
|
||||||
config.neopass_origin = "http://localhost:8585"
|
config.neopass_origin = "https://localhost:8585"
|
||||||
|
|
||||||
|
# Set the NeoPass redirect callback URL.
|
||||||
|
config.neopass_redirect_uri =
|
||||||
|
"http://localhost:3000/auth_users/auth/neopass/callback"
|
||||||
end
|
end
|
||||||
|
|
|
@ -140,4 +140,8 @@ Rails.application.configure do
|
||||||
|
|
||||||
# Use the live NeoPass production server.
|
# Use the live NeoPass production server.
|
||||||
config.neopass_origin = "https://oidc.neopets.com"
|
config.neopass_origin = "https://oidc.neopets.com"
|
||||||
|
|
||||||
|
# Set the NeoPass redirect callback URL.
|
||||||
|
config.neopass_redirect_uri =
|
||||||
|
"https://impress.openneo.net/auth_users/auth/neopass/callback"
|
||||||
end
|
end
|
||||||
|
|
|
@ -76,5 +76,9 @@ Rails.application.configure do
|
||||||
config.neopass_access_secret = "1"
|
config.neopass_access_secret = "1"
|
||||||
|
|
||||||
# Use the local NeoPass development server.
|
# Use the local NeoPass development server.
|
||||||
config.neopass_origin = "http://localhost:8585"
|
config.neopass_origin = "https://localhost:8585"
|
||||||
|
|
||||||
|
# Set the NeoPass redirect callback URL.
|
||||||
|
config.neopass_redirect_uri =
|
||||||
|
"http://localhost:3000/auth_users/auth/neopass/callback"
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
require "strategies/neopass"
|
|
||||||
|
|
||||||
# Assuming you have not yet modified this file, each configuration option below
|
# Assuming you have not yet modified this file, each configuration option below
|
||||||
# is set to its default value. Note that some are commented out while others
|
# is set to its default value. Note that some are commented out while others
|
||||||
|
@ -274,7 +273,21 @@ Devise.setup do |config|
|
||||||
# ==> OmniAuth
|
# ==> OmniAuth
|
||||||
# Add a new OmniAuth provider. Check the wiki for more information on setting
|
# Add a new OmniAuth provider. Check the wiki for more information on setting
|
||||||
# up on your models and hooks.
|
# up on your models and hooks.
|
||||||
config.omniauth :neopass, strategy_class: Strategies::NeoPass
|
config.omniauth :openid_connect, {
|
||||||
|
name: :neopass,
|
||||||
|
scope: [:openid, :email, :profile],
|
||||||
|
response_type: :code,
|
||||||
|
issuer: Rails.configuration.neopass_origin,
|
||||||
|
discovery: true,
|
||||||
|
client_options: {
|
||||||
|
identifier: "DTI-TODO",
|
||||||
|
secret: "DTI-TODO",
|
||||||
|
redirect_uri: Rails.configuration.neopass_redirect_uri,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
# Output OmniAuth debug info to the server logs in development
|
||||||
|
OmniAuth.config.logger = Rails.logger if Rails.env.development?
|
||||||
|
|
||||||
# ==> Warden configuration
|
# ==> Warden configuration
|
||||||
# If you want to use other strategies, that are not supported by Devise, or
|
# If you want to use other strategies, that are not supported by Devise, or
|
||||||
|
|
|
@ -18,7 +18,4 @@
|
||||||
ActiveSupport::Inflector.inflections(:en) do |inflect|
|
ActiveSupport::Inflector.inflections(:en) do |inflect|
|
||||||
# Teach Zeitwerk that `RocketAMF` is what to expect in `lib/rocketamf`.
|
# Teach Zeitwerk that `RocketAMF` is what to expect in `lib/rocketamf`.
|
||||||
inflect.acronym "RocketAMF"
|
inflect.acronym "RocketAMF"
|
||||||
|
|
||||||
# Teach Zeitwerk that "NeoPass" is what to expect in `neopass.rb`.
|
|
||||||
inflect.acronym "NeoPass"
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
require "omniauth-oauth2"
|
|
||||||
|
|
||||||
module Strategies
|
|
||||||
class NeoPass < OmniAuth::Strategies::OAuth2
|
|
||||||
option :name, "neopass"
|
|
||||||
|
|
||||||
option :client_options, {
|
|
||||||
site: Rails.configuration.neopass_origin,
|
|
||||||
authorize_url: "/oauth2/auth",
|
|
||||||
token_url: "/oauth2/token",
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
BIN
vendor/cache/aes_key_wrap-1.1.0.gem
vendored
Normal file
BIN
vendor/cache/aes_key_wrap-1.1.0.gem
vendored
Normal file
Binary file not shown.
BIN
vendor/cache/attr_required-1.0.2.gem
vendored
Normal file
BIN
vendor/cache/attr_required-1.0.2.gem
vendored
Normal file
Binary file not shown.
BIN
vendor/cache/bindata-2.5.0.gem
vendored
Normal file
BIN
vendor/cache/bindata-2.5.0.gem
vendored
Normal file
Binary file not shown.
BIN
vendor/cache/email_validator-2.2.4.gem
vendored
Normal file
BIN
vendor/cache/email_validator-2.2.4.gem
vendored
Normal file
Binary file not shown.
BIN
vendor/cache/faraday-follow_redirects-0.3.0.gem
vendored
Normal file
BIN
vendor/cache/faraday-follow_redirects-0.3.0.gem
vendored
Normal file
Binary file not shown.
BIN
vendor/cache/json-jwt-1.16.6.gem
vendored
Normal file
BIN
vendor/cache/json-jwt-1.16.6.gem
vendored
Normal file
Binary file not shown.
BIN
vendor/cache/jwt-2.8.1.gem
vendored
BIN
vendor/cache/jwt-2.8.1.gem
vendored
Binary file not shown.
BIN
vendor/cache/oauth2-2.0.9.gem
vendored
BIN
vendor/cache/oauth2-2.0.9.gem
vendored
Binary file not shown.
BIN
vendor/cache/omniauth-oauth2-1.8.0.gem
vendored
BIN
vendor/cache/omniauth-oauth2-1.8.0.gem
vendored
Binary file not shown.
BIN
vendor/cache/omniauth_openid_connect-0.7.1.gem
vendored
Normal file
BIN
vendor/cache/omniauth_openid_connect-0.7.1.gem
vendored
Normal file
Binary file not shown.
BIN
vendor/cache/openid_connect-2.3.0.gem
vendored
Normal file
BIN
vendor/cache/openid_connect-2.3.0.gem
vendored
Normal file
Binary file not shown.
BIN
vendor/cache/rack-oauth2-2.2.1.gem
vendored
Normal file
BIN
vendor/cache/rack-oauth2-2.2.1.gem
vendored
Normal file
Binary file not shown.
BIN
vendor/cache/snaky_hash-2.0.1.gem
vendored
BIN
vendor/cache/snaky_hash-2.0.1.gem
vendored
Binary file not shown.
BIN
vendor/cache/swd-2.0.3.gem
vendored
Normal file
BIN
vendor/cache/swd-2.0.3.gem
vendored
Normal file
Binary file not shown.
BIN
vendor/cache/validate_url-1.0.15.gem
vendored
Normal file
BIN
vendor/cache/validate_url-1.0.15.gem
vendored
Normal file
Binary file not shown.
BIN
vendor/cache/version_gem-1.1.3.gem
vendored
BIN
vendor/cache/version_gem-1.1.3.gem
vendored
Binary file not shown.
BIN
vendor/cache/webfinger-2.1.3.gem
vendored
Normal file
BIN
vendor/cache/webfinger-2.1.3.gem
vendored
Normal file
Binary file not shown.
Loading…
Reference in a new issue