1
0
Fork 0

Remove cryptography

This commit is contained in:
Alex Kotov 2019-09-15 18:26:15 +05:00
parent 557e892e44
commit 358069eeea
Signed by: kotovalexarian
GPG key ID: 553C0EBBEB5D5F08
82 changed files with 24 additions and 2917 deletions

View file

@ -21,7 +21,6 @@ Layout/EmptyLinesAroundArguments:
Enabled: false Enabled: false
Metrics/AbcSize: Metrics/AbcSize:
Max: 15.5
Exclude: Exclude:
- 'db/migrate/*.rb' - 'db/migrate/*.rb'
@ -48,7 +47,6 @@ Metrics/MethodLength:
Naming/PredicateName: Naming/PredicateName:
Exclude: Exclude:
- 'app/forms/application_form.rb'
- 'app/models/application_record.rb' - 'app/models/application_record.rb'
Rails: Rails:

View file

@ -21,12 +21,7 @@ private
@current_account ||= current_user&.account @current_account ||= current_user&.account
end end
def pundit_user alias pundit_user current_account
@pundit_user ||= ApplicationPolicy::Context.new(
account: current_account,
params: params,
)
end
def set_raven_context def set_raven_context
Raven.user_context( Raven.user_context(

View file

@ -1,60 +0,0 @@
# frozen_string_literal: true
class AsymmetricKeysController < ApplicationController
before_action :set_asymmetric_key, except: %i[index new create]
# GET /asymmetric_keys
def index
authorize AsymmetricKey
@asymmetric_keys = policy_scope(AsymmetricKey).page(params[:page])
end
# GET /asymmetric_keys/:id
def show
authorize @asymmetric_key
respond_to do |format|
format.html
format.pem do
send_data @asymmetric_key.public_key_pem, filename: 'public.pem'
end
end
end
# GET /asymmetric_keys/new
def new
@asymmetric_key_form = AsymmetricKeyForm.new
authorize @asymmetric_key_form
end
# POST /asymmetric_keys
def create
@asymmetric_key_form = AsymmetricKeyForm.new asymmetric_key_form_params
authorize @asymmetric_key_form
result = ImportAsymmetricKey.call @asymmetric_key_form.attributes
if result.failure?
@asymmetric_key_form.errors.add :public_key_pem
return render :new
end
redirect_to after_create_url result.asymmetric_key
end
private
def set_asymmetric_key
@asymmetric_key = AsymmetricKey.find params[:id]
end
def asymmetric_key_form_params
params.require(:asymmetric_key).permit(
:public_key_pem,
)
end
def after_create_url(asymmetric_key)
asymmetric_key_url(asymmetric_key)
end
end

View file

@ -1,30 +0,0 @@
# frozen_string_literal: true
class PrivateKeysController < ApplicationController
before_action :set_asymmetric_key
before_action :set_secret
# GET /asymmetric_keys/:asymmetric_key_id/private_key
def show
authorize PrivateKey.new(@asymmetric_key)
@asymmetric_key.decrypt_private_key_pem
respond_to do |format|
format.key do
send_data @asymmetric_key.private_key_pem, filename: 'private.key'
end
end
end
private
def set_asymmetric_key
@asymmetric_key = AsymmetricKey.find params[:asymmetric_key_id]
end
def set_secret
@asymmetric_key.private_key_pem_secret =
Base64.urlsafe_decode64 params[:private_key_pem_secret]
end
end

View file

@ -1,63 +0,0 @@
# frozen_string_literal: true
class Staffs::X509CertificatesController < ApplicationController
before_action :set_x509_certificate, except: %i[index new create]
# GET /staff/x509_certificates
def index
authorize %i[staff x509_certificate]
@x509_certificates = policy_scope(
X509Certificate,
policy_scope_class: Staff::X509CertificatePolicy::Scope,
).page(params[:page])
end
# GET /staff/x509_certificates/:id
def show
authorize [:staff, @x509_certificate]
end
# GET /staff/x509_certificates/new
def new
@x509_certificate_form = X509CertificateForm.new
authorize [:staff, @x509_certificate_form]
end
# POST /staff/x509_certificates
def create
@x509_certificate_form =
X509CertificateForm.new x509_certificate_form_params
authorize [:staff, @x509_certificate_form]
return render :new unless @x509_certificate_form.valid?
result = CreateRSAKeysAndX509SelfSignedCertificate.call \
@x509_certificate_form.attributes.merge(account: current_account)
redirect_to after_create_url result.certificate
end
private
def set_x509_certificate
@x509_certificate = X509Certificate.find params[:id]
end
def x509_certificate_form_params
params.require(:x509_certificate).permit(
:distinguished_name,
:not_before,
:not_after,
)
end
def after_create_url(certificate)
staff_x509_certificate_url(
certificate,
private_key_pem_secret: Base64.urlsafe_encode64(
certificate.asymmetric_key.private_key_pem_secret,
),
)
end
end

View file

@ -1,16 +0,0 @@
# frozen_string_literal: true
class ApplicationForm
include ActiveModel::Model
include ActiveModel::Attributes
include ActiveModel::Validations::Callbacks
include ActiveRecord::AttributeAssignment
def has_attribute?(name)
attributes.key?(name.to_s)
end
def type_for_attribute(name)
self.class.attribute_types[name.to_s]
end
end

View file

@ -1,13 +0,0 @@
# frozen_string_literal: true
class AsymmetricKeyForm < ApplicationForm
attribute :public_key_pem, :string
def self.model_name
ActiveModel::Name.new(self, nil, AsymmetricKey.name)
end
def self.policy_class
'AsymmetricKeyPolicy'
end
end

View file

@ -1,31 +0,0 @@
# frozen_string_literal: true
class X509CertificateForm < ApplicationForm
attribute :distinguished_name, :string
attribute :not_before, :datetime
attribute :not_after, :datetime
validates :distinguished_name, presence: true
validates :not_before, presence: true
validates :not_after, presence: true
validate :can_be_parsed_with_openssl
def self.model_name
ActiveModel::Name.new(self, nil, X509Certificate.name)
end
def self.policy_class
'X509CertificatePolicy'
end
private
def can_be_parsed_with_openssl
OpenSSL::X509::Name.parse distinguished_name if distinguished_name.present?
rescue
errors.add :distinguished_name
end
end

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
module ApplicationHelper # rubocop:disable Metrics/ModuleLength module ApplicationHelper
def federal_subjects_controller? def federal_subjects_controller?
controller_path == 'federal_subjects' controller_path == 'federal_subjects'
end end
@ -13,34 +13,6 @@ module ApplicationHelper # rubocop:disable Metrics/ModuleLength
[*negative_timezones_collection, *positive_timezones_collection].freeze [*negative_timezones_collection, *positive_timezones_collection].freeze
end end
def display_sha1(str)
str = String(str).upcase
raise 'Invalid format for SHA-1' unless str.match?(/\A[A-F0-9]{40}\z/)
tag.small do
concat display_fingerprint str[0...20]
concat tag.br
concat display_fingerprint str[20..-1]
end
end
def display_sha256(str)
str = String(str).upcase
raise 'Invalid format for SHA-256' unless str.match?(/\A[A-F0-9]{64}\z/)
tag.small do
concat display_fingerprint str[0...32]
concat tag.br
concat display_fingerprint str[32..-1]
end
end
def display_fingerprint(str)
tag.samp do
String(str).strip.upcase.each_char.each_slice(2).map(&:join).join(':')
end
end
def positive_timezones_collection def positive_timezones_collection
0.upto(11).flat_map do |n| 0.upto(11).flat_map do |n|
s = n.to_s.rjust(2, '0') s = n.to_s.rjust(2, '0')

View file

@ -1,77 +0,0 @@
# frozen_string_literal: true
class CreateEcurveKeys
include Interactor
DEFAULT_CURVE = 'prime256v1'
before :set_curve
def call
context.asymmetric_key =
EcurveKey.create!(attributes, &:encrypt_private_key_pem)
ClearAsymmetricPrivateKeyJob
.set(wait: AsymmetricKey::PRIVATE_KEY_CLEAR_DELAY)
.perform_later context.asymmetric_key.id
end
private
def set_curve
context.curve ||= DEFAULT_CURVE
context.curve = String(context.curve).freeze
raise 'Invalid curve' unless EcurveKey::CURVES.include? context.curve
end
def pkey
@pkey ||= OpenSSL::PKey::EC.generate context.curve
end
def pkey_public
@pkey_public ||=
OpenSSL::PKey::EC.new(pkey.public_key.group).tap do |pkey_public|
pkey_public.public_key = pkey.public_key
end
end
def attributes
{
account: context.account,
public_key_pem: public_key_pem,
public_key_der: public_key_der,
private_key_pem: private_key_pem,
has_password: context.password.present?,
curve: context.curve,
sha1: sha1,
sha256: sha256,
}
end
def sha1
@sha1 ||= Digest::SHA1.hexdigest(pkey_public.to_der).freeze
end
def sha256
@sha256 ||= Digest::SHA256.hexdigest(pkey_public.to_der).freeze
end
def public_key_pem
@public_key_pem ||= pkey_public.to_pem.freeze
end
def public_key_der
@public_key_der ||= pkey_public.to_der.freeze
end
def private_key_pem
@private_key_pem ||=
if context.password.present?
pkey.to_pem(OpenSSL::Cipher::AES256.new, context.password).freeze
else
pkey.to_pem.freeze
end
end
end

View file

@ -1,70 +0,0 @@
# frozen_string_literal: true
class CreateRSAKeys
include Interactor
DEFAULT_BITS = 4096
before :set_bits
def call
context.asymmetric_key =
RSAKey.create!(attributes, &:encrypt_private_key_pem)
ClearAsymmetricPrivateKeyJob
.set(wait: AsymmetricKey::PRIVATE_KEY_CLEAR_DELAY)
.perform_later context.asymmetric_key.id
end
private
def set_bits
context.bits ||= DEFAULT_BITS
context.bits = Integer(context.bits)
raise 'Invalid key size' unless RSAKey::BITS.include? context.bits
end
def pkey
@pkey ||= OpenSSL::PKey::RSA.new context.bits
end
def attributes
{
account: context.account,
public_key_pem: public_key_pem,
public_key_der: public_key_der,
private_key_pem: private_key_pem,
has_password: context.password.present?,
bits: context.bits,
sha1: sha1,
sha256: sha256,
}
end
def sha1
@sha1 ||= Digest::SHA1.hexdigest(pkey.public_key.to_der).freeze
end
def sha256
@sha256 ||= Digest::SHA256.hexdigest(pkey.public_key.to_der).freeze
end
def public_key_pem
@public_key_pem ||= pkey.public_key.to_pem.freeze
end
def public_key_der
@public_key_der ||= pkey.public_key.to_der.freeze
end
def private_key_pem
@private_key_pem ||=
if context.password.present?
pkey.to_pem(OpenSSL::Cipher::AES256.new, context.password).freeze
else
pkey.to_pem.freeze
end
end
end

View file

@ -1,13 +0,0 @@
# frozen_string_literal: true
class CreateRSAKeysAndX509SelfSignedCertificate
include Interactor::Organizer
organize CreateRSAKeys, CreateX509SelfSignedCertificate
around do |interactor|
ActiveRecord::Base.transaction do
interactor.call
end
end
end

View file

@ -1,117 +0,0 @@
# frozen_string_literal: true
class CreateX509SelfSignedCertificate
include Interactor
before do
context.not_before = Time.at(context.not_before).utc
context.not_after = Time.at(context.not_after).utc
end
def call # rubocop:disable Metrics/AbcSize
context.certificate = X509Certificate.create!(
asymmetric_key: context.asymmetric_key,
pem: cert.to_pem,
subject: cert.subject.to_s,
issuer: cert.issuer.to_s,
not_before: cert.not_before,
not_after: cert.not_after,
)
end
private
def private_key_pkey
@private_key_pkey ||= OpenSSL::PKey::RSA.new(
context.asymmetric_key.private_key_pem,
String(context.password),
)
end
def public_key_pkey
@public_key_pkey ||= OpenSSL::PKey::RSA.new(
context.asymmetric_key.public_key_pem,
String(context.password),
)
end
def subject
@subject ||= OpenSSL::X509::Name.parse context.distinguished_name
end
def cert # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
@cert ||= OpenSSL::X509::Certificate.new.tap do |cert|
cert.version = 2
cert.serial = SecureRandom.rand 0...(2**16)
cert.subject = subject
cert.issuer = cert.subject
cert.public_key = public_key_pkey
cert.not_before = context.not_before
cert.not_after = context.not_after
AddExtensions.call cert
cert.sign private_key_pkey, OpenSSL::Digest::SHA256.new
end
end
class AddExtensions
def self.call(cert)
new(cert).call
end
def initialize(cert)
@cert = cert
end
def call
cert.add_extension basic_constraints
cert.add_extension key_usage
cert.add_extension subject_key_ident
cert.add_extension authority_key_ident
end
private
attr_reader :cert
def ext_factory
@ext_factory ||= OpenSSL::X509::ExtensionFactory.new.tap do |ext_factory|
ext_factory.subject_certificate = cert
ext_factory.issuer_certificate = cert
end
end
def basic_constraints
@basic_constraints ||= ext_factory.create_extension(
'basicConstraints',
'CA:TRUE',
true,
)
end
def key_usage
@key_usage ||= ext_factory.create_extension(
'keyUsage',
'keyCertSign, cRLSign',
true,
)
end
def subject_key_ident
@subject_key_ident ||= ext_factory.create_extension(
'subjectKeyIdentifier',
'hash',
false,
)
end
def authority_key_ident
@authority_key_ident ||= ext_factory.create_extension(
'authorityKeyIdentifier',
'keyid:always,issuer:always',
false,
)
end
end
end

View file

@ -1,98 +0,0 @@
# frozen_string_literal: true
class ImportAsymmetricKey
include Interactor
RSA_BITS_RE = /^RSA Public-Key: \((\d+) bit\)$/.freeze
ECURVE_CURVE_RE = /^ASN1 OID: ((-|\w)+)$/.freeze
before :unset_asymmetric_key
before :sanitize_public_key_der
before :sanitize_public_key_pem
before :set_public_key_openssl_pkey
before :validate_public_key_der
before :validate_public_key_pem
def call
if context.public_key_openssl_pkey.private?
context.fail!
end
find_asymmetric_key
return unless context.asymmetric_key.nil?
case context.public_key_openssl_pkey
when OpenSSL::PKey::RSA then create_rsa_key
when OpenSSL::PKey::EC then create_ecurve_key
else context.fail!
end
end
def find_asymmetric_key
context.asymmetric_key = AsymmetricKey.find_by(
public_key_der: context.public_key_openssl_pkey.to_der,
)
end
def create_rsa_key
context.asymmetric_key = RSAKey.create!(
public_key_pem: context.public_key_openssl_pkey.to_pem,
public_key_der: context.public_key_openssl_pkey.to_der,
sha1: Digest::SHA1.hexdigest(context.public_key_openssl_pkey.to_der),
sha256: Digest::SHA256.hexdigest(context.public_key_openssl_pkey.to_der),
bits: context.public_key_openssl_pkey.to_text.lines
.grep(RSA_BITS_RE).first.match(RSA_BITS_RE)[1].to_i,
)
end
def create_ecurve_key
context.asymmetric_key = EcurveKey.create!(
public_key_pem: context.public_key_openssl_pkey.to_pem,
public_key_der: context.public_key_openssl_pkey.to_der,
sha1: Digest::SHA1.hexdigest(context.public_key_openssl_pkey.to_der),
sha256: Digest::SHA256.hexdigest(context.public_key_openssl_pkey.to_der),
curve: context.public_key_openssl_pkey.to_text.lines
.grep(ECURVE_CURVE_RE).first.match(ECURVE_CURVE_RE)[1],
)
end
private
def unset_asymmetric_key
context.asymmetric_key = nil
end
def sanitize_public_key_der
context.public_key_der = String(context.public_key_der).presence&.dup.freeze
end
def sanitize_public_key_pem
context.public_key_pem = String(context.public_key_pem).lines.map do |line|
"#{line.strip}\n"
end.join.presence.freeze
end
def set_public_key_openssl_pkey
context.public_key_openssl_pkey ||= OpenSSL::PKey.read(
context.public_key_der || context.public_key_pem || '',
'',
)
rescue OpenSSL::PKey::PKeyError
context.fail!
end
def validate_public_key_der
return if context.public_key_der.blank?
return if context.public_key_der == context.public_key_openssl_pkey.to_der
raise 'Invalid DER'
end
def validate_public_key_pem
return if context.public_key_pem.blank?
return if context.public_key_pem == context.public_key_openssl_pkey.to_pem
raise 'Invalid PEM'
end
end

View file

@ -1,11 +0,0 @@
# frozen_string_literal: true
class ClearAsymmetricPrivateKeyJob < ApplicationJob
queue_as :default
def perform(asymmetric_key_id)
AsymmetricKey
.find(asymmetric_key_id)
.update! private_key_pem_iv: nil, private_key_pem_ciphertext: nil
end
end

View file

@ -1,84 +0,0 @@
# frozen_string_literal: true
class AsymmetricKey < ApplicationRecord
PRIVATE_KEY_CLEAR_DELAY = 1.hour.freeze
attr_accessor :private_key_pem, :private_key_pem_secret
################
# Associations #
################
belongs_to :account, optional: true
###############
# Validations #
###############
validates :public_key_pem,
presence: true,
uniqueness: true
validates :public_key_der,
presence: true,
uniqueness: true
validates :bits,
allow_nil: true,
numericality: {
only_integer: true,
greater_than: 0,
}
validates :sha1,
presence: true,
uniqueness: { case_sensitive: false }
validates :sha256,
presence: true,
uniqueness: { case_sensitive: false }
###########
# Methods #
###########
def self.policy_class
AsymmetricKeyPolicy
end
def algo_class
raise NotImplementedError, "#{self.class}#algo_class"
end
def algo_variant
raise NotImplementedError, "#{self.class}#algo_variant"
end
def encrypt_private_key_pem
cipher = OpenSSL::Cipher::AES256.new
cipher.encrypt
self.private_key_pem_iv = cipher.random_iv.freeze
self.private_key_pem_secret = cipher.random_key.freeze
self.private_key_pem_ciphertext = [
cipher.update(private_key_pem),
cipher.final,
].join.freeze
private_key_pem_secret
end
def decrypt_private_key_pem
cipher = OpenSSL::Cipher::AES256.new
cipher.decrypt
cipher.iv = private_key_pem_iv
cipher.key = private_key_pem_secret
self.private_key_pem = [
cipher.update(private_key_pem_ciphertext),
cipher.final,
].join.freeze
end
end

View file

@ -1,26 +0,0 @@
# frozen_string_literal: true
class EcurveKey < AsymmetricKey
ALGO_CLASS = 'Elliptic curve'
CURVES = %w[prime256v1 secp384r1].freeze
###############
# Validations #
###############
validates :curve, inclusion: { in: CURVES }
validates :bits, absence: true
###########
# Methods #
###########
def algo_class
ALGO_CLASS
end
def algo_variant
curve
end
end

View file

@ -1,26 +0,0 @@
# frozen_string_literal: true
class RSAKey < AsymmetricKey
ALGO_CLASS = 'RSA'
BITS = [2048, 4096].freeze
###############
# Validations #
###############
validates :bits, inclusion: { in: BITS }
validates :curve, absence: true
###########
# Methods #
###########
def algo_class
ALGO_CLASS
end
def algo_variant
"#{bits} bits"
end
end

View file

@ -1,33 +0,0 @@
# frozen_string_literal: true
class X509Certificate < ApplicationRecord
################
# Associations #
################
belongs_to :asymmetric_key
###############
# Validations #
###############
validates :pem, presence: true
validates :subject, presence: true
validates :issuer, presence: true
validates :not_before, presence: true
validates :not_after, presence: true
validate :can_be_parsed_and_exported_with_openssl
private
def can_be_parsed_and_exported_with_openssl
OpenSSL::X509::Certificate.new(pem)&.to_text if pem.present?
rescue
errors.add :pem
end
end

View file

@ -1,12 +1,10 @@
# frozen_string_literal: true # frozen_string_literal: true
class ApplicationPolicy class ApplicationPolicy
attr_reader :context, :record attr_reader :account, :record
delegate :account, :params, to: :context, allow_nil: true def initialize(account, record)
@account = account
def initialize(context, record)
@context = context
@record = record @record = record
end end
@ -53,12 +51,10 @@ private
end end
class Scope class Scope
attr_reader :context, :scope attr_reader :account, :scope
delegate :account, :params, to: :context, allow_nil: true def initialize(account, scope)
@account = account
def initialize(context, scope)
@context = context
@scope = scope @scope = scope
end end
@ -76,13 +72,4 @@ private
Rails.application.restricted? Rails.application.restricted?
end end
end end
class Context
attr_reader :account, :params
def initialize(account:, params:)
@account = account
@params = params
end
end
end end

View file

@ -1,21 +0,0 @@
# frozen_string_literal: true
class AsymmetricKeyPolicy < ApplicationPolicy
def index?
true
end
def show?
true
end
def create?
true
end
class Scope < Scope
def resolve
scope.all
end
end
end

View file

@ -1,14 +0,0 @@
# frozen_string_literal: true
class PrivateKeyPolicy < ApplicationPolicy
def show?
show_alert? && record.exist?
end
def show_alert?
return false if account.nil?
params[:private_key_pem_secret].present? &&
(account.superuser? || account == record.account)
end
end

View file

@ -1,31 +0,0 @@
# frozen_string_literal: true
class Staff::X509CertificatePolicy < ApplicationPolicy
def index?
return false if restricted?
account&.superuser?
end
def show?
return false if restricted?
account&.superuser?
end
def create?
return false if restricted?
account&.superuser?
end
class Scope < Scope
def resolve
return scope.none if restricted?
return scope.all if account&.superuser?
scope.none
end
end
end

View file

@ -1,20 +0,0 @@
# frozen_string_literal: true
class PrivateKey
attr_reader :asymmetric_key
delegate :account, to: :asymmetric_key
def self.policy_class
'PrivateKeyPolicy'
end
def initialize(asymmetric_key)
@asymmetric_key = asymmetric_key or raise
end
def exist?
asymmetric_key.private_key_pem_iv.present? &&
asymmetric_key.private_key_pem_ciphertext.present?
end
end

View file

@ -1,31 +0,0 @@
<table class="table">
<thead>
<tr>
<th scope="col">
<%= AsymmetricKey.human_attribute_name :id %>
</th>
<th scope="col">
<%= AsymmetricKey.human_attribute_name :algo_class %>
</th>
<th scope="col">
<%= AsymmetricKey.human_attribute_name :algo_variant %>
</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<% asymmetric_keys.each do |asymmetric_key| %>
<tr>
<td scope="row"><%= asymmetric_key.id %></td>
<td><%= asymmetric_key.algo_class %></td>
<td><%= asymmetric_key.algo_variant %></td>
<td>
<% if policy(asymmetric_key).show? %>
<%= open_action asymmetric_key_path(asymmetric_key) %>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>

View file

@ -1,20 +0,0 @@
<div class="container">
<%= nav_breadcrumb AsymmetricKey.model_name.human count: 0 %>
<% if policy(AsymmetricKey).new? %>
<div class="btn-group" role="group">
<% if policy(AsymmetricKey).new? %>
<%= link_to translate(:add_existing),
new_asymmetric_key_path,
class: 'btn btn-primary',
role: :button %>
<% end %>
</div>
<% end %>
<div class="mt-3">
<%= render partial: 'table',
locals: { asymmetric_keys: @asymmetric_keys } %>
<%= pagination @asymmetric_keys %>
</div>
</div>

View file

@ -1,14 +0,0 @@
<div class="container">
<%= nav_breadcrumb(
[AsymmetricKey.model_name.human(count: 0), asymmetric_keys_path],
translate(:add_existing),
) %>
<%= simple_form_for @asymmetric_key_form do |f| %>
<%= f.error_notification %>
<%= f.input :public_key_pem, as: :text %>
<%= f.button :submit %>
<% end %>
</div>

View file

@ -1,35 +0,0 @@
<div class="container">
<%= nav_breadcrumb(
[AsymmetricKey.model_name.human(count: 0), asymmetric_keys_path],
AsymmetricKey.model_name.human(count: 1),
) %>
<div class="row">
<div class="col-md-6">
<dl>
<dt><%= AsymmetricKey.human_attribute_name :id %></dt>
<dd><%= @asymmetric_key.id %></dd>
<dt><%= AsymmetricKey.human_attribute_name :algo_class %></dt>
<dd><%= @asymmetric_key.algo_class %></dd>
<dt><%= AsymmetricKey.human_attribute_name :algo_variant %></dt>
<dd><%= @asymmetric_key.algo_variant %></dd>
<dt><%= AsymmetricKey.human_attribute_name :sha1 %></dt>
<dd><%= display_sha1 @asymmetric_key.sha1 %></dd>
<dt><%= AsymmetricKey.human_attribute_name :sha256 %></dt>
<dd><%= display_sha256 @asymmetric_key.sha256 %></dd>
</dl>
</div>
<div class="col-md-6">
<%= render partial: 'private_keys/alert',
locals: {
asymmetric_key: @asymmetric_key,
}
%>
</div>
</div>
</div>

View file

@ -1,40 +0,0 @@
<% if policy(PrivateKey.new(asymmetric_key)).show_alert? %>
<% if policy(PrivateKey.new(asymmetric_key)).show? %>
<div class="alert alert-primary" role="alert">
<h4 class="alert-heading">
<%= translate '.primary_header' %>
</h4>
<hr/>
<p>
<%= translate(
'.primary_text',
delay: distance_of_time_in_words(
AsymmetricKey::PRIVATE_KEY_CLEAR_DELAY,
),
) %>
</p>
<%= link_to(
translate('.link'),
asymmetric_key_private_key_path(
asymmetric_key,
format: :key,
private_key_pem_secret: params[:private_key_pem_secret],
),
class: 'btn btn-primary',
) %>
</div>
<% else %>
<div class="alert alert-secondary" role="alert">
<h4 class="alert-heading">
<%= translate '.secondary_header' %>
</h4>
<p>
<%= translate '.secondary_text' %>
</p>
</div>
<% end %>
<% end %>

View file

@ -26,12 +26,5 @@
staff_contact_networks_path %> staff_contact_networks_path %>
</li> </li>
<% end %> <% end %>
<% if policy(%i[staff x509_certificate]).index? %>
<li>
<%= link_to X509Certificate.model_name.human(count: 0),
staff_x509_certificates_path %>
</li>
<% end %>
</ul> </ul>
</div> </div>

View file

@ -1,31 +0,0 @@
<table class="table">
<thead>
<tr>
<th scope="col">
<%= X509Certificate.human_attribute_name :id %>
</th>
<th scope="col">
<%= X509Certificate.human_attribute_name :not_before %>
</th>
<th scope="col">
<%= X509Certificate.human_attribute_name :not_after %>
</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<% x509_certificates.each do |x509_certificate| %>
<tr>
<td scope="row"><%= x509_certificate.id %></td>
<td><%= localize x509_certificate.not_before, format: :long %></td>
<td><%= localize x509_certificate.not_after, format: :long %></td>
<td>
<% if policy([:staff, x509_certificate]).show? %>
<%= open_action [:staff, x509_certificate] %>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>

View file

@ -1,23 +0,0 @@
<div class="container">
<%= nav_breadcrumb(
[translate(:staff_services), staff_root_path],
X509Certificate.model_name.human(count: 0),
) %>
<% if policy([:staff, X509Certificate]).new? %>
<div class="btn-group" role="group">
<% if policy([:staff, X509Certificate]).new? %>
<%= link_to translate(:create),
new_staff_x509_certificate_path,
class: 'btn btn-primary',
role: :button %>
<% end %>
</div>
<% end %>
<div class="mt-3">
<%= render partial: 'table',
locals: { x509_certificates: @x509_certificates } %>
<%= pagination @x509_certificates %>
</div>
</div>

View file

@ -1,17 +0,0 @@
<div class="container">
<%= nav_breadcrumb(
[translate(:staff_services), staff_root_path],
[X509Certificate.model_name.human(count: 0), staff_x509_certificates_path],
translate(:create),
) %>
<%= simple_form_for [:staff, @x509_certificate_form] do |f| %>
<%= f.error_notification %>
<%= f.input :distinguished_name %>
<%= f.input :not_before %>
<%= f.input :not_after %>
<%= f.button :submit %>
<% end %>
</div>

View file

@ -1,86 +0,0 @@
<div class="container">
<%= nav_breadcrumb(
[translate(:staff_services), staff_root_path],
[X509Certificate.model_name.human(count: 0), staff_x509_certificates_path],
X509Certificate.model_name.human(count: 1),
) %>
<div id="myTab" class="mb-3">
<ul class="nav nav-tabs" role="tablist">
<li class="nav-item">
<%= link_to translate('nav_tabs.x509_certificate.overview'),
'#overview',
id: 'overview-tab',
class: 'nav-link active',
role: :tab,
'data-toggle': :tab,
'aria-controls': :overview,
'aria-selected': true %>
</li>
<li class="nav-item">
<%= link_to translate('nav_tabs.x509_certificate.pem'),
'#pem',
id: 'pem-tab',
class: 'nav-link',
role: :tab,
'data-toggle': :tab,
'aria-controls': :pem,
'aria-selected': true %>
</li>
<li class="nav-item">
<%= link_to translate('nav_tabs.x509_certificate.text'),
'#text',
id: 'text-tab',
class: 'nav-link',
role: :tab,
'data-toggle': :tab,
'aria-controls': :text,
'aria-selected': true %>
</li>
</ul>
</div>
<div id="myTabContent" class="tab-content">
<div id="overview" class="tab-pane show active" role="tabpanel" aria-labelledby="overview-tab">
<div class="row">
<div class="col-md-6">
<dl>
<dt><%= X509Certificate.human_attribute_name :id %></dt>
<dd><%= @x509_certificate.id %></dd>
<dt><%= X509Certificate.human_attribute_name :subject %></dt>
<dd><%= truncate @x509_certificate.subject %></dd>
<dt><%= X509Certificate.human_attribute_name :issuer %></dt>
<dd><%= truncate @x509_certificate.issuer %></dd>
<dt><%= X509Certificate.human_attribute_name :not_before %></dt>
<dd><%= localize @x509_certificate.not_before, format: :long %></dd>
<dt><%= X509Certificate.human_attribute_name :not_after %></dt>
<dd><%= localize @x509_certificate.not_after, format: :long %></dd>
</dl>
</div>
<div class="col-md-6">
<%= render partial: 'private_keys/alert',
locals: {
asymmetric_key: @x509_certificate.asymmetric_key,
}
%>
</div>
</div>
</div>
<div id="pem" class="tab-pane" role="tabpanel" aria-labelledby"pem-tab">
<pre><code><%= @x509_certificate.pem %></code></pre>
</div>
<div id="text" class="tab-pane" role="tabpanel" aria-labelledby="text-tab">
<pre><code><%= OpenSSL::X509::Certificate.new(@x509_certificate.pem).to_text %></code></pre>
</div>
</div>
</div>

View file

@ -26,7 +26,6 @@ module Partynest
confirmation_token confirmation_token
password password
password_confirmation password_confirmation
private_key_pem_secret
reset_password_token reset_password_token
secret secret
unlock_token unlock_token
@ -61,7 +60,6 @@ module Partynest
# Custom directories with classes and modules you want to be autoloadable. # Custom directories with classes and modules you want to be autoloadable.
config.autoload_paths += [ config.autoload_paths += [
config.root.join('app', 'forms'),
config.root.join('app', 'primitives'), config.root.join('app', 'primitives'),
config.root.join('app', 'validators'), config.root.join('app', 'validators'),
config.root.join('lib'), config.root.join('lib'),

View file

@ -12,6 +12,7 @@
# inflect.uncountable %w( fish sheep ) # inflect.uncountable %w( fish sheep )
# end # end
ActiveSupport::Inflector.inflections :en do |inflect| # These inflection rules are supported but not enabled by default:
inflect.acronym 'RSA' # ActiveSupport::Inflector.inflections(:en) do |inflect|
end # inflect.acronym 'RESTful'
# end

View file

@ -2,5 +2,5 @@
# Be sure to restart your server when you modify this file. # Be sure to restart your server when you modify this file.
Mime::Type.register 'application/pkcs8', :key # Add new mime types for use in respond_to blocks:
Mime::Type.register 'application/x-pem-file', :pem # Mime::Type.register "text/richtext", :rtf

View file

@ -1,9 +0,0 @@
en:
activemodel:
attributes:
asymmetric_key:
public_key_pem: Public key in PEM format
x509_certificate:
distinguished_name: Distinguished name
not_before: Active since
not_after: Expires at

View file

@ -1,9 +0,0 @@
ru:
activemodel:
attributes:
asymmetric_key:
public_key_pem: Публичный ключ в формате PEM
x509_certificate:
distinguished_name: Уникальное имя (distinguished name)
not_before: Активен с
not_after: Истекает

View file

@ -4,10 +4,6 @@ en:
account: account:
one: Account one: Account
many: Accounts many: Accounts
asymmetric_key:
one: Public key
few: Public keys
many: Public keys
contact: contact:
one: Contact one: Contact
few: Contacts few: Contacts
@ -40,10 +36,6 @@ en:
user: user:
one: User one: User
many: Users many: Users
x509_certificate:
one: X509 certificate
few: X509 certificates
many: X509 certificates
attributes: attributes:
account: account:
id: ID id: ID
@ -53,12 +45,6 @@ en:
avatar: Avatar avatar: Avatar
person: Person person: Person
timezone: Timezone timezone: Timezone
asymmetric_key:
id: ID
algo_class: Algorithm class
algo_variant: Variant
sha1: SHA-1 fingerprint
sha256: SHA-256 fingerprint
contact: contact:
id: ID id: ID
contact_network: Contact network contact_network: Contact network
@ -145,13 +131,6 @@ en:
unconfirmed_email: Unconfirmed email unconfirmed_email: Unconfirmed email
unlock_token: Unlock token unlock_token: Unlock token
updated_at: Updated at updated_at: Updated at
x509_certificate:
id: ID
pem: PEM
subject: Subject
issuer: Issuer
not_before: Active since
not_after: Expires at
errors: errors:
messages: messages:
image_size: 'has too big size' image_size: 'has too big size'

View file

@ -4,10 +4,6 @@ ru:
account: account:
one: Аккаунт one: Аккаунт
many: Аккаунты many: Аккаунты
asymmetric_key:
one: Публичный ключ
few: Публичных ключа
many: Публичные ключи
contact: contact:
one: Контакт one: Контакт
few: Контакта few: Контакта
@ -40,10 +36,6 @@ ru:
user: user:
one: Пользователь one: Пользователь
many: Пользователи many: Пользователи
x509_certificate:
one: Сертификат X509
few: Сертификатов X509
many: Сертификаты X509
attributes: attributes:
account: account:
id: ID id: ID
@ -53,12 +45,6 @@ ru:
avatar: Аватар avatar: Аватар
person: Человек person: Человек
timezone: Часовой пояс timezone: Часовой пояс
asymmetric_key:
id: ID
algo_class: Класс алгоритма
algo_variant: Вариант
sha1: Отпечаток SHA-1
sha256: Отпечаток SHA-256
contact: contact:
id: ID id: ID
contact_network: Сеть контактов contact_network: Сеть контактов
@ -145,13 +131,6 @@ ru:
unconfirmed_email: Неподтвержденный email unconfirmed_email: Неподтвержденный email
unlock_token: Токен разблокировки unlock_token: Токен разблокировки
updated_at: Дата обновления updated_at: Дата обновления
x509_certificate:
id: ID
pem: PEM
subject: Имя субъекта
issuer: Имя издателя
not_before: Активен с
not_after: Истекает
errors: errors:
messages: messages:
image_size: 'имеет слишком большой размер' image_size: 'имеет слишком большой размер'

View file

@ -11,8 +11,6 @@ en:
display_entries: 'Displaying %{entry_name} display_entries: 'Displaying %{entry_name}
<b>%{first}&nbsp;-&nbsp;%{last}</b> of <b>%{total}</b> in total' <b>%{first}&nbsp;-&nbsp;%{last}</b> of <b>%{total}</b> in total'
submit: submit:
asymmetric_key:
create: Add
person: person:
create: Send create: Send
person_comment: person_comment:

View file

@ -11,8 +11,6 @@ ru:
display_entries: 'Отображение %{entry_name} display_entries: 'Отображение %{entry_name}
<b>%{first}&nbsp;-&nbsp;%{last}</b> из <b>%{total}</b> всего' <b>%{first}&nbsp;-&nbsp;%{last}</b> из <b>%{total}</b> всего'
submit: submit:
asymmetric_key:
create: Добавить
person: person:
create: Отправить create: Отправить
person_comment: person_comment:

View file

@ -16,23 +16,6 @@ en:
If this was you, you can ignore this alert. If you suspect If this was you, you can ignore this alert. If you suspect
any suspicious activity on your account, please change your password any suspicious activity on your account, please change your password
and enable two-factor authentication and enable two-factor authentication
private_keys:
alert:
link: Download
primary_header: >-
Your private key is ready, but you have to download it right now!
secondary_header: >-
Your private key was deleted.
primary_text: >-
For better security we have encrypted your private key
with temporary secret token. You can download it until
you leave this page. Also note that key will be deleted
in %{delay} after creation anyway.
secondary_text: >-
For better security we have deleted your private key.
Hope you have downloaded it, because we can not restore it.
If you haven't downloaded it, you have to repeat the whole
procedure to generate new private key.
staffs: staffs:
people: people:
show: show:

View file

@ -17,23 +17,6 @@ ru:
Если это были вы, можете проигнорировать это предупреждение. Если это были вы, можете проигнорировать это предупреждение.
Если вы заметили подозрительную активность вашего аккаунта, пожалуйста Если вы заметили подозрительную активность вашего аккаунта, пожалуйста
измените пароль и включите двухфакторную аутентификацию измените пароль и включите двухфакторную аутентификацию
private_keys:
alert:
link: Скачать
primary_header: >-
Ваш приватный ключ готов, но вы должны скачать его прямо сейчас!
secondary_header: >-
Ваш приватный ключ был удалён.
primary_text: >-
Для большей безопасности мы зашифровали ваш приватный ключ
с помощью временного токена. Вы можете скачать его пока не покините
эту страницу. Также учтите, что ключ будет уничтожен через %{delay}
после создания в любом случае.
secondary_text: >-
Для большей безопасности мы удалили ваш приватный ключ.
Надеемся, что вы его скачали, потому что мы не можем его восстановить.
Если вы не скачали его, вам придётся повторить всю процедуру сначала
чтобы сгенерировать новый приватный ключ.
settings: settings:
people: people:
show: show:

View file

@ -12,7 +12,3 @@ en:
person: Person person: Person
contacts: Contacts contacts: Contacts
sessions: Sessions sessions: Sessions
x509_certificate:
overview: Overview
pem: PEM
text: Text

View file

@ -12,7 +12,3 @@ ru:
person: Личность person: Личность
contacts: Контакты contacts: Контакты
sessions: Сессии sessions: Сессии
x509_certificate:
overview: Обзор
pem: PEM
text: Текст

View file

@ -12,4 +12,3 @@ en:
save: Save save: Save
hello: Hello hello: Hello
new_sign_in: New sign in to your account new_sign_in: New sign in to your account
add_existing: Add existing

View file

@ -12,4 +12,3 @@ ru:
save: Сохранить save: Сохранить
hello: Здравствуйте hello: Здравствуйте
new_sign_in: Произведён вход в ваш аккаунт new_sign_in: Произведён вход в ваш аккаунт
add_existing: Добавить существующий

View file

@ -13,10 +13,6 @@ Rails.application.routes.draw do
resources :federal_subjects, param: :number, only: %i[index show] resources :federal_subjects, param: :number, only: %i[index show]
resources :asymmetric_keys, only: %i[index show new create] do
resource :private_key, only: :show
end
############### ###############
# User routes # # User routes #
############### ###############
@ -65,8 +61,6 @@ Rails.application.routes.draw do
resources :accounts, param: :nickname, only: %i[index show] resources :accounts, param: :nickname, only: %i[index show]
resources :x509_certificates, only: %i[index show new create]
resources :people, only: %i[index show new create] do resources :people, only: %i[index show new create] do
resources :person_comments, resources :person_comments,
path: 'comments', path: 'comments',

View file

@ -0,0 +1,8 @@
# frozen_string_literal: true
class DropX509Tables < ActiveRecord::Migration[6.0]
def change
drop_table :x509_certificates
drop_table :asymmetric_keys
end
end

View file

@ -364,49 +364,6 @@ CREATE TABLE public.ar_internal_metadata (
); );
--
-- Name: asymmetric_keys; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.asymmetric_keys (
id bigint NOT NULL,
created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL,
type character varying NOT NULL,
account_id bigint,
public_key_pem text NOT NULL,
public_key_der bytea NOT NULL,
private_key_pem_iv bytea,
private_key_pem_ciphertext bytea,
has_password boolean,
sha1 character varying NOT NULL,
sha256 character varying NOT NULL,
bits integer,
curve character varying,
CONSTRAINT bits CHECK (((bits IS NULL) OR (bits = ANY (ARRAY[2048, 4096])))),
CONSTRAINT curve CHECK (((curve IS NULL) OR ((curve)::text = ANY ((ARRAY['prime256v1'::character varying, 'secp384r1'::character varying])::text[]))))
);
--
-- Name: asymmetric_keys_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.asymmetric_keys_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: asymmetric_keys_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.asymmetric_keys_id_seq OWNED BY public.asymmetric_keys.id;
-- --
-- Name: contact_lists; Type: TABLE; Schema: public; Owner: - -- Name: contact_lists; Type: TABLE; Schema: public; Owner: -
-- --
@ -924,42 +881,6 @@ CREATE SEQUENCE public.users_id_seq
ALTER SEQUENCE public.users_id_seq OWNED BY public.users.id; ALTER SEQUENCE public.users_id_seq OWNED BY public.users.id;
--
-- Name: x509_certificates; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.x509_certificates (
id bigint NOT NULL,
created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL,
asymmetric_key_id bigint NOT NULL,
pem text NOT NULL,
subject character varying NOT NULL,
issuer character varying NOT NULL,
not_before timestamp without time zone NOT NULL,
not_after timestamp without time zone NOT NULL
);
--
-- Name: x509_certificates_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.x509_certificates_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: x509_certificates_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.x509_certificates_id_seq OWNED BY public.x509_certificates.id;
-- --
-- Name: accounts id; Type: DEFAULT; Schema: public; Owner: - -- Name: accounts id; Type: DEFAULT; Schema: public; Owner: -
-- --
@ -981,13 +902,6 @@ ALTER TABLE ONLY public.active_storage_attachments ALTER COLUMN id SET DEFAULT n
ALTER TABLE ONLY public.active_storage_blobs ALTER COLUMN id SET DEFAULT nextval('public.active_storage_blobs_id_seq'::regclass); ALTER TABLE ONLY public.active_storage_blobs ALTER COLUMN id SET DEFAULT nextval('public.active_storage_blobs_id_seq'::regclass);
--
-- Name: asymmetric_keys id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.asymmetric_keys ALTER COLUMN id SET DEFAULT nextval('public.asymmetric_keys_id_seq'::regclass);
-- --
-- Name: contact_lists id; Type: DEFAULT; Schema: public; Owner: - -- Name: contact_lists id; Type: DEFAULT; Schema: public; Owner: -
-- --
@ -1079,13 +993,6 @@ ALTER TABLE ONLY public.user_omniauths ALTER COLUMN id SET DEFAULT nextval('publ
ALTER TABLE ONLY public.users ALTER COLUMN id SET DEFAULT nextval('public.users_id_seq'::regclass); ALTER TABLE ONLY public.users ALTER COLUMN id SET DEFAULT nextval('public.users_id_seq'::regclass);
--
-- Name: x509_certificates id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.x509_certificates ALTER COLUMN id SET DEFAULT nextval('public.x509_certificates_id_seq'::regclass);
-- --
-- Name: accounts accounts_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- Name: accounts accounts_pkey; Type: CONSTRAINT; Schema: public; Owner: -
-- --
@ -1118,14 +1025,6 @@ ALTER TABLE ONLY public.ar_internal_metadata
ADD CONSTRAINT ar_internal_metadata_pkey PRIMARY KEY (key); ADD CONSTRAINT ar_internal_metadata_pkey PRIMARY KEY (key);
--
-- Name: asymmetric_keys asymmetric_keys_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.asymmetric_keys
ADD CONSTRAINT asymmetric_keys_pkey PRIMARY KEY (id);
-- --
-- Name: contact_lists contact_lists_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- Name: contact_lists contact_lists_pkey; Type: CONSTRAINT; Schema: public; Owner: -
-- --
@ -1238,14 +1137,6 @@ ALTER TABLE ONLY public.users
ADD CONSTRAINT users_pkey PRIMARY KEY (id); ADD CONSTRAINT users_pkey PRIMARY KEY (id);
--
-- Name: x509_certificates x509_certificates_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.x509_certificates
ADD CONSTRAINT x509_certificates_pkey PRIMARY KEY (id);
-- --
-- Name: index_accounts_on_contact_list_id; Type: INDEX; Schema: public; Owner: - -- Name: index_accounts_on_contact_list_id; Type: INDEX; Schema: public; Owner: -
-- --
@ -1288,48 +1179,6 @@ CREATE UNIQUE INDEX index_active_storage_attachments_uniqueness ON public.active
CREATE UNIQUE INDEX index_active_storage_blobs_on_key ON public.active_storage_blobs USING btree (key); CREATE UNIQUE INDEX index_active_storage_blobs_on_key ON public.active_storage_blobs USING btree (key);
--
-- Name: index_asymmetric_keys_on_account_id; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_asymmetric_keys_on_account_id ON public.asymmetric_keys USING btree (account_id);
--
-- Name: index_asymmetric_keys_on_public_key_der; Type: INDEX; Schema: public; Owner: -
--
CREATE UNIQUE INDEX index_asymmetric_keys_on_public_key_der ON public.asymmetric_keys USING btree (public_key_der);
--
-- Name: index_asymmetric_keys_on_public_key_pem; Type: INDEX; Schema: public; Owner: -
--
CREATE UNIQUE INDEX index_asymmetric_keys_on_public_key_pem ON public.asymmetric_keys USING btree (public_key_pem);
--
-- Name: index_asymmetric_keys_on_sha1; Type: INDEX; Schema: public; Owner: -
--
CREATE UNIQUE INDEX index_asymmetric_keys_on_sha1 ON public.asymmetric_keys USING btree (sha1);
--
-- Name: index_asymmetric_keys_on_sha256; Type: INDEX; Schema: public; Owner: -
--
CREATE UNIQUE INDEX index_asymmetric_keys_on_sha256 ON public.asymmetric_keys USING btree (sha256);
--
-- Name: index_asymmetric_keys_on_type_and_id; Type: INDEX; Schema: public; Owner: -
--
CREATE UNIQUE INDEX index_asymmetric_keys_on_type_and_id ON public.asymmetric_keys USING btree (type, id);
-- --
-- Name: index_contact_networks_on_codename; Type: INDEX; Schema: public; Owner: - -- Name: index_contact_networks_on_codename; Type: INDEX; Schema: public; Owner: -
-- --
@ -1575,13 +1424,6 @@ CREATE UNIQUE INDEX index_users_on_reset_password_token ON public.users USING bt
CREATE UNIQUE INDEX index_users_on_unlock_token ON public.users USING btree (unlock_token); CREATE UNIQUE INDEX index_users_on_unlock_token ON public.users USING btree (unlock_token);
--
-- Name: index_x509_certificates_on_asymmetric_key_id; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_x509_certificates_on_asymmetric_key_id ON public.x509_certificates USING btree (asymmetric_key_id);
-- --
-- Name: accounts ensure_contact_list_id_matches_related_person; Type: TRIGGER; Schema: public; Owner: - -- Name: accounts ensure_contact_list_id_matches_related_person; Type: TRIGGER; Schema: public; Owner: -
-- --
@ -1619,14 +1461,6 @@ ALTER TABLE ONLY public.relationships
ADD CONSTRAINT fk_rails_124c042ac0 FOREIGN KEY (initiator_account_id) REFERENCES public.accounts(id); ADD CONSTRAINT fk_rails_124c042ac0 FOREIGN KEY (initiator_account_id) REFERENCES public.accounts(id);
--
-- Name: x509_certificates fk_rails_1671512c40; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.x509_certificates
ADD CONSTRAINT fk_rails_1671512c40 FOREIGN KEY (asymmetric_key_id) REFERENCES public.asymmetric_keys(id);
-- --
-- Name: people fk_rails_4f02f930eb; Type: FK CONSTRAINT; Schema: public; Owner: - -- Name: people fk_rails_4f02f930eb; Type: FK CONSTRAINT; Schema: public; Owner: -
-- --
@ -1683,14 +1517,6 @@ ALTER TABLE ONLY public.regional_offices
ADD CONSTRAINT fk_rails_7a6d5fdd9a FOREIGN KEY (federal_subject_id) REFERENCES public.federal_subjects(id); ADD CONSTRAINT fk_rails_7a6d5fdd9a FOREIGN KEY (federal_subject_id) REFERENCES public.federal_subjects(id);
--
-- Name: asymmetric_keys fk_rails_7d85781ea1; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.asymmetric_keys
ADD CONSTRAINT fk_rails_7d85781ea1 FOREIGN KEY (account_id) REFERENCES public.accounts(id);
-- --
-- Name: user_omniauths fk_rails_8c1c9cb22e; Type: FK CONSTRAINT; Schema: public; Owner: - -- Name: user_omniauths fk_rails_8c1c9cb22e; Type: FK CONSTRAINT; Schema: public; Owner: -
-- --
@ -1759,6 +1585,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20190910040709'), ('20190910040709'),
('20190911081459'), ('20190911081459'),
('20190914050858'), ('20190914050858'),
('20190915085803'); ('20190915085803'),
('20190915131325');

View file

@ -1,27 +0,0 @@
# frozen_string_literal: true
FactoryBot.define do
factory :ecurve_key do
association :account, factory: :usual_account
public_key_pem do
point = OpenSSL::PKey::EC.generate(curve).public_key
pkey = OpenSSL::PKey::EC.new point.group
pkey.public_key = point
pkey.to_pem
end
public_key_der do
point = OpenSSL::PKey::EC.generate(curve).public_key
pkey = OpenSSL::PKey::EC.new point.group
pkey.public_key = point
pkey.to_der
end
has_password { [false, true].sample }
sha1 { Digest::SHA1.hexdigest SecureRandom.hex }
sha256 { Digest::SHA256.hexdigest SecureRandom.hex }
curve { EcurveKey::CURVES.sample }
end
end

View file

@ -1,16 +0,0 @@
# frozen_string_literal: true
FactoryBot.define do
factory :rsa_key do
association :account, factory: :usual_account
public_key_pem { OpenSSL::PKey::RSA.new(bits).public_key.to_pem }
public_key_der { OpenSSL::PKey::RSA.new(bits).public_key.to_der }
has_password { [false, true].sample }
sha1 { Digest::SHA1.hexdigest SecureRandom.hex }
sha256 { Digest::SHA256.hexdigest SecureRandom.hex }
bits { RSAKey::BITS.sample }
end
end

View file

@ -1,13 +0,0 @@
# frozen_string_literal: true
FactoryBot.define do
factory :self_signed_x509_certificate, class: X509Certificate do
association :asymmetric_key, factory: :rsa_key
pem { File.read Rails.root.join 'fixtures', 'ca.crt' }
subject { '/CN=example.com' }
issuer { subject }
not_before { Faker::Time.backward.utc }
not_after { Faker::Time.forward.utc }
end
end

View file

@ -1,30 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFLzCCAxegAwIBAgIDAOcoMA0GCSqGSIb3DQEBCwUAMBYxFDASBgNVBAMMC2V4
YW1wbGUuY29tMB4XDTE5MDkxMTEwMDcxMloXDTIwMDkxMDEwMDcxMlowFjEUMBIG
A1UEAwwLZXhhbXBsZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
AQDSzS7+xkHL2KsB7P6jzbLPpAAqV7PCbuxqQsxWDHnadmJ4VCRNP8VuecT2hN1Q
tJRHb3FpooB+nFvjLt7b1rUoAoaBUF389UBsmCNPiAttGNGnRib0m4wVhxWhHLZ+
rTuXrKjZjWci06aFj+rybQJjMYrcSx9/2MhaZpL7o7bsQ9gxV7ohmbEtNCLSGxAP
vfhNrhgx8aZi1ZHusior51pt35bhLst+ixvfG/fW8SrJ4rd6nAYlI52RXtkxOanX
wJYKDzsJC5lVptjP/s/PuZuYhTDiYlI69w0qK7dMu2HygzmMdCVmzsFVOyCPCZa6
SbCSkntS0oSLugY7XSIRp6tD1Lz/FoaQcF8GswDkt4qE5lPOfT6y2xREv6rpTcrZ
kC1g/ztfcphkCAdSBHhM1WfZdx2RjpMnyjOGAVTiORX0qgXJ+WKIlzAf0JAmPAB+
FM53hPqf+Py4v0jTYAjs+kR8lIoiPUaPIxIWbHFSHmPzQvtmh8V43N3GAXEMCGRw
seKoUvInUaq/EEtSoG6qBkXO7FSTwLGF6++VNa57ZGtqgDebf3OTvNQSrhGQRi1x
qp9yk+6ob8m2WLHjN6FNnA8R4J+X0RJNiyztTcQxa1BEeDS1fhk3zmsJyMCSa7RE
+Q8HPdY08JSUgcVqFazu9CFjv/NNGkaaWXoqSkdQKIlYGwIDAQABo4GFMIGCMA8G
A1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTkEQS/jMRY
5qI4Vm82EJ+qU0bXMjBABgNVHSMEOTA3gBTkEQS/jMRY5qI4Vm82EJ+qU0bXMqEa
pBgwFjEUMBIGA1UEAwwLZXhhbXBsZS5jb22CAwDnKDANBgkqhkiG9w0BAQsFAAOC
AgEAdlzNvT5JNGMKX7IStrAprY4rWpd3UkM36n2CriMrQHfyv0zWS277eiY+DNHf
Hx1qscYSA6YyKj5ow9BwVgKz0NoEjbX5CAN2EebmqKePXDNTgHkhx2h2+1S8JeQp
bOei0TANSiQpqCR8lO9kEi8+4vcHdfYC9Hn7EFXuW4xvYbxJ3YVmkRZDQ/3oUX0q
HevogupOtH6ZpemSkQx81VOMPoloCCwq9wU+yHDMcYRIxp8ySdsxEAMHTlBXW1wB
86eZ6TotzSgiK4VzYTth67O4dQaWYASA/CGBURVWuwV1kzMrDaZn+V8oySDBo9Ct
TM3K+UWjNuLlEwgpCMF8ze/TNaJQHg5R0ap34hb0nfdOnIComxM8kzXzmbODSinz
/VgndXjnlxiw+JTgR8Fuc5mBolnyZddj9QXTO83Ze0/u2lUU/RP93MrgPQAYGOa2
IdnKhkiEvS0xhBdQWevgLLL3aRqfzdiHxXMZ3dtEAo2X5iAZtyH/ZFR8XNeFb2xm
yNjID1691R7HHzA/KIh89vimv47H1XdjpTlKS21WcS82pOPZndq4B0q788KZ2npo
33dSAd7PlWfzZQjooKEWXVbfTewkN5DIHmWZG8ZMqxLHtf0vzPy5UKe2KVLcZ3N1
chdoswVOLa4omXy+pYGiLuhv+xEp/zev18hjcwz1b0Piuds=
-----END CERTIFICATE-----

View file

@ -1,7 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe X509CertificateForm, type: :model do
pending "add some examples to (or delete) #{__FILE__}"
end

View file

@ -1,194 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe CreateEcurveKeys do
subject do
described_class.call account: account, password: password, curve: curve
end
let(:account) { create :initial_account }
let(:password) { Faker::Internet.password }
let(:curve) { EcurveKey::CURVES.sample }
specify do
expect { subject }.to change(AsymmetricKey, :count).by(1)
end
specify do
expect { subject }.to change(EcurveKey, :count).by(1)
end
specify do
expect { subject }.to(
have_enqueued_job(ClearAsymmetricPrivateKeyJob)
.with do |asymmetric_key_id|
expect(asymmetric_key_id).to equal AsymmetricKey.last.id
end,
)
end
specify do
expect(subject.asymmetric_key).to be_instance_of EcurveKey
end
specify do
expect(subject.asymmetric_key.curve).to eq curve
end
specify do
expect(subject.asymmetric_key.bits).to equal nil
end
specify do
expect(subject.asymmetric_key.has_password).to equal true
end
specify do
expect(subject.asymmetric_key.sha1).not_to be_blank
end
specify do
expect(subject.asymmetric_key.sha256).not_to be_blank
end
specify do
expect(subject.asymmetric_key.private_key_pem).not_to be_blank
end
specify do
expect(subject.asymmetric_key.private_key_pem_secret).not_to be_blank
end
specify do
expect(subject.asymmetric_key.account).to eq account
end
specify do
expect do
OpenSSL::PKey::EC.new(
subject.asymmetric_key.private_key_pem,
String(password),
)
end.not_to raise_error
end
specify do
expect do
OpenSSL::PKey::EC.new(
subject.asymmetric_key.public_key_pem,
String(password),
)
end.not_to raise_error
end
specify do
expect(subject.asymmetric_key.sha1).to eq(
Digest::SHA1.hexdigest(
OpenSSL::PKey::EC.new(
subject.asymmetric_key.public_key_pem,
String(password),
).to_der,
),
)
end
specify do
expect(subject.asymmetric_key.sha256).to eq(
Digest::SHA256.hexdigest(
OpenSSL::PKey::EC.new(
subject.asymmetric_key.public_key_pem,
String(password),
).to_der,
),
)
end
specify do
private_key = OpenSSL::PKey::EC.new(
subject.asymmetric_key.private_key_pem,
String(password),
)
public_key = OpenSSL::PKey::EC.new private_key.public_key.group
public_key.public_key = private_key.public_key
expect(subject.asymmetric_key.public_key_pem).to eq public_key.to_pem
end
specify do
expect(subject.asymmetric_key.private_key_pem_iv).not_to be_blank
end
specify do
expect(subject.asymmetric_key.private_key_pem_ciphertext).not_to be_blank
end
specify do
cipher = OpenSSL::Cipher::AES256.new
cipher.decrypt
cipher.iv = subject.asymmetric_key.private_key_pem_iv
cipher.key = subject.asymmetric_key.private_key_pem_secret
cleartext = [
cipher.update(subject.asymmetric_key.private_key_pem_ciphertext),
cipher.final,
].join.freeze
expect(cleartext).to eq subject.asymmetric_key.private_key_pem
end
context 'when owner is not specified' do
let(:account) { nil }
specify do
expect(subject.asymmetric_key.account).to equal nil
end
end
context 'when password is nil' do
let(:password) { nil }
specify do
expect(subject.asymmetric_key.has_password).to equal false
end
end
context 'when password is blank' do
let(:password) { ' ' * rand(1..3) }
specify do
expect(subject.asymmetric_key.has_password).to equal false
end
end
context 'when password.to_s returns nil' do
let :password do
Class.new do
def to_s
nil
end
end.new
end
specify do
expect { subject }.to raise_error TypeError
end
end
context 'when curve value is invalid' do
let(:curve) { 'secp521r1' }
specify do
expect { subject }.to raise_error RuntimeError, 'Invalid curve'
end
end
context 'when curve value is nil' do
let(:curve) { nil }
specify do
expect(subject.asymmetric_key.curve).to eq 'prime256v1'
end
end
end

View file

@ -1,90 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe CreateRSAKeysAndX509SelfSignedCertificate do
subject do
described_class.call(
account: account,
password: password,
distinguished_name: distinguished_name,
not_before: not_before,
not_after: not_after,
)
end
let(:account) { create :initial_account }
let(:password) { Faker::Internet.password }
let(:distinguished_name) { "CN=#{Faker::Internet.domain_name}" }
let(:not_before) { Faker::Time.backward.utc }
let(:not_after) { Faker::Time.forward.utc }
specify do
expect { subject }.to change(AsymmetricKey, :count).by(1)
end
specify do
expect { subject }.to change(RSAKey, :count).by(1)
end
specify do
expect { subject }.to change(X509Certificate, :count).by(1)
end
specify do
expect { subject }.to(
have_enqueued_job(ClearAsymmetricPrivateKeyJob)
.with do |asymmetric_key_id|
expect(asymmetric_key_id).to equal AsymmetricKey.last.id
end,
)
end
specify do
expect(subject.asymmetric_key).to be_instance_of RSAKey
end
specify do
expect(subject.asymmetric_key.has_password).to equal true
end
specify do
expect(subject.certificate).to be_instance_of X509Certificate
end
specify do
expect(subject.asymmetric_key.private_key_pem).not_to be_blank
end
specify do
expect(subject.asymmetric_key.private_key_pem_secret).not_to be_blank
end
specify do
expect(subject.asymmetric_key.account).to eq account
end
context 'when owner is not specified' do
let(:account) { nil }
specify do
expect(subject.asymmetric_key.account).to equal nil
end
end
context 'when password is nil' do
let(:password) { nil }
specify do
expect(subject.asymmetric_key.has_password).to equal false
end
end
context 'when password is blank' do
let(:password) { ' ' * rand(1..3) }
specify do
expect(subject.asymmetric_key.has_password).to equal false
end
end
end

View file

@ -1,192 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe CreateRSAKeys do
subject do
described_class.call account: account, password: password, bits: bits
end
let(:account) { create :initial_account }
let(:password) { Faker::Internet.password }
let(:bits) { RSAKey::BITS.sample }
specify do
expect { subject }.to change(AsymmetricKey, :count).by(1)
end
specify do
expect { subject }.to change(RSAKey, :count).by(1)
end
specify do
expect { subject }.to(
have_enqueued_job(ClearAsymmetricPrivateKeyJob)
.with do |asymmetric_key_id|
expect(asymmetric_key_id).to equal AsymmetricKey.last.id
end,
)
end
specify do
expect(subject.asymmetric_key).to be_instance_of RSAKey
end
specify do
expect(subject.asymmetric_key.bits).to equal bits
end
specify do
expect(subject.asymmetric_key.curve).to equal nil
end
specify do
expect(subject.asymmetric_key.has_password).to equal true
end
specify do
expect(subject.asymmetric_key.sha1).not_to be_blank
end
specify do
expect(subject.asymmetric_key.sha256).not_to be_blank
end
specify do
expect(subject.asymmetric_key.private_key_pem).not_to be_blank
end
specify do
expect(subject.asymmetric_key.private_key_pem_secret).not_to be_blank
end
specify do
expect(subject.asymmetric_key.account).to eq account
end
specify do
expect do
OpenSSL::PKey::RSA.new(
subject.asymmetric_key.private_key_pem,
String(password),
)
end.not_to raise_error
end
specify do
expect do
OpenSSL::PKey::RSA.new(
subject.asymmetric_key.public_key_pem,
String(password),
)
end.not_to raise_error
end
specify do
expect(subject.asymmetric_key.sha1).to eq(
Digest::SHA1.hexdigest(
OpenSSL::PKey::RSA.new(
subject.asymmetric_key.public_key_pem,
String(password),
).to_der,
),
)
end
specify do
expect(subject.asymmetric_key.sha256).to eq(
Digest::SHA256.hexdigest(
OpenSSL::PKey::RSA.new(
subject.asymmetric_key.public_key_pem,
String(password),
).to_der,
),
)
end
specify do
expect(subject.asymmetric_key.public_key_pem).to eq(
OpenSSL::PKey::RSA.new(
subject.asymmetric_key.private_key_pem,
String(password),
)
.public_key.to_pem,
)
end
specify do
expect(subject.asymmetric_key.private_key_pem_iv).not_to be_blank
end
specify do
expect(subject.asymmetric_key.private_key_pem_ciphertext).not_to be_blank
end
specify do
cipher = OpenSSL::Cipher::AES256.new
cipher.decrypt
cipher.iv = subject.asymmetric_key.private_key_pem_iv
cipher.key = subject.asymmetric_key.private_key_pem_secret
cleartext = [
cipher.update(subject.asymmetric_key.private_key_pem_ciphertext),
cipher.final,
].join.freeze
expect(cleartext).to eq subject.asymmetric_key.private_key_pem
end
context 'when owner is not specified' do
let(:account) { nil }
specify do
expect(subject.asymmetric_key.account).to equal nil
end
end
context 'when password is nil' do
let(:password) { nil }
specify do
expect(subject.asymmetric_key.has_password).to equal false
end
end
context 'when password is blank' do
let(:password) { ' ' * rand(1..3) }
specify do
expect(subject.asymmetric_key.has_password).to equal false
end
end
context 'when password.to_s returns nil' do
let :password do
Class.new do
def to_s
nil
end
end.new
end
specify do
expect { subject }.to raise_error TypeError
end
end
context 'when bits value is invalid' do
let(:bits) { 1024 }
specify do
expect { subject }.to raise_error RuntimeError, 'Invalid key size'
end
end
context 'when bits value is nil' do
let(:bits) { nil }
specify do
expect(subject.asymmetric_key.bits).to equal 4096
end
end
end

View file

@ -1,52 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe CreateX509SelfSignedCertificate do
subject do
described_class.call(
asymmetric_key: asymmetric_key,
distinguished_name: distinguished_name,
not_before: not_before,
not_after: not_after,
)
end
let(:asymmetric_key) { CreateRSAKeys.call.asymmetric_key }
let(:distinguished_name) { "CN=#{Faker::Internet.domain_name}" }
let(:not_before) { Faker::Time.backward.utc }
let(:not_after) { Faker::Time.forward.utc }
specify do
expect { subject }.to change(X509Certificate, :count).by(1)
end
specify do
expect(subject.certificate).to be_instance_of X509Certificate
end
specify do
expect(subject.certificate.asymmetric_key).to eq asymmetric_key
end
specify do
expect(subject.certificate.pem).to \
be_start_with "-----BEGIN CERTIFICATE-----\n"
end
specify do
expect(subject.certificate.subject).to eq "/#{distinguished_name}"
end
specify do
expect(subject.certificate.issuer).to eq "/#{distinguished_name}"
end
specify do
expect(subject.certificate.not_before).to eq not_before
end
specify do
expect(subject.certificate.not_after).to eq not_after
end
end

View file

@ -1,7 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe ImportAsymmetricKey do
pending "add some examples to (or delete) #{__FILE__}"
end

View file

@ -1,7 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe ClearAsymmetricPrivateKeyJob do
pending "add some examples to (or delete) #{__FILE__}"
end

View file

@ -1,7 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe AsymmetricKey do
pending "add some examples to (or delete) #{__FILE__}"
end

View file

@ -1,20 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe EcurveKey do
subject { create :ecurve_key }
it_behaves_like 'asymmetric_key'
describe '#curve' do
it do
is_expected.to \
validate_inclusion_of(:curve).in_array(%w[prime256v1 secp384r1])
end
end
describe '#bits' do
it { is_expected.to validate_absence_of :bits }
end
end

View file

@ -1,212 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe RSAKey do
subject { create :rsa_key }
it_behaves_like 'asymmetric_key'
describe '#bits' do
it { is_expected.to validate_inclusion_of(:bits).in_array([2048, 4096]) }
end
describe '#curve' do
it { is_expected.to validate_absence_of :curve }
end
describe '#encrypt_private_key_pem' do
subject { create :rsa_key, private_key_pem: cleartext }
let(:cleartext) { OpenSSL::PKey::RSA.new.to_pem.freeze }
specify do
expect(subject.encrypt_private_key_pem).to be_instance_of String
end
specify do
expect(subject.encrypt_private_key_pem).to be_frozen
end
specify do
expect(subject.encrypt_private_key_pem).to \
equal subject.private_key_pem_secret
end
specify do
expect { subject.encrypt_private_key_pem }.to \
change(subject, :private_key_pem_iv)
.from(nil)
end
specify do
expect { subject.encrypt_private_key_pem }.to \
change(subject, :private_key_pem_secret)
.from(nil)
end
specify do
expect { subject.encrypt_private_key_pem }.to \
change(subject, :private_key_pem_ciphertext)
.from(nil)
end
context 'after call' do
before { subject.encrypt_private_key_pem }
specify do
expect(subject.private_key_pem).to be_instance_of String
end
specify do
expect(subject.private_key_pem_iv).to be_instance_of String
end
specify do
expect(subject.private_key_pem_secret).to be_instance_of String
end
specify do
expect(subject.private_key_pem_ciphertext).to be_instance_of String
end
specify do
expect(subject.private_key_pem).to be_frozen
end
specify do
expect(subject.private_key_pem_iv).to be_frozen
end
specify do
expect(subject.private_key_pem_secret).to be_frozen
end
specify do
expect(subject.private_key_pem_ciphertext).to be_frozen
end
specify do
expect(subject.private_key_pem).to eq cleartext
end
specify do
expect(subject.private_key_pem_iv).not_to be_blank
end
specify do
expect(subject.private_key_pem_secret).not_to be_blank
end
specify do
expect(subject.private_key_pem_ciphertext).not_to be_blank
end
specify do
cipher = OpenSSL::Cipher::AES256.new
cipher.encrypt
cipher.iv = subject.private_key_pem_iv
cipher.key = subject.private_key_pem_secret
ciphertext = [
cipher.update(cleartext),
cipher.final,
].join.freeze
expect(subject.private_key_pem_ciphertext).to eq ciphertext
end
end
end
describe '#decrypt_private_key_pem' do
subject do
create(
:rsa_key,
private_key_pem_iv: iv,
private_key_pem_secret: secret,
private_key_pem_ciphertext: ciphertext,
)
end
let(:cleartext) { OpenSSL::PKey::RSA.new.to_pem.freeze }
let!(:cipher) { OpenSSL::Cipher::AES256.new.tap(&:encrypt) }
let!(:iv) { cipher.random_iv.freeze }
let!(:secret) { cipher.random_key.freeze }
let!(:ciphertext) { [cipher.update(cleartext), cipher.final].join.freeze }
specify do
expect(subject.decrypt_private_key_pem).to be_instance_of String
end
specify do
expect(subject.decrypt_private_key_pem).to be_frozen
end
specify do
expect(subject.decrypt_private_key_pem).to equal subject.private_key_pem
end
specify do
expect { subject.decrypt_private_key_pem }.to \
change(subject, :private_key_pem)
.from(nil)
.to(cleartext)
end
context 'after call' do
before { subject.decrypt_private_key_pem }
specify do
expect(subject.private_key_pem).to be_instance_of String
end
specify do
expect(subject.private_key_pem_iv).to be_instance_of String
end
specify do
expect(subject.private_key_pem_secret).to be_instance_of String
end
specify do
expect(subject.private_key_pem_ciphertext).to be_instance_of String
end
specify do
expect(subject.private_key_pem).to be_frozen
end
specify do
expect(subject.private_key_pem_iv).to be_frozen
end
specify do
expect(subject.private_key_pem_secret).to be_frozen
end
specify do
expect(subject.private_key_pem_ciphertext).to be_frozen
end
specify do
expect(subject.private_key_pem).to eq cleartext
end
specify do
expect(subject.private_key_pem_iv).to equal iv
end
specify do
expect(subject.private_key_pem_secret).to equal secret
end
specify do
expect(subject.private_key_pem_ciphertext).to equal ciphertext
end
end
end
end

View file

@ -1,52 +0,0 @@
# frozen_string_literal: true
RSpec.shared_examples 'asymmetric_key' do
describe '#account' do
it { is_expected.to belong_to(:account).optional }
it { is_expected.not_to validate_presence_of :account }
it { is_expected.not_to validate_uniqueness_of :account }
end
describe '#public_key_pem' do
it { is_expected.to validate_presence_of :public_key_pem }
it { is_expected.to validate_uniqueness_of :public_key_pem }
end
describe '#public_key_der' do
it { is_expected.to validate_presence_of :public_key_der }
it { is_expected.to validate_uniqueness_of :public_key_der }
end
describe '#has_password' do
it { is_expected.not_to validate_presence_of :has_password }
end
describe '#bits' do
it do
is_expected.to \
validate_numericality_of(:bits)
.allow_nil
.only_integer
.is_greater_than(0)
end
end
describe '#sha1' do
it { is_expected.to validate_presence_of :sha1 }
it { is_expected.to validate_uniqueness_of(:sha1).case_insensitive }
end
describe '#sha256' do
it { is_expected.to validate_presence_of :sha256 }
it { is_expected.to validate_uniqueness_of(:sha256).case_insensitive }
end
describe '#private_key_pem_iv' do
it { is_expected.not_to validate_presence_of :private_key_pem_iv }
end
describe '#private_key_pem_ciphertext' do
it { is_expected.not_to validate_presence_of :private_key_pem_ciphertext }
end
end

View file

@ -1,50 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe X509Certificate do
subject { create :self_signed_x509_certificate }
describe '#asymmetric_key' do
it { is_expected.to belong_to(:asymmetric_key).required }
it do
is_expected.to \
validate_presence_of(:asymmetric_key).with_message(:required)
end
it { is_expected.not_to validate_uniqueness_of :asymmetric_key }
end
describe '#pem' do
def allow_value(*)
super.for :pem
end
it { is_expected.to validate_presence_of :pem }
it 'is allowed to be a valid certificate' do
is_expected.to allow_value File.read Rails.root.join 'fixtures', 'ca.crt'
end
it 'is not allowed to be an invalid certificate' do
is_expected.not_to allow_value OpenSSL::X509::Certificate.new.to_pem
end
end
describe '#subject' do
it { is_expected.to validate_presence_of :subject }
end
describe '#issuer' do
it { is_expected.to validate_presence_of :issuer }
end
describe '#not_before' do
it { is_expected.to validate_presence_of :not_before }
end
describe '#not_after' do
it { is_expected.to validate_presence_of :not_after }
end
end

View file

@ -1,7 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe AsymmetricKeyPolicy do
pending "add some examples to (or delete) #{__FILE__}"
end

View file

@ -1,7 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe PrivateKeyPolicy do
pending "add some examples to (or delete) #{__FILE__}"
end

View file

@ -1,7 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Staff::X509CertificatePolicy do
pending "add some examples to (or delete) #{__FILE__}"
end

View file

@ -1,7 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe PrivateKey, type: :model do
pending "add some examples to (or delete) #{__FILE__}"
end

View file

@ -37,7 +37,6 @@ require_relative 'support/database_cleaner'
require_relative 'support/devise' require_relative 'support/devise'
require_relative 'support/pundit' require_relative 'support/pundit'
require_relative 'models/shared_examples/asymmetric_key'
require_relative 'models/shared_examples/nameable' require_relative 'models/shared_examples/nameable'
require_relative 'models/shared_examples/required_nameable' require_relative 'models/shared_examples/required_nameable'

View file

@ -1,7 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'POST /asymmetric_keys' do
pending "add some examples to (or delete) #{__FILE__}"
end

View file

@ -1,69 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'GET /asymmetric_keys' do
let(:current_account) { create :superuser_account }
let :asymmetric_keys_count do
[0, 1, rand(2..4), rand(5..10), rand(20..40)].sample
end
let(:rsa_keys_count) { rand(1...asymmetric_keys_count) || 0 }
let(:ecurve_keys_count) { asymmetric_keys_count - rsa_keys_count }
before do
sign_in current_account.user if current_account&.user
create_list :rsa_key, rsa_keys_count
create_list :ecurve_key, ecurve_keys_count
get '/asymmetric_keys'
end
for_account_types nil, :usual, :superuser do
specify do
expect(response).to have_http_status :ok
end
end
context 'when there are no asymmetric keys' do
let(:asymmetric_keys_count) { 0 }
specify do
expect(response).to have_http_status :ok
end
end
context 'when there is one asymmetric key' do
let(:asymmetric_keys_count) { 1 }
specify do
expect(response).to have_http_status :ok
end
end
context 'when there are few asymmetric keys' do
let(:asymmetric_keys_count) { rand 2..4 }
specify do
expect(response).to have_http_status :ok
end
end
context 'when there are many asymmetric keys' do
let(:asymmetric_keys_count) { rand 5..10 }
specify do
expect(response).to have_http_status :ok
end
end
context 'when there are lot of asymmetric keys' do
let(:asymmetric_keys_count) { rand 20..40 }
specify do
expect(response).to have_http_status :ok
end
end
end

View file

@ -1,17 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'GET /asymmetric_keys/new' do
before do
sign_in current_account.user if current_account&.user
get '/asymmetric_keys/new'
end
for_account_types nil, :usual, :superuser do
specify do
expect(response).to have_http_status :ok
end
end
end

View file

@ -1,40 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'GET /asymmetric_keys/:id' do
let(:current_account) { nil }
let(:asymmetric_key) { create %i[rsa_key ecurve_key].sample }
def make_request
get "/asymmetric_keys/#{asymmetric_key.id}"
end
before do
sign_in current_account.user if current_account&.user
make_request
end
for_account_types nil, :usual, :superuser do
specify do
expect(response).to have_http_status :ok
end
end
context 'for RSA key' do
let(:asymmetric_key) { create :rsa_key }
specify do
expect(response).to have_http_status :ok
end
end
context 'for elliptic-curve key' do
let(:asymmetric_key) { create :ecurve_key }
specify do
expect(response).to have_http_status :ok
end
end
end

View file

@ -1,7 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'GET /private_keys/:id' do
pending "add some examples to (or delete) #{__FILE__}"
end

View file

@ -1,140 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'POST /staff/x509_certificates' do
let(:current_account) { create :superuser_account }
let :x509_certificate_form_attributes do
{
distinguished_name: distinguished_name,
not_before: not_before,
not_after: not_after,
}
end
let :x509_certificate_attributes do
{
subject: distinguished_name,
issuer: distinguished_name,
not_before: not_before,
not_after: not_after,
}
end
let(:distinguished_name) { "/CN=#{Faker::Internet.domain_name}" }
let(:not_before) { Faker::Time.backward.utc }
let(:not_after) { Faker::Time.forward.utc }
def make_request
post '/staff/x509_certificates',
params: { x509_certificate: x509_certificate_form_attributes }
end
before do
sign_in current_account.user if current_account&.user
end
for_account_types nil, :usual do
specify do
expect { make_request }.not_to change(X509Certificate, :count)
end
context 'after request' do
before { make_request }
specify do
expect(response).to have_http_status :forbidden
end
end
end
for_account_types :superuser do
specify do
expect { make_request }.to change(X509Certificate, :count).by(1)
end
context 'after request' do
before { make_request }
specify do
expect(response).to \
redirect_to(/\A#{staff_x509_certificate_url(X509Certificate.last)}\?/)
end
specify do
expect(X509Certificate.last).to \
have_attributes x509_certificate_attributes
end
specify do
expect(X509Certificate.last.asymmetric_key.account).to \
eq current_account
end
end
end
context 'when distinguished name is missing' do
let(:distinguished_name) { nil }
specify do
expect { make_request }.not_to change(X509Certificate, :count)
end
context 'after request' do
before { make_request }
specify do
expect(response).to have_http_status :ok
end
end
end
context 'when activation time is missing' do
let(:not_before) { nil }
specify do
expect { make_request }.not_to change(X509Certificate, :count)
end
context 'after request' do
before { make_request }
specify do
expect(response).to have_http_status :ok
end
end
end
context 'when expiration time is missing' do
let(:not_after) { nil }
specify do
expect { make_request }.not_to change(X509Certificate, :count)
end
context 'after request' do
before { make_request }
specify do
expect(response).to have_http_status :ok
end
end
end
context 'when distinguished name is invalid' do
let(:distinguished_name) { 'Hello!' }
specify do
expect { make_request }.not_to change(X509Certificate, :count)
end
context 'after request' do
before { make_request }
specify do
expect(response).to have_http_status :ok
end
end
end
end

View file

@ -1,71 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'GET /staff/x509_certificates' do
let(:current_account) { create :superuser_account }
let :x509_certificates_count do
[0, 1, rand(2..4), rand(5..10), rand(20..40)].sample
end
before do
sign_in current_account.user if current_account&.user
create_list :self_signed_x509_certificate, x509_certificates_count
get '/staff/x509_certificates'
end
for_account_types nil, :usual do
specify do
expect(response).to have_http_status :forbidden
end
end
for_account_types :superuser do
specify do
expect(response).to have_http_status :ok
end
end
context 'when there are no X509 certificates' do
let(:x509_certificates_count) { 0 }
specify do
expect(response).to have_http_status :ok
end
end
context 'when there is one X509 certificate' do
let(:x509_certificates_count) { 1 }
specify do
expect(response).to have_http_status :ok
end
end
context 'when there are few X509 certificates' do
let(:x509_certificates_count) { rand 2..4 }
specify do
expect(response).to have_http_status :ok
end
end
context 'when there are many X509 certificates' do
let(:x509_certificates_count) { rand 5..10 }
specify do
expect(response).to have_http_status :ok
end
end
context 'when there are lot of X509 certificates' do
let(:x509_certificates_count) { rand 20..40 }
specify do
expect(response).to have_http_status :ok
end
end
end

View file

@ -1,23 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'GET /staff/x509_certificates/new' do
before do
sign_in current_account.user if current_account&.user
get '/staff/x509_certificates/new'
end
for_account_types nil, :usual do
specify do
expect(response).to have_http_status :forbidden
end
end
for_account_types :superuser do
specify do
expect(response).to have_http_status :ok
end
end
end

View file

@ -1,28 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'GET /staff/x509_certificates/:id' do
let(:x509_certificate) { create :self_signed_x509_certificate }
def make_request
get "/staff/x509_certificates/#{x509_certificate.id}"
end
before do
sign_in current_account.user if current_account&.user
make_request
end
for_account_types nil, :usual do
specify do
expect(response).to have_http_status :forbidden
end
end
for_account_types :superuser do
specify do
expect(response).to have_http_status :ok
end
end
end