Skip to content
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

Encrypt patron data #628

merged 7 commits into from Feb 18, 2020
Changes from all commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.


Just for now

@@ -5,6 +5,8 @@ git_source(:github) { |repo| "{repo}.git" }
# ie `~> 2.5` or `~> 2.6`, not including additional that may be in 2.3
ruby "~> #{'.ruby-version').chomp.split('.').slice(0,3).join('.')}"

gem 'lockbox'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 5.2.4'
gem 'webpacker', '~> 4.0'
@@ -314,6 +314,7 @@ GEM
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
ruby_dep (~> 1.2)
lockbox (0.3.1)
loofah (2.4.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
@@ -651,6 +652,7 @@ DEPENDENCIES
kaminari (~> 1.0)
listen (>= 3.0.5, < 3.2)
oai (~> 1.0, >= 1.0.1)
pdf-reader (~> 2.2)
pg (>= 0.18, < 2.0)
@@ -95,6 +95,8 @@ Some other interesting/complicated sub-systems we've written documentation for:
* [access-granted]( is used for some very simple authorization/permissions (right now just admins can do some things other logged in staff can not)
* [blacklight]( We are currently using Blacklight
for the "end-user-facing" search, although we are using it in a very limited and customized fashion, not including a lot of things the BL generator wanted to include in our app, that we didn't plan on using.
* [lockbox]( for encrypting our patron data in Admin::RAndRItem.
For rotating keys should private key need to be changed, see

### Task to copy a Work from staging to your local dev instance

@@ -63,6 +63,16 @@ def self.production?
define_key :aws_access_key_id
define_key :aws_secret_access_key

define_key :lockbox_master_key, default: -> {
# In production, we insist that local_env.yml contain
# a real 64-bit key; if none is defined, we fail at
# deploy time (see config/initializers/lockbox.rb).
# However, we do provide a dummy key for dev and test
# environments, which is a string of 64 zeros.
"0" * 64 if Rails.env.test? || Rails.env.development?

define_key :aws_region, default: "us-east-1"

# eg "", or "http://localhost:3000".
@@ -1,6 +1,17 @@
# This model is based on the parallel Admin::DigitizationQueueItem.rb.

# "RAndR" is "Rights & Reproductions", and represents requests from specific patrons
# for copies of things in our collection. We sometimes photograph things in response
# to patron request, sometimes they will wind up also being processed for adding
# to Digital Collections, other times not.
# This model is based on the parallel Admin::DigitizationQueueItem.rb, both are
# adaptations of former google doc spreadsheet-based processes, and track workflow.
class Admin::RAndRItem < ApplicationRecord

# For more info about how to rotate a leaked Lockbox master key,
# see
# and
encrypts :patron_name, :patron_email

has_many :digitization_queue_item, dependent: :nullify
has_many :queue_item_comments, dependent: :destroy

@@ -2,3 +2,6 @@

# Configure sensitive parameters which will be filtered from the log file.
Rails.application.config.filter_parameters += [:password]

Rails.application.config.filter_parameters += [:patron_email]
Rails.application.config.filter_parameters += [:patron_name]
@@ -0,0 +1,21 @@
lockbox_master_key = ScihistDigicoll::Env.lookup(:lockbox_master_key)

unless lockbox_master_key.present?
raise RuntimeError,
Lockbox master key is missing in production.
We encrypt our patron information using Lockbox.
For encryption to work in production, local_env.yml
must contain a line such as:
lockbox_master_key: #{Lockbox.generate_key}
A key can be generated in the Rails console by running:
More details can be found at .

Lockbox.master_key = lockbox_master_key
@@ -0,0 +1,9 @@
class AddPatronCyphertextToRAndRItems < ActiveRecord::Migration[5.2]
def change
add_column :r_and_r_items, :patron_name_ciphertext, :text
add_column :r_and_r_items, :patron_email_ciphertext, :text

remove_column :r_and_r_items, :patron_name, :string
remove_column :r_and_r_items, :patron_email, :string
@@ -343,8 +343,6 @@ CREATE TABLE public.r_and_r_items (
title character varying,
curator character varying,
collecting_area character varying,
patron_name character varying,
patron_email character varying,
bib_number character varying,
location character varying,
accession_number character varying,
@@ -365,7 +363,9 @@ CREATE TABLE public.r_and_r_items (
deadline timestamp without time zone,
date_files_sent timestamp without time zone,
created_at timestamp without time zone NOT NULL,
updated_at timestamp without time zone NOT NULL
updated_at timestamp without time zone NOT NULL,
patron_name_ciphertext text,
patron_email_ciphertext text

@@ -893,6 +893,7 @@ INSERT INTO "schema_migrations" (version) VALUES

@@ -21,6 +21,12 @@
expect(Admin::RAndRItem.count).to eq 1
item = Admin::RAndRItem.last
expect(item.title).to eq "Some Item"
# Just by way of making sure the patron and email are indeed
# encrypted in the DB. The length of the encrypted strings
# is arbitrary, but shouldn't change unless e.g. the master_key
# used for our test environment changes first.
expect(item.patron_name_ciphertext.length).to eq 56
expect(item.patron_email_ciphertext.length).to eq 56

it "it can show a single item" do
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.