Compare commits

...

12 Commits

Author SHA1 Message Date
Mattermost Build
41848b2634 Bump app build number to 307 (#4503)
Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
2020-06-26 22:04:54 -04:00
Mattermost Build
8d81d946c5 Automated cherry pick of #4499 (#4501)
* Revert updated dependecies for SSO

* Fix test setup

Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
2020-06-26 21:58:26 -04:00
Mattermost Build
10d27ee5ba Fix SSO login with subpaths (#4495)
Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
2020-06-26 16:47:40 -04:00
Elias Nahum
647def15be Bump Version to 1.32.2 and Build number to 306 (#4494)
* Bump app version number to 1.32.2

* Bump app build number to 306
2020-06-26 16:45:23 -04:00
Mattermost Build
da440e50fb Automated cherry pick of #4489 (#4492)
* Avoid throwing when purging

* Update app/store/index.ts

Co-authored-by: Miguel Alatzar <migbot@users.noreply.github.com>

Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
Co-authored-by: Miguel Alatzar <migbot@users.noreply.github.com>
2020-06-26 16:20:17 -04:00
Miguel Alatzar
793ac98d74 Bump build number to 305 (#4477) 2020-06-23 18:50:25 -07:00
Mattermost Build
fab353b494 Various fixes: (#4475)
* Fix map call on Set
* Ensure we don't destructure non-iterable values
* Include error message and stack in Alert

Co-authored-by: Miguel Alatzar <this.migbot@gmail.com>
2020-06-23 16:50:37 -07:00
Miguel Alatzar
8853b5dd45 Bump app build number to 304 (#4468) 2020-06-22 15:38:45 -07:00
Mattermost Build
464d93df8d Various fixes: (#4466)
* Dispatch REHYDRATED if already hydrated after getStoredState call
* Empty/null prev version is valid
* Update iOS target to 11.0

Co-authored-by: Miguel Alatzar <this.migbot@gmail.com>
2020-06-22 15:31:27 -07:00
Miguel Alatzar
47f126b71f Bump build number (#4459) 2020-06-19 16:53:27 -07:00
Miguel Alatzar
4b2a0c7aea Bump version number (#4458) 2020-06-19 16:45:07 -07:00
Mattermost Build
f6bedbb7d6 Automated cherry pick of #4452 (#4456)
* Remove withEncryption

* Remove warm up

* Downgrade react-native-keychain

Co-authored-by: Miguel Alatzar <this.migbot@gmail.com>
2020-06-19 16:19:31 -07:00
21 changed files with 3341 additions and 7357 deletions

View File

@@ -133,8 +133,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
missingDimensionStrategy "RNNotifications.reactNativeVersion", "reactNative60"
versionCode 302
versionName "1.32.0"
versionCode 307
versionName "1.32.2"
multiDexEnabled = true
ndk {
abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64'

View File

@@ -36,12 +36,7 @@ public class MattermostCredentialsHelper {
HashMap<String, String> asyncStorageResults = asyncStorage.multiGet(asyncStorageKeys);
String serverUrl = asyncStorageResults.get(CURRENT_SERVER_URL);
final WritableMap options = Arguments.createMap();
final WritableMap authPrompt = Arguments.createMap();
authPrompt.putString("title", "Authenticate to retrieve secret");
authPrompt.putString("cancel", "Cancel");
options.putMap("authenticationPrompt", authPrompt);
keychainModule.getInternetCredentialsForServer(serverUrl, options, promise);
keychainModule.getGenericPasswordForOptions(serverUrl, promise);
}
}

View File

@@ -55,7 +55,7 @@ export function getEmojisInPosts(posts) {
const emojisToLoad = getNeededCustomEmojis(state, posts);
if (emojisToLoad?.size > 0) {
const promises = emojisToLoad.map((name) => getCustomEmojiByName(name));
const promises = Array.from(emojisToLoad).map((name) => getCustomEmojiByName(name));
const result = await Promise.all(promises);
const actions = [];
const data = [];

View File

@@ -3,7 +3,7 @@
import {Alert, AppState, Dimensions, Linking, NativeModules, Platform} from 'react-native';
import AsyncStorage from '@react-native-community/async-storage';
import CookieManager from '@react-native-community/cookies';
import CookieManager from 'react-native-cookies';
import DeviceInfo from 'react-native-device-info';
import {getLocales} from 'react-native-localize';
import RNFetchBlob from 'rn-fetch-blob';

View File

@@ -885,7 +885,7 @@ export const getDefaultChannelForTeams: (a: GlobalState) => RelationOneToOne<Tea
});
export const getMyFirstChannelForTeams: (a: GlobalState) => RelationOneToOne<Team, Channel> = createSelector(getAllChannels, getMyChannelMemberships, getMyTeams, getCurrentUser, (allChannels: IDMappedObjects<Channel>, myChannelMemberships: RelationOneToOne<Channel, ChannelMembership>, myTeams: Array<Team>, currentUser: UserProfile): RelationOneToOne<Team, Channel> => {
const locale = currentUser.locale || General.DEFAULT_LOCALE;
const locale = currentUser?.locale || General.DEFAULT_LOCALE;
const result: RelationOneToOne<Team, Channel> = {};
for (const team of myTeams) {

View File

@@ -10,7 +10,7 @@ import {
Platform,
} from 'react-native';
import {WebView} from 'react-native-webview';
import CookieManager from '@react-native-community/cookies';
import CookieManager from 'react-native-cookies';
import urlParse from 'url-parse';
import {Client4} from '@mm-redux/client';
@@ -27,7 +27,7 @@ const HEADERS = {
'X-Mobile-App': 'mattermost',
};
const postMessageJS = 'window.ReactNativeWebView.postMessage(document.body.innerText);';
const postMessageJS = "window.postMessage(document.body.innerText, '*');";
// Used to make sure that OneLogin forms scale appropriately on both platforms.
const oneLoginFormScalingJS = `
@@ -109,7 +109,15 @@ class SSO extends PureComponent {
}
extractCookie = (parsedUrl) => {
CookieManager.get(parsedUrl.origin, true).then((res) => {
const original = urlParse(this.props.serverUrl);
// Check whether we need to set a sub-path
parsedUrl.set('pathname', original.pathname || '');
parsedUrl.set('query', '');
Client4.setUrl(parsedUrl.href);
CookieManager.get(parsedUrl.href, true).then((res) => {
const mmtoken = res.MMAUTHTOKEN;
const token = typeof mmtoken === 'object' ? mmtoken.value : mmtoken;
@@ -121,13 +129,6 @@ class SSO extends PureComponent {
} = this.props.actions;
Client4.setToken(token);
if (this.props.serverUrl !== parsedUrl.origin) {
const original = urlParse(this.props.serverUrl);
// Check whether we need to set a sub-path
parsedUrl.set('pathname', original.pathname || '');
Client4.setUrl(parsedUrl.href);
}
ssoLogin(token).then((result) => {
if (result.error) {
this.onLoadEndError(result.error);
@@ -239,17 +240,16 @@ class SSO extends PureComponent {
<WebView
ref={this.webViewRef}
source={{uri: this.loginUrl, headers: HEADERS}}
javaScriptEnabled={true}
javaScriptEnabledAndroid={true}
automaticallyAdjustContentInsets={false}
startInLoadingState={true}
onNavigationStateChange={this.onNavigationStateChange}
onShouldStartLoadWithRequest={() => true}
injectedJavaScript={jsCode}
onLoadEnd={this.onLoadEnd}
onMessage={(messagingEnabled || Platform.OS === 'android') ? this.onMessage : null}
sharedCookiesEnabled={Platform.OS === 'android'}
onMessage={messagingEnabled ? this.onMessage : null}
useSharedProcessPool={true}
cacheEnabled={false}
useSharedProcessPool={false}
/>
);
}

View File

@@ -187,7 +187,9 @@ export default function configureStore(storage: any, preloadedState: any = {}, o
const rootReducer: any = (state: GlobalState, action: GenericAction) => {
if (action.type === General.OFFLINE_STORE_PURGE) {
// eslint-disable-next-line no-underscore-dangle
delete action.data._persist;
if (action.data?._persist) {
delete action?.data?._persist;
}
return baseReducer(action.data, action as any);
}
return baseReducer(state as any, action as any);
@@ -230,7 +232,7 @@ export default function configureStore(storage: any, preloadedState: any = {}, o
store.dispatch({
type: General.OFFLINE_STORE_PURGE,
state,
data: state,
});
console.log('HYDRATED FROM v4', storeKeys); // eslint-disable-line no-console
@@ -240,6 +242,8 @@ export default function configureStore(storage: any, preloadedState: any = {}, o
});
store.dispatch({type: General.REHYDRATED});
AsyncStorage.multiRemove(storeKeys);
} else if (store.getState()._persist?.rehydrated) { // eslint-disable-line no-underscore-dangle
store.dispatch({type: General.REHYDRATED});
} else {
let executed = false;
const unsubscribe = store.subscribe(() => {

View File

@@ -31,9 +31,9 @@ export function cleanUpState(payload, keepCurrent = false) {
postsInChannel: {},
postsInThread: {},
reactions: {},
openGraph: payload.entities.posts.openGraph,
selectedPostId: payload.entities.posts.selectedPostId,
currentFocusedPostId: payload.entities.posts.currentFocusedPostId,
openGraph: payload.entities?.posts?.openGraph,
selectedPostId: payload.entities?.posts?.selectedPostId,
currentFocusedPostId: payload.entities?.posts?.currentFocusedPostId,
},
files: {
files: {},
@@ -42,21 +42,20 @@ export function cleanUpState(payload, keepCurrent = false) {
};
let retentionPeriod = 0;
if (payload.entities.general && payload.entities.general.dataRetentionPolicy &&
payload.entities.general.dataRetentionPolicy.message_deletion_enabled) {
if (payload.entities?.general?.dataRetentionPolicy?.message_deletion_enabled) {
retentionPeriod = payload.entities.general.dataRetentionPolicy.message_retention_cutoff;
}
const postIdsToKeep = [];
// Keep the last 60 posts in each recently viewed channel
nextEntities.posts.postsInChannel = cleanUpPostsInChannel(payload.entities.posts.postsInChannel, lastChannelForTeam, keepCurrent ? currentChannelId : '');
nextEntities.posts.postsInChannel = cleanUpPostsInChannel(payload.entities.posts?.postsInChannel, lastChannelForTeam, keepCurrent ? currentChannelId : '');
postIdsToKeep.push(...getAllFromPostsInChannel(nextEntities.posts.postsInChannel));
// Keep any posts that appear in search results
let searchResults = [];
let flaggedPosts = [];
if (payload.entities.search) {
if (payload.entities?.search) {
if (payload.entities.search.results?.length) {
const {results} = payload.entities.search;
searchResults = results;
@@ -71,50 +70,57 @@ export function cleanUpState(payload, keepCurrent = false) {
}
const nextSearch = {
...payload.entities.search,
...(payload.entities.search || {}),
results: searchResults,
flagged: flaggedPosts,
};
postIdsToKeep.forEach((postId) => {
const post = payload.entities.posts.posts[postId];
if (payload.entities.posts?.posts) {
const reactions = payload.entities.posts.reactions || {};
const fileIdsByPostId = payload.entities.files?.fileIdsByPostId || {};
const files = payload.entities.files?.files || {};
const postsInThread = payload.entities.posts.postsInThread || {};
if (post) {
if (retentionPeriod && post.create_at < retentionPeriod) {
// This post has been removed by data retention, so don't keep it
removeFromPostsInChannel(nextEntities.posts.postsInChannel, post.channel_id, postId);
postIdsToKeep.forEach((postId) => {
const post = payload.entities.posts.posts[postId];
return;
if (post) {
if (retentionPeriod && post.create_at < retentionPeriod) {
// This post has been removed by data retention, so don't keep it
removeFromPostsInChannel(nextEntities.posts.postsInChannel, post.channel_id, postId);
return;
}
// Keep the post
nextEntities.posts.posts[postId] = post;
// And its reactions
const reaction = reactions[postId];
if (reaction) {
nextEntities.posts.reactions[postId] = reaction;
}
// And its files
const fileIds = fileIdsByPostId[postId];
if (fileIds) {
nextEntities.files.fileIdsByPostId[postId] = fileIds;
fileIds.forEach((fileId) => {
nextEntities.files.files[fileId] = files[fileId];
});
}
// And its comments
const threadPosts = postsInThread[postId];
if (threadPosts) {
nextEntities.posts.postsInThread[postId] = threadPosts;
}
}
// Keep the post
nextEntities.posts.posts[postId] = post;
// And its reactions
const reaction = payload.entities.posts.reactions[postId];
if (reaction) {
nextEntities.posts.reactions[postId] = reaction;
}
// And its files
const fileIds = payload.entities.files.fileIdsByPostId[postId];
if (fileIds) {
nextEntities.files.fileIdsByPostId[postId] = fileIds;
fileIds.forEach((fileId) => {
nextEntities.files.files[fileId] = payload.entities.files.files[fileId];
});
}
// And its comments
const postsInThread = payload.entities.posts.postsInThread[postId];
if (postsInThread) {
nextEntities.posts.postsInThread[postId] = postsInThread;
}
}
});
});
}
// Remove any pending posts that haven't failed
if (payload.entities.posts && payload.entities.posts.pendingPostIds && payload.entities.posts.pendingPostIds.length) {
if (payload.entities.posts?.pendingPostIds?.length) {
const nextPendingPostIds = [...payload.entities.posts.pendingPostIds];
payload.entities.posts.pendingPostIds.forEach((id) => {
const posts = nextEntities.posts.posts;
@@ -135,9 +141,9 @@ export function cleanUpState(payload, keepCurrent = false) {
}
nextState.views = {
...nextState.views,
...(nextState.views || {}),
root: {
...nextState.views?.root,
...(nextState.views?.root || {}),
// eslint-disable-next-line no-underscore-dangle
hydrationComplete: nextState.views?.root?.hydrationComplete || !nextState._persist,
},
@@ -161,41 +167,43 @@ export function cleanUpState(payload, keepCurrent = false) {
export function cleanUpPostsInChannel(postsInChannel, lastChannelForTeam, currentChannelId, recentPostCount = 60) {
const nextPostsInChannel = {};
for (const channelIds of Object.values(lastChannelForTeam)) {
for (const channelId of channelIds) {
if (nextPostsInChannel[channelId]) {
// This is a DM or GM channel that we've already seen on another team
continue;
}
const postsForChannel = postsInChannel[channelId];
if (!postsForChannel) {
// We don't have anything to keep for this channel
continue;
}
let nextPostsForChannel;
if (channelId === currentChannelId) {
// Keep all of the posts for this channel
nextPostsForChannel = postsForChannel;
} else {
// Only keep the most recent posts for this channel
const recentBlock = postsForChannel.find((block) => block.recent);
if (!recentBlock) {
// We don't have recent posts for this channel
if (postsInChannel && lastChannelForTeam) {
for (const channelIds of Object.values(lastChannelForTeam)) {
for (const channelId of channelIds) {
if (nextPostsInChannel[channelId]) {
// This is a DM or GM channel that we've already seen on another team
continue;
}
nextPostsForChannel = [{
...recentBlock,
order: recentBlock.order.slice(0, recentPostCount),
}];
}
const postsForChannel = postsInChannel[channelId];
nextPostsInChannel[channelId] = nextPostsForChannel;
if (!postsForChannel) {
// We don't have anything to keep for this channel
continue;
}
let nextPostsForChannel;
if (channelId === currentChannelId) {
// Keep all of the posts for this channel
nextPostsForChannel = postsForChannel;
} else {
// Only keep the most recent posts for this channel
const recentBlock = postsForChannel.find((block) => block.recent);
if (!recentBlock) {
// We don't have recent posts for this channel
continue;
}
nextPostsForChannel = [{
...recentBlock,
order: recentBlock.order.slice(0, recentPostCount),
}];
}
nextPostsInChannel[channelId] = nextPostsForChannel;
}
}
}
@@ -206,9 +214,11 @@ export function cleanUpPostsInChannel(postsInChannel, lastChannelForTeam, curren
export function getAllFromPostsInChannel(postsInChannel) {
const postIds = [];
for (const postsForChannel of Object.values(postsInChannel)) {
for (const block of postsForChannel) {
postIds.push(...block.order);
if (postsInChannel) {
for (const postsForChannel of Object.values(postsInChannel)) {
for (const block of postsForChannel) {
postIds.push(...block.order);
}
}
}

View File

@@ -31,7 +31,6 @@ export default async function getStorage(identifier = 'default') {
const MMKV = await new MMKVStorage.Loader().
withInstanceID(identifier).
setProcessingMode(MMKVStorage.MODES.MULTI_PROCESS).
withEncryption().
initialize();
return {

View File

@@ -55,7 +55,7 @@ class JavascriptAndNativeErrorHandler {
Alert.alert(
translations[t('mobile.error_handler.title')],
translations[t('mobile.error_handler.description')],
translations[t('mobile.error_handler.description')] + `\n\n${e.message}\n\n${e.stack}`,
[{
text: translations[t('mobile.error_handler.button')],
onPress: async () => {

View File

@@ -90,7 +90,7 @@ export function validatePreviousVersion(previousVersion) {
INVALID_VERSIONS.push('1.31.0', '1.31.1');
}
if (!previousVersion || INVALID_VERSIONS.includes(previousVersion)) {
if (INVALID_VERSIONS.includes(previousVersion)) {
return false;
}

View File

@@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import {Client4} from '@mm-redux/client';
import CookieManager from '@react-native-community/cookies';
import CookieManager from 'react-native-cookies';
export function setCSRFFromCookie(url) {
return new Promise((resolve) => {

View File

@@ -936,7 +936,7 @@
CODE_SIGN_ENTITLEMENTS = Mattermost/Mattermost.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 302;
CURRENT_PROJECT_VERSION = 307;
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = UQ8HT4Q2XM;
ENABLE_BITCODE = NO;
@@ -945,7 +945,7 @@
"$(SRCROOT)/UploadAttachments/UploadAttachments",
);
INFOPLIST_FILE = Mattermost/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
OTHER_CFLAGS = (
"$(inherited)",
@@ -978,7 +978,7 @@
CODE_SIGN_ENTITLEMENTS = Mattermost/Mattermost.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 302;
CURRENT_PROJECT_VERSION = 307;
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = UQ8HT4Q2XM;
ENABLE_BITCODE = NO;
@@ -987,7 +987,7 @@
"$(SRCROOT)/UploadAttachments/UploadAttachments",
);
INFOPLIST_FILE = Mattermost/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
OTHER_CFLAGS = (
"$(inherited)",
@@ -1035,7 +1035,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
HEADER_SEARCH_PATHS = "$(SRCROOT)/UploadAttachments/UploadAttachments";
INFOPLIST_FILE = MattermostShare/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
@@ -1081,7 +1081,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
HEADER_SEARCH_PATHS = "$(SRCROOT)/UploadAttachments/UploadAttachments";
INFOPLIST_FILE = MattermostShare/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
MTL_FAST_MATH = YES;
OTHER_CFLAGS = (
@@ -1123,7 +1123,7 @@
DEVELOPMENT_TEAM = UQ8HT4Q2XM;
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = NotificationService/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
@@ -1167,7 +1167,7 @@
DEVELOPMENT_TEAM = UQ8HT4Q2XM;
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = NotificationService/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
MTL_FAST_MATH = YES;
OTHER_CFLAGS = (

View File

@@ -19,7 +19,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.32.0</string>
<string>1.32.2</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
@@ -34,7 +34,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>302</string>
<string>307</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSRequiresIPhoneOS</key>

View File

@@ -17,9 +17,9 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>1.32.0</string>
<string>1.32.2</string>
<key>CFBundleVersion</key>
<string>302</string>
<string>307</string>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>

View File

@@ -17,9 +17,9 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>1.32.0</string>
<string>1.32.2</string>
<key>CFBundleVersion</key>
<string>302</string>
<string>307</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>

View File

@@ -207,7 +207,7 @@ PODS:
- React-jsinspector (0.62.2)
- react-native-cameraroll (1.6.2):
- React
- react-native-cookies (3.0.0):
- react-native-cookies (3.2.0):
- React
- react-native-document-picker (3.4.0):
- React
@@ -235,7 +235,7 @@ PODS:
- react-native-video/Video (= 5.0.2)
- react-native-video/Video (5.0.2):
- React
- react-native-webview (9.4.0):
- react-native-webview (7.0.1):
- React
- React-RCTActionSheet (0.62.2):
- React-Core/RCTActionSheetHeaders (= 0.62.2)
@@ -320,7 +320,7 @@ PODS:
- React
- RNGestureHandler (1.6.1):
- React
- RNKeychain (6.0.0):
- RNKeychain (4.0.5):
- React
- RNLocalize (1.4.0):
- React
@@ -380,7 +380,7 @@ DEPENDENCIES:
- React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
- "react-native-cameraroll (from `../node_modules/@react-native-community/cameraroll`)"
- "react-native-cookies (from `../node_modules/@react-native-community/cookies`)"
- react-native-cookies (from `../node_modules/react-native-cookies/ios`)
- react-native-document-picker (from `../node_modules/react-native-document-picker`)
- react-native-hw-keyboard-event (from `../node_modules/react-native-hw-keyboard-event`)
- react-native-image-picker (from `../node_modules/react-native-image-picker`)
@@ -484,7 +484,7 @@ EXTERNAL SOURCES:
react-native-cameraroll:
:path: "../node_modules/@react-native-community/cameraroll"
react-native-cookies:
:path: "../node_modules/@react-native-community/cookies"
:path: "../node_modules/react-native-cookies/ios"
react-native-document-picker:
:path: "../node_modules/react-native-document-picker"
react-native-hw-keyboard-event:
@@ -597,7 +597,7 @@ SPEC CHECKSUMS:
React-jsiexecutor: 1540d1c01bb493ae3124ed83351b1b6a155db7da
React-jsinspector: 512e560d0e985d0e8c479a54a4e5c147a9c83493
react-native-cameraroll: 94bec91c68b94ac946c61b497b594bb38692c41b
react-native-cookies: 6fe6a70d3b2fd8e81ddcd94d60a87727010d9b2e
react-native-cookies: 854d59c4135c70b92a02ca4930e68e4e2eb58150
react-native-document-picker: d694111879537cec2c258a1dcd2243d9df746824
react-native-hw-keyboard-event: b517cefb8d5c659a38049c582de85ff43337dc53
react-native-image-picker: 668e72d0277dc8c12ae90e835507c1eddd2e4f85
@@ -609,7 +609,7 @@ SPEC CHECKSUMS:
react-native-safe-area: e8230b0017d76c00de6b01e2412dcf86b127c6a3
react-native-safe-area-context: 5f3e081f937ab7c44c179d551f332fa494cfcf8f
react-native-video: 961749da457e73bf0b5565edfbaffc25abfb8974
react-native-webview: 0e2881d2e3e72ad52a82445c1a116c43205fd471
react-native-webview: 0d1c2b4e7ffb0543a74fa0512f2f8dc5fb0e49e2
React-RCTActionSheet: f41ea8a811aac770e0cc6e0ad6b270c644ea8b7c
React-RCTAnimation: 49ab98b1c1ff4445148b72a3d61554138565bad0
React-RCTBlob: a332773f0ebc413a0ce85942a55b064471587a71
@@ -630,7 +630,7 @@ SPEC CHECKSUMS:
RNFastImage: 35ae972d6727c84ee3f5c6897e07f84d0a3445e9
RNFileViewer: 3600e85d326dadfd0fd367eb38fcb4300b699b49
RNGestureHandler: 8f09cd560f8d533eb36da5a6c5a843af9f056b38
RNKeychain: bf2d7e9a0ae7a073c07770dd2aa6d11c67581733
RNKeychain: 840f8e6f13be0576202aefcdffd26a4f54bfe7b5
RNLocalize: fc27ee5878ce5a3af73873fb2d8e866e0d1e6d84
RNPermissions: 8ca17fd6c822eea589fe84709d9426e05cc39c39
RNReactNativeHapticFeedback: 22c5ecf474428766c6b148f96f2ff6155cd7225e

10230
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "mattermost-mobile",
"version": "1.32.0",
"version": "1.32.2",
"description": "Mattermost Mobile with React Native",
"repository": "git@github.com:mattermost/mattermost-mobile.git",
"author": "Mattermost, Inc.",
@@ -10,7 +10,6 @@
"@babel/runtime": "7.9.6",
"@react-native-community/async-storage": "1.10.1",
"@react-native-community/cameraroll": "1.6.2",
"@react-native-community/cookies": "3.0.0",
"@react-native-community/masked-view": "0.1.10",
"@react-native-community/netinfo": "5.8.1",
"@react-navigation/native": "5.3.2",
@@ -39,6 +38,7 @@
"react-native-button": "3.0.1",
"react-native-calendars": "1.265.0",
"react-native-circular-progress": "1.3.6",
"react-native-cookies": "github:mattermost/react-native-cookies#b35bafc388ae09c83bd875e887daf6a0755e0b40",
"react-native-device-info": "5.5.7",
"react-native-document-picker": "3.4.0",
"react-native-elements": "2.0.0",
@@ -52,7 +52,7 @@
"react-native-image-picker": "2.3.1",
"react-native-keyboard-aware-scroll-view": "0.9.1",
"react-native-keyboard-tracking-view": "5.7.0",
"react-native-keychain": "6.0.0",
"react-native-keychain": "4.0.5",
"react-native-linear-gradient": "2.5.6",
"react-native-local-auth": "1.6.0",
"react-native-localize": "1.4.0",
@@ -72,7 +72,7 @@
"react-native-v8": "0.62.2-patch.1",
"react-native-vector-icons": "6.6.0",
"react-native-video": "5.0.2",
"react-native-webview": "9.4.0",
"react-native-webview": "github:mattermost/react-native-webview#b5e22940a613869d3999feac9451ee65352f4fbe",
"react-native-youtube": "2.0.1",
"react-redux": "7.2.0",
"redux": "4.0.5",

View File

@@ -1,188 +0,0 @@
diff --git a/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java b/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java
index 1995d87..33bd83c 100644
--- a/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java
+++ b/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java
@@ -2,8 +2,12 @@ package com.reactnativecommunity.webview;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
+import android.app.Activity;
+import android.app.AlertDialog;
import android.app.DownloadManager;
+import android.content.ActivityNotFoundException;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
@@ -15,6 +19,7 @@ import android.os.Build;
import android.os.Environment;
import androidx.annotation.RequiresApi;
import androidx.core.content.ContextCompat;
+import android.text.InputType;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.View;
@@ -25,7 +30,9 @@ import android.webkit.ConsoleMessage;
import android.webkit.CookieManager;
import android.webkit.DownloadListener;
import android.webkit.GeolocationPermissions;
+import android.webkit.HttpAuthHandler;
import android.webkit.JavascriptInterface;
+import android.widget.LinearLayout;
import android.webkit.PermissionRequest;
import android.webkit.URLUtil;
import android.webkit.ValueCallback;
@@ -35,6 +42,7 @@ import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
+import android.widget.EditText;
import android.widget.FrameLayout;
import com.facebook.react.views.scroll.ScrollEvent;
@@ -720,6 +728,7 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
protected static class RNCWebViewClient extends WebViewClient {
+ protected Activity mCurrentActivity;
protected boolean mLastLoadFailed = false;
protected @Nullable
ReadableArray mUrlPrefixesForDefaultIntent;
@@ -729,6 +738,10 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
ignoreErrFailedForThisURL = url;
}
+ public void setCurrentActivity(Activity mCurrentActivity) {
+ this.mCurrentActivity = mCurrentActivity;
+ }
+
@Override
public void onPageFinished(WebView webView, String url) {
super.onPageFinished(webView, url);
@@ -810,6 +823,49 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
new TopLoadingErrorEvent(webView.getId(), eventData));
}
+ @Override
+ public void onReceivedHttpAuthRequest(WebView view,
+ final HttpAuthHandler handler, String host, String realm)
+ {
+ if (this.mCurrentActivity != null) {
+ final EditText usernameInput = new EditText(this.mCurrentActivity);
+ usernameInput.setHint("Username");
+
+ final EditText passwordInput = new EditText(this.mCurrentActivity);
+ passwordInput.setHint("Password");
+ passwordInput.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
+
+ LinearLayout layout = new LinearLayout(this.mCurrentActivity);
+ layout.setOrientation(LinearLayout.VERTICAL);
+ layout.addView(usernameInput);
+ layout.addView(passwordInput);
+
+ AlertDialog.Builder authDialog = new AlertDialog.Builder(this.mCurrentActivity)
+ .setTitle("Authentication Challenge")
+ .setMessage(host + " requires user name and password ")
+ .setView(layout)
+ .setCancelable(false)
+ .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialogInterface, int i) {
+ handler.proceed(usernameInput.getText().toString(), passwordInput.getText().toString());
+ dialogInterface.dismiss();
+ }
+ })
+ .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialogInterface, int i) {
+ dialogInterface.dismiss();
+ handler.cancel();
+ }
+ });
+
+ if (view != null) {
+ authDialog.show();
+ }
+ } else {
+ handler.cancel();
+ }
+ }
+
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onReceivedHttpError(
@@ -1010,6 +1066,7 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
protected boolean sendContentSizeChangeEvents = false;
private OnScrollDispatchHelper mOnScrollDispatchHelper;
protected boolean hasScrollEvent = false;
+ protected ReactContext reactContext;
/**
* WebView must be created with an context of the current activity
@@ -1019,6 +1076,7 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
*/
public RNCWebView(ThemedReactContext reactContext) {
super(reactContext);
+ this.reactContext = reactContext;
}
public void setIgnoreErrFailedForThisURL(String url) {
@@ -1069,6 +1127,9 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
super.setWebViewClient(client);
if (client instanceof RNCWebViewClient) {
mRNCWebViewClient = (RNCWebViewClient) client;
+ if (this.reactContext != null && this.reactContext.getCurrentActivity() != null && mRNCWebViewClient != null) {
+ mRNCWebViewClient.setCurrentActivity(this.reactContext.getCurrentActivity());
+ }
}
}
diff --git a/node_modules/react-native-webview/apple/RNCWebView.m b/node_modules/react-native-webview/apple/RNCWebView.m
index d2f9956..4b8d0fe 100644
--- a/node_modules/react-native-webview/apple/RNCWebView.m
+++ b/node_modules/react-native-webview/apple/RNCWebView.m
@@ -737,7 +737,44 @@ - (void) webView:(WKWebView *)webView
if (webView.URL != nil) {
host = webView.URL.host;
}
- if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodClientCertificate) {
+
+ NSString *authenticationMethod = [[challenge protectionSpace] authenticationMethod];
+
+ if (authenticationMethod == NSURLAuthenticationMethodNTLM || authenticationMethod == NSURLAuthenticationMethodNegotiate) {
+ NSString *title = @"Authentication Challenge";
+ NSString *message = [NSString stringWithFormat:@"%@ requires user name and password", host];
+ UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
+ [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
+ textField.placeholder = @"User";
+ }];
+
+ [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
+ textField.placeholder = @"Password";
+ textField.secureTextEntry = YES;
+ }];
+
+ [alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
+ NSString *userName = ((UITextField *)alertController.textFields[0]).text;
+ NSString *password = ((UITextField *)alertController.textFields[1]).text;
+ NSURLCredential *credential = [[NSURLCredential alloc] initWithUser:userName password:password persistence:NSURLCredentialPersistenceNone];
+
+ completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
+ }]];
+
+ [alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
+ completionHandler(NSURLSessionAuthChallengeUseCredential, nil);
+ }]];
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+ UIViewController *rootVC = UIApplication.sharedApplication.delegate.window.rootViewController;
+
+ while (rootVC.presentedViewController != nil) {
+ rootVC = rootVC.presentedViewController;
+ }
+ [rootVC presentViewController:alertController animated:YES completion:^{}];
+ });
+ return;
+ } else if (authenticationMethod == NSURLAuthenticationMethodClientCertificate) {
completionHandler(NSURLSessionAuthChallengeUseCredential, clientAuthenticationCredential);
return;
}

View File

@@ -154,7 +154,7 @@ jest.mock('react-native-localize', () => ({
]),
}));
jest.mock('@react-native-community/cookies', () => ({
jest.mock('react-native-cookies', () => ({
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
openURL: jest.fn(),