diff --git a/Gruntfile.js b/Gruntfile.js
index 4a20457c7..e769102ca 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -67,9 +67,6 @@ module.exports = grunt => {
'libtextsecure/errors.js',
'libtextsecure/libsignal-protocol.js',
'libtextsecure/crypto.js',
- 'libtextsecure/storage.js',
- 'libtextsecure/storage/user.js',
- 'libtextsecure/helpers.js',
],
dest: 'js/libtextsecure.js',
},
diff --git a/background.html b/background.html
index 5004ac77f..6a3ee28aa 100644
--- a/background.html
+++ b/background.html
@@ -32,7 +32,6 @@
-->
-
diff --git a/js/background.js b/js/background.js
index 548649428..aa2f349bc 100644
--- a/js/background.js
+++ b/js/background.js
@@ -329,8 +329,7 @@
initialLoadComplete,
});
}
- });
-
+ };
Whisper.events.on('openInbox', () => {
appView.openInbox({
diff --git a/js/storage.js b/js/storage.js
deleted file mode 100644
index 017eee1b3..000000000
--- a/js/storage.js
+++ /dev/null
@@ -1,107 +0,0 @@
-/* eslint-disable more/no-then */
-
-// eslint-disable-next-line func-names
-(function() {
- 'use strict';
-
- window.Whisper = window.Whisper || {};
-
- let ready = false;
- let items;
- let callbacks = [];
-
- reset();
-
- async function put(key, value) {
- if (value === undefined) {
- throw new Error('Tried to store undefined');
- }
- if (!ready) {
- window.log.warn('Called storage.put before storage is ready. key:', key);
- }
-
- const data = { id: key, value };
-
- items[key] = data;
- await window.Signal.Data.createOrUpdateItem(data);
- }
-
- function get(key, defaultValue) {
- if (!ready) {
- window.log.warn('Called storage.get before storage is ready. key:', key);
- }
-
- const item = items[key];
- if (!item) {
- return defaultValue;
- }
-
- return item.value;
- }
-
- async function remove(key) {
- if (!ready) {
- window.log.warn('Called storage.get before storage is ready. key:', key);
- }
-
- delete items[key];
- await window.Signal.Data.removeItemById(key);
- }
-
- function onready(callback) {
- if (ready) {
- callback();
- } else {
- callbacks.push(callback);
- }
- }
-
- function callListeners() {
- if (ready) {
- callbacks.forEach(callback => callback());
- callbacks = [];
- }
- }
-
- async function fetch() {
- this.reset();
- const array = await window.Signal.Data.getAllItems();
-
- for (let i = 0, max = array.length; i < max; i += 1) {
- const item = array[i];
- const { id } = item;
- items[id] = item;
- }
-
- ready = true;
- callListeners();
- }
-
- function reset() {
- ready = false;
- items = Object.create(null);
- }
-
- const storage = {
- fetch,
- put,
- get,
- remove,
- onready,
- reset,
- };
-
- // Keep a reference to this storage system, since there are scenarios where
- // we need to replace it with the legacy storage system for a while.
- window.newStorage = storage;
-
- window.textsecure = window.textsecure || {};
- window.textsecure.storage = window.textsecure.storage || {};
-
- window.installStorage = newStorage => {
- window.storage = newStorage;
- window.textsecure.storage.impl = newStorage;
- };
-
- window.installStorage(storage);
-})();
diff --git a/libtextsecure/helpers.js b/libtextsecure/helpers.js
deleted file mode 100644
index 87574d975..000000000
--- a/libtextsecure/helpers.js
+++ /dev/null
@@ -1,76 +0,0 @@
-/* global window, dcodeIO */
-
-/* eslint-disable no-proto, no-restricted-syntax, guard-for-in */
-
-window.textsecure = window.textsecure || {};
-
-/** *******************************
- *** Type conversion utilities ***
- ******************************** */
-// Strings/arrays
-// TODO: Throw all this shit in favor of consistent types
-// TODO: Namespace
-const StaticByteBufferProto = new dcodeIO.ByteBuffer().__proto__;
-const StaticArrayBufferProto = new ArrayBuffer().__proto__;
-const StaticUint8ArrayProto = new Uint8Array().__proto__;
-function getString(thing) {
- if (thing === Object(thing)) {
- if (thing.__proto__ === StaticUint8ArrayProto) {
- return String.fromCharCode.apply(null, thing);
- }
- if (thing.__proto__ === StaticArrayBufferProto) {
- return getString(new Uint8Array(thing));
- }
- if (thing.__proto__ === StaticByteBufferProto) {
- return thing.toString('binary');
- }
- }
- return thing;
-}
-
-function getStringable(thing) {
- return (
- typeof thing === 'string' ||
- typeof thing === 'number' ||
- typeof thing === 'boolean' ||
- (thing === Object(thing) &&
- (thing.__proto__ === StaticArrayBufferProto ||
- thing.__proto__ === StaticUint8ArrayProto ||
- thing.__proto__ === StaticByteBufferProto))
- );
-}
-
-// Number formatting utils
-window.textsecure.utils = (() => {
- const self = {};
- self.unencodeNumber = number => number.split('.');
- self.isNumberSane = number => number[0] === '+' && /^[0-9]+$/.test(number.substring(1));
-
- /** ************************
- *** JSON'ing Utilities ***
- ************************* */
- function ensureStringed(thing) {
- if (getStringable(thing)) {
- return getString(thing);
- } else if (thing instanceof Array) {
- const res = [];
- for (let i = 0; i < thing.length; i += 1) {
- res[i] = ensureStringed(thing[i]);
- }
- return res;
- } else if (thing === Object(thing)) {
- const res = {};
- for (const key in thing) {
- res[key] = ensureStringed(thing[key]);
- }
- return res;
- } else if (thing === null) {
- return null;
- }
- throw new Error(`unsure of how to jsonify object of type ${typeof thing}`);
- }
-
- self.jsonThing = thing => JSON.stringify(ensureStringed(thing));
-
- return self;
-})();
diff --git a/libtextsecure/storage.js b/libtextsecure/storage.js
deleted file mode 100644
index 300f7e913..000000000
--- a/libtextsecure/storage.js
+++ /dev/null
@@ -1,40 +0,0 @@
-/* global window, textsecure, localStorage */
-
-// eslint-disable-next-line func-names
-(function() {
- /** **********************************************
- *** Utilities to store data in local storage ***
- *********************************************** */
- window.textsecure = window.textsecure || {};
- window.textsecure.storage = window.textsecure.storage || {};
-
- // Overrideable storage implementation
- window.textsecure.storage.impl = window.textsecure.storage.impl || {
- /** ***************************
- *** Base Storage Routines ***
- **************************** */
- put(key, value) {
- if (value === undefined) {
- throw new Error('Tried to store undefined');
- }
- localStorage.setItem(`${key}`, textsecure.utils.jsonThing(value));
- },
-
- get(key, defaultValue) {
- const value = localStorage.getItem(`${key}`);
- if (value === null) {
- return defaultValue;
- }
- return JSON.parse(value);
- },
-
- remove(key) {
- localStorage.removeItem(`${key}`);
- },
- };
-
- window.textsecure.storage.put = (key, value) => textsecure.storage.impl.put(key, value);
- window.textsecure.storage.get = (key, defaultValue) =>
- textsecure.storage.impl.get(key, defaultValue);
- window.textsecure.storage.remove = key => textsecure.storage.impl.remove(key);
-})();
diff --git a/libtextsecure/storage/user.js b/libtextsecure/storage/user.js
deleted file mode 100644
index b4b771e88..000000000
--- a/libtextsecure/storage/user.js
+++ /dev/null
@@ -1,70 +0,0 @@
-/* global textsecure, window */
-
-// eslint-disable-next-line func-names
-(function() {
- /** *******************************************
- *** Utilities to store data about the user ***
- ********************************************* */
- window.textsecure = window.textsecure || {};
- window.textsecure.storage = window.textsecure.storage || {};
-
- window.textsecure.storage.user = {
- setNumberAndDeviceId(number, deviceId, deviceName) {
- textsecure.storage.put('number_id', `${number}.${deviceId}`);
- if (deviceName) {
- textsecure.storage.put('device_name', deviceName);
- }
- },
-
- getNumber() {
- const numberId = textsecure.storage.get('number_id');
- if (numberId === undefined) {
- return undefined;
- }
- return textsecure.utils.unencodeNumber(numberId)[0];
- },
-
- isSignInByLinking() {
- const isSignInByLinking = textsecure.storage.get('is_sign_in_by_linking');
- if (isSignInByLinking === undefined) {
- return false;
- }
- return isSignInByLinking;
- },
-
- setSignInByLinking(isLinking) {
- textsecure.storage.put('is_sign_in_by_linking', isLinking);
- },
-
- isSignWithRecoveryPhrase() {
- const isRecoveryPhraseUsed = textsecure.storage.get('is_sign_in_recovery_phrase');
- if (isRecoveryPhraseUsed === undefined) {
- return false;
- }
- return isRecoveryPhraseUsed;
- },
- setSignWithRecoveryPhrase(isRecoveryPhraseUsed) {
- textsecure.storage.put('is_sign_in_recovery_phrase', isRecoveryPhraseUsed);
- },
-
- getLastProfileUpdateTimestamp() {
- return textsecure.storage.get('last_profile_update_timestamp');
- },
-
- setLastProfileUpdateTimestamp(lastUpdateTimestamp) {
- textsecure.storage.put('last_profile_update_timestamp', lastUpdateTimestamp);
- },
-
- getDeviceId() {
- const numberId = textsecure.storage.get('number_id');
- if (numberId === undefined) {
- return undefined;
- }
- return textsecure.utils.unencodeNumber(numberId)[1];
- },
-
- getDeviceName() {
- return textsecure.storage.get('device_name');
- },
- };
-})();
diff --git a/ts/components/conversation/SessionConversation.tsx b/ts/components/conversation/SessionConversation.tsx
index cc02b2862..b3e993e73 100644
--- a/ts/components/conversation/SessionConversation.tsx
+++ b/ts/components/conversation/SessionConversation.tsx
@@ -20,7 +20,7 @@ import { SplitViewContainer } from '../SplitViewContainer';
import { LightboxGallery, MediaItemType } from '../lightbox/LightboxGallery';
import { getLastMessageInConversation, getPubkeysInPublicConversation } from '../../data/data';
import { getConversationController } from '../../session/conversations';
-import { ToastUtils, UserUtils } from '../../session/utils';
+import { ToastUtils } from '../../session/utils';
import {
openConversationToSpecificMessage,
quoteMessage,
@@ -50,6 +50,7 @@ import { blobToArrayBuffer } from 'blob-util';
import { MAX_ATTACHMENT_FILESIZE_BYTES } from '../../session/constants';
import { ConversationMessageRequestButtons } from './ConversationRequestButtons';
import { ConversationRequestinfo } from './ConversationRequestInfo';
+import { getCurrentRecoveryPhrase } from '../../util/storage';
// tslint:disable: jsx-curly-spacing
interface State {
@@ -176,8 +177,7 @@ export class SessionConversation extends React.Component {
await this.scrollToNow();
};
- // const recoveryPhrase = window.textsecure.storage.get('mnemonic');
- const recoveryPhrase = UserUtils.getCurrentRecoveryPhrase();
+ const recoveryPhrase = getCurrentRecoveryPhrase() as string;
// string replace to fix case where pasted text contains invis characters causing false negatives
if (msg.body.replace(/\s/g, '').includes(recoveryPhrase.replace(/\s/g, ''))) {
diff --git a/ts/components/dialog/EditProfileDialog.tsx b/ts/components/dialog/EditProfileDialog.tsx
index b115a44db..4447e1020 100644
--- a/ts/components/dialog/EditProfileDialog.tsx
+++ b/ts/components/dialog/EditProfileDialog.tsx
@@ -21,6 +21,7 @@ import { MAX_USERNAME_LENGTH } from '../registration/RegistrationStages';
import { SessionWrapperModal } from '../SessionWrapperModal';
import { pickFileForAvatar } from '../../types/attachments/VisualAttachment';
import { sanitizeSessionUsername } from '../../session/utils/String';
+import { setLastProfileUpdateTimestamp } from '../../util/storage';
interface State {
profileName: string;
@@ -319,7 +320,7 @@ async function commitProfileEdits(newName: string, scaledAvatarUrl: string | nul
});
// might be good to not trigger a sync if the name did not change
await conversation.commit();
- UserUtils.setLastProfileUpdateTimestamp(Date.now());
+ await setLastProfileUpdateTimestamp(Date.now());
await SyncUtils.forceSyncConfigurationNowIfNeeded(true);
}
diff --git a/ts/components/dialog/SessionSeedModal.tsx b/ts/components/dialog/SessionSeedModal.tsx
index 08b8f4f2a..c24c66373 100644
--- a/ts/components/dialog/SessionSeedModal.tsx
+++ b/ts/components/dialog/SessionSeedModal.tsx
@@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react';
-import { ToastUtils, UserUtils } from '../../session/utils';
+import { ToastUtils } from '../../session/utils';
import { PasswordUtil } from '../../util';
import { getPasswordHash } from '../../data/data';
import { QRCode } from 'react-qr-svg';
@@ -10,6 +10,7 @@ import { recoveryPhraseModal } from '../../state/ducks/modalDialog';
import { useDispatch } from 'react-redux';
import { SessionButton, SessionButtonColor } from '../basic/SessionButton';
import { SessionWrapperModal } from '../SessionWrapperModal';
+import { getCurrentRecoveryPhrase } from '../../util/storage';
interface PasswordProps {
setPasswordValid: (val: boolean) => any;
@@ -168,7 +169,7 @@ const SessionSeedModalInner = (props: ModalInnerProps) => {
if (recoveryPhrase) {
return false;
}
- const newRecoveryPhrase = UserUtils.getCurrentRecoveryPhrase();
+ const newRecoveryPhrase = getCurrentRecoveryPhrase();
setRecoveryPhrase(newRecoveryPhrase);
setLoadingSeed(false);
diff --git a/ts/components/leftpane/LeftPaneSectionHeader.tsx b/ts/components/leftpane/LeftPaneSectionHeader.tsx
index a2610e7f4..f75f2a227 100644
--- a/ts/components/leftpane/LeftPaneSectionHeader.tsx
+++ b/ts/components/leftpane/LeftPaneSectionHeader.tsx
@@ -7,9 +7,9 @@ import { recoveryPhraseModal } from '../../state/ducks/modalDialog';
import { Flex } from '../basic/Flex';
import { getFocusedSection, getOverlayMode } from '../../state/selectors/section';
import { SectionType, setOverlayMode } from '../../state/ducks/section';
-import { UserUtils } from '../../session/utils';
import { SessionButton, SessionButtonType } from '../basic/SessionButton';
import { SessionIcon, SessionIconButton } from '../icon';
+import { isSignWithRecoveryPhrase } from '../../util/storage';
const SectionTitle = styled.h1`
padding: 0 var(--margins-sm);
@@ -94,7 +94,7 @@ const BannerInner = () => {
export const LeftPaneBanner = () => {
const section = useSelector(getFocusedSection);
- const isSignInWithRecoveryPhrase = UserUtils.isSignWithRecoveryPhrase();
+ const isSignInWithRecoveryPhrase = isSignWithRecoveryPhrase();
if (section !== SectionType.Message || isSignInWithRecoveryPhrase) {
return null;
diff --git a/ts/components/registration/RegistrationStages.tsx b/ts/components/registration/RegistrationStages.tsx
index 80b0f1b0f..4f1f8a63f 100644
--- a/ts/components/registration/RegistrationStages.tsx
+++ b/ts/components/registration/RegistrationStages.tsx
@@ -5,7 +5,7 @@ import { createOrUpdateItem, removeAll } from '../../data/data';
import { getSwarmPollingInstance } from '../../session/apis/snode_api';
import { getConversationController } from '../../session/conversations';
import { mn_decode } from '../../session/crypto/mnemonic';
-import { PromiseUtils, StringUtils, ToastUtils, UserUtils } from '../../session/utils';
+import { PromiseUtils, StringUtils, ToastUtils } from '../../session/utils';
import { TaskTimedOutError } from '../../session/utils/Promise';
import { trigger } from '../../shims/events';
import {
@@ -15,14 +15,15 @@ import {
signInByLinkingDevice,
} from '../../util/accountManager';
import { fromHex } from '../../session/utils/String';
+import { setSignInByLinking, setSignWithRecoveryPhrase, Storage } from '../../util/storage';
export const MAX_USERNAME_LENGTH = 26;
// tslint:disable: use-simple-attributes
export async function resetRegistration() {
await removeAll();
- await window.storage.reset();
- await window.storage.fetch();
+ Storage.reset();
+ await Storage.fetch();
getConversationController().reset();
await getConversationController().load();
}
@@ -64,7 +65,7 @@ export async function signUp(signUpDetails: {
value: true,
timestamp: Date.now(),
});
- UserUtils.setSignWithRecoveryPhrase(false);
+ setSignWithRecoveryPhrase(false);
trigger('openInbox');
} catch (e) {
await resetRegistration();
@@ -95,7 +96,7 @@ export async function signInWithRecovery(signInDetails: {
await resetRegistration();
await registerSingleDevice(userRecoveryPhrase, 'english', trimName);
- UserUtils.setSignWithRecoveryPhrase(true);
+ setSignWithRecoveryPhrase(true);
trigger('openInbox');
} catch (e) {
@@ -120,10 +121,10 @@ export async function signInWithLinking(signInDetails: { userRecoveryPhrase: str
await getSwarmPollingInstance().start();
await PromiseUtils.waitForTask(done => {
- window.Whisper.events.on('configurationMessageReceived', (displayName: string) => {
+ window.Whisper.events.on('configurationMessageReceived', async (displayName: string) => {
window.Whisper.events.off('configurationMessageReceived');
- UserUtils.setSignInByLinking(false);
- UserUtils.setSignWithRecoveryPhrase(true);
+ await setSignInByLinking(false);
+ await setSignWithRecoveryPhrase(true);
done(displayName);
displayNameFromNetwork = displayName;
diff --git a/ts/components/registration/SessionRegistrationView.tsx b/ts/components/registration/SessionRegistrationView.tsx
index a830c5244..41919d3ef 100644
--- a/ts/components/registration/SessionRegistrationView.tsx
+++ b/ts/components/registration/SessionRegistrationView.tsx
@@ -4,9 +4,9 @@ import { AccentText } from './AccentText';
import { RegistrationStages } from './RegistrationStages';
import { SessionIcon } from '../icon';
import { SessionToastContainer } from '../SessionToastContainer';
-import { setSignInByLinking } from '../../session/utils/User';
import { SessionTheme } from '../../state/ducks/SessionTheme';
import { Flex } from '../basic/Flex';
+import { setSignInByLinking } from '../../util/storage';
export const SessionRegistrationView = () => {
useEffect(() => {
diff --git a/ts/data/data.ts b/ts/data/data.ts
index 733b1c64a..f8ded917c 100644
--- a/ts/data/data.ts
+++ b/ts/data/data.ts
@@ -19,6 +19,7 @@ import { PubKey } from '../session/types';
import { fromArrayBufferToBase64, fromBase64ToArrayBuffer } from '../session/utils/String';
import { ReduxConversationType } from '../state/ducks/conversations';
import { ExpirationTimerOptions } from '../util/expiringMessages';
+import { Storage } from '../util/storage';
import { channels } from './channels';
import { channelsToMake as channelstoMakeOpenGroupV2 } from './opengroups';
@@ -469,7 +470,7 @@ export async function generateAttachmentKeyIfEmpty() {
value: encryptingKey,
});
// be sure to write the new key to the cache. so we can access it straight away
- window.textsecure.storage.put('local_attachment_encrypted_key', encryptingKey);
+ await Storage.put('local_attachment_encrypted_key', encryptingKey);
}
}
diff --git a/ts/interactions/conversationInteractions.ts b/ts/interactions/conversationInteractions.ts
index 3f3c49cf8..2e035b4df 100644
--- a/ts/interactions/conversationInteractions.ts
+++ b/ts/interactions/conversationInteractions.ts
@@ -45,6 +45,7 @@ import { perfEnd, perfStart } from '../session/utils/Performance';
import { processNewAttachment } from '../types/MessageAttachment';
import { urlToBlob } from '../types/attachments/VisualAttachment';
import { MIME } from '../types';
+import { setLastProfileUpdateTimestamp } from '../util/storage';
export const getCompleteUrlForV2ConvoId = async (convoId: string) => {
if (convoId.match(openGroupV2ConversationIdRegex)) {
@@ -462,7 +463,7 @@ export async function uploadOurAvatar(newAvatarDecrypted?: ArrayBuffer) {
await createOrUpdateItem({ id: lastAvatarUploadTimestamp, value: newTimestampReupload });
if (newAvatarDecrypted) {
- UserUtils.setLastProfileUpdateTimestamp(Date.now());
+ await setLastProfileUpdateTimestamp(Date.now());
await SyncUtils.forceSyncConfigurationNowIfNeeded(true);
} else {
window.log.info(
diff --git a/ts/models/conversation.ts b/ts/models/conversation.ts
index fd94a6776..5e2b58bca 100644
--- a/ts/models/conversation.ts
+++ b/ts/models/conversation.ts
@@ -64,6 +64,7 @@ import {
import { getOurPubKeyStrFromCache } from '../session/utils/User';
import { MessageRequestResponse } from '../session/messages/outgoing/controlMessage/MessageRequestResponse';
import { Notifications } from '../util/notifications';
+import { Storage } from '../util/storage';
export enum ConversationTypeEnum {
GROUP = 'group',
@@ -1146,10 +1147,10 @@ export class ConversationModel extends Backbone.Model {
if (this.isPrivate() && read.length && options.sendReadReceipts) {
window?.log?.info(
`Sending ${read.length} read receipts?`,
- window.storage.get(SettingsKey.settingsReadReceipt) || false
+ Storage.get(SettingsKey.settingsReadReceipt) || false
);
const dontSendReceipt = this.isBlocked() || this.isIncomingRequest();
- if (window.storage.get(SettingsKey.settingsReadReceipt) && !dontSendReceipt) {
+ if (Storage.get(SettingsKey.settingsReadReceipt) && !dontSendReceipt) {
const timestamps = _.map(read, 'timestamp').filter(t => !!t) as Array;
const receiptMessage = new ReadReceiptMessage({
timestamp: Date.now(),
@@ -1658,7 +1659,7 @@ export class ConversationModel extends Backbone.Model {
// for typing to happen, this must be a private unblocked active convo, and the settings to be on
if (
!this.isActive() ||
- !window.storage.get(SettingsKey.settingsTypingIndicator) ||
+ !Storage.get(SettingsKey.settingsTypingIndicator) ||
this.isBlocked() ||
!this.isPrivate()
) {
diff --git a/ts/models/message.ts b/ts/models/message.ts
index 9148c15eb..4f066ef2a 100644
--- a/ts/models/message.ts
+++ b/ts/models/message.ts
@@ -62,6 +62,7 @@ import {
} from '../types/MessageAttachment';
import { ExpirationTimerOptions } from '../util/expiringMessages';
import { Notifications } from '../util/notifications';
+import { Storage } from '../util/storage';
// tslint:disable: cyclomatic-complexity
/**
@@ -428,7 +429,7 @@ export class MessageModel extends Backbone.Model {
}
const readBy = this.get('read_by') || [];
- if (window.storage.get(SettingsKey.settingsReadReceipt) && readBy.length > 0) {
+ if (Storage.get(SettingsKey.settingsReadReceipt) && readBy.length > 0) {
return 'read';
}
const sent = this.get('sent');
diff --git a/ts/notifications/getStatus.ts b/ts/notifications/getStatus.ts
index c837b132a..379e95e59 100644
--- a/ts/notifications/getStatus.ts
+++ b/ts/notifications/getStatus.ts
@@ -14,7 +14,7 @@ interface Status {
type: Type;
}
-type UserSetting = 'off' | 'count' | 'name' | 'message';
+export type UserSetting = 'off' | 'count' | 'name' | 'message';
type Type = 'ok' | 'disabled' | 'appIsFocused' | 'noNotifications' | 'userSetting';
diff --git a/ts/receiver/configMessage.ts b/ts/receiver/configMessage.ts
index 8c3801673..e76ccf46d 100644
--- a/ts/receiver/configMessage.ts
+++ b/ts/receiver/configMessage.ts
@@ -17,13 +17,14 @@ import { handleNewClosedGroup } from './closedGroups';
import { updateProfileOneAtATime } from './dataMessage';
import { EnvelopePlus } from './types';
import { ConversationInteraction } from '../interactions';
+import { getLastProfileUpdateTimestamp, setLastProfileUpdateTimestamp } from '../util/storage';
async function handleOurProfileUpdate(
sentAt: number | Long,
configMessage: SignalService.ConfigurationMessage,
ourPubkey: string
) {
- const latestProfileUpdateTimestamp = UserUtils.getLastProfileUpdateTimestamp();
+ const latestProfileUpdateTimestamp = getLastProfileUpdateTimestamp();
if (!latestProfileUpdateTimestamp || sentAt > latestProfileUpdateTimestamp) {
window?.log?.info(
`Handling our profileUdpate ourLastUpdate:${latestProfileUpdateTimestamp}, envelope sent at: ${sentAt}`
@@ -41,7 +42,7 @@ async function handleOurProfileUpdate(
profilePicture,
};
await updateProfileOneAtATime(ourConversation, lokiProfile, profileKey);
- UserUtils.setLastProfileUpdateTimestamp(_.toNumber(sentAt));
+ await setLastProfileUpdateTimestamp(_.toNumber(sentAt));
// do not trigger a signin by linking if the display name is empty
if (displayName) {
trigger(configurationMessageReceived, displayName);
diff --git a/ts/receiver/contentMessage.ts b/ts/receiver/contentMessage.ts
index 90a8adb71..7a678ba86 100644
--- a/ts/receiver/contentMessage.ts
+++ b/ts/receiver/contentMessage.ts
@@ -20,6 +20,7 @@ import { handleCallMessage } from './callMessage';
import { SettingsKey } from '../data/settings-key';
import { ConversationTypeEnum } from '../models/conversation';
import { ReadReceipts } from '../util/readReceipts';
+import { Storage } from '../util/storage';
export async function handleSwarmContentMessage(envelope: EnvelopePlus, messageHash: string) {
try {
@@ -491,7 +492,7 @@ async function handleTypingMessage(
await removeFromCache(envelope);
// We don't do anything with incoming typing messages if the setting is disabled
- if (!window.storage.get(SettingsKey.settingsTypingIndicator)) {
+ if (!Storage.get(SettingsKey.settingsTypingIndicator)) {
return;
}
diff --git a/ts/session/utils/User.ts b/ts/session/utils/User.ts
index 02bfcd26c..f3c3266e7 100644
--- a/ts/session/utils/User.ts
+++ b/ts/session/utils/User.ts
@@ -6,6 +6,7 @@ import { PubKey } from '../types';
import { fromHexToArray, toHex } from './String';
import { getConversationController } from '../conversations';
import { LokiProfile } from '../../types/Message';
+import { getNumber, Storage } from '../../util/storage';
export type HexKeyPair = {
pubKey: string;
@@ -29,7 +30,7 @@ export function isUsFromCache(pubKey: string | PubKey | undefined): boolean {
* Returns the public key of this current device as a STRING, or throws an error
*/
export function getOurPubKeyStrFromCache(): string {
- const ourNumber = window.textsecure.storage.user.getNumber();
+ const ourNumber = getNumber();
if (!ourNumber) {
throw new Error('ourNumber is not set');
}
@@ -78,27 +79,11 @@ export async function getUserED25519KeyPair(): Promise {
return undefined;
}
-export function isSignInByLinking(): boolean {
- return window.textsecure.storage.user.isSignInByLinking();
-}
-
-export function setSignInByLinking(isLinking: boolean) {
- window.textsecure.storage.user.setSignInByLinking(isLinking);
-}
-
-export function isSignWithRecoveryPhrase(): boolean {
- return window.textsecure.storage.user.isSignWithRecoveryPhrase();
-}
-
-export function setSignWithRecoveryPhrase(isLinking: boolean) {
- window.textsecure.storage.user.setSignWithRecoveryPhrase(isLinking);
-}
-
export function getOurProfile(): LokiProfile | undefined {
try {
// Secondary devices have their profile stored
// in their primary device's conversation
- const ourNumber = window.storage.get('primaryDevicePubKey');
+ const ourNumber = Storage.get('primaryDevicePubKey') as string;
const ourConversation = getConversationController().get(ourNumber);
const ourProfileKeyHex = ourConversation.get('profileKey');
const profileKeyAsBytes = ourProfileKeyHex ? fromHexToArray(ourProfileKeyHex) : null;
@@ -115,19 +100,3 @@ export function getOurProfile(): LokiProfile | undefined {
return undefined;
}
}
-
-export function getLastProfileUpdateTimestamp(): number | undefined {
- return window.textsecure.storage.user.getLastProfileUpdateTimestamp();
-}
-
-export function setLastProfileUpdateTimestamp(lastUpdateTimestamp: number) {
- return window.textsecure.storage.user.setLastProfileUpdateTimestamp(lastUpdateTimestamp);
-}
-
-export function getCurrentRecoveryPhrase() {
- return window.textsecure.storage.get('mnemonic');
-}
-
-export function saveRecoveryPhrase(mnemonic: string) {
- return window.textsecure.storage.put('mnemonic', mnemonic);
-}
diff --git a/ts/state/selectors/conversations.ts b/ts/state/selectors/conversations.ts
index 4fbed7e74..f040e5b82 100644
--- a/ts/state/selectors/conversations.ts
+++ b/ts/state/selectors/conversations.ts
@@ -33,6 +33,7 @@ import { GenericReadableMessageSelectorProps } from '../../components/conversati
import { LightBoxOptions } from '../../components/conversation/SessionConversation';
import { getConversationController } from '../../session/conversations';
import { UserUtils } from '../../session/utils';
+import { Storage } from '../../util/storage';
export const getConversations = (state: StateType): ConversationsStateType => state.conversations;
@@ -129,7 +130,7 @@ export const isPublicGroupConversation = createSelector(
export const getOurPrimaryConversation = createSelector(
getConversations,
(state: ConversationsStateType): ReduxConversationType =>
- state.conversationLookup[window.storage.get('primaryDevicePubKey')]
+ state.conversationLookup[Storage.get('primaryDevicePubKey') as string]
);
const getMessagesOfSelectedConversation = createSelector(
diff --git a/ts/types/Attachment.ts b/ts/types/Attachment.ts
index a8263a623..59fe9f3d6 100644
--- a/ts/types/Attachment.ts
+++ b/ts/types/Attachment.ts
@@ -7,6 +7,7 @@ import { SignalService } from '../protobuf';
import { isImageTypeSupported, isVideoTypeSupported } from '../util/GoogleChrome';
import { fromHexToArray } from '../session/utils/String';
import { ATTACHMENT_DEFAULT_MAX_SIDE } from '../util/attachmentsUtil';
+import { Storage } from '../util/storage';
const MAX_WIDTH = 200;
const MAX_HEIGHT = MAX_WIDTH;
@@ -396,9 +397,8 @@ export const encryptAttachmentBuffer = async (bufferIn: ArrayBuffer) => {
if (!isArrayBuffer(bufferIn)) {
throw new TypeError("'bufferIn' must be an array buffer");
}
- const encryptingKey = fromHexToArray(
- window.textsecure.storage.get('local_attachment_encrypted_key')
- );
+ const key = Storage.get('local_attachment_encrypted_key') as string;
+ const encryptingKey = fromHexToArray(key);
return window.callWorker('encryptAttachmentBuffer', encryptingKey, bufferIn);
};
@@ -406,8 +406,7 @@ export const decryptAttachmentBuffer = async (bufferIn: ArrayBuffer): Promise;
+let callbacks: Array<() => void> = [];
+
+reset();
+
+async function put(key: string, value: ValueType) {
+ if (value === undefined) {
+ throw new Error('Tried to store undefined');
+ }
+ if (!ready) {
+ window.log.warn('Called storage.put before storage is ready. key:', key);
+ }
+
+ const data: InsertedValueType = { id: key, value };
+
+ items[key] = data;
+ await Data.createOrUpdateItem(data);
+}
+
+function get(key: string, defaultValue?: ValueType) {
+ if (!ready) {
+ window.log.warn('Called storage.get before storage is ready. key:', key);
+ }
+
+ const item = items[key];
+ if (!item) {
+ return defaultValue;
+ }
+
+ return item.value;
+}
+
+async function remove(key: string) {
+ if (!ready) {
+ window.log.warn('Called storage.get before storage is ready. key:', key);
+ }
+
+ // tslint:disable-next-line: no-dynamic-delete
+ delete items[key];
+ await Data.removeItemById(key);
+}
+
+function onready(callback: () => void) {
+ if (ready) {
+ callback();
+ } else {
+ callbacks.push(callback);
+ }
+}
+
+function callListeners() {
+ if (ready) {
+ callbacks.forEach(callback => {
+ callback();
+ });
+ callbacks = [];
+ }
+}
+
+async function fetch() {
+ reset();
+ const array = await Data.getAllItems();
+
+ // tslint:disable-next-line: one-variable-per-declaration
+ for (let i = 0, max = array.length; i < max; i += 1) {
+ const item = array[i];
+ const { id } = item;
+ items[id] = item;
+ }
+
+ ready = true;
+ callListeners();
+}
+
+function reset() {
+ ready = false;
+ items = Object.create(null);
+}
+
+export async function setLocalPubKey(pubkey: string) {
+ await put('number_id', `${pubkey}.1`);
+}
+
+export function getNumber() {
+ const numberId = get('number_id') as string | undefined;
+ if (numberId === undefined) {
+ return undefined;
+ }
+ return numberId.split('.')[0];
+}
+
+export function isSignInByLinking() {
+ const isByLinking = get('is_sign_in_by_linking');
+ if (isByLinking === undefined) {
+ return false;
+ }
+ return isByLinking;
+}
+
+export async function setSignInByLinking(isLinking: boolean) {
+ await put('is_sign_in_by_linking', isLinking);
+}
+
+export function isSignWithRecoveryPhrase() {
+ const isRecoveryPhraseUsed = get('is_sign_in_recovery_phrase');
+ if (isRecoveryPhraseUsed === undefined) {
+ return false;
+ }
+ return isRecoveryPhraseUsed;
+}
+
+export async function setSignWithRecoveryPhrase(isRecoveryPhraseUsed: boolean) {
+ await put('is_sign_in_recovery_phrase', isRecoveryPhraseUsed);
+}
+
+export function getLastProfileUpdateTimestamp() {
+ return get('last_profile_update_timestamp');
+}
+
+export async function setLastProfileUpdateTimestamp(lastUpdateTimestamp: number) {
+ await put('last_profile_update_timestamp', lastUpdateTimestamp);
+}
+
+export function getCurrentRecoveryPhrase() {
+ return Storage.get('mnemonic') as string;
+}
+
+export async function saveRecoveryPhrase(mnemonic: string) {
+ return Storage.put('mnemonic', mnemonic);
+}
+
+export const Storage = { fetch, put, get, remove, onready, reset };