* feat: add shared server password to server setup * feat: allow editing the sever * refactor: changed password -> secret, styling and tests * e2e: draft e2e tests * chore: lint fix * feat: also send preauth secret header when using native share * fix: removed unused server database migration credentials are being stored in the keychain * i18n: added missing english translations * test(e2e): simplified connection tests * test(e2e): rework * refactor: remove setBearerToken * chore: restore migrations the way it was * chore: reverted file to original state * chore: removed unneeded test and renamed password to secret * chore: function version * chore: updated forms i18n keys * chore: remove if from test * chore: unneeded variable * fix: add missing key on object list * refactor: swift keychain access to retrieve all credentials in one call * revert: edit server screen * refactor: credentials use getGenericCredential * fix: objc code calling old method * fix: added scroll to login screen * chore: variable names * fix: avoid inline styles * fix: Improved appVersion positioning * Update app/screens/server/form.tsx Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * feat: show error message on 403 * Revert "feat: show error message on 403" This reverts commit f41630c767e10211adf1885321ceefd8a0931e32. --------- Co-authored-by: Matthew Birtch <mattbirtch@gmail.com>
118 lines
4.1 KiB
TypeScript
118 lines
4.1 KiB
TypeScript
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
import {defineMessage} from 'react-intl';
|
|
|
|
import {SYSTEM_IDENTIFIERS} from '@constants/database';
|
|
import {PUSH_PROXY_RESPONSE_VERIFIED, PUSH_PROXY_STATUS_VERIFIED} from '@constants/push_proxy';
|
|
import DatabaseManager from '@database/manager';
|
|
import NetworkManager from '@managers/network_manager';
|
|
import {getDeviceToken} from '@queries/app/global';
|
|
import {getExpandedLinks, getPushVerificationStatus} from '@queries/servers/system';
|
|
import {getFullErrorMessage} from '@utils/errors';
|
|
import {logDebug} from '@utils/log';
|
|
|
|
import {forceLogoutIfNecessary} from './session';
|
|
|
|
import type {Client} from '@client/rest';
|
|
import type {ClientResponse} from '@mattermost/react-native-network-client';
|
|
|
|
async function getDeviceIdForPing(serverUrl: string, checkDeviceId: boolean) {
|
|
if (!checkDeviceId) {
|
|
return undefined;
|
|
}
|
|
|
|
const serverDatabase = DatabaseManager.serverDatabases?.[serverUrl]?.database;
|
|
if (serverDatabase) {
|
|
const status = await getPushVerificationStatus(serverDatabase);
|
|
if (status === PUSH_PROXY_STATUS_VERIFIED) {
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
return getDeviceToken();
|
|
}
|
|
|
|
// Default timeout interval for ping is 5 seconds
|
|
export const doPing = async (serverUrl: string, verifyPushProxy: boolean, timeoutInterval = 5000, preauthSecret?: string) => {
|
|
let client: Client;
|
|
try {
|
|
client = await NetworkManager.createClient(serverUrl, undefined, preauthSecret);
|
|
} catch (error) {
|
|
return {error};
|
|
}
|
|
|
|
const certificateError = defineMessage({
|
|
id: 'mobile.server_requires_client_certificate',
|
|
defaultMessage: 'Server requires client certificate for authentication.',
|
|
});
|
|
|
|
const pingError = defineMessage({
|
|
id: 'mobile.server_ping_failed',
|
|
defaultMessage: 'Cannot connect to the server.',
|
|
});
|
|
|
|
const deviceId = await getDeviceIdForPing(serverUrl, verifyPushProxy);
|
|
|
|
let response: ClientResponse;
|
|
try {
|
|
response = await client.ping(deviceId, timeoutInterval);
|
|
|
|
if (response.code === 401) {
|
|
// Don't invalidate the client since we want to eventually
|
|
// import a certificate with client.importClientP12()
|
|
// if for some reason cert is not imported do invalidate the client then.
|
|
return {error: {intl: certificateError}};
|
|
}
|
|
|
|
if (!response.ok) {
|
|
logDebug('Server ping returned not ok response', response);
|
|
NetworkManager.invalidateClient(serverUrl);
|
|
return {error: {intl: pingError}};
|
|
}
|
|
} catch (error) {
|
|
logDebug('Server ping threw an exception', getFullErrorMessage(error));
|
|
NetworkManager.invalidateClient(serverUrl);
|
|
return {error: {intl: pingError}};
|
|
}
|
|
|
|
if (verifyPushProxy) {
|
|
let canReceiveNotifications = response?.data?.CanReceiveNotifications;
|
|
|
|
// Already verified or old server
|
|
if (deviceId === undefined || canReceiveNotifications === null) {
|
|
canReceiveNotifications = PUSH_PROXY_RESPONSE_VERIFIED;
|
|
}
|
|
|
|
return {canReceiveNotifications};
|
|
}
|
|
|
|
return {};
|
|
};
|
|
|
|
export const getRedirectLocation = async (serverUrl: string, link: string) => {
|
|
try {
|
|
const client = NetworkManager.getClient(serverUrl);
|
|
const {database, operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
|
const expandedLink = await client.getRedirectLocation(link);
|
|
if (expandedLink?.location) {
|
|
const storedLinks = await getExpandedLinks(database);
|
|
storedLinks[link] = expandedLink.location;
|
|
const expanded: IdValue = {
|
|
id: SYSTEM_IDENTIFIERS.EXPANDED_LINKS,
|
|
value: JSON.stringify(storedLinks),
|
|
};
|
|
await operator.handleSystem({
|
|
systems: [expanded],
|
|
prepareRecordsOnly: false,
|
|
});
|
|
}
|
|
|
|
return {expandedLink};
|
|
} catch (error) {
|
|
logDebug('error on getRedirectLocation', getFullErrorMessage(error));
|
|
forceLogoutIfNecessary(serverUrl, error);
|
|
return {error};
|
|
}
|
|
};
|
|
|