Skip to content

Commit

Permalink
Merge pull request #3584 from SailingSteve/steveWebAppDec5-11am
Browse files Browse the repository at this point in the history
Allow Facebook signin from a browser that has not previously signed into facebook.com
  • Loading branch information
DaleMcGrew authored Dec 5, 2022
2 parents 69d975f + e790dc1 commit 8c1a0e3
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 23 deletions.
72 changes: 71 additions & 1 deletion docs/working/SECURE_CERTIFICATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,77 @@ that describes how to install a locally signed secure certificate on the Mac (it
- Then run `npm start` again.

# Turn on https for WebApp
In WebApp/src/js/config.js, set SECURE_CERTIFICATE_INSTALLED to true, and then run `npm start`.
In WebApp/src/js/config.js, set SECURE_CERTIFICATE_INSTALLED to true, and then run `npm start-https`.

WebApp will startup at http://localhost.3000

## Signing in with Facebook on your dev machine
### Make a small necessary change to your /etc/hosts

Facebook will no longer redirect to localhost, so make a second alias for 127.0.0.1 with this specific made up domain: `wevotedeveloper.com`

So we have to make a small change to /etc/hosts. This is the before:
```
(venv2) stevepodell@StevesM1Dec2021 WeVoteServer % cat /etc/hosts
##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting. Do not change this entry.
##
127.0.0.1 localhost
255.255.255.255 broadcasthost
::1 localhost
(venv2) stevepodell@StevesM1Dec2021 WeVoteServer %
```
We have added a fake local domain `wevotedeveloper.com` for the [Facebook Valid OAuth Redirect URIs](https://developers.facebook.com/apps/1097389196952441/fb-login/settings/),
you need to add that domain to your 127.0.0.1 line in /etc/hosts. After the change:
```
(venv2) stevepodell@StevesM1Dec2021 WeVoteServer % cat /etc/hosts
##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting. Do not change this entry.
##
127.0.0.1 localhost wevotedeveloper.com
255.255.255.255 broadcasthost
::1 localhost
(venv2) stevepodell@StevesM1Dec2021 WeVoteServer %
```

You will need to elevate your privileges with sudo to make this edit to this linux system file ... ` % sudo vi /etc/hosts` or with some other editor.

Start WebApp with the 'start-https' command, and open WebApp at https://wevotedeveloper.com:3000

Then Facebook signin should work on your dev machine

### Really Really Signing out of Facebook

Facebook takes many simultaneous approaches to prevent an end user from fully signing out of Facebook in a browser.

You will need to take the following steps to completely sign out, with no tendrils of Facebook's signin remaining, to prove that Facebook sign in from a brand new machine or browser will work.
(In a Cordova simulator, simply go to Device/Erase All Content and Settings -- and you will be fully signed out.)

1) Open Facebook in a tab
1) Log out of facebook
2) Using devtools/applications on that Facebook tab...
1) turn off service workers
2) clear "Local Storage"
3) clear "Session Storage"
4) clear Cookies
5) remove anything in the URL bar except "https://www.facebook.com/"
2) In WebApp, sign out
1) Using devtools/applications on the WebApp tab..
1) clear "Local Storage"
2) clear "Session Storage"
3) clear Cookies
2) Hard refresh WebApp Ctrl+Shift+R

Note: All the creative things that Facebook does to keep its hooks in your browser and to try to prevent you from fully logging out, may have left the tab with facebook in it messed-up -- you may need to close it and open another.




---

Expand Down
12 changes: 10 additions & 2 deletions src/js/components/Facebook/FacebookSignIn.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,10 @@ class FacebookSignIn extends Component {
facebook_sign_in_found: facebookSignInFound, facebook_sign_in_verified: facebookSignInVerified,
facebook_secret_key: facebookSecretKey } = this.state.facebookAuthResponse;

// console.log(`FacebookSignIn facebookIsLoggedIn ${facebookIsLoggedIn} facebookSignInFailed: ${facebookSignInFailed} facebookSignInFound: ${facebookSignInFound} facebookSignInVerified: ${facebookSignInVerified}`);

if (facebookIsLoggedIn && !facebookSignInFailed && facebookSignInFound && facebookSignInVerified) {
// console.log('FacebookSignIn setting redirectInProcess: false');
this.setState({ redirectInProcess: false });
oAuthLog('FacebookSignIn calling voterMergeTwoAccountsByFacebookKey, since the voter is authenticated with facebook');
VoterActions.voterMergeTwoAccountsByFacebookKey(facebookSecretKey);
Expand Down Expand Up @@ -219,9 +222,14 @@ class FacebookSignIn extends Component {
renderLog('FacebookSignIn'); // Set LOG_RENDER_EVENTS to log all renders
const { buttonText } = this.props;
const { buttonSubmittedText, facebookAuthResponse, facebookConnectionInitialized, facebookSignInSequenceStarted, mergingTwoAccounts, redirectInProgress, waitingForMergeTwoAccounts } = this.state;
// As of late 2022, Facebook will only allow sign ins from secure (https) connections. This is possible to setup on your local server.
// See the doc file https://github.com/wevote/WebApp/blob/develop/docs/working/SECURE_CERTIFICATE.md
// Preventing a behind the scenes automatic re-login by facebook is difficult...
// See the doc file https://github.com/wevote/WebApp/blob/develop/docs/working/SECURE_CERTIFICATE.md#really-really-signing-out-of-facebook
if (isWebApp() && !facebookConnectionInitialized) {
console.log('FacebookSignIn: Do not offer Facebook button if we aren\'t getting status back');
return null;
// Steve 12/2/22: This "return null" was breaking signing in with facebook in webapp (and Cordova) if you had "never" been signed in before in the browser
// console.log('FacebookSignIn: (disabled) Do not offer Facebook button if we aren\'t getting status back');
// return null; 12/2/22, see note above
}
if (redirectInProgress) {
return null;
Expand Down
5 changes: 2 additions & 3 deletions src/js/components/SignIn/SignInOptionsPanel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import LoadingWheel from '../../common/components/Widgets/LoadingWheel';
import { isAndroid, restoreStylesAfterCordovaKeyboard } from '../../common/utils/cordovaUtils';
import historyPush from '../../common/utils/historyPush';
import { normalizedHref } from '../../common/utils/hrefUtils';
import { isCordova, isWebApp } from '../../common/utils/isCordovaOrWebApp';
import { isWebApp } from '../../common/utils/isCordovaOrWebApp';
import Cookies from '../../common/utils/js-cookie/Cookies';
import { oAuthLog, renderLog } from '../../common/utils/logging';
import stringContains from '../../common/utils/stringContains';
Expand Down Expand Up @@ -90,8 +90,7 @@ export default class SignInOptionsPanel extends Component {
Cookies.remove('sign_in_start_full_url', { path: '/', domain: 'wevote.us' });
}
let pathname = '';
const { hostname } = window.location;
const isOnFacebookSupportedDomainUrl = hostname.replace('www.', '') === 'wevote.us' || hostname === 'quality.wevote.us' || hostname === 'localhost' || isCordova() || window.location.href.includes('ngrok');
const isOnFacebookSupportedDomainUrl = AppObservableStore.isOnFacebookJsSdkHostDomainList(); // hostname.replace('www.', '') === 'wevote.us' || hostname === 'quality.wevote.us' || hostname === 'localhost' || hostname === 'wevotedeveloper.com' || isCordova() || window.location.href.includes('ngrok');

const getStartedMode = AppObservableStore.getStartedMode();
AnalyticsActions.saveActionAccountPage(VoterStore.electionId());
Expand Down
36 changes: 20 additions & 16 deletions src/js/stores/AppObservableStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -518,12 +518,27 @@ export default {
},

isOnWeVoteRootUrl () {
const weVoteURL = nonFluxState.onWeVoteRootUrl || false;
// console.log('AppObservableStore nonFluxState.onWeVoteRootUrl: ', nonFluxState.onWeVoteRootUrl,
// ', isOnWeVoteRootUrl weVoteURL: ', weVoteURL,
// ', isCordovaLocal(): ', isCordovaLocal(),
// ', is localhost: ', stringContains('localhost:', window.location.href));
return weVoteURL || isCordovaLocal() || stringContains('localhost:', window.location.href) || stringContains('ngrok.io', window.location.href);

const { location: { href: localhost } } = window;

return (nonFluxState.onWeVoteRootUrl || false) ||
isCordovaLocal() ||
stringContains('wevote.us:', localhost) ||
stringContains('wevote.org:', localhost) || // includes quality.wevote.us
stringContains('localhost:', localhost) ||
stringContains('wevotedeveloper.com:', localhost) ||
stringContains('ngrok.io', localhost);
},

isOnFacebookJsSdkHostDomainList () {
const { hostname } = window.location;
const host = hostname.replace('www.', '');
// console.log('----------------------', hostname);
return host === 'wevote.us' || host === 'quality.wevote.us' || host === 'localhost' || host === 'wevotedeveloper.com' || isCordovaLocal() || window.location.href.includes('ngrok');
},

isOnWeVoteSubdomainUrl () {
Expand Down Expand Up @@ -677,24 +692,13 @@ export default {
}

// console.log('AppObservableStore siteConfigurationRetrieve hostname, newHostname:', hostname, newHostname);
if (newHostname === 'localhost' ||
newHostname === 'quality.wevote.us' ||
newHostname === 'wevote.org' ||
newHostname === 'wevote.us') {
onWeVoteRootUrl = true;
} else if (stringContains('wevote.us', newHostname)) {
onWeVoteRootUrl = this.isOnWeVoteRootUrl();
if (stringContains('wevote.us', newHostname)) {
onWeVoteSubdomainUrl = true;
} else {
onChosenFullDomainUrl = true;
}
// May 2021: This code doesn't need an API call to generate an answer, abandoning querying the store to get the answer
if (newHostname === 'localhost' ||
newHostname === 'quality.wevote.us' ||
newHostname === 'wevote.org' ||
newHostname === 'wevote.us' ||
isCordovaLocal()) {
onFacebookSupportedDomainUrl = true;
}
onFacebookSupportedDomainUrl = this.isOnFacebookJsSdkHostDomainList();
// console.log('AppObservableStore siteConfigurationRetrieve onFacebookSupportedDomainUrl:', onFacebookSupportedDomainUrl);
// console.log('AppObservableStore externalVoterId:', externalVoterId, ', siteOwnerOrganizationWeVoteId:', siteOwnerOrganizationWeVoteId);
const { voterExternalIdHasBeenSavedOnce } = nonFluxState;
Expand Down
2 changes: 1 addition & 1 deletion src/js/stores/FacebookStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ class FacebookStore extends ReduceStore {
if (action.res.minimum_data_saved) {
// Only reach out for the Facebook Sign In information if the save_profile_data call has completed
// TODO: We need a check here to prevent an infinite loop if the local voter_device_id isn't recognized by server
// console.log("FacebookStore voterFacebookSignInSave, voter exists");
// console.log('FacebookStore voterFacebookSignInSave, voter exists');
FacebookActions.voterFacebookSignInRetrieve();
}

Expand Down
1 change: 1 addition & 0 deletions webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ module.exports = (env, argv) => ({
] : []),
],
devServer: {
allowedHosts: 'all',
static: {
directory: path.join(__dirname, './build'),
},
Expand Down

0 comments on commit 8c1a0e3

Please sign in to comment.