Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions app/i18n/locales/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,7 @@ export default {
You_will_be_logged_out_of_this_application: 'You will be logged out of this application.',
Clear: 'Clear',
This_will_clear_all_your_offline_data: 'This will clear all your offline data.',
This_will_remove_all_data_from_this_server: 'This will remove all data from this server.',
Mark_unread: 'Mark Unread',
Wait_activation_warning: 'Before you can login, your account must be manually activated by an administrator.'
};
1 change: 1 addition & 0 deletions app/i18n/locales/pt-BR.js
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,7 @@ export default {
You_will_be_logged_out_of_this_application: 'Você sairá deste aplicativo.',
Clear: 'Limpar',
This_will_clear_all_your_offline_data: 'Isto limpará todos os seus dados offline.',
This_will_remove_all_data_from_this_server: 'Isto removerá todos os dados desse servidor.',
Mark_unread: 'Marcar como não Lida',
Wait_activation_warning: 'Antes que você possa fazer o login, sua conta deve ser manualmente ativada por um administrador.'
};
60 changes: 32 additions & 28 deletions app/lib/database/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,36 @@ if (__DEV__ && isIOS) {
console.log(appGroupPath);
}

export const getDatabase = (database = '') => {
const path = database.replace(/(^\w+:|^)\/\//, '').replace(/\//g, '.');
const dbName = `${ appGroupPath }${ path }.db`;

const adapter = new SQLiteAdapter({
dbName,
schema: appSchema,
migrations
});

return new Database({
adapter,
modelClasses: [
Subscription,
Room,
Message,
Thread,
ThreadMessage,
CustomEmoji,
FrequentlyUsedEmoji,
Upload,
Setting,
Role,
Permission,
SlashCommand
],
actionsEnabled: true
});
};

class DB {
databases = {
serversDB: new Database({
Expand Down Expand Up @@ -86,34 +116,8 @@ class DB {
});
}

setActiveDB(database = '') {
const path = database.replace(/(^\w+:|^)\/\//, '').replace(/\//g, '.');
const dbName = `${ appGroupPath }${ path }.db`;

const adapter = new SQLiteAdapter({
dbName,
schema: appSchema,
migrations
});

this.databases.activeDB = new Database({
adapter,
modelClasses: [
Subscription,
Room,
Message,
Thread,
ThreadMessage,
CustomEmoji,
FrequentlyUsedEmoji,
Upload,
Setting,
Role,
Permission,
SlashCommand
],
actionsEnabled: true
});
setActiveDB(database) {
this.databases.activeDB = getDatabase(database);
}
}

Expand Down
127 changes: 127 additions & 0 deletions app/lib/methods/logout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import RNUserDefaults from 'rn-user-defaults';
import * as FileSystem from 'expo-file-system';
import { Rocketchat as RocketchatClient } from '@rocket.chat/sdk';

import { SERVERS, SERVER_URL } from '../../constants/userDefaults';
import { getDeviceToken } from '../../notifications/push';
import { extractHostname } from '../../utils/server';
import { BASIC_AUTH_KEY } from '../../utils/fetch';
import database, { getDatabase } from '../database';
import RocketChat from '../rocketchat';
import { useSsl } from '../../utils/url';

async function removeServerKeys({ server, userId }) {
await RNUserDefaults.clear(`${ RocketChat.TOKEN_KEY }-${ server }`);
await RNUserDefaults.clear(`${ RocketChat.TOKEN_KEY }-${ userId }`);
await RNUserDefaults.clear(`${ BASIC_AUTH_KEY }-${ server }`);
}

async function removeSharedCredentials({ server }) {
try {
const servers = await RNUserDefaults.objectForKey(SERVERS);
await RNUserDefaults.setObjectForKey(SERVERS, servers && servers.filter(srv => srv[SERVER_URL] !== server));

// clear certificate for server - SSL Pinning
const certificate = await RNUserDefaults.objectForKey(extractHostname(server));
if (certificate && certificate.path) {
await RNUserDefaults.clear(extractHostname(server));
await FileSystem.deleteAsync(certificate.path);
}
} catch (e) {
console.log('removeSharedCredentials', e);
}
}

async function removeServerData({ server }) {
try {
const batch = [];
const serversDB = database.servers;
const userId = await RNUserDefaults.get(`${ RocketChat.TOKEN_KEY }-${ server }`);

const usersCollection = serversDB.collections.get('users');
if (userId) {
const userRecord = await usersCollection.find(userId);
batch.push(userRecord.prepareDestroyPermanently());
}
const serverCollection = serversDB.collections.get('servers');
const serverRecord = await serverCollection.find(server);
batch.push(serverRecord.prepareDestroyPermanently());

await serversDB.action(() => serversDB.batch(...batch));
await removeSharedCredentials({ server });
await removeServerKeys({ server });
} catch (e) {
console.log('removeServerData', e);
}
}

async function removeCurrentServer() {
await RNUserDefaults.clear('currentServer');
await RNUserDefaults.clear(RocketChat.TOKEN_KEY);
}

async function removeServerDatabase({ server }) {
try {
const db = getDatabase(server);
await db.action(() => db.unsafeResetDatabase());
} catch (e) {
console.log(e);
}
}

export async function removeServer({ server }) {
try {
const userId = await RNUserDefaults.get(`${ RocketChat.TOKEN_KEY }-${ server }`);
if (userId) {
const resume = await RNUserDefaults.get(`${ RocketChat.TOKEN_KEY }-${ userId }`);

const sdk = new RocketchatClient({ host: server, protocol: 'ddp', useSsl: useSsl(server) });
await sdk.login({ resume });

const token = getDeviceToken();
if (token) {
await sdk.del('push.token', { token });
}

await sdk.logout();
}

await removeServerData({ server });
await removeServerDatabase({ server });
} catch (e) {
console.log('removePush', e);
}
}

export default async function logout({ server }) {
if (this.roomsSub) {
this.roomsSub.stop();
this.roomsSub = null;
}

if (this.activeUsersSubTimeout) {
clearTimeout(this.activeUsersSubTimeout);
this.activeUsersSubTimeout = false;
}

try {
await this.removePushToken();
} catch (e) {
console.log('removePushToken', e);
}

try {
// RC 0.60.0
await this.sdk.logout();
} catch (e) {
console.log('logout', e);
}

if (this.sdk) {
this.sdk = null;
}

await removeServerData({ server });
await removeCurrentServer();
await removeServerDatabase({ server });
}
91 changes: 8 additions & 83 deletions app/lib/rocketchat.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@ import semver from 'semver';
import { Rocketchat as RocketchatClient } from '@rocket.chat/sdk';
import RNUserDefaults from 'rn-user-defaults';
import { Q } from '@nozbe/watermelondb';
import * as FileSystem from 'expo-file-system';

import reduxStore from './createStore';
import defaultSettings from '../constants/settings';
import messagesStatus from '../constants/messagesStatus';
import database from './database';
import log from '../utils/log';
import { isIOS, getBundleId } from '../utils/deviceInfo';
import { extractHostname } from '../utils/server';
import fetch, { BASIC_AUTH_KEY } from '../utils/fetch';
import fetch from '../utils/fetch';

import { setUser, setLoginServices, loginRequest } from '../actions/login';
import { disconnect, connectSuccess, connectRequest } from '../actions/connect';
Expand Down Expand Up @@ -43,12 +41,13 @@ import sendMessage, { sendMessageCall } from './methods/sendMessage';
import { sendFileMessage, cancelUpload, isUploadActive } from './methods/sendFileMessage';

import callJitsi from './methods/callJitsi';
import logout, { removeServer } from './methods/logout';

import { getDeviceToken } from '../notifications/push';
import { SERVERS, SERVER_URL } from '../constants/userDefaults';
import { setActiveUsers } from '../actions/activeUsers';
import I18n from '../i18n';
import { twoFactor } from '../utils/twoFactor';
import { useSsl } from '../utils/url';

const TOKEN_KEY = 'reactnativemeteor_usertoken';
const SORT_PREFS_KEY = 'RC_SORT_PREFS_KEY';
Expand Down Expand Up @@ -86,10 +85,7 @@ const RocketChat = {
}
},
async getWebsocketInfo({ server }) {
// Use useSsl: false only if server url starts with http://
const useSsl = !/http:\/\//.test(server);

const sdk = new RocketchatClient({ host: server, protocol: 'ddp', useSsl });
const sdk = new RocketchatClient({ host: server, protocol: 'ddp', useSsl: useSsl(server) });

try {
await sdk.connect();
Expand Down Expand Up @@ -200,10 +196,7 @@ const RocketChat = {
this.code = null;
}

// Use useSsl: false only if server url starts with http://
const useSsl = !/http:\/\//.test(server);

this.sdk = new RocketchatClient({ host: server, protocol: 'ddp', useSsl });
this.sdk = new RocketchatClient({ host: server, protocol: 'ddp', useSsl: useSsl(server) });
this.getSettings();

const sdkConnect = () => this.sdk.connect()
Expand Down Expand Up @@ -270,10 +263,7 @@ const RocketChat = {
this.shareSDK = null;
}

// Use useSsl: false only if server url starts with http://
const useSsl = !/http:\/\//.test(server);

this.shareSDK = new RocketchatClient({ host: server, protocol: 'ddp', useSsl });
this.shareSDK = new RocketchatClient({ host: server, protocol: 'ddp', useSsl: useSsl(server) });

// set Server
const serversDB = database.servers;
Expand Down Expand Up @@ -408,73 +398,8 @@ const RocketChat = {
throw e;
}
},
async logout({ server }) {
if (this.roomsSub) {
this.roomsSub.stop();
this.roomsSub = null;
}

if (this.activeUsersSubTimeout) {
clearTimeout(this.activeUsersSubTimeout);
this.activeUsersSubTimeout = false;
}

try {
await this.removePushToken();
} catch (error) {
console.log('logout -> removePushToken -> catch -> error', error);
}
try {
// RC 0.60.0
await this.sdk.logout();
} catch (error) {
console.log('​logout -> api logout -> catch -> error', error);
}
this.sdk = null;

try {
const servers = await RNUserDefaults.objectForKey(SERVERS);
await RNUserDefaults.setObjectForKey(SERVERS, servers && servers.filter(srv => srv[SERVER_URL] !== server));
// clear certificate for server - SSL Pinning
const certificate = await RNUserDefaults.objectForKey(extractHostname(server));
if (certificate && certificate.path) {
await RNUserDefaults.clear(extractHostname(server));
await FileSystem.deleteAsync(certificate.path);
}
} catch (error) {
console.log('logout_rn_user_defaults', error);
}

const userId = await RNUserDefaults.get(`${ TOKEN_KEY }-${ server }`);

try {
const serversDB = database.servers;
await serversDB.action(async() => {
const usersCollection = serversDB.collections.get('users');
const userRecord = await usersCollection.find(userId);
const serverCollection = serversDB.collections.get('servers');
const serverRecord = await serverCollection.find(server);
await serversDB.batch(
userRecord.prepareDestroyPermanently(),
serverRecord.prepareDestroyPermanently()
);
});
} catch (error) {
// Do nothing
}

await RNUserDefaults.clear('currentServer');
await RNUserDefaults.clear(TOKEN_KEY);
await RNUserDefaults.clear(`${ TOKEN_KEY }-${ server }`);
await RNUserDefaults.clear(`${ BASIC_AUTH_KEY }-${ server }`);

try {
const db = database.active;
await db.action(() => db.unsafeResetDatabase());
} catch (error) {
console.log(error);
}
},
logout,
removeServer,
async clearCache({ server }) {
try {
const serversDB = database.servers;
Expand Down
Loading