Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
6acd5d1
dehydrate login methods from rocketchat.js
gerzonc Feb 18, 2022
3aed051
export icredentials
gerzonc Feb 25, 2022
ff44417
Merge branch 'develop' into chore.dehydrate-login-methods-from-rocket…
gerzonc Feb 25, 2022
1afc794
dehydrate login methods from rocketchat.js
gerzonc Feb 25, 2022
4eb6c46
Merge branch 'develop' into chore.dehydrate-login-methods-from-rocket…
gerzonc Feb 25, 2022
9249d69
remove unused imports
gerzonc Feb 25, 2022
5a4bfc8
Merge branch 'develop' into chore.dehydrate-login-methods-from-rocket…
gerzonc Feb 26, 2022
ab8ff58
dehydrate abort, checkAndReopen and disconnect
gerzonc Feb 26, 2022
3aa227e
update: ILoginResultFromServer
gerzonc Mar 2, 2022
f8fe01b
Merge branch 'develop' into chore.dehydrate-login-methods-from-rocket…
gerzonc Mar 2, 2022
0694d7b
Merge branch 'develop' into chore.dehydrate-login-methods-from-rocket…
gerzonc Mar 2, 2022
3cd8926
Merge branch 'develop' into chore.dehydrate-login-methods-from-rocket…
gerzonc Mar 2, 2022
c14a061
Merge branch 'develop' into chore.dehydrate-login-methods-from-rocket…
gerzonc Mar 2, 2022
06c9c79
add: `connect` and `stopListener` to `connect.ts`
gerzonc Mar 4, 2022
766a2ca
Merge branch 'develop' into chore.dehydrate-login-methods-from-rocket…
gerzonc Mar 4, 2022
edbb15d
remove: unused imports and leftovers
gerzonc Mar 4, 2022
411323f
Merge branch 'chore.dehydrate-login-methods-from-rocketchatjs' of htt…
gerzonc Mar 4, 2022
0949b1d
Merge branch 'develop' into chore.dehydrate-login-methods-from-rocket…
gerzonc Mar 8, 2022
d52e642
remove: unused import
gerzonc Mar 8, 2022
1f7f99b
Revert "remove: unused import"
gerzonc Mar 8, 2022
5a4f02b
remove: unused import
gerzonc Mar 8, 2022
6015349
fix: login error
gerzonc Mar 8, 2022
d6ce877
fix: logout being `undefined`
gerzonc Mar 8, 2022
f2a69e4
Merge branch 'develop' into chore.dehydrate-login-methods-from-rocket…
gerzonc Mar 8, 2022
ba8eabb
Merge branch 'develop' into chore.dehydrate-login-methods-from-rocket…
gerzonc Mar 8, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/containers/LoginServices.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ class LoginServices extends React.PureComponent<ILoginServicesProps, any> {
AppleAuthentication.AppleAuthenticationScope.EMAIL
]
});

