diff --git a/package.json b/package.json index 7d79472e37b38c73fc51a7d3df14c2262a89cb3c..534ab12b6a97580ff59895978e4ac4d8ad171ad7 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "build-parity-electron": "cd packages/parity-electron && yarn build", "preelectron": "yarn build", "electron": "cd packages/fether-electron && yarn electron", - "lint": "semistandard 'packages/**/*.js' --parser babel-eslint", + "lint": "semistandard 'packages/**/*.js' 'packages/**/*.ts' --parser babel-eslint", "prepackage": "yarn build", "package": "cd packages/fether-electron && yarn package", "release": "cd packages/fether-electron && yarn release", diff --git a/packages/fether-electron/src/main/messages/index.js b/packages/fether-electron/src/main/messages/index.js index 42e9d3d6c14848d8812867b1a795fd044d486a9c..a2a1125cf85445a1d4512f837b094e75ad7ad46a 100644 --- a/packages/fether-electron/src/main/messages/index.js +++ b/packages/fether-electron/src/main/messages/index.js @@ -3,7 +3,7 @@ // // SPDX-License-Identifier: BSD-3-Clause -import { signerNewToken } from '@parity/electron'; +import { checkClockSync, signerNewToken } from '@parity/electron'; import Pino from '../utils/pino'; @@ -24,10 +24,16 @@ export default async (mainWindow, event, action, ...args) => { mainWindow.setContentSize(width, Math.round(newHeight) + 2); break; } + case 'check-clock-sync': { + checkClockSync().then(t => { + event.sender.send('check-clock-sync-reply', t); + }); + break; + } case 'signer-new-token': { const token = await signerNewToken(); // Send back the token to the renderer process - event.sender.send('asynchronous-reply', token); + event.sender.send('signer-new-token-reply', token); break; } default: diff --git a/packages/fether-react/src/stores/healthStore.js b/packages/fether-react/src/stores/healthStore.js index a0457e850352791c5d46732ea993d6e25f1ad487..435b8ffe9610c23560ba6e22ce1d51d3765d1e71 100644 --- a/packages/fether-react/src/stores/healthStore.js +++ b/packages/fether-react/src/stores/healthStore.js @@ -5,10 +5,16 @@ import { action, computed, observable } from 'mobx'; import BigNumber from 'bignumber.js'; +import isElectron from 'is-electron'; + import { nodeHealth$, syncing$ } from '@parity/light.js'; +import Debug from '../utils/debug'; import parityStore from './parityStore'; +const debug = Debug('healthStore'); +const electron = isElectron() ? window.require('electron') : null; + // List here all possible states of our health store. Each state can have a // payload. export const STATUS = { @@ -25,16 +31,30 @@ export const STATUS = { export class HealthStore { @observable nodeHealth; @observable syncing; + @observable clockSync; constructor () { nodeHealth$().subscribe(this.setNodeHealth); syncing$().subscribe(this.setSyncing); + + if (!electron) { + debug( + 'Not in Electron, ignoring clock sync verification.' + ); + return; + } + + const { ipcRenderer } = electron; + ipcRenderer.send('asynchronous-message', 'check-clock-sync'); + ipcRenderer.once('check-clock-sync-reply', (_, clockSync) => { + this.setClockSync(clockSync); + }); } /** * Calculate the current status. * - * @return [Object{ status: StatusEnum, payload: Any}] - An object which + * @return {Object{ status: StatusEnum, payload: Any}} - An object which * represents the current status, with a custom payload. */ @computed @@ -133,11 +153,7 @@ export class HealthStore { return { status: STATUS.NOINTERNET, payload: message }; } - if ( - message.includes( - 'Your clock is not in sync. Detected difference is too big for the protocol to work' - ) - ) { + if (this.clockSync && this.clockSync.isClockSync) { return { status: STATUS.CLOCKNOTSYNC, payload: message }; } @@ -149,6 +165,11 @@ export class HealthStore { this.nodeHealth = nodeHealth; }; + @action + setClockSync = clockSync => { + this.clockSync = clockSync; + }; + @action setSyncing = syncing => { this.syncing = syncing; diff --git a/packages/fether-react/src/stores/parityStore.js b/packages/fether-react/src/stores/parityStore.js index 0c026a06d1330a4150c6c8438daa58f91fe6fdc6..78b830f9db935dd111aac6c8cbd0663ca8b84d49 100644 --- a/packages/fether-react/src/stores/parityStore.js +++ b/packages/fether-react/src/stores/parityStore.js @@ -94,7 +94,7 @@ export class ParityStore { // Request new token from Electron debug('Requesting new token.'); ipcRenderer.send('asynchronous-message', 'signer-new-token'); - ipcRenderer.once('asynchronous-reply', (_, token) => { + ipcRenderer.once('signer-new-token-reply', (_, token) => { if (!token) { return; } diff --git a/packages/parity-electron/README.md b/packages/parity-electron/README.md index 9b194f7e34028891cd8bbdf5b8387fcbe5cfdf9e..48f155121b5f1c8254f6f7e63eda3b0f2994b486 100644 --- a/packages/parity-electron/README.md +++ b/packages/parity-electron/README.md @@ -76,3 +76,7 @@ If Parity has been downloaded to Electron's `userData` folder, then it deletes t #### `signerNewToken(): Promise` Runs `parity signer new-token` and resolves with a new secure token to be used in a dapp. Rejects if no token could be extracted. + +#### `checkClockSync(): Promise` + +Use SNTP to check if the local clock is synchronized; return the time drift. \ No newline at end of file diff --git a/packages/parity-electron/package.json b/packages/parity-electron/package.json index fe706c2b265cd0031f94dac69ca233937f9754c6..1809a99a7335b00e4e8ab80ee9568a18ec2a08ac 100644 --- a/packages/parity-electron/package.json +++ b/packages/parity-electron/package.json @@ -37,7 +37,8 @@ "command-exists": "^1.2.6", "debug": "^3.1.0", "electron-dl": "^1.11.0", - "promise-any": "^0.2.0" + "promise-any": "^0.2.0", + "sntp": "^3.0.1" }, "devDependencies": { "electron": "^2.0.2", diff --git a/packages/parity-electron/src/checkClockSync.ts b/packages/parity-electron/src/checkClockSync.ts new file mode 100644 index 0000000000000000000000000000000000000000..cf8b5eb187336d3dcdf4702f99839a589059e4bc --- /dev/null +++ b/packages/parity-electron/src/checkClockSync.ts @@ -0,0 +1,16 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. +// +// SPDX-License-Identifier: BSD-3-Clause + +import { time } from 'sntp'; + +export const MAX_TIME_DRIFT = 10000; // milliseconds + +export const checkClockSync = async () => { + const { t: timeDrift }: { t: number } = await time(); + return { + isClockSync: timeDrift < MAX_TIME_DRIFT, + timeDrift + }; +}; diff --git a/packages/parity-electron/src/fetchParity.ts b/packages/parity-electron/src/fetchParity.ts index c10a857532d47295a721bc3b4c0581f0ee7e9549..43414017229962b642a1d18ed35fd094dc9ddf31 100644 --- a/packages/parity-electron/src/fetchParity.ts +++ b/packages/parity-electron/src/fetchParity.ts @@ -123,7 +123,7 @@ export const fetchParity = async ( await fsChmod(downloadPath, '755'); // Double-check that Parity exists now. - return await getParityPath(); + return getParityPath(); }, { retries: 3 diff --git a/packages/parity-electron/src/index.ts b/packages/parity-electron/src/index.ts index 3c8c1863299df5a92ad2ea79b38e354df1b8b1a8..a7852affd064a9f0fd1c8b7e2bfe6812561628e3 100644 --- a/packages/parity-electron/src/index.ts +++ b/packages/parity-electron/src/index.ts @@ -7,6 +7,7 @@ import { CliObject, LoggerFunction } from './types'; import { setCli } from './utils/cli'; import { setLogger } from './utils/logger'; +export * from './checkClockSync'; export * from './getParityPath'; export * from './fetchParity'; export * from './isParityRunning'; diff --git a/yarn.lock b/yarn.lock index 67801d85f4871e462ea0acd9167f8a42374faa12..de316cfba16fbc1b4b33f5f55d39522a2b905247 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2540,6 +2540,19 @@ boom@2.x.x: dependencies: hoek "2.x.x" +boom@7.x.x: + version "7.2.0" + resolved "https://registry.yarnpkg.com/boom/-/boom-7.2.0.tgz#2bff24a55565767fde869ec808317eb10c48e966" + dependencies: + hoek "5.x.x" + +bounce@1.x.x: + version "1.2.0" + resolved "https://registry.yarnpkg.com/bounce/-/bounce-1.2.0.tgz#e3bac68c73fd256e38096551efc09f504873c8c8" + dependencies: + boom "7.x.x" + hoek "5.x.x" + boxen@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b" @@ -5993,6 +6006,10 @@ hoek@2.x.x: version "2.16.3" resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" +hoek@5.x.x: + version "5.0.3" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-5.0.3.tgz#b71d40d943d0a95da01956b547f83c4a5b4a34ac" + hoist-non-react-statics@^1.0.3: version "1.2.0" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb" @@ -10634,6 +10651,15 @@ sntp@1.x.x: dependencies: hoek "2.x.x" +sntp@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-3.0.1.tgz#1aa9088d3eb844ea8c0980fce1877884d4117d09" + dependencies: + boom "7.x.x" + bounce "1.x.x" + hoek "5.x.x" + teamwork "3.x.x" + sockjs-client@1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.1.4.tgz#5babe386b775e4cf14e7520911452654016c8b12" @@ -11208,6 +11234,10 @@ tar@^4: safe-buffer "^5.1.2" yallist "^3.0.2" +teamwork@3.x.x: + version "3.0.1" + resolved "https://registry.yarnpkg.com/teamwork/-/teamwork-3.0.1.tgz#ff38c7161f41f8070b7813716eb6154036ece196" + temp-dir@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d"