forked from ccdcoe/Providentia
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Data model is: - `CredentialSet` <--many-to-one --> `Credential`
- Loading branch information
Showing
33 changed files
with
636 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# frozen_string_literal: true | ||
|
||
class CredentialSetsController < ApplicationController | ||
before_action :get_exercise | ||
before_action :get_credential_sets, only: %i[show update destroy] | ||
|
||
def index | ||
@credential_sets = authorized_scope(@exercise.credential_sets).order(:name) | ||
end | ||
|
||
def new | ||
@credential_set = @exercise.credential_sets.build | ||
authorize! @credential_set | ||
end | ||
|
||
def create | ||
@credential_set = @exercise.credential_sets.build(credential_set_params) | ||
authorize! @credential_set | ||
|
||
if @credential_set.save | ||
redirect_to [@credential_set.exercise, @credential_set], notice: 'Credential was successfully created.' | ||
else | ||
render :new, status: 400 | ||
end | ||
end | ||
|
||
def show; end | ||
|
||
def update | ||
if @credential_set.update credential_set_params | ||
redirect_to [@credential_set.exercise, @credential_set], notice: 'Credential was successfully updated.' | ||
else | ||
render :show, status: 400 | ||
end | ||
end | ||
|
||
def destroy | ||
if @credential_set.destroy | ||
redirect_to [@exercise, :credential_sets], notice: 'Credential was successfully destroyed.' | ||
else | ||
redirect_to [@exercise, :credential_set], flash: { error: @credential_set.errors.full_messages.join(', ') } | ||
end | ||
end | ||
|
||
private | ||
def credential_set_params | ||
params.require(:credential_set).permit(:name, :description, :network_id) | ||
end | ||
|
||
def get_credential_sets | ||
@credential_set = @exercise.credential_sets.friendly.find(params[:id]) | ||
authorize! @credential_set | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
# frozen_string_literal: true | ||
|
||
class CredentialsController < ApplicationController | ||
before_action :get_exercise, :get_credential_set | ||
before_action :get_credential, only: %i[show update destroy] | ||
|
||
respond_to :turbo_stream | ||
|
||
def new | ||
@credential = @credential_set.credentials.build | ||
authorize! @credential | ||
end | ||
|
||
def create | ||
@credential = @credential_set.credentials.build(credential_params) | ||
@credential.password = Credential.generate_password | ||
authorize! @credential | ||
@credential.save | ||
end | ||
|
||
def update | ||
if params[:cm] | ||
config_map_update | ||
elsif randomize_param.present? | ||
@credential.update(password: Credential.generate_password) | ||
else | ||
@credential.update(credential_params) | ||
end | ||
end | ||
|
||
def destroy | ||
@credential.destroy | ||
end | ||
|
||
def import | ||
parsed_creds = Psych.safe_load(params[:import_yaml], symbolize_names: true) | ||
Credential.transaction do | ||
parsed_creds[:credentials].each do |cred| | ||
next unless cred[:name].to_s.strip.present? | ||
cred in {password:} | ||
cred in {custom_fields: Hash => custom_fields} | ||
|
||
@credential_set.credentials | ||
.where(name: cred[:name].to_s.strip) | ||
.first_or_create(password: password || Credential.generate_password) | ||
.tap { | ||
_1.password = password if password | ||
_1.config_map.merge!(custom_fields) if custom_fields | ||
} | ||
.save | ||
end | ||
end | ||
rescue Psych::SyntaxError | ||
render status: 400 | ||
end | ||
|
||
|
||
private | ||
def get_credential_set | ||
@credential_set = authorized_scope(@exercise.credential_sets).friendly.find(params[:credential_set_id]) | ||
end | ||
|
||
def get_credential | ||
@credential = authorized_scope(@credential_set.credentials).find(params[:id]) | ||
authorize! @credential | ||
end | ||
|
||
def randomize_param | ||
@randomize_param ||= params[:credential].extract!(:randomize_password) | ||
end | ||
|
||
def credential_params | ||
params.require(:credential).permit(:name, :password, :email_override, :username_override, :read_only) | ||
end | ||
|
||
def config_map_update | ||
@form = ConfigMapForm.new(@credential, params[:cm]) | ||
if @form.save | ||
render turbo_stream: turbo_stream.remove('config_map_errors') | ||
else | ||
render turbo_stream: turbo_stream.append( | ||
helpers.dom_id(@credential, 'config_map_form'), | ||
FormErrorBoxComponent.new(@form, id: 'config_map_errors').render_in(view_context) | ||
) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# frozen_string_literal: true | ||
|
||
class Credential < ApplicationRecord | ||
has_paper_trail | ||
belongs_to :credential_set, touch: true | ||
|
||
validates :name, :password, presence: true | ||
|
||
def self.to_icon | ||
'fa-key' | ||
end | ||
|
||
def self.generate_password | ||
SecureRandom.alphanumeric(12) | ||
end | ||
|
||
def email | ||
[config_map['email'].presence || username, domain_from_network].join('@') | ||
end | ||
|
||
def username | ||
config_map['username'].presence || ActiveSupport::Inflector.parameterize(name, separator: '.') | ||
end | ||
|
||
def config_map_as_yaml | ||
config_map.to_yaml | ||
end | ||
|
||
private | ||
def domain_from_network | ||
return unless credential_set.network | ||
credential_set.network.full_domain | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# frozen_string_literal: true | ||
|
||
class CredentialBinding < ApplicationRecord | ||
belongs_to :credential_set | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# frozen_string_literal: true | ||
|
||
class CredentialSet < ApplicationRecord | ||
extend FriendlyId | ||
friendly_id :name, use: [:slugged, :scoped], scope: :exercise | ||
has_paper_trail | ||
|
||
belongs_to :exercise | ||
belongs_to :network, optional: true | ||
has_many :credentials, dependent: :destroy | ||
has_many :credential_bindings, dependent: :destroy | ||
|
||
validates :name, uniqueness: { scope: :exercise }, presence: true | ||
|
||
def self.to_icon | ||
'fa-key' | ||
end | ||
|
||
def network_domain_prefix | ||
network.full_domain.split('.').first.upcase if network | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# frozen_string_literal: true | ||
|
||
class CredentialPolicy < ApplicationPolicy | ||
def index? | ||
true | ||
end | ||
|
||
def show? | ||
true | ||
end | ||
|
||
def create? | ||
allowed_to?(:update?, record.credential_set) | ||
end | ||
|
||
def update? | ||
create? | ||
end | ||
|
||
def destroy? | ||
create? | ||
end | ||
|
||
relation_scope do |relation| | ||
next relation | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# frozen_string_literal: true | ||
|
||
class CredentialSetPolicy < ApplicationPolicy | ||
include EnvironmentAssociatedPolicy | ||
|
||
def show? | ||
can_read_exercise? | ||
end | ||
|
||
def create? | ||
false | ||
end | ||
|
||
def update? | ||
create? | ||
end | ||
|
||
def destroy? | ||
create? | ||
end | ||
|
||
relation_scope do |relation| | ||
next relation if user.super_admin? | ||
relation | ||
.joins(:exercise) | ||
.merge(Exercise.for_user(user)) | ||
.distinct | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
%li.px-4.my-2.group{id: dom_id(credential, 'list_item')} | ||
.flex.items-center | ||
= link_to credential.name, [@exercise, @credential_set, credential], class: 'grow text-lg font-bold', data: { turbo_frame: "editable_cred" } | ||
- if allowed_to?(:destroy?, credential) | ||
.opacity-0.group-hover:opacity-100.transition-opacity | ||
= link_to [@exercise, @credential_set, credential], data: { turbo_method: 'delete', turbo_confirm: 'Are you sure?' } do | ||
%i.fas.fa-times-circle.text-red-600 | ||
|
||
.flex.items-center.gap-1 | ||
.grow.opacity-60.text-sm= credential.email | ||
|
||
- %i(username password email).each do |cred_attr| | ||
%div{data: { controller: 'clipboard', clipboard_success_content_value: '<i>✓</i>'}} | ||
%span.hidden{data: {clipboard_target: 'source'}}<= credential.public_send(cred_attr) | ||
= link_to 'javascript:;', data: {action: "clipboard#copy"} do | ||
%span.inline-flex.items-center.gap-1.bg-blue-100.text-blue-800.text-xs.font-medium.rounded.dark:bg-blue-900.dark:text-blue-300{class: "px-2.5 py-0.5"} | ||
%span{data: {clipboard_target: 'button'}} | ||
%i.fas.fa-clipboard | ||
= Credential.human_attribute_name(cred_attr) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
= render SubResourceSectionComponent.new(header: 'Credentials list') do |section| | ||
- if allowed_to?(:create?, Credential.new(credential_set: @credential_set)) | ||
- section.with_button do | ||
= link_to [:new, @exercise, @credential_set, :credential], data: { turbo_frame: "editable_cred" }, class: 'form-submit-add' do | ||
%i.fas.fa-plus.self-center | ||
Add credential | ||
|
||
- section.with_button do | ||
= render ModalComponent.new(header: 'Bulk import credentials') do |c| | ||
- c.with_body do | ||
= form_with(url: import_exercise_credential_set_credentials_path(@exercise, @credential_set), data: { action: "modal#close"}) do |f| | ||
%p Importer is using following YAML format | ||
%code | ||
%pre | ||
:plain | ||
--- | ||
credentials: | ||
- name: User Name | ||
password: My.Password | ||
custom_fields: # freeform import to configmap | ||
|
||
.my-1= f.text_area :import_yaml, data: {controller: 'editor', editor_live_value: false} | ||
.my-2= f.submit :save, class: 'form-submit' | ||
|
||
= link_to 'javascript:;', class: 'form-submit', data: { action: "click->modal#open" } do | ||
Bulk import | ||
|
||
.grid.grid-cols-12.mb-8 | ||
%aside.col-span-6 | ||
%ul#credential-list.py-3.overflow-y-auto{class: 'h-[50vh]'} | ||
- @credential_set.credentials.order(:name).each do |credential| | ||
= render 'credential_list_row', credential: | ||
|
||
= turbo_frame_tag 'editable_cred', class: 'col-span-6 border-l-4 border-double border-zinc-500 bg-zinc-100 dark:bg-zinc-800' do | ||
= render 'empty' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
.flex.h-full.items-center.justify-center | ||
.text-3xl.text-gray-700.dark:text-gray-500.text-center | ||
%i.fas.fa-3x{class: Credential.to_icon} | ||
|
||
%p.py-6 | ||
Select a cred from the list or add a new one |
Oops, something went wrong.