diff --git a/.gitignore b/.gitignore index 4cb12784f5..1eb148df02 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ test/test.js # React / TypeScript ts/**/*.js +ts/protobuf/*.d.ts diff --git a/.prettierignore b/.prettierignore index ed8fd952d7..c7b5de7190 100644 --- a/.prettierignore +++ b/.prettierignore @@ -2,14 +2,19 @@ # supports `.gitignore`: https://github.com/prettier/prettier/issues/2294 # Generated files +config/local-*.json +config/local.json dist/** js/components.js js/libsignal-protocol-worker.js js/libtextsecure.js libtextsecure/components.js libtextsecure/test/test.js +stylesheets/*.css test/test.js ts/**/*.js +ts/protobuf/*.d.ts +ts/protobuf/*.js # Third-party files components/** diff --git a/.travis.yml b/.travis.yml index 96730e76c2..b56c17dd63 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,11 +7,10 @@ dist: trusty install: - yarn install --frozen-lockfile script: - - yarn transpile + - yarn generate - yarn lint - yarn test-node - yarn nsp check - - yarn generate - yarn prepare-beta-build - $(yarn bin)/build --config.extraMetadata.environment=$SIGNAL_ENV --config.mac.bundleVersion='$TRAVIS_BUILD_NUMBER' --publish=never - ./travis.sh diff --git a/Gruntfile.js b/Gruntfile.js index 72d0aa4e85..4b23b8bdad 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -186,17 +186,21 @@ module.exports = function(grunt) { }, }, watch: { - sass: { - files: ['./stylesheets/*.scss'], - tasks: ['sass'], + dist: { + files: ['<%= dist.src %>', '<%= dist.res %>'], + tasks: ['copy_dist'], }, libtextsecure: { files: ['./libtextsecure/*.js', './libtextsecure/storage/*.js'], tasks: ['concat:libtextsecure'], }, - dist: { - files: ['<%= dist.src %>', '<%= dist.res %>'], - tasks: ['copy_dist'], + protobuf: { + files: ['./protos/SignalService.proto'], + tasks: ['exec:build-protobuf'], + }, + sass: { + files: ['./stylesheets/*.scss'], + tasks: ['sass'], }, scripts: { files: ['<%= jshint.files %>'], @@ -216,7 +220,10 @@ module.exports = function(grunt) { cmd: 'tx pull', }, transpile: { - cmd: 'npm run transpile', + cmd: 'yarn transpile', + }, + 'build-protobuf': { + cmd: 'yarn build-protobuf', }, }, 'test-release': { @@ -499,10 +506,11 @@ module.exports = function(grunt) { grunt.registerTask('copy_dist', ['gitinfo', 'copy:res', 'copy:src']); grunt.registerTask('date', ['gitinfo', 'getExpireTime']); grunt.registerTask('default', [ + 'exec:build-protobuf', + 'exec:transpile', 'concat', 'copy:deps', 'sass', 'date', - 'exec:transpile', ]); }; diff --git a/appveyor.yml b/appveyor.yml index 52dac757c0..1ba2bac72a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -12,11 +12,10 @@ install: - yarn install --frozen-lockfile build_script: - - yarn transpile + - yarn generate - yarn lint-windows - yarn test-node - yarn nsp check - - yarn generate - node build\grunt.js - type package.json | findstr /v certificateSubjectName > temp.json - move temp.json package.json diff --git a/js/models/messages.js b/js/models/messages.js index 67431eea68..032428d215 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -1,10 +1,12 @@ /* global _: false */ /* global Backbone: false */ -/* global Whisper: false */ -/* global textsecure: false */ + /* global ConversationController: false */ -/* global i18n: false */ /* global getAccountManager: false */ +/* global i18n: false */ +/* global Signal: false */ +/* global textsecure: false */ +/* global Whisper: false */ /* eslint-disable more/no-then */ @@ -14,8 +16,8 @@ window.Whisper = window.Whisper || {}; - const { Message: TypedMessage } = window.Signal.Types; - const { deleteAttachmentData } = window.Signal.Migrations; + const { Message: TypedMessage } = Signal.Types; + const { deleteAttachmentData } = Signal.Migrations; window.Whisper.Message = Backbone.Model.extend({ database: Whisper.Database, @@ -31,9 +33,6 @@ this.on('change:expireTimer', this.setToExpire); this.on('unload', this.unload); this.setToExpire(); - - this.VOICE_FLAG = - textsecure.protobuf.AttachmentPointer.Flags.VOICE_MESSAGE; }, idForLogging() { return `${this.get('source')}.${this.get('sourceDevice')} ${this.get( @@ -246,8 +245,7 @@ }); return Object.assign({}, attachment, { - // eslint-disable-next-line no-bitwise - isVoiceMessage: Boolean(attachment.flags & this.VOICE_FLAG), + isVoiceMessage: Signal.Types.Attachment.isVoiceMessage(attachment), thumbnail: thumbnailWithObjectUrl, }); }, diff --git a/js/modules/types/attachment.js b/js/modules/types/attachment.js index 5010f87fc4..1420152654 100644 --- a/js/modules/types/attachment.js +++ b/js/modules/types/attachment.js @@ -179,4 +179,5 @@ exports.deleteData = deleteAttachmentData => { }; }; +exports.isVoiceMessage = AttachmentTS.isVoiceMessage; exports.save = AttachmentTS.save; diff --git a/js/views/attachment_view.js b/js/views/attachment_view.js index 798039e7c4..15654e82bd 100644 --- a/js/views/attachment_view.js +++ b/js/views/attachment_view.js @@ -5,7 +5,6 @@ /* global i18n: false */ /* global Signal: false */ -/* global textsecure: false */ /* global Whisper: false */ // eslint-disable-next-line func-names @@ -119,20 +118,7 @@ Signal.Backbone.Views.Lightbox.show(this.lightboxView.el); }, isVoiceMessage() { - if ( - // eslint-disable-next-line no-bitwise - this.model.flags & - textsecure.protobuf.AttachmentPointer.Flags.VOICE_MESSAGE - ) { - return true; - } - - // Support for android legacy voice messages - if (this.isAudio() && this.model.fileName === null) { - return true; - } - - return false; + return Signal.Types.Attachment.isVoiceMessage(this.model); }, isAudio() { const { contentType } = this.model; diff --git a/libtextsecure/test/index.html b/libtextsecure/test/index.html index ca81c39ad7..acb9304363 100644 --- a/libtextsecure/test/index.html +++ b/libtextsecure/test/index.html @@ -2,7 +2,7 @@ - libTextSecure test runner + libtextsecure test runner diff --git a/package.json b/package.json index 583113b7cf..3213678bac 100644 --- a/package.json +++ b/package.json @@ -15,9 +15,13 @@ "start": "electron .", "grunt": "grunt", "icon-gen": "electron-icon-maker --input=images/icon_1024.png --output=./build", - "generate": "npm run icon-gen && grunt", + "generate": "yarn icon-gen && yarn grunt", "build": "build --config.extraMetadata.environment=$SIGNAL_ENV", "build-release": "SIGNAL_ENV=production npm run build -- --config.directories.output=release", + "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", @@ -69,6 +73,7 @@ "node-fetch": "https://github.com/scottnonnenberg/node-fetch.git#3e5f51e08c647ee5f20c43b15cf2d352d61c36b4", "os-locale": "^2.1.0", "pify": "^3.0.0", + "protobufjs": "^6.8.6", "proxy-agent": "^2.1.0", "react": "^16.2.0", "react-dom": "^16.2.0", diff --git a/protos/WhisperTextProtocol.proto b/protos/WhisperTextProtocol.proto deleted file mode 100644 index 852d5640b5..0000000000 --- a/protos/WhisperTextProtocol.proto +++ /dev/null @@ -1,28 +0,0 @@ -package signalservice; - -option java_package = "org.whispersystems.libsignal.protocol"; -option java_outer_classname = "WhisperProtos"; - -message WhisperMessage { - optional bytes ephemeralKey = 1; - optional uint32 counter = 2; - optional uint32 previousCounter = 3; - optional bytes ciphertext = 4; // PushMessageContent -} - -message PreKeyWhisperMessage { - optional uint32 registrationId = 5; - optional uint32 preKeyId = 1; - optional uint32 signedPreKeyId = 6; - optional bytes baseKey = 2; - optional bytes identityKey = 3; - optional bytes message = 4; // WhisperMessage -} - -message KeyExchangeMessage { - optional uint32 id = 1; - optional bytes baseKey = 2; - optional bytes ephemeralKey = 3; - optional bytes identityKey = 4; - optional bytes baseKeySignature = 5; -} diff --git a/ts/components/conversation/Message.md b/ts/components/conversation/Message.md index afefcd5078..1b01c3cba1 100644 --- a/ts/components/conversation/Message.md +++ b/ts/components/conversation/Message.md @@ -597,7 +597,7 @@ const outgoing = new Whisper.Message({ sent_at: Date.now() - 15000, attachments: [ { - flags: textsecure.protobuf.AttachmentPointer.Flags.VOICE_MESSAGE, + flags: SignalService.AttachmentPointer.Flags.VOICE_MESSAGE, data: util.mp3, fileName: 'agnus_dei.mp3', contentType: 'audio/mp3', diff --git a/ts/components/conversation/Quote.md b/ts/components/conversation/Quote.md index 7cdf0b514a..5ab2f58966 100644 --- a/ts/components/conversation/Quote.md +++ b/ts/components/conversation/Quote.md @@ -572,7 +572,7 @@ const outgoing = new Whisper.Message({ attachments: [ { // proposed as of afternoon of 4/6 in Quoted Replies group - flags: textsecure.protobuf.AttachmentPointer.Flags.VOICE_MESSAGE, + flags: SignalService.AttachmentPointer.Flags.VOICE_MESSAGE, contentType: 'audio/mp3', fileName: 'agnus_dei.mp4', }, diff --git a/ts/components/conversation/media-gallery/DocumentListItem.tsx b/ts/components/conversation/media-gallery/DocumentListItem.tsx index b5d6394038..b8e83bcec9 100644 --- a/ts/components/conversation/media-gallery/DocumentListItem.tsx +++ b/ts/components/conversation/media-gallery/DocumentListItem.tsx @@ -4,7 +4,7 @@ import moment from 'moment'; import formatFileSize from 'filesize'; interface Props { - fileName?: string; + fileName?: string | null; fileSize?: number; i18n: (key: string, values?: Array) => string; onClick?: () => void; diff --git a/ts/protobuf/README.md b/ts/protobuf/README.md new file mode 100644 index 0000000000..57cdbc733d --- /dev/null +++ b/ts/protobuf/README.md @@ -0,0 +1,3 @@ +# Protocol Buffers + +Placeholder directory for Protocol Buffers compiled to JavaScript / TypeScript. diff --git a/ts/protobuf/index.ts b/ts/protobuf/index.ts new file mode 100644 index 0000000000..c760e2caec --- /dev/null +++ b/ts/protobuf/index.ts @@ -0,0 +1,3 @@ +import { signalservice as SignalService } from './compiled'; + +export { SignalService }; diff --git a/ts/styleguide/StyleGuideUtil.ts b/ts/styleguide/StyleGuideUtil.ts index ecba629d8f..1b8167c699 100644 --- a/ts/styleguide/StyleGuideUtil.ts +++ b/ts/styleguide/StyleGuideUtil.ts @@ -19,7 +19,9 @@ export { BackboneWrapper } from '../components/utility/BackboneWrapper'; import { Quote } from '../components/conversation/Quote'; import * as HTML from '../html'; +import * as Attachment from '../../ts/types/Attachment'; import * as MIME from '../../ts/types/MIME'; +import { SignalService } from '../../ts/protobuf'; // TypeScript wants two things when you import: // 1) a normal typescript file @@ -125,10 +127,12 @@ parent.ReactDOM = ReactDOM; parent.Signal.HTML = HTML; parent.Signal.Types.MIME = MIME; +parent.Signal.Types.Attachment = Attachment; parent.Signal.Components = { Quote, }; parent.Signal.Util = Util; +parent.SignalService = SignalService; parent.filesize = filesize; parent.ConversationController._initialFetchComplete = true; diff --git a/ts/test/types/Attachment_test.ts b/ts/test/types/Attachment_test.ts index 343373d4ba..14b0cdcee7 100644 --- a/ts/test/types/Attachment_test.ts +++ b/ts/test/types/Attachment_test.ts @@ -5,7 +5,8 @@ import 'mocha'; import { assert } from 'chai'; import * as Attachment from '../../types/Attachment'; -import { MIMEType } from '../../types/MIME'; +import * as MIME from '../../types/MIME'; +import { SignalService } from '../../protobuf'; // @ts-ignore import { stringToArrayBuffer } from '../../../js/modules/string_to_array_buffer'; @@ -14,7 +15,7 @@ describe('Attachment', () => { it('should return file extension from content type', () => { const input: Attachment.Attachment = { data: stringToArrayBuffer('foo'), - contentType: 'image/gif' as MIMEType, + contentType: MIME.IMAGE_GIF, }; assert.strictEqual(Attachment.getFileExtension(input), 'gif'); }); @@ -22,7 +23,7 @@ describe('Attachment', () => { it('should return file extension for QuickTime videos', () => { const input: Attachment.Attachment = { data: stringToArrayBuffer('foo'), - contentType: 'video/quicktime' as MIMEType, + contentType: MIME.VIDEO_QUICKTIME, }; assert.strictEqual(Attachment.getFileExtension(input), 'mov'); }); @@ -34,7 +35,7 @@ describe('Attachment', () => { const attachment: Attachment.Attachment = { fileName: 'funny-cat.mov', data: stringToArrayBuffer('foo'), - contentType: 'video/quicktime' as MIMEType, + contentType: MIME.VIDEO_QUICKTIME, }; const actual = Attachment.getSuggestedFilename({ attachment }); const expected = 'funny-cat.mov'; @@ -45,7 +46,7 @@ describe('Attachment', () => { it('should generate a filename based on timestamp', () => { const attachment: Attachment.Attachment = { data: stringToArrayBuffer('foo'), - contentType: 'video/quicktime' as MIMEType, + contentType: MIME.VIDEO_QUICKTIME, }; const timestamp = new Date(new Date(0).getTimezoneOffset() * 60 * 1000); const actual = Attachment.getSuggestedFilename({ @@ -57,4 +58,34 @@ describe('Attachment', () => { }); }); }); + + describe('isVoiceMessage', () => { + it('should return true for voice message attachment', () => { + const attachment: Attachment.Attachment = { + fileName: 'Voice Message.aac', + flags: SignalService.AttachmentPointer.Flags.VOICE_MESSAGE, + data: stringToArrayBuffer('voice message'), + contentType: MIME.AUDIO_AAC, + }; + assert.isTrue(Attachment.isVoiceMessage(attachment)); + }); + + it('should return true for legacy Android voice message attachment', () => { + const attachment: Attachment.Attachment = { + fileName: null, + data: stringToArrayBuffer('voice message'), + contentType: MIME.AUDIO_MP3, + }; + assert.isTrue(Attachment.isVoiceMessage(attachment)); + }); + + it('should return false for other attachments', () => { + const attachment: Attachment.Attachment = { + fileName: 'foo.gif', + data: stringToArrayBuffer('foo'), + contentType: MIME.IMAGE_GIF, + }; + assert.isFalse(Attachment.isVoiceMessage(attachment)); + }); + }); }); diff --git a/ts/test/types/message/initializeAttachmentMetadata_test.ts b/ts/test/types/message/initializeAttachmentMetadata_test.ts index d76618f280..9c87215f3b 100644 --- a/ts/test/types/message/initializeAttachmentMetadata_test.ts +++ b/ts/test/types/message/initializeAttachmentMetadata_test.ts @@ -3,7 +3,7 @@ import { assert } from 'chai'; import * as Message from '../../../../ts/types/message/initializeAttachmentMetadata'; import { IncomingMessage } from '../../../../ts/types/Message'; -import { MIMEType } from '../../../../ts/types/MIME'; +import * as MIME from '../../../../ts/types/MIME'; // @ts-ignore import { stringToArrayBuffer } from '../../../../js/modules/string_to_array_buffer'; @@ -19,7 +19,7 @@ describe('Message', () => { sent_at: 1523317140800, attachments: [ { - contentType: 'image/jpeg' as MIMEType, + contentType: MIME.IMAGE_JPEG, data: stringToArrayBuffer('foo'), fileName: 'foo.jpg', size: 1111, @@ -35,7 +35,7 @@ describe('Message', () => { sent_at: 1523317140800, attachments: [ { - contentType: 'image/jpeg' as MIMEType, + contentType: MIME.IMAGE_JPEG, data: stringToArrayBuffer('foo'), fileName: 'foo.jpg', size: 1111, diff --git a/ts/types/Attachment.ts b/ts/types/Attachment.ts index d37b2f3e34..e4e58ffe84 100644 --- a/ts/types/Attachment.ts +++ b/ts/types/Attachment.ts @@ -2,13 +2,15 @@ import is from '@sindresorhus/is'; import moment from 'moment'; import * as GoogleChrome from '../util/GoogleChrome'; -import { saveURLAsFile } from '../util/saveURLAsFile'; +import * as MIME from './MIME'; import { arrayBufferToObjectURL } from '../util/arrayBufferToObjectURL'; -import { MIMEType } from './MIME'; +import { saveURLAsFile } from '../util/saveURLAsFile'; +import { SignalService } from '../protobuf'; export type Attachment = { - fileName?: string; - contentType?: MIMEType; + fileName?: string | null; + flags?: SignalService.AttachmentPointer.Flags; + contentType?: MIME.MIMEType; size?: number; data: ArrayBuffer; @@ -20,15 +22,12 @@ export type Attachment = { // thumbnail?: ArrayBuffer; // key?: ArrayBuffer; // digest?: ArrayBuffer; - // flags?: number; } & Partial; interface AttachmentSchemaVersion3 { path: string; } -const SAVE_CONTENT_TYPE = 'application/octet-stream' as MIMEType; - export const isVisualMedia = (attachment: Attachment): boolean => { const { contentType } = attachment; @@ -41,6 +40,26 @@ export const isVisualMedia = (attachment: Attachment): boolean => { return isSupportedImageType || isSupportedVideoType; }; +export const isVoiceMessage = (attachment: Attachment): boolean => { + const flag = SignalService.AttachmentPointer.Flags.VOICE_MESSAGE; + const hasFlag = + // tslint:disable-next-line no-bitwise + !is.undefined(attachment.flags) && (attachment.flags & flag) === flag; + if (hasFlag) { + return true; + } + + const isLegacyAndroidVoiceMessage = + !is.undefined(attachment.contentType) && + MIME.isAudio(attachment.contentType) && + attachment.fileName === null; + if (isLegacyAndroidVoiceMessage) { + return true; + } + + return false; +}; + export const save = ({ attachment, document, @@ -57,7 +76,7 @@ export const save = ({ ? getAbsolutePath(attachment.path) : arrayBufferToObjectURL({ data: attachment.data, - type: SAVE_CONTENT_TYPE, + type: MIME.APPLICATION_OCTET_STREAM, }); const filename = getSuggestedFilename({ attachment, timestamp }); saveURLAsFile({ url, filename, document }); diff --git a/ts/types/MIME.ts b/ts/types/MIME.ts index 620df41c96..c2cc66ac58 100644 --- a/ts/types/MIME.ts +++ b/ts/types/MIME.ts @@ -1,5 +1,12 @@ export type MIMEType = string & { _mimeTypeBrand: any }; +export const APPLICATION_OCTET_STREAM = 'application/octet-stream' as MIMEType; +export const AUDIO_AAC = 'audio/aac' as MIMEType; +export const AUDIO_MP3 = 'audio/mp3' as MIMEType; +export const IMAGE_GIF = 'image/gif' as MIMEType; +export const IMAGE_JPEG = 'image/jpeg' as MIMEType; +export const VIDEO_QUICKTIME = 'video/quicktime' as MIMEType; + export const isJPEG = (value: MIMEType): boolean => value === 'image/jpeg'; export const isImage = (value: MIMEType): boolean => value.startsWith('image/'); export const isVideo = (value: MIMEType): boolean => value.startsWith('video/'); diff --git a/yarn.lock b/yarn.lock index 47540d5bbb..86b435defe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -22,6 +22,49 @@ "7zip-bin-mac" "~1.0.1" "7zip-bin-win" "~2.2.0" +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + "@sindresorhus/is@^0.7.0": version "0.7.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" @@ -56,6 +99,10 @@ version "4.14.106" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.106.tgz#6093e9a02aa567ddecfe9afadca89e53e5dce4dd" +"@types/long@^3.0.32": + version "3.0.32" + resolved "https://registry.yarnpkg.com/@types/long/-/long-3.0.32.tgz#f4e5af31e9e9b196d8e5fca8a5e2e20aa3d60b69" + "@types/mocha@^5.0.0": version "5.0.0" resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.0.0.tgz#a3014921991066193f6c8e47290d4d598dfd19e6" @@ -68,6 +115,10 @@ version "8.9.4" resolved "https://registry.yarnpkg.com/@types/node/-/node-8.9.4.tgz#dfd327582a06c114eb6e0441fa3d6fab35edad48" +"@types/node@^8.9.4": + version "8.10.12" + resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.12.tgz#dcb66f6de39074a296534bd1a256a3c6a1c8f5b5" + "@types/qs@^6.5.1": version "6.5.1" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.5.1.tgz#a38f69c62528d56ba7bd1f91335a8004988d72f7" @@ -5326,6 +5377,10 @@ lolex@^2.2.0, lolex@^2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/lolex/-/lolex-2.3.2.tgz#85f9450425103bf9e7a60668ea25dc43274ca807" +long@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" + longest-streak@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-2.0.2.tgz#2421b6ba939a443bb9ffebf596585a50b4c38e2e" @@ -6947,6 +7002,24 @@ prop-types@^15.5.10, prop-types@^15.6.0, prop-types@^15.6.1: loose-envify "^1.3.1" object-assign "^4.1.1" +protobufjs@^6.8.6: + version "6.8.6" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.8.6.tgz#ce3cf4fff9625b62966c455fc4c15e4331a11ca2" + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/long" "^3.0.32" + "@types/node" "^8.9.4" + long "^4.0.0" + proxy-addr@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341"