From e82146d52fd725734e6883f761c96ce592279f71 Mon Sep 17 00:00:00 2001 From: Daniel Schalla Date: Wed, 20 Feb 2019 17:06:03 +0100 Subject: [PATCH] [MM-10346] Set CSRF Token from Cookie after Login / on App load (#2534) * Set CSRF Token from Cookie after Login / on App load * Reset CSRF on Logout * Simplify cookie value access * Make Set CSRF Blocking --- app/actions/views/login.js | 2 ++ app/actions/views/login.test.js | 15 +++++++++++++++ app/app.js | 2 ++ app/mattermost.js | 1 + app/utils/security.js | 18 ++++++++++++++++++ 5 files changed, 38 insertions(+) create mode 100644 app/utils/security.js diff --git a/app/actions/views/login.js b/app/actions/views/login.js index 3f3915bfc..0ea69dc48 100644 --- a/app/actions/views/login.js +++ b/app/actions/views/login.js @@ -13,6 +13,7 @@ import {ViewTypes} from 'app/constants'; import {app} from 'app/mattermost'; import PushNotifications from 'app/push_notifications'; import {getDeviceTimezone, isTimezoneEnabled} from 'app/utils/timezone'; +import {setCSRFFromCookie} from 'app/utils/security'; export function handleLoginIdChanged(loginId) { return async (dispatch, getState) => { @@ -42,6 +43,7 @@ export function handleSuccessfulLogin() { const deviceToken = state.entities.general.deviceToken; const currentUserId = getCurrentUserId(state); + await setCSRFFromCookie(url); app.setAppCredentials(deviceToken, currentUserId, token, url); const enableTimezone = isTimezoneEnabled(state); diff --git a/app/actions/views/login.test.js b/app/actions/views/login.test.js index 062f3683b..66020d79c 100644 --- a/app/actions/views/login.test.js +++ b/app/actions/views/login.test.js @@ -17,6 +17,21 @@ jest.mock('app/mattermost', () => ({ }, })); +jest.mock('react-native-cookies', () => ({ + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + openURL: jest.fn(), + canOpenURL: jest.fn(), + getInitialURL: jest.fn(), + get: () => Promise.resolve(({ + res: { + MMCSRF: { + value: 'the cookie', + }, + }, + })), +})); + const mockStore = configureStore([thunk]); describe('Actions.Views.Login', () => { diff --git a/app/app.js b/app/app.js index c66f2e7df..35b648bf3 100644 --- a/app/app.js +++ b/app/app.js @@ -17,6 +17,7 @@ import {getCurrentLocale} from 'app/selectors/i18n'; import {getTranslations as getLocalTranslations} from 'app/i18n'; import {store, handleManagedConfig} from 'app/mattermost'; import avoidNativeBridge from 'app/utils/avoid_native_bridge'; +import {setCSRFFromCookie} from 'utils/security'; const {Initialization} = NativeModules; @@ -138,6 +139,7 @@ export default class App { this.url = url; Client4.setUrl(url); Client4.setToken(token); + await setCSRFFromCookie(url); } else { this.waitForRehydration = true; } diff --git a/app/mattermost.js b/app/mattermost.js index e09612109..acc650a90 100644 --- a/app/mattermost.js +++ b/app/mattermost.js @@ -138,6 +138,7 @@ const handleLogout = () => { // the Client online flag to true cause the network handler // is not available at this point Client4.setOnline(true); + Client4.setCSRF(null); store.dispatch(closeWebSocket(false)); app.setAppStarted(true); diff --git a/app/utils/security.js b/app/utils/security.js new file mode 100644 index 000000000..0041d06c2 --- /dev/null +++ b/app/utils/security.js @@ -0,0 +1,18 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {Client4} from 'mattermost-redux/client'; +import CookieManager from 'react-native-cookies'; +import urlParse from 'url-parse'; + +export function setCSRFFromCookie(url) { + return new Promise((resolve) => { + CookieManager.get(urlParse(url).origin, false).then((res) => { + const token = res.MMCSRF; + if (token) { + Client4.setCSRF(token?.value || token); + } + resolve(); + }); + }); +}