-
Notifications
You must be signed in to change notification settings - Fork 983
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixes #13870 - encrypts specific settings values in db #3230
Conversation
@@ -0,0 +1,75 @@ | |||
module EncryptField |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Encryptable
module encrypts the whole attribute (column), while in some cases there is a need to encrypt a specific field (instance variable). such use cases can be found in settings, and in parameters.
hence encryptable
module has splitted into two modules, the first one is encrypt_field
, which can be included to models in case of specific fields encryption, and the encryptable
which keeps the logic for attribute encryption.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick, can you call this EncryptString or similar? "field" has a similar meaning to "attribute" to me, so I was confused for a while with the terminology.
@domcleal An |
[test] |
The failures are on every combination as DB migration from clean is failing, please take a look at the errors. |
Unit test failures remain, please take a look. Please remember to comment on PRs when you change them, see https://groups.google.com/d/msg/foreman-dev/poyjF8Ig5UE/jaFyZVGOsEUJ. |
@@ -100,11 +101,13 @@ def self.method_missing(method, *args) | |||
|
|||
def value=(v) | |||
v = v.to_yaml unless v.nil? | |||
v = encrypt_field(v) if defined? encrypted and encrypted |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefer has_attribute?(:encrypted)
perhaps? A comment to say why you're performing this check would be useful - I'm assuming it's to enable DB migrations on older versions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefer &&
in an expression instead of and
.
if change.is_a? Array | ||
change.map! {|c| c.to_s.start_with?(EncryptValue::ENCRYPTION_PREFIX) ? _("[encrypted]") : c} | ||
else | ||
audited_changes[name] = _("[encrypted]") if change.to_s.start_with?(EncryptValue::ENCRYPTION_PREFIX) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using _()
in this context will store the translated message in the database, so it'll be stored in the language of whoever made the change instead of whoever is viewing it.
I think perhaps you want to use _N('[encrypted]')
here to only extract it, store the English and then call _(db_value)
in the helper for display purposes (when db_value == '[encrypted]'
).
self.audited_changes.each do |name,change| | ||
next if change.nil? || change.to_s.empty? | ||
if change.is_a? Array | ||
change.map! {|c| c.to_s.start_with?(EncryptValue::ENCRYPTION_PREFIX) ? _("[encrypted]") : c} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto, storing a translated string instead of English
@@ -13,7 +13,7 @@ def id_to_label(name, change) | |||
when /.*_id$/ | |||
name.classify.gsub('Id','').constantize.find(change).to_label | |||
else | |||
change.to_s | |||
change.to_s.include?(EncryptValue::ENCRYPTION_PREFIX) ? _("[encrypted]") : change.to_s |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, that's better, but there aren't any tests for the functionality - please add to test/models/concerns/audit_extensions_test.rb.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i18n issue with the stored string, and missing unit test for the audit model changes.
@domcleal I fixed i18n issue , and added a unit test into Audit model extension. |
if change.is_a? Array | ||
change.map! {|c| c.to_s.start_with?(EncryptValue::ENCRYPTION_PREFIX) ? N_("[encrypted]") : c} | ||
else | ||
audited_changes[name] = N_("[encrypted]") if change.to_s.start_with?(EncryptValue::ENCRYPTION_PREFIX) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where does [encrypted]
get translated in the UI? My last comment here suggested doing it in a UI helper, but I can't see that in this PR. (See #3230 (comment))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just forgot to commit the changes in audits_helper
.
assert setting.save | ||
end | ||
a = Audit.where(auditable_type: 'Setting') | ||
assert_equal N_("[encrypted]"), a.last.audited_changes["value"][1] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove N_()
from here, no need to extract a string in a test.
Thanks, one last thing: the |
@domcleal I inserted |
Merged, thanks @amirfefer. |
In the following PR the use case came up.
In order to encrypt a setting value, set its
encrypted
flag to true: