diff --git a/docs/working/SECURE_CERTIFICATE.md b/docs/working/SECURE_CERTIFICATE.md
index b0d4fb849..78505994f 100644
--- a/docs/working/SECURE_CERTIFICATE.md
+++ b/docs/working/SECURE_CERTIFICATE.md
@@ -38,12 +38,17 @@ In WebApp/src/js/config.js, set SECURE_CERTIFICATE_INSTALLED to true, and then u
WebApp will startup at http://localhost:3000
-## Signing in with Facebook on your dev machine
+## Signing in with Facebook and Twitter on your dev machine
### Make a small necessary change to your /etc/hosts
Facebook will no longer redirect to localhost, so we make a second alias for 127.0.0.1 with this specific made up
domain: `wevotedeveloper.com` by running the following command in a terminal:
+This `wevotedeveloper.com` is also needed to debug "Sign in with Twitter" while using the `wevotedeveloper.com` domain for your local Python API server.
+NOTE: As of March 2024, Chrome stopped responding to this domain (possibly since it can't match it with a public DNS lookup), so you will have to debug this setup with Safari.
+Safari has a version of Devtools called "Web Inspector" that you get to by right-clicking in the tab, and clicking "Inspect Element". Devtools and Web
+Inspector share the Chromium code base and have almost identical capabilities.
+
`sudo node node/updateHosts.js`
The run will look like this
diff --git a/src/App.jsx b/src/App.jsx
index 296359fb8..2efd8333f 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -566,6 +566,7 @@ class App extends Component {
+
} />
diff --git a/src/js/actions/TwitterActions.js b/src/js/actions/TwitterActions.js
index 43270c2de..b876935eb 100644
--- a/src/js/actions/TwitterActions.js
+++ b/src/js/actions/TwitterActions.js
@@ -20,14 +20,6 @@ export default {
});
},
- twitterNativeSignInSave (twitterAccessToken, twitterAccessTokenSecret) {
- Dispatcher.loadEndpoint('twitterNativeSignInSave',
- {
- twitter_access_token: twitterAccessToken,
- twitter_access_token_secret: twitterAccessTokenSecret,
- });
- },
-
twitterProcessDeferredImages (twitterImageLoadInfo) {
Dispatcher.loadEndpoint('twitterProcessDeferredImages', {
status: twitterImageLoadInfo.status,
@@ -54,4 +46,13 @@ export default {
});
},
+ twitterOauth1UserHandler (oauthToken, oauthVerifier) { // For twitter V2 API, March 2024
+ // console.log('twitterOauth1UserHandler: ', oauthToken, oauthVerifier);
+ Dispatcher.loadEndpoint('twitterOauth1UserHandler',
+ {
+ oauth_token: oauthToken,
+ oauth_verifier: oauthVerifier,
+ });
+ },
+
};
diff --git a/src/js/components/Twitter/TwitterSignIn.jsx b/src/js/components/Twitter/TwitterSignIn.jsx
index a4d2e8fcb..0690de309 100644
--- a/src/js/components/Twitter/TwitterSignIn.jsx
+++ b/src/js/components/Twitter/TwitterSignIn.jsx
@@ -83,6 +83,7 @@ class TwitterSignIn extends Component {
twitterSignInCrash: false,
twitterSignInStartSubmitted: false,
};
+ oAuthLog(`twitterSignIn redirect url = ${returnURL}`);
}
componentDidMount () {
diff --git a/src/js/config - wevotedeveloper SSL Web and local API.js b/src/js/config - wevotedeveloper SSL Web and local API.js
new file mode 100644
index 000000000..22c2be447
--- /dev/null
+++ b/src/js/config - wevotedeveloper SSL Web and local API.js
@@ -0,0 +1,53 @@
+/* eslint-disable */
+// Note that we import these values where needed as "webAppConfig"
+module.exports = {
+ WE_VOTE_URL_PROTOCOL: 'https://', // "http://" for local dev or "https://" for live server
+ WE_VOTE_HOSTNAME: 'wevotedeveloper.com:3000', // This should be without "http...". This is "WeVote.US" on live server.
+ WE_VOTE_IMAGE_PATH_FOR_CORDOVA: 'https://wevote.us', // If you are not working with Cordova, you don't need to change this
+ SECURE_CERTIFICATE_INSTALLED: false,
+
+ WE_VOTE_SERVER_ROOT_URL: 'https://wevotedeveloper.com:8000/',
+ WE_VOTE_SERVER_ADMIN_ROOT_URL: 'https://wevotedeveloper.com:8000/admin/',
+ WE_VOTE_SERVER_API_ROOT_URL: 'https://wevotedeveloper.com:8000/apis/v1/',
+ WE_VOTE_SERVER_API_CDN_ROOT_URL: 'https://wevotedeveloper.com:8000/apis/v1/',
+
+ ENABLE_NEXT_RELEASE_FEATURES: false,
+ ENABLE_WORKBOX_SERVICE_WORKER: false, // After setting this false, recompile, then in Chrome DevTools go to Application Tab, Application/Service Worker and for the sw.js click the "unregister" button to the right
+
+ DEBUG_MODE: false,
+ SHOW_TEST_OPTIONS: false, // On the DeviceDialog
+
+ LOG_RENDER_EVENTS: false,
+ LOG_ONLY_FIRST_RENDER_EVENTS: false,
+ LOG_HTTP_REQUESTS: false,
+ LOG_ROUTING: false,
+ LOG_SIGNIN_STEPS: false,
+ LOG_CORDOVA_OFFSETS: false,
+ SHOW_CORDOVA_URL_FIELD: false, // Only needed for debugging in Cordova
+
+ // Use 1 or 0 as opposed to true or false
+ test: {
+ use_test_election: 0,
+ },
+
+ location: {
+ text_for_map_search: '',
+ },
+
+ ENABLE_FACEBOOK: false,
+ ENABLE_TWITTER: true,
+ ENABLE_PAY_TO_PROMOTE: false,
+
+ // API Keys, some of these are publishable (not secret)
+ FACEBOOK_APP_ID: "1097389196952441",
+ FULL_STORY_ORG: '',
+ GOOGLE_ADS_TRACKING_ID: 'T',
+ GOOGLE_ANALYTICS_TRACKING_ID: '',
+ GOOGLE_MAPS_API_KEY: '',
+ GOOGLE_PEOPLE_API_KEY: '',
+ GOOGLE_PEOPLE_API_CLIENT_ID: '',
+ GOOGLE_RECAPTCHA_KEY: '',
+ OPEN_REPLAY_PROJECT_KEY: '',
+ OPEN_REPLAY_INGEST_POINT: 'https://openreplay.wevote.us/ingest',
+ STRIPE_API_KEY: "",
+};
diff --git a/src/js/pages/Process/TwitterSignInProcess.jsx b/src/js/pages/Process/TwitterSignInProcess.jsx
index 63439598d..77d53ff3f 100644
--- a/src/js/pages/Process/TwitterSignInProcess.jsx
+++ b/src/js/pages/Process/TwitterSignInProcess.jsx
@@ -26,15 +26,30 @@ export default class TwitterSignInProcess extends Component {
savingAccount: false,
redirectInProgress: false,
twitterAuthResponse: {},
+ redirectCount: 0,
};
+ this.twitterOauthLeg3 = this.twitterOauthLeg3.bind(this);
}
componentDidMount () {
+ // console.log('--------------- TwitterSignInProcess componentDidMount');
this.appStateSubscription = messageService.getMessage().subscribe(() => this.onAppObservableStoreChange());
this.twitterStoreListener = TwitterStore.addListener(this.onTwitterStoreChange.bind(this));
this.voterStoreListener = VoterStore.addListener(this.onVoterStoreChange.bind(this));
- this.twitterSignInRetrieve();
window.scrollTo(0, 0);
+ this.twitterSignInRetrieve();
+ const { location: { search } } = this.props;
+ const { redirectCount } = this.state;
+ oAuthLog('TwitterSignInProcess search props: ', search);
+ const urlParams = new URLSearchParams(search);
+ const oauthToken = urlParams.get('oauth_token');
+ const oauthVerifier = urlParams.get('oauth_verifier');
+ if (oauthToken && oauthVerifier && redirectCount === 0) {
+ oAuthLog('TwitterSignInProcess received redirect from Twitter redirectCount: ', redirectCount, ', oauthToken: ', oauthToken, ', oauthVerifier: ', oauthVerifier);
+ this.setState({ redirectCount: (redirectCount + 1) });
+ TwitterActions.twitterOauth1UserHandler(oauthToken, oauthVerifier);
+ this.twitterSignInRetrieve();
+ }
}
componentWillUnmount () {
@@ -54,7 +69,10 @@ export default class TwitterSignInProcess extends Component {
const { mergingTwoAccounts, savingAccount } = this.state;
console.log('TwitterSignInProcess onTwitterStoreChange, twitterAuthResponse:', twitterAuthResponse);
- if (twitterAuthResponse.twitter_sign_in_failed) {
+ if (twitterAuthResponse.twitter_sign_in_failed === undefined && twitterAuthResponse.twitter_oauth_voter_info_stored_in_db) {
+ oAuthLog('Twitter sign undefined, but oauth_voter_info_stored_in_db - calling twitterSignInRetrieve()');
+ this.twitterSignInRetrieve();
+ } else if (twitterAuthResponse.twitter_sign_in_failed) {
oAuthLog('Twitter sign in failed - push to /settings/account');
historyPush({
pathname: '/settings/account', // SnackNotifier that handles this is in SettingsDashboard
@@ -191,9 +209,17 @@ export default class TwitterSignInProcess extends Component {
}
twitterSignInRetrieve () {
+ oAuthLog('Twitter twitterSignInRetrieve on TwitterSignInProcess component mount');
TwitterActions.twitterSignInRetrieve();
}
+ twitterOauthLeg3 (oauthToken, oauthVerifier) {
+ const { redirectCount } = this.state;
+ oAuthLog('TwitterSignInProcess received redirect from Twitter redirectCount: ', redirectCount, ', oauthToken: ', oauthToken, ', oauthVerifier: ', oauthVerifier);
+ this.setState({ redirectCount: (redirectCount + 1) });
+ TwitterActions.twitterOauth1UserHandler(oauthToken, oauthVerifier);
+ }
+
render () {
renderLog('TwitterSignInProcess'); // Set LOG_RENDER_EVENTS to log all renders
const { redirectInProgress, twitterAuthResponse } = this.state;
diff --git a/src/js/stores/BallotStore.js b/src/js/stores/BallotStore.js
index fb106099d..43dc17f78 100644
--- a/src/js/stores/BallotStore.js
+++ b/src/js/stores/BallotStore.js
@@ -879,7 +879,6 @@ class BallotStore extends ReduceStore {
BallotActions.voterBallotItemsRetrieve();
return this.resetState();
- case 'twitterNativeSignInSave':
case 'twitterSignInRetrieve':
case 'voterEmailAddressSignIn':
case 'voterFacebookSignInRetrieve':
diff --git a/src/js/stores/FriendStore.js b/src/js/stores/FriendStore.js
index 7bdbec4d7..685a55db1 100644
--- a/src/js/stores/FriendStore.js
+++ b/src/js/stores/FriendStore.js
@@ -439,7 +439,6 @@ class FriendStore extends ReduceStore {
currentFriendsOrganizationWeVoteIds,
};
- case 'twitterNativeSignInSave':
case 'twitterSignInRetrieve':
case 'voterEmailAddressSignIn':
case 'voterFacebookSignInRetrieve':
diff --git a/src/js/stores/IssueStore.js b/src/js/stores/IssueStore.js
index fe34cfc91..d92b81d7e 100644
--- a/src/js/stores/IssueStore.js
+++ b/src/js/stores/IssueStore.js
@@ -966,7 +966,6 @@ class IssueStore extends ReduceStore {
issueWeVoteIdsUnderEachBallotItem,
organizationWeVoteIdsLinkedToIssueDict,
};
- case 'twitterNativeSignInSave':
case 'twitterSignInRetrieve':
case 'voterEmailAddressSignIn':
case 'voterFacebookSignInRetrieve':
diff --git a/src/js/stores/OrganizationStore.js b/src/js/stores/OrganizationStore.js
index 5ce96edd8..1a72ced23 100644
--- a/src/js/stores/OrganizationStore.js
+++ b/src/js/stores/OrganizationStore.js
@@ -1006,7 +1006,6 @@ class OrganizationStore extends ReduceStore {
organizationWeVoteIdsVoterIsIgnoring,
};
- case 'twitterNativeSignInSave':
case 'twitterSignInRetrieve':
case 'voterEmailAddressSignIn':
case 'voterFacebookSignInRetrieve':
diff --git a/src/js/stores/SupportStore.js b/src/js/stores/SupportStore.js
index a9a705d07..c045f8231 100644
--- a/src/js/stores/SupportStore.js
+++ b/src/js/stores/SupportStore.js
@@ -234,7 +234,6 @@ class SupportStore extends ReduceStore {
SupportActions.voterAllPositionsRetrieve();
return this.resetState();
- case 'twitterNativeSignInSave':
case 'twitterSignInRetrieve':
case 'voterEmailAddressSignIn':
case 'voterFacebookSignInRetrieve':
diff --git a/src/js/stores/TwitterStore.js b/src/js/stores/TwitterStore.js
index 6feefb619..933c5e2be 100644
--- a/src/js/stores/TwitterStore.js
+++ b/src/js/stores/TwitterStore.js
@@ -1,15 +1,15 @@
import { ReduceStore } from 'flux/utils';
import CandidateActions from '../actions/CandidateActions';
import OrganizationActions from '../actions/OrganizationActions';
-import TwitterActions from '../actions/TwitterActions';
import VoterActions from '../actions/VoterActions';
import Dispatcher from '../common/dispatcher/Dispatcher';
class TwitterStore extends ReduceStore {
getInitialState () {
- // return {
- // success: true,
- // };
+ return {
+ twitter_store_initialized: true,
+ twitter_oauth_voter_info_stored_in_db: false,
+ };
}
get () {
@@ -101,6 +101,7 @@ class TwitterStore extends ReduceStore {
existing_twitter_account_found: this.getState().existing_twitter_account_found,
voter_we_vote_id_attached_to_twitter: this.getState().voter_we_vote_id_attached_to_twitter,
twitter_image_load_info: this.getState().twitter_image_load_info,
+ twitter_oauth_voter_info_stored_in_db: this.getState().twitter_oauth_voter_info_stored_in_db,
};
}
@@ -156,21 +157,6 @@ class TwitterStore extends ReduceStore {
status: action.res.status,
};
- case 'twitterNativeSignInSave':
- // Exit if we don't have a successful response (since we expect certain variables in a successful response below)
- if (!action.res || !action.res.success) return state;
- if (action.res.success) {
- TwitterActions.twitterSignInRetrieve();
- }
-
- return {
- // ...state,
- voter_device_id: action.res.voter_device_id,
- twitter_handle: action.res.twitter_handle,
- twitter_handle_found: action.res.twitter_handle_found,
- twitter_secret_key: action.res.twitter_secret_key,
- };
-
case 'twitterProcessDeferredImages':
if (!action.res || !action.res.success) return state;
// console.log('twitter twitterProcessDeferredImages', action.res);
@@ -183,10 +169,12 @@ class TwitterStore extends ReduceStore {
we_vote_hosted_profile_image_url_tiny: action.res.we_vote_hosted_profile_image_url_tiny,
};
-
case 'twitterSignInRetrieve':
- // Exit if we don't have a successful response (since we expect certain variables in a successful response below)
- if (!action.res || !action.res.success) return state;
+ // console.log('twitterSignInRetrieve in TwitterStore received: ', action.res);
+ if (!action.res || !action.res.success) {
+ // Exit if we don't have a successful response (since we expect certain variables in a successful response below)
+ return state;
+ }
if (action.res.twitter_sign_in_verified) {
VoterActions.voterRetrieve();
VoterActions.twitterRetrieveIdsIfollow();
@@ -217,10 +205,16 @@ class TwitterStore extends ReduceStore {
// return this.resetState();
return this.resetVoterSpecificData();
- default:
+ case 'twitterOauth1UserHandler':
+ if (!action.res || !action.res.success) return state;
+ console.log('twitterOauth1UserHandler res: ', action.res);
return {
...state,
+ twitter_oauth_voter_info_stored_in_db: true,
};
+
+ default:
+ return state;
}
}
}
diff --git a/src/js/stores/VoterGuideStore.js b/src/js/stores/VoterGuideStore.js
index 9a054d4b8..26ed83aff 100644
--- a/src/js/stores/VoterGuideStore.js
+++ b/src/js/stores/VoterGuideStore.js
@@ -868,7 +868,6 @@ class VoterGuideStore extends ReduceStore {
organizationWeVoteIdsToFollowForLatestBallotItem: state.organizationWeVoteIdsToFollowForLatestBallotItem.filter((existingOrgWeVoteId) => existingOrgWeVoteId !== organizationWeVoteId),
};
- case 'twitterNativeSignInSave':
case 'twitterSignInRetrieve':
case 'voterEmailAddressSignIn':
case 'voterFacebookSignInRetrieve':