Working with deps

pull/713/head
Vincent 5 years ago
parent 659d4412bd
commit 648cc2339c

@ -660,6 +660,9 @@
"unableToLoadAttachment": {
"message": "Unable to load selected attachment."
},
"connect": {
"message": "Connect"
},
"disconnected": {
"message": "Disconnected",
"description":
@ -946,7 +949,7 @@
"message": "Close"
},
"pairNewDevice": {
"message": "Pair new Device"
"message": "Pair New Device"
},
"devicePairingAccepted": {
"message": "Device Pairing Accepted"
@ -957,6 +960,9 @@
"waitingForDeviceToRegister": {
"message": "Waiting for device to register..."
},
"pairNewDevicePrompt": {
"message": "Scan the QR Code on your secondary device"
},
"pairedDevices": {
"message": "Paired Devices"
},
@ -2107,7 +2113,7 @@
"Button action that the user can click to connect to a new public server"
},
"addServerDialogTitle": {
"message": "Connect to new public server",
"message": "Connect To New Public Server",
"description":
"Title for the dialog box used to connect to a new public server"
},

@ -50,9 +50,13 @@ const {
} = require('../../ts/components/conversation/CreateGroupDialog');
const { EditProfileDialog } = require('../../ts/components/EditProfileDialog');
const { UserDetailsDialog } = require('../../ts/components/UserDetailsDialog');
const { DevicePairingDialog } = require('../../ts/components/DevicePairingDialog');
const { SessionSettings,
const {
DevicePairingDialog,
} = require('../../ts/components/DevicePairingDialog');
const { AddServerDialog } = require('../../ts/components/AddServerDialog');
const {
SessionSettings,
} = require('../../ts/components/session/SessionSettings');
const { SessionToast } = require('../../ts/components/session/SessionToast');
const { SessionToggle } = require('../../ts/components/session/SessionToggle');
@ -253,6 +257,7 @@ exports.setup = (options = {}) => {
EditProfileDialog,
UserDetailsDialog,
DevicePairingDialog,
AddServerDialog,
SessionRegistrationView,
ConfirmDialog,
UpdateGroupDialog,

@ -1,4 +1,4 @@
/* global Whisper, i18n, _ */
/* global Whisper, i18n, */
// eslint-disable-next-line func-names
(function() {
@ -7,86 +7,28 @@
window.Whisper = window.Whisper || {};
Whisper.AddServerDialogView = Whisper.View.extend({
templateName: 'add-server-template',
className: 'loki-dialog add-server modal',
initialize(options = {}) {
this.title = i18n('addServerDialogTitle');
this.okText = options.okText || i18n('ok');
this.cancelText = options.cancelText || i18n('cancel');
this.$('input').focus();
className: 'loki-dialog add-server-dialog modal',
initialize() {
this.close = this.close.bind(this);
this.render();
},
events: {
keyup: 'onKeyup',
'click .ok': 'confirm',
'click .cancel': 'close',
},
render_attributes() {
return {
title: this.title,
ok: this.okText,
cancel: this.cancelText,
};
},
confirm() {
// Remove error if there is one
this.showError(null);
const serverUrl = this.$('#server-url')
.val()
.toLowerCase();
// TODO: Make this not hard coded
const channelId = 1;
const dialog = new Whisper.ConnectingToServerDialogView({
serverUrl,
channelId,
});
const dialogDelayTimer = setTimeout(() => {
this.el.append(dialog.el);
}, 200);
dialog.once('connectionResult', result => {
clearTimeout(dialogDelayTimer);
if (result.cancelled) {
this.showError(null);
return;
}
if (result.errorCode) {
this.showError(result.errorCode);
return;
}
window.pushToast({
title: i18n('connectToServerSuccess'),
type: 'success',
id: 'connectToServerSuccess',
});
this.close();
render() {
this.dialogView = new Whisper.ReactWrapperView({
className: 'add-server-dialog',
Component: window.Signal.Components.AddServerDialog,
props: {
i18n,
onClose: this.close,
},
});
dialog.trigger('attemptConnection');
this.$el.append(this.dialogView.el);
return this;
},
close() {
this.remove();
},
showError(message) {
if (_.isEmpty(message)) {
this.$('.error').text('');
this.$('.error').hide();
} else {
this.$('.error').text(`Error: ${message}`);
this.$('.error').show();
}
this.$('input').focus();
},
onKeyup(event) {
switch (event.key) {
case 'Enter':
this.confirm();
break;
case 'Escape':
case 'Esc':
this.close();
break;
default:
break;
}
},
});
})();

@ -0,0 +1,92 @@
/* global Whisper, i18n, _ */
// eslint-disable-next-line func-names
(function() {
'use strict';
window.Whisper = window.Whisper || {};
Whisper.AddServerDialogView = Whisper.View.extend({
templateName: 'add-server-template',
className: 'loki-dialog add-server modal',
initialize(options = {}) {
this.title = i18n('addServerDialogTitle');
this.okText = options.okText || i18n('ok');
this.cancelText = options.cancelText || i18n('cancel');
this.$('input').focus();
this.render();
},
events: {
keyup: 'onKeyup',
'click .ok': 'confirm',
'click .cancel': 'close',
},
render_attributes() {
return {
title: this.title,
ok: this.okText,
cancel: this.cancelText,
};
},
confirm() {
// Remove error if there is one
this.showError(null);
const serverUrl = this.$('#server-url')
.val()
.toLowerCase();
// TODO: Make this not hard coded
const channelId = 1;
const dialog = new Whisper.ConnectingToServerDialogView({
serverUrl,
channelId,
});
const dialogDelayTimer = setTimeout(() => {
this.el.append(dialog.el);
}, 200);
dialog.once('connectionResult', result => {
clearTimeout(dialogDelayTimer);
if (result.cancelled) {
this.showError(null);
return;
}
if (result.errorCode) {
this.showError(result.errorCode);
return;
}
window.pushToast({
title: i18n('connectToServerSuccess'),
type: 'success',
id: 'connectToServerSuccess',
});
this.close();
});
dialog.trigger('attemptConnection');
},
close() {
this.remove();
},
showError(message) {
if (_.isEmpty(message)) {
this.$('.error').text('');
this.$('.error').hide();
} else {
this.$('.error').text(`Error: ${message}`);
this.$('.error').show();
}
this.$('input').focus();
},
onKeyup(event) {
switch (event.key) {
case 'Enter':
this.confirm();
break;
case 'Escape':
case 'Esc':
this.close();
break;
default:
break;
}
},
});
})();

@ -1,11 +1,4 @@
/* global
Whisper,
i18n,
libloki,
textsecure,
ConversationController,
$,
*/
/* global Whisper, i18n, */
// eslint-disable-next-line func-names
(function() {
@ -17,12 +10,10 @@
className: 'loki-dialog device-pairing-dialog modal',
initialize() {
this.close = this.close.bind(this);
this.render();
},
render(){
render() {
this.dialogView = new Whisper.ReactWrapperView({
className: 'device-pairing-dialog',
Component: window.Signal.Components.DevicePairingDialog,
@ -36,7 +27,6 @@
return this;
},
close() {
this.remove();
},

@ -0,0 +1,318 @@
{
"name": "loki-messenger-desktop",
"productName": "Loki Messenger",
"description": "Private messaging from your desktop",
"repository": "https://github.com/loki-project/loki-messenger.git",
"version": "1.0.0-beta9",
"license": "GPL-3.0",
"author": {
"name": "Loki Project",
"email": "team@loki.network"
},
"main": "main.js",
"scripts": {
"postinstall": "electron-builder install-app-deps && rimraf node_modules/dtrace-provider",
"start": "electron .",
"start-multi": "NODE_APP_INSTANCE=1 electron .",
"start-multi2": "NODE_APP_INSTANCE=2 electron .",
"start-prod": "NODE_ENV=production NODE_APP_INSTANCE=devprod LOKI_DEV=1 electron .",
"start-prod-multi": "NODE_ENV=production NODE_APP_INSTANCE=devprod1 LOKI_DEV=1 electron .",
"grunt": "grunt",
"icon-gen": "electron-icon-maker --input=images/icon_1024.png --output=./build",
"generate": "yarn icon-gen && yarn grunt",
"build": "electron-builder --config.extraMetadata.environment=$SIGNAL_ENV",
"build-release": "export SIGNAL_ENV=production && npm run build -- --config.directories.output=release",
"sign-release": "node ts/updater/generateSignature.js",
"build-module-protobuf": "pbjs --target static-module --wrap commonjs --out ts/protobuf/compiled.js protos/*.proto && pbts --out ts/protobuf/compiled.d.ts ts/protobuf/compiled.js",
"clean-module-protobuf": "rm -f ts/protobuf/compiled.d.ts ts/protobuf/compiled.js",
"build-protobuf": "yarn build-module-protobuf",
"clean-protobuf": "yarn clean-module-protobuf",
"prepare-beta-build": "node prepare_beta_build.js",
"prepare-import-build": "node prepare_import_build.js",
"publish-to-apt": "NAME=$npm_package_name VERSION=$npm_package_version ./aptly.sh",
"test": "yarn test-node && yarn test-electron",
"test-view": "NODE_ENV=test yarn run start",
"test-lib-view": "NODE_ENV=test-lib yarn run start",
"test-loki-view": "NODE_ENV=test-loki yarn run start",
"test-electron": "yarn grunt test",
"test-node": "mocha --recursive --exit test/app test/modules ts/test libloki/test/node",
"test-node-coverage": "nyc --reporter=lcov --reporter=text mocha --recursive test/app test/modules ts/test libloki/test/node",
"test-node-coverage-html": "nyc --reporter=lcov --reporter=html mocha --recursive test/app test/modules ts/test libloki/test/node",
"eslint": "eslint .",
"lint": "yarn format --list-different && yarn lint-windows",
"dev-lint": "yarn format --list-different; yarn lint-windows",
"lint-windows": "yarn eslint && yarn tslint",
"lint-deps": "node ts/util/lint/linter.js",
"tslint": "tslint --format stylish --project .",
"format": "prettier --write \"*.{css,js,json,md,scss,ts,tsx}\" \"./**/*.{css,js,json,md,scss,ts,tsx}\"",
"transpile": "tsc",
"clean-transpile": "rimraf ts/**/*.js && rimraf ts/*.js",
"open-coverage": "open coverage/lcov-report/index.html",
"styleguide": "styleguidist server",
"pow-metrics": "node metrics_app.js localhost 9000",
"ready": "yarn clean-transpile && yarn grunt && yarn lint && yarn test-node && yarn test-electron && yarn lint-deps"
},
"dependencies": {
"@journeyapps/sqlcipher": "https://github.com/scottnonnenberg-signal/node-sqlcipher.git#2e28733b61640556b0272a3bfc78b0357daf71e6",
"@sindresorhus/is": "0.8.0",
"@types/dompurify": "^2.0.0",
"backbone": "1.3.3",
"blob-util": "1.3.0",
"blueimp-canvas-to-blob": "3.14.0",
"blueimp-load-image": "2.18.0",
"buffer-crc32": "0.2.13",
"bunyan": "1.8.12",
"classnames": "2.2.5",
"color": "^3.1.2",
"config": "1.28.1",
"dompurify": "^2.0.7",
"electron-context-menu": "^0.15.0",
"electron-editor-context-menu": "1.1.1",
"electron-is-dev": "0.3.0",
"emoji-datasource": "4.0.0",
"emoji-datasource-apple": "4.0.0",
"emoji-js": "3.4.0",
"emoji-panel": "https://github.com/scottnonnenberg-signal/emoji-panel.git#v0.5.5",
"filesize": "3.6.1",
"firstline": "1.2.1",
"form-data": "2.3.2",
"fs-extra": "5.0.0",
"glob": "7.1.2",
"google-libphonenumber": "3.2.2",
"got": "8.2.0",
"he": "1.2.0",
"intl-tel-input": "12.1.15",
"jquery": "3.3.1",
"js-sha512": "0.8.0",
"js-yaml": "3.13.0",
"jsbn": "1.1.0",
"libsodium-wrappers": "^0.7.4",
"linkify-it": "2.0.3",
"lodash": "4.17.11",
"mixpanel": "^0.10.2",
"mkdirp": "0.5.1",
"moment": "2.21.0",
"mustache": "2.3.0",
"nat-upnp": "^1.1.1",
"node-fetch": "2.3.0",
"node-gyp": "3.8.0",
"node-sass": "4.9.3",
"os-locale": "2.1.0",
"pify": "3.0.0",
"protobufjs": "6.8.6",
"proxy-agent": "3.0.3",
"qrcode": "^1.4.4",
"react": "16.8.3",
"react-contextmenu": "2.11.0",
"react-dom": "16.8.3",
"react-portal": "^4.2.0",
"react-qrcode": "^0.2.0",
"react-redux": "6.0.1",
"react-virtualized": "9.21.0",
"read-last-lines": "1.3.0",
"redux": "4.0.1",
"redux-logger": "3.0.6",
"redux-promise-middleware": "6.1.0",
"reselect": "4.0.0",
"rimraf": "2.6.2",
"selfsigned": "^1.10.4",
"semver": "5.4.1",
"spellchecker": "3.5.1",
"tar": "4.4.8",
"testcheck": "1.0.0-rc.2",
"tmp": "0.0.33",
"to-arraybuffer": "1.0.1",
"underscore": "1.9.0",
"uuid": "3.3.2",
"websocket": "1.0.28"
},
"devDependencies": {
"@types/chai": "4.1.2",
"@types/classnames": "2.2.3",
"@types/color": "^3.0.0",
"@types/config": "0.0.34",
"@types/filesize": "3.6.0",
"@types/fs-extra": "5.0.5",
"@types/google-libphonenumber": "7.4.14",
"@types/got": "9.4.1",
"@types/jquery": "3.3.29",
"@types/js-yaml": "3.12.0",
"@types/linkify-it": "2.0.3",
"@types/lodash": "4.14.106",
"@types/mkdirp": "0.5.2",
"@types/mocha": "5.0.0",
"@types/pify": "3.0.2",
"@types/qs": "6.5.1",
"@types/react": "16.8.5",
"@types/react-dom": "16.8.2",
"@types/react-portal": "^4.0.2",
"@types/react-redux": "7.0.1",
"@types/react-virtualized": "9.18.12",
"@types/redux-logger": "3.0.7",
"@types/rimraf": "2.0.2",
"@types/semver": "5.5.0",
"@types/sinon": "4.3.1",
"@types/uuid": "3.4.4",
"arraybuffer-loader": "1.0.3",
"asar": "0.14.0",
"axios": "0.18.0",
"bower": "1.8.2",
"chai": "4.1.2",
"dashdash": "1.14.1",
"electron": "4.1.2",
"electron-builder": "21.2.0",
"electron-icon-maker": "0.0.3",
"electron-notarize": "^0.2.0",
"eslint": "4.14.0",
"eslint-config-airbnb-base": "12.1.0",
"eslint-config-prettier": "2.9.0",
"eslint-plugin-import": "2.8.0",
"eslint-plugin-mocha": "4.12.1",
"eslint-plugin-more": "0.3.1",
"extract-zip": "1.6.6",
"grunt": "1.0.1",
"grunt-cli": "1.2.0",
"grunt-contrib-concat": "1.0.1",
"grunt-contrib-copy": "1.0.0",
"grunt-contrib-watch": "1.0.0",
"grunt-exec": "3.0.0",
"grunt-gitinfo": "0.1.7",
"grunt-sass": "3.0.1",
"mocha": "4.1.0",
"mocha-testcheck": "1.0.0-rc.0",
"node-sass-import-once": "1.2.0",
"nyc": "11.4.1",
"prettier": "1.12.0",
"qs": "6.5.1",
"react-docgen-typescript": "1.2.6",
"react-styleguidist": "7.0.1",
"sinon": "4.4.2",
"spectron": "5.0.0",
"ts-loader": "4.1.0",
"tslint": "5.13.0",
"tslint-microsoft-contrib": "6.0.0",
"tslint-react": "3.6.0",
"typescript": "3.3.3333",
"webpack": "4.4.1"
},
"engines": {
"node": "10.13.0"
},
"build": {
"appId": "com.loki-project.messenger-desktop",
"afterSign": "build/notarize.js",
"mac": {
"artifactName": "${name}-mac-${version}.${ext}",
"category": "public.app-category.social-networking",
"icon": "build/icons/mac/icon.icns",
"target": [
"dmg"
],
"bundleVersion": "1",
"hardenedRuntime": true,
"gatekeeperAssess": false,
"entitlements": "build/entitlements.mac.plist",
"entitlementsInherit": "build/entitlements.mac.plist"
},
"dmg": {
"sign": false
},
"win": {
"asarUnpack": "node_modules/spellchecker/vendor/hunspell_dictionaries",
"artifactName": "${name}-win-${version}.${ext}",
"publisherName": "Loki Project",
"icon": "build/icons/win/icon.ico",
"publish": [
{
"provider": "generic",
"url": "https://updates.signal.org/desktop"
}
],
"target": [
"nsis"
]
},
"nsis": {
"deleteAppDataOnUninstall": true
},
"linux": {
"category": "Network",
"desktop": {
"StartupWMClass": "Loki Messenger"
},
"asarUnpack": "node_modules/spellchecker/vendor/hunspell_dictionaries",
"target": [
"deb"
],
"icon": "build/icons/png"
},
"deb": {
"depends": [
"libnotify4",
"libappindicator1",
"libxtst6",
"libnss3",
"libasound2",
"libxss1"
]
},
"files": [
"package.json",
"config/default.json",
"config/${env.SIGNAL_ENV}.json",
"config/local-${env.SIGNAL_ENV}.json",
"background.html",
"about.html",
"settings.html",
"password.html",
"permissions_popup.html",
"debug_log.html",
"_locales/**",
"libloki/modules/*.js",
"mnemonic_languages/**",
"protos/*",
"js/**",
"ts/**/*.js",
"ts/*.js",
"stylesheets/*.css",
"!js/register.js",
"js/views/standalone_registration_view.js",
"app/*",
"preload.js",
"about_preload.js",
"settings_preload.js",
"permissions_popup_preload.js",
"debug_log_preload.js",
"password_preload.js",
"main.js",
"images/**",
"fonts/*",
"build/assets",
"node_modules/**",
"!node_modules/emoji-panel/dist/*",
"!node_modules/emoji-panel/lib/emoji-panel-emojione-*.css",
"!node_modules/emoji-panel/lib/emoji-panel-google-*.css",
"!node_modules/emoji-panel/lib/emoji-panel-twitter-*.css",
"!node_modules/emoji-panel/lib/emoji-panel-apple-{16,20,64}.css",
"!node_modules/emoji-datasource/emoji_pretty.json",
"!node_modules/emoji-datasource/*.png",
"!node_modules/emoji-datasource-apple/emoji_pretty.json",
"!node_modules/emoji-datasource-apple/img/apple/{sheets-128,sheets-256}/*.png",
"!node_modules/emoji-datasource-apple/img/apple/sheets/{16,20,32}.png",
"!node_modules/spellchecker/vendor/hunspell/**/*",
"!**/node_modules/*/{CHANGELOG.md,README.md,README,readme.md,readme,test,__tests__,tests,powered-test,example,examples,*.d.ts}",
"!**/node_modules/.bin",
"!**/node_modules/*/build/**",
"!**/*.{o,hprof,orig,pyc,pyo,rbc}",
"!**/._*",
"!**/{.DS_Store,.git,.hg,.svn,CVS,RCS,SCCS,__pycache__,thumbs.db,.gitignore,.gitattributes,.editorconfig,.flowconfig,.yarn-metadata.json,.idea,appveyor.yml,.travis.yml,circle.yml,npm-debug.log,.nyc_output,yarn.lock,.yarn-integrity}",
"node_modules/spellchecker/build/Release/*.node",
"node_modules/websocket/build/Release/*.node",
"node_modules/socks/build/*.js",
"node_modules/socks/build/common/*.js",
"node_modules/socks/build/client/*.js",
"node_modules/smart-buffer/build/*.js",
"!node_modules/@journeyapps/sqlcipher/deps/*"
]
}
}

@ -97,6 +97,14 @@ div.spacer-lg {
opacity: 0.6;
}
.text-soft {
opacity: 0.4;
}
.fullwidth {
width: 100%;
}
$session-transition-duration: 0.25s;
$session-icon-size-sm: 15px;
@ -256,6 +264,30 @@ $session_message-container-border-radius: 5px;
}
}
.session-label {
color: $session-color-white;
padding: $session-margin-sm;
width: 100%;
border-radius: 2px;
text-align: center;
&.primary {
background-color: $session-color-primary;
}
&.secondary {
background-color: $session-color-secondary;
}
&.success {
background-color: $session-color-success;
}
&.danger {
background-color: $session-color-danger;
}
&.warning {
background-color: $session-color-warning;
}
}
@mixin set-icon-margin($size) {
margin: $size / 3;
}
@ -551,8 +583,7 @@ label {
}
&__body {
padding: $session-margin-lg;
padding: 0px $session-margin-lg $session-margin-lg $session-margin-lg;
font-family: 'Wasa';
line-height: 16px;
font-size: 13px;
@ -562,10 +593,16 @@ label {
}
}
&__centered {
display: flex;
flex-direction: column;
align-items: center;
}
&__button-group {
display: flex;
justify-content: flex-end;
.session-button {
margin-left: $session-margin-sm;
}
@ -574,14 +611,11 @@ label {
display: flex;
justify-content: center;
}
.session-button {
margin: 0 $session-margin-xs;
}
}
}
.session-toggle {

@ -0,0 +1,171 @@
import React from 'react';
import { ImpulseSpinner } from 'react-spinners-kit';
import { SessionModal } from './session/SessionModal';
import { SessionButton } from './session/SessionButton';
interface Props {
i18n: any;
onClose: any;
}
interface State {
title: string;
error: string | null;
connecting: boolean;
view: 'connecting' | 'default';
}
export class AddServerDialog extends React.Component<Props, State> {
constructor(props: any) {
super(props);
this.state = {
title: '',
error: null,
connecting: false,
view: 'default',
};
this.confirm = this.confirm.bind(this);
this.showError = this.showError.bind(this);
this.showView = this.showView.bind(this);
this.closeDialog = this.closeDialog.bind(this);
this.onKeyUp = this.onKeyUp.bind(this);
}
public render() {
const { i18n } = this.props;
return (
<SessionModal
title={this.state.title}
onOk={() => null}
onClose={this.closeDialog}
>
{this.state.view === 'default' ? (
<>
<div className="spacer-lg" />
<input type="text" id="server-url" placeholder="Server Url" />
<div className="spacer-sm" />
{this.showError()}
<div className="session-modal__button-group">
<SessionButton
text={i18n('connect')}
onClick={() => this.showView('connecting')}
/>
<SessionButton text={i18n('cancel')} onClick={this.closeDialog} />
</div>
</>
) : null}
{this.state.view === 'connecting' ? (
<>
connecting!
<br />
<ClipLoader/>
<div className="spacer-lg" />
<div className="session-modal__button-group">
<SessionButton
text={i18n('cancel')}
onClick={() => this.showView('default')}
/>
</div>
</>
) : null}
</SessionModal>
);
}
private showView(view: 'default' | 'connecting') {
const { i18n } = this.props;
if (view === 'default') {
this.setState({
title: i18n('addServerDialogTitle'),
error: null,
view: 'default',
});
}
if (view === 'connecting') {
this.setState({
title: i18n('connectingLoad'),
error: null,
view: 'connecting',
});
}
}
private confirm() {
// const { i18n } = this.props;
// Remove error if there is one
this.setState({
error: null,
});
const connected = false;
const serverUrl = String(
$('.add-server-dialog #server-url').val()
).toLowerCase();
// // TODO: Make this not hard coded
const channelId = 1;
console.log(serverUrl);
if (connected) {
// window.pushToast({
// title: i18n('connectToServerSuccess'),
// type: 'success',
// id: 'connectToServerSuccess',
// });
this.closeDialog();
}
}
private showError() {
const message = this.state.error;
return (
<>
{message ? (
<>
<div className="session-label danger">{message}</div>
<div className="spacer-lg" />
</>
) : null}
</>
);
// if (_.isEmpty(message)) {
// this.$('.error').text('');
// this.$('.error').hide();
// } else {
// this.$('.error').text(`Error: ${message}`);
// this.$('.error').show();
// }
// $('input').focus();
}
private onKeyUp(event: any) {
switch (event.key) {
case 'Esc':
case 'Escape':
this.closeDialog();
break;
default:
}
}
private closeDialog() {
window.removeEventListener('keyup', this.onKeyUp);
this.props.onClose();
}
}

@ -1,23 +1,30 @@
import React from 'react';
import { QRCode } from 'react-qrcode'
import { QRCode } from 'react-qrcode';
import { SessionModal } from './session/SessionModal';
import { SessionButton } from './session/SessionButton';
interface Props {
i18n: any,
onClose: any,
pubKeyToUnpair: string | null;
pubKey: string | null;
i18n: any;
onClose: any;
pubKeyToUnpair: string | null;
pubKey: string | null;
}
interface State {
accepted: boolean;
isListening: boolean;
success: boolean;
loading: boolean;
data: Array<any>;
currentPubKey: string | null;
accepted: boolean;
isListening: boolean;
success: boolean;
loading: boolean;
view:
| 'default'
| 'waitingForRequest'
| 'requestReceived'
| 'requestAccepted'
| 'confirmUnpair';
pubKeyRequests: Array<any>;
data: Array<any>;
}
export class DevicePairingDialog extends React.Component<Props, State> {
@ -31,122 +38,242 @@ export class DevicePairingDialog extends React.Component<Props, State> {
this.getPubkeyName = this.getPubkeyName.bind(this);
this.state = {
accepted: false,
isListening: false,
success: false,
loading: true,
data: [],
currentPubKey: this.props.pubKey,
accepted: false,
isListening: false,
success: false,
loading: true,
view: 'default',
pubKeyRequests: [],
data: [],
};
}
componentDidMount() {
this.getSecondaryDevices();
this.getSecondaryDevices();
}
private async getSecondaryDevices(){
const secondaryDevices = await window.libloki.storage.getSecondaryDevicesFor(this.props.pubKey);
private async getSecondaryDevices() {
const secondaryDevices = await window.libloki.storage.getSecondaryDevicesFor(
this.state.currentPubKey
);
this.setState({
data: secondaryDevices,
loading: false
data: secondaryDevices,
loading: false,
});
}
public render() {
const {i18n, } = this.props;
const { i18n } = this.props;
const newData = ['053e18835c106a5f9f463a44a9d7ff9a26281d529285a047bd969cfc59d4ab8607'];
const newData = [
'053e18835c106a5f9f463a44a9d7ff9a26281d529285a047bd969cfc59d4ab8607',
'053e18835c106a5f9f463a44a9d7ff9a26281d529285a047bd969cfc59d4ab8604',
];
setTimeout(() => {
this.setState({
data: newData,
});
this.setState({
data: newData,
});
}, 2000);
return (
<>
{ ! this.state.loading ? (
<SessionModal
title={i18n('pairedDevices')}
onOk={() => null}
onClose={this.closeDialog}
>
{ this.state.isListening ? (
<div>
{i18n('waitingForDeviceToRegister')}
<div className="spacer-lg"></div>
<div id="qr">
<QRCode value={window.textsecure.storage.user.getNumber()}/>
</div>
<>
{!this.state.loading ? (
<SessionModal
title={i18n('pairedDevices')}
onOk={() => null}
onClose={this.closeDialog}
>
{this.state.view === 'waitingForRequest' ? (
<div className="session-modal__centered">
<h3>{i18n('waitingForDeviceToRegister')}</h3>
<small className="text-subtle">
{i18n('pairNewDevicePrompt')}
</small>
<div className="spacer-lg" />
</div>
)
: (
<>
{this.state.data.length == 0 ? (
<>
<div>{i18n('noPairedDevices')}</div>
<div className="spacer-lg"></div>
<div className="session-modal__button-group__center">
<SessionButton
text = {i18n('pairNewDevice')}
onClick = {this.startReceivingRequests}
/>
</div>
</>
)
: (
<>
{
this.state.data.map((pubKey: any) => {
const pubKeyInfo = this.getPubkeyName(pubKey);
return (
<p>
{ pubKeyInfo.deviceAlias }
<br/>
<span className="text-subtle">Pairing Secret:</span> { pubKeyInfo.secretWords }
</p>
);
})
}
</>
)}
</>
<div id="qr">
<QRCode value={window.textsecure.storage.user.getNumber()} />
</div>
<div className="spacer-lg" />
<div className="session-modal__button-group__center">
<SessionButton
text={i18n('cancel')}
onClick={this.stopReceivingRequests}
/>
</div>
</div>
) : (
<>
{this.state.data.length == 0 ? (
<div className="session-modal__centered">
<div>{i18n('noPairedDevices')}</div>
</div>
) : (
<div className="session-modal__centered">
{this.state.data.map((pubKey: any) => {
const pubKeyInfo = this.getPubkeyName(pubKey);
const isFinalItem =
this.state.data[this.state.data.length - 1] === pubKey;
return (
<div key={pubKey}>
<p>
{pubKeyInfo.deviceAlias}
<br />
<span className="text-subtle">
Pairing Secret:
</span>{' '}
{pubKeyInfo.secretWords}
</p>
{!isFinalItem ? (
<hr className="text-soft fullwidth" />
) : null}
</div>
);
})}
</div>
)}
</SessionModal>
) : null }
<div className="spacer-lg" />
<div className="session-modal__button-group__center">
<SessionButton
text={i18n('pairNewDevice')}
onClick={this.startReceivingRequests}
/>
</div>
</>
)}
</SessionModal>
) : null}
</>
);
}
private showView(
view?:
| 'default'
| 'waitingForRequest'
| 'requestReceived'
| 'requestAccepted'
| 'confirmUnpair'
) {
if (!view) {
this.setState({
view: 'default',
});
return;
}
this.setState({ view });
}
private startReceivingRequests() {
this.setState({
isListening: true,
isListening: true,
});
this.showView('waitingForRequest');
//TESTING
//TESTING
//TESTING
setTimeout(() => {
this.setState({
accepted: true,
success: true,
});
}, 3000);
}
private getPubkeyName(pubKey: string) {
private getPubkeyName(pubKey: string | null) {
if (!pubKey) {
return {};
}
const secretWords = window.mnemonic.pubkey_to_secret_words(pubKey);
const conv = window.ConversationController.get(this.props.pubKey);
const conv = window.ConversationController.get(this.state.currentPubKey);
const deviceAlias = conv ? conv.getNickname() : 'Unnamed Device';
return {deviceAlias, secretWords};
return { deviceAlias, secretWords };
}
private stopReceivingRequests() {
if (this.state.success) {
const conv = window.ConversationController.get(this.props.pubKey);
//if (conv) {
// conv.setNickname(this.props.deviceAlias);
//}
const deviceAlias = this.getPubkeyName(this.state.currentPubKey)[
'deviceAlias'
];
const conv = window.ConversationController.get(this.state.currentPubKey);
if (conv) {
conv.setNickname(deviceAlias);
}
}
this.forceUpdate();
this.showView();
}
private requestReceived(secondaryDevicePubKey: string | EventHandlerNonNull) {
// FIFO: push at the front of the array with unshift()
this.state.pubKeyRequests.unshift(secondaryDevicePubKey);
if (!this.state.currentPubKey) {
this.nextPubKey();
this.showView('requestReceived');
}
}
allowDevice() {
this.setState({
accepted: true,
});
window.Whisper.trigger(
'devicePairingRequestAccepted',
this.state.currentPubKey,
(errors: any) => this.transmisssionCB(errors)
);
this.showView();
}
transmisssionCB(errors: any) {
if (!errors) {
// this.$('.transmissionStatus').text(i18n('provideDeviceAlias'));
// this.$('#deviceAliasView').show();
// this.$('#deviceAlias').on('input', e => {
// if (e.target.value.trim()) {
// this.$('.requestAcceptedView .ok').removeAttr('disabled');
// } else {
// this.$('.requestAcceptedView .ok').attr('disabled', true);
// }
// });
// this.$('.requestAcceptedView .ok').show();
// this.$('.requestAcceptedView .ok').attr('disabled', true);
this.setState({
success: true,
});
} else {
// this.$('.transmissionStatus').text(errors);
// this.$('.requestAcceptedView .ok').show();
}
}
skipDevice() {
window.Whisper.trigger(
'devicePairingRequestRejected',
this.state.currentPubKey
);
this.nextPubKey();
this.showView();
}
nextPubKey() {
// FIFO: pop at the back of the array using pop()
const pubKeyRequests = this.state.pubKeyRequests;
this.setState({
currentPubKey: pubKeyRequests.pop(),
});
}
private onKeyUp(event: any) {
switch (event.key) {
@ -160,6 +287,7 @@ export class DevicePairingDialog extends React.Component<Props, State> {
private closeDialog() {
window.removeEventListener('keyup', this.onKeyUp);
this.stopReceivingRequests();
this.props.onClose();
}
}
}

1
ts/global.d.ts vendored

@ -14,6 +14,7 @@ interface Window {
Session: any;
i18n: any;
generateID: any;
pushToast: any;
}
interface Promise<T> {

Loading…
Cancel
Save