Skip to content
Merged

0.379.0 #1825

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 19 additions & 19 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
GIT
remote: https://github.com/18F/omniauth_login_dot_gov.git
revision: b4d30dc92f2659e46680161bf02550ba424d768e
revision: 3eeff9bfcd57d781467e2ffb6cc11f459d8202ed
branch: main
specs:
omniauth_login_dot_gov (3.0.0)
Expand Down Expand Up @@ -103,10 +103,10 @@ GEM
aes_key_wrap (1.1.0)
ast (2.4.3)
aws-eventstream (1.3.2)
aws-partitions (1.1074.0)
aws-partitions (1.1078.0)
aws-record (2.13.2)
aws-sdk-dynamodb (~> 1, >= 1.85.0)
aws-sdk-core (3.221.0)
aws-sdk-core (3.222.1)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.992.0)
aws-sigv4 (~> 1.9)
Expand All @@ -130,7 +130,7 @@ GEM
aws-sessionstore-dynamodb (~> 2)
concurrent-ruby (~> 1.3, >= 1.3.1)
railties (>= 7.0.0)
aws-sdk-s3 (1.182.0)
aws-sdk-s3 (1.183.0)
aws-sdk-core (~> 3, >= 3.216.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.5)
Expand Down Expand Up @@ -329,7 +329,7 @@ GEM
listen (3.9.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
logger (1.6.6)
logger (1.7.0)
logstop (0.4.1)
logger
loofah (2.24.0)
Expand Down Expand Up @@ -370,24 +370,24 @@ GEM
net-protocol
newrelic_rpm (9.17.0)
nio4r (2.7.4)
nokogiri (1.18.6)
nokogiri (1.18.7)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
nokogiri (1.18.6-aarch64-linux-gnu)
nokogiri (1.18.7-aarch64-linux-gnu)
racc (~> 1.4)
nokogiri (1.18.6-aarch64-linux-musl)
nokogiri (1.18.7-aarch64-linux-musl)
racc (~> 1.4)
nokogiri (1.18.6-arm-linux-gnu)
nokogiri (1.18.7-arm-linux-gnu)
racc (~> 1.4)
nokogiri (1.18.6-arm-linux-musl)
nokogiri (1.18.7-arm-linux-musl)
racc (~> 1.4)
nokogiri (1.18.6-arm64-darwin)
nokogiri (1.18.7-arm64-darwin)
racc (~> 1.4)
nokogiri (1.18.6-x86_64-darwin)
nokogiri (1.18.7-x86_64-darwin)
racc (~> 1.4)
nokogiri (1.18.6-x86_64-linux-gnu)
nokogiri (1.18.7-x86_64-linux-gnu)
racc (~> 1.4)
nokogiri (1.18.6-x86_64-linux-musl)
nokogiri (1.18.7-x86_64-linux-musl)
racc (~> 1.4)
oauth2 (2.0.9)
faraday (>= 0.17.3, < 3.0)
Expand Down Expand Up @@ -415,7 +415,7 @@ GEM
activerecord (>= 6.1)
request_store (~> 1.4)
parallel (1.26.3)
parser (3.3.7.3)
parser (3.3.7.4)
ast (~> 2.4.1)
racc
pg (1.5.9)
Expand Down Expand Up @@ -492,7 +492,7 @@ GEM
rb-fsevent (0.11.2)
rb-inotify (0.11.1)
ffi (~> 1.0)
rdoc (6.13.0)
rdoc (6.13.1)
psych (>= 4.0.0)
redis (5.4.0)
redis-client (>= 0.22.0)
Expand Down Expand Up @@ -529,7 +529,7 @@ GEM
rspec-support (3.13.2)
rspec_junit_formatter (0.6.0)
rspec-core (>= 2, < 4, != 2.12.0)
rubocop (1.75.0)
rubocop (1.75.1)
json (~> 2.3)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.1.0)
Expand All @@ -543,11 +543,11 @@ GEM
rubocop-ast (1.43.0)
parser (>= 3.3.7.2)
prism (~> 1.4)
rubocop-rails (2.30.3)
rubocop-rails (2.31.0)
activesupport (>= 4.2.0)
lint_roller (~> 1.1)
rack (>= 1.1)
rubocop (>= 1.72.1, < 2.0)
rubocop (>= 1.75.0, < 2.0)
rubocop-ast (>= 1.38.0, < 2.0)
rubocop-rspec (3.5.0)
lint_roller (~> 1.1)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ within the Technology Transformation Services'

Touchpoints is online at <https://touchpoints.digital.gov/>.

A current Demo version is online at <https://touchpoints-demo.app.cloud.gov/index/>,
A Demo environment is online at <https://app-demo.touchpoints.digital.gov/>,
and government customers are [encouraged](https://github.com/GSA/touchpoints/wiki/Touchpoints-Demo-Environment/) to sign up and try it out.

## Documentation
Expand Down
2 changes: 2 additions & 0 deletions app/controllers/admin/forms_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,8 @@ def form_admin_options_params
:kind,
:aasm_state,
:early_submission,
:enable_turnstile,
:append_id_to_success_text,
:notes,
:status,
:title,
Expand Down
30 changes: 29 additions & 1 deletion app/controllers/submissions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,21 @@ def create
private

def create_in_local_database(submission)
if submission.form.enable_turnstile? && !verify_turnstile(params["cf-turnstile-response"])
submission.errors.add(:base, "Turnstile verification failed")
end

respond_to do |format|
if submission.save
if submission.errors.empty? && submission.save
format.html do
redirect_to submit_touchpoint_path(submission.form),
notice: 'Thank You. Response was submitted successfully.'
end
format.json do
form_success_text = submission.form.append_id_to_success_text? ?
submission.form.success_text + "<br><br> Your Response ID is: <strong>#{submission.uuid[-12..-1]}</strong>" :
submission.form.success_text

render json: {
submission: {
id: submission.uuid,
Expand Down Expand Up @@ -115,6 +123,8 @@ def create_in_local_database(submission)
id: submission.form.uuid,
name: submission.form.name,
organization_name: submission.organization_name,
success_text_heading: submission.form.success_text_heading,
success_text: form_success_text,
},
},
},
Expand Down Expand Up @@ -151,10 +161,28 @@ def set_form
def submission_params
permitted_fields = @form.questions.collect(&:answer_field)
permitted_fields << %i[language location_code referer hostname page query_string fba_directive]
permitted_fields << %i[cf-turnstile-response]
params.require(:submission).permit(permitted_fields)
end

def form_requires_verification
@form.verify_csrf?
end


private

def verify_turnstile(response_token)
secret_key = ENV.fetch("TURNSTILE_SECRET_KEY", nil)
uri = URI("https://challenges.cloudflare.com/turnstile/v0/siteverify")

response = Net::HTTP.post_form(uri, {
"secret" => secret_key,
"response" => response_token,
"remoteip" => request.remote_ip
})

json = JSON.parse(response.body)
json["success"] == true
end
end
24 changes: 24 additions & 0 deletions app/views/admin/forms/_form_manager_options.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,30 @@
<%= f.text_field :expiration_date, class: "usa-input" %>
</div>

<fieldset class="usa-fieldset margin-top-2">
<legend class="usa-sr-only">Enable Cloudfront Turnstile</legend>
<div class="usa-checkbox">
<%= f.check_box :enable_turnstile, class: "usa-checkbox__input" %>
<%= f.label :enable_turnstile, class: "usa-checkbox__label" do %>
Enable Cloudfront Turnstile
<small class="text-base">
As a spam prevention mechanism
</small>
<% end %>
</div>
</fieldset>
<fieldset class="usa-fieldset margin-top-2">
<legend class="usa-sr-only">Append ID to the form's Success Text</legend>
<div class="usa-checkbox">
<%= f.check_box :append_id_to_success_text, class: "usa-checkbox__input" %>
<%= f.label :append_id_to_success_text, class: "usa-checkbox__label" do %>
Append ID to Form's Success Text
<small class="text-base">
Append "Your Response ID is: 1307" to the Form's Success Text
</small>
<% end %>
</div>
</fieldset>
<fieldset class="usa-fieldset margin-top-2">
<legend class="usa-sr-only">Display Organization Tag Logo</legend>
<div class="usa-checkbox">
Expand Down
6 changes: 6 additions & 0 deletions app/views/components/forms/_custom.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@
<% end %>
</div>
<% end %>
<% if form.enable_turnstile? %>
<div class="margin-top-2">
<div class="cf-turnstile" data-sitekey="<%= ENV.fetch("TURNSTILE_SITE_KEY", nil) %>"></div>
<%= hidden_field_tag "cf-turnstile-response", nil %>
</div>
<% end %>
<%- if section == form.form_sections.last && !form.suppress_submit_button %>
<button type="submit" class="usa-button submit_form_button"><%= t 'form.submit' %></button>
<% end %>
Expand Down
30 changes: 26 additions & 4 deletions app/views/components/widget/_fba.js.erb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ function FBAform(d, N) {
if (this.options.formSpecificScript) {
this.options.formSpecificScript();
}
<% if form.enable_turnstile? %>
this.loadTurnstile()
<% end %>
d.dispatchEvent(new CustomEvent('onTouchpointsFormLoaded', {
detail: {
formComponent: this
Expand Down Expand Up @@ -413,16 +416,16 @@ function FBAform(d, N) {
successText: function() {
return this.options.successText;
},
showFormSuccess: function(e) {
showFormSuccess: function(headerText, bodyHTML) {
var formComponent = this.formComponent();
var formElement = this.formElement();
var alertElement = formComponent.querySelector(".fba-alert");
var alertElementHeading = formComponent.querySelector(".usa-alert__heading");
var alertElementBody = formComponent.querySelector(".usa-alert__text");

// Display success Message
alertElementHeading.innerHTML += this.successHeadingText();
alertElementBody.innerHTML = this.successText();
alertElementHeading.innerHTML = headerText;
alertElementBody.innerHTML = bodyHTML
alertElement.removeAttribute("hidden");
this.formComponent().scrollIntoView();

Expand Down Expand Up @@ -489,7 +492,11 @@ function FBAform(d, N) {
if(submitButton) {
submitButton.disabled = true;
}
this.showFormSuccess();

const submission = JSON.parse(e.target.response).submission;
const successHeaderText = submission.form.success_text_heading;
const successBodyText = submission.form.success_text;
this.showFormSuccess(successHeaderText, successBodyText);
} else if (e.target.status === 422) { // FORM ERRORS
this.successState = false;
d.dispatchEvent(new Event('onTouchpointsFormSubmissionError'));
Expand Down Expand Up @@ -548,6 +555,9 @@ function FBAform(d, N) {
xhr.setRequestHeader("Content-Type", "application/json; charset=UTF-8;");
xhr.onload = callback.bind(this);
xhr.send(JSON.stringify({
<% if form.enable_turnstile? %>
"cf-turnstile-response" : form.querySelector("input[name='cf-turnstile-response']") ? form.querySelector("input[name='cf-turnstile-response']").value : null,
<% end %>
"submission": params,
<%- if form.verify_csrf? %>
"authenticity_token": form.querySelector("#authenticity_token") ?
Expand Down Expand Up @@ -635,6 +645,18 @@ function FBAform(d, N) {
modalId: function() {
return `fba-modal-${this.options.formId}`;
},
<% if form.enable_turnstile? %>
loadTurnstile: function() {
let script = document.createElement("script");
script.src = "https://challenges.cloudflare.com/turnstile/v0/api.js";
script.async = true;
script.defer = true;
script.onload = function() {
document.querySelector("input[name='cf-turnstile-response']").value = token;
};
document.head.appendChild(script);
},
<% end %>
};
};

Expand Down
5 changes: 5 additions & 0 deletions db/migrate/20250401201045_append_id_to_success_text.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AppendIdToSuccessText < ActiveRecord::Migration[8.0]
def change
add_column :forms, :append_id_to_success_text, :boolean, default: false, comment: "Set to true to append a response ID to the form's success_text"
end
end
5 changes: 5 additions & 0 deletions db/migrate/20250401223209_add_form_turnstile.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddFormTurnstile < ActiveRecord::Migration[8.0]
def change
add_column :forms, :enable_turnstile, :boolean, default: false, comment: "Set to true to enable Cloudfront Turnstile"
end
end
4 changes: 3 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[8.0].define(version: 2025_03_07_211304) do
ActiveRecord::Schema[8.0].define(version: 2025_04_01_223209) do
# These are extensions that must be enabled in order to support this database
enable_extension "pg_catalog.plpgsql"

Expand Down Expand Up @@ -302,6 +302,8 @@
t.string "short_uuid", limit: 8
t.boolean "enforce_new_submission_validations", default: true
t.integer "service_stage_id"
t.boolean "append_id_to_success_text", default: false, comment: "Set to true to append a response ID to the form's success_text"
t.boolean "enable_turnstile", default: false, comment: "Set to true to enable Cloudfront Turnstile"
t.index ["legacy_touchpoint_id"], name: "index_forms_on_legacy_touchpoint_id"
t.index ["legacy_touchpoint_uuid"], name: "index_forms_on_legacy_touchpoint_uuid"
t.index ["organization_id"], name: "index_forms_on_organization_id"
Expand Down