// @ts-ignore
await RocketChat.loginOAuthOrSso({ fullName, email, identityToken });
} catch {
logEvent(events.ENTER_WITH_APPLE_F);
Expand Down
8 changes: 2 additions & 6 deletions app/containers/MessageBox/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import { sanitizeLikeString } from '../../lib/database/utils';
import { CustomIcon } from '../../lib/Icons';
import { IMessage } from '../../definitions/IMessage';
import { forceJpgExtension } from './forceJpgExtension';
import { IUser } from '../../definitions';

if (isAndroid) {
require('./EmojiKeyboard');
Expand Down Expand Up @@ -80,12 +81,7 @@ export interface IMessageBoxProps {
editing: boolean;
threadsEnabled: boolean;
isFocused(): boolean;
user: {
id: string;
_id: string;
username: string;
token: string;
};
user: IUser;
roomType: string;
tmid: string;
replyWithMention: boolean;
Expand Down
15 changes: 15 additions & 0 deletions app/definitions/ICredentials.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export interface ICredentials {
user?: string;
password?: string;
username?: string;
ldapPass?: string;
ldap?: boolean;
ldapOptions?: object;
crowdPassword?: string;
crowd?: boolean;
code?: string;
totp?: {
login: ICredentials;
code: string;
};
}
22 changes: 21 additions & 1 deletion app/definitions/ILoggedUser.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,38 @@
import Model from '@nozbe/watermelondb/Model';

import { IUserEmail, IUserSettings } from './IUser';
import { UserStatus } from './UserStatus';

export interface ILoggedUser {
id: string;
token: string;
username: string;
name: string;
language?: string;
status: string;
status: UserStatus;
statusText?: string;
customFields?: {
[key: string]: any;
};
statusLivechat?: string;
emails?: IUserEmail[];
roles?: string[];
avatarETag?: string;
showMessageInMainThread?: boolean;
isFromWebView?: boolean;
enableMessageParserEarlyAdoption?: boolean;
}

export interface ILoggedUserResultFromServer
extends Omit<ILoggedUser, 'enableMessageParserEarlyAdoption' | 'showMessageInMainThread'> {
settings: IUserSettings;
}

export interface ILoginResultFromServer {
status: string;
authToken: string;
userId: string;
me: ILoggedUserResultFromServer;
}

export type TLoggedUserModel = ILoggedUser & Model;
1 change: 1 addition & 0 deletions app/definitions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export * from './IServerHistory';
export * from './IRocketChat';
export * from './ICertificate';
export * from './IUrl';
export * from './ICredentials';

export interface IBaseScreen<T extends Record<string, object | undefined>, S extends string> {
navigation: StackNavigationProp<T, S>;
Expand Down
195 changes: 24 additions & 171 deletions app/lib/rocketchat/rocketchat.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { Rocketchat as RocketchatClient, settings as RocketChatSettings } from '
import { InteractionManager } from 'react-native';
import RNFetchBlob from 'rn-fetch-blob';
import { setActiveUsers } from '../../actions/activeUsers';
import { connectRequest, connectSuccess, disconnect } from '../../actions/connect';
import { connectRequest, connectSuccess, disconnect as disconnectAction } from '../../actions/connect';
import { encryptionInit } from '../../actions/encryption';
import { loginRequest, setLoginServices, setUser } from '../../actions/login';
import { loginRequest, setUser } from '../../actions/login';
import { updatePermission } from '../../actions/permissions';
import { selectServerFailure } from '../../actions/server';
import { updateSettings } from '../../actions/settings';
Expand All @@ -17,10 +17,8 @@ import I18n from '../../i18n';
import { getDeviceToken } from '../../notifications/push';
import { getBundleId, isIOS } from '../../utils/deviceInfo';
import EventEmitter from '../../utils/events';
import fetch from '../../utils/fetch';
import log from '../../utils/log';
import SSLPinning from '../../utils/sslPinning';
import { twoFactor } from '../../utils/twoFactor';
import { useSsl } from '../../utils/url';
import database from '../database';
import { sanitizeLikeString } from '../database/utils';
Expand Down Expand Up @@ -65,6 +63,17 @@ import getUserInfo from './services/getUserInfo';
// Services
import sdk from './services/sdk';
import toggleFavorite from './services/toggleFavorite';
import {
login,
loginTOTP,
loginWithPassword,
loginOAuthOrSso,
getLoginServices,
determineAuthType,
disconnect,
checkAndReopen,
abort
} from './services/connect';
import * as restAPis from './services/restApi';

const TOKEN_KEY = 'reactnativemeteor_usertoken';
Expand All @@ -74,7 +83,7 @@ const CERTIFICATE_KEY = 'RC_CERTIFICATE_KEY';
export const THEME_PREFERENCES_KEY = 'RC_THEME_PREFERENCES_KEY';
export const CRASH_REPORT_KEY = 'RC_CRASH_REPORT_KEY';
export const ANALYTICS_EVENTS_KEY = 'RC_ANALYTICS_EVENTS_KEY';
const MIN_ROCKETCHAT_VERSION = '0.70.0';
export const MIN_ROCKETCHAT_VERSION = '0.70.0';

const STATUSES = ['offline', 'online', 'away', 'busy'];

Expand Down Expand Up @@ -168,21 +177,9 @@ const RocketChat = {
return listener && listener.stop();
},
// Abort all requests and create a new AbortController
abort() {
if (this.controller) {
this.controller.abort();
if (this.sdk) {
this.sdk.abort();
}
}
this.controller = new AbortController();
},
checkAndReopen() {
return this?.sdk?.checkAndReopen();
},
disconnect() {
this.sdk = sdk.disconnect();
},
abort,
checkAndReopen,
disconnect,
connect({ server, user, logoutOnError = false }) {
return new Promise(resolve => {
if (this?.sdk?.client?.host === server) {
Expand Down Expand Up @@ -258,7 +255,7 @@ const RocketChat = {
});

this.closeListener = this.sdk.onStreamData('close', () => {
reduxStore.dispatch(disconnect());
reduxStore.dispatch(disconnectAction());
});

this.usersListener = this.sdk.onStreamData(
Expand Down Expand Up @@ -487,103 +484,10 @@ const RocketChat = {
return this.methodCallWrapper('e2e.resetOwnE2EKey');
},

loginTOTP(params, loginEmailPassword, isFromWebView = false) {
return new Promise(async (resolve, reject) => {
try {
const result = await this.login(params, isFromWebView);
return resolve(result);
} catch (e) {
if (e.data?.error && (e.data.error === 'totp-required' || e.data.error === 'totp-invalid')) {
const { details } = e.data;
try {
const code = await twoFactor({ method: details?.method || 'totp', invalid: details?.error === 'totp-invalid' });

if (loginEmailPassword) {
reduxStore.dispatch(setUser({ username: params.user || params.username }));

// Force normalized params for 2FA starting RC 3.9.0.
const serverVersion = reduxStore.getState().server.version;
if (compareServerVersion(serverVersion, 'greaterThanOrEqualTo', '3.9.0')) {
const user = params.user ?? params.username;
const password = params.password ?? params.ldapPass ?? params.crowdPassword;
params = { user, password };
}

return resolve(this.loginTOTP({ ...params, code: code?.twoFactorCode }, loginEmailPassword));
}

return resolve(
this.loginTOTP({
totp: {
login: {
...params
},
code: code?.twoFactorCode
}
})
);
} catch {
// twoFactor was canceled
return reject();
}
} else {
reject(e);
}
}
});
},

loginWithPassword({ user, password }) {
let params = { user, password };
const state = reduxStore.getState();

if (state.settings.LDAP_Enable) {
params = {
username: user,
ldapPass: password,
ldap: true,
ldapOptions: {}
};
} else if (state.settings.CROWD_Enable) {
params = {
username: user,
crowdPassword: password,
crowd: true
};
}

return this.loginTOTP(params, true);
},

async loginOAuthOrSso(params, isFromWebView = true) {
const result = await this.loginTOTP(params, false, isFromWebView);
reduxStore.dispatch(loginRequest({ resume: result.token }, false, isFromWebView));
},

async login(credentials, isFromWebView = false) {
const sdk = this.shareSDK || this.sdk;
// RC 0.64.0
await sdk.login(credentials);
const { result } = sdk.currentLogin;
const user = {
id: result.userId,
token: result.authToken,
username: result.me.username,
name: result.me.name,
language: result.me.language,
status: result.me.status,
statusText: result.me.statusText,
customFields: result.me.customFields,
statusLivechat: result.me.statusLivechat,
emails: result.me.emails,
roles: result.me.roles,
avatarETag: result.me.avatarETag,
isFromWebView,
showMessageInMainThread: result.me.settings?.preferences?.showMessageInMainThread ?? true,
enableMessageParserEarlyAdoption: result.me.settings?.preferences?.enableMessageParserEarlyAdoption ?? true
};
return user;
},
loginTOTP,
loginWithPassword,
loginOAuthOrSso,
login,
logout,
logoutOtherLocations() {
const { id: userId } = reduxStore.getState().login.user;
Expand Down Expand Up @@ -928,59 +832,8 @@ const RocketChat = {
prefs = { ...prefs, ...param };
return UserPreferences.setMapAsync(SORT_PREFS_KEY, prefs);
},
async getLoginServices(server) {
try {
let loginServices = [];
const loginServicesResult = await fetch(`${server}/api/v1/settings.oauth`).then(response => response.json());

if (loginServicesResult.success && loginServicesResult.services) {
const { services } = loginServicesResult;
loginServices = services;

const loginServicesReducer = loginServices.reduce((ret, item) => {
const name = item.name || item.buttonLabelText || item.service;
const authType = this._determineAuthType(item);

if (authType !== 'not_supported') {
ret[name] = { ...item, name, authType };
}

return ret;
}, {});
reduxStore.dispatch(setLoginServices(loginServicesReducer));
} else {
reduxStore.dispatch(setLoginServices({}));
}
} catch (error) {
console.log(error);
reduxStore.dispatch(setLoginServices({}));
}
},
_determineAuthType(services) {
const { name, custom, showButton = true, service } = services;

const authName = name || service;

if (custom && showButton) {
return 'oauth_custom';
}

if (service === 'saml') {
return 'saml';
}

if (service === 'cas') {
return 'cas';
}

if (authName === 'apple' && isIOS) {
return 'apple';
}

// TODO: remove this after other oauth providers are implemented. e.g. Drupal, github_enterprise
const availableOAuth = ['facebook', 'github', 'gitlab', 'google', 'linkedin', 'meteor-developer', 'twitter', 'wordpress'];
return availableOAuth.includes(authName) ? 'oauth' : 'not_supported';
},
getLoginServices,
determineAuthType,
roomTypeToApiType,
readThreads(tmid) {
const serverVersion = reduxStore.getState().server.version;
Expand Down
Loading