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

Apply reCaptcha to Public Forms #477

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
c6fc02d
Working POC reCaptcha implementation
Jan 27, 2020
fd21a50
Merge faf049362452d4f5a86305375247f244fb8d29af into feature/sw-authfl…
salesforce-org-metaci[bot] Jan 28, 2020
ffaf21e
Adding component
Jan 28, 2020
7b17b51
Merge branch 'feature/sw-authflow__captcha' of github.com:SalesforceF…
Jan 28, 2020
29d8c71
Update captcha component
Jan 29, 2020
75a0549
Updated tests and formatting
Jan 29, 2020
894f842
Updated custom setting and formatting
Jan 29, 2020
a2f566f
Merge 876a3eccadc1a6702957b98432dc3bc73999ba17 into feature/sw-authfl…
salesforce-org-metaci[bot] Jan 29, 2020
aa1713d
Merge ef95b084c39a1621f6b4fc730a85af393bd9449a into feature/sw-authfl…
salesforce-org-metaci[bot] Jan 30, 2020
2c6ca8c
Updated structure, adjusted tests, fixed modal display
Jan 30, 2020
a68f6e1
Merge branch 'feature/sw-authflow__captcha' of github.com:SalesforceF…
Jan 30, 2020
00f5a05
Updated formatting
Jan 30, 2020
6ae848e
Missing class files
Jan 30, 2020
722920b
Formatting
Jan 30, 2020
342e0fa
Merge 93f3eb9ec459bc2530fec1141909e360ae79ef02 into feature/sw-authfl…
salesforce-org-metaci[bot] Jan 31, 2020
019e161
Merge 0f95a88d5a7452fa1992da9ccf136c174266c48e into feature/sw-authfl…
salesforce-org-metaci[bot] Mar 3, 2020
cdd3133
Merge f2b69caa85760a5124794d0c18fa4249f12a2890 into feature/sw-authfl…
salesforce-org-metaci[bot] May 6, 2020
ff9330f
Merge be11289a8509d325bb578d3583be67651341e65f into feature/sw-authfl…
salesforce-org-metaci[bot] Aug 21, 2020
46b0b63
Merge c564089b82817b72302707b60bcc9350e7fadbbc into feature/sw-authfl…
salesforce-org-metaci[bot] Aug 24, 2020
6859e89
Merge a3b9b7000d0a61fce1b2a24e9528d0b0ff3fefe6 into feature/sw-authfl…
salesforce-org-metaci[bot] Aug 27, 2020
1f88dca
Merge 75eb39a085b715bc7bba819e296a9ed25677aa80 into feature/sw-authfl…
salesforce-org-metaci[bot] Aug 27, 2020
fd621d5
Merge dd36f9a1139b84ac31682574a8e1e28ae55a9834 into feature/sw-authfl…
salesforce-org-metaci[bot] Sep 10, 2020
92fb1a8
Merge 117ea91f43f8383477296d08d73812979dc83817 into feature/sw-authfl…
salesforce-org-metaci[bot] Sep 30, 2020
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
25 changes: 25 additions & 0 deletions src/classes/HttpMockFactory.cls
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
@isTest
public class HttpMockFactory implements HttpCalloutMock {
protected Integer code;
protected String status;
protected String body;
protected Map<String, String> responseHeaders;

public HttpMockFactory(Integer code, String status, String body, Map<String, String> responseHeaders) {
this.code = code;
this.status = status;
this.body = body;
this.responseHeaders = responseHeaders;
}

public HTTPResponse respond(HTTPRequest req) {
HttpResponse res = new HttpResponse();
for (String key : this.responseHeaders.keySet()) {
res.setHeader(key, this.responseHeaders.get(key));
}
res.setBody(this.body);
res.setStatusCode(this.code);
res.setStatus(this.status);
return res;
}
}
5 changes: 5 additions & 0 deletions src/classes/HttpMockFactory.cls-meta.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>47.0</apiVersion>
<status>Active</status>
</ApexClass>
7 changes: 7 additions & 0 deletions src/classes/UTIL_UnitTest.cls
Original file line number Diff line number Diff line change
Expand Up @@ -251,4 +251,11 @@ public class UTIL_UnitTest {
Weekly_Occurrence__c = '1st');
}

