move storage.js to ts
This commit is contained in:
parent
747bcb766c
commit
6bd835dfc3
|
@ -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',
|
||||
},
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
-->
|
||||
|
||||
<script type="text/javascript" src="js/components.js"></script>
|
||||
<script type="text/javascript" src="js/storage.js"></script>
|
||||
<script type="text/javascript" src="js/libtextsecure.js"></script>
|
||||
|
||||
<script type="text/javascript" src="js/views/react_wrapper_view.js"></script>
|
||||
|
|
|
@ -329,8 +329,7 @@
|
|||
initialLoadComplete,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
Whisper.events.on('openInbox', () => {
|
||||
appView.openInbox({
|
||||
|
|
107
js/storage.js
107
js/storage.js
|
@ -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);
|
||||
})();
|
|
@ -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;
|
||||
})();
|
|
@ -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);
|
||||
})();
|
|
@ -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');
|
||||
},
|
||||
};
|
||||
})();
|
|
@ -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<Props, State> {
|
|||
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, ''))) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(() => {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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<ConversationAttributes> {
|
|||
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<number>;
|
||||
const receiptMessage = new ReadReceiptMessage({
|
||||
timestamp: Date.now(),
|
||||
|
@ -1658,7 +1659,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
|
|||
// 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()
|
||||
) {
|
||||
|
|
|
@ -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<MessageAttributes> {
|
|||
}
|
||||
|
||||
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');
|
||||
|
|
|
@ -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';
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<HexKeyPair | undefined> {
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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<Ui
|
|||
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('decryptAttachmentBuffer', encryptingKey, bufferIn);
|
||||
};
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { getConversationController } from '../session/conversations';
|
||||
import { getSodium } from '../session/crypto';
|
||||
import { UserUtils } from '../session/utils';
|
||||
import { fromArrayBufferToBase64, fromHex, toHex } from '../session/utils/String';
|
||||
import { getOurPubKeyStrFromCache } from '../session/utils/User';
|
||||
import { trigger } from '../shims/events';
|
||||
|
@ -9,6 +8,14 @@ import { actions as userActions } from '../state/ducks/user';
|
|||
import { mn_decode, mn_encode } from '../session/crypto/mnemonic';
|
||||
import { ConversationTypeEnum } from '../models/conversation';
|
||||
import { SettingsKey } from '../data/settings-key';
|
||||
import {
|
||||
saveRecoveryPhrase,
|
||||
setLastProfileUpdateTimestamp,
|
||||
setLocalPubKey,
|
||||
setSignInByLinking,
|
||||
Storage,
|
||||
} from './storage';
|
||||
import { Registration } from './registration';
|
||||
|
||||
/**
|
||||
* Might throw
|
||||
|
@ -76,9 +83,9 @@ export async function signInByLinkingDevice(mnemonic: string, mnemonicLanguage:
|
|||
}
|
||||
|
||||
const identityKeyPair = await generateKeypair(mnemonic, mnemonicLanguage);
|
||||
UserUtils.setSignInByLinking(true);
|
||||
await setSignInByLinking(true);
|
||||
await createAccount(identityKeyPair);
|
||||
UserUtils.saveRecoveryPhrase(mnemonic);
|
||||
await saveRecoveryPhrase(mnemonic);
|
||||
const pubKeyString = toHex(identityKeyPair.pubKey);
|
||||
|
||||
// await for the first configuration message to come in.
|
||||
|
@ -109,8 +116,8 @@ export async function registerSingleDevice(
|
|||
const identityKeyPair = await generateKeypair(generatedMnemonic, mnemonicLanguage);
|
||||
|
||||
await createAccount(identityKeyPair);
|
||||
UserUtils.saveRecoveryPhrase(generatedMnemonic);
|
||||
await UserUtils.setLastProfileUpdateTimestamp(Date.now());
|
||||
await saveRecoveryPhrase(generatedMnemonic);
|
||||
await setLastProfileUpdateTimestamp(Date.now());
|
||||
|
||||
const pubKeyString = toHex(identityKeyPair.pubKey);
|
||||
await registrationDone(pubKeyString, profileName);
|
||||
|
@ -131,39 +138,39 @@ async function createAccount(identityKeyPair: any) {
|
|||
password = password.substring(0, password.length - 2);
|
||||
|
||||
await Promise.all([
|
||||
window.textsecure.storage.remove('identityKey'),
|
||||
window.textsecure.storage.remove('signaling_key'),
|
||||
window.textsecure.storage.remove('password'),
|
||||
window.textsecure.storage.remove('registrationId'),
|
||||
window.textsecure.storage.remove('number_id'),
|
||||
window.textsecure.storage.remove('device_name'),
|
||||
window.textsecure.storage.remove('userAgent'),
|
||||
window.textsecure.storage.remove(SettingsKey.settingsReadReceipt),
|
||||
window.textsecure.storage.remove(SettingsKey.settingsTypingIndicator),
|
||||
window.textsecure.storage.remove('regionCode'),
|
||||
window.textsecure.storage.remove('local_attachment_encrypted_key'),
|
||||
Storage.remove('identityKey'),
|
||||
Storage.remove('signaling_key'),
|
||||
Storage.remove('password'),
|
||||
Storage.remove('registrationId'),
|
||||
Storage.remove('number_id'),
|
||||
Storage.remove('device_name'),
|
||||
Storage.remove('userAgent'),
|
||||
Storage.remove(SettingsKey.settingsReadReceipt),
|
||||
Storage.remove(SettingsKey.settingsTypingIndicator),
|
||||
Storage.remove('regionCode'),
|
||||
Storage.remove('local_attachment_encrypted_key'),
|
||||
]);
|
||||
|
||||
// update our own identity key, which may have changed
|
||||
// if we're relinking after a reinstall on the master device
|
||||
const pubKeyString = toHex(identityKeyPair.pubKey);
|
||||
|
||||
await window.textsecure.storage.put('identityKey', identityKeyPair);
|
||||
await window.textsecure.storage.put('password', password);
|
||||
await Storage.put('identityKey', identityKeyPair);
|
||||
await Storage.put('password', password);
|
||||
|
||||
// disable read-receipt by default
|
||||
await window.textsecure.storage.put(SettingsKey.settingsReadReceipt, false);
|
||||
await Storage.put(SettingsKey.settingsReadReceipt, false);
|
||||
|
||||
// Enable typing indicators by default
|
||||
await window.textsecure.storage.put(SettingsKey.settingsTypingIndicator, false);
|
||||
await Storage.put(SettingsKey.settingsTypingIndicator, false);
|
||||
|
||||
await window.textsecure.storage.user.setNumberAndDeviceId(pubKeyString, 1);
|
||||
await setLocalPubKey(pubKeyString);
|
||||
}
|
||||
|
||||
async function registrationDone(ourPubkey: string, displayName: string) {
|
||||
window?.log?.info('registration done');
|
||||
|
||||
window.textsecure.storage.put('primaryDevicePubKey', ourPubkey);
|
||||
await Storage.put('primaryDevicePubKey', ourPubkey);
|
||||
|
||||
// Ensure that we always have a conversation for ourself
|
||||
const conversation = await getConversationController().getOrCreateAndWait(
|
||||
|
@ -174,10 +181,10 @@ async function registrationDone(ourPubkey: string, displayName: string) {
|
|||
await conversation.setIsApproved(true);
|
||||
const user = {
|
||||
ourNumber: getOurPubKeyStrFromCache(),
|
||||
ourPrimary: window.textsecure.storage.get('primaryDevicePubKey'),
|
||||
ourPrimary: ourPubkey,
|
||||
};
|
||||
window.inboxStore?.dispatch(userActions.userChanged(user));
|
||||
window.Whisper.Registration.markDone();
|
||||
await Registration.markDone();
|
||||
window?.log?.info('dispatching registration event');
|
||||
trigger('registration_done');
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import _ from 'lodash';
|
||||
import { getStatus } from '../notifications';
|
||||
import { UserSetting } from '../notifications/getStatus';
|
||||
import { isMacOS } from '../OS';
|
||||
import { isAudioNotificationSupported } from '../types/Settings';
|
||||
import { isWindowFocused } from './focusListener';
|
||||
import { Storage } from './storage';
|
||||
|
||||
const SettingNames = {
|
||||
COUNT: 'count',
|
||||
|
@ -106,7 +108,7 @@ function update() {
|
|||
}
|
||||
|
||||
const isAppFocused = isWindowFocused();
|
||||
const isAudioNotificationEnabled = storage.get('audio-notification') || false;
|
||||
const isAudioNotificationEnabled = (Storage.get('audio-notification') as boolean) || false;
|
||||
const audioNotificationSupported = isAudioNotificationSupported();
|
||||
// const isNotificationGroupingSupported = Settings.isNotificationGroupingSupported();
|
||||
const numNotifications = currentNotifications.length;
|
||||
|
@ -221,7 +223,7 @@ function update() {
|
|||
// ‘10 new messages’) assuming that `Notification::close` does its job.
|
||||
}
|
||||
function getUserSetting() {
|
||||
return storage.get('notification-setting') || SettingNames.MESSAGE;
|
||||
return (Storage.get('notification-setting') as UserSetting) || SettingNames.MESSAGE;
|
||||
}
|
||||
function onRemove() {
|
||||
// window.log.info('Remove notification');
|
||||
|
|
|
@ -1,21 +1,23 @@
|
|||
function markEverDone() {
|
||||
storage.put('chromiumRegistrationDoneEver', '');
|
||||
import { Storage } from './storage';
|
||||
|
||||
async function markEverDone() {
|
||||
await Storage.put('chromiumRegistrationDoneEver', '');
|
||||
}
|
||||
function markDone() {
|
||||
this.markEverDone();
|
||||
storage.put('chromiumRegistrationDone', '');
|
||||
async function markDone() {
|
||||
await markEverDone();
|
||||
await Storage.put('chromiumRegistrationDone', '');
|
||||
}
|
||||
function isDone() {
|
||||
return storage.get('chromiumRegistrationDone') === '';
|
||||
return Storage.get('chromiumRegistrationDone') === '';
|
||||
}
|
||||
function everDone() {
|
||||
return (
|
||||
storage.get('chromiumRegistrationDoneEver') === '' ||
|
||||
storage.get('chromiumRegistrationDone') === ''
|
||||
Storage.get('chromiumRegistrationDoneEver') === '' ||
|
||||
Storage.get('chromiumRegistrationDone') === ''
|
||||
);
|
||||
}
|
||||
function remove() {
|
||||
storage.remove('chromiumRegistrationDone');
|
||||
async function remove() {
|
||||
await Storage.remove('chromiumRegistrationDone');
|
||||
}
|
||||
|
||||
export const Registration = { markEverDone, markDone, isDone, everDone, remove };
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
import * as Data from '../data/data';
|
||||
|
||||
let ready = false;
|
||||
|
||||
type ValueType = string | number | boolean;
|
||||
type InsertedValueType = { id: string; value: ValueType };
|
||||
let items: Record<string, InsertedValueType>;
|
||||
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 };
|
Loading…
Reference in New Issue