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/errors.js',
|
||||||
'libtextsecure/libsignal-protocol.js',
|
'libtextsecure/libsignal-protocol.js',
|
||||||
'libtextsecure/crypto.js',
|
'libtextsecure/crypto.js',
|
||||||
'libtextsecure/storage.js',
|
|
||||||
'libtextsecure/storage/user.js',
|
|
||||||
'libtextsecure/helpers.js',
|
|
||||||
],
|
],
|
||||||
dest: 'js/libtextsecure.js',
|
dest: 'js/libtextsecure.js',
|
||||||
},
|
},
|
||||||
|
|
|
@ -32,7 +32,6 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<script type="text/javascript" src="js/components.js"></script>
|
<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/libtextsecure.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript" src="js/views/react_wrapper_view.js"></script>
|
<script type="text/javascript" src="js/views/react_wrapper_view.js"></script>
|
||||||
|
|
|
@ -329,8 +329,7 @@
|
||||||
initialLoadComplete,
|
initialLoadComplete,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
|
||||||
Whisper.events.on('openInbox', () => {
|
Whisper.events.on('openInbox', () => {
|
||||||
appView.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 { LightboxGallery, MediaItemType } from '../lightbox/LightboxGallery';
|
||||||
import { getLastMessageInConversation, getPubkeysInPublicConversation } from '../../data/data';
|
import { getLastMessageInConversation, getPubkeysInPublicConversation } from '../../data/data';
|
||||||
import { getConversationController } from '../../session/conversations';
|
import { getConversationController } from '../../session/conversations';
|
||||||
import { ToastUtils, UserUtils } from '../../session/utils';
|
import { ToastUtils } from '../../session/utils';
|
||||||
import {
|
import {
|
||||||
openConversationToSpecificMessage,
|
openConversationToSpecificMessage,
|
||||||
quoteMessage,
|
quoteMessage,
|
||||||
|
@ -50,6 +50,7 @@ import { blobToArrayBuffer } from 'blob-util';
|
||||||
import { MAX_ATTACHMENT_FILESIZE_BYTES } from '../../session/constants';
|
import { MAX_ATTACHMENT_FILESIZE_BYTES } from '../../session/constants';
|
||||||
import { ConversationMessageRequestButtons } from './ConversationRequestButtons';
|
import { ConversationMessageRequestButtons } from './ConversationRequestButtons';
|
||||||
import { ConversationRequestinfo } from './ConversationRequestInfo';
|
import { ConversationRequestinfo } from './ConversationRequestInfo';
|
||||||
|
import { getCurrentRecoveryPhrase } from '../../util/storage';
|
||||||
// tslint:disable: jsx-curly-spacing
|
// tslint:disable: jsx-curly-spacing
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
|
@ -176,8 +177,7 @@ export class SessionConversation extends React.Component<Props, State> {
|
||||||
await this.scrollToNow();
|
await this.scrollToNow();
|
||||||
};
|
};
|
||||||
|
|
||||||
// const recoveryPhrase = window.textsecure.storage.get('mnemonic');
|
const recoveryPhrase = getCurrentRecoveryPhrase() as string;
|
||||||
const recoveryPhrase = UserUtils.getCurrentRecoveryPhrase();
|
|
||||||
|
|
||||||
// string replace to fix case where pasted text contains invis characters causing false negatives
|
// 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, ''))) {
|
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 { SessionWrapperModal } from '../SessionWrapperModal';
|
||||||
import { pickFileForAvatar } from '../../types/attachments/VisualAttachment';
|
import { pickFileForAvatar } from '../../types/attachments/VisualAttachment';
|
||||||
import { sanitizeSessionUsername } from '../../session/utils/String';
|
import { sanitizeSessionUsername } from '../../session/utils/String';
|
||||||
|
import { setLastProfileUpdateTimestamp } from '../../util/storage';
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
profileName: string;
|
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
|
// might be good to not trigger a sync if the name did not change
|
||||||
await conversation.commit();
|
await conversation.commit();
|
||||||
UserUtils.setLastProfileUpdateTimestamp(Date.now());
|
await setLastProfileUpdateTimestamp(Date.now());
|
||||||
await SyncUtils.forceSyncConfigurationNowIfNeeded(true);
|
await SyncUtils.forceSyncConfigurationNowIfNeeded(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { ToastUtils, UserUtils } from '../../session/utils';
|
import { ToastUtils } from '../../session/utils';
|
||||||
import { PasswordUtil } from '../../util';
|
import { PasswordUtil } from '../../util';
|
||||||
import { getPasswordHash } from '../../data/data';
|
import { getPasswordHash } from '../../data/data';
|
||||||
import { QRCode } from 'react-qr-svg';
|
import { QRCode } from 'react-qr-svg';
|
||||||
|
@ -10,6 +10,7 @@ import { recoveryPhraseModal } from '../../state/ducks/modalDialog';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
import { SessionButton, SessionButtonColor } from '../basic/SessionButton';
|
import { SessionButton, SessionButtonColor } from '../basic/SessionButton';
|
||||||
import { SessionWrapperModal } from '../SessionWrapperModal';
|
import { SessionWrapperModal } from '../SessionWrapperModal';
|
||||||
|
import { getCurrentRecoveryPhrase } from '../../util/storage';
|
||||||
|
|
||||||
interface PasswordProps {
|
interface PasswordProps {
|
||||||
setPasswordValid: (val: boolean) => any;
|
setPasswordValid: (val: boolean) => any;
|
||||||
|
@ -168,7 +169,7 @@ const SessionSeedModalInner = (props: ModalInnerProps) => {
|
||||||
if (recoveryPhrase) {
|
if (recoveryPhrase) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const newRecoveryPhrase = UserUtils.getCurrentRecoveryPhrase();
|
const newRecoveryPhrase = getCurrentRecoveryPhrase();
|
||||||
setRecoveryPhrase(newRecoveryPhrase);
|
setRecoveryPhrase(newRecoveryPhrase);
|
||||||
setLoadingSeed(false);
|
setLoadingSeed(false);
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,9 @@ import { recoveryPhraseModal } from '../../state/ducks/modalDialog';
|
||||||
import { Flex } from '../basic/Flex';
|
import { Flex } from '../basic/Flex';
|
||||||
import { getFocusedSection, getOverlayMode } from '../../state/selectors/section';
|
import { getFocusedSection, getOverlayMode } from '../../state/selectors/section';
|
||||||
import { SectionType, setOverlayMode } from '../../state/ducks/section';
|
import { SectionType, setOverlayMode } from '../../state/ducks/section';
|
||||||
import { UserUtils } from '../../session/utils';
|
|
||||||
import { SessionButton, SessionButtonType } from '../basic/SessionButton';
|
import { SessionButton, SessionButtonType } from '../basic/SessionButton';
|
||||||
import { SessionIcon, SessionIconButton } from '../icon';
|
import { SessionIcon, SessionIconButton } from '../icon';
|
||||||
|
import { isSignWithRecoveryPhrase } from '../../util/storage';
|
||||||
|
|
||||||
const SectionTitle = styled.h1`
|
const SectionTitle = styled.h1`
|
||||||
padding: 0 var(--margins-sm);
|
padding: 0 var(--margins-sm);
|
||||||
|
@ -94,7 +94,7 @@ const BannerInner = () => {
|
||||||
|
|
||||||
export const LeftPaneBanner = () => {
|
export const LeftPaneBanner = () => {
|
||||||
const section = useSelector(getFocusedSection);
|
const section = useSelector(getFocusedSection);
|
||||||
const isSignInWithRecoveryPhrase = UserUtils.isSignWithRecoveryPhrase();
|
const isSignInWithRecoveryPhrase = isSignWithRecoveryPhrase();
|
||||||
|
|
||||||
if (section !== SectionType.Message || isSignInWithRecoveryPhrase) {
|
if (section !== SectionType.Message || isSignInWithRecoveryPhrase) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { createOrUpdateItem, removeAll } from '../../data/data';
|
||||||
import { getSwarmPollingInstance } from '../../session/apis/snode_api';
|
import { getSwarmPollingInstance } from '../../session/apis/snode_api';
|
||||||
import { getConversationController } from '../../session/conversations';
|
import { getConversationController } from '../../session/conversations';
|
||||||
import { mn_decode } from '../../session/crypto/mnemonic';
|
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 { TaskTimedOutError } from '../../session/utils/Promise';
|
||||||
import { trigger } from '../../shims/events';
|
import { trigger } from '../../shims/events';
|
||||||
import {
|
import {
|
||||||
|
@ -15,14 +15,15 @@ import {
|
||||||
signInByLinkingDevice,
|
signInByLinkingDevice,
|
||||||
} from '../../util/accountManager';
|
} from '../../util/accountManager';
|
||||||
import { fromHex } from '../../session/utils/String';
|
import { fromHex } from '../../session/utils/String';
|
||||||
|
import { setSignInByLinking, setSignWithRecoveryPhrase, Storage } from '../../util/storage';
|
||||||
|
|
||||||
export const MAX_USERNAME_LENGTH = 26;
|
export const MAX_USERNAME_LENGTH = 26;
|
||||||
// tslint:disable: use-simple-attributes
|
// tslint:disable: use-simple-attributes
|
||||||
|
|
||||||
export async function resetRegistration() {
|
export async function resetRegistration() {
|
||||||
await removeAll();
|
await removeAll();
|
||||||
await window.storage.reset();
|
Storage.reset();
|
||||||
await window.storage.fetch();
|
await Storage.fetch();
|
||||||
getConversationController().reset();
|
getConversationController().reset();
|
||||||
await getConversationController().load();
|
await getConversationController().load();
|
||||||
}
|
}
|
||||||
|
@ -64,7 +65,7 @@ export async function signUp(signUpDetails: {
|
||||||
value: true,
|
value: true,
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
});
|
});
|
||||||
UserUtils.setSignWithRecoveryPhrase(false);
|
setSignWithRecoveryPhrase(false);
|
||||||
trigger('openInbox');
|
trigger('openInbox');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
await resetRegistration();
|
await resetRegistration();
|
||||||
|
@ -95,7 +96,7 @@ export async function signInWithRecovery(signInDetails: {
|
||||||
await resetRegistration();
|
await resetRegistration();
|
||||||
|
|
||||||
await registerSingleDevice(userRecoveryPhrase, 'english', trimName);
|
await registerSingleDevice(userRecoveryPhrase, 'english', trimName);
|
||||||
UserUtils.setSignWithRecoveryPhrase(true);
|
setSignWithRecoveryPhrase(true);
|
||||||
|
|
||||||
trigger('openInbox');
|
trigger('openInbox');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -120,10 +121,10 @@ export async function signInWithLinking(signInDetails: { userRecoveryPhrase: str
|
||||||
await getSwarmPollingInstance().start();
|
await getSwarmPollingInstance().start();
|
||||||
|
|
||||||
await PromiseUtils.waitForTask(done => {
|
await PromiseUtils.waitForTask(done => {
|
||||||
window.Whisper.events.on('configurationMessageReceived', (displayName: string) => {
|
window.Whisper.events.on('configurationMessageReceived', async (displayName: string) => {
|
||||||
window.Whisper.events.off('configurationMessageReceived');
|
window.Whisper.events.off('configurationMessageReceived');
|
||||||
UserUtils.setSignInByLinking(false);
|
await setSignInByLinking(false);
|
||||||
UserUtils.setSignWithRecoveryPhrase(true);
|
await setSignWithRecoveryPhrase(true);
|
||||||
done(displayName);
|
done(displayName);
|
||||||
|
|
||||||
displayNameFromNetwork = displayName;
|
displayNameFromNetwork = displayName;
|
||||||
|
|
|
@ -4,9 +4,9 @@ import { AccentText } from './AccentText';
|
||||||
import { RegistrationStages } from './RegistrationStages';
|
import { RegistrationStages } from './RegistrationStages';
|
||||||
import { SessionIcon } from '../icon';
|
import { SessionIcon } from '../icon';
|
||||||
import { SessionToastContainer } from '../SessionToastContainer';
|
import { SessionToastContainer } from '../SessionToastContainer';
|
||||||
import { setSignInByLinking } from '../../session/utils/User';
|
|
||||||
import { SessionTheme } from '../../state/ducks/SessionTheme';
|
import { SessionTheme } from '../../state/ducks/SessionTheme';
|
||||||
import { Flex } from '../basic/Flex';
|
import { Flex } from '../basic/Flex';
|
||||||
|
import { setSignInByLinking } from '../../util/storage';
|
||||||
|
|
||||||
export const SessionRegistrationView = () => {
|
export const SessionRegistrationView = () => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
@ -19,6 +19,7 @@ import { PubKey } from '../session/types';
|
||||||
import { fromArrayBufferToBase64, fromBase64ToArrayBuffer } from '../session/utils/String';
|
import { fromArrayBufferToBase64, fromBase64ToArrayBuffer } from '../session/utils/String';
|
||||||
import { ReduxConversationType } from '../state/ducks/conversations';
|
import { ReduxConversationType } from '../state/ducks/conversations';
|
||||||
import { ExpirationTimerOptions } from '../util/expiringMessages';
|
import { ExpirationTimerOptions } from '../util/expiringMessages';
|
||||||
|
import { Storage } from '../util/storage';
|
||||||
import { channels } from './channels';
|
import { channels } from './channels';
|
||||||
import { channelsToMake as channelstoMakeOpenGroupV2 } from './opengroups';
|
import { channelsToMake as channelstoMakeOpenGroupV2 } from './opengroups';
|
||||||
|
|
||||||
|
@ -469,7 +470,7 @@ export async function generateAttachmentKeyIfEmpty() {
|
||||||
value: encryptingKey,
|
value: encryptingKey,
|
||||||
});
|
});
|
||||||
// be sure to write the new key to the cache. so we can access it straight away
|
// 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 { processNewAttachment } from '../types/MessageAttachment';
|
||||||
import { urlToBlob } from '../types/attachments/VisualAttachment';
|
import { urlToBlob } from '../types/attachments/VisualAttachment';
|
||||||
import { MIME } from '../types';
|
import { MIME } from '../types';
|
||||||
|
import { setLastProfileUpdateTimestamp } from '../util/storage';
|
||||||
|
|
||||||
export const getCompleteUrlForV2ConvoId = async (convoId: string) => {
|
export const getCompleteUrlForV2ConvoId = async (convoId: string) => {
|
||||||
if (convoId.match(openGroupV2ConversationIdRegex)) {
|
if (convoId.match(openGroupV2ConversationIdRegex)) {
|
||||||
|
@ -462,7 +463,7 @@ export async function uploadOurAvatar(newAvatarDecrypted?: ArrayBuffer) {
|
||||||
await createOrUpdateItem({ id: lastAvatarUploadTimestamp, value: newTimestampReupload });
|
await createOrUpdateItem({ id: lastAvatarUploadTimestamp, value: newTimestampReupload });
|
||||||
|
|
||||||
if (newAvatarDecrypted) {
|
if (newAvatarDecrypted) {
|
||||||
UserUtils.setLastProfileUpdateTimestamp(Date.now());
|
await setLastProfileUpdateTimestamp(Date.now());
|
||||||
await SyncUtils.forceSyncConfigurationNowIfNeeded(true);
|
await SyncUtils.forceSyncConfigurationNowIfNeeded(true);
|
||||||
} else {
|
} else {
|
||||||
window.log.info(
|
window.log.info(
|
||||||
|
|
|
@ -64,6 +64,7 @@ import {
|
||||||
import { getOurPubKeyStrFromCache } from '../session/utils/User';
|
import { getOurPubKeyStrFromCache } from '../session/utils/User';
|
||||||
import { MessageRequestResponse } from '../session/messages/outgoing/controlMessage/MessageRequestResponse';
|
import { MessageRequestResponse } from '../session/messages/outgoing/controlMessage/MessageRequestResponse';
|
||||||
import { Notifications } from '../util/notifications';
|
import { Notifications } from '../util/notifications';
|
||||||
|
import { Storage } from '../util/storage';
|
||||||
|
|
||||||
export enum ConversationTypeEnum {
|
export enum ConversationTypeEnum {
|
||||||
GROUP = 'group',
|
GROUP = 'group',
|
||||||
|
@ -1146,10 +1147,10 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
|
||||||
if (this.isPrivate() && read.length && options.sendReadReceipts) {
|
if (this.isPrivate() && read.length && options.sendReadReceipts) {
|
||||||
window?.log?.info(
|
window?.log?.info(
|
||||||
`Sending ${read.length} read receipts?`,
|
`Sending ${read.length} read receipts?`,
|
||||||
window.storage.get(SettingsKey.settingsReadReceipt) || false
|
Storage.get(SettingsKey.settingsReadReceipt) || false
|
||||||
);
|
);
|
||||||
const dontSendReceipt = this.isBlocked() || this.isIncomingRequest();
|
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 timestamps = _.map(read, 'timestamp').filter(t => !!t) as Array<number>;
|
||||||
const receiptMessage = new ReadReceiptMessage({
|
const receiptMessage = new ReadReceiptMessage({
|
||||||
timestamp: Date.now(),
|
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
|
// for typing to happen, this must be a private unblocked active convo, and the settings to be on
|
||||||
if (
|
if (
|
||||||
!this.isActive() ||
|
!this.isActive() ||
|
||||||
!window.storage.get(SettingsKey.settingsTypingIndicator) ||
|
!Storage.get(SettingsKey.settingsTypingIndicator) ||
|
||||||
this.isBlocked() ||
|
this.isBlocked() ||
|
||||||
!this.isPrivate()
|
!this.isPrivate()
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -62,6 +62,7 @@ import {
|
||||||
} from '../types/MessageAttachment';
|
} from '../types/MessageAttachment';
|
||||||
import { ExpirationTimerOptions } from '../util/expiringMessages';
|
import { ExpirationTimerOptions } from '../util/expiringMessages';
|
||||||
import { Notifications } from '../util/notifications';
|
import { Notifications } from '../util/notifications';
|
||||||
|
import { Storage } from '../util/storage';
|
||||||
// tslint:disable: cyclomatic-complexity
|
// tslint:disable: cyclomatic-complexity
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -428,7 +429,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
|
||||||
}
|
}
|
||||||
|
|
||||||
const readBy = this.get('read_by') || [];
|
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';
|
return 'read';
|
||||||
}
|
}
|
||||||
const sent = this.get('sent');
|
const sent = this.get('sent');
|
||||||
|
|
|
@ -14,7 +14,7 @@ interface Status {
|
||||||
type: Type;
|
type: Type;
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserSetting = 'off' | 'count' | 'name' | 'message';
|
export type UserSetting = 'off' | 'count' | 'name' | 'message';
|
||||||
|
|
||||||
type Type = 'ok' | 'disabled' | 'appIsFocused' | 'noNotifications' | 'userSetting';
|
type Type = 'ok' | 'disabled' | 'appIsFocused' | 'noNotifications' | 'userSetting';
|
||||||
|
|
||||||
|
|
|
@ -17,13 +17,14 @@ import { handleNewClosedGroup } from './closedGroups';
|
||||||
import { updateProfileOneAtATime } from './dataMessage';
|
import { updateProfileOneAtATime } from './dataMessage';
|
||||||
import { EnvelopePlus } from './types';
|
import { EnvelopePlus } from './types';
|
||||||
import { ConversationInteraction } from '../interactions';
|
import { ConversationInteraction } from '../interactions';
|
||||||
|
import { getLastProfileUpdateTimestamp, setLastProfileUpdateTimestamp } from '../util/storage';
|
||||||
|
|
||||||
async function handleOurProfileUpdate(
|
async function handleOurProfileUpdate(
|
||||||
sentAt: number | Long,
|
sentAt: number | Long,
|
||||||
configMessage: SignalService.ConfigurationMessage,
|
configMessage: SignalService.ConfigurationMessage,
|
||||||
ourPubkey: string
|
ourPubkey: string
|
||||||
) {
|
) {
|
||||||
const latestProfileUpdateTimestamp = UserUtils.getLastProfileUpdateTimestamp();
|
const latestProfileUpdateTimestamp = getLastProfileUpdateTimestamp();
|
||||||
if (!latestProfileUpdateTimestamp || sentAt > latestProfileUpdateTimestamp) {
|
if (!latestProfileUpdateTimestamp || sentAt > latestProfileUpdateTimestamp) {
|
||||||
window?.log?.info(
|
window?.log?.info(
|
||||||
`Handling our profileUdpate ourLastUpdate:${latestProfileUpdateTimestamp}, envelope sent at: ${sentAt}`
|
`Handling our profileUdpate ourLastUpdate:${latestProfileUpdateTimestamp}, envelope sent at: ${sentAt}`
|
||||||
|
@ -41,7 +42,7 @@ async function handleOurProfileUpdate(
|
||||||
profilePicture,
|
profilePicture,
|
||||||
};
|
};
|
||||||
await updateProfileOneAtATime(ourConversation, lokiProfile, profileKey);
|
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
|
// do not trigger a signin by linking if the display name is empty
|
||||||
if (displayName) {
|
if (displayName) {
|
||||||
trigger(configurationMessageReceived, displayName);
|
trigger(configurationMessageReceived, displayName);
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { handleCallMessage } from './callMessage';
|
||||||
import { SettingsKey } from '../data/settings-key';
|
import { SettingsKey } from '../data/settings-key';
|
||||||
import { ConversationTypeEnum } from '../models/conversation';
|
import { ConversationTypeEnum } from '../models/conversation';
|
||||||
import { ReadReceipts } from '../util/readReceipts';
|
import { ReadReceipts } from '../util/readReceipts';
|
||||||
|
import { Storage } from '../util/storage';
|
||||||
|
|
||||||
export async function handleSwarmContentMessage(envelope: EnvelopePlus, messageHash: string) {
|
export async function handleSwarmContentMessage(envelope: EnvelopePlus, messageHash: string) {
|
||||||
try {
|
try {
|
||||||
|
@ -491,7 +492,7 @@ async function handleTypingMessage(
|
||||||
await removeFromCache(envelope);
|
await removeFromCache(envelope);
|
||||||
|
|
||||||
// We don't do anything with incoming typing messages if the setting is disabled
|
// 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { PubKey } from '../types';
|
||||||
import { fromHexToArray, toHex } from './String';
|
import { fromHexToArray, toHex } from './String';
|
||||||
import { getConversationController } from '../conversations';
|
import { getConversationController } from '../conversations';
|
||||||
import { LokiProfile } from '../../types/Message';
|
import { LokiProfile } from '../../types/Message';
|
||||||
|
import { getNumber, Storage } from '../../util/storage';
|
||||||
|
|
||||||
export type HexKeyPair = {
|
export type HexKeyPair = {
|
||||||
pubKey: string;
|
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
|
* Returns the public key of this current device as a STRING, or throws an error
|
||||||
*/
|
*/
|
||||||
export function getOurPubKeyStrFromCache(): string {
|
export function getOurPubKeyStrFromCache(): string {
|
||||||
const ourNumber = window.textsecure.storage.user.getNumber();
|
const ourNumber = getNumber();
|
||||||
if (!ourNumber) {
|
if (!ourNumber) {
|
||||||
throw new Error('ourNumber is not set');
|
throw new Error('ourNumber is not set');
|
||||||
}
|
}
|
||||||
|
@ -78,27 +79,11 @@ export async function getUserED25519KeyPair(): Promise<HexKeyPair | undefined> {
|
||||||
return 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 {
|
export function getOurProfile(): LokiProfile | undefined {
|
||||||
try {
|
try {
|
||||||
// Secondary devices have their profile stored
|
// Secondary devices have their profile stored
|
||||||
// in their primary device's conversation
|
// 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 ourConversation = getConversationController().get(ourNumber);
|
||||||
const ourProfileKeyHex = ourConversation.get('profileKey');
|
const ourProfileKeyHex = ourConversation.get('profileKey');
|
||||||
const profileKeyAsBytes = ourProfileKeyHex ? fromHexToArray(ourProfileKeyHex) : null;
|
const profileKeyAsBytes = ourProfileKeyHex ? fromHexToArray(ourProfileKeyHex) : null;
|
||||||
|
@ -115,19 +100,3 @@ export function getOurProfile(): LokiProfile | undefined {
|
||||||
return 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 { LightBoxOptions } from '../../components/conversation/SessionConversation';
|
||||||
import { getConversationController } from '../../session/conversations';
|
import { getConversationController } from '../../session/conversations';
|
||||||
import { UserUtils } from '../../session/utils';
|
import { UserUtils } from '../../session/utils';
|
||||||
|
import { Storage } from '../../util/storage';
|
||||||
|
|
||||||
export const getConversations = (state: StateType): ConversationsStateType => state.conversations;
|
export const getConversations = (state: StateType): ConversationsStateType => state.conversations;
|
||||||
|
|
||||||
|
@ -129,7 +130,7 @@ export const isPublicGroupConversation = createSelector(
|
||||||
export const getOurPrimaryConversation = createSelector(
|
export const getOurPrimaryConversation = createSelector(
|
||||||
getConversations,
|
getConversations,
|
||||||
(state: ConversationsStateType): ReduxConversationType =>
|
(state: ConversationsStateType): ReduxConversationType =>
|
||||||
state.conversationLookup[window.storage.get('primaryDevicePubKey')]
|
state.conversationLookup[Storage.get('primaryDevicePubKey') as string]
|
||||||
);
|
);
|
||||||
|
|
||||||
const getMessagesOfSelectedConversation = createSelector(
|
const getMessagesOfSelectedConversation = createSelector(
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { SignalService } from '../protobuf';
|
||||||
import { isImageTypeSupported, isVideoTypeSupported } from '../util/GoogleChrome';
|
import { isImageTypeSupported, isVideoTypeSupported } from '../util/GoogleChrome';
|
||||||
import { fromHexToArray } from '../session/utils/String';
|
import { fromHexToArray } from '../session/utils/String';
|
||||||
import { ATTACHMENT_DEFAULT_MAX_SIDE } from '../util/attachmentsUtil';
|
import { ATTACHMENT_DEFAULT_MAX_SIDE } from '../util/attachmentsUtil';
|
||||||
|
import { Storage } from '../util/storage';
|
||||||
|
|
||||||
const MAX_WIDTH = 200;
|
const MAX_WIDTH = 200;
|
||||||
const MAX_HEIGHT = MAX_WIDTH;
|
const MAX_HEIGHT = MAX_WIDTH;
|
||||||
|
@ -396,9 +397,8 @@ export const encryptAttachmentBuffer = async (bufferIn: ArrayBuffer) => {
|
||||||
if (!isArrayBuffer(bufferIn)) {
|
if (!isArrayBuffer(bufferIn)) {
|
||||||
throw new TypeError("'bufferIn' must be an array buffer");
|
throw new TypeError("'bufferIn' must be an array buffer");
|
||||||
}
|
}
|
||||||
const encryptingKey = fromHexToArray(
|
const key = Storage.get('local_attachment_encrypted_key') as string;
|
||||||
window.textsecure.storage.get('local_attachment_encrypted_key')
|
const encryptingKey = fromHexToArray(key);
|
||||||
);
|
|
||||||
return window.callWorker('encryptAttachmentBuffer', encryptingKey, bufferIn);
|
return window.callWorker('encryptAttachmentBuffer', encryptingKey, bufferIn);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -406,8 +406,7 @@ export const decryptAttachmentBuffer = async (bufferIn: ArrayBuffer): Promise<Ui
|
||||||
if (!isArrayBuffer(bufferIn)) {
|
if (!isArrayBuffer(bufferIn)) {
|
||||||
throw new TypeError("'bufferIn' must be an array buffer");
|
throw new TypeError("'bufferIn' must be an array buffer");
|
||||||
}
|
}
|
||||||
const encryptingKey = fromHexToArray(
|
const key = Storage.get('local_attachment_encrypted_key') as string;
|
||||||
window.textsecure.storage.get('local_attachment_encrypted_key')
|
const encryptingKey = fromHexToArray(key);
|
||||||
);
|
|
||||||
return window.callWorker('decryptAttachmentBuffer', encryptingKey, bufferIn);
|
return window.callWorker('decryptAttachmentBuffer', encryptingKey, bufferIn);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { getConversationController } from '../session/conversations';
|
import { getConversationController } from '../session/conversations';
|
||||||
import { getSodium } from '../session/crypto';
|
import { getSodium } from '../session/crypto';
|
||||||
import { UserUtils } from '../session/utils';
|
|
||||||
import { fromArrayBufferToBase64, fromHex, toHex } from '../session/utils/String';
|
import { fromArrayBufferToBase64, fromHex, toHex } from '../session/utils/String';
|
||||||
import { getOurPubKeyStrFromCache } from '../session/utils/User';
|
import { getOurPubKeyStrFromCache } from '../session/utils/User';
|
||||||
import { trigger } from '../shims/events';
|
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 { mn_decode, mn_encode } from '../session/crypto/mnemonic';
|
||||||
import { ConversationTypeEnum } from '../models/conversation';
|
import { ConversationTypeEnum } from '../models/conversation';
|
||||||
import { SettingsKey } from '../data/settings-key';
|
import { SettingsKey } from '../data/settings-key';
|
||||||
|
import {
|
||||||
|
saveRecoveryPhrase,
|
||||||
|
setLastProfileUpdateTimestamp,
|
||||||
|
setLocalPubKey,
|
||||||
|
setSignInByLinking,
|
||||||
|
Storage,
|
||||||
|
} from './storage';
|
||||||
|
import { Registration } from './registration';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Might throw
|
* Might throw
|
||||||
|
@ -76,9 +83,9 @@ export async function signInByLinkingDevice(mnemonic: string, mnemonicLanguage:
|
||||||
}
|
}
|
||||||
|
|
||||||
const identityKeyPair = await generateKeypair(mnemonic, mnemonicLanguage);
|
const identityKeyPair = await generateKeypair(mnemonic, mnemonicLanguage);
|
||||||
UserUtils.setSignInByLinking(true);
|
await setSignInByLinking(true);
|
||||||
await createAccount(identityKeyPair);
|
await createAccount(identityKeyPair);
|
||||||
UserUtils.saveRecoveryPhrase(mnemonic);
|
await saveRecoveryPhrase(mnemonic);
|
||||||
const pubKeyString = toHex(identityKeyPair.pubKey);
|
const pubKeyString = toHex(identityKeyPair.pubKey);
|
||||||
|
|
||||||
// await for the first configuration message to come in.
|
// await for the first configuration message to come in.
|
||||||
|
@ -109,8 +116,8 @@ export async function registerSingleDevice(
|
||||||
const identityKeyPair = await generateKeypair(generatedMnemonic, mnemonicLanguage);
|
const identityKeyPair = await generateKeypair(generatedMnemonic, mnemonicLanguage);
|
||||||
|
|
||||||
await createAccount(identityKeyPair);
|
await createAccount(identityKeyPair);
|
||||||
UserUtils.saveRecoveryPhrase(generatedMnemonic);
|
await saveRecoveryPhrase(generatedMnemonic);
|
||||||
await UserUtils.setLastProfileUpdateTimestamp(Date.now());
|
await setLastProfileUpdateTimestamp(Date.now());
|
||||||
|
|
||||||
const pubKeyString = toHex(identityKeyPair.pubKey);
|
const pubKeyString = toHex(identityKeyPair.pubKey);
|
||||||
await registrationDone(pubKeyString, profileName);
|
await registrationDone(pubKeyString, profileName);
|
||||||
|
@ -131,39 +138,39 @@ async function createAccount(identityKeyPair: any) {
|
||||||
password = password.substring(0, password.length - 2);
|
password = password.substring(0, password.length - 2);
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
window.textsecure.storage.remove('identityKey'),
|
Storage.remove('identityKey'),
|
||||||
window.textsecure.storage.remove('signaling_key'),
|
Storage.remove('signaling_key'),
|
||||||
window.textsecure.storage.remove('password'),
|
Storage.remove('password'),
|
||||||
window.textsecure.storage.remove('registrationId'),
|
Storage.remove('registrationId'),
|
||||||
window.textsecure.storage.remove('number_id'),
|
Storage.remove('number_id'),
|
||||||
window.textsecure.storage.remove('device_name'),
|
Storage.remove('device_name'),
|
||||||
window.textsecure.storage.remove('userAgent'),
|
Storage.remove('userAgent'),
|
||||||
window.textsecure.storage.remove(SettingsKey.settingsReadReceipt),
|
Storage.remove(SettingsKey.settingsReadReceipt),
|
||||||
window.textsecure.storage.remove(SettingsKey.settingsTypingIndicator),
|
Storage.remove(SettingsKey.settingsTypingIndicator),
|
||||||
window.textsecure.storage.remove('regionCode'),
|
Storage.remove('regionCode'),
|
||||||
window.textsecure.storage.remove('local_attachment_encrypted_key'),
|
Storage.remove('local_attachment_encrypted_key'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// update our own identity key, which may have changed
|
// update our own identity key, which may have changed
|
||||||
// if we're relinking after a reinstall on the master device
|
// if we're relinking after a reinstall on the master device
|
||||||
const pubKeyString = toHex(identityKeyPair.pubKey);
|
const pubKeyString = toHex(identityKeyPair.pubKey);
|
||||||
|
|
||||||
await window.textsecure.storage.put('identityKey', identityKeyPair);
|
await Storage.put('identityKey', identityKeyPair);
|
||||||
await window.textsecure.storage.put('password', password);
|
await Storage.put('password', password);
|
||||||
|
|
||||||
// disable read-receipt by default
|
// disable read-receipt by default
|
||||||
await window.textsecure.storage.put(SettingsKey.settingsReadReceipt, false);
|
await Storage.put(SettingsKey.settingsReadReceipt, false);
|
||||||
|
|
||||||
// Enable typing indicators by default
|
// 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) {
|
async function registrationDone(ourPubkey: string, displayName: string) {
|
||||||
window?.log?.info('registration done');
|
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
|
// Ensure that we always have a conversation for ourself
|
||||||
const conversation = await getConversationController().getOrCreateAndWait(
|
const conversation = await getConversationController().getOrCreateAndWait(
|
||||||
|
@ -174,10 +181,10 @@ async function registrationDone(ourPubkey: string, displayName: string) {
|
||||||
await conversation.setIsApproved(true);
|
await conversation.setIsApproved(true);
|
||||||
const user = {
|
const user = {
|
||||||
ourNumber: getOurPubKeyStrFromCache(),
|
ourNumber: getOurPubKeyStrFromCache(),
|
||||||
ourPrimary: window.textsecure.storage.get('primaryDevicePubKey'),
|
ourPrimary: ourPubkey,
|
||||||
};
|
};
|
||||||
window.inboxStore?.dispatch(userActions.userChanged(user));
|
window.inboxStore?.dispatch(userActions.userChanged(user));
|
||||||
window.Whisper.Registration.markDone();
|
await Registration.markDone();
|
||||||
window?.log?.info('dispatching registration event');
|
window?.log?.info('dispatching registration event');
|
||||||
trigger('registration_done');
|
trigger('registration_done');
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { getStatus } from '../notifications';
|
import { getStatus } from '../notifications';
|
||||||
|
import { UserSetting } from '../notifications/getStatus';
|
||||||
import { isMacOS } from '../OS';
|
import { isMacOS } from '../OS';
|
||||||
import { isAudioNotificationSupported } from '../types/Settings';
|
import { isAudioNotificationSupported } from '../types/Settings';
|
||||||
import { isWindowFocused } from './focusListener';
|
import { isWindowFocused } from './focusListener';
|
||||||
|
import { Storage } from './storage';
|
||||||
|
|
||||||
const SettingNames = {
|
const SettingNames = {
|
||||||
COUNT: 'count',
|
COUNT: 'count',
|
||||||
|
@ -106,7 +108,7 @@ function update() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const isAppFocused = isWindowFocused();
|
const isAppFocused = isWindowFocused();
|
||||||
const isAudioNotificationEnabled = storage.get('audio-notification') || false;
|
const isAudioNotificationEnabled = (Storage.get('audio-notification') as boolean) || false;
|
||||||
const audioNotificationSupported = isAudioNotificationSupported();
|
const audioNotificationSupported = isAudioNotificationSupported();
|
||||||
// const isNotificationGroupingSupported = Settings.isNotificationGroupingSupported();
|
// const isNotificationGroupingSupported = Settings.isNotificationGroupingSupported();
|
||||||
const numNotifications = currentNotifications.length;
|
const numNotifications = currentNotifications.length;
|
||||||
|
@ -221,7 +223,7 @@ function update() {
|
||||||
// ‘10 new messages’) assuming that `Notification::close` does its job.
|
// ‘10 new messages’) assuming that `Notification::close` does its job.
|
||||||
}
|
}
|
||||||
function getUserSetting() {
|
function getUserSetting() {
|
||||||
return storage.get('notification-setting') || SettingNames.MESSAGE;
|
return (Storage.get('notification-setting') as UserSetting) || SettingNames.MESSAGE;
|
||||||
}
|
}
|
||||||
function onRemove() {
|
function onRemove() {
|
||||||
// window.log.info('Remove notification');
|
// window.log.info('Remove notification');
|
||||||
|
|
|
@ -1,21 +1,23 @@
|
||||||
function markEverDone() {
|
import { Storage } from './storage';
|
||||||
storage.put('chromiumRegistrationDoneEver', '');
|
|
||||||
|
async function markEverDone() {
|
||||||
|
await Storage.put('chromiumRegistrationDoneEver', '');
|
||||||
}
|
}
|
||||||
function markDone() {
|
async function markDone() {
|
||||||
this.markEverDone();
|
await markEverDone();
|
||||||
storage.put('chromiumRegistrationDone', '');
|
await Storage.put('chromiumRegistrationDone', '');
|
||||||
}
|
}
|
||||||
function isDone() {
|
function isDone() {
|
||||||
return storage.get('chromiumRegistrationDone') === '';
|
return Storage.get('chromiumRegistrationDone') === '';
|
||||||
}
|
}
|
||||||
function everDone() {
|
function everDone() {
|
||||||
return (
|
return (
|
||||||
storage.get('chromiumRegistrationDoneEver') === '' ||
|
Storage.get('chromiumRegistrationDoneEver') === '' ||
|
||||||
storage.get('chromiumRegistrationDone') === ''
|
Storage.get('chromiumRegistrationDone') === ''
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
function remove() {
|
async function remove() {
|
||||||
storage.remove('chromiumRegistrationDone');
|
await Storage.remove('chromiumRegistrationDone');
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Registration = { markEverDone, markDone, isDone, everDone, remove };
|
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