public static void setupCaptchaSettings(Boolean enabled) {
VOL_SharedCode.VolunteersSettings.Enable_Site_Captcha__c = enabled;
VOL_SharedCode.VolunteersSettings.Google_reCaptcha_Endpoint__c = 'www.salesforce.com';
VOL_SharedCode.VolunteersSettings.Google_reCaptcha_Site_Key__c = '1234567890';
VOL_SharedCode.VolunteersSettings.Google_reCaptcha_Secret_Key__c = '1234567890';
}

}
18 changes: 12 additions & 6 deletions src/classes/VOL_CTRL_PersonalSiteContactLookup.cls
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
global with sharing class VOL_CTRL_PersonalSiteContactLookup {
@TestVisible
private static VOL_Access access = VOL_Access.getInstance();

@TestVisible
private static VOL_Captcha captcha = VOL_Captcha.getInstance();

// constructor
global VOL_CTRL_PersonalSiteContactLookup() {
Expand Down Expand Up @@ -72,12 +75,16 @@ global with sharing class VOL_CTRL_PersonalSiteContactLookup {
}

global string strResult { get; set; }
global string strLanguage { get; set; }
global string strLanguage { get; set; }

// the action method called from the page to lookup the contact, and to send them email if found.
global PageReference LookupContact() {

list<Contact> listCon = VOL_SharedCode.LookupContact(contact, null);
global PageReference LookupContact() {
if (!captcha.verifyCaptcha()) {
strResult = System.Label.CaptchaFailure;
return null;
}

list<Contact> listCon = VOL_SharedCode.LookupContact(contact, null);
if (listCon == null || listCon.size() == 0) {
strResult = System.Label.labelContactLookupAmbiguous;
} else {
Expand Down Expand Up @@ -123,7 +130,7 @@ global with sharing class VOL_CTRL_PersonalSiteContactLookup {
mail.setTemplateID(emailTemplateId);
if (orgWideEmailId != null) {
mail.setOrgWideEmailAddressId(orgWideEmailId);
}
}
list<Messaging.SendEmailResult> listSER;
listSER = Messaging.sendEmail(new Messaging.Email[] { mail }, false);
if (listSER[0].isSuccess()) {
Expand Down Expand Up @@ -183,5 +190,4 @@ global with sharing class VOL_CTRL_PersonalSiteContactLookup {
null :
closedTaskStatuses[0].ApiName;
}

}
46 changes: 46 additions & 0 deletions src/classes/VOL_CTRL_PersonalSiteContactLookup_TEST.cls
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,51 @@ private with sharing class VOL_CTRL_PersonalSiteContactLookup_TEST {
System.assertEquals(defaultClosedStatus, VOL_CTRL_PersonalSiteContactLookup.getClosedTaskStatus(), 'Expected the system to find the default closed task status when ran as a guest user.');
}
}

@IsTest
private static void shouldReturnErrorOnCaptchaFailure() {
//enable captcha
UTIL_UnitTest.setupCaptchaSettings(true);

//point to our VF page
PageReference lookupPage = Page.PersonalSiteContactLookup;
Test.setCurrentPage(lookupPage);

Test.startTest();
VOL_CTRL_PersonalSiteContactLookup ctrl = new VOL_CTRL_PersonalSiteContactLookup();
ctrl.contact.Firstname = 'Test';
ctrl.contact.Lastname = 'User';
ctrl.contact.Email = '[email protected]';
ctrl.LookupContact();
Test.stopTest();

System.assertEquals(System.Label.CaptchaFailure, ctrl.strResult);
}

@IsTest
private static void shouldReturnSuccessMessageOnCaptchaSuccess() {
//enable captcha
UTIL_UnitTest.setupCaptchaSettings(true);

HttpMockFactory mock = new HttpMockFactory(200, 'OK', '{"success":true}', new Map<String,String>());
Test.setMock(HttpCalloutMock.class, mock);

//point to our VF page
PageReference lookupPage = Page.PersonalSiteContactLookup;
Test.setCurrentPage(lookupPage);
System.currentPageReference().getParameters().put('g-recaptcha-response', '1234567890');

Test.startTest();
VOL_CTRL_PersonalSiteContactLookup ctrl = new VOL_CTRL_PersonalSiteContactLookup();
ctrl.contact.Firstname = 'Test';
ctrl.contact.Lastname = 'User';
ctrl.contact.Email = '[email protected]';
ctrl.LookupContact();
Test.stopTest();

System.assertEquals(System.Label.labelContactLookupAmbiguous, ctrl.strResult);
}

@isTest(SeeAllData=true) // SeeAllData so the CSS file is viewable
/*******************************************************************************************************
* @description test the visualforce page controller, running as the Sites Guest User, if such as user
Expand All @@ -104,6 +148,8 @@ private with sharing class VOL_CTRL_PersonalSiteContactLookup_TEST {
}

private static void TestPersonalSiteContactLookup() {
//disable captcha
UTIL_UnitTest.setupCaptchaSettings(false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it is disabled by default, why do we need to disable it here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Safeguards the test against unexpected changes elsewhere by being explicit here.


//point to our VF page
PageReference p = new PageReference('Page.PersonalSiteContactLookup');
Expand Down
12 changes: 10 additions & 2 deletions src/classes/VOL_CTRL_VolunteersJobListingFS.cls
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
global virtual with sharing class VOL_CTRL_VolunteersJobListingFS {
@TestVisible
private static VOL_Access access = VOL_Access.getInstance();

@TestVisible
private static VOL_Captcha captcha = VOL_Captcha.getInstance();

/**
* Hard coding the subquery limit to 200 to prevent an error being displayed when
* attempting to access the list of child records when more than 200 are present
Expand Down Expand Up @@ -418,6 +422,11 @@ global virtual with sharing class VOL_CTRL_VolunteersJobListingFS {
private class MyException extends Exception {}

global virtual PageReference VolunteerShiftSignUp() {
if (!captcha.verifyCaptcha()) {
strSaveResult = System.Label.CaptchaFailure;
ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.FATAL, System.Label.CaptchaFailure));
return null;
}

Savepoint sp = Database.setSavepoint();
try {
Expand Down Expand Up @@ -449,8 +458,7 @@ global virtual with sharing class VOL_CTRL_VolunteersJobListingFS {
dtStart = listShift[0].Start_Date_Time__c.date();
duration = listShift[0].Duration__c;
}
}

}
// when used within the Personal Site, we should use the appropriate Contact
Cookie cId = ApexPages.currentPage().getCookies().get('contactIdPersonalSite');
ID contactIdPersonalSite = null;
Expand Down
62 changes: 62 additions & 0 deletions src/classes/VOL_CTRL_VolunteersJobListingFS_TEST.cls
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,68 @@ private with sharing class VOL_CTRL_VolunteersJobListingFS_TEST {
System.assertEquals(QUERY_LIMIT, jobListingCtrl.listVolunteerJobs[0].Volunteer_Job_Slots__r.size(), 'The number of shifts returned was not as expected.');
}

@IsTest
private static void shouldNotContainPageMessageOnCaptchaSuccess() {
generateData(1);
UTIL_UnitTest.setupCaptchaSettings(true);

HttpMockFactory mock = new HttpMockFactory(200, 'OK', '{"success":true}', new Map<String,String>());
Test.setMock(HttpCalloutMock.class, mock);

Contact existingContact = UTIL_UnitTest.createContact('Signup Update ' + DateTime.now().getTime());
insert existingContact;

Id jobId = [SELECT Id FROM Volunteer_Job__c LIMIT 1].Id;
Id shiftId = [SELECT Id FROM Volunteer_Shift__c Where Volunteer_Job__c = :jobId LIMIT 1].Id;

setupPage(new Map<String, String>{'g-recaptcha-response' => '1234567890'});

Test.startTest();
jobListingCtrl.shiftIdSignUp = shiftId;
jobListingCtrl.jobIdSignUp = jobId;
jobListingCtrl.contact = existingContact;
jobListingCtrl.vhours.Number_of_Volunteers__c = 2;
jobListingCtrl.VolunteerShiftSignUp();
Test.stopTest();

List<Apexpages.Message> messages = ApexPages.getMessages();
System.assertEquals(0, messages.size());
}

@IsTest
private static void shouldReturnErrorOnCaptchaFailure() {
generateData(1);
UTIL_UnitTest.setupCaptchaSettings(true);

Contact existingContact = UTIL_UnitTest.createContact('Signup Update ' + DateTime.now().getTime());
insert existingContact;

Id jobId = [SELECT Id FROM Volunteer_Job__c LIMIT 1].Id;
Id shiftId = [SELECT Id FROM Volunteer_Shift__c Where Volunteer_Job__c = :jobId LIMIT 1].Id;

setupPage(new Map<String, String>());

Test.startTest();
jobListingCtrl.shiftIdSignUp = shiftId;
jobListingCtrl.jobIdSignUp = jobId;
jobListingCtrl.contact = existingContact;
jobListingCtrl.vhours.Number_of_Volunteers__c = 2;
jobListingCtrl.VolunteerShiftSignUp();
Test.stopTest();

Boolean expectedMessage = false;
List<Apexpages.Message> messages = ApexPages.getMessages();
System.assertNotEquals(0, messages.size());

for (Apexpages.Message message : messages) {
if (message.getDetail().contains(System.Label.CaptchaFailure)) {
expectedMessage = true;
}
}

System.assertEquals(true, expectedMessage);
}

private static void setupPage(Map<String, String> params) {
PageReference pageRef = Page.VolunteersJobListingFS;

Expand Down
12 changes: 9 additions & 3 deletions src/classes/VOL_CTRL_VolunteersReportHours.cls
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,13 @@
*/

global virtual with sharing class VOL_CTRL_VolunteersReportHours {
private VOL_SharedCode volSharedCode;

private VOL_SharedCode volSharedCode;
@TestVisible
private static VOL_Access access = VOL_Access.getInstance();

@TestVisible
private static VOL_Captcha captcha = VOL_Captcha.getInstance();

// constructor
global VOL_CTRL_VolunteersReportHours() {
Expand Down Expand Up @@ -255,9 +258,12 @@ global virtual with sharing class VOL_CTRL_VolunteersReportHours {

private class MyException extends Exception {}


// action method for saving the the volunteer's hours.
global virtual PageReference Save() {
if (!captcha.verifyCaptcha()) {
strSaveResult = System.Label.CaptchaFailure;
return null;
}
Savepoint sp = Database.setSavepoint();
try {
// because we need to use actionSupport immediate=false to support the combo's,
Expand Down
54 changes: 54 additions & 0 deletions src/classes/VOL_CTRL_VolunteersReportHours_TEST.cls
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,60 @@ private with sharing class VOL_CTRL_VolunteersReportHours_TEST {
accessMock.assertMethodCalled('updateRecords', Volunteer_Hours__c.SObjectType);
}

@IsTest
private static void shouldReturnSuccessMessageOnCaptchaSuccess() {
UTIL_UnitTest.generateData();

//enable captcha
UTIL_UnitTest.setupCaptchaSettings(true);

HttpMockFactory mock = new HttpMockFactory(200, 'OK', '{"success":true}', new Map<String,String>());
Test.setMock(HttpCalloutMock.class, mock);

Contact contactRecord = (Contact) UTIL_UnitTest.getSObject(Contact.SObjectType);
Id jobId = UTIL_UnitTest.getId(Volunteer_Job__c.SObjectType);
Volunteer_Hours__c hours = UTIL_UnitTest.createHours(contactRecord.Id, jobId, null);
insert hours;

Test.setCurrentPage(reportHoursPage);
System.currentPageReference().getParameters().put('g-recaptcha-response', '1234567890');

Test.startTest();
VOL_CTRL_VolunteersReportHours reportHoursCtrl = new VOL_CTRL_VolunteersReportHours();
reportHoursCtrl.contact = contactRecord;
reportHoursCtrl.volunteerJobId = jobId;
reportHoursCtrl.vhours = hours;
reportHoursCtrl.Save();
Test.stopTest();

System.assertEquals(System.Label.labelVolunteerReportHoursThankYou, reportHoursCtrl.strSaveResult);
}

@IsTest
private static void shouldReturnErrorOnCaptchaFailure() {
UTIL_UnitTest.generateData();

//enable captcha
UTIL_UnitTest.setupCaptchaSettings(true);

Contact contactRecord = (Contact) UTIL_UnitTest.getSObject(Contact.SObjectType);
Id jobId = UTIL_UnitTest.getId(Volunteer_Job__c.SObjectType);
Volunteer_Hours__c hours = UTIL_UnitTest.createHours(contactRecord.Id, jobId, null);
insert hours;

Test.setCurrentPage(reportHoursPage);

Test.startTest();
VOL_CTRL_VolunteersReportHours reportHoursCtrl = new VOL_CTRL_VolunteersReportHours();
reportHoursCtrl.contact = contactRecord;
reportHoursCtrl.volunteerJobId = jobId;
reportHoursCtrl.vhours = hours;
reportHoursCtrl.Save();
Test.stopTest();

System.assertEquals(System.Label.CaptchaFailure, reportHoursCtrl.strSaveResult);
}

/*******************************************************************************************************
* @description test the visualforce page controller, running as the Sites Guest User, if such as user
* exists. if not, will run under the current user.
Expand Down
8 changes: 7 additions & 1 deletion src/classes/VOL_CTRL_VolunteersSignupFS.cls
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@
*/

global virtual with sharing class VOL_CTRL_VolunteersSignupFS {

@TestVisible
private static VOL_Captcha captcha = VOL_Captcha.getInstance();

// constructor
global VOL_CTRL_VolunteersSignupFS() {

Expand Down Expand Up @@ -96,6 +98,10 @@ global virtual with sharing class VOL_CTRL_VolunteersSignupFS {
global Attachment attachment { get; set; }

global virtual PageReference Save() {
if (!captcha.verifyCaptcha()) {
StrSaveResult = System.Label.CaptchaFailure;
return null;
}
try {
// save or update the contact
ID contactId = VOL_SharedCode.CreateOrUpdateContactFS(null, contact, contact.Volunteer_Organization__c, listStrFields, true);
Expand Down
Loading