230 lines
No EOL
7.5 KiB
TypeScript
230 lines
No EOL
7.5 KiB
TypeScript
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
import React, {ReactNode} from 'react';
|
|
import {intlShape} from 'react-intl';
|
|
import {Alert, NativeModules, PermissionsAndroid} from 'react-native';
|
|
import LocalAuth from 'react-native-local-auth';
|
|
import RNFetchBlob from 'rn-fetch-blob';
|
|
|
|
import Loading from '@components/loading';
|
|
import {MAX_FILE_COUNT} from '@constants/post_draft';
|
|
import {getAppCredentials} from '@init/credentials';
|
|
import type {FileInfo} from '@mm-redux/types/files';
|
|
import type {Team} from '@mm-redux/types/teams';
|
|
import {getFormattedFileSize, lookupMimeType} from '@mm-redux/utils/file_utils';
|
|
import {getExtensionFromMime} from '@utils/file';
|
|
import mattermostManaged from 'app/mattermost_managed';
|
|
|
|
import ShareError from '@share/components/error';
|
|
|
|
const ShareExtension = NativeModules.MattermostShare;
|
|
|
|
export async function isAuthorized(intl: typeof intlShape): Promise<boolean> {
|
|
try {
|
|
const config = await mattermostManaged.getConfig();
|
|
|
|
if (config) {
|
|
const authNeeded = config.inAppPinCode && config.inAppPinCode === 'true';
|
|
const vendor = config.vendor || 'Mattermost';
|
|
if (authNeeded) {
|
|
const isSecured = await mattermostManaged.isDeviceSecure();
|
|
if (isSecured) {
|
|
try {
|
|
await LocalAuth.auth({
|
|
reason: intl.formatMessage({
|
|
id: 'mobile.managed.secured_by',
|
|
defaultMessage: 'Secured by {vendor}',
|
|
}, {vendor}),
|
|
fallbackToPasscode: true,
|
|
suppressEnterPassword: false,
|
|
});
|
|
} catch (err) {
|
|
ShareExtension.close(null);
|
|
}
|
|
} else {
|
|
await showNotSecuredAlert(intl, vendor);
|
|
|
|
ShareExtension.close(null);
|
|
}
|
|
}
|
|
}
|
|
} catch {
|
|
// do nothing
|
|
}
|
|
|
|
return getCredentials();
|
|
}
|
|
|
|
export async function getSharedItems(items: Array<ShareItem>, intl: typeof intlShape): Promise<ProcessedSharedItems> {
|
|
const text = [];
|
|
const files: Array<ShareFileInfo> = [];
|
|
let totalSize = 0;
|
|
let error;
|
|
|
|
for (let i = 0; i < items.length; i++) {
|
|
const item = items[i];
|
|
switch (item.type) {
|
|
case 'text/plain':
|
|
text.push(item.value);
|
|
break;
|
|
default: {
|
|
let fileSize = {size: 0};
|
|
const fullPath = item.value;
|
|
try {
|
|
fileSize = await RNFetchBlob.fs.stat(fullPath); // eslint-disable-line no-await-in-loop
|
|
} catch (e) {
|
|
error = intl.formatMessage({
|
|
id: 'mobile.extension.file_error',
|
|
defaultMessage: 'There was an error reading the file to be shared.\nPlease try again.',
|
|
});
|
|
break;
|
|
}
|
|
let filename = fullPath.replace(/^.*[\\/]/, '');
|
|
let extension = filename.split('.').pop();
|
|
if (extension === filename) {
|
|
extension = getExtensionFromMime(item.type);
|
|
filename = `${filename}.${extension}`;
|
|
}
|
|
|
|
totalSize += fileSize.size;
|
|
files.push({
|
|
extension,
|
|
filename,
|
|
fullPath,
|
|
mimeType: item.type || lookupMimeType(filename.toLowerCase()),
|
|
size: getFormattedFileSize(fileSize as FileInfo),
|
|
type: item.type,
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
const value = text.join('\n');
|
|
|
|
return {error, files, value, totalSize};
|
|
}
|
|
|
|
export async function permissionEnabled(): Promise<boolean> {
|
|
const hasPermission = await PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE);
|
|
let granted;
|
|
if (!hasPermission) {
|
|
granted = await PermissionsAndroid.request(
|
|
PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE,
|
|
);
|
|
}
|
|
|
|
return (hasPermission || granted === PermissionsAndroid.RESULTS.GRANTED);
|
|
}
|
|
|
|
export function getErrorElement(
|
|
state: ShareState,
|
|
canUploadFiles: boolean,
|
|
maxFileSize: number,
|
|
team: Team | undefined | null,
|
|
intl: typeof intlShape,
|
|
): ReactNode | undefined {
|
|
if (state.loading) {
|
|
return <Loading/>;
|
|
}
|
|
|
|
if (!state.authorized) {
|
|
return <ShareError/>;
|
|
}
|
|
|
|
if (!team?.id) {
|
|
const teamRequired = intl.formatMessage({
|
|
id: 'mobile.extension.team_required',
|
|
defaultMessage: 'You must belong to a team before you can share files.',
|
|
});
|
|
|
|
return <ShareError message={teamRequired}/>;
|
|
}
|
|
|
|
if (!canUploadFiles) {
|
|
const uploadsDisabled = intl.formatMessage({
|
|
id: 'mobile.file_upload.disabled',
|
|
defaultMessage: 'File uploads from mobile are disabled. Please contact your System Admin for more details.',
|
|
});
|
|
|
|
return <ShareError message={uploadsDisabled}/>;
|
|
}
|
|
|
|
if (state.hasPermission === false) {
|
|
const storage = intl.formatMessage({
|
|
id: 'mobile.extension.permission',
|
|
defaultMessage: 'Mattermost needs access to the device storage to share files.',
|
|
});
|
|
|
|
return <ShareError message={storage}/>;
|
|
}
|
|
|
|
if (state.files.length > MAX_FILE_COUNT) {
|
|
const fileCount = intl.formatMessage({
|
|
id: 'mobile.extension.file_limit',
|
|
defaultMessage: 'Sharing is limited to a maximum of 5 files.',
|
|
});
|
|
|
|
return <ShareError message={fileCount}/>;
|
|
}
|
|
|
|
if ((state.totalSize || 0) > maxFileSize) {
|
|
const maxSize = intl.formatMessage({
|
|
id: 'mobile.extension.max_file_size',
|
|
defaultMessage: 'File attachments shared in Mattermost must be less than {size}.',
|
|
}, {size: getFormattedFileSize({size: maxFileSize} as FileInfo)});
|
|
|
|
return <ShareError message={maxSize}/>;
|
|
}
|
|
|
|
return undefined;
|
|
}
|
|
|
|
async function getCredentials(): Promise<boolean> {
|
|
try {
|
|
const credentials = await getAppCredentials();
|
|
return Boolean(credentials);
|
|
} catch (error) {
|
|
return false;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function showNotSecuredAlert(intl: typeof intlShape, vendor: string): Promise<void> {
|
|
const {formatMessage} = intl;
|
|
|
|
return new Promise((resolve) => {
|
|
Alert.alert(
|
|
formatMessage({
|
|
id: 'mobile.managed.blocked_by',
|
|
defaultMessage: 'Blocked by {vendor}',
|
|
}, {vendor}),
|
|
formatMessage({
|
|
id: 'mobile.managed.not_secured.android',
|
|
defaultMessage: 'This device must be secured with a screen lock to use Mattermost.',
|
|
}),
|
|
[
|
|
{
|
|
text: formatMessage({
|
|
id: 'mobile.managed.settings',
|
|
defaultMessage: 'Go to settings',
|
|
}),
|
|
onPress: () => {
|
|
mattermostManaged.goToSecuritySettings();
|
|
},
|
|
},
|
|
{
|
|
text: formatMessage({
|
|
id: 'mobile.managed.exit',
|
|
defaultMessage: 'Exit',
|
|
}),
|
|
onPress: () => resolve(),
|
|
style: 'cancel',
|
|
},
|
|
],
|
|
{onDismiss: resolve},
|
|
);
|
|
});
|
|
} |