ssh_key_switcher 1.0.0
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 +7 -0
- data/README.md +94 -0
- data/bin/sks +7 -0
- data/lib/ssh_key_switcher/options/current_agent.rb +38 -0
- data/lib/ssh_key_switcher/options/delete.rb +65 -0
- data/lib/ssh_key_switcher/options/ping.rb +24 -0
- data/lib/ssh_key_switcher/options/remove.rb +66 -0
- data/lib/ssh_key_switcher/options/select.rb +56 -0
- data/lib/ssh_key_switcher/utils/cmd.rb +20 -0
- data/lib/ssh_key_switcher/utils/contains.rb +9 -0
- data/lib/ssh_key_switcher/utils/helper.rb +27 -0
- data/lib/ssh_key_switcher/utils/ssh_agent.rb +19 -0
- data/lib/ssh_key_switcher/version.rb +3 -0
- data/lib/ssh_key_switcher.rb +45 -0
- metadata +88 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f533df5b3d9d76377ed35a3267899f82d5a7603a80c29894de402e854710f1d9
|
4
|
+
data.tar.gz: 2f077163c2255fc4498b7f8f9c1e6828387706fc669f1ad7f8e8d6fdcf89adf0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b721f9d2f12001dce27f73847a54ad3be8aff4d24cc865c234d986ffa69ebefb8198eba89e6104f8507d96a1fa3bf69fd48634a6af8c49bc8aaee8b02645e980
|
7
|
+
data.tar.gz: fbd9c084f585f68be76dd671f251100640ca3551f479107d35db48f70d706188129d0a689b04e490dced827dbbe9726d4c29dd1d2c05c1b8966a182161c443c9
|
data/README.md
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
# SSH Key Switcher
|
2
|
+
|
3
|
+
A simple and efficient Ruby gem for managing and switching between OpenSSH keys seamlessly
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'ssh_key_switcher'
|
11
|
+
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
```bash
|
17
|
+
$ bundle install
|
18
|
+
|
19
|
+
```
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
```bash
|
24
|
+
$ gem install ssh_key_switcher
|
25
|
+
|
26
|
+
```
|
27
|
+
|
28
|
+
## Usage
|
29
|
+
|
30
|
+
### Show Help
|
31
|
+
|
32
|
+
```bash
|
33
|
+
$ sks -h [--help]
|
34
|
+
|
35
|
+
```
|
36
|
+
|
37
|
+
### Show Version
|
38
|
+
|
39
|
+
```bash
|
40
|
+
$ sks -v [--version]
|
41
|
+
|
42
|
+
```
|
43
|
+
|
44
|
+
Displays the current version of SSH Key Switcher.
|
45
|
+
|
46
|
+
### Ping Server
|
47
|
+
|
48
|
+
```bash
|
49
|
+
$ sks -p [--ping]
|
50
|
+
|
51
|
+
```
|
52
|
+
|
53
|
+
Tests the connection to servers listed in **`SshKeySwitcher::Contains::SERVER_NAMES`**.
|
54
|
+
|
55
|
+
### Select OpenSSH Key
|
56
|
+
|
57
|
+
```bash
|
58
|
+
$ sks -s [--select]
|
59
|
+
|
60
|
+
```
|
61
|
+
|
62
|
+
Allows you to interactively select and set an OpenSSH key for your sessions.
|
63
|
+
|
64
|
+
### List Active OpenSSH Keys
|
65
|
+
|
66
|
+
```bash
|
67
|
+
$ sks -c [--current]
|
68
|
+
|
69
|
+
```
|
70
|
+
|
71
|
+
Displays a list of currently active SSH keys.
|
72
|
+
|
73
|
+
### Remove OpenSSH Key
|
74
|
+
|
75
|
+
```bash
|
76
|
+
$ sks --rm [--remove]
|
77
|
+
|
78
|
+
```
|
79
|
+
|
80
|
+
Interactive prompt to remove an OpenSSH key from the list of managed keys.
|
81
|
+
|
82
|
+
## Contributing
|
83
|
+
|
84
|
+
Bug reports and pull requests are welcome on GitHub at [SSH Key Switcher](https://github.com/TOMOSIA-VIETNAM/ssh_key_switcher).
|
85
|
+
|
86
|
+
## License
|
87
|
+
|
88
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
89
|
+
|
90
|
+
## Development
|
91
|
+
|
92
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
93
|
+
|
94
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
data/bin/sks
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SshKeySwitcher
|
4
|
+
module Options
|
5
|
+
class CurrentAgent
|
6
|
+
class << self
|
7
|
+
def fetch_results
|
8
|
+
results = []
|
9
|
+
payload = Cmd.exec('ssh-add -l')[0]
|
10
|
+
payload.each_line { |line| results << line.split[-2..].join(' ') }
|
11
|
+
results
|
12
|
+
end
|
13
|
+
|
14
|
+
def display
|
15
|
+
if fetch_results[0].include?('no identities')
|
16
|
+
prompt.warn('No active SSH keys')
|
17
|
+
elsif fetch_results.size == 1
|
18
|
+
prompt.say('Active SSH key: ')
|
19
|
+
prompt.ok(fetch_results[0])
|
20
|
+
else
|
21
|
+
prompt.say('List of active SSH keys:')
|
22
|
+
fetch_results.each.with_index(1) do |result, index|
|
23
|
+
prompt.ok(" #{index}) #{result}")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
include SshKeySwitcher::Utils
|
31
|
+
|
32
|
+
def prompt
|
33
|
+
@prompt ||= TTY::Prompt.new
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SshKeySwitcher
|
4
|
+
module Options
|
5
|
+
class Delete
|
6
|
+
class << self
|
7
|
+
def display_select
|
8
|
+
keys = Helper.find_open_ssh_keys
|
9
|
+
if keys.empty?
|
10
|
+
prompt.error('No OpenSSH keys found in ~/.ssh')
|
11
|
+
nil
|
12
|
+
else
|
13
|
+
msg = 'Choose the OpenSSH keys to REMOVE. Press [CTRL+C] to exit.'
|
14
|
+
prompt.multi_select(msg, select_options) do |menu|
|
15
|
+
menu.enum '.'
|
16
|
+
select_choices(menu, keys)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def del(path_open_ssh_keys)
|
22
|
+
is_no = prompt.no?('Are you sure you want to delete it permanently?')
|
23
|
+
|
24
|
+
if is_no
|
25
|
+
prompt.say('Cancelled!')
|
26
|
+
else
|
27
|
+
path_open_ssh_keys.each do |path|
|
28
|
+
SshKeySwitcher::Utils::SshAgent.del(path)
|
29
|
+
Cmd.exec("rm #{path}")
|
30
|
+
Cmd.exec("rm #{path}.pub")
|
31
|
+
end
|
32
|
+
prompt.ok('OpenSSH key removed successfully!')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
include SshKeySwitcher::Contains
|
39
|
+
include SshKeySwitcher::Utils
|
40
|
+
|
41
|
+
def prompt
|
42
|
+
@prompt ||= TTY::Prompt.new(interrupt: :exit)
|
43
|
+
end
|
44
|
+
|
45
|
+
def select_options
|
46
|
+
{
|
47
|
+
cycle: true,
|
48
|
+
symbols: { marker: '●' },
|
49
|
+
per_page: 100,
|
50
|
+
filter: true,
|
51
|
+
help: 'Use ↑/↓ arrow keys, and letter keys to filter',
|
52
|
+
show_help: :always
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
def select_choices(menu, keys)
|
57
|
+
keys.each do |value|
|
58
|
+
display_text = value.split('/')[-2..].join('/').gsub('.ssh/', '')
|
59
|
+
menu.choice display_text, value
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SshKeySwitcher
|
4
|
+
module Options
|
5
|
+
class Ping
|
6
|
+
class << self
|
7
|
+
def pong
|
8
|
+
server_names = SERVER_NAMES.map { |server| "git@#{server}" }
|
9
|
+
result = prompt.select('Connect to', server_names, default: 'git@github.com')
|
10
|
+
Cmd.exec("ssh -T #{result}", print: true)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
include SshKeySwitcher::Contains
|
16
|
+
include SshKeySwitcher::Utils
|
17
|
+
|
18
|
+
def prompt
|
19
|
+
@prompt ||= TTY::Prompt.new(interrupt: :exit)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SshKeySwitcher
|
4
|
+
module Options
|
5
|
+
class Remove
|
6
|
+
class << self
|
7
|
+
def display_select
|
8
|
+
keys = Helper.find_open_ssh_keys
|
9
|
+
if keys.empty?
|
10
|
+
prompt.error('No OpenSSH keys found in ~/.ssh')
|
11
|
+
nil
|
12
|
+
else
|
13
|
+
prompt.multi_select('Choose the OpenSSH keys to delete. Press [CTRL+C] to exit.',
|
14
|
+
select_options) do |menu|
|
15
|
+
menu.enum '.'
|
16
|
+
select_choices(menu, keys)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def del(path_open_ssh_keys)
|
23
|
+
is_no = prompt.no?('Are you sure you want to remove these keys?')
|
24
|
+
|
25
|
+
if is_no
|
26
|
+
prompt.say('Cancelled!')
|
27
|
+
else
|
28
|
+
path_open_ssh_keys.each do |path|
|
29
|
+
SshKeySwitcher::Utils::SshAgent.del(path)
|
30
|
+
Cmd.exec("rm #{path}")
|
31
|
+
Cmd.exec("rm #{path}.pub")
|
32
|
+
end
|
33
|
+
prompt.ok('OpenSSH key removed successfully!')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
include SshKeySwitcher::Contains
|
40
|
+
include SshKeySwitcher::Utils
|
41
|
+
|
42
|
+
def prompt
|
43
|
+
@prompt ||= TTY::Prompt.new(interrupt: :exit)
|
44
|
+
end
|
45
|
+
|
46
|
+
def select_options
|
47
|
+
{
|
48
|
+
cycle: true,
|
49
|
+
symbols: { marker: '●' },
|
50
|
+
per_page: 100,
|
51
|
+
filter: true,
|
52
|
+
help: 'Use ↑/↓ arrow keys, and letter keys to filter',
|
53
|
+
show_help: :always
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
def select_choices(menu, keys)
|
58
|
+
keys.each do |value|
|
59
|
+
display_text = value.split('/')[-2..].join('/').gsub('.ssh/', '')
|
60
|
+
menu.choice display_text, value
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SshKeySwitcher
|
4
|
+
module Options
|
5
|
+
class Select
|
6
|
+
class << self
|
7
|
+
def display_select
|
8
|
+
ssh_keys = Helper.find_open_ssh_keys
|
9
|
+
if ssh_keys.empty?
|
10
|
+
prompt.error('No OpenSSH keys found in ~/.ssh')
|
11
|
+
nil
|
12
|
+
else
|
13
|
+
prompt.select('Select an OpenSSH key:', select_options) do |menu|
|
14
|
+
menu.enum '.'
|
15
|
+
select_choices(menu, ssh_keys)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def add(path_open_ssh_key)
|
22
|
+
SshKeySwitcher::Utils::SshAgent.remove_all
|
23
|
+
SshKeySwitcher::Utils::SshAgent.add(path_open_ssh_key)
|
24
|
+
prompt.ok('OpenSSH key added successfully!')
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
include SshKeySwitcher::Contains
|
30
|
+
include SshKeySwitcher::Utils
|
31
|
+
|
32
|
+
def prompt
|
33
|
+
@prompt ||= TTY::Prompt.new(interrupt: :exit)
|
34
|
+
end
|
35
|
+
|
36
|
+
def select_options
|
37
|
+
{
|
38
|
+
cycle: true,
|
39
|
+
symbols: { marker: '➜' },
|
40
|
+
per_page: 20,
|
41
|
+
filter: true,
|
42
|
+
help: 'Use ↑/↓ arrow keys, and letter keys to filter',
|
43
|
+
show_help: :always
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
def select_choices(menu, keys)
|
48
|
+
keys.each do |value|
|
49
|
+
display_text = value.split('/')[-2..].join('/').gsub('.ssh/', '')
|
50
|
+
menu.choice display_text, value
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'open3'
|
4
|
+
|
5
|
+
module SshKeySwitcher
|
6
|
+
module Utils
|
7
|
+
module Cmd
|
8
|
+
module_function
|
9
|
+
|
10
|
+
def exec(command, opts = {})
|
11
|
+
stdout, stderr, status = Open3.capture3(command)
|
12
|
+
if opts[:print]
|
13
|
+
print stderr
|
14
|
+
print stdout
|
15
|
+
end
|
16
|
+
[stdout, stderr, status]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SshKeySwitcher
|
4
|
+
module Utils
|
5
|
+
module Helper
|
6
|
+
include SshKeySwitcher::Contains
|
7
|
+
|
8
|
+
module_function
|
9
|
+
|
10
|
+
def find_open_ssh_keys
|
11
|
+
ssh_folder = File.expand_path(SSH_DIR)
|
12
|
+
|
13
|
+
Dir.glob("#{ssh_folder}/*").select { |file| valid_ssh_key?(file) }.sort
|
14
|
+
end
|
15
|
+
|
16
|
+
def valid_ssh_key?(file)
|
17
|
+
File.open(file, 'rb') do |f|
|
18
|
+
# Read the first 20 bytes from the file
|
19
|
+
header = f.read(20)
|
20
|
+
header.include?(STRING_DETECT_OPENSSH_KEY)
|
21
|
+
end
|
22
|
+
rescue StandardError
|
23
|
+
false
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SshKeySwitcher
|
4
|
+
module Utils
|
5
|
+
class SshAgent
|
6
|
+
def self.add(key)
|
7
|
+
Cmd.exec("ssh-add #{key}")
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.remove_all
|
11
|
+
Cmd.exec('ssh-add -D')
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.del(path)
|
15
|
+
Cmd.exec("ssh-add -d #{path}")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'tty-prompt'
|
4
|
+
require 'thor'
|
5
|
+
require_relative 'ssh_key_switcher/version'
|
6
|
+
Dir.glob("#{__dir__}/ssh_key_switcher/utils/*.rb").sort.each { |file| require_relative(file) }
|
7
|
+
Dir.glob("#{__dir__}/ssh_key_switcher/options/*.rb").sort.each { |file| require_relative(file) }
|
8
|
+
|
9
|
+
module SshKeySwitcher
|
10
|
+
class Error < StandardError; end
|
11
|
+
|
12
|
+
class CLI < Thor
|
13
|
+
desc 'version [-v, --version]', 'Show version'
|
14
|
+
map %w[-v --version] => :version
|
15
|
+
def version
|
16
|
+
TTY::Prompt.new.say("SSHKeySwitcher version #{VERSION}")
|
17
|
+
end
|
18
|
+
|
19
|
+
desc 'ping [-p, --ping]', "Connect to servers #{SshKeySwitcher::Contains::SERVER_NAMES}"
|
20
|
+
map %w[-p --ping] => :ping
|
21
|
+
def ping
|
22
|
+
SshKeySwitcher::Options::Ping.pong
|
23
|
+
end
|
24
|
+
|
25
|
+
desc 'select [-s, --select]', 'Select an OpenSSH key'
|
26
|
+
map %w[-s --select] => :select
|
27
|
+
def select
|
28
|
+
path_open_ssh_key = SshKeySwitcher::Options::Select.display_select
|
29
|
+
SshKeySwitcher::Options::Select.add(path_open_ssh_key)
|
30
|
+
end
|
31
|
+
|
32
|
+
desc 'current [-c, --current]', 'List of active OpenSSH keys'
|
33
|
+
map %w[-c --current] => :current
|
34
|
+
def current
|
35
|
+
SshKeySwitcher::Options::CurrentAgent.display
|
36
|
+
end
|
37
|
+
|
38
|
+
desc 'remove [-rm, --remove]', 'Remove an OpenSSH key'
|
39
|
+
map %w[-rm --remove] => :remove
|
40
|
+
def remove
|
41
|
+
path_open_ssh_key = SshKeySwitcher::Options::Remove.display_select
|
42
|
+
SshKeySwitcher::Options::Remove.del(path_open_ssh_key)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
metadata
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ssh_key_switcher
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Minh Tang Q.
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-12-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: thor
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.3.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.3.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: tty-prompt
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.23.1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.23.1
|
41
|
+
description: Simple and efficient for managing and switching between OpenSSH keys
|
42
|
+
seamlessly
|
43
|
+
email:
|
44
|
+
- minh.tang1@tomosia.com
|
45
|
+
- vhquocminhit@gmail.com
|
46
|
+
executables:
|
47
|
+
- sks
|
48
|
+
extensions: []
|
49
|
+
extra_rdoc_files: []
|
50
|
+
files:
|
51
|
+
- README.md
|
52
|
+
- bin/sks
|
53
|
+
- lib/ssh_key_switcher.rb
|
54
|
+
- lib/ssh_key_switcher/options/current_agent.rb
|
55
|
+
- lib/ssh_key_switcher/options/delete.rb
|
56
|
+
- lib/ssh_key_switcher/options/ping.rb
|
57
|
+
- lib/ssh_key_switcher/options/remove.rb
|
58
|
+
- lib/ssh_key_switcher/options/select.rb
|
59
|
+
- lib/ssh_key_switcher/utils/cmd.rb
|
60
|
+
- lib/ssh_key_switcher/utils/contains.rb
|
61
|
+
- lib/ssh_key_switcher/utils/helper.rb
|
62
|
+
- lib/ssh_key_switcher/utils/ssh_agent.rb
|
63
|
+
- lib/ssh_key_switcher/version.rb
|
64
|
+
homepage: https://github.com
|
65
|
+
licenses:
|
66
|
+
- MIT
|
67
|
+
metadata:
|
68
|
+
rubygems_mfa_required: 'true'
|
69
|
+
post_install_message:
|
70
|
+
rdoc_options: []
|
71
|
+
require_paths:
|
72
|
+
- lib
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 2.6.0
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
requirements: []
|
84
|
+
rubygems_version: 3.3.20
|
85
|
+
signing_key:
|
86
|
+
specification_version: 4
|
87
|
+
summary: Simple and efficient for managing and switching between OpenSSH keys seamlessly
|
88
|
+
test_files: []
|