ccli 0.1.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/.rubocop.yml +121 -0
- data/.travis.yml +9 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +75 -0
- data/README.md +63 -0
- data/bin/cry +6 -0
- data/ccli.gemspec +24 -0
- data/lib/adapters/cluster_secret_adapter.rb +70 -0
- data/lib/adapters/cryptopus_adapter.rb +100 -0
- data/lib/adapters/k8s_adapter.rb +20 -0
- data/lib/adapters/ose_adapter.rb +20 -0
- data/lib/adapters/session_adapter.rb +74 -0
- data/lib/cli.rb +342 -0
- data/lib/errors.rb +40 -0
- data/lib/models/account.rb +44 -0
- data/lib/models/folder.rb +25 -0
- data/lib/models/k8s_secret.rb +11 -0
- data/lib/models/ose_secret.rb +28 -0
- data/lib/models/team.rb +45 -0
- data/lib/presenters/team_presenter.rb +18 -0
- data/lib/serializers/account_serializer.rb +57 -0
- data/lib/serializers/folder_serializer.rb +12 -0
- data/lib/serializers/ose_secret_serializer.rb +16 -0
- data/lib/serializers/team_serializer.rb +18 -0
- metadata +129 -0
data/lib/errors.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Error < StandardError
|
4
|
+
end
|
5
|
+
|
6
|
+
class SessionMissingError < Error
|
7
|
+
end
|
8
|
+
|
9
|
+
class UnauthorizedError < Error
|
10
|
+
end
|
11
|
+
|
12
|
+
class ForbiddenError < Error
|
13
|
+
end
|
14
|
+
|
15
|
+
class OpenshiftClientMissingError < Error
|
16
|
+
end
|
17
|
+
|
18
|
+
class OpenshiftClientNotLoggedInError < Error
|
19
|
+
end
|
20
|
+
|
21
|
+
class KubernetesClientMissingError < Error
|
22
|
+
end
|
23
|
+
|
24
|
+
class KubernetesClientNotLoggedInError < Error
|
25
|
+
end
|
26
|
+
|
27
|
+
class OpenshiftSecretNotFoundError < Error
|
28
|
+
end
|
29
|
+
|
30
|
+
class NoFolderSelectedError < Error
|
31
|
+
end
|
32
|
+
|
33
|
+
class CryptopusAccountNotFoundError < Error
|
34
|
+
end
|
35
|
+
|
36
|
+
class TeamNotFoundError < Error
|
37
|
+
end
|
38
|
+
|
39
|
+
class FolderNotFoundError < Error
|
40
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Account
|
4
|
+
attr_reader :id, :accountname, :username, :password, :type, :ose_secret
|
5
|
+
attr_accessor :folder
|
6
|
+
|
7
|
+
def initialize(accountname: nil, username: nil, password: nil,
|
8
|
+
ose_secret: nil, type: nil, id: nil)
|
9
|
+
@id = id
|
10
|
+
@accountname = accountname
|
11
|
+
@username = username
|
12
|
+
@password = password
|
13
|
+
@ose_secret = ose_secret
|
14
|
+
@type = type || 'credentials'
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_json(*_args)
|
18
|
+
AccountSerializer.to_json(self)
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_yaml
|
22
|
+
AccountSerializer.to_yaml(self)
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_osesecret
|
26
|
+
AccountSerializer.to_osesecret(self)
|
27
|
+
end
|
28
|
+
|
29
|
+
class << self
|
30
|
+
def find(id)
|
31
|
+
AccountSerializer.from_json(CryptopusAdapter.new.get("accounts/#{id}"))
|
32
|
+
end
|
33
|
+
|
34
|
+
def find_by_name_and_folder_id(name, id)
|
35
|
+
Folder.find(id).accounts.find do |account|
|
36
|
+
account.accountname.downcase == name.downcase
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def from_json(json)
|
41
|
+
AccountSerializer.from_json(json)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Folder
|
4
|
+
attr_reader :name, :id, :accounts
|
5
|
+
|
6
|
+
def initialize(name: nil, id: nil, accounts: [])
|
7
|
+
@name = name
|
8
|
+
@id = id
|
9
|
+
@accounts = accounts
|
10
|
+
end
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def find(id)
|
14
|
+
json = JSON.parse(CryptopusAdapter.new.get("folders/#{id}"),
|
15
|
+
symbolize_names: true)
|
16
|
+
included = json[:included] || []
|
17
|
+
name = json[:data][:attributes][:name]
|
18
|
+
accounts = included.map do |record|
|
19
|
+
Account.from_json(record.to_json) if %w[account_ose_secrets
|
20
|
+
account_credentials].include? record[:type]
|
21
|
+
end.compact
|
22
|
+
Folder.new(id: id, name: name, accounts: accounts)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class OSESecret
|
4
|
+
attr_reader :name, :ose_secret
|
5
|
+
|
6
|
+
def initialize(name, ose_secret)
|
7
|
+
@name = name
|
8
|
+
@ose_secret = ose_secret
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_account
|
12
|
+
OSESecretSerializer.to_account(self)
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_yaml
|
16
|
+
OSESecretSerializer.to_yaml(self)
|
17
|
+
end
|
18
|
+
|
19
|
+
class << self
|
20
|
+
def find_by_name(name)
|
21
|
+
OSESecretSerializer.from_yaml(OSEAdapter.new.fetch_secret(name))
|
22
|
+
end
|
23
|
+
|
24
|
+
def all
|
25
|
+
OSEAdapter.new.fetch_all_secrets.map { |s| OSESecretSerializer.from_yaml(s) }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/models/team.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Team
|
4
|
+
attr_reader :name, :id, :folders
|
5
|
+
|
6
|
+
def initialize(name: nil, folders: nil, id: nil)
|
7
|
+
@name = name
|
8
|
+
@folders = folders
|
9
|
+
@id = id
|
10
|
+
end
|
11
|
+
|
12
|
+
def render_list
|
13
|
+
TeamPresenter.render_list(self)
|
14
|
+
end
|
15
|
+
|
16
|
+
def folder_by_name(name)
|
17
|
+
folders.find do |folder|
|
18
|
+
folder.name.downcase.gsub(' ', '-') == name.downcase
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class << self
|
23
|
+
def all
|
24
|
+
cryptopus_adapter = CryptopusAdapter.new
|
25
|
+
response = JSON.parse(cryptopus_adapter.get('teams'), symbolize_names: true)
|
26
|
+
response[:data].map do |team|
|
27
|
+
TeamSerializer.from_json(team.to_json, folders_json: included_folders(response))
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def find_by_name(name)
|
32
|
+
Team.all.find do |team|
|
33
|
+
team.name.downcase.gsub(' ', '-') == name.downcase
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def included_folders(json)
|
40
|
+
json[:included].select do |folder|
|
41
|
+
folder[:type] == 'folders'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class TeamPresenter
|
4
|
+
class << self
|
5
|
+
def render_list(team)
|
6
|
+
team_name = team.name.downcase
|
7
|
+
despaced_team_name = team_name.gsub(' ', '-')
|
8
|
+
folder_rows = team.folders.map do |folder|
|
9
|
+
folder_name = folder.name.downcase
|
10
|
+
"#{folder_name} (cry use #{despaced_team_name}/#{folder_name.gsub(' ', '-')})"
|
11
|
+
end
|
12
|
+
|
13
|
+
team_name = "#{team_name} => "
|
14
|
+
joined_folder_rows = folder_rows.join("\n" + ' ' * team_name.length)
|
15
|
+
team_name + joined_folder_rows
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
class AccountSerializer
|
6
|
+
class << self
|
7
|
+
# rubocop:disable Metrics/MethodLength
|
8
|
+
def to_json(account)
|
9
|
+
{
|
10
|
+
data: {
|
11
|
+
type: 'accounts',
|
12
|
+
id: account.id,
|
13
|
+
attributes: {
|
14
|
+
accountname: account.accountname,
|
15
|
+
type: account.type,
|
16
|
+
cleartext_username: account.username,
|
17
|
+
cleartext_password: account.password,
|
18
|
+
ose_secret: account.ose_secret
|
19
|
+
},
|
20
|
+
relationships: {
|
21
|
+
folder: {
|
22
|
+
data: {
|
23
|
+
id: account.folder,
|
24
|
+
type: 'folders'
|
25
|
+
}
|
26
|
+
}
|
27
|
+
}
|
28
|
+
}
|
29
|
+
}.compact.to_json
|
30
|
+
end
|
31
|
+
# rubocop:enable Metrics/MethodLength
|
32
|
+
|
33
|
+
def to_yaml(account)
|
34
|
+
{ 'id' => account.id,
|
35
|
+
'accountname' => account.accountname,
|
36
|
+
'username' => account.username,
|
37
|
+
'password' => account.password,
|
38
|
+
'type' => account.type }.to_yaml
|
39
|
+
end
|
40
|
+
|
41
|
+
def from_json(json)
|
42
|
+
json = JSON.parse(json, symbolize_names: true)
|
43
|
+
data = json[:data] || json
|
44
|
+
attributes = data[:attributes]
|
45
|
+
Account.new(accountname: attributes[:accountname],
|
46
|
+
username: attributes[:cleartext_username],
|
47
|
+
password: attributes[:cleartext_password],
|
48
|
+
ose_secret: attributes[:ose_secret],
|
49
|
+
type: attributes[:type],
|
50
|
+
id: data[:id])
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_osesecret(account)
|
54
|
+
OSESecret.new(account.accountname, account.ose_secret)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class FolderSerializer
|
4
|
+
class << self
|
5
|
+
def from_json(json)
|
6
|
+
json = JSON.parse(json, symbolize_names: true)
|
7
|
+
data = json[:data] || json
|
8
|
+
attributes = data[:attributes]
|
9
|
+
Folder.new(name: attributes[:name], id: data[:id])
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'psych'
|
4
|
+
|
5
|
+
class OSESecretSerializer
|
6
|
+
class << self
|
7
|
+
def from_yaml(yaml)
|
8
|
+
secret_hash = Psych.load(yaml, symbolize_names: true)
|
9
|
+
OSESecret.new(secret_hash.dig(:metadata, :name), yaml)
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_account(secret)
|
13
|
+
Account.new(accountname: secret.name, ose_secret: secret.ose_secret, type: 'ose_secret')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class TeamSerializer
|
4
|
+
class << self
|
5
|
+
def from_json(json, folders_json: [])
|
6
|
+
json = JSON.parse(json, symbolize_names: true)
|
7
|
+
data = json[:data] || json
|
8
|
+
attributes = data[:attributes]
|
9
|
+
folder_ids = data[:relationships][:folders][:data].map { |folder| folder[:id] }
|
10
|
+
folders = folders_json.map do |folder|
|
11
|
+
FolderSerializer.from_json(folder.to_json) if folder_ids.include?(folder[:id])
|
12
|
+
end.compact
|
13
|
+
Team.new(name: attributes[:name],
|
14
|
+
folders: folders,
|
15
|
+
id: data[:id])
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ccli
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nils Rauch
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-10-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: commander
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.5'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 4.5.2
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '4.5'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 4.5.2
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: tty-command
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: tty-exit
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: tty-logger
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
type: :runtime
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
description:
|
76
|
+
email: rauch@puzzle.ch
|
77
|
+
executables:
|
78
|
+
- cry
|
79
|
+
extensions: []
|
80
|
+
extra_rdoc_files: []
|
81
|
+
files:
|
82
|
+
- ".rubocop.yml"
|
83
|
+
- ".travis.yml"
|
84
|
+
- Gemfile
|
85
|
+
- Gemfile.lock
|
86
|
+
- README.md
|
87
|
+
- bin/cry
|
88
|
+
- ccli.gemspec
|
89
|
+
- lib/adapters/cluster_secret_adapter.rb
|
90
|
+
- lib/adapters/cryptopus_adapter.rb
|
91
|
+
- lib/adapters/k8s_adapter.rb
|
92
|
+
- lib/adapters/ose_adapter.rb
|
93
|
+
- lib/adapters/session_adapter.rb
|
94
|
+
- lib/cli.rb
|
95
|
+
- lib/errors.rb
|
96
|
+
- lib/models/account.rb
|
97
|
+
- lib/models/folder.rb
|
98
|
+
- lib/models/k8s_secret.rb
|
99
|
+
- lib/models/ose_secret.rb
|
100
|
+
- lib/models/team.rb
|
101
|
+
- lib/presenters/team_presenter.rb
|
102
|
+
- lib/serializers/account_serializer.rb
|
103
|
+
- lib/serializers/folder_serializer.rb
|
104
|
+
- lib/serializers/ose_secret_serializer.rb
|
105
|
+
- lib/serializers/team_serializer.rb
|
106
|
+
homepage:
|
107
|
+
licenses: []
|
108
|
+
metadata: {}
|
109
|
+
post_install_message:
|
110
|
+
rdoc_options: []
|
111
|
+
require_paths:
|
112
|
+
- lib
|
113
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '2.0'
|
118
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
requirements: []
|
124
|
+
rubyforge_project:
|
125
|
+
rubygems_version: 2.7.9
|
126
|
+
signing_key:
|
127
|
+
specification_version: 4
|
128
|
+
summary: Command line client for the opensource password manager Cryptopus
|
129
|
+
test_files: []
|