diff --git a/.eslintrc.yaml b/.eslintrc.yaml
index f29ef809e31..ed073426ebe 100644
--- a/.eslintrc.yaml
+++ b/.eslintrc.yaml
@@ -7,12 +7,16 @@ extends:
"eslint:recommended"
globals:
+ _: true
$: true
amplify: true
ko: true
+ LRUCache: true
+ wire: true
z: true
rules:
+ brace-style: [2, 1tbs]
comma-dangle: [2, always-multiline]
handle-callback-err: 2
indent: [2, 2, {SwitchCase: 1}]
diff --git a/app/page/auth.html b/app/page/auth.html
index 994f5211e81..b83200e884b 100644
--- a/app/page/auth.html
+++ b/app/page/auth.html
@@ -71,8 +71,8 @@
-
-
diff --git a/app/script/announce/AnnounceRepository.js b/app/script/announce/AnnounceRepository.js
index 5ce0a77211a..c2d6aefb1be 100644
--- a/app/script/announce/AnnounceRepository.js
+++ b/app/script/announce/AnnounceRepository.js
@@ -50,7 +50,7 @@
check_version() {
return this.announce_service.get_version().then((server_version) => {
- this.logger.info(`Found new version ${server_version}`);
+ this.logger.info(`Checking current webapp version. Server '${server_version}' vs. local '${z.util.Environment.version(false, true)}'`);
if (server_version > z.util.Environment.version(false, true)) {
amplify.publish(z.event.WebApp.LIFECYCLE.UPDATE, z.announce.UPDATE_SOURCE.WEBAPP);
diff --git a/app/script/assets/Asset.coffee b/app/script/assets/Asset.coffee
deleted file mode 100644
index 18c9a567091..00000000000
--- a/app/script/assets/Asset.coffee
+++ /dev/null
@@ -1,52 +0,0 @@
-#
-# Wire
-# Copyright (C) 2016 Wire Swiss GmbH
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see http://www.gnu.org/licenses/.
-#
-
-window.z ?= {}
-z.assets ?= {}
-
-# Asset entity for the asset service.
-class z.assets.Asset
- ###
- Construct a new asset for the asset service.
-
- @param config [Object] Asset configuration
- ###
- constructor: (config) ->
- @correlation_id = config.correlation_id or z.util.create_random_uuid()
- @content_type = config.content_type
- @array_buffer = config.array_buffer
- @payload =
- conv_id: config.conversation_id
- correlation_id: @correlation_id
- public: config.public or false
- tag: config.tag or 'medium'
- inline: config.inline or false
- nonce: @correlation_id
- md5: config.md5
- width: config.width
- height: config.height
- original_width: config.original_width or config.width
- original_height: config.original_height or config.width
- native_push: config.native_push or false
-
- # Create the content disposition header for the asset.
- get_content_disposition: ->
- payload = ['zasset']
- for key, value of @payload
- payload.push "#{key}=#{value}"
- return payload.join ';'
diff --git a/app/script/assets/Asset.js b/app/script/assets/Asset.js
new file mode 100644
index 00000000000..dc12310acb1
--- /dev/null
+++ b/app/script/assets/Asset.js
@@ -0,0 +1,65 @@
+/*
+ * Wire
+ * Copyright (C) 2016 Wire Swiss GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+
+'use strict';
+
+window.z = window.z || {};
+window.z.assets = z.assets || {};
+
+z.assets.Asset = class Asset {
+
+ /*
+ Construct a new asset for the asset service.
+
+ @deprecated
+ @param {Object} config - Asset configuration
+ */
+ constructor(config) {
+ this.correlation_id = config.correlation_id || z.util.create_random_uuid();
+ this.content_type = config.content_type;
+ this.array_buffer = config.array_buffer;
+ this.payload = {
+ conv_id: config.conversation_id,
+ correlation_id: this.correlation_id,
+ public: config.public || false,
+ tag: config.tag || 'medium',
+ inline: config.inline || false,
+ nonce: this.correlation_id,
+ md5: config.md5,
+ width: config.width,
+ height: config.height,
+ original_width: config.original_width || config.width,
+ original_height: config.original_height || config.width,
+ native_push: config.native_push || false,
+ };
+ }
+
+ /*
+ Create the content disposition header for the asset.
+ */
+ get_content_disposition() {
+ const payload = ['zasset'];
+ for (let key in this.payload) {
+ const value = this.payload[key];
+ payload.push(`${key}=${value}`);
+ }
+ return payload.join(';');
+ }
+
+};
diff --git a/app/script/assets/AssetCrypto.coffee b/app/script/assets/AssetCrypto.coffee
deleted file mode 100644
index 8cb2e5e4951..00000000000
--- a/app/script/assets/AssetCrypto.coffee
+++ /dev/null
@@ -1,76 +0,0 @@
-#
-# Wire
-# Copyright (C) 2016 Wire Swiss GmbH
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see http://www.gnu.org/licenses/.
-#
-
-window.z ?= {}
-z.assets ?= {}
-
-z.assets.AssetCrypto =
- ###
- @param plaintext [ArrayBuffer]
-
- @return key_bytes [ArrayBuffer] AES key used for encryption
- @return computed_sha256 [ArrayBuffer] SHA-256 checksum of the ciphertext
- @return ciphertext [ArrayBuffer] Encrypted plaintext
- ###
- encrypt_aes_asset: (plaintext) ->
- key = null
- iv_ciphertext = null
- computed_sha256 = null
- iv = new Uint8Array 16
-
- window.crypto.getRandomValues iv
-
- return window.crypto.subtle.generateKey {name: 'AES-CBC', length: 256}, true, ['encrypt']
- .then (ckey) ->
- key = ckey
-
- return window.crypto.subtle.encrypt {name: 'AES-CBC', iv: iv.buffer}, key, plaintext
- .then (ciphertext) ->
- iv_ciphertext = new Uint8Array(ciphertext.byteLength + iv.byteLength)
- iv_ciphertext.set iv, 0
- iv_ciphertext.set new Uint8Array(ciphertext), iv.byteLength
-
- return window.crypto.subtle.digest 'SHA-256', iv_ciphertext
- .then (digest) ->
- computed_sha256 = digest
-
- return window.crypto.subtle.exportKey 'raw', key
- .then (key_bytes) ->
- return [key_bytes, computed_sha256, iv_ciphertext.buffer]
-
- ###
- @param key_bytes [ArrayBuffer] AES key used for encryption
- @param computed_sha256 [ArrayBuffer] SHA-256 checksum of the ciphertext
- @param ciphertext [ArrayBuffer] Encrypted plaintext
-
- @param [ArrayBuffer]
- ###
- decrypt_aes_asset: (ciphertext, key_bytes, reference_sha256) ->
- return window.crypto.subtle.digest 'SHA-256', ciphertext
- .then (computed_sha256) ->
- a = new Uint32Array reference_sha256
- b = new Uint32Array computed_sha256
-
- if a.length is b.length and a.every((x, i) -> x is b[i])
- return window.crypto.subtle.importKey 'raw', key_bytes, 'AES-CBC', false, ['decrypt']
-
- throw new Error 'Encrypted asset does not match its SHA-256 hash'
- .then (key) ->
- iv = ciphertext.slice 0, 16
- img_ciphertext = ciphertext.slice 16
- return window.crypto.subtle.decrypt {name: 'AES-CBC', iv: iv}, key, img_ciphertext
diff --git a/app/script/assets/AssetCrypto.js b/app/script/assets/AssetCrypto.js
new file mode 100644
index 00000000000..3fdc8f580c8
--- /dev/null
+++ b/app/script/assets/AssetCrypto.js
@@ -0,0 +1,81 @@
+/*
+ * Wire
+ * Copyright (C) 2016 Wire Swiss GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+
+'use strict';
+
+window.z = window.z || {};
+window.z.assets = z.assets || {};
+
+z.assets.AssetCrypto = {
+
+ /*
+ @param {ArrayBuffer} key_bytes - AES key used for encryption
+ @param {ArrayBuffer} computed_sha256 - SHA-256 checksum of the ciphertext
+ @param {ArrayBuffer} ciphertext - Encrypted plaintext
+ */
+ encrypt_aes_asset(plaintext) {
+ const iv = new Uint8Array(16);
+ let key = null;
+ let iv_ciphertext = null;
+ let computed_sha256 = null;
+
+ window.crypto.getRandomValues(iv);
+
+ return window.crypto.subtle.generateKey({name: 'AES-CBC', length: 256}, true, ['encrypt'])
+ .then(function(ckey) {
+ key = ckey;
+
+ return window.crypto.subtle.encrypt({name: 'AES-CBC', iv: iv.buffer}, key, plaintext);
+ }).then(function(ciphertext) {
+ iv_ciphertext = new Uint8Array(ciphertext.byteLength + iv.byteLength);
+ iv_ciphertext.set(iv, 0);
+ iv_ciphertext.set(new Uint8Array(ciphertext), iv.byteLength);
+
+ return window.crypto.subtle.digest('SHA-256', iv_ciphertext);
+ }).then(function(digest) {
+ computed_sha256 = digest;
+
+ return window.crypto.subtle.exportKey('raw', key);
+ }).then(key_bytes => [key_bytes, computed_sha256, iv_ciphertext.buffer]);
+ },
+
+ /*
+ @param {ArrayBuffer} key_bytes - AES key used for encryption
+ @param {ArrayBuffer} computed_sha256 - SHA-256 checksum of the ciphertext
+ @param {ArrayBuffer} ciphertext - Encrypted plaintext
+ */
+ decrypt_aes_asset(ciphertext, key_bytes, reference_sha256) {
+ return window.crypto.subtle.digest('SHA-256', ciphertext)
+ .then(function(computed_sha256) {
+ const a = new Uint32Array(reference_sha256);
+ const b = new Uint32Array(computed_sha256);
+
+ if ((a.length === b.length) && a.every((x, i) => x === b[i])) {
+ return window.crypto.subtle.importKey('raw', key_bytes, 'AES-CBC', false, ['decrypt']);
+ }
+
+ throw new Error('Encrypted asset does not match its SHA-256 hash');
+ }).then(function(key) {
+ const iv = ciphertext.slice(0, 16);
+ const img_ciphertext = ciphertext.slice(16);
+ return window.crypto.subtle.decrypt({name: 'AES-CBC', iv}, key, img_ciphertext);
+ });
+ },
+
+};
diff --git a/app/script/assets/AssetMetaDataBuilder.coffee b/app/script/assets/AssetMetaDataBuilder.coffee
deleted file mode 100644
index 09508e173e3..00000000000
--- a/app/script/assets/AssetMetaDataBuilder.coffee
+++ /dev/null
@@ -1,95 +0,0 @@
-#
-# Wire
-# Copyright (C) 2017 Wire Swiss GmbH
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see http://www.gnu.org/licenses/.
-#
-
-window.z ?= {}
-z.assets ?= {}
-
-# Builder for creating all kinds of asset metadata
-z.assets.AssetMetaDataBuilder =
-
- ###
- Constructs corresponding asset metadata depending on the given file type
-
- @param file [File] the file to generate metadata for
- @return metadata [ImageMetaData, VideoMetaData, AudioMetaData]
- ###
- build_metadata: (file) ->
- @logger = new z.util.Logger 'z.assets.AssetMetaDataBuilder', z.config.LOGGER.OPTIONS
- if @is_video file
- return @_build_video_metdadata file
- else if @is_audio file
- return @_build_audio_metdadata file
- else if @is_image file
- return @_build_image_metdadata file
- else
- return Promise.resolve()
-
- is_video: (file) ->
- file?.type?.startsWith 'video'
-
- is_audio: (file) ->
- file?.type?.startsWith 'audio'
-
- is_image: (file) ->
- file?.type?.startsWith 'image'
-
- _build_video_metdadata: (videofile) ->
- return new Promise (resolve, reject) ->
- url = window.URL.createObjectURL videofile
- videoElement = document.createElement 'video'
- videoElement.onloadedmetadata = ->
- resolve new z.proto.Asset.VideoMetaData videoElement.videoWidth, videoElement.videoHeight, videoElement.duration
- window.URL.revokeObjectURL url
- videoElement.onerror = (error) ->
- reject error
- window.URL.revokeObjectURL url
- videoElement.src = url
-
- _build_image_metdadata: (imagefile) ->
- return new Promise (resolve, reject) ->
- url = window.URL.createObjectURL imagefile
- img = new Image()
- img.onload = ->
- resolve new z.proto.Asset.ImageMetaData img.width, img.height
- window.URL.revokeObjectURL url
- img.onerror = (error) ->
- reject error
- window.URL.revokeObjectURL url
- img.src = url
-
- _build_audio_metdadata: (audiofile) ->
- z.util.load_file_buffer audiofile
- .then (buffer) ->
- audioContext = new AudioContext()
- audioContext.close()
- audioContext.decodeAudioData buffer
- .then (audio_buffer) ->
- return new z.proto.Asset.AudioMetaData audio_buffer.duration * 1000, z.assets.AssetMetaDataBuilder._normalise_loudness audio_buffer
-
- _normalise_loudness: (audio_buffer) ->
- MAX_SAMPLES = 200
- AMPLIFIER = 700 # in favour of iterating all samples before we interpolate them
- preview = [0..MAX_SAMPLES]
- for channel_index in [0..audio_buffer.numberOfChannels]
- channel = Array.from audio_buffer.getChannelData channel_index
- bucket_size = parseInt channel.length / MAX_SAMPLES
- buckets = z.util.ArrayUtil.chunk channel, bucket_size
- for bucket, bucket_index in buckets
- preview[bucket_index] = z.util.NumberUtil.cap_to_byte AMPLIFIER * z.util.NumberUtil.root_mean_square bucket
- break # only select first channel
- return new Uint8Array preview
diff --git a/app/script/assets/AssetMetaDataBuilder.js b/app/script/assets/AssetMetaDataBuilder.js
new file mode 100644
index 00000000000..4e5978791a2
--- /dev/null
+++ b/app/script/assets/AssetMetaDataBuilder.js
@@ -0,0 +1,118 @@
+/*
+ * Wire
+ * Copyright (C) 2016 Wire Swiss GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+
+'use strict';
+
+window.z = window.z || {};
+window.z.assets = z.assets || {};
+
+// Builder for creating all kinds of asset metadata
+z.assets.AssetMetaDataBuilder = {
+
+ /*
+ Constructs corresponding asset metadata depending on the given file type
+
+ @param {File|Blob} file - the file to generate metadata for
+ @returns {ImageMetaData|VideoMetaData|AudioMetaData}
+ */
+ build_metadata(file) {
+ if (!(file instanceof Blob)) {
+ throw new Error('Expected file to be type of Blob');
+ }
+
+ if (this.is_video(file)) {
+ return this._build_video_metdadata(file);
+ } else if (this.is_audio(file)) {
+ return this._build_audio_metdadata(file);
+ } else if (this.is_image(file)) {
+ return this._build_image_metdadata(file);
+ } else {
+ return Promise.resolve();
+ }
+ },
+
+ is_audio(file) {
+ return file && file.type.startsWith('audio');
+ },
+
+ is_video(file) {
+ return file && file.type.startsWith('video');
+ },
+
+ is_image(file) {
+ return file && file.type.startsWith('image');
+ },
+
+ _build_video_metdadata(videofile) {
+ return new Promise((resolve, reject) => {
+ const url = window.URL.createObjectURL(videofile);
+ const video = document.createElement('video');
+ video.onloadedmetadata = () => {
+ resolve(new z.proto.Asset.VideoMetaData(video.videoWidth, video.videoHeight, video.duration));
+ window.URL.revokeObjectURL(url);
+ };
+ video.onerror = (error) => {
+ reject(error);
+ window.URL.revokeObjectURL(url);
+ };
+ video.src = url;
+ });
+ },
+
+ _build_image_metdadata(imagefile) {
+ return new Promise((resolve, reject) =>{
+ const url = window.URL.createObjectURL(imagefile);
+ const img = new Image();
+ img.onload = () => {
+ resolve(new z.proto.Asset.ImageMetaData(img.width, img.height));
+ window.URL.revokeObjectURL(url);
+ };
+ img.onerror = (error) => {
+ reject(error);
+ window.URL.revokeObjectURL(url);
+ };
+ img.src = url;
+ });
+ },
+
+ _build_audio_metdadata(audiofile) {
+ return z.util.load_file_buffer(audiofile).then((buffer) => {
+ const audioContext = new AudioContext();
+ audioContext.close();
+ return audioContext.decodeAudioData(buffer);
+ }).then(audio_buffer => {
+ return new z.proto.Asset.AudioMetaData(audio_buffer.duration * 1000, z.assets.AssetMetaDataBuilder._normalise_loudness(audio_buffer));
+ });
+ },
+
+ _normalise_loudness(audio_buffer) {
+ const MAX_SAMPLES = 200;
+ const AMPLIFIER = 700; // in favour of iterating all samples before we interpolate them
+ const channel = audio_buffer.getChannelData(0);
+ const bucket_size = parseInt(channel.length / MAX_SAMPLES);
+ const buckets = z.util.ArrayUtil.chunk(channel, bucket_size);
+
+ const preview = buckets.map((bucket) => {
+ return z.util.NumberUtil.cap_to_byte(AMPLIFIER * z.util.NumberUtil.root_mean_square(bucket));
+ });
+
+ return new Uint8Array(preview);
+ },
+
+};
diff --git a/app/script/assets/AssetRemoteData.coffee b/app/script/assets/AssetRemoteData.coffee
deleted file mode 100644
index 6164166f975..00000000000
--- a/app/script/assets/AssetRemoteData.coffee
+++ /dev/null
@@ -1,112 +0,0 @@
-#
-# Wire
-# Copyright (C) 2016 Wire Swiss GmbH
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see http://www.gnu.org/licenses/.
-#
-
-window.z ?= {}
-z.assets ?= {}
-
-class z.assets.AssetRemoteData
-
- ###
- Use either z.assets.AssetRemoteData.v2 or z.assets.AssetRemoteData.v3
- to initialize.
-
- @param otr_key [Uint8Array]
- @param sha256 [Uint8Array]
- ###
- constructor: (@otr_key, @sha256) ->
- @download_progress = ko.observable()
- @cancel_download = undefined
- @generate_url = undefined
- @identifier = undefined
-
- ###
- Static initializer for v3 assets
-
- @param asset_key [String]
- @param otr_key [Uint8Array]
- @param sha256 [Uint8Array]
- @param asset_token [String] token is optional
- @param force_caching [Boolean]
- ###
- @v3: (asset_key, otr_key, sha256, asset_token, force_caching = false) ->
- remote_data = new z.assets.AssetRemoteData otr_key, sha256
- remote_data.generate_url = -> wire.app.service.asset.generate_asset_url_v3 asset_key, asset_token, force_caching
- remote_data.identifier = "#{asset_key}"
- return remote_data
-
- ###
- Static initializer for v2 assets
-
- @param conversation_id [String]
- @param asset_id [String]
- @param otr_key [Uint8Array]
- @param sha256 [Uint8Array]
- @param force_caching [Boolean]
- ###
- @v2: (conversation_id, asset_id, otr_key, sha256, force_caching = false) ->
- remote_data = new z.assets.AssetRemoteData otr_key, sha256
- remote_data.generate_url = -> wire.app.service.asset.generate_asset_url_v2 asset_id, conversation_id, force_caching
- remote_data.identifier = "#{conversation_id}#{asset_id}"
- return remote_data
-
- ###
- Static initializer for v1 assets
-
- @deprecated
- @param conversation_id [String]
- @param asset_id [String]
- @param force_caching [Boolean]
- ###
- @v1: (conversation_id, asset_id, force_caching = false) ->
- remote_data = new z.assets.AssetRemoteData()
- remote_data.generate_url = -> wire.app.service.asset.generate_asset_url asset_id, conversation_id, force_caching
- remote_data.identifier = "#{conversation_id}#{asset_id}"
- return remote_data
-
- ###
- Loads and decrypts stored asset
-
- @returns [Blob]
- ###
- load: =>
- type = undefined
-
- @_load_buffer()
- .then (data) =>
- [buffer, type] = data
- if @otr_key? and @sha256?
- return z.assets.AssetCrypto.decrypt_aes_asset buffer, @otr_key.buffer, @sha256.buffer
- return buffer
- .then (buffer) ->
- return new Blob [new Uint8Array buffer], type: type
-
- ###
- Get object url for asset remote data. URLs are cached in memory
-
- @returns [String] url
- ###
- get_object_url: =>
- object_url = z.assets.AssetURLCache.get_url @identifier
- return Promise.resolve object_url if object_url?
-
- @load().then (blob) => z.assets.AssetURLCache.set_url @identifier, window.URL.createObjectURL(blob)
-
- _load_buffer: =>
- z.util.load_url_buffer @generate_url(), (xhr) =>
- xhr.onprogress = (event) => @download_progress Math.round event.loaded / event.total * 100
- @cancel_download = -> xhr.abort.call xhr
diff --git a/app/script/assets/AssetRemoteData.js b/app/script/assets/AssetRemoteData.js
new file mode 100644
index 00000000000..b63e0950013
--- /dev/null
+++ b/app/script/assets/AssetRemoteData.js
@@ -0,0 +1,128 @@
+/*
+ * Wire
+ * Copyright (C) 2016 Wire Swiss GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+
+'use strict';
+
+window.z = window.z || {};
+window.z.assets = z.assets || {};
+
+z.assets.AssetRemoteData = class AssetRemoteData {
+
+ /*
+ Use either z.assets.AssetRemoteData.v2 or z.assets.AssetRemoteData.v3
+ to initialize.
+
+ @param {Uint8Array} otr_key
+ @param {Uint8Array} sha256
+ */
+ constructor(otr_key, sha256) {
+ this.otr_key = otr_key;
+ this.sha256 = sha256;
+ this.download_progress = ko.observable();
+ this.cancel_download = undefined;
+ this.generate_url = undefined;
+ this.identifier = undefined;
+ }
+
+ /*
+ Static initializer for v3 assets
+
+ @param {string} asset_key
+ @param {Uint8Array} [otr_key]
+ @param {Uint8Array} [sha256]
+ @param {string} [asset_token]
+ @param {string} [force_caching=false]
+ */
+ static v3(asset_key, otr_key, sha256, asset_token, force_caching = false) {
+ const remote_data = new z.assets.AssetRemoteData(otr_key, sha256);
+ remote_data.generate_url = () => wire.app.service.asset.generate_asset_url_v3(asset_key, asset_token, force_caching);
+ remote_data.identifier = `${asset_key}`;
+ return remote_data;
+ }
+
+ /*
+ Static initializer for v2 assets
+
+ @param {string} conversation_id
+ @param {string} asset_id
+ @param {Uint8Array} otr_key
+ @param {Uint8Array} sha256
+ @param {string} [force_caching=false]
+ */
+ static v2(conversation_id, asset_id, otr_key, sha256, force_caching = false) {
+ const remote_data = new z.assets.AssetRemoteData(otr_key, sha256);
+ remote_data.generate_url = () => wire.app.service.asset.generate_asset_url_v2(asset_id, conversation_id, force_caching);
+ remote_data.identifier = `${conversation_id}${asset_id}`;
+ return remote_data;
+ }
+
+ /*
+ Static initializer for v1 assets
+
+ @deprecated
+ @param {string} conversation_id
+ @param {string} asset_id
+ @param {string} [force_caching=false]
+ */
+ static v1(conversation_id, asset_id, force_caching = false) {
+ const remote_data = new z.assets.AssetRemoteData();
+ remote_data.generate_url = () => wire.app.service.asset.generate_asset_url(asset_id, conversation_id, force_caching);
+ remote_data.identifier = `${conversation_id}${asset_id}`;
+ return remote_data;
+ }
+
+ /*
+ Loads and decrypts stored asset
+
+ @returns {Blob}
+ */
+ load() {
+ let mime_type;
+
+ return this._load_buffer()
+ .then(([buffer, type]) => {
+ mime_type = type;
+ if ((this.otr_key != null) && (this.sha256 != null)) {
+ return z.assets.AssetCrypto.decrypt_aes_asset(buffer, this.otr_key.buffer, this.sha256.buffer);
+ }
+ return buffer;
+ }).then(plaintext => new Blob([new Uint8Array(plaintext)], {mime_type}));
+ }
+
+ /*
+ Get object url for asset remote data. URLs are cached in memory
+
+ @returns {String}
+ */
+ get_object_url() {
+ const object_url = z.assets.AssetURLCache.get_url(this.identifier);
+ if (object_url != null) {
+ return Promise.resolve(object_url);
+ }
+
+ return this.load().then(blob => z.assets.AssetURLCache.set_url(this.identifier, window.URL.createObjectURL(blob)));
+ }
+
+ _load_buffer() {
+ return z.util.load_url_buffer(this.generate_url(), xhr => {
+ xhr.onprogress = event => this.download_progress(Math.round((event.loaded / event.total) * 100));
+ return this.cancel_download = () => xhr.abort.call(xhr);
+ });
+ }
+};
diff --git a/app/script/assets/AssetRetentionPolicy.coffee b/app/script/assets/AssetRetentionPolicy.coffee
deleted file mode 100644
index dd90f4bb382..00000000000
--- a/app/script/assets/AssetRetentionPolicy.coffee
+++ /dev/null
@@ -1,25 +0,0 @@
-#
-# Wire
-# Copyright (C) 2016 Wire Swiss GmbH
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see http://www.gnu.org/licenses/.
-#
-
-window.z ?= {}
-z.assets ?= {}
-
-z.assets.AssetRetentionPolicy =
- ETERNAL: 'eternal'
- PERSISTENT: 'persistent'
- VOLATILE: 'volatile'
diff --git a/app/script/assets/AssetRetentionPolicy.js b/app/script/assets/AssetRetentionPolicy.js
new file mode 100644
index 00000000000..96b1cfe8635
--- /dev/null
+++ b/app/script/assets/AssetRetentionPolicy.js
@@ -0,0 +1,29 @@
+/*
+ * Wire
+ * Copyright (C) 2016 Wire Swiss GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+
+'use strict';
+
+window.z = window.z || {};
+window.z.assets = z.assets || {};
+
+z.assets.AssetRetentionPolicy = {
+ ETERNAL: 'eternal',
+ PERSISTENT: 'persistent',
+ VOLATILE: 'volatile',
+};
diff --git a/app/script/assets/AssetService.coffee b/app/script/assets/AssetService.coffee
deleted file mode 100644
index 7d8557f3041..00000000000
--- a/app/script/assets/AssetService.coffee
+++ /dev/null
@@ -1,405 +0,0 @@
-#
-# Wire
-# Copyright (C) 2016 Wire Swiss GmbH
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see http://www.gnu.org/licenses/.
-#
-
-window.z ?= {}
-z.assets ?= {}
-
-# AssetService for all asset handling and the calls to the backend REST API.
-class z.assets.AssetService
- ###
- Construct a new Asset Service.
-
- @param client [z.service.Client] Client for the API calls
- ###
- constructor: (@client) ->
- @logger = new z.util.Logger 'z.assets.AssetService', z.config.LOGGER.OPTIONS
- @BOUNDARY = 'frontier'
- @pending_uploads = {}
-
- ###
- Upload any asset to the backend using asset api v1.
-
- @deprecated
- @param config [Object] Configuration object containing the jQuery call settings
- @option config [Object] data
- @option config [String] contentType
- @option config [String] contentDisposition
- ###
- post_asset: (config) ->
- @client.send_request
- type: 'POST'
- url: @client.create_url '/assets'
- data: config.data
- processData: false # otherwise jquery will convert it to a query string
- contentType: config.contentType
- headers:
- 'Content-Disposition': config.contentDisposition
-
- ###
- Upload any asset pair to the backend using asset api v1.
-
- @deprecated
- @param small [z.assets.Asset] Small asset for upload
- @param medium [z.assets.Asset] Medium asset for upload
- ###
- post_asset_pair: (small, medium) ->
- Promise.all [
- @post_asset
- contentType: small.content_type
- contentDisposition: small.get_content_disposition()
- data: small.array_buffer
- @post_asset
- contentType: medium.content_type
- contentDisposition: medium.get_content_disposition()
- data: medium.array_buffer
- ]
-
- ###
- Update the user profile image by first making it usable, transforming it and then uploading the asset pair.
-
- @deprecated
- @param conversation_id [String] ID of self conversation
- @param image [File, Blob]
- ###
- upload_profile_image: (conversation_id, image) ->
- Promise.all([
- @_compress_profile_image image
- @_compress_image image
- ]).then ([small, medium]) =>
- [small_image, small_image_bytes] = small
- [medium_image, medium_image_bytes] = medium
-
- medium_asset = new z.assets.Asset
- array_buffer: medium_image_bytes
- content_type: 'image/jpg'
- conversation_id: conversation_id
- md5: z.util.array_to_md5_base64 medium_image_bytes
- width: medium_image.height
- height: medium_image.height
- public: true
-
- small_profile_asset = $.extend true, {}, medium_asset
- small_profile_asset.array_buffer = small_image_bytes
- small_profile_asset.payload.width = small_image.width
- small_profile_asset.payload.height = small_image.height
- small_profile_asset.payload.md5 = z.util.array_to_md5_base64 small_image_bytes
- small_profile_asset.payload.tag = z.assets.ImageSizeType.SMALL_PROFILE
-
- @post_asset_pair small_profile_asset, medium_asset
- .then ([small_response, medium_response]) ->
- return [small_response.data, medium_response.data]
-
- ###
- Update the user profile image by first making it usable, transforming it and then uploading the asset pair.
-
- @param conversation_id [String] ID of self conversation
- @param image [File, Blob]
- ###
- upload_profile_image_v3: (image) ->
- Promise.all([
- @_compress_profile_image image
- @_compress_image image
- ]).then ([small, medium]) =>
- [small_image, small_image_bytes] = small
- [medium_image, medium_image_bytes] = medium
-
- return Promise.all([
- @post_asset_v3 small_image_bytes, {public: true}
- @post_asset_v3 medium_image_bytes, {public: true}
- ])
- .then ([small_credentials, medium_credentials]) ->
- return [small_credentials.key, medium_credentials.key]
-
- ###
- Upload arbitrary binary data using the new asset api v3.
- The data is AES encrypted before uploading.
-
- @param bytes [Uint8Array] asset binary data
- @param options [Object]
- @option public [Boolean]
- @option retention [z.assets.AssetRetentionPolicy]
- @param xhr_accessor_function [Function] Function will get a reference to the underlying XMLHTTPRequest
- ###
- _upload_asset: (bytes, options, xhr_accessor_function) ->
- z.assets.AssetCrypto.encrypt_aes_asset bytes
- .then ([key_bytes, sha256, ciphertext]) =>
- return @post_asset_v3 ciphertext, options, xhr_accessor_function
- .then ({key, token}) ->
- return [key_bytes, sha256, key, token]
-
- ###
- Upload file using the new asset api v3. Promise will resolve with z.proto.Asset instance.
- In case of an successful upload the uploaded property is set.
-
- @param file [File, Blob]
- @param options [Object]
- @option public [Boolean]
- @option retention [z.assets.AssetRetentionPolicy]
- @param xhr_accessor_function [Function] Function will get a reference to the underlying XMLHTTPRequest
- ###
- upload_asset: (file, options, xhr_accessor_function) ->
- z.util.load_file_buffer file
- .then (buffer) =>
- @_upload_asset buffer, options, xhr_accessor_function
- .then ([key_bytes, sha256, key, token]) ->
- asset = new z.proto.Asset()
- asset.set 'uploaded', new z.proto.Asset.RemoteData key_bytes, sha256, key, token
- return asset
-
- ###
- Upload image using the new asset api v3. Promise will resolve with z.proto.Asset instance.
- In case of an successful upload the uploaded property is set.
-
- @param image [File, Blob]
- @param options [Object]
- @option public [Boolean]
- @option retention [z.assets.AssetRetentionPolicy]
- ###
- upload_image_asset: (image, options) ->
- @_compress_image image
- .then ([compressed_image, compressed_bytes]) =>
- @_upload_asset compressed_bytes, options
- .then ([key_bytes, sha256, key, token]) ->
- image_meta_data = new z.proto.Asset.ImageMetaData compressed_image.width, compressed_image.height
- asset = new z.proto.Asset()
- asset.set 'original', new z.proto.Asset.Original image.type, compressed_bytes.length, null, image_meta_data
- asset.set 'uploaded', new z.proto.Asset.RemoteData key_bytes, sha256, key, token
- return asset
-
- ###
- Generates the URL an asset can be downloaded from.
-
- @deprecated
- @param asset_id [String] ID of the asset
- @param conversation_id [String] ID of the conversation the asset belongs to
- @param force_caching [Boolean]
- @return [String] Asset URL
- ###
- generate_asset_url: (asset_id, conversation_id, force_caching) ->
- url = @client.create_url "/assets/#{asset_id}"
- asset_url = "#{url}?access_token=#{@client.access_token}&conv_id=#{conversation_id}"
- asset_url = "#{asset_url}&forceCaching=true" if force_caching
- return asset_url
-
- ###
- Generates the URL for asset api v2.
-
- @deprecated
- @param asset_id [String] ID of the asset
- @param conversation_id [String] ID of the conversation the asset belongs to
- @param force_caching [Boolean]
- @return [String] Asset URL
- ###
- generate_asset_url_v2: (asset_id, conversation_id, force_caching) ->
- url = @client.create_url "/conversations/#{conversation_id}/otr/assets/#{asset_id}"
- asset_url = "#{url}?access_token=#{@client.access_token}"
- asset_url = "#{asset_url}&forceCaching=true" if force_caching
- return asset_url
-
- ###
- Generates the URL for asset api v3.
-
- @param asset_key [String]
- @param asset_token [String]
- @param force_caching [Boolean]
- @return [String] Asset URL
- ###
- generate_asset_url_v3: (asset_key, asset_token, force_caching) ->
- url = @client.create_url "/assets/v3/#{asset_key}/"
- asset_url = "#{url}?access_token=#{@client.access_token}"
- asset_url = "#{asset_url}&asset_token=#{asset_token}" if asset_token
- asset_url = "#{asset_url}&forceCaching=true" if force_caching
- return asset_url
-
- ###
- Create request data for asset upload.
-
- @param asset_data [UInt8Array|ArrayBuffer] Asset data
- @param metadata [Object] image meta data
- ###
- _create_asset_multipart_body: (asset_data, metadata) ->
- metadata = JSON.stringify metadata
- asset_data_md5 = z.util.array_to_md5_base64 asset_data
-
- body = ''
- body += '--' + @BOUNDARY + '\r\n'
- body += 'Content-Type: application/json; charset=utf-8\r\n'
- body += "Content-length: #{metadata.length}\r\n"
- body += '\r\n'
- body += metadata + '\r\n'
- body += '--' + @BOUNDARY + '\r\n'
- body += 'Content-Type: application/octet-stream\r\n'
- body += "Content-length: #{asset_data.length}\r\n"
- body += "Content-MD5: #{asset_data_md5}\r\n"
- body += '\r\n'
-
- footer = '\r\n--' + @BOUNDARY + '--\r\n'
-
- return new Blob [body, asset_data, footer]
-
- ###
- Post assets to a conversation.
-
- @deprecated
- @param conversation_id [String] ID of the self conversation
- @param json_payload [Object] First part of the multipart message
- @param image_data [Uint8Array|ArrayBuffer] encrypted image data
- @param precondition_option [Array|Boolean] Level that backend checks for missing clients
- @param upload_id [String] Identifies the upload request
- ###
- post_asset_v2: (conversation_id, json_payload, image_data, precondition_option, upload_id) ->
- return new Promise (resolve, reject) =>
- url = @client.create_url "/conversations/#{conversation_id}/otr/assets"
-
- if _.isArray precondition_option
- url = "#{url}?report_missing=#{precondition_option.join ','}"
- else if precondition_option
- url = "#{url}?ignore_missing=true"
-
- image_data = new Uint8Array image_data
- data = @_create_asset_multipart_body image_data, json_payload
- pending_uploads = @pending_uploads
-
- xhr = new XMLHttpRequest()
- xhr.open 'POST', url
- xhr.setRequestHeader 'Content-Type', 'multipart/mixed; boundary=' + @BOUNDARY
- xhr.setRequestHeader 'Authorization', "#{@client.access_token_type} #{@client.access_token}"
- xhr.onload = (event) ->
- if @status is 201
- resolve [JSON.parse(@response), @getResponseHeader 'Location']
- else if @status is 412
- reject JSON.parse @response
- else
- reject event
- delete pending_uploads[upload_id]
- xhr.onerror = (error) ->
- reject error
- delete pending_uploads[upload_id]
- xhr.upload.onprogress = (event) ->
- if upload_id
- # we use amplify due to the fact that Promise API lacks progress support
- percentage_progress = Math.round(event.loaded / event.total * 100)
- amplify.publish 'upload' + upload_id, percentage_progress
- xhr.send data
-
- pending_uploads[upload_id] = xhr
-
- ###
- Post assets using asset api v3.
-
- @param asset_data [Uint8Array|ArrayBuffer]
- @param metadata [Object]
- @option public [Boolean] Default is false
- @option retention [z.assets.AssetRetentionPolicy] Default is z.assets.AssetRetentionPolicy.PERSISTENT
- @param xhr_accessor_function [Function] Function will get a reference to the underlying XMLHTTPRequest
- ###
- post_asset_v3: (asset_data, metadata, xhr_accessor_function) ->
- return new Promise (resolve, reject) =>
- metadata = $.extend
- public: false
- retention: z.assets.AssetRetentionPolicy.PERSISTENT
- , metadata
-
- xhr = new XMLHttpRequest()
- xhr.open 'POST', @client.create_url '/assets/v3'
- xhr.setRequestHeader 'Content-Type', 'multipart/mixed; boundary=' + @BOUNDARY
- xhr.setRequestHeader 'Authorization', "#{@client.access_token_type} #{@client.access_token}"
- xhr.onload = (event) -> if @status is 201 then resolve JSON.parse(@response) else reject event
- xhr.onerror = reject
- xhr_accessor_function? xhr
- xhr.send @_create_asset_multipart_body new Uint8Array(asset_data), metadata
-
- ###
- Cancel an asset upload.
-
- @param upload_id [String] Identifies the upload request
- ###
- cancel_asset_upload: (upload_id) =>
- xhr = @pending_uploads[upload_id]
- if xhr?
- xhr.abort()
- delete @pending_uploads[upload_id]
-
- ###
- Create image proto message.
-
- @deprecated
- @param image [File, Blob]
- ###
- create_image_proto: (image) ->
- @_compress_image image
- .then ([compressed_image, compressed_bytes]) ->
- return z.assets.AssetCrypto.encrypt_aes_asset compressed_bytes
- .then ([key_bytes, sha256, ciphertext]) ->
- image_asset = new z.proto.ImageAsset()
- image_asset.set_tag z.assets.ImageSizeType.MEDIUM
- image_asset.set_width compressed_image.width
- image_asset.set_height compressed_image.height
- image_asset.set_original_width compressed_image.width
- image_asset.set_original_height compressed_image.height
- image_asset.set_mime_type image.type
- image_asset.set_size compressed_bytes.length
- image_asset.set_otr_key key_bytes
- image_asset.set_sha256 sha256
- return [image_asset, new Uint8Array ciphertext]
-
- ###
- Create asset proto message.
-
- @deprecated
- @param asset [File, Blob]
- ###
- create_asset_proto: (asset) ->
- z.util.load_file_buffer asset
- .then (file_bytes) ->
- return z.assets.AssetCrypto.encrypt_aes_asset file_bytes
- .then ([key_bytes, sha256, ciphertext]) ->
- asset = new z.proto.Asset()
- asset.set 'uploaded', new z.proto.Asset.RemoteData key_bytes, sha256
- return [asset, ciphertext]
-
- ###
- Compress image.
- @param image [File, Blob]
- ###
- _compress_image: (image) ->
- @_compress_image_with_worker 'worker/image-worker.js', image, -> image.type is 'image/gif'
-
- ###
- Compress profile image.
- @param image [File, Blob]
- ###
- _compress_profile_image: (image) ->
- @_compress_image_with_worker 'worker/profile-image-worker.js', image
-
- ###
- Compress image using given worker.
- @param worker [String] path to worker file
- @param image [File, Blob]
- @param filter [Function] skips compression if function returns true
- ###
- _compress_image_with_worker: (worker, image, filter) ->
- z.util.load_file_buffer image
- .then (buffer) ->
- return buffer if filter?()
- image_worker = new z.util.Worker worker
- return image_worker.post buffer
- .then (compressed_bytes) ->
- return z.util.load_image new Blob [new Uint8Array compressed_bytes], 'type': image.type
- .then (compressed_image) ->
- return [compressed_image, new Uint8Array compressed_bytes]
diff --git a/app/script/assets/AssetService.js b/app/script/assets/AssetService.js
new file mode 100644
index 00000000000..81156f5a2fe
--- /dev/null
+++ b/app/script/assets/AssetService.js
@@ -0,0 +1,474 @@
+/*
+ * Wire
+ * Copyright (C) 2016 Wire Swiss GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+
+'use strict';
+
+window.z = window.z || {};
+window.z.assets = z.assets || {};
+
+// AssetService for all asset handling and the calls to the backend REST API.
+z.assets.AssetService = class AssetService {
+
+ /*
+ Construct a new Asset Service.
+
+ @param {z.service.Client} client - Client for the API calls
+ */
+ constructor(client) {
+ this.cancel_asset_upload = this.cancel_asset_upload.bind(this);
+ this.client = client;
+ this.logger = new z.util.Logger('z.assets.AssetService', z.config.LOGGER.OPTIONS);
+ this.BOUNDARY = 'frontier';
+ this.pending_uploads = {};
+ }
+
+ /*
+ Upload any asset to the backend using asset api v1.
+
+ @deprecated
+ @param {Object} config - Configuration object containing the jQuery call settings
+ @param {String} config.data
+ @param {String} config.contentDisposition
+ @param {String} config.contentType
+ */
+ post_asset(config) {
+ return this.client.send_request({
+ type: 'POST',
+ url: this.client.create_url('/assets'),
+ data: config.data,
+ processData: false, // otherwise jquery will convert it to a query string
+ contentType: config.contentType,
+ headers: {
+ 'Content-Disposition': config.contentDisposition,
+ },
+ });
+ }
+
+ /*
+ Upload any asset pair to the backend using asset api v1.
+
+ @deprecated
+ @param {z.assets.Asset} small
+ @param {z.assets.Asset} medium
+ */
+ post_asset_pair(small, medium) {
+ return Promise.all([
+ this.post_asset({
+ contentType: small.content_type,
+ contentDisposition: small.get_content_disposition(),
+ data: small.array_buffer,
+ }),
+ this.post_asset({
+ contentType: medium.content_type,
+ contentDisposition: medium.get_content_disposition(),
+ data: medium.array_buffer,
+ }),
+ ]);
+ }
+
+ /*
+ Update the user profile image by first making it usable, transforming it and then uploading the asset pair.
+
+ @deprecated
+ @param {string} conversation_id
+ @param {File|Blob} image
+ */
+ upload_profile_image(conversation_id, image) {
+ return Promise.all([
+ this._compress_profile_image(image),
+ this._compress_image(image),
+ ]).then(([small, medium]) => {
+ const [small_image, small_image_bytes] = small;
+ const [medium_image, medium_image_bytes] = medium;
+
+ const medium_asset = new z.assets.Asset({
+ array_buffer: medium_image_bytes,
+ content_type: 'image/jpg',
+ conversation_id,
+ md5: z.util.array_to_md5_base64(medium_image_bytes),
+ width: medium_image.width,
+ height: medium_image.height,
+ public: true,
+ });
+
+ const small_profile_asset = $.extend(true, {}, medium_asset);
+ small_profile_asset.__proto__ = z.assets.Asset.prototype;
+ small_profile_asset.array_buffer = small_image_bytes;
+ small_profile_asset.payload.width = small_image.width;
+ small_profile_asset.payload.height = small_image.height;
+ small_profile_asset.payload.md5 = z.util.array_to_md5_base64(small_image_bytes);
+ small_profile_asset.payload.tag = z.assets.ImageSizeType.SMALL_PROFILE;
+
+ return this.post_asset_pair(small_profile_asset, medium_asset);
+ }).then(([small_response, medium_response]) => {
+ return [small_response.data, medium_response.data];
+ });
+ }
+
+ /*
+ Update the user profile image by first making it usable, transforming it and then uploading the asset pair.
+
+ @param {File|Blob} image
+ */
+ upload_profile_image_v3(image) {
+ return Promise.all([
+ this._compress_profile_image(image),
+ this._compress_image(image),
+ ]).then(([small, medium]) => {
+ const [, small_image_bytes] = small;
+ const [, medium_image_bytes] = medium;
+
+ return Promise.all([
+ this.post_asset_v3(small_image_bytes, {public: true}),
+ this.post_asset_v3(medium_image_bytes, {public: true}),
+ ]);
+ }).then(([small_credentials, medium_credentials]) => {
+ return [small_credentials.key, medium_credentials.key];
+ });
+ }
+
+ /*
+ Upload arbitrary binary data using the new asset api v3.
+ The data is AES encrypted before uploading.
+
+ @param {Uint8Array} bytes - asset binary data
+ @param {Object} options
+ @param {Boolean} config.public
+ @param {z.assets.AssetRetentionPolicy} config.retention
+ @param {Function} xhr_accessor_function - Function will get a reference to the underlying XMLHTTPRequest
+ */
+ _upload_asset(bytes, options, xhr_accessor_function) {
+ return z.assets.AssetCrypto.encrypt_aes_asset(bytes)
+ .then(([key_bytes, sha256, ciphertext]) => {
+ return this.post_asset_v3(ciphertext, options, xhr_accessor_function)
+ .then(({key, token}) => [key_bytes, sha256, key, token]);
+ });
+ }
+
+ /*
+ Upload file using the new asset api v3. Promise will resolve with z.proto.Asset instance.
+ In case of an successful upload the uploaded property is set.
+
+ @param {Blob|File} file
+ @param {Object} options
+ @param {Boolean} config.public
+ @param {z.assets.AssetRetentionPolicy} config.retention
+ @param {Function} xhr_accessor_function - Function will get a reference to the underlying XMLHTTPRequest
+ */
+ upload_asset(file, options, xhr_accessor_function) {
+ return z.util.load_file_buffer(file)
+ .then(buffer => {
+ return this._upload_asset(buffer, options, xhr_accessor_function);
+ }).then(function([key_bytes, sha256, key, token]) {
+ const asset = new z.proto.Asset();
+ asset.set('uploaded', new z.proto.Asset.RemoteData(key_bytes, sha256, key, token));
+ return asset;
+ });
+ }
+
+ /*
+ Upload image using the new asset api v3. Promise will resolve with z.proto.Asset instance.
+ In case of an successful upload the uploaded property is set.
+
+ @param {Blob|File} file
+ @param {Object} options
+ @param {Boolean} config.public
+ @param {z.assets.AssetRetentionPolicy} config.retention
+ */
+ upload_image_asset(image, options) {
+ return this._compress_image(image)
+ .then(([compressed_image, compressed_bytes]) => {
+ return this._upload_asset(compressed_bytes, options)
+ .then(function([key_bytes, sha256, key, token]) {
+ const image_meta_data = new z.proto.Asset.ImageMetaData(compressed_image.width, compressed_image.height);
+ const asset = new z.proto.Asset();
+ asset.set('original', new z.proto.Asset.Original(image.type, compressed_bytes.length, null, image_meta_data));
+ asset.set('uploaded', new z.proto.Asset.RemoteData(key_bytes, sha256, key, token));
+ return asset;
+ });
+ }
+ );
+ }
+
+ /*
+ Generates the URL an asset can be downloaded from.
+
+ @deprecated
+ @param {string} asset_id
+ @param {string} conversation_id
+ @param {Boolean} force_caching
+ @returns {String}
+ */
+ generate_asset_url(asset_id, conversation_id, force_caching) {
+ const url = this.client.create_url(`/assets/${asset_id}`);
+ let asset_url = `${url}?access_token=${this.client.access_token}&conv_id=${conversation_id}`;
+ if (force_caching) {
+ asset_url = `${asset_url}&forceCaching=true`;
+ }
+ return asset_url;
+ }
+
+ /*
+ Generates the URL for asset api v2.
+
+ @deprecated
+ @param {string} asset_id
+ @param {string} conversation_id
+ @param {Boolean} force_caching
+ @returns {String}
+ */
+ generate_asset_url_v2(asset_id, conversation_id, force_caching) {
+ const url = this.client.create_url(`/conversations/${conversation_id}/otr/assets/${asset_id}`);
+ let asset_url = `${url}?access_token=${this.client.access_token}`;
+ if (force_caching) {
+ asset_url = `${asset_url}&forceCaching=true`;
+ }
+ return asset_url;
+ }
+
+ /*
+ Generates the URL for asset api v3.
+
+ @param {string} asset_key
+ @param {string} asset_token
+ @param {Boolean} force_caching
+ @returns {String}
+ */
+ generate_asset_url_v3(asset_key, asset_token, force_caching) {
+ const url = this.client.create_url(`/assets/v3/${asset_key}/`);
+ let asset_url = `${url}?access_token=${this.client.access_token}`;
+ if (asset_token) {
+ asset_url = `${asset_url}&asset_token=${asset_token}`;
+ }
+ if (force_caching) {
+ asset_url = `${asset_url}&forceCaching=true`;
+ }
+ return asset_url;
+ }
+
+ /*
+ Create request data for asset upload.
+
+ @param {UInt8Array|ArrayBuffer} asset_data
+ @param {Object} metadata
+ */
+ _create_asset_multipart_body(asset_data, metadata) {
+ metadata = JSON.stringify(metadata);
+ const asset_data_md5 = z.util.array_to_md5_base64(asset_data);
+
+ let body = '';
+ body += `--${this.BOUNDARY}\r\n`;
+ body += 'Content-Type: application/json; charset=utf-8\r\n';
+ body += `Content-length: ${metadata.length}\r\n`;
+ body += '\r\n';
+ body += metadata + '\r\n';
+ body += `--${this.BOUNDARY}\r\n`;
+ body += 'Content-Type: application/octet-stream\r\n';
+ body += `Content-length: ${asset_data.length}\r\n`;
+ body += `Content-MD5: ${asset_data_md5}\r\n`;
+ body += '\r\n';
+
+ const footer = `\r\n--${this.BOUNDARY}--\r\n`;
+
+ return new Blob([body, asset_data, footer]);
+ }
+
+ /*
+ Post assets to a conversation.
+
+ @deprecated
+ @param {string} conversation_id
+ @param {Object} json_payload
+ @param {Uint8Array|ArrayBuffer} image_data
+ @param {Array|Boolean} precondition_option - Level that backend checks for missing clients
+ @param {String} upload_id
+ */
+ post_asset_v2(conversation_id, json_payload, image_data, precondition_option, upload_id) {
+ return new Promise((resolve, reject) => {
+ let url = this.client.create_url(`/conversations/${conversation_id}/otr/assets`);
+
+ if (Array.isArray(precondition_option)) {
+ url = `${url}?report_missing=${precondition_option.join(',')}`;
+ } else if (precondition_option) {
+ url = `${url}?ignore_missing=true`;
+ }
+
+ image_data = new Uint8Array(image_data);
+ let data = this._create_asset_multipart_body(image_data, json_payload);
+ let { pending_uploads } = this;
+
+ let xhr = new XMLHttpRequest();
+ xhr.open('POST', url);
+ xhr.setRequestHeader('Content-Type', `multipart/mixed; boundary=${this.BOUNDARY}`);
+ xhr.setRequestHeader('Authorization', `${this.client.access_token_type} ${this.client.access_token}`);
+ xhr.onload = function(event) {
+ if (this.status === 201) {
+ resolve([JSON.parse(this.response), this.getResponseHeader('Location')]);
+ } else if (this.status === 412) {
+ reject(JSON.parse(this.response));
+ } else {
+ reject(event);
+ }
+ delete pending_uploads[upload_id];
+ };
+ xhr.onerror = function(error) {
+ reject(error);
+ delete pending_uploads[upload_id];
+ };
+ xhr.upload.onprogress = function(event) {
+ if (upload_id) {
+ // we use amplify due to the fact that Promise API lacks progress support
+ const percentage_progress = Math.round((event.loaded / event.total) * 100);
+ return amplify.publish(`upload${upload_id}`, percentage_progress);
+ }
+ };
+ xhr.send(data);
+
+ return pending_uploads[upload_id] = xhr;
+ });
+ }
+
+ /*
+ Post assets using asset api v3.
+
+ @param {Uint8Array|ArrayBuffer} asset_data
+ @param {Object} metadata
+ @param {Boolean} metadata.public
+ @param {z.assets.AssetRetentionPolicy} metadata.retention
+ @param {Function} xhr_accessor_function - Function will get a reference to the underlying XMLHTTPRequest
+ */
+ post_asset_v3(asset_data, metadata, xhr_accessor_function) {
+ return new Promise((resolve, reject) => {
+ metadata = Object.assign({
+ public: false,
+ retention: z.assets.AssetRetentionPolicy.PERSISTENT,
+ }, metadata);
+
+ const xhr = new XMLHttpRequest();
+ xhr.open('POST', this.client.create_url('/assets/v3'));
+ xhr.setRequestHeader('Content-Type', `multipart/mixed; boundary=${this.BOUNDARY}`);
+ xhr.setRequestHeader('Authorization', `${this.client.access_token_type} ${this.client.access_token}`);
+ xhr.onload = function(event) {
+ if (this.status === 201) {
+ return resolve(JSON.parse(this.response));
+ }
+ return reject(event);
+ };
+ xhr.onerror = reject;
+
+ if (typeof xhr_accessor_function === 'function') {
+ xhr_accessor_function(xhr);
+ }
+
+ xhr.send(this._create_asset_multipart_body(new Uint8Array(asset_data), metadata));
+ });
+ }
+
+ /*
+ Cancel an asset upload.
+
+ @param {string} upload_id - Identifies the upload request
+ */
+ cancel_asset_upload(upload_id) {
+ let xhr = this.pending_uploads[upload_id];
+ if (xhr != null) {
+ xhr.abort();
+ delete this.pending_uploads[upload_id];
+ }
+ }
+
+ /*
+ Create image proto message.
+
+ @deprecated
+ @param {File|Blob} image
+ */
+ create_image_proto(image) {
+ return this._compress_image(image)
+ .then(([compressed_image, compressed_bytes]) => {
+ return z.assets.AssetCrypto.encrypt_aes_asset(compressed_bytes)
+ .then(([key_bytes, sha256, ciphertext]) => {
+ let image_asset = new z.proto.ImageAsset();
+ image_asset.set_tag(z.assets.ImageSizeType.MEDIUM);
+ image_asset.set_width(compressed_image.width);
+ image_asset.set_height(compressed_image.height);
+ image_asset.set_original_width(compressed_image.width);
+ image_asset.set_original_height(compressed_image.height);
+ image_asset.set_mime_type(image.type);
+ image_asset.set_size(compressed_bytes.length);
+ image_asset.set_otr_key(key_bytes);
+ image_asset.set_sha256(sha256);
+ return [image_asset, new Uint8Array(ciphertext)];
+ });
+ });
+ }
+
+ /*
+ Create asset proto message.
+
+ @deprecated
+ @param {File|Blob} assets
+ */
+ create_asset_proto(asset) {
+ return z.util.load_file_buffer(asset)
+ .then(file_bytes => z.assets.AssetCrypto.encrypt_aes_asset(file_bytes))
+ .then(([key_bytes, sha256, ciphertext]) => {
+ asset = new z.proto.Asset();
+ asset.set('uploaded', new z.proto.Asset.RemoteData(key_bytes, sha256));
+ return [asset, ciphertext];
+ });
+ }
+
+ /*
+ Compress image.
+ @param {File|Blob} image
+ */
+ _compress_image(image) {
+ return this._compress_image_with_worker('worker/image-worker.js', image, () => image.type === 'image/gif');
+ }
+
+ /*
+ Compress profile image.
+ @param {File|Blob} image
+ */
+ _compress_profile_image(image) {
+ return this._compress_image_with_worker('worker/profile-image-worker.js', image);
+ }
+
+ /*
+ Compress image using given worker.
+ @param {string} worker - path to worker file
+ @param {File|Blob} image
+ @param {Function} filter -
+ */
+ _compress_image_with_worker(worker, image, filter) {
+ return z.util.load_file_buffer(image)
+ .then((buffer) => {
+ if (typeof filter === 'function' ? filter() : undefined) {
+ return new Uint8Array(buffer);
+ }
+ return new z.util.Worker(worker).post(buffer);
+ }).then(compressed_bytes => {
+ return Promise.all([
+ z.util.load_image(new Blob([compressed_bytes], {'type': image.type})),
+ compressed_bytes,
+ ]);
+ });
+ }
+};
diff --git a/app/script/assets/AssetTransferState.coffee b/app/script/assets/AssetTransferState.coffee
deleted file mode 100644
index ed90b5bd2fb..00000000000
--- a/app/script/assets/AssetTransferState.coffee
+++ /dev/null
@@ -1,28 +0,0 @@
-#
-# Wire
-# Copyright (C) 2016 Wire Swiss GmbH
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see http://www.gnu.org/licenses/.
-#
-
-window.z ?= {}
-z.assets ?= {}
-
-# Enum of different asset upload status.
-z.assets.AssetTransferState =
- UPLOADING: 'uploading'
- UPLOADED: 'uploaded'
- UPLOAD_FAILED: 'upload-failed'
- UPLOAD_CANCELED: 'upload-canceled'
- DOWNLOADING: 'downloading'
diff --git a/app/script/assets/AssetTransferState.js b/app/script/assets/AssetTransferState.js
new file mode 100644
index 00000000000..92695d6ed1b
--- /dev/null
+++ b/app/script/assets/AssetTransferState.js
@@ -0,0 +1,31 @@
+/*
+ * Wire
+ * Copyright (C) 2016 Wire Swiss GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+
+'use strict';
+
+window.z = window.z || {};
+window.z.assets = z.assets || {};
+
+z.assets.AssetTransferState = {
+ UPLOADING: 'uploading',
+ UPLOADED: 'uploaded',
+ UPLOAD_FAILED: 'upload-failed',
+ UPLOAD_CANCELED: 'upload-canceled',
+ DOWNLOADING: 'downloading',
+};
diff --git a/app/script/assets/AssetType.coffee b/app/script/assets/AssetType.coffee
deleted file mode 100644
index 72bb705124a..00000000000
--- a/app/script/assets/AssetType.coffee
+++ /dev/null
@@ -1,27 +0,0 @@
-#
-# Wire
-# Copyright (C) 2016 Wire Swiss GmbH
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see http://www.gnu.org/licenses/.
-#
-
-window.z ?= {}
-z.assets ?= {}
-
-# Enum of different asset types.
-z.assets.AssetType =
- FILE: 'File'
- LOCATION: 'Location'
- IMAGE: 'Image'
- TEXT: 'Text'
diff --git a/app/script/assets/AssetType.js b/app/script/assets/AssetType.js
new file mode 100644
index 00000000000..ba1fe42e214
--- /dev/null
+++ b/app/script/assets/AssetType.js
@@ -0,0 +1,30 @@
+/*
+ * Wire
+ * Copyright (C) 2016 Wire Swiss GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+
+'use strict';
+
+window.z = window.z || {};
+window.z.assets = z.assets || {};
+
+z.assets.AssetType = {
+ FILE: 'File',
+ LOCATION: 'Location',
+ IMAGE: 'Image',
+ TEXT: 'Text',
+};
diff --git a/app/script/assets/AssetURLCache.coffee b/app/script/assets/AssetURLCache.coffee
deleted file mode 100644
index 25691e99932..00000000000
--- a/app/script/assets/AssetURLCache.coffee
+++ /dev/null
@@ -1,43 +0,0 @@
-#
-# Wire
-# Copyright (C) 2016 Wire Swiss GmbH
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see http://www.gnu.org/licenses/.
-#
-
-window.z ?= {}
-z.assets ?= {}
-
-z.assets.AssetURLCache = do ->
- lru_cache = new LRUCache 100
-
- set_url = (identifier, url) ->
- existing_url = get_url identifier
- if existing_url
- window.URL.revokeObjectURL url
- return existing_url
-
- outdated_url = lru_cache.set identifier, url
- if outdated_url?
- window.URL.revokeObjectURL outdated_url
-
- return url
-
- get_url = (identifier) ->
- return lru_cache.get identifier
-
- return {
- get_url: get_url
- set_url: set_url
- }
diff --git a/app/script/assets/AssetURLCache.js b/app/script/assets/AssetURLCache.js
new file mode 100644
index 00000000000..da3347ec32b
--- /dev/null
+++ b/app/script/assets/AssetURLCache.js
@@ -0,0 +1,51 @@
+/*
+ * Wire
+ * Copyright (C) 2016 Wire Swiss GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+
+'use strict';
+
+window.z = window.z || {};
+window.z.assets = z.assets || {};
+
+z.assets.AssetURLCache = (function() {
+ const lru_cache = new LRUCache(100);
+
+ const set_url = function(identifier, url) {
+ const existing_url = get_url(identifier);
+
+ if (existing_url) {
+ window.URL.revokeObjectURL(url);
+ return existing_url;
+ }
+
+ const outdated_url = lru_cache.set(identifier, url);
+
+ if (outdated_url != null) {
+ window.URL.revokeObjectURL(outdated_url);
+ }
+
+ return url;
+ };
+
+ const get_url = identifier => lru_cache.get(identifier);
+
+ return {
+ get_url,
+ set_url,
+ };
+})();
diff --git a/app/script/assets/AssetUploadFailedReason.coffee b/app/script/assets/AssetUploadFailedReason.coffee
deleted file mode 100644
index 61e514bcf1c..00000000000
--- a/app/script/assets/AssetUploadFailedReason.coffee
+++ /dev/null
@@ -1,25 +0,0 @@
-#
-# Wire
-# Copyright (C) 2016 Wire Swiss GmbH
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see http://www.gnu.org/licenses/.
-#
-
-window.z ?= {}
-z.assets ?= {}
-
-# Enum of different asset upload status.
-z.assets.AssetUploadFailedReason =
- FAILED: 1
- CANCELLED: 0
diff --git a/app/script/assets/AssetUploadFailedReason.js b/app/script/assets/AssetUploadFailedReason.js
new file mode 100644
index 00000000000..5b369318a3b
--- /dev/null
+++ b/app/script/assets/AssetUploadFailedReason.js
@@ -0,0 +1,28 @@
+/*
+ * Wire
+ * Copyright (C) 2016 Wire Swiss GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+
+'use strict';
+
+window.z = window.z || {};
+window.z.assets = z.assets || {};
+
+z.assets.AssetUploadFailedReason = {
+ CANCELLED: 0,
+ FAILED: 1,
+};
diff --git a/app/script/assets/ImageSizeType.coffee b/app/script/assets/ImageSizeType.coffee
deleted file mode 100644
index 119f335cbc8..00000000000
--- a/app/script/assets/ImageSizeType.coffee
+++ /dev/null
@@ -1,26 +0,0 @@
-#
-# Wire
-# Copyright (C) 2016 Wire Swiss GmbH
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see http://www.gnu.org/licenses/.
-#
-
-window.z ?= {}
-z.assets ?= {}
-
-# Enum of different image size types.
-z.assets.ImageSizeType =
- MEDIUM: 'medium'
- PREVIEW: 'preview'
- SMALL_PROFILE: 'smallProfile'
diff --git a/app/script/assets/ImageSizeType.js b/app/script/assets/ImageSizeType.js
new file mode 100644
index 00000000000..cc0af923bd0
--- /dev/null
+++ b/app/script/assets/ImageSizeType.js
@@ -0,0 +1,28 @@
+//
+// Wire
+// Copyright (C) 2016 Wire Swiss GmbH
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see http://www.gnu.org/licenses/.
+//
+
+'use strict';
+
+window.z = window.z || {};
+window.z.assets = z.assets || {};
+
+z.assets.ImageSizeType = {
+ MEDIUM: 'medium',
+ PREVIEW: 'preview',
+ SMALL_PROFILE: 'smallProfile',
+};
diff --git a/app/script/audio/AudioError.coffee b/app/script/audio/AudioError.coffee
deleted file mode 100644
index ca5d4d2eac2..00000000000
--- a/app/script/audio/AudioError.coffee
+++ /dev/null
@@ -1,47 +0,0 @@
-#
-# Wire
-# Copyright (C) 2016 Wire Swiss GmbH
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see http://www.gnu.org/licenses/.
-#
-
-window.z ?= {}
-z.audio ?= {}
-
-class z.audio.AudioError
- constructor: (type) ->
- @name = @constructor.name
- @stack = (new Error()).stack
- @type = type or z.audio.AudioError::TYPE.UNKNOWN
-
- @message = switch @type
- when z.audio.AudioError::TYPE.ALREADY_PLAYING
- 'Sound is already playing'
- when z.audio.AudioError::TYPE.FAILED_TO_PLAY
- 'Failed to play sound'
- when z.audio.AudioError::TYPE.IGNORED_SOUND
- 'Ignored request to play sound'
- when z.audio.AudioError::TYPE.NOT_FOUND
- 'AudioElement or ID not found'
- else
- 'Unknown AudioError'
-
- @:: = new Error()
- @::constructor = @
- @::TYPE =
- ALREADY_PLAYING: 'z.audio.AudioError::TYPE.ALREADY_PLAYING'
- FAILED_TO_PLAY: 'z.audio.AudioError::TYPE.FAILED_TO_PLAY'
- IGNORED_SOUND: 'z.audio.AudioError::TYPE.IGNORED_SOUND'
- NOT_FOUND: 'z.audio.AudioError::TYPE.NOT_FOUND'
- UNKNOWN: 'z.audio.AudioError::TYPE.UNKNOWN'
diff --git a/app/script/audio/AudioError.js b/app/script/audio/AudioError.js
new file mode 100644
index 00000000000..05606e88ac4
--- /dev/null
+++ b/app/script/audio/AudioError.js
@@ -0,0 +1,60 @@
+/*
+ * Wire
+ * Copyright (C) 2016 Wire Swiss GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+
+'use strict';
+
+window.z = window.z || {};
+window.z.audio = z.audio || {};
+
+window.z.audio.AudioError = class AudioError extends Error {
+ constructor(type) {
+ super();
+ this.name = this.constructor.name;
+ this.stack = (new Error()).stack;
+ this.type = type || z.audio.AudioError.TYPE.UNKNOWN;
+ switch (this.type) {
+ case z.audio.AudioError.TYPE.ALREADY_PLAYING:
+ this.message = 'Sound is already playing';
+ break;
+ case z.audio.AudioError.TYPE.FAILED_TO_PLAY:
+ this.message = 'Failed to play sound';
+ break;
+ case z.audio.AudioError.TYPE.IGNORED_SOUND:
+ this.message = 'Ignored request to play sound';
+ break;
+ case z.audio.AudioError.TYPE.NOT_FOUND:
+ this.message = 'AudioElement or ID not found';
+ break;
+ default:
+ this.message = 'Unknown AudioError';
+ }
+ }
+
+ static get TYPE() {
+ return {
+ ALREADY_PLAYING: 'z.audio.AudioError.TYPE.ALREADY_PLAYING',
+ FAILED_TO_PLAY: 'z.audio.AudioError.TYPE.FAILED_TO_PLAY',
+ IGNORED_SOUND: 'z.audio.AudioError.TYPE.IGNORED_SOUND',
+ NOT_FOUND: 'z.audio.AudioError.TYPE.NOT_FOUND',
+ UNKNOWN: 'z.audio.AudioError.TYPE.UNKNOWN',
+ };
+ }
+};
+
+
diff --git a/app/script/audio/AudioPlayingType.coffee b/app/script/audio/AudioPlayingType.coffee
deleted file mode 100644
index 09699e589bf..00000000000
--- a/app/script/audio/AudioPlayingType.coffee
+++ /dev/null
@@ -1,40 +0,0 @@
-#
-# Wire
-# Copyright (C) 2016 Wire Swiss GmbH
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see http://www.gnu.org/licenses/.
-#
-
-window.z ?= {}
-z.audio ?= {}
-
-# Enum of sounds playing for different sound settings.
-z.audio.AudioPlayingType =
- NONE: [
- z.audio.AudioType.CALL_DROP
- z.audio.AudioType.NETWORK_INTERRUPTION
- z.audio.AudioType.OUTGOING_CALL
- z.audio.AudioType.READY_TO_TALK
- z.audio.AudioType.TALK_LATER
- ]
- SOME: [
- z.audio.AudioType.CALL_DROP
- z.audio.AudioType.INCOMING_CALL
- z.audio.AudioType.INCOMING_PING
- z.audio.AudioType.NETWORK_INTERRUPTION
- z.audio.AudioType.OUTGOING_CALL
- z.audio.AudioType.OUTGOING_PING
- z.audio.AudioType.READY_TO_TALK
- z.audio.AudioType.TALK_LATER
- ]
diff --git a/app/script/audio/AudioPlayingType.js b/app/script/audio/AudioPlayingType.js
new file mode 100644
index 00000000000..c6c532c703e
--- /dev/null
+++ b/app/script/audio/AudioPlayingType.js
@@ -0,0 +1,43 @@
+/*
+ * Wire
+ * Copyright (C) 2016 Wire Swiss GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+
+'use strict';
+
+window.z = window.z || {};
+window.z.audio = z.audio || {};
+
+z.audio.AudioPlayingType = {
+ NONE: [
+ z.audio.AudioType.CALL_DROP,
+ z.audio.AudioType.NETWORK_INTERRUPTION,
+ z.audio.AudioType.OUTGOING_CALL,
+ z.audio.AudioType.READY_TO_TALK,
+ z.audio.AudioType.TALK_LATER,
+ ],
+ SOME: [
+ z.audio.AudioType.CALL_DROP,
+ z.audio.AudioType.INCOMING_CALL,
+ z.audio.AudioType.INCOMING_PING,
+ z.audio.AudioType.NETWORK_INTERRUPTION,
+ z.audio.AudioType.OUTGOING_CALL,
+ z.audio.AudioType.OUTGOING_PING,
+ z.audio.AudioType.READY_TO_TALK,
+ z.audio.AudioType.TALK_LATER,
+ ],
+};
diff --git a/app/script/audio/AudioPreference.coffee b/app/script/audio/AudioPreference.coffee
deleted file mode 100644
index bbabd630189..00000000000
--- a/app/script/audio/AudioPreference.coffee
+++ /dev/null
@@ -1,26 +0,0 @@
-#
-# Wire
-# Copyright (C) 2016 Wire Swiss GmbH
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see http://www.gnu.org/licenses/.
-#
-
-window.z ?= {}
-z.audio ?= {}
-
-# Enum of audio preferences.
-z.audio.AudioPreference =
- ALL: 'all'
- NONE: 'none'
- SOME: 'some'
diff --git a/app/script/audio/AudioPreference.js b/app/script/audio/AudioPreference.js
new file mode 100644
index 00000000000..409cbe30dc3
--- /dev/null
+++ b/app/script/audio/AudioPreference.js
@@ -0,0 +1,29 @@
+/*
+ * Wire
+ * Copyright (C) 2016 Wire Swiss GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+
+'use strict';
+
+window.z = window.z || {};
+window.z.audio = z.audio || {};
+
+z.audio.AudioPreference = {
+ ALL: 'all',
+ NONE: 'none',
+ SOME: 'some',
+};
diff --git a/app/script/audio/AudioRepository.coffee b/app/script/audio/AudioRepository.coffee
deleted file mode 100644
index 71620939a89..00000000000
--- a/app/script/audio/AudioRepository.coffee
+++ /dev/null
@@ -1,195 +0,0 @@
-#
-# Wire
-# Copyright (C) 2016 Wire Swiss GmbH
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see http://www.gnu.org/licenses/.
-#
-
-window.z ?= {}
-z.audio ?= {}
-
-# Audio repository for all audio interactions.
-class z.audio.AudioRepository
- AUDIO_PATH: '/audio'
-
- # Construct a new Audio Repository.
- constructor: ->
- @logger = new z.util.Logger 'z.audio.AudioRepository', z.config.LOGGER.OPTIONS
-
- @audio_elements = {}
- @currently_looping = {}
-
- @audio_preference = ko.observable z.audio.AudioPreference.ALL
- @audio_preference.subscribe (audio_preference) =>
- @_stop_all() if audio_preference is z.audio.AudioPreference.NONE
-
- @_subscribe_to_audio_properties()
-
- ###
- Initialize the repository.
- @param pre_load [Boolean] Should sounds be pre-loaded with false as default
- ###
- init: (pre_load = false) =>
- @_init_sounds()
- @_subscribe_to_audio_events()
- @_preload() if pre_load
-
- ###
- Start playback of a sound in a loop.
- @note Prevent playing multiples instances of looping sounds
- @param audio_id [z.audio.AudioType] Sound identifier
- ###
- loop: (audio_id) =>
- @play audio_id, true
-
- ###
- Start playback of a sound.
- @param audio_id [z.audio.AudioType] Sound identifier
- @param play_in_loop [Boolean] Play sound in loop
- ###
- play: (audio_id, play_in_loop = false) =>
- @_check_sound_setting audio_id
- .then =>
- @_get_sound_by_id audio_id
- .then (audio_element) =>
- @_play audio_id, audio_element, play_in_loop
- .then (audio_element) =>
- @logger.info "Playing sound '#{audio_id}' (loop: '#{play_in_loop}')", audio_element
- .catch (error) =>
- if error not instanceof z.audio.AudioError
- @logger.error "Failed playing sound '#{audio_id}': #{error.message}"
- throw error
-
- ###
- Stop playback of a sound.
- @param audio_id [z.audio.AudioType] Sound identifier
- ###
- stop: (audio_id) =>
- @_get_sound_by_id audio_id
- .then (audio_element) =>
- if not audio_element.paused
- @logger.info "Stopping sound '#{audio_id}'", audio_element
- audio_element.pause()
- delete @currently_looping[audio_id] if @currently_looping[audio_id]
- .catch (error) =>
- @logger.error "Failed stopping sound '#{audio_id}': #{error.message}", audio_element
- throw error
-
- ###
- Check if sound should be played with current setting.
- @private
- @param audio_id [z.audio.AudioType] Sound identifier
- @param [Promise] Resolves if the sound should be played
- ###
- _check_sound_setting: (audio_id) ->
- return new Promise (resolve, reject) =>
- if @audio_preference() is z.audio.AudioPreference.NONE and audio_id not in z.audio.AudioPlayingType.NONE
- reject new z.audio.AudioError z.audio.AudioError::TYPE.IGNORED_SOUND
- else if @audio_preference() is z.audio.AudioPreference.SOME and audio_id not in z.audio.AudioPlayingType.SOME
- reject new z.audio.AudioError z.audio.AudioError::TYPE.IGNORED_SOUND
- else
- resolve()
-
- ###
- Create HTMLAudioElement.
- @param source_path [String] Source for HTMLAudioElement
- @param [HTMLAudioElement]
- ###
- _create_audio_element: (source_path) ->
- audio_element = new Audio()
- audio_element.preload = 'none'
- audio_element.src = source_path
- return audio_element
-
- ###
- Get the sound object
- @private
- @param audio_id [z.audio.AudioType] Sound identifier
- @return [Promise] Resolves with the HTMLAudioElement
- ###
- _get_sound_by_id: (audio_id) =>
- return new Promise (resolve, reject) =>
- if @audio_elements[audio_id]
- resolve @audio_elements[audio_id]
- else
- reject new z.audio.AudioError z.audio.AudioError::TYPE.NOT_FOUND
-
- ###
- Initialize all sounds.
- @private
- ###
- _init_sounds: ->
- @audio_elements[audio_id] = @_create_audio_element "#{@AUDIO_PATH}/#{audio_id}.mp3" for type, audio_id of z.audio.AudioType
- @logger.info 'Initialized sounds'
-
- ###
- Start playback of a sound.
- @private
- @param audio_id [z.audio.AudioType] Sound identifier
- @param audio_element [HTMLAudioElement] AudioElement to play
- @param play_in_loop [Boolean] Play sound in loop
- @return [Promise] Resolves with the HTMLAudioElement
- ###
- _play: (audio_id, audio_element, play_in_loop = false) ->
- if not audio_id or not audio_element
- return Promise.reject new z.audio.AudioError z.audio.AudioError::TYPE.NOT_FOUND
-
- return new Promise (resolve, reject) =>
- if audio_element.paused
- audio_element.loop = play_in_loop
- audio_element.currentTime = 0 if audio_element.currentTime isnt 0
- play_promise = audio_element.play()
-
- _play_success = =>
- @currently_looping[audio_id] = audio_id if play_in_loop
- resolve audio_element
-
- if play_promise
- play_promise.then(_play_success).catch ->
- reject new z.audio.AudioError z.audio.AudioError::TYPE.FAILED_TO_PLAY
- else
- _play_success()
- else
- reject new z.audio.AudioError z.audio.AudioError::TYPE.ALREADY_PLAYING
-
- ###
- Preload all sounds for immediate playback.
- @private
- ###
- _preload: =>
- for audio_id, audio_element of @audio_elements
- audio_element.preload = 'auto'
- audio_element.load()
- @logger.info 'Pre-loading audio files for immediate playback'
-
- ###
- Stop all sounds playing in loop.
- @private
- ###
- _stop_all: ->
- @stop audio_id for audio_id of @currently_looping
-
- # Use Amplify to subscribe to all audio playback related events.
- _subscribe_to_audio_events: ->
- amplify.subscribe z.event.WebApp.AUDIO.PLAY, @play
- amplify.subscribe z.event.WebApp.AUDIO.PLAY_IN_LOOP, @loop
- amplify.subscribe z.event.WebApp.AUDIO.STOP, @stop
-
- # Use Amplify to subscribe to all audio properties related events.
- _subscribe_to_audio_properties: ->
- amplify.subscribe z.event.WebApp.PROPERTIES.UPDATED, (properties) =>
- @audio_preference properties.settings.sound.alerts
-
- amplify.subscribe z.event.WebApp.PROPERTIES.UPDATE.SOUND_ALERTS, (audio_preference) =>
- @audio_preference audio_preference
diff --git a/app/script/audio/AudioRepository.js b/app/script/audio/AudioRepository.js
new file mode 100644
index 00000000000..3b1fa1ea3e6
--- /dev/null
+++ b/app/script/audio/AudioRepository.js
@@ -0,0 +1,248 @@
+/*
+ * Wire
+ * Copyright (C) 2016 Wire Swiss GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+
+'use strict';
+
+window.z = window.z || {};
+window.z.audio = z.audio || {};
+
+window.z.audio.AudioRepository = class AudioRepository {
+ constructor() {
+ this.logger = new z.util.Logger('z.audio.AudioRepository', z.config.LOGGER.OPTIONS);
+ this.audio_elements = {};
+ this.currently_looping = {};
+ this.audio_preference = ko.observable(z.audio.AudioPreference.ALL);
+ this.audio_preference.subscribe((audio_preference) => {
+ if (audio_preference === z.audio.AudioPreference.NONE) {
+ this._stop_all();
+ }
+ });
+ this._subscribe_to_audio_properties();
+ }
+
+ /**
+ * Check if sound should be played with current setting.
+ * @private
+ * @param {z.audio.AudioType} audio_id - Sound identifier
+ * @returns {Promise} Resolves if the sound should be played.
+ */
+ _check_sound_setting(audio_id) {
+ return new Promise((resolve, reject) => {
+ if (this.audio_preference() === z.audio.AudioPreference.NONE && !(z.audio.AudioPlayingType.NONE.includes(audio_id))) {
+ reject(new z.audio.AudioError(z.audio.AudioError.TYPE.IGNORED_SOUND));
+ } else if (this.audio_preference() === z.audio.AudioPreference.SOME && !(z.audio.AudioPlayingType.SOME.includes(audio_id))) {
+ reject(new z.audio.AudioError(z.audio.AudioError.TYPE.IGNORED_SOUND));
+ } else {
+ resolve();
+ }
+ });
+ }
+
+ /**
+ * Create HTMLAudioElement.
+ * @private
+ * @param {string} source_path - Source for HTMLAudioElement
+ * @returns {Audio} Returns the audio element.
+ */
+ _create_audio_element(source_path) {
+ const audio_element = new Audio();
+ audio_element.preload = 'none';
+ audio_element.src = source_path;
+ return audio_element;
+ }
+
+ /**
+ * Get the sound object
+ * @private
+ * @param {z.audio.AudioType} audio_id - Sound identifier
+ * @returns {Promise} Resolves with the HTMLAudioElement.
+ */
+ _get_sound_by_id(audio_id) {
+ return new Promise((resolve, reject) => {
+ if (this.audio_elements[audio_id]) {
+ resolve(this.audio_elements[audio_id]);
+ } else {
+ reject(new z.audio.AudioError(z.audio.AudioError.TYPE.NOT_FOUND));
+ }
+ });
+ }
+
+ /**
+ * Initialize all sounds.
+ * @private
+ */
+ _init_sounds() {
+ for (let type in z.audio.AudioType) {
+ const audio_id = z.audio.AudioType[type];
+ this.audio_elements[audio_id] = this._create_audio_element(`/audio/${audio_id}.mp3`);
+ }
+ this.logger.info('Initialized sounds');
+ }
+
+ /**
+ * Start playback of a sound.
+ * @private
+ * @param {z.audio.AudioType} audio_id - Sound identifier
+ * @param {HTMLAudioElement} audio_element - AudioElement to play
+ * @param {Boolean} play_in_loop - Play sound in loop
+ * @return {Promise} Resolves with the HTMLAudioElement
+ */
+ _play(audio_id, audio_element, play_in_loop = false) {
+ if (!audio_id || !audio_element) {
+ return Promise.reject(new z.audio.AudioError(z.audio.AudioError.TYPE.NOT_FOUND));
+ }
+
+ return new Promise((resolve, reject) => {
+ if (audio_element.paused) {
+ audio_element.loop = play_in_loop;
+
+ if (audio_element.currentTime !== 0) {
+ audio_element.currentTime = 0;
+ }
+
+ const _play_success = () => {
+ if (play_in_loop) {
+ this.currently_looping[audio_id] = audio_id;
+ }
+ resolve(audio_element);
+ };
+
+ const play_promise = audio_element.play();
+
+ if (play_promise) {
+ play_promise.then(_play_success).catch(() => {
+ reject(new z.audio.AudioError(z.audio.AudioError.TYPE.FAILED_TO_PLAY));
+ });
+ } else {
+ _play_success();
+ }
+ } else {
+ reject(new z.audio.AudioError(z.audio.AudioError.TYPE.ALREADY_PLAYING));
+ }
+ });
+ }
+
+ /**
+ * Preload all sounds for immediate playback.
+ * @private
+ */
+ _preload() {
+ for (let audio_id in this.audio_elements) {
+ const audio_element = this.audio_elements[audio_id];
+ audio_element.preload = 'auto';
+ audio_element.load();
+ }
+ this.logger.info('Pre-loading audio files for immediate playback');
+ }
+
+ /**
+ * Stop all sounds playing in loop.
+ * @private
+ */
+ _stop_all() {
+ for (let audio_id in this.currently_looping) {
+ this.stop(audio_id);
+ }
+ }
+
+ /**
+ * Use Amplify to subscribe to all audio playback related events.
+ * @private
+ */
+ _subscribe_to_audio_events() {
+ amplify.subscribe(z.event.WebApp.AUDIO.PLAY, this, this.play);
+ amplify.subscribe(z.event.WebApp.AUDIO.PLAY_IN_LOOP, this, this.loop);
+ amplify.subscribe(z.event.WebApp.AUDIO.STOP, this, this.stop);
+ }
+
+ /**
+ * Use Amplify to subscribe to all audio properties related events.
+ * @private
+ */
+ _subscribe_to_audio_properties() {
+ amplify.subscribe(z.event.WebApp.PROPERTIES.UPDATED, this, (properties) => {
+ this.audio_preference(properties.settings.sound.alerts);
+ });
+
+ amplify.subscribe(z.event.WebApp.PROPERTIES.UPDATE.SOUND_ALERTS, this, (audio_preference) => {
+ this.audio_preference(audio_preference);
+ });
+ }
+
+ /**
+ * Initialize the repository.
+ * @param {boolean} pre_load - Should sounds be pre-loaded with false as default
+ */
+ init(pre_load = false) {
+ this._init_sounds();
+ this._subscribe_to_audio_events();
+ if (pre_load) {
+ this._preload();
+ }
+ }
+
+ /**
+ * Start playback of a sound in a loop.
+ * @note Prevent playing multiples instances of looping sounds
+ * @param {z.audio.AudioType} audio_id - Sound identifier
+ */
+ loop(audio_id) {
+ this.play(audio_id, true);
+ }
+
+ /**
+ * Start playback of a sound.
+ * @param {z.audio.AudioType} audio_id - Sound identifier
+ * @param {boolean} play_in_loop - Play sound in loop
+ */
+ play(audio_id, play_in_loop = false) {
+ return this._check_sound_setting(audio_id).then(() => {
+ return this._get_sound_by_id(audio_id);
+ }).then((audio_element) => {
+ return this._play(audio_id, audio_element, play_in_loop);
+ }).then((audio_element) => {
+ return this.logger.info(`Playing sound '${audio_id}' (loop: '${play_in_loop}')`, audio_element);
+ }).catch((error) => {
+ if (!(error instanceof z.audio.AudioError)) {
+ this.logger.error(`Failed playing sound '${audio_id}': ${error.message}`);
+ throw error;
+ }
+ });
+ }
+
+ /**
+ * Stop playback of a sound.
+ * @param {z.audio.AudioType} audio_id - Sound identifier
+ */
+ stop(audio_id) {
+ return this._get_sound_by_id(audio_id).then((audio_element) => {
+ if (!audio_element.paused) {
+ this.logger.info(`Stopping sound '${audio_id}'`, audio_element);
+ audio_element.pause();
+ }
+
+ if (this.currently_looping[audio_id]) {
+ delete this.currently_looping[audio_id];
+ }
+ }).catch((error) => {
+ this.logger.error(`Failed stopping sound '${audio_id}': ${error.message}`);
+ throw error;
+ });
+ }
+};
diff --git a/app/script/audio/AudioType.coffee b/app/script/audio/AudioType.coffee
deleted file mode 100644
index e78b9cbd740..00000000000
--- a/app/script/audio/AudioType.coffee
+++ /dev/null
@@ -1,33 +0,0 @@
-#
-# Wire
-# Copyright (C) 2016 Wire Swiss GmbH
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see http://www.gnu.org/licenses/.
-#
-
-window.z ?= {}
-z.audio ?= {}
-
-# Enum of different supported sounds.
-z.audio.AudioType =
- ALERT: 'alert'
- CALL_DROP: 'call_drop'
- INCOMING_CALL: 'ringing_from_them'
- INCOMING_PING: 'ping_from_them'
- NETWORK_INTERRUPTION: 'nw_interruption'
- NEW_MESSAGE: 'new_message'
- OUTGOING_CALL: 'ringing_from_me'
- OUTGOING_PING: 'ping_from_me'
- READY_TO_TALK: 'ready_to_talk'
- TALK_LATER: 'talk_later'
diff --git a/app/script/audio/AudioType.js b/app/script/audio/AudioType.js
new file mode 100644
index 00000000000..815c8193e13
--- /dev/null
+++ b/app/script/audio/AudioType.js
@@ -0,0 +1,36 @@
+/*
+ * Wire
+ * Copyright (C) 2016 Wire Swiss GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/.
+ *
+ */
+
+'use strict';
+
+window.z = window.z || {};
+window.z.announce = z.announce || {};
+
+z.audio.AudioType = {
+ ALERT: 'alert',
+ CALL_DROP: 'call_drop',
+ INCOMING_CALL: 'ringing_from_them',
+ INCOMING_PING: 'ping_from_them',
+ NETWORK_INTERRUPTION: 'nw_interruption',
+ NEW_MESSAGE: 'new_message',
+ OUTGOING_CALL: 'ringing_from_me',
+ OUTGOING_PING: 'ping_from_me',
+ READY_TO_TALK: 'ready_to_talk',
+ TALK_LATER: 'talk_later',
+};
diff --git a/app/script/calling/entities/Call.coffee b/app/script/calling/entities/Call.coffee
index c3b77725c99..166db71e1c4 100644
--- a/app/script/calling/entities/Call.coffee
+++ b/app/script/calling/entities/Call.coffee
@@ -76,9 +76,7 @@ class z.calling.entities.Call
@interrupted_participants = ko.observableArray []
# Media
- @local_stream_audio = @v2_call_center.media_stream_handler.local_media_streams.audio
- @local_stream_video = @v2_call_center.media_stream_handler.local_media_streams.video
-
+ @local_media_stream = @v2_call_center.media_stream_handler.local_media_stream
@local_media_type = @v2_call_center.media_stream_handler.local_media_type
@remote_media_type = ko.observable z.media.MediaType.NONE
diff --git a/app/script/calling/entities/ECall.coffee b/app/script/calling/entities/ECall.coffee
index 2f61bf94e21..2f74d99f398 100644
--- a/app/script/calling/entities/ECall.coffee
+++ b/app/script/calling/entities/ECall.coffee
@@ -66,9 +66,7 @@ class z.calling.entities.ECall
@interrupted_participants = ko.observableArray []
# Media
- @local_stream_audio = @v3_call_center.media_stream_handler.local_media_streams.audio
- @local_stream_video = @v3_call_center.media_stream_handler.local_media_streams.video
-
+ @local_media_stream = @v3_call_center.media_stream_handler.local_media_stream
@local_media_type = @v3_call_center.media_stream_handler.local_media_type
@remote_media_type = ko.observable z.media.MediaType.NONE
diff --git a/app/script/calling/entities/EFlow.coffee b/app/script/calling/entities/EFlow.coffee
index f28bff5de18..d6b4f9d85d5 100644
--- a/app/script/calling/entities/EFlow.coffee
+++ b/app/script/calling/entities/EFlow.coffee
@@ -22,6 +22,7 @@ z.calling.entities ?= {}
E_FLOW_CONFIG =
RTC_DATA_CHANNEL_LABEL: 'calling-3.0'
+ SDP_SEND_TIMEOUT_RENEGOTIATION: 50
SDP_SEND_TIMEOUT_RESET: 1000
SDP_SEND_TIMEOUT: 5000
@@ -67,8 +68,7 @@ class z.calling.entities.EFlow
@pc_initialized.subscribe (is_initialized) =>
@telemetry.set_peer_connection @peer_connection if is_initialized
- @audio_stream = @e_call_et.local_stream_audio
- @video_stream = @e_call_et.local_stream_video
+ @media_stream = @e_call_et.local_media_stream
@data_channels = {}
@connection_state = ko.observable z.calling.rtc.ICEConnectionState.NEW
@@ -114,7 +114,7 @@ class z.calling.entities.EFlow
when z.calling.rtc.SignalingState.CLOSED
@logger.debug "PeerConnection with '#{@remote_user.name()}' was closed"
@e_call_et.delete_e_participant @e_participant_et
- @_remove_media_streams()
+ @_remove_media_stream @media_stream()
when z.calling.rtc.SignalingState.REMOTE_OFFER
@negotiation_needed true
@@ -226,22 +226,24 @@ class z.calling.entities.EFlow
return @save_remote_sdp e_call_message_et
@is_answer false
- start_negotiation: =>
- @audio.hookup true
- @_create_peer_connection()
- @_add_media_streams()
- @_set_sdp_states()
- @negotiation_needed true
- @pc_initialized true
-
- restart_negotiation: (negotiation_mode, is_answer) =>
+ restart_negotiation: (negotiation_mode, is_answer, media_stream) =>
@logger.debug "Negotiation restart triggered by '#{negotiation_mode}'"
- @negotiation_mode negotiation_mode
+ @_close_peer_connection()
+ @_clear_send_sdp_timeout()
+ @_reset_signaling_states()
@is_answer is_answer
@local_sdp undefined
@remote_sdp undefined
+ @start_negotiation negotiation_mode, media_stream
+
+ start_negotiation: (negotiation_mode = z.calling.enum.SDP_NEGOTIATION_MODE.DEFAULT, media_stream = @media_stream()) =>
+ @audio.hookup true
+ @_create_peer_connection()
+ @_add_media_stream media_stream
@_set_sdp_states()
+ @negotiation_mode negotiation_mode
@negotiation_needed true
+ @pc_initialized true
_set_sdp_states: ->
@should_set_remote_sdp true
@@ -285,7 +287,7 @@ class z.calling.entities.EFlow
@peer_connection = new window.RTCPeerConnection @_create_peer_connection_configuration()
@telemetry.time_step z.telemetry.calling.CallSetupSteps.PEER_CONNECTION_CREATED
@signaling_state @peer_connection.signalingState
- @logger.debug "PeerConnection with '#{@remote_user.name()}' created - is_answer' #{@is_answer()}", @e_call_et.config().ice_servers
+ @logger.debug "PeerConnection with '#{@remote_user.name()}' created - is_answer '#{@is_answer()}'", @e_call_et.config().ice_servers
@peer_connection.onaddstream = @_on_add_stream
@peer_connection.ontrack = @_on_track
@@ -416,8 +418,9 @@ class z.calling.entities.EFlow
.then ([remote_sdp, ice_candidates]) =>
if remote_sdp.type is z.calling.rtc.SDPType.OFFER
if @signaling_state() is z.calling.rtc.SignalingState.LOCAL_OFFER
- return @_solve_colliding_states()
- else if e_call_message_et.type is z.calling.enum.E_CALL_MESSAGE_TYPE.UPDATE
+ return if @_solve_colliding_states()
+
+ if e_call_message_et.type is z.calling.enum.E_CALL_MESSAGE_TYPE.UPDATE
@restart_negotiation z.calling.enum.SDP_NEGOTIATION_MODE.STREAM_CHANGE, true
@remote_sdp remote_sdp
@@ -433,9 +436,10 @@ class z.calling.entities.EFlow
.then ([local_sdp, ice_candidates]) =>
@local_sdp local_sdp
- if sending_on_timeout and not @_contains_relay_candidate ice_candidates
- @logger.warn "Local SDP does not contain any relay ICE candidates, resetting timeout\n#{ice_candidates}", ice_candidates
- return @_set_send_sdp_timeout false
+ if sending_on_timeout and @negotiation_mode() is z.calling.enum.SDP_NEGOTIATION_MODE.DEFAULT
+ unless @_contains_relay_candidate ice_candidates
+ @logger.warn "Local SDP does not contain any relay ICE candidates, resetting timeout\n#{ice_candidates}", ice_candidates
+ return @_set_send_sdp_timeout false
@logger.info "Sending local '#{@local_sdp().type}' SDP containing '#{ice_candidates.length}' ICE candidates for flow with '#{@remote_user.name()}'\n#{@local_sdp().sdp}"
@should_send_local_sdp false
@@ -520,7 +524,6 @@ class z.calling.entities.EFlow
@call_et.telemetry.track_event z.tracking.EventName.CALLING.FAILED_RTC, undefined, attributes
amplify.publish z.event.WebApp.CALL.STATE.LEAVE, @e_call_et.id, z.calling.enum.TERMINATION_REASON.SDP_FAILED
-
###
Sets the local Session Description Protocol on the PeerConnection.
@private
@@ -532,9 +535,10 @@ class z.calling.entities.EFlow
@logger.debug "Setting local '#{@local_sdp().type}' SDP successful", @peer_connection.localDescription
@telemetry.time_step z.telemetry.calling.CallSetupSteps.LOCAL_SDP_SET
@should_set_local_sdp false
- if @negotiation_mode() is z.calling.enum.SDP_NEGOTIATION_MODE.STREAM_CHANGE
- return @send_local_sdp()
- @_set_send_sdp_timeout()
+ switch @negotiation_mode()
+ when z.calling.enum.SDP_NEGOTIATION_MODE.STREAM_CHANGE then @send_local_sdp()
+ when z.calling.enum.SDP_NEGOTIATION_MODE.ICE_RESTART then @_set_gathering_state_timeout()
+ else @_set_send_sdp_timeout()
.catch (error) =>
@logger.error "Setting local '#{@local_sdp().type}' SDP failed: #{error.name} - #{error.message}", error
attributes = {cause: error.name, step: 'set_sdp', location: 'local', type: @local_sdp()?.type}
@@ -558,6 +562,18 @@ class z.calling.entities.EFlow
@call_et.telemetry.track_event z.tracking.EventName.CALLING.FAILED_RTC, undefined, attributes
amplify.publish z.event.WebApp.CALL.STATE.LEAVE, @e_call_et.id, z.calling.enum.TERMINATION_REASON.SDP_FAILED
+ ###
+ Set timeout to check for ICE gathering state on renegotiation.
+ @note If renegotiation was triggered by remote end, we do not gather new candidates and can send SDP almost immediately.
+ ###
+ _set_gathering_state_timeout: ->
+ @send_sdp_timeout = window.setTimeout =>
+ if @gathering_state() is z.calling.rtc.ICEGatheringState.COMPLETE
+ @logger.debug 'Sending local SDP as ICE gathering state did not change'
+ return @send_local_sdp true
+ @_set_send_sdp_timeout()
+ , E_FLOW_CONFIG.SDP_SEND_TIMEOUT_RENEGOTIATION
+
###
Set the SDP send timeout.
@private
@@ -583,13 +599,10 @@ class z.calling.entities.EFlow
_solve_colliding_states: ->
if @self_user_id < @remote_user_id
@logger.warn "We need to switch SDP state of flow with '#{@remote_user.name()}' to answer."
- @_close_peer_connection()
- @_clear_send_sdp_timeout()
- @_reset_signaling_states()
- @is_answer true
- @local_sdp undefined
- return @start_negotiation()
+ @restart_negotiation z.calling.enum.SDP_NEGOTIATION_MODE.ICE_RESTART, true
+ return false
@logger.warn "Remote side needs to switch SDP state of flow with '#{@remote_user.name()}' to answer."
+ return true
###############################################################################
@@ -632,23 +645,6 @@ class z.calling.entities.EFlow
@logger.info "Added local '#{media_stream.type}' MediaStream to PeerConnection",
{stream: media_stream, audio_tracks: media_stream.getAudioTracks(), video_tracks: media_stream.getVideoTracks()}
- ###
- Adds the local MediaStreams to the PeerConnection.
- @private
- ###
- _add_media_streams: ->
- media_streams_identical = @_compare_local_media_streams()
-
- @_add_media_stream @audio_stream() if @audio_stream()
- @_add_media_stream @video_stream() if @video_stream() and not media_streams_identical
-
- ###
- Compare whether local audio and video streams are identical.
- @private
- ###
- _compare_local_media_streams: ->
- return @audio_stream() and @video_stream() and @audio_stream().id is @video_stream().id
-
###
Replace the MediaStream attached to the PeerConnection.
@private
@@ -657,27 +653,17 @@ class z.calling.entities.EFlow
_replace_media_stream: (media_stream_info) ->
Promise.resolve()
.then =>
- return @_remove_media_streams media_stream_info.type
+ return @_remove_media_stream @media_stream()
.then =>
@_upgrade_media_stream media_stream_info.stream, media_stream_info.type
- .then (media_stream) =>
- @_add_media_stream media_stream
- @logger.info "Replaced the MediaStream to update '#{media_stream_info.type}' successfully", media_stream
- @restart_negotiation z.calling.enum.SDP_NEGOTIATION_MODE.STREAM_CHANGE, false
- return media_stream_info
+ .then (updated_media_stream) =>
+ @logger.info "Upgraded the MediaStream to update '#{media_stream_info.type}' successfully", updated_media_stream
+ @restart_negotiation z.calling.enum.SDP_NEGOTIATION_MODE.STREAM_CHANGE, false, updated_media_stream
+ return updated_media_stream
.catch (error) =>
@logger.error "Failed to replace local MediaStream: #{error.message}", error
throw error
- _upgrade_media_stream: (new_media_stream, media_type) ->
- active_media_stream = if media_type is z.media.MediaType.AUDIO then @audio_stream() else @video_stream()
-
- if active_media_stream
- active_media_stream.removeTrack media_stream_track for media_stream_track in z.media.MediaStreamHandler.get_media_tracks active_media_stream, media_type
- active_media_stream.addTrack media_stream_track for media_stream_track in z.media.MediaStreamHandler.get_media_tracks new_media_stream, media_type
- return active_media_stream
- return new_media_stream
-
###
Replace the a MediaStreamTrack attached to the MediaStream of the PeerConnection.
@private
@@ -723,21 +709,25 @@ class z.calling.entities.EFlow
{stream: media_stream, audio_tracks: media_stream.getAudioTracks(), video_tracks: media_stream.getVideoTracks()}
###
- Reset the flows MediaStream and media elements.
+ Upgrade the local MediaStream with new MediaStreamTracks
+
@private
- @param media_type [z.media.MediaType] Optional media type of MediaStreams to be removed
+ @param new_media_stream [MediaStream] MediaStream containing new MediaStreamTracks
+ @param media_type [z.media.MediaType] Type of tracks to update
+ @return [MediaStream] New MediaStream to be used
###
- _remove_media_streams: (media_type = z.media.MediaType.AUDIO_VIDEO) ->
- switch media_type
- when z.media.MediaType.AUDIO_VIDEO
- media_streams_identical = @_compare_local_media_streams()
+ _upgrade_media_stream: (new_media_stream, media_type) ->
+ if @media_stream()
+ for media_stream_track in z.media.MediaStreamHandler.get_media_tracks @media_stream(), media_type
+ @media_stream().removeTrack media_stream_track
+ media_stream_track.stop()
+ @logger.info "Stopping MediaStreamTrack of kind '#{media_stream_track.kind}' successful", media_stream_track
- @_remove_media_stream @audio_stream() if @audio_stream()
- @_remove_media_stream @video_stream() if @video_stream() and not media_streams_identical
- when z.media.MediaType.AUDIO
- @_remove_media_stream @audio_stream() if @audio_stream()
- when z.media.MediaType.VIDEO
- @_remove_media_stream @video_stream() if @video_stream()
+ media_stream = @media_stream().clone()
+
+ media_stream.addTrack media_stream_track for media_stream_track in z.media.MediaStreamHandler.get_media_tracks new_media_stream, media_type
+ return z.media.MediaStreamHandler.detect_media_stream_type media_stream
+ return new_media_stream
###############################################################################
@@ -752,7 +742,7 @@ class z.calling.entities.EFlow
@_clear_send_sdp_timeout()
@telemetry.reset_statistics()
@logger.info "Resetting flow with user '#{@remote_user.id}'"
- @_remove_media_streams()
+ @_remove_media_stream @media_stream() if @media_stream()
@_close_peer_connection() if @peer_connection?.signalingState isnt z.calling.rtc.SignalingState.CLOSED
@_reset_signaling_states()
@pc_initialized false
diff --git a/app/script/calling/entities/Flow.coffee b/app/script/calling/entities/Flow.coffee
index cdc4758f4bf..a1f07cfa5be 100644
--- a/app/script/calling/entities/Flow.coffee
+++ b/app/script/calling/entities/Flow.coffee
@@ -83,10 +83,7 @@ class z.calling.entities.Flow
@telemetry.set_peer_connection @peer_connection
@telemetry.schedule_check 5000 if is_initialized
- @audio_stream = @call_et.local_stream_audio
- @video_stream = @call_et.local_stream_video
-
- @has_media_stream = ko.pureComputed => return @video_stream()? or @audio_stream()?
+ @media_stream = @call_et.local_media_stream
@connection_state = ko.observable z.calling.rtc.ICEConnectionState.NEW
@gathering_state = ko.observable z.calling.rtc.ICEGatheringState.NEW
@@ -113,7 +110,7 @@ class z.calling.entities.Flow
@participant_et.is_connected false
@call_et.delete_participant @participant_et
return if @call_et.participants().length
- termination_reason = if @e_call_et.is_connected() then z.calling.enum.TERMINATION_REASON.CONNECTION_DROP else z.calling.enum.TERMINATION_REASON.CONNECTION_FAILED
+ termination_reason = if @call_et.is_connected() then z.calling.enum.TERMINATION_REASON.CONNECTION_DROP else z.calling.enum.TERMINATION_REASON.CONNECTION_FAILED
amplify.publish z.event.WebApp.CALL.STATE.LEAVE, @call_et.id, termination_reason
when z.calling.rtc.ICEConnectionState.CLOSED
@@ -126,7 +123,7 @@ class z.calling.entities.Flow
return if @converted_own_sdp_state()
@logger.debug "PeerConnection with '#{@remote_user.name()}' was closed"
@call_et.delete_participant @participant_et
- @_remove_media_streams()
+ @_remove_media_stream @media_stream()
when z.calling.rtc.SignalingState.REMOTE_OFFER
@negotiation_needed true
@@ -245,7 +242,7 @@ class z.calling.entities.Flow
@_create_offer()
@can_initialize_peer_connection = ko.pureComputed =>
- can_initialize = @has_media_stream() and @payload() and not @pc_initialized()
+ can_initialize = @media_stream() and @payload() and not @pc_initialized()
return can_initialize
@can_initialize_peer_connection.subscribe (can_initialize) =>
@@ -298,6 +295,7 @@ class z.calling.entities.Flow
_rewrite_payload: (payload) ->
for ice_server in payload.ice_servers when not ice_server.urls
ice_server.urls = [ice_server.url]
+ delete ice_server.url
return payload
@@ -352,8 +350,9 @@ class z.calling.entities.Flow
# Initialize the PeerConnection.
_initialize_peer_connection: ->
@_create_peer_connection()
- @_add_media_streams()
+ @_add_media_stream @media_stream()
@pc_initialized true
+ @negotiation_needed true
###
A MediaStream was added to the PeerConnection.
@@ -708,25 +707,6 @@ class z.calling.entities.Flow
@logger.info "Added local '#{media_stream.type}' MediaStream to PeerConnection",
{stream: media_stream, audio_tracks: media_stream.getAudioTracks(), video_tracks: media_stream.getVideoTracks()}
- ###
- Adds the local MediaStreams to the PeerConnection.
- @private
- ###
- _add_media_streams: ->
- media_streams_identical = @_compare_local_media_streams()
-
- @_add_media_stream @audio_stream() if @audio_stream()
- @_add_media_stream @video_stream() if @video_stream() and not media_streams_identical
-
- @negotiation_needed true
-
- ###
- Compare whether local audio and video streams are identical.
- @private
- ###
- _compare_local_media_streams: ->
- return @audio_stream() and @video_stream() and @audio_stream().id is @video_stream().id
-
###
Replace the MediaStream attached to the PeerConnection.
@private
@@ -735,14 +715,16 @@ class z.calling.entities.Flow
_replace_media_stream: (media_stream_info) ->
Promise.resolve()
.then =>
- return @_remove_media_streams media_stream_info.type
+ return @_remove_media_stream @media_stream()
.then =>
+ @_upgrade_media_stream media_stream_info.stream, media_stream_info.type
+ .then (updated_media_stream) =>
@negotiation_mode z.calling.enum.SDP_NEGOTIATION_MODE.STREAM_CHANGE
- @_add_media_stream media_stream_info.stream
+ @_add_media_stream updated_media_stream
@is_answer false
@negotiation_needed true
@logger.info 'Replaced the MediaStream successfully', media_stream_info.stream
- return media_stream_info
+ return updated_media_stream
.catch (error) =>
@logger.error "Failed to replace local MediaStream: #{error.message}", error
throw error
@@ -792,21 +774,25 @@ class z.calling.entities.Flow
{stream: media_stream, audio_tracks: media_stream.getAudioTracks(), video_tracks: media_stream.getVideoTracks()}
###
- Reset the flows MediaStream and media elements.
+ Upgrade the local MediaStream with new MediaStreamTracks
+
@private
- @param media_type [z.media.MediaType] Optional media type of MediaStreams to be removed
+ @param new_media_stream [MediaStream] MediaStream containing new MediaStreamTracks
+ @param media_type [z.media.MediaType] Type of tracks to update
+ @return [MediaStream] New MediaStream to be used
###
- _remove_media_streams: (media_type = z.media.MediaType.AUDIO_VIDEO) ->
- switch media_type
- when z.media.MediaType.AUDIO_VIDEO
- media_streams_identical = @_compare_local_media_streams()
+ _upgrade_media_stream: (new_media_stream, media_type) ->
+ if @media_stream()
+ for media_stream_track in z.media.MediaStreamHandler.get_media_tracks @media_stream(), media_type
+ @media_stream().removeTrack media_stream_track
+ media_stream_track.stop()
+ @logger.info "Stopping MediaStreamTrack of kind '#{media_stream_track.kind}' successful", media_stream_track
+
+ media_stream = @media_stream().clone()
- @_remove_media_stream @audio_stream() if @audio_stream()
- @_remove_media_stream @video_stream() if @video_stream() and not media_streams_identical
- when z.media.MediaType.AUDIO
- @_remove_media_stream @audio_stream() if @audio_stream()
- when z.media.MediaType.VIDEO
- @_remove_media_stream @video_stream() if @video_stream()
+ media_stream.addTrack media_stream_track for media_stream_track in z.media.MediaStreamHandler.get_media_tracks new_media_stream, media_type
+ return z.media.MediaStreamHandler.detect_media_stream_type media_stream
+ return new_media_stream
###############################################################################
@@ -831,7 +817,7 @@ class z.calling.entities.Flow
@_close_peer_connection()
catch error
@logger.error "We caught the #{error.name}: #{error.message}", error
- @_remove_media_streams()
+ @_remove_media_stream @media_stream()
@_reset_signaling_states()
@ice_candidates_cache = []
@payload undefined
diff --git a/app/script/calling/handler/CallStateHandler.coffee b/app/script/calling/handler/CallStateHandler.coffee
index 297ebd12b8f..eaa82a8e413 100644
--- a/app/script/calling/handler/CallStateHandler.coffee
+++ b/app/script/calling/handler/CallStateHandler.coffee
@@ -226,7 +226,7 @@ class z.calling.handler.CallStateHandler
@logger.error "PUTting the state to '#{payload.state}' in '#{conversation_id}' failed: #{error.message}", error
attributes = {cause: error.label or error.name, method: 'put', request: 'state', video: payload.videod}
@v2_call_center.telemetry.track_event z.tracking.EventName.CALLING.FAILED_REQUEST, undefined, attributes
- @v2_call_center.media_stream_handler.release_media_streams()
+ @v2_call_center.media_stream_handler.release_media_stream()
switch error.label
when z.service.BackendClientError::LABEL.CONVERSATION_TOO_BIG
amplify.publish z.event.WebApp.WARNING.MODAL, z.ViewModel.ModalType.CALL_FULL_CONVERSATION,
@@ -318,7 +318,7 @@ class z.calling.handler.CallStateHandler
call_et.state z.calling.enum.CallState.ENDED
call_et.reset_call()
@_remove_call call_et.id
- @v2_call_center.media_stream_handler.reset_media_streams()
+ @v2_call_center.media_stream_handler.reset_media_stream()
.catch (error) =>
@logger.warn "No call found in conversation '#{conversation_id}' to delete", error
@@ -331,7 +331,7 @@ class z.calling.handler.CallStateHandler
.then (call_et) =>
call_et.ignore()
@logger.info "Call in '#{conversation_id}' ignored"
- @v2_call_center.media_stream_handler.reset_media_streams()
+ @v2_call_center.media_stream_handler.reset_media_stream()
.catch (error) =>
@logger.warn "No call found in conversation '#{conversation_id}' to ignore", error
@@ -353,8 +353,8 @@ class z.calling.handler.CallStateHandler
with_bot: conversation_et.is_with_bot()
.then =>
@v2_call_center.timings = new z.telemetry.calling.CallSetupTimings conversation_id
- if @v2_call_center.media_stream_handler.has_media_streams()
- @logger.info 'MediaStream has already been initialized', @v2_call_center.media_stream_handler.local_media_streams
+ if @v2_call_center.media_stream_handler.local_media_stream()
+ @logger.info 'MediaStream has already been initialized', @v2_call_center.media_stream_handler.local_media_stream
else
return @v2_call_center.media_stream_handler.initiate_media_stream conversation_id, is_videod
.then =>
@@ -369,7 +369,7 @@ class z.calling.handler.CallStateHandler
@param termination_reason [z.calling.enum.TERMINATION_REASON] Optional on reason for call termination
###
leave_call: (conversation_id, termination_reason) =>
- @v2_call_center.media_stream_handler.release_media_streams()
+ @v2_call_center.media_stream_handler.release_media_stream()
@v2_call_center.get_call_by_id conversation_id
.then (call_et) =>
call_et.state z.calling.enum.CallState.DISCONNECTING
@@ -479,7 +479,7 @@ class z.calling.handler.CallStateHandler
call_et.state z.calling.enum.CallState.ONGOING if call_et.participants_count() >= 2
if call_et.is_remote_video_send() and call_et.is_ongoing_on_another_client()
- @v2_call_center.media_stream_handler.release_media_streams()
+ @v2_call_center.media_stream_handler.release_media_stream()
###############################################################################
diff --git a/app/script/calling/mapper/SDPMapper.coffee b/app/script/calling/mapper/SDPMapper.coffee
index acd03be2d49..d3e7e186984 100644
--- a/app/script/calling/mapper/SDPMapper.coffee
+++ b/app/script/calling/mapper/SDPMapper.coffee
@@ -39,20 +39,7 @@ z.calling.mapper.SDPMapper =
type: if e_call_message_et.response is true then z.calling.rtc.SDPType.ANSWER else z.calling.rtc.SDPType.OFFER
map_event_to_object: (event) ->
- _convert_fingerprint_to_uppercase = (sdp_string) ->
- sdp_lines = sdp_string.split '\r\n'
-
- for sdp_line, index in sdp_lines when sdp_line.startsWith 'a=fingerprint'
- sdp_line_parts = sdp_line.split ' '
- sdp_lines[index] = "#{sdp_line_parts[0]} #{sdp_line_parts[1].toUpperCase()}"
-
- return sdp_lines.join '\r\n'
-
- remote_sdp =
- sdp: _convert_fingerprint_to_uppercase event.sdp
- type: event.state
-
- return new window.RTCSessionDescription remote_sdp
+ return new window.RTCSessionDescription sdp: event.sdp, type: event.state
###
Rewrite the SDP for compatibility reasons.
@@ -84,13 +71,9 @@ z.calling.mapper.SDPMapper =
else if sdp_line.startsWith 'a=candidate'
ice_candidates.push sdp_line
- else if sdp_line.startsWith 'a=group'
- if flow_et.negotiation_mode() is z.calling.enum.SDP_NEGOTIATION_MODE.STREAM_CHANGE and sdp_source is z.calling.enum.SDPSource.LOCAL
- sdp_lines.push 'a=x-streamchange'
-
# Remove once obsolete due to high uptake of clients based on AVS build 3.3.11 containing fix for AUDIO-1215
else if sdp_line.startsWith 'a=mid'
- if rtc_sdp.type is z.calling.rtc.SDPType.ANSWER and z.util.Environment.browser.firefox and sdp_source is z.calling.enum.SDPSource.REMOTE
+ if sdp_source is z.calling.enum.SDPSource.REMOTE and z.util.Environment.browser.firefox and rtc_sdp.type is z.calling.rtc.SDPType.ANSWER
outline = 'a=mid:sdparta_2' if sdp_line is 'a=mid:data'
# Code to nail in bit-rate and ptime settings for improved performance and experience
diff --git a/app/script/calling/mapper/SDPRewriteMapper.coffee b/app/script/calling/mapper/SDPRewriteMapper.coffee
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/app/script/calling/v3/CallCenter.coffee b/app/script/calling/v3/CallCenter.coffee
index e954539716f..1f71f981ec7 100644
--- a/app/script/calling/v3/CallCenter.coffee
+++ b/app/script/calling/v3/CallCenter.coffee
@@ -341,7 +341,7 @@ class z.calling.v3.CallCenter
e_call_et.state z.calling.enum.CallState.ENDED
e_call_et.reset_call()
@e_calls.remove (e_call_et) -> e_call_et.id is conversation_id
- @media_stream_handler.reset_media_streams()
+ @media_stream_handler.reset_media_stream()
return undefined
.catch (error) ->
throw error unless error.type is z.calling.v3.CallError::TYPE.NOT_FOUND
@@ -355,7 +355,7 @@ class z.calling.v3.CallCenter
.then (e_call_et) =>
@logger.debug "Ignoring e-call in conversation '#{conversation_id}'", e_call_et
e_call_et.state z.calling.enum.CallState.IGNORED
- @media_stream_handler.reset_media_streams()
+ @media_stream_handler.reset_media_stream()
.catch (error) ->
throw error unless error.type is z.calling.v3.CallError::TYPE.NOT_FOUND
@@ -378,7 +378,7 @@ class z.calling.v3.CallCenter
e_call_et = e_call
@logger.debug "Joining e-call in conversation '#{conversation_id}'", e_call_et
e_call_et.start_timings()
- if not @media_stream_handler.has_media_streams()
+ if not @media_stream_handler.local_media_stream()
@media_stream_handler.initiate_media_stream conversation_id, video_send
.then =>
e_call_et.timings.time_step z.telemetry.calling.CallSetupSteps.STREAM_RECEIVED
@@ -404,7 +404,7 @@ class z.calling.v3.CallCenter
@get_e_call_by_id conversation_id
.then (e_call_et) =>
@logger.debug "Leaving e-call in conversation '#{conversation_id}'", e_call_et
- @media_stream_handler.release_media_streams()
+ @media_stream_handler.release_media_stream()
e_call_et.state z.calling.enum.CallState.DISCONNECTING
e_call_et.termination_reason = termination_reason if termination_reason and not e_call_et.termination_reason
@@ -491,7 +491,7 @@ class z.calling.v3.CallCenter
@telemetry.track_event z.tracking.EventName.CALLING.RECEIVED_CALL, e_call_et
@_distribute_activation_event e_call_message_et
.catch (error) =>
- @delete_call e_call_et.conversation_et.id
+ @delete_call e_call_message_et.conversation_id
throw error unless error instanceof z.media.MediaError
###
diff --git a/app/script/components/userInput.coffee b/app/script/components/userInput.coffee
index c28b368743a..6d83b8956e3 100644
--- a/app/script/components/userInput.coffee
+++ b/app/script/components/userInput.coffee
@@ -62,7 +62,8 @@ ko.components.register 'user-input',
-
+
+
diff --git a/app/script/entity/message/Asset.coffee b/app/script/entity/message/Asset.coffee
index 181cdd71ef7..e5251d4f65c 100644
--- a/app/script/entity/message/Asset.coffee
+++ b/app/script/entity/message/Asset.coffee
@@ -70,11 +70,11 @@ class z.entity.Asset
###
is_video: ->
is_video_asset = @type is z.assets.AssetType.FILE and @file_type?.startsWith 'video'
- is_supported_browser = not (z.util.Environment.browser.firefox and platform.version < 49)
- if is_video_asset and is_supported_browser
+ if is_video_asset
can_play = document.createElement('video').canPlayType @file_type
return true if can_play isnt ''
return false
+
###
Check if asset is a audio.
diff --git a/app/script/localization/strings-cs.coffee b/app/script/localization/strings-cs.coffee
index 5c1f54f64dd..4c834da9fe0 100644
--- a/app/script/localization/strings-cs.coffee
+++ b/app/script/localization/strings-cs.coffee
@@ -198,11 +198,6 @@ z.string.cs.modal_session_reset_message_2 = 'nás.'
# Too many members in conversation
z.string.cs.modal_too_many_members_headline = 'Přeplněné kupé'
z.string.cs.modal_too_many_members_message = 'Ke konverzaci se může připojit az %max účastníků. Je zde ještě místo pro %no.'
-# Whitelist screensharing
-z.string.cs.modal_whitelist_screensharing_headline = 'Wire potřebuje oprávnění sdílet vaši obrazovku'
-z.string.cs.modal_whitelist_screensharing_message_1 = 'Otevřete about:config a přidejte *.wire.com do seznamu domén s právy sdílet obrazovku. Otevřete'
-z.string.cs.modal_whitelist_screensharing_message_link = 'Časté dotazy'
-z.string.cs.modal_whitelist_screensharing_message_2 = 'pro více informací.'
# Parallel uploads
z.string.cs.modal_uploads_parallel = 'Najednou můžete poslat až %no souborů.'
diff --git a/app/script/localization/strings-da.coffee b/app/script/localization/strings-da.coffee
index d0ee5f2d481..efba34436c0 100644
--- a/app/script/localization/strings-da.coffee
+++ b/app/script/localization/strings-da.coffee
@@ -208,11 +208,6 @@ z.string.da.modal_session_reset_message_2 = 'os.'
# Too many members in conversation
z.string.da.modal_too_many_members_headline = 'Fuldt hus'
z.string.da.modal_too_many_members_message = 'Op til %max personer kan deltage i en samtale. Der er plads til %no personer mere herinde.'
-# Whitelist screensharing
-z.string.da.modal_whitelist_screensharing_headline = 'Wire skal have tilladelse til at dele din skærm'
-z.string.da.modal_whitelist_screensharing_message_1 = 'Åben about:config og tilføj *.wire.com til listen over tilladte domæner for skærmdeling. Se'
-z.string.da.modal_whitelist_screensharing_message_link = 'FAQ'
-z.string.da.modal_whitelist_screensharing_message_2 = 'for detaljer.'
# Parallel uploads
z.string.da.modal_uploads_parallel = 'Du kan sende op til %no filer på én gang.'
diff --git a/app/script/localization/strings-de.coffee b/app/script/localization/strings-de.coffee
index 23c4ff0baf2..e6a5fd947da 100644
--- a/app/script/localization/strings-de.coffee
+++ b/app/script/localization/strings-de.coffee
@@ -209,11 +209,6 @@ z.string.de.modal_session_reset_message_2 = 'uns.'
# Too many members in conversation
z.string.de.modal_too_many_members_headline = 'Volles Haus'
z.string.de.modal_too_many_members_message = 'An einer Unterhaltung für eine Gruppe können bis zu %max Personen teilnehmen. Hier ist noch Platz für %no Personen.'
-# Whitelist screensharing
-z.string.de.modal_whitelist_screensharing_headline = 'Wire braucht die Berechtigung deinen Bildschirm zu teilen'
-z.string.de.modal_whitelist_screensharing_message_1 = 'Öffne about:config und füge *.wire.com zur Liste der für Screensharing zugelassenen Domains hinzu. Lies den'
-z.string.de.modal_whitelist_screensharing_message_link = 'FAQ'
-z.string.de.modal_whitelist_screensharing_message_2 = 'für weitere Informationen.'
# Parallel uploads
z.string.de.modal_uploads_parallel = 'Du kannst bis zu %no Dateien auf einmal senden.'
diff --git a/app/script/localization/strings-es.coffee b/app/script/localization/strings-es.coffee
index 1b3ac18dd90..d72b448dd9a 100644
--- a/app/script/localization/strings-es.coffee
+++ b/app/script/localization/strings-es.coffee
@@ -208,11 +208,6 @@ z.string.es.modal_session_reset_message_2 = 'nosotros.'
# Too many members in conversation
z.string.es.modal_too_many_members_headline = 'Llamada llena'
z.string.es.modal_too_many_members_message = 'Hasta %max personas pueden unirse a una conversación. Hay espacio para %no más personas aquí.'
-# Whitelist screensharing
-z.string.es.modal_whitelist_screensharing_headline = 'Wire necesita permiso para compartir su pantalla'
-z.string.es.modal_whitelist_screensharing_message_1 = 'Abrir about:config y agregar *.wire.com a la lista de dominios que pueden compartir la pantalla. Ver'
-z.string.es.modal_whitelist_screensharing_message_link = 'Preguntas más Frecuentes'
-z.string.es.modal_whitelist_screensharing_message_2 = 'para mayor detalle.'
# Parallel uploads
z.string.es.modal_uploads_parallel = 'Puede enviar hasta %no archivos a la vez.'
diff --git a/app/script/localization/strings-fi.coffee b/app/script/localization/strings-fi.coffee
index 2768a3ff8b6..4caf7a339ad 100644
--- a/app/script/localization/strings-fi.coffee
+++ b/app/script/localization/strings-fi.coffee
@@ -200,11 +200,6 @@ z.string.fi.modal_session_reset_message_2 = 'meihin.'
# Too many members in conversation
z.string.fi.modal_too_many_members_headline = 'Talo täynnä'
z.string.fi.modal_too_many_members_message = 'Maksimissaan %max henkilöä voi liittyä keskusteluun. Tässä keskustelussa on tilaa %no hengelle.'
-# Whitelist screensharing
-z.string.fi.modal_whitelist_screensharing_headline = 'Wire tarvitsee luvan jakaa näyttösi'
-z.string.fi.modal_whitelist_screensharing_message_1 = 'Avaa about:config ja lisää *.wire.com näytön jakamisen sallivaan verkkotunnus-listaan'
-z.string.fi.modal_whitelist_screensharing_message_link = 'UKK'
-z.string.fi.modal_whitelist_screensharing_message_2 = 'lisätiedoille.'
# Parallel uploads
z.string.fi.modal_uploads_parallel = 'Voit lähettää jopa %no tiedostoa samaan aikaan.'
diff --git a/app/script/localization/strings-fr.coffee b/app/script/localization/strings-fr.coffee
index e640ad6c595..ac5da404714 100644
--- a/app/script/localization/strings-fr.coffee
+++ b/app/script/localization/strings-fr.coffee
@@ -208,11 +208,6 @@ z.string.fr.modal_session_reset_message_2 = '-nous.'
# Too many members in conversation
z.string.fr.modal_too_many_members_headline = 'Maison pleine'
z.string.fr.modal_too_many_members_message = 'Jusqu’à %max personnes peuvent se joindre à une conversation. Il y a encore de la place pour %no gens ici.'
-# Whitelist screensharing
-z.string.fr.modal_whitelist_screensharing_headline = 'Wire a besoin de votre autorisation pour partager votre écran'
-z.string.fr.modal_whitelist_screensharing_message_1 = 'Ouvrez about:config et ajoutez *.wire.com à la liste des domaines autorisés à partager l’écran. Allez voir la'
-z.string.fr.modal_whitelist_screensharing_message_link = 'FAQ'
-z.string.fr.modal_whitelist_screensharing_message_2 = 'pour plus de détails.'
# Parallel uploads
z.string.fr.modal_uploads_parallel = 'Vous pouvez envoyer jusqu’à %no fichiers à la fois.'
diff --git a/app/script/localization/strings-hr.coffee b/app/script/localization/strings-hr.coffee
index 66b514830f8..6d95cf32af6 100644
--- a/app/script/localization/strings-hr.coffee
+++ b/app/script/localization/strings-hr.coffee
@@ -198,11 +198,6 @@ z.string.hr.modal_session_reset_message_2 = 'nas.'
# Too many members in conversation
z.string.hr.modal_too_many_members_headline = 'Puna kuća'
z.string.hr.modal_too_many_members_message = 'Do %max ljudi može pristupiti razgovoru. Ima mjesta za još %no ljudi ovdje.'
-# Whitelist screensharing
-z.string.hr.modal_whitelist_screensharing_headline = 'Wire treba dozvolu za zajedničko korištenje vašeg zaslona'
-z.string.hr.modal_whitelist_screensharing_message_1 = 'Otvorite about:config i dodajte *. wire.com na popis dopuštenih domena za screensharing. Vidjeti'
-z.string.hr.modal_whitelist_screensharing_message_link = 'Česta pitanja'
-z.string.hr.modal_whitelist_screensharing_message_2 = 'detalje.'
# Parallel uploads
z.string.hr.modal_uploads_parallel = 'Možete poslati %no datoteke odjednom.'
diff --git a/app/script/localization/strings-hu.coffee b/app/script/localization/strings-hu.coffee
index bdb3fee412f..21614652e09 100644
--- a/app/script/localization/strings-hu.coffee
+++ b/app/script/localization/strings-hu.coffee
@@ -208,11 +208,6 @@ z.string.hu.modal_session_reset_message_2 = 'minket.'
# Too many members in conversation
z.string.hu.modal_too_many_members_headline = 'Telt ház'
z.string.hu.modal_too_many_members_message = 'Legfeljebb %max partner tud csatlakozni a beszélgetéshez. Még %no partner számára van hely a csoportban.'
-# Whitelist screensharing
-z.string.hu.modal_whitelist_screensharing_headline = 'Böngészőjének engedélyre van szüksége, hogy megossza képernyőjét'
-z.string.hu.modal_whitelist_screensharing_message_1 = 'Nyissa meg a beállításokat és adja hozzá a *.wire.com-ot, az engedélyezett domainekhez a képernyőmegosztási beállításokban. Lásd'
-z.string.hu.modal_whitelist_screensharing_message_link = 'GY. I. K'
-z.string.hu.modal_whitelist_screensharing_message_2 = 'a részletekért.'
# Parallel uploads
z.string.hu.modal_uploads_parallel = 'Egyszerre %no fájt küldhet.'
diff --git a/app/script/localization/strings-it.coffee b/app/script/localization/strings-it.coffee
index 7b91605d1af..f530d3c09b8 100644
--- a/app/script/localization/strings-it.coffee
+++ b/app/script/localization/strings-it.coffee
@@ -208,11 +208,6 @@ z.string.it.modal_session_reset_message_2 = 'Wire.'
# Too many members in conversation
z.string.it.modal_too_many_members_headline = 'Chiamata piena'
z.string.it.modal_too_many_members_message = 'Fino a %max persone possono partecipare a una conversazione. C’è spazio per ancora %no persone qui dentro.'
-# Whitelist screensharing
-z.string.it.modal_whitelist_screensharing_headline = 'Wire richiede l’autorizzazione per condividere il tuo schermo'
-z.string.it.modal_whitelist_screensharing_message_1 = 'Aprire about:config e aggiungere *.wire.com alla lista dei domini consentiti per la condivisione dello schermo. Vedere'
-z.string.it.modal_whitelist_screensharing_message_link = 'FAQ'
-z.string.it.modal_whitelist_screensharing_message_2 = 'per ulteriori dettagli.'
# Parallel uploads
z.string.it.modal_uploads_parallel = 'È possibile inviare fino a %no file in una sola volta.'
diff --git a/app/script/localization/strings-pt.coffee b/app/script/localization/strings-pt.coffee
index 2f9e86de006..2e9c7ab6987 100644
--- a/app/script/localization/strings-pt.coffee
+++ b/app/script/localization/strings-pt.coffee
@@ -208,11 +208,6 @@ z.string.pt.modal_session_reset_message_2 = 'contate.'
# Too many members in conversation
z.string.pt.modal_too_many_members_headline = 'Chamada cheia'
z.string.pt.modal_too_many_members_message = 'Até %max pessoas podem participar de uma conversa. Há espaço para %no pessoas aqui.'
-# Whitelist screensharing
-z.string.pt.modal_whitelist_screensharing_headline = 'Wire precisa de permissão para compartilhar sua tela'
-z.string.pt.modal_whitelist_screensharing_message_1 = 'Abrir about:config e adicione *. wire.com à lista de domínios permitidos para compartilhamento de tela. Consulte'
-z.string.pt.modal_whitelist_screensharing_message_link = 'o FAQ'
-z.string.pt.modal_whitelist_screensharing_message_2 = 'para detalhes.'
# Parallel uploads
z.string.pt.modal_uploads_parallel = 'Você pode enviar até %no arquivos de uma só vez.'
diff --git a/app/script/localization/strings-ro.coffee b/app/script/localization/strings-ro.coffee
index 86cbadf86f9..5cc2912531b 100644
--- a/app/script/localization/strings-ro.coffee
+++ b/app/script/localization/strings-ro.coffee
@@ -208,11 +208,6 @@ z.string.ro.modal_session_reset_message_2 = 'ne.'
# Too many members in conversation
z.string.ro.modal_too_many_members_headline = 'Conversație plină'
z.string.ro.modal_too_many_members_message = 'Maxim %max persoane se pot alătura conversației. Mai este loc pentru %no persoane aici.'
-# Whitelist screensharing
-z.string.ro.modal_whitelist_screensharing_headline = 'Wire are nevoie de permisiuni pentru a partaja ecranul'
-z.string.ro.modal_whitelist_screensharing_message_1 = 'Deschide about:config și adaugă *.wire.com în lista de domenii permise pentru partajarea ecranului. Vezi'
-z.string.ro.modal_whitelist_screensharing_message_link = 'Întrebări frecvente'
-z.string.ro.modal_whitelist_screensharing_message_2 = 'pentru detalii.'
# Parallel uploads
z.string.ro.modal_uploads_parallel = 'Poți trimite maxim %no fișiere simultan.'
diff --git a/app/script/localization/strings-ru.coffee b/app/script/localization/strings-ru.coffee
index 8703067f126..5b282222184 100644
--- a/app/script/localization/strings-ru.coffee
+++ b/app/script/localization/strings-ru.coffee
@@ -208,11 +208,6 @@ z.string.ru.modal_session_reset_message_2 = 'с нами.'
# Too many members in conversation
z.string.ru.modal_too_many_members_headline = 'Канал переполнен'
z.string.ru.modal_too_many_members_message = 'К разговору может присоединиться до %max человек. Здесь хватит места ещё для %no человек.'
-# Whitelist screensharing
-z.string.ru.modal_whitelist_screensharing_headline = 'Wire требуется разрешение для демонстрации экрана'
-z.string.ru.modal_whitelist_screensharing_message_1 = 'Откройте about:config и добавьте *.wire.com в список разрешённых доменов для демонстрации экрана. Смотрите'
-z.string.ru.modal_whitelist_screensharing_message_link = 'Вопросы и ответы'
-z.string.ru.modal_whitelist_screensharing_message_2 = 'для уточнения деталей.'
# Parallel uploads
z.string.ru.modal_uploads_parallel = 'Вы можете отправить до %no файлов за раз.'
diff --git a/app/script/localization/strings-sk.coffee b/app/script/localization/strings-sk.coffee
index b9e8048add6..a561bfa0dc6 100644
--- a/app/script/localization/strings-sk.coffee
+++ b/app/script/localization/strings-sk.coffee
@@ -208,11 +208,6 @@ z.string.sk.modal_session_reset_message_2 = 'nás.'
# Too many members in conversation
z.string.sk.modal_too_many_members_headline = 'Priveľa účastníkov'
z.string.sk.modal_too_many_members_message = 'Do rozhovoru sa môže zapojiť %max ľudí. '
-# Whitelist screensharing
-z.string.sk.modal_whitelist_screensharing_headline = 'Wire potrebuje povolenie na zdieľanie obrazovky'
-z.string.sk.modal_whitelist_screensharing_message_1 = 'Otvorte about:config a pridajte *.wire.com do zoznamu povolených domén pre zdieľanie obrazovky.'
-z.string.sk.modal_whitelist_screensharing_message_link = 'FAQ'
-z.string.sk.modal_whitelist_screensharing_message_2 = 'pre viac informácií.'
# Parallel uploads
z.string.sk.modal_uploads_parallel = 'Súčasne môžete poslať až %no súborov.'
diff --git a/app/script/localization/strings-sl.coffee b/app/script/localization/strings-sl.coffee
index 2aae842b769..2e52e2af136 100644
--- a/app/script/localization/strings-sl.coffee
+++ b/app/script/localization/strings-sl.coffee
@@ -208,11 +208,6 @@ z.string.sl.modal_session_reset_message_2 = 'nas.'
# Too many members in conversation
z.string.sl.modal_too_many_members_headline = 'Polna hiša'
z.string.sl.modal_too_many_members_message = 'Do %max oseb se lahko pridruži pogovoru. Tukaj je prostora še za %no oseb.'
-# Whitelist screensharing
-z.string.sl.modal_whitelist_screensharing_headline = 'Wire potrebuje dovoljenje za deljenje vašega zaslona'
-z.string.sl.modal_whitelist_screensharing_message_1 = 'Odpri about:config in dodaj *.wire.com na seznam dovoljenih domen za deljenje zaslona. Glej'
-z.string.sl.modal_whitelist_screensharing_message_link = 'Pogosto zastavljena vprašanja'
-z.string.sl.modal_whitelist_screensharing_message_2 = 'za podrobnosti.'
# Parallel uploads
z.string.sl.modal_uploads_parallel = 'Lahko pošljete do %no zbirk naenkrat.'
diff --git a/app/script/localization/strings-tr.coffee b/app/script/localization/strings-tr.coffee
index cd8a0ddf913..ed9fdd2329b 100644
--- a/app/script/localization/strings-tr.coffee
+++ b/app/script/localization/strings-tr.coffee
@@ -208,11 +208,6 @@ z.string.tr.modal_session_reset_message_2 = 'biz.'
# Too many members in conversation
z.string.tr.modal_too_many_members_headline = 'Dolup taşmış'
z.string.tr.modal_too_many_members_message = 'Görüşmeye en fazla %max kişi katılabilir. Burada %no kişi için daha boş yer var.'
-# Whitelist screensharing
-z.string.tr.modal_whitelist_screensharing_headline = 'Wire ekranınızı paylaşmak için gerekli izinleri sağlamalıdır'
-z.string.tr.modal_whitelist_screensharing_message_1 = 'Hakkında:ayarlar bölümünü açın ve *.wire.com adresini ekran paylaşımı izinli alan adları listesine ekleyin'
-z.string.tr.modal_whitelist_screensharing_message_link = 'SSS'
-z.string.tr.modal_whitelist_screensharing_message_2 = 'detaylar için.'
# Parallel uploads
z.string.tr.modal_uploads_parallel = 'Tek seferde en fazla %no boyutunda dosya gönderebilirsiniz.'
diff --git a/app/script/localization/strings-uk.coffee b/app/script/localization/strings-uk.coffee
index e0927270303..de353efa4e4 100644
--- a/app/script/localization/strings-uk.coffee
+++ b/app/script/localization/strings-uk.coffee
@@ -208,11 +208,6 @@ z.string.uk.modal_session_reset_message_2 = 'з нами.'
# Too many members in conversation
z.string.uk.modal_too_many_members_headline = 'Голосовий канал переповнений'
z.string.uk.modal_too_many_members_message = 'В розмові може бути до %max учасників. В даній розмові уже не вистачає місця для %no учасників.'
-# Whitelist screensharing
-z.string.uk.modal_whitelist_screensharing_headline = 'Для Wire необхідний дозвіл, щоб ви могли поділитись скріншотами робочого столу'
-z.string.uk.modal_whitelist_screensharing_message_1 = 'Перейдіть до about:config та додайте *.wire.com до списку дозволених доменів для обміну скріншотами робочого столу. Дивіться'
-z.string.uk.modal_whitelist_screensharing_message_link = 'розділ Часті запитання'
-z.string.uk.modal_whitelist_screensharing_message_2 = ', щоб дізнатись більше деталей.'
# Parallel uploads
z.string.uk.modal_uploads_parallel = 'Ви можете надіслати до %no файлів за один раз.'
diff --git a/app/script/localization/strings.coffee b/app/script/localization/strings.coffee
index bfd497b45ac..f452c8004ed 100644
--- a/app/script/localization/strings.coffee
+++ b/app/script/localization/strings.coffee
@@ -38,7 +38,7 @@ z.string.auth_account_create_account = 'Create an account'
z.string.auth_account_expiration = 'You were signed out because your session expired. Please log in again.'
z.string.auth_account_get_wire = 'Simple, private & secure messenger for chat, calls, sharing pics, music, videos, GIFs and more.'
z.string.auth_account_password_forgot = 'Forgot password'
-z.string.auth_account_remember_me = 'Remember me'
+z.string.auth_account_public_computer = 'This is a public computer'
z.string.auth_account_sign_in = 'Log in'
z.string.auth_account_sign_in_email = 'Email'
z.string.auth_account_sign_in_phone = 'Phone'
@@ -209,11 +209,6 @@ z.string.modal_session_reset_message_2 = 'us.'
# Too many members in conversation
z.string.modal_too_many_members_headline = 'Full house'
z.string.modal_too_many_members_message = 'Up to %max people can join a conversation. There is room for %no more people in here.'
-# Whitelist screensharing
-z.string.modal_whitelist_screensharing_headline = 'Wire needs permission to share your screen'
-z.string.modal_whitelist_screensharing_message_1 = 'Open about:config and add *.wire.com to the list of allowed domains for screensharing. See'
-z.string.modal_whitelist_screensharing_message_link = 'FAQ'
-z.string.modal_whitelist_screensharing_message_2 = 'for details.'
# Parallel uploads
z.string.modal_uploads_parallel = 'You can send up to %no files at once.'
diff --git a/app/script/media/MediaDevicesHandler.coffee b/app/script/media/MediaDevicesHandler.coffee
index 9f840bbef6f..9e1452f20de 100644
--- a/app/script/media/MediaDevicesHandler.coffee
+++ b/app/script/media/MediaDevicesHandler.coffee
@@ -97,7 +97,7 @@ class z.media.MediaDevicesHandler
@current_device_id.audio_input.subscribe (media_device_id) =>
z.util.StorageUtil.set_value z.media.MediaDeviceType.AUDIO_INPUT, media_device_id
- if media_device_id and @media_repository.stream_handler.local_media_streams.audio()
+ if media_device_id and @media_repository.stream_handler.local_media_stream()
@media_repository.stream_handler.replace_input_source z.media.MediaType.AUDIO
@_update_current_index_from_id z.media.MediaDeviceType.AUDIO_INPUT, media_device_id
@@ -108,13 +108,13 @@ class z.media.MediaDevicesHandler
@_update_current_index_from_id z.media.MediaDeviceType.AUDIO_OUTPUT, media_device_id
@current_device_id.screen_input.subscribe (media_device_id) =>
- if media_device_id and @media_repository.stream_handler.local_media_streams.video() and @media_repository.stream_handler.local_media_type() is z.media.MediaType.SCREEN
+ if media_device_id and @media_repository.stream_handler.local_media_stream() and @media_repository.stream_handler.local_media_type() is z.media.MediaType.SCREEN
@media_repository.stream_handler.replace_input_source z.media.MediaType.SCREEN
@_update_current_index_from_id z.media.MediaDeviceType.SCREEN_INPUT, media_device_id
@current_device_id.video_input.subscribe (media_device_id) =>
z.util.StorageUtil.set_value z.media.MediaDeviceType.VIDEO_INPUT, media_device_id
- if media_device_id and @media_repository.stream_handler.local_media_streams.video() and @media_repository.stream_handler.local_media_type() is z.media.MediaType.VIDEO
+ if media_device_id and @media_repository.stream_handler.local_media_stream() and @media_repository.stream_handler.local_media_type() is z.media.MediaType.VIDEO
@media_repository.stream_handler.replace_input_source z.media.MediaType.VIDEO
@_update_current_index_from_id z.media.MediaDeviceType.VIDEO_INPUT, media_device_id
diff --git a/app/script/media/MediaStreamHandler.coffee b/app/script/media/MediaStreamHandler.coffee
index 28e73b0e402..a6a4c448be8 100644
--- a/app/script/media/MediaStreamHandler.coffee
+++ b/app/script/media/MediaStreamHandler.coffee
@@ -65,9 +65,7 @@ class z.media.MediaStreamHandler
@calls = -> return []
@joined_call = -> return undefined
- @local_media_streams =
- audio: ko.observable()
- video: ko.observable()
+ @local_media_stream = ko.observable()
@remote_media_streams =
audio: ko.observableArray []
@@ -80,9 +78,6 @@ class z.media.MediaStreamHandler
@local_media_type = ko.observable z.media.MediaType.AUDIO
- @has_media_streams = ko.pureComputed =>
- return @local_media_streams.audio() or @local_media_streams.video()
-
@request_hint_timeout = undefined
@current_device_id = @media_repository.devices_handler.current_device_id
@@ -211,16 +206,12 @@ class z.media.MediaStreamHandler
if _.isArray error
[error, media_type] = error
@_initiate_media_stream_failure error, media_type, conversation_id
- @logger.error "Requesting MediaStream failed: #{error.message or error.name}", error
amplify.publish z.event.WebApp.ANALYTICS.EVENT, z.tracking.EventName.CALLING.FAILED_REQUESTING_MEDIA, {cause: error.name or error.message, video: video_send}
throw error
- # Release the MediaStreams.
- release_media_streams: =>
- media_streams_identical = @_compare_local_media_streams()
-
- @local_media_streams.audio undefined if @_release_media_stream @local_media_streams.audio()
- @local_media_streams.video undefined if media_streams_identical or @_release_media_stream @local_media_streams.video()
+ # Release the MediaStream.
+ release_media_stream: =>
+ @local_media_stream undefined if @_release_media_stream @local_media_stream()
###
Replace the MediaStream after a change of the selected input device.
@@ -234,15 +225,12 @@ class z.media.MediaStreamHandler
@_set_stream_state media_stream_info
update_promise = Promise.all (flow_et.update_media_stream media_stream_info for flow_et in @joined_call().get_flows())
else
- update_promise = Promise.resolve [media_stream_info]
+ update_promise = Promise.resolve media_stream_info.stream
update_promise.then (resolve_array) =>
- media_stream_info = resolve_array[0]
- if media_stream_info.type is z.media.MediaType.AUDIO
- @_release_media_stream @local_media_streams.audio(), z.media.MediaType.AUDIO
- else
- @_release_media_stream @local_media_streams.video(), z.media.MediaType.VIDEO
- @set_local_media_stream media_stream_info
+ media_stream = resolve_array[0]
+ @_release_media_stream @local_media_stream()
+ @local_media_stream media_stream
###
Update the used MediaStream after a new input device was selected.
@@ -264,7 +252,9 @@ class z.media.MediaStreamHandler
return @replace_media_stream media_stream_info
.catch (error) =>
[error, media_type] = error if _.isArray error
- @_replace_input_source_failure error, media_type
+ if media_type is z.media.MediaType.SCREEN
+ return @logger.error "Failed to enable screen sharing: #{error.message}", error
+ @logger.error "Failed to replace '#{media_type}' input source: #{error.message}", error
###
Request a MediaStream.
@@ -292,6 +282,7 @@ class z.media.MediaStreamHandler
@_clear_permission_request_hint media_type
resolve new z.media.MediaStreamInfo z.media.MediaStreamSource.LOCAL, 'self', media_stream
.catch (error) =>
+ @logger.warn "MediaStream request failed: #{error.name} - #{error.message}"
@_clear_permission_request_hint media_type
if error.name in z.calling.rtc.MediaStreamErrorTypes.DEVICE
error = new z.media.MediaError z.media.MediaError::TYPE.MEDIA_STREAM_DEVICE
@@ -301,15 +292,8 @@ class z.media.MediaStreamHandler
error = new z.media.MediaError z.media.MediaError::TYPE.MEDIA_STREAM_PERMISSION
reject [error, media_type]
- ###
- Save a reference to a local MediaStream.
- @param media_stream_info [z.media.MediaStreamInfo] MediaStream and meta information
- ###
- set_local_media_stream: (media_stream_info) =>
- if media_stream_info.type in [z.media.MediaType.AUDIO, z.media.MediaType.AUDIO_VIDEO]
- @local_media_streams.audio media_stream_info.stream
- if media_stream_info.type in [z.media.MediaType.AUDIO_VIDEO, z.media.MediaType.VIDEO]
- @local_media_streams.video media_stream_info.stream
+ set_local_media_stream: (media_stream) =>
+ @local_media_stream media_stream
###
Clear the permission request hint timeout or hide the warning.
@@ -321,14 +305,6 @@ class z.media.MediaStreamHandler
return window.clearTimeout @request_hint_timeout
return @_hide_permission_request_hint media_type
- ###
- Compare the local MediaStreams for equality.
- @private
- @return [Boolean] True if both audio and video stream are identical
- ###
- _compare_local_media_streams: ->
- return @local_media_streams.audio()?.id is @local_media_streams.video()?.id
-
###
Hide the permission denied hint banner.
@private
@@ -368,7 +344,7 @@ class z.media.MediaStreamHandler
@logger.debug "Received initial MediaStream with '#{media_stream_info.stream.getTracks().length}' MediaStreamTrack(s)",
{stream: media_stream_info.stream, audio_tracks: media_stream_info.stream.getAudioTracks(), video_tracks: media_stream_info.stream.getVideoTracks()}
@_set_stream_state media_stream_info
- @set_local_media_stream media_stream_info
+ @local_media_stream media_stream_info.stream
###
Local MediaStream creation failed.
@@ -407,24 +383,6 @@ class z.media.MediaStreamHandler
@logger.warn 'No MediaStreamTrack found to stop', media_stream
return false
- ###
- Failed to replace an input source.
-
- @private
- @param error [Error] Error thrown when attempting to replace the source
- @param media_type [z.media.MediaType] Type of failed request
- ###
- _replace_input_source_failure: (error, media_type) ->
- if media_type is z.media.MediaType.SCREEN
- if z.util.Environment.browser.firefox and error.type is z.media.MediaError::TYPE.MEDIA_STREAM_PERMISSION
- # @deprecated Remove once we require Firefox 52 ESR
- @logger.warn 'We are not on the white list. Manually add the current domain to media.getusermedia.screensharing.allowed_domains on about:config'
- amplify.publish z.event.WebApp.WARNING.MODAL, z.ViewModel.ModalType.WHITELIST_SCREENSHARING
- else
- @logger.error "Failed to enable screen sharing: #{error.message}", error
- else
- @logger.error "Failed to replace '#{media_type}' input source: #{error.message}", error
-
###
Show microphone not found hin banner.
@@ -502,18 +460,18 @@ class z.media.MediaStreamHandler
# Toggle the camera.
toggle_video_send: =>
- if @local_media_streams.video() and @local_media_type() is z.media.MediaType.VIDEO
+ if @local_media_stream() and @local_media_type() is z.media.MediaType.VIDEO
return @_toggle_video_send()
return @replace_input_source z.media.MediaType.VIDEO
# Toggle the mute state of the microphone.
toggle_audio_send: =>
- return @_toggle_audio_send() if @local_media_streams.audio()
+ return @_toggle_audio_send() if @local_media_stream()
return Promise.reject new z.media.MediaError z.media.MediaError::TYPE.NO_AUDIO_STREAM_FOUND
# Toggle the screen.
toggle_screen_send: =>
- if @local_media_streams.video() and @local_media_type() is z.media.MediaType.SCREEN
+ if @local_media_stream() and @local_media_type() is z.media.MediaType.SCREEN
return @_toggle_screen_send()
return @replace_input_source z.media.MediaType.SCREEN
@@ -524,10 +482,10 @@ class z.media.MediaStreamHandler
@self_stream_state.video_send false
@local_media_type z.media.MediaType.AUDIO
- # Reset the MediaStreams and states.
- reset_media_streams: =>
+ # Reset the MediaStream and states.
+ reset_media_stream: =>
if not @needs_media_stream()
- @release_media_streams()
+ @release_media_stream()
@reset_self_states()
@media_repository.close_audio_context()
@@ -567,7 +525,7 @@ class z.media.MediaStreamHandler
@private
###
_toggle_audio_send: ->
- @_toggle_stream_enabled z.media.MediaType.AUDIO, @local_media_streams.audio(), @self_stream_state.audio_send
+ @_toggle_stream_enabled z.media.MediaType.AUDIO, @local_media_stream(), @self_stream_state.audio_send
.then (audio_track) =>
@logger.info "Microphone enabled: #{@self_stream_state.audio_send()}", audio_track
return @self_stream_state.audio_send()
@@ -577,7 +535,7 @@ class z.media.MediaStreamHandler
@private
###
_toggle_screen_send: ->
- @_toggle_stream_enabled z.media.MediaType.VIDEO, @local_media_streams.video(), @self_stream_state.screen_send
+ @_toggle_stream_enabled z.media.MediaType.VIDEO, @local_media_stream(), @self_stream_state.screen_send
.then (video_track) =>
@logger.info "Screen enabled: #{@self_stream_state.screen_send()}", video_track
return @self_stream_state.screen_send()
@@ -587,7 +545,7 @@ class z.media.MediaStreamHandler
@private
###
_toggle_video_send: ->
- @_toggle_stream_enabled z.media.MediaType.VIDEO, @local_media_streams.video(), @self_stream_state.video_send
+ @_toggle_stream_enabled z.media.MediaType.VIDEO, @local_media_stream(), @self_stream_state.video_send
.then (video_track) =>
@logger.info "Camera enabled: #{@self_stream_state.video_send()}", video_track
return @self_stream_state.video_send()
diff --git a/app/script/service/Client.coffee b/app/script/service/Client.coffee
index 7d72fd6ce11..53cb34d4cc5 100644
--- a/app/script/service/Client.coffee
+++ b/app/script/service/Client.coffee
@@ -19,18 +19,25 @@
window.z ?= {}
z.service ?= {}
-IGNORED_BACKEND_ERRORS = [
- z.service.BackendClientError::STATUS_CODE.BAD_GATEWAY
- z.service.BackendClientError::STATUS_CODE.BAD_REQUEST
- z.service.BackendClientError::STATUS_CODE.CONFLICT
- z.service.BackendClientError::STATUS_CODE.CONNECTIVITY_PROBLEM
- z.service.BackendClientError::STATUS_CODE.INTERNAL_SERVER_ERROR
- z.service.BackendClientError::STATUS_CODE.NOT_FOUND
- z.service.BackendClientError::STATUS_CODE.PRECONDITION_FAILED
- z.service.BackendClientError::STATUS_CODE.REQUEST_TIMEOUT
- z.service.BackendClientError::STATUS_CODE.REQUEST_TOO_LARGE
- z.service.BackendClientError::STATUS_CODE.TOO_MANY_REQUESTS
-]
+CLIENT_CONFIG =
+ IGNORED_BACKEND_ERRORS: [
+ z.service.BackendClientError::STATUS_CODE.BAD_GATEWAY
+ z.service.BackendClientError::STATUS_CODE.BAD_REQUEST
+ z.service.BackendClientError::STATUS_CODE.CONFLICT
+ z.service.BackendClientError::STATUS_CODE.CONNECTIVITY_PROBLEM
+ z.service.BackendClientError::STATUS_CODE.INTERNAL_SERVER_ERROR
+ z.service.BackendClientError::STATUS_CODE.NOT_FOUND
+ z.service.BackendClientError::STATUS_CODE.PRECONDITION_FAILED
+ z.service.BackendClientError::STATUS_CODE.REQUEST_TIMEOUT
+ z.service.BackendClientError::STATUS_CODE.REQUEST_TOO_LARGE
+ z.service.BackendClientError::STATUS_CODE.TOO_MANY_REQUESTS
+ ]
+ IGNORED_BACKEND_LABELS: [
+ z.service.BackendClientError::LABEL.PASSWORD_EXISTS
+ z.service.BackendClientError::LABEL.TOO_MANY_CLIENTS
+ z.service.BackendClientError::LABEL.TOO_MANY_MEMBERS
+ ]
+
# Client for all backend REST API calls.
class z.service.Client
@@ -180,15 +187,12 @@ class z.service.Client
amplify.publish z.event.WebApp.CONNECTION.ACCESS_TOKEN.RENEW, 'Unauthorized backend request'
return
when z.service.BackendClientError::STATUS_CODE.FORBIDDEN
- switch jqXHR.responseJSON?.label
- when z.service.BackendClientError::LABEL.INVALID_CREDENTIALS
- Raygun.send new Error 'Server request failed: Invalid credentials'
- when z.service.BackendClientError::LABEL.TOO_MANY_CLIENTS, z.service.BackendClientError::LABEL.TOO_MANY_MEMBERS
- @logger.warn "Server request failed: '#{jqXHR.responseJSON.label}'"
- else
- Raygun.send new Error 'Server request failed'
+ if jqXHR.responseJSON?.label in CLIENT_CONFIG.IGNORED_BACKEND_LABELS
+ @logger.warn "Server request failed: #{jqXHR.responseJSON?.label}"
+ else
+ Raygun.send new Error "Server request failed: #{jqXHR.responseJSON?.label}"
else
- if jqXHR.status not in IGNORED_BACKEND_ERRORS
+ if jqXHR.status not in CLIENT_CONFIG.IGNORED_BACKEND_ERRORS
Raygun.send new Error "Server request failed: #{jqXHR.status}"
reject jqXHR.responseJSON or new z.service.BackendClientError jqXHR.status
diff --git a/app/script/util/ArrayUtil.coffee b/app/script/util/ArrayUtil.coffee
index fec3da93e13..4b534fd75d6 100644
--- a/app/script/util/ArrayUtil.coffee
+++ b/app/script/util/ArrayUtil.coffee
@@ -24,7 +24,7 @@ z.util.ArrayUtil =
# returns chunks of the given size
chunk: (array, size) ->
chunks = []
- temp_array = [].concat array
+ temp_array = Array.from array
while temp_array.length
chunks.push temp_array.splice 0, size
return chunks
diff --git a/app/script/util/DebugUtil.coffee b/app/script/util/DebugUtil.coffee
index 4c3cc5bf552..49a6fe93d75 100644
--- a/app/script/util/DebugUtil.coffee
+++ b/app/script/util/DebugUtil.coffee
@@ -82,6 +82,40 @@ class z.util.DebugUtil
@logger.warn "From: #{debug_information.user.name()}", debug_information.user
resolve debug_information
+ get_serialised_session: (session_id) ->
+ return wire.app.repository.storage.storage_service.load 'sessions', session_id
+ .then (record) ->
+ base64_encoded_payload = z.util.array_to_base64 record.serialised
+ record.serialised = base64_encoded_payload
+ return record
+
+ get_serialised_identity: ->
+ return wire.app.repository.storage.storage_service.load 'keys', 'local_identity'
+ .then (record) ->
+ base64_encoded_payload = z.util.array_to_base64 record.serialised
+ record.serialised = base64_encoded_payload
+ return record
+
+ get_event_from_notification_stream: (event_id) ->
+ client_id = wire.app.repository.client.current_client().id
+ return wire.app.service.notification.get_notifications(client_id, undefined, 10000)
+ .then (response) ->
+ events = response.notifications.filter (item) ->
+ return item.id is event_id
+ return events[0]
+
+ get_objects_for_decryption_errors: (session_id, event_id) ->
+ return Promise.all([
+ @get_event_from_notification_stream event_id
+ @get_serialised_identity()
+ @get_serialised_session session_id
+ ])
+ .then (items) ->
+ return JSON.stringify
+ event: items[0]
+ identity: items[1]
+ session: items[2]
+
log_connection_status: ->
@logger.log 'Online Status'
@logger.log "-- Browser online: #{window.navigator.onLine}"
diff --git a/app/script/util/Environment.coffee b/app/script/util/Environment.coffee
index 539ea1e8698..ffba63aabf4 100644
--- a/app/script/util/Environment.coffee
+++ b/app/script/util/Environment.coffee
@@ -72,8 +72,7 @@ z.util.Environment = do ->
return false
supports_screen_sharing: ->
return true if window.desktopCapturer
- # @deprecated Remove warning modal once we require Firefox 52 ESR
- return @is_firefox() and @get_version() >= 48
+ return @is_firefox()
os =
is_mac: ->
diff --git a/app/script/view_model/AuthViewModel.coffee b/app/script/view_model/AuthViewModel.coffee
index 3939309e7e0..d9e0d948424 100644
--- a/app/script/view_model/AuthViewModel.coffee
+++ b/app/script/view_model/AuthViewModel.coffee
@@ -73,17 +73,19 @@ class z.ViewModel.AuthViewModel
@session_expired = ko.observable false
@device_reused = ko.observable false
- @client_type = ko.observable z.client.ClientType.TEMPORARY
@country_code = ko.observable ''
@country = ko.observable ''
@name = ko.observable ''
@password = ko.observable ''
- @persist = ko.observable z.util.Environment.electron
+ @persist = ko.observable true
@phone_number = ko.observable ''
@username = ko.observable ''
- @persist.subscribe (is_persistent) =>
- if is_persistent then @client_type z.client.ClientType.PERMANENT else z.client.ClientType.TEMPORARY
+ @is_public_computer = ko.observable false
+ @is_public_computer.subscribe (is_public_computer) => @persist not is_public_computer
+
+ @client_type = ko.pureComputed =>
+ if @persist() then z.client.ClientType.PERMANENT else z.client.ClientType.TEMPORARY
@self_user = ko.observable()
diff --git a/app/script/view_model/ModalsViewModel.coffee b/app/script/view_model/ModalsViewModel.coffee
index 6d44315ce96..b91552f37b9 100644
--- a/app/script/view_model/ModalsViewModel.coffee
+++ b/app/script/view_model/ModalsViewModel.coffee
@@ -43,7 +43,6 @@ z.ViewModel.ModalType =
SESSION_RESET: '.modal-session-reset'
UPLOAD_PARALLEL: '.modal-asset-upload-parallel'
UPLOAD_TOO_LARGE: '.modal-asset-upload-too-large'
- WHITELIST_SCREENSHARING: '.modal-whitelist-screensharing'
z.ViewModel.MODAL_CONSENT_TYPE =
diff --git a/app/script/view_model/VideoCallingViewModel.coffee b/app/script/view_model/VideoCallingViewModel.coffee
index 669121a88d0..a4a204a59d5 100644
--- a/app/script/view_model/VideoCallingViewModel.coffee
+++ b/app/script/view_model/VideoCallingViewModel.coffee
@@ -30,7 +30,7 @@ class z.ViewModel.VideoCallingViewModel
@current_device_id = @media_repository.devices_handler.current_device_id
@current_device_index = @media_repository.devices_handler.current_device_index
- @local_video_stream = @media_repository.stream_handler.local_media_streams.video
+ @local_video_stream = @media_repository.stream_handler.local_media_stream
@remote_video_stream = @media_repository.stream_handler.remote_media_streams.video
@self_stream_state = @media_repository.stream_handler.self_stream_state
diff --git a/app/script/view_model/bindings/CommonBindings.coffee b/app/script/view_model/bindings/CommonBindings.coffee
index b142b918a8e..aaa7383e968 100644
--- a/app/script/view_model/bindings/CommonBindings.coffee
+++ b/app/script/view_model/bindings/CommonBindings.coffee
@@ -217,9 +217,6 @@ ko.subscribable.fn.subscribe_once = (handler, owner, event_name) ->
ko.bindingHandlers.antiscroll =
init: (element, valueAccessor) ->
- if z.util.Environment.os.mac and not z.util.Environment.browser.firefox
- return
-
$(element).antiscroll
autoHide: true
autoWrap: true
diff --git a/app/script/view_model/content/CollectionDetailsViewModel.coffee b/app/script/view_model/content/CollectionDetailsViewModel.coffee
index 78af5e07f74..6f7a7519ce3 100644
--- a/app/script/view_model/content/CollectionDetailsViewModel.coffee
+++ b/app/script/view_model/content/CollectionDetailsViewModel.coffee
@@ -71,7 +71,7 @@ class z.ViewModel.content.CollectionDetailsViewModel
should_show_header: (message_et) =>
if not @last_message_timestamp?
- @last_message_timestamp = message_et.timestamp
+ @last_message_timestamp = message_et.timestamp()
return true
# we passed today
diff --git a/app/script/view_model/content/PreferencesAVViewModel.coffee b/app/script/view_model/content/PreferencesAVViewModel.coffee
index f8aa3184fdd..f326426158d 100644
--- a/app/script/view_model/content/PreferencesAVViewModel.coffee
+++ b/app/script/view_model/content/PreferencesAVViewModel.coffee
@@ -30,14 +30,13 @@ class z.ViewModel.content.PreferencesAVViewModel
@current_device_id = @media_devices_handler.current_device_id
@media_stream_handler = @media_repository.stream_handler
- @audio_stream = @media_stream_handler.local_media_streams.audio
- @video_stream = @media_stream_handler.local_media_streams.video
+ @media_stream = @media_stream_handler.local_media_stream
@is_visible = false
- @audio_stream.subscribe (audio_stream) =>
+ @media_stream.subscribe (media_stream) =>
@_release_audio_meter() if @audio_interval
- @_initiate_audio_meter audio_stream if @is_visible and audio_stream
+ @_initiate_audio_meter media_stream if @is_visible and media_stream
@audio_context = undefined
@audio_level = ko.observable 0
@@ -49,29 +48,29 @@ class z.ViewModel.content.PreferencesAVViewModel
initiate_devices: =>
@is_visible = true
@_get_media_stream()
- .then (audio_stream) =>
- @_initiate_audio_meter audio_stream if audio_stream and not @audio_interval
+ .then (media_stream) =>
+ @_initiate_audio_meter media_stream if media_stream and not @audio_interval
# Release devices.
release_devices: =>
@is_visible = false
@_release_audio_meter()
- @_release_media_streams()
+ @_release_media_stream()
###
Get current MediaStream or initiate it.
@private
###
_get_media_stream: =>
- return Promise.resolve @audio_stream() if @audio_stream() and @video_stream()
+ return Promise.resolve @media_stream() if @media_stream() and @media_stream_handler.local_media_type() is z.media.MediaType.VIDEO
@media_stream_handler.get_media_stream_constraints @available_devices.audio_input().length, @available_devices.video_input().length
.then ([media_type, media_stream_constraints]) =>
return @media_stream_handler.request_media_stream media_type, media_stream_constraints
.then (media_stream_info) =>
@media_stream_handler.local_media_type z.media.MediaType.VIDEO if @available_devices.video_input().length
- @media_stream_handler.set_local_media_stream media_stream_info
- return @audio_stream()
+ @media_stream_handler.local_media_stream media_stream_info.stream
+ return @media_stream_handler.local_media_stream()
.catch (error) =>
error = error[0] if _.isArray error
@logger.error "Requesting MediaStream failed: #{error.message}", error
@@ -83,10 +82,10 @@ class z.ViewModel.content.PreferencesAVViewModel
###
Initiate audio meter.
@private
- @param audio_stream []
+ @param media_stream [MediaStream] MediaStream to measure audio levels on
###
- _initiate_audio_meter: (audio_stream) =>
- @logger.info 'Initiating new audio meter', audio_stream
+ _initiate_audio_meter: (media_stream) =>
+ @logger.info 'Initiating new audio meter', media_stream
@audio_context = @media_repository.get_audio_context()
@audio_analyser = @audio_context.createAnalyser()
@@ -106,7 +105,7 @@ class z.ViewModel.content.PreferencesAVViewModel
@audio_level average_volume - 0.075
, 100
- @audio_source = @audio_context.createMediaStreamSource audio_stream
+ @audio_source = @audio_context.createMediaStreamSource media_stream
@audio_source.connect @audio_analyser
_release_audio_meter: =>
@@ -114,6 +113,6 @@ class z.ViewModel.content.PreferencesAVViewModel
@audio_interval = undefined
@audio_source.disconnect() if @audio_source
- _release_media_streams: =>
- @media_stream_handler.reset_media_streams()
+ _release_media_stream: =>
+ @media_stream_handler.reset_media_stream()
@permission_denied false
diff --git a/app/style/components/asset/link-preview-asset.less b/app/style/components/asset/link-preview-asset.less
index b903d4a0805..196035d3355 100644
--- a/app/style/components/asset/link-preview-asset.less
+++ b/app/style/components/asset/link-preview-asset.less
@@ -61,7 +61,6 @@ link-preview-asset {
.link-preview-info-title {
font-weight: @font-weight-bold;
line-height: @line-height-lg;
- margin-bottom: 4px;
}
.link-preview-info-title-singleline {
diff --git a/aws/config.py b/aws/config.py
index 90430707675..04eb71e0e51 100644
--- a/aws/config.py
+++ b/aws/config.py
@@ -29,9 +29,9 @@
PUBLIC_KEY_PINS = os.environ.get('PUBLIC_KEY_PINS', '')
SUPPORTED = {
- 'chrome': 52,
- 'firefox': 45,
- 'opera': 41,
+ 'chrome': 55,
+ 'firefox': 52,
+ 'opera': 42,
'msedge': 14,
}
diff --git a/karma.conf.js b/karma.conf.js
index 2eb1b71d732..1f8fc51589c 100644
--- a/karma.conf.js
+++ b/karma.conf.js
@@ -102,7 +102,7 @@ module.exports = function (config) {
each: {
statements: 2,
branches: 0,
- functions: 1,
+ functions: 0,
lines: 2
}
}
diff --git a/test/unit_tests/assets/AssetRemoteDataSpec.coffee b/test/unit_tests/assets/AssetRemoteDataSpec.coffee
index fe2bbdf6d28..49d21a14b5c 100644
--- a/test/unit_tests/assets/AssetRemoteDataSpec.coffee
+++ b/test/unit_tests/assets/AssetRemoteDataSpec.coffee
@@ -28,7 +28,7 @@ describe 'z.assets.AssetRemoteData', ->
conversation_id = z.util.create_random_uuid()
asset_id = z.util.create_random_uuid()
remote_data = z.assets.AssetRemoteData.v1 conversation_id, asset_id
- spyOn(remote_data, '_load_buffer').and.returnValue Promise.resolve video_bytes.buffer
+ spyOn(remote_data, '_load_buffer').and.returnValue Promise.resolve([video_bytes.buffer, video_type])
it 'should load and decrypt asset', (done) ->
remote_data.load()
diff --git a/test/unit_tests/audio/AudioRepositorySpec.coffee b/test/unit_tests/audio/AudioRepositorySpec.coffee
index 9bfff551fa3..99fb50f605c 100644
--- a/test/unit_tests/audio/AudioRepositorySpec.coffee
+++ b/test/unit_tests/audio/AudioRepositorySpec.coffee
@@ -42,7 +42,7 @@ describe 'z.audio.AudioRepository', ->
.then done.fail
.catch (error) ->
expect(error).toEqual jasmine.any z.audio.AudioError
- expect(error.type).toBe z.audio.AudioError::TYPE.IGNORED_SOUND
+ expect(error.type).toBe z.audio.AudioError.TYPE.IGNORED_SOUND
done()
describe '_get_sound_by_id', ->
@@ -58,7 +58,7 @@ describe 'z.audio.AudioRepository', ->
.then done.fail
.catch (error) ->
expect(error).toEqual jasmine.any z.audio.AudioError
- expect(error.type).toBe z.audio.AudioError::TYPE.NOT_FOUND
+ expect(error.type).toBe z.audio.AudioError.TYPE.NOT_FOUND
done()
xdescribe '_play', ->
@@ -91,7 +91,7 @@ describe 'z.audio.AudioRepository', ->
.then done.fail
.catch (error) ->
expect(error).toEqual jasmine.any z.audio.AudioError
- expect(error.type).toBe z.audio.AudioError::TYPE.ALREADY_PLAYING
+ expect(error.type).toBe z.audio.AudioError.TYPE.ALREADY_PLAYING
done()
.catch done.fail
@@ -99,7 +99,7 @@ describe 'z.audio.AudioRepository', ->
audio_repository._play undefined, audio_repository.audio_elements[z.audio.AudioType.OUTGOING_CALL]
.catch (error) ->
expect(error).toEqual jasmine.any z.audio.AudioError
- expect(error.type).toBe z.audio.AudioError::TYPE.NOT_FOUND
+ expect(error.type).toBe z.audio.AudioError.TYPE.NOT_FOUND
done()
.catch done.fail
@@ -107,6 +107,6 @@ describe 'z.audio.AudioRepository', ->
audio_repository._play z.audio.AudioType.OUTGOING_CALL, undefined
.catch (error) ->
expect(error).toEqual jasmine.any z.audio.AudioError
- expect(error.type).toBe z.audio.AudioError::TYPE.NOT_FOUND
+ expect(error.type).toBe z.audio.AudioError.TYPE.NOT_FOUND
done()
.catch done.fail
diff --git a/test/unit_tests/calling/v2/CallCenterSpec.coffee b/test/unit_tests/calling/v2/CallCenterSpec.coffee
index 0f028d17b93..c828be4b4a3 100644
--- a/test/unit_tests/calling/v2/CallCenterSpec.coffee
+++ b/test/unit_tests/calling/v2/CallCenterSpec.coffee
@@ -397,14 +397,14 @@ describe 'z.calling.v2.CallCenter', ->
'member_count': 11
'message': 'too many members for calling'
}
- spyOn v2_call_center.media_stream_handler, 'release_media_streams'
+ spyOn v2_call_center.media_stream_handler, 'release_media_stream'
v2_call_center.state_handler._put_state conversation_et.id, {state: z.calling.enum.ParticipantState.JOINED, videod: false}
.then done.fail
.catch (error) ->
expect(error).toEqual jasmine.any z.calling.v2.CallError
expect(error.type).toBe z.calling.v2.CallError::TYPE.CONVERSATION_TOO_BIG
- expect(v2_call_center.media_stream_handler.release_media_streams).toHaveBeenCalled()
+ expect(v2_call_center.media_stream_handler.release_media_stream).toHaveBeenCalled()
done()
server.requests[0].respond 409, 'Content-Type': 'application/json', JSON.stringify error_payload
@@ -415,14 +415,14 @@ describe 'z.calling.v2.CallCenter', ->
'max_joined': 5
'message': 'the voice channel is full'
}
- spyOn v2_call_center.media_stream_handler, 'release_media_streams'
+ spyOn v2_call_center.media_stream_handler, 'release_media_stream'
v2_call_center.state_handler._put_state conversation_et.id, {state: z.calling.enum.ParticipantState.JOINED, videod: false}
.then done.fail
.catch (error) ->
expect(error).toEqual jasmine.any z.calling.v2.CallError
expect(error.type).toBe z.calling.v2.CallError::TYPE.VOICE_CHANNEL_FULL
- expect(v2_call_center.media_stream_handler.release_media_streams).toHaveBeenCalled()
+ expect(v2_call_center.media_stream_handler.release_media_stream).toHaveBeenCalled()
done()
server.requests[0].respond 409, 'Content-Type': 'application/json', JSON.stringify error_payload
@@ -432,13 +432,13 @@ describe 'z.calling.v2.CallCenter', ->
'label': 'invalid-op'
'message': 'Nobody left to call'
}
- spyOn v2_call_center.media_stream_handler, 'release_media_streams'
+ spyOn v2_call_center.media_stream_handler, 'release_media_stream'
v2_call_center.state_handler._put_state conversation_et.id, {state: z.calling.enum.ParticipantState.JOINED, videod: false}
.then done.fail
.catch (error) ->
expect(error).toEqual jasmine.any z.calling.v2.CallError
expect(error.type).toBe z.calling.v2.CallError::TYPE.CONVERSATION_EMPTY
- expect(v2_call_center.media_stream_handler.release_media_streams).toHaveBeenCalled()
+ expect(v2_call_center.media_stream_handler.release_media_stream).toHaveBeenCalled()
done()
server.requests[0].respond 400, 'Content-Type': 'application/json', JSON.stringify error_payload
diff --git a/test/unit_tests/media/MediaStreamHandlerSpec.coffee b/test/unit_tests/media/MediaStreamHandlerSpec.coffee
index 2e1210977fb..e2db322dc75 100644
--- a/test/unit_tests/media/MediaStreamHandlerSpec.coffee
+++ b/test/unit_tests/media/MediaStreamHandlerSpec.coffee
@@ -36,7 +36,7 @@ describe 'z.media.MediaStreamHandler', ->
spyOn(media_repository.stream_handler, '_toggle_audio_send').and.returnValue Promise.resolve()
it 'toggles the audio stream if available', (done) ->
- media_repository.stream_handler.local_media_streams.audio true
+ media_repository.stream_handler.local_media_stream true
media_repository.stream_handler.toggle_audio_send()
.then ->
@@ -45,7 +45,7 @@ describe 'z.media.MediaStreamHandler', ->
.catch done.fail
it 'throws an error if no audio stream is found', (done) ->
- media_repository.stream_handler.local_media_streams.audio undefined
+ media_repository.stream_handler.local_media_stream undefined
media_repository.stream_handler.toggle_audio_send()
.then done.fail
@@ -61,7 +61,7 @@ describe 'z.media.MediaStreamHandler', ->
spyOn(media_repository.stream_handler, 'replace_input_source').and.returnValue Promise.resolve()
it 'toggles the video stream if available and in video mode', (done) ->
- media_repository.stream_handler.local_media_streams.video true
+ media_repository.stream_handler.local_media_stream true
media_repository.stream_handler.local_media_type z.media.MediaType.VIDEO
media_repository.stream_handler.toggle_video_send()
@@ -72,7 +72,7 @@ describe 'z.media.MediaStreamHandler', ->
.catch done.fail
it 'turns on the video stream if it does not exist', (done) ->
- media_repository.stream_handler.local_media_streams.video undefined
+ media_repository.stream_handler.local_media_stream undefined
media_repository.stream_handler.local_media_type z.media.MediaType.VIDEO
media_repository.stream_handler.toggle_video_send()
@@ -83,7 +83,7 @@ describe 'z.media.MediaStreamHandler', ->
.catch done.fail
it 'turns on the video stream if not in video mode', (done) ->
- media_repository.stream_handler.local_media_streams.video true
+ media_repository.stream_handler.local_media_stream true
media_repository.stream_handler.local_media_type z.media.MediaType.SCREEN
media_repository.stream_handler.toggle_video_send()
@@ -100,7 +100,7 @@ describe 'z.media.MediaStreamHandler', ->
spyOn(media_repository.stream_handler, 'replace_input_source').and.returnValue Promise.resolve()
it 'toggles screen sharing if available and in screen sharing mode', (done) ->
- media_repository.stream_handler.local_media_streams.video true
+ media_repository.stream_handler.local_media_stream true
media_repository.stream_handler.local_media_type z.media.MediaType.SCREEN
media_repository.stream_handler.toggle_screen_send()
@@ -111,7 +111,7 @@ describe 'z.media.MediaStreamHandler', ->
.catch done.fail
it 'turns on the screen sharing stream if it does not exist', (done) ->
- media_repository.stream_handler.local_media_streams.video undefined
+ media_repository.stream_handler.local_media_stream undefined
media_repository.stream_handler.local_media_type z.media.MediaType.SCREEN
media_repository.stream_handler.toggle_screen_send()
@@ -122,7 +122,7 @@ describe 'z.media.MediaStreamHandler', ->
.catch done.fail
it 'turns on the video stream if not in screen sharing mode', (done) ->
- media_repository.stream_handler.local_media_streams.video true
+ media_repository.stream_handler.local_media_stream true
media_repository.stream_handler.local_media_type z.media.MediaType.VIDEO
media_repository.stream_handler.toggle_screen_send()
diff --git a/yarn.lock b/yarn.lock
index 71fbc71a42d..8e4de076461 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -13,10 +13,35 @@ accepts@1.3.3, accepts@~1.3.3:
mime-types "~2.1.11"
negotiator "0.6.1"
+acorn-jsx@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b"
+ dependencies:
+ acorn "^3.0.4"
+
+acorn@4.0.4:
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.4.tgz#17a8d6a7a6c4ef538b814ec9abac2779293bf30a"
+
+acorn@^3.0.4:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
+
after@0.8.2:
version "0.8.2"
resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
+ajv-keywords@^1.0.0:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
+
+ajv@^4.7.0, ajv@^4.9.1:
+ version "4.11.5"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.5.tgz#b6ee74657b993a01dce44b7944d56f485828d5bd"
+ dependencies:
+ co "^4.6.0"
+ json-stable-stringify "^1.0.1"
+
align-text@^0.1.1, align-text@^0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
@@ -29,6 +54,10 @@ amdefine@>=0.0.4:
version "1.0.1"
resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
+ansi-escapes@^1.1.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
+
ansi-regex@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-0.1.0.tgz#55ca60db6900857c423ae9297980026f941ed903"
@@ -216,15 +245,15 @@ asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
-autoprefixer@6.6.1:
- version "6.6.1"
- resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.6.1.tgz#11a4077abb4b313253ec2f6e1adb91ad84253519"
+autoprefixer@6.7.7:
+ version "6.7.7"
+ resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014"
dependencies:
- browserslist "~1.5.1"
- caniuse-db "^1.0.30000604"
+ browserslist "^1.7.6"
+ caniuse-db "^1.0.30000634"
normalize-range "^0.1.2"
num2fraction "^1.2.2"
- postcss "^5.2.8"
+ postcss "^5.2.16"
postcss-value-parser "^3.2.3"
aws-sdk@2.0.x:
@@ -246,6 +275,14 @@ aws4@^1.2.1:
version "1.5.0"
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.5.0.tgz#0a29ffb79c31c9e712eeb087e8e7a64b4a56d755"
+babel-code-frame@^6.16.0:
+ version "6.22.0"
+ resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4"
+ dependencies:
+ chalk "^1.1.0"
+ esutils "^2.0.2"
+ js-tokens "^3.0.0"
+
backo2@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947"
@@ -319,18 +356,18 @@ bluebird@^3.3.0:
version "3.4.7"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3"
-body-parser@^1.12.4:
- version "1.16.0"
- resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.16.0.tgz#924a5e472c6229fb9d69b85a20d5f2532dec788b"
+body-parser@^1.16.1:
+ version "1.17.1"
+ resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.17.1.tgz#75b3bc98ddd6e7e0d8ffe750dfaca5c66993fa47"
dependencies:
bytes "2.4.0"
content-type "~1.0.2"
- debug "2.6.0"
+ debug "2.6.1"
depd "~1.1.0"
- http-errors "~1.5.1"
+ http-errors "~1.6.1"
iconv-lite "0.4.15"
on-finished "~2.3.0"
- qs "6.2.1"
+ qs "6.4.0"
raw-body "~2.2.0"
type-is "~1.6.14"
@@ -472,11 +509,12 @@ browserify-zlib@^0.1.4:
dependencies:
pako "~0.2.0"
-browserslist@~1.5.1:
- version "1.5.2"
- resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.5.2.tgz#1c82fde0ee8693e6d15c49b7bff209dc06298c56"
+browserslist@^1.7.6:
+ version "1.7.7"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9"
dependencies:
- caniuse-db "^1.0.30000604"
+ caniuse-db "^1.0.30000639"
+ electron-to-chromium "^1.2.7"
buffer-crc32@^0.2.1:
version "0.2.13"
@@ -502,10 +540,20 @@ bytes@2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339"
+caller-path@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f"
+ dependencies:
+ callsites "^0.2.0"
+
callsite@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20"
+callsites@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca"
+
camelcase-keys@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7"
@@ -521,9 +569,9 @@ camelcase@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
-caniuse-db@^1.0.30000604:
- version "1.0.30000613"
- resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000613.tgz#639133b7a5380c1416f9701d23d54d093dd68299"
+caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
+ version "1.0.30000640"
+ resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000640.tgz#7b7fd3cf13c0d9d41f8754b577b202113e2be7ca"
cardinal@0.4.0:
version "0.4.0"
@@ -535,6 +583,10 @@ caseless@~0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7"
+caseless@~0.12.0:
+ version "0.12.0"
+ resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
+
caseless@~0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.6.0.tgz#8167c1ab8397fb5bb95f96d28e5a81c50f247ac4"
@@ -556,7 +608,7 @@ chainsaw@~0.1.0:
dependencies:
traverse ">=0.3.0 <0.4"
-chalk@0.5.0:
+chalk@0.5.0, chalk@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.5.0.tgz#375dfccbc21c0a60a8b61bc5b78f3dc2a55c212f"
dependencies:
@@ -566,7 +618,7 @@ chalk@0.5.0:
strip-ansi "^0.3.0"
supports-color "^0.2.0"
-chalk@^0.5.0, chalk@^0.5.1:
+chalk@^0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174"
dependencies:
@@ -576,7 +628,7 @@ chalk@^0.5.0, chalk@^0.5.1:
strip-ansi "^0.3.0"
supports-color "^0.2.0"
-chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3, chalk@~1.1.1:
+chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3, chalk@~1.1.1:
version "1.1.3"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
dependencies:
@@ -615,6 +667,10 @@ chokidar@^1.4.1:
optionalDependencies:
fsevents "^1.0.0"
+circular-json@^0.3.1:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d"
+
cli-color@~0.3.2:
version "0.3.3"
resolved "https://registry.yarnpkg.com/cli-color/-/cli-color-0.3.3.tgz#12d5bdd158ff8a0b0db401198913c03df069f6f5"
@@ -624,6 +680,16 @@ cli-color@~0.3.2:
memoizee "~0.3.8"
timers-ext "0.1"
+cli-cursor@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987"
+ dependencies:
+ restore-cursor "^1.0.1"
+
+cli-width@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a"
+
cliui@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
@@ -632,6 +698,10 @@ cliui@^2.1.0:
right-align "^0.1.1"
wordwrap "0.0.2"
+co@^4.6.0:
+ version "4.6.0"
+ resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
+
code-point-at@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
@@ -723,7 +793,7 @@ concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
-concat-stream@^1.4.1:
+concat-stream@^1.4.1, concat-stream@^1.5.2:
version "1.6.0"
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7"
dependencies:
@@ -755,7 +825,7 @@ connect-livereload@^0.5.0:
version "0.5.4"
resolved "https://registry.yarnpkg.com/connect-livereload/-/connect-livereload-0.5.4.tgz#80157d1371c9f37cc14039ab1895970d119dc3bc"
-connect@^3.3.5, connect@^3.4.0:
+connect@^3.4.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/connect/-/connect-3.5.0.tgz#b357525a0b4c1f50599cd983e1d9efeea9677198"
dependencies:
@@ -764,6 +834,15 @@ connect@^3.3.5, connect@^3.4.0:
parseurl "~1.3.1"
utils-merge "1.0.0"
+connect@^3.6.0:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/connect/-/connect-3.6.0.tgz#f09a4f7dcd17324b663b725c815bdb1c4158a46e"
+ dependencies:
+ debug "2.6.1"
+ finalhandler "1.0.0"
+ parseurl "~1.3.1"
+ utils-merge "1.0.0"
+
console-control-strings@^1.0.0, console-control-strings@~1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
@@ -821,6 +900,12 @@ custom-event@~1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425"
+d@1:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f"
+ dependencies:
+ es5-ext "^0.10.9"
+
d@^0.1.1, d@~0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309"
@@ -840,7 +925,7 @@ dateformat@^1.0.6, dateformat@~1.0.12:
get-stdin "^4.0.1"
meow "^3.3.0"
-debug@2.2.0, debug@~2.2.0:
+debug@2.2.0, debug@^2.1.1, debug@~2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da"
dependencies:
@@ -852,9 +937,9 @@ debug@2.3.3:
dependencies:
ms "0.7.2"
-debug@2.6.0:
- version "2.6.0"
- resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.0.tgz#bc596bcabe7617f11d9fa15361eded5608b8499b"
+debug@2.6.1:
+ version "2.6.1"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.1.tgz#79855090ba2c4e3115cc7d8769491d58f0491351"
dependencies:
ms "0.7.2"
@@ -886,6 +971,25 @@ deep-is@~0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
+define-properties@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94"
+ dependencies:
+ foreach "^2.0.5"
+ object-keys "^1.0.8"
+
+del@^2.0.2:
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8"
+ dependencies:
+ globby "^5.0.0"
+ is-path-cwd "^1.0.0"
+ is-path-in-cwd "^1.0.0"
+ object-assign "^4.0.1"
+ pify "^2.0.0"
+ pinkie-promise "^2.0.0"
+ rimraf "^2.2.8"
+
delayed-stream@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f"
@@ -898,7 +1002,7 @@ delegates@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
-depd@~1.1.0:
+depd@1.1.0, depd@~1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3"
@@ -914,6 +1018,13 @@ diff@^2.0.2:
version "2.2.3"
resolved "https://registry.yarnpkg.com/diff/-/diff-2.2.3.tgz#60eafd0d28ee906e4e8ff0a52c1229521033bf99"
+doctrine@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.0.tgz#c73d8d2909d22291e1a007a395804da8b665fe63"
+ dependencies:
+ esutils "^2.0.2"
+ isarray "^1.0.0"
+
dom-serialize@^2.2.0:
version "2.2.1"
resolved "https://registry.yarnpkg.com/dom-serialize/-/dom-serialize-2.2.1.tgz#562ae8999f44be5ea3076f5419dcd59eb43ac95b"
@@ -933,6 +1044,10 @@ ee-first@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
+electron-to-chromium@^1.2.7:
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.2.8.tgz#22c2e6200d350da27d6050db7e3f6f85d18cf4ed"
+
encodeurl@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20"
@@ -949,9 +1064,9 @@ end-of-stream@~1.0.0:
dependencies:
once "~1.3.0"
-engine.io-client@1.8.2:
- version "1.8.2"
- resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-1.8.2.tgz#c38767547f2a7d184f5752f6f0ad501006703766"
+engine.io-client@1.8.3:
+ version "1.8.3"
+ resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-1.8.3.tgz#1798ed93451246453d4c6f635d7a201fe940d5ab"
dependencies:
component-emitter "1.2.1"
component-inherit "0.0.3"
@@ -962,7 +1077,7 @@ engine.io-client@1.8.2:
parsejson "0.0.3"
parseqs "0.0.5"
parseuri "0.0.5"
- ws "1.1.1"
+ ws "1.1.2"
xmlhttprequest-ssl "1.5.3"
yeast "0.1.2"
@@ -977,16 +1092,16 @@ engine.io-parser@1.3.2:
has-binary "0.1.7"
wtf-8 "1.0.0"
-engine.io@1.8.2:
- version "1.8.2"
- resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-1.8.2.tgz#6b59be730b348c0125b0a4589de1c355abcf7a7e"
+engine.io@1.8.3:
+ version "1.8.3"
+ resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-1.8.3.tgz#8de7f97895d20d39b85f88eeee777b2bd42b13d4"
dependencies:
accepts "1.3.3"
base64id "1.0.0"
cookie "0.3.1"
debug "2.3.3"
engine.io-parser "1.3.2"
- ws "1.1.1"
+ ws "1.1.2"
ent@~2.2.0:
version "2.2.0"
@@ -1004,6 +1119,13 @@ error-ex@^1.2.0:
dependencies:
is-arrayish "^0.2.1"
+es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14:
+ version "0.10.15"
+ resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.15.tgz#c330a5934c1ee21284a7c081a86e5fd937c91ea6"
+ dependencies:
+ es6-iterator "2"
+ es6-symbol "~3.1"
+
es5-ext@^0.10.7, es5-ext@~0.10.11, es5-ext@~0.10.2, es5-ext@~0.10.5, es5-ext@~0.10.6, es5-ext@~0.10.7:
version "0.10.12"
resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.12.tgz#aa84641d4db76b62abba5e45fd805ecbab140047"
@@ -1019,6 +1141,14 @@ es6-iterator@2:
es5-ext "^0.10.7"
es6-symbol "3"
+es6-iterator@^2.0.1, es6-iterator@~2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.1.tgz#8e319c9f0453bf575d374940a655920e59ca5512"
+ dependencies:
+ d "1"
+ es5-ext "^0.10.14"
+ es6-symbol "^3.1"
+
es6-iterator@~0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-0.1.3.tgz#d6f58b8c4fc413c249b4baa19768f8e4d7c8944e"
@@ -1027,6 +1157,27 @@ es6-iterator@~0.1.3:
es5-ext "~0.10.5"
es6-symbol "~2.0.1"
+es6-map@^0.1.3:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0"
+ dependencies:
+ d "1"
+ es5-ext "~0.10.14"
+ es6-iterator "~2.0.1"
+ es6-set "~0.1.5"
+ es6-symbol "~3.1.1"
+ event-emitter "~0.3.5"
+
+es6-set@~0.1.5:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1"
+ dependencies:
+ d "1"
+ es5-ext "~0.10.14"
+ es6-iterator "~2.0.1"
+ es6-symbol "3.1.1"
+ event-emitter "~0.3.5"
+
es6-symbol@3, es6-symbol@~3.1:
version "3.1.0"
resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.0.tgz#94481c655e7a7cad82eba832d97d5433496d7ffa"
@@ -1034,6 +1185,13 @@ es6-symbol@3, es6-symbol@~3.1:
d "~0.1.1"
es5-ext "~0.10.11"
+es6-symbol@3.1.1, es6-symbol@^3.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77"
+ dependencies:
+ d "1"
+ es5-ext "~0.10.14"
+
es6-symbol@~2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-2.0.1.tgz#761b5c67cfd4f1d18afb234f691d678682cb3bf3"
@@ -1041,6 +1199,15 @@ es6-symbol@~2.0.1:
d "~0.1.1"
es5-ext "~0.10.5"
+es6-weak-map@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f"
+ dependencies:
+ d "1"
+ es5-ext "^0.10.14"
+ es6-iterator "^2.0.1"
+ es6-symbol "^3.1.1"
+
es6-weak-map@~0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-0.1.4.tgz#706cef9e99aa236ba7766c239c8b9e286ea7d228"
@@ -1069,6 +1236,62 @@ escodegen@1.8.x:
optionalDependencies:
source-map "~0.2.0"
+escope@^3.6.0:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3"
+ dependencies:
+ es6-map "^0.1.3"
+ es6-weak-map "^2.0.1"
+ esrecurse "^4.1.0"
+ estraverse "^4.1.1"
+
+eslint@3.18.0:
+ version "3.18.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.18.0.tgz#647e985c4ae71502d20ac62c109f66d5104c8a4b"
+ dependencies:
+ babel-code-frame "^6.16.0"
+ chalk "^1.1.3"
+ concat-stream "^1.5.2"
+ debug "^2.1.1"
+ doctrine "^2.0.0"
+ escope "^3.6.0"
+ espree "^3.4.0"
+ esquery "^1.0.0"
+ estraverse "^4.2.0"
+ esutils "^2.0.2"
+ file-entry-cache "^2.0.0"
+ glob "^7.0.3"
+ globals "^9.14.0"
+ ignore "^3.2.0"
+ imurmurhash "^0.1.4"
+ inquirer "^0.12.0"
+ is-my-json-valid "^2.10.0"
+ is-resolvable "^1.0.0"
+ js-yaml "^3.5.1"
+ json-stable-stringify "^1.0.0"
+ levn "^0.3.0"
+ lodash "^4.0.0"
+ mkdirp "^0.5.0"
+ natural-compare "^1.4.0"
+ optionator "^0.8.2"
+ path-is-inside "^1.0.1"
+ pluralize "^1.2.1"
+ progress "^1.1.8"
+ require-uncached "^1.0.2"
+ shelljs "^0.7.5"
+ strip-bom "^3.0.0"
+ strip-json-comments "~2.0.1"
+ table "^3.7.8"
+ text-table "~0.2.0"
+ user-home "^2.0.0"
+
+espree@^3.4.0:
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/espree/-/espree-3.4.0.tgz#41656fa5628e042878025ef467e78f125cb86e1d"
+ dependencies:
+ acorn "4.0.4"
+ acorn-jsx "^3.0.0"
+
esprima@2.7.x, esprima@^2.6.0, esprima@^2.7.1:
version "2.7.3"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
@@ -1077,10 +1300,31 @@ esprima@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.0.4.tgz#9f557e08fc3b4d26ece9dd34f8fbf476b62585ad"
+esquery@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.0.tgz#cfba8b57d7fba93f17298a8a006a04cda13d80fa"
+ dependencies:
+ estraverse "^4.0.0"
+
+esrecurse@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220"
+ dependencies:
+ estraverse "~4.1.0"
+ object-assign "^4.0.1"
+
estraverse@^1.9.1:
version "1.9.3"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44"
+estraverse@^4.0.0, estraverse@^4.1.1, estraverse@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13"
+
+estraverse@~4.1.0:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2"
+
esutils@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
@@ -1096,6 +1340,13 @@ event-emitter@~0.3.4:
d "~0.1.1"
es5-ext "~0.10.7"
+event-emitter@~0.3.5:
+ version "0.3.5"
+ resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39"
+ dependencies:
+ d "1"
+ es5-ext "~0.10.14"
+
eventemitter2@~0.4.13:
version "0.4.14"
resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-0.4.14.tgz#8f61b75cde012b2e9eb284d4545583b5643b61ab"
@@ -1104,6 +1355,10 @@ eventemitter3@1.x.x:
version "1.2.0"
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508"
+exit-hook@^1.0.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8"
+
exit@~0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c"
@@ -1159,13 +1414,20 @@ faye-websocket@~0.10.0:
dependencies:
websocket-driver ">=0.5.1"
-figures@^1.0.1, figures@^1.3.2:
+figures@^1.0.1, figures@^1.3.2, figures@^1.3.5:
version "1.7.0"
resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e"
dependencies:
escape-string-regexp "^1.0.5"
object-assign "^4.1.0"
+file-entry-cache@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361"
+ dependencies:
+ flat-cache "^1.2.1"
+ object-assign "^4.0.1"
+
file-sync-cmp@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz#a5e7a8ffbfa493b43b923bbd4ca89a53b63b612b"
@@ -1194,6 +1456,18 @@ finalhandler@0.5.0:
statuses "~1.3.0"
unpipe "~1.0.0"
+finalhandler@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.0.tgz#b5691c2c0912092f18ac23e9416bde5cd7dc6755"
+ dependencies:
+ debug "2.6.1"
+ encodeurl "~1.0.1"
+ escape-html "~1.0.3"
+ on-finished "~2.3.0"
+ parseurl "~1.3.1"
+ statuses "~1.3.1"
+ unpipe "~1.0.0"
+
find-up@^1.0.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
@@ -1207,6 +1481,15 @@ findup-sync@~0.3.0:
dependencies:
glob "~5.0.0"
+flat-cache@^1.2.1:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96"
+ dependencies:
+ circular-json "^0.3.1"
+ del "^2.0.2"
+ graceful-fs "^4.1.2"
+ write "^0.2.1"
+
for-in@^0.1.5:
version "0.1.6"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.6.tgz#c9f96e89bfad18a545af5ec3ed352a1d9e5b4dc8"
@@ -1217,6 +1500,10 @@ for-own@^0.1.4:
dependencies:
for-in "^0.1.5"
+foreach@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
+
forever-agent@~0.5.0:
version "0.5.2"
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.5.2.tgz#6d0e09c4921f94a27f63d3b49c5feff1ea4c5130"
@@ -1293,6 +1580,10 @@ fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.10, fstream@~1.0.2:
mkdirp ">=0.5 0"
rimraf "2"
+function-bind@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771"
+
gauge@~2.7.1:
version "2.7.2"
resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.2.tgz#15cecc31b02d05345a5d6b0e171cdb3ad2307774"
@@ -1360,9 +1651,9 @@ glob@^5.0.15, glob@~5.0.0:
once "^1.3.0"
path-is-absolute "^1.0.0"
-glob@^7.0.0, glob@^7.0.5, glob@^7.1.1, glob@~7.1.1:
- version "7.1.1"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
+glob@^7.0.0, glob@^7.0.5, glob@^7.0.6, glob@~7.0.0:
+ version "7.0.6"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.6.tgz#211bafaf49e525b8cd93260d14ab136152b3f57a"
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
@@ -1371,9 +1662,9 @@ glob@^7.0.0, glob@^7.0.5, glob@^7.1.1, glob@~7.1.1:
once "^1.3.0"
path-is-absolute "^1.0.0"
-glob@^7.0.6, glob@~7.0.0:
- version "7.0.6"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.6.tgz#211bafaf49e525b8cd93260d14ab136152b3f57a"
+glob@^7.0.3, glob@^7.1.1, glob@~7.1.1:
+ version "7.1.1"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
@@ -1391,6 +1682,21 @@ glob@~4.0.2:
minimatch "^1.0.0"
once "^1.3.0"
+globals@^9.14.0:
+ version "9.16.0"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-9.16.0.tgz#63e903658171ec2d9f51b1d31de5e2b8dc01fb80"
+
+globby@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d"
+ dependencies:
+ array-union "^1.0.1"
+ arrify "^1.0.0"
+ glob "^7.0.3"
+ object-assign "^4.0.1"
+ pify "^2.0.0"
+ pinkie-promise "^2.0.0"
+
globule@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/globule/-/globule-1.1.0.tgz#c49352e4dc183d85893ee825385eb994bb6df45f"
@@ -1511,23 +1817,23 @@ grunt-contrib-copy@1.0.0:
chalk "^1.1.1"
file-sync-cmp "^0.1.0"
-grunt-contrib-less@1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/grunt-contrib-less/-/grunt-contrib-less-1.4.0.tgz#17ee79cad21c9720ee07b3a991fab5103b513514"
+grunt-contrib-less@1.4.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/grunt-contrib-less/-/grunt-contrib-less-1.4.1.tgz#3bbdec0b75d12ceaa55d62943625c0b0861cdf6f"
dependencies:
async "^2.0.0"
chalk "^1.0.0"
less "~2.7.1"
lodash "^4.8.2"
-grunt-contrib-uglify@2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/grunt-contrib-uglify/-/grunt-contrib-uglify-2.0.0.tgz#8c9970d690936cde6d25aa1193549bd929016930"
+grunt-contrib-uglify@wireapp/grunt-contrib-uglify#2f25cd5df1fe8160168843831b9966ec70e64f9e:
+ version "2.2.0"
+ resolved "https://codeload.github.com/wireapp/grunt-contrib-uglify/tar.gz/2f25cd5df1fe8160168843831b9966ec70e64f9e"
dependencies:
chalk "^1.0.0"
- lodash.assign "^4.0.9"
maxmin "^1.1.0"
- uglify-js "~2.7.0"
+ object.assign "^4.0.4"
+ uglify-js mishoo/UglifyJS2#harmony-v2.8.12
uri-path "^1.0.0"
grunt-contrib-watch@1.0.0:
@@ -1671,6 +1977,10 @@ handlebars@~2.0.0:
optionalDependencies:
uglify-js "~2.3"
+har-schema@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e"
+
har-validator@~2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d"
@@ -1680,6 +1990,13 @@ har-validator@~2.0.6:
is-my-json-valid "^2.12.4"
pinkie-promise "^2.0.0"
+har-validator@~4.2.1:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a"
+ dependencies:
+ ajv "^4.9.1"
+ har-schema "^1.0.5"
+
has-ansi@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-0.1.0.tgz#84f265aae8c0e6a88a12d7022894b7568894c62e"
@@ -1758,7 +2075,7 @@ http-errors@~1.3.1:
inherits "~2.0.1"
statuses "1"
-http-errors@~1.5.0, http-errors@~1.5.1:
+http-errors@~1.5.0:
version "1.5.1"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.5.1.tgz#788c0d2c1de2c81b9e6e8c01843b6b97eb920750"
dependencies:
@@ -1766,6 +2083,15 @@ http-errors@~1.5.0, http-errors@~1.5.1:
setprototypeof "1.0.2"
statuses ">= 1.3.1 < 2"
+http-errors@~1.6.1:
+ version "1.6.1"
+ resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.1.tgz#5f8b8ed98aca545656bf572997387f904a722257"
+ dependencies:
+ depd "1.1.0"
+ inherits "2.0.3"
+ setprototypeof "1.0.3"
+ statuses ">= 1.3.1 < 2"
+
http-proxy@^1.13.0:
version "1.16.2"
resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.16.2.tgz#06dff292952bf64dbe8471fa9df73066d4f37742"
@@ -1801,7 +2127,7 @@ iconv-lite@0.4.15, iconv-lite@~0.4.13:
version "0.4.15"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb"
-ignore@^3.0.9:
+ignore@^3.0.9, ignore@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.0.tgz#8d88f03c3002a0ac52114db25d2c673b0bf1e435"
@@ -1809,6 +2135,10 @@ image-size@~0.5.0:
version "0.5.1"
resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.1.tgz#28eea8548a4b1443480ddddc1e083ae54652439f"
+imurmurhash@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
+
indent-string@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80"
@@ -1851,6 +2181,24 @@ inquirer@0.7.1:
rx "^2.2.27"
through "~2.3.4"
+inquirer@^0.12.0:
+ version "0.12.0"
+ resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e"
+ dependencies:
+ ansi-escapes "^1.1.0"
+ ansi-regex "^2.0.0"
+ chalk "^1.0.0"
+ cli-cursor "^1.0.1"
+ cli-width "^2.0.0"
+ figures "^1.3.5"
+ lodash "^4.3.0"
+ readline2 "^1.0.1"
+ run-async "^0.1.0"
+ rx-lite "^3.1.2"
+ string-width "^1.0.1"
+ strip-ansi "^3.0.0"
+ through "^2.3.6"
+
inquirer@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.6.0.tgz#614d7bb3e48f9e6a8028e94a0c38f23ef29823d3"
@@ -1877,6 +2225,10 @@ insight@0.4.3:
request "^2.40.0"
tough-cookie "^0.12.1"
+interpret@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.1.tgz#d579fb7f693b858004947af39fa0db49f795602c"
+
intersect@~0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/intersect/-/intersect-0.0.3.tgz#c1a4a5e5eac6ede4af7504cc07e0ada7bc9f4920"
@@ -1931,13 +2283,17 @@ is-fullwidth-code-point@^1.0.0:
dependencies:
number-is-nan "^1.0.0"
+is-fullwidth-code-point@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
+
is-glob@^2.0.0, is-glob@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
dependencies:
is-extglob "^1.0.0"
-is-my-json-valid@^2.12.4:
+is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4:
version "2.15.0"
resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz#936edda3ca3c211fd98f3b2d3e08da43f7b2915b"
dependencies:
@@ -1956,6 +2312,22 @@ is-number@^2.0.2, is-number@^2.1.0:
dependencies:
kind-of "^3.0.2"
+is-path-cwd@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d"
+
+is-path-in-cwd@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc"
+ dependencies:
+ is-path-inside "^1.0.0"
+
+is-path-inside@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f"
+ dependencies:
+ path-is-inside "^1.0.1"
+
is-posix-bracket@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
@@ -1968,6 +2340,12 @@ is-property@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84"
+is-resolvable@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62"
+ dependencies:
+ tryit "^1.0.1"
+
is-root@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-root/-/is-root-1.0.0.tgz#07b6c233bc394cd9d02ba15c966bd6660d6342d5"
@@ -1984,7 +2362,7 @@ isarray@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
-isarray@1.0.0, isarray@~1.0.0:
+isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
@@ -2043,7 +2421,11 @@ js-base64@^2.1.9:
version "2.1.9"
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.1.9.tgz#f0e80ae039a4bd654b5f281fc93f04a914a7fcce"
-js-yaml@3.x, js-yaml@^3.1.0, js-yaml@~3.5.2:
+js-tokens@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7"
+
+js-yaml@3.x, js-yaml@^3.1.0, js-yaml@^3.5.1, js-yaml@~3.5.2:
version "3.5.5"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.5.5.tgz#0377c38017cabc7322b0d1fbcd25a491641f2fbe"
dependencies:
@@ -2058,6 +2440,12 @@ json-schema@0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
+json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af"
+ dependencies:
+ jsonify "~0.0.0"
+
json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
@@ -2107,16 +2495,16 @@ karma-jasmine@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/karma-jasmine/-/karma-jasmine-1.1.0.tgz#22e4c06bf9a182e5294d1f705e3733811b810acf"
-karma@1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/karma/-/karma-1.4.0.tgz#bf5edbccabb8579cb68ae699871f3e79608ec94b"
+karma@1.5.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/karma/-/karma-1.5.0.tgz#9c4c14f0400bef2c04c8e8e6bff59371025cc009"
dependencies:
bluebird "^3.3.0"
- body-parser "^1.12.4"
+ body-parser "^1.16.1"
chokidar "^1.4.1"
colors "^1.1.0"
combine-lists "^1.0.0"
- connect "^3.3.5"
+ connect "^3.6.0"
core-js "^2.2.0"
di "^0.0.1"
dom-serialize "^2.2.0"
@@ -2132,12 +2520,12 @@ karma@1.4.0:
optimist "^0.6.1"
qjobs "^1.1.4"
range-parser "^1.2.0"
- rimraf "^2.3.3"
+ rimraf "^2.6.0"
safe-buffer "^5.0.1"
- socket.io "1.7.2"
+ socket.io "1.7.3"
source-map "^0.5.3"
- tmp "0.0.28"
- useragent "^2.1.10"
+ tmp "0.0.31"
+ useragent "^2.1.12"
kind-of@^3.0.2:
version "3.1.0"
@@ -2174,7 +2562,7 @@ less@~2.7.1:
request "^2.72.0"
source-map "^0.5.3"
-levn@~0.3.0:
+levn@^0.3.0, levn@~0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
dependencies:
@@ -2216,10 +2604,6 @@ lodash._objecttypes@~2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/lodash._objecttypes/-/lodash._objecttypes-2.4.1.tgz#7c0b7f69d98a1f76529f890b0cdb1b4dfec11c11"
-lodash.assign@^4.0.9:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7"
-
lodash.debounce@^2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-2.4.1.tgz#d8cead246ec4b926e8b85678fc396bfeba8cc6fc"
@@ -2252,7 +2636,7 @@ lodash@^3.10.1, lodash@^3.8.0, lodash@~3.10.1:
version "3.10.1"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
-lodash@^4.14.0, lodash@^4.5.0, lodash@^4.7.0, lodash@^4.8.0, lodash@^4.8.2:
+lodash@^4.0.0, lodash@^4.14.0, lodash@^4.3.0, lodash@^4.5.0, lodash@^4.7.0, lodash@^4.8.0, lodash@^4.8.2:
version "4.17.4"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
@@ -2433,16 +2817,16 @@ mkdirp@0.5.0, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0:
dependencies:
minimist "0.0.8"
-mkdirp@~0.3.5:
- version "0.3.5"
- resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.5.tgz#de3e5f8961c88c787ee1368df849ac4413eca8d7"
-
-mkdirp@~0.5.1:
+mkdirp@^0.5.1, mkdirp@~0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
dependencies:
minimist "0.0.8"
+mkdirp@~0.3.5:
+ version "0.3.5"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.5.tgz#de3e5f8961c88c787ee1368df849ac4413eca8d7"
+
mkpath@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/mkpath/-/mkpath-0.1.0.tgz#7554a6f8d871834cc97b5462b122c4c124d6de91"
@@ -2482,6 +2866,10 @@ mute-stream@0.0.4, mute-stream@~0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.4.tgz#a9219960a6d5d5d046597aee51252c6655f7177e"
+mute-stream@0.0.5:
+ version "0.0.5"
+ resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0"
+
nan@^2.3.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.5.0.tgz#aa8f1e34531d807e9e27755b234b4a6ec0c152a8"
@@ -2490,6 +2878,10 @@ natives@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.0.tgz#e9ff841418a6b2ec7a495e939984f78f163e6e31"
+natural-compare@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
+
negotiator@0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
@@ -2628,6 +3020,18 @@ object-component@0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291"
+object-keys@^1.0.10, object-keys@^1.0.8:
+ version "1.0.11"
+ resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d"
+
+object.assign@^4.0.4:
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.0.4.tgz#b1c9cc044ef1b9fe63606fc141abbb32e14730cc"
+ dependencies:
+ define-properties "^1.1.2"
+ function-bind "^1.1.0"
+ object-keys "^1.0.10"
+
object.omit@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
@@ -2661,6 +3065,10 @@ once@~1.3.0, once@~1.3.3:
dependencies:
wrappy "1"
+onetime@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789"
+
open@~0.0.4:
version "0.0.5"
resolved "https://registry.yarnpkg.com/open/-/open-0.0.5.tgz#42c3e18ec95466b6bf0dc42f3a2945c3f0cad8fc"
@@ -2689,7 +3097,7 @@ optimist@~0.3, optimist@~0.3.5:
dependencies:
wordwrap "~0.0.2"
-optionator@^0.8.1:
+optionator@^0.8.1, optionator@^0.8.2:
version "0.8.2"
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64"
dependencies:
@@ -2704,6 +3112,10 @@ options@>=0.0.5:
version "0.0.6"
resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f"
+os-homedir@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
+
os-name@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/os-name/-/os-name-1.0.3.tgz#1b379f64835af7c5a7f498b357cb95215c159edf"
@@ -2793,6 +3205,10 @@ path-is-absolute@^1.0.0, path-is-absolute@~1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+path-is-inside@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
+
path-key@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
@@ -2805,6 +3221,10 @@ path-type@^1.0.0:
pify "^2.0.0"
pinkie-promise "^2.0.0"
+performance-now@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
+
pify@^2.0.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
@@ -2825,6 +3245,10 @@ pkg-up@^1.0.0:
dependencies:
find-up "^1.0.0"
+pluralize@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45"
+
portscanner@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/portscanner/-/portscanner-1.2.0.tgz#b14bbda257d14c310fa9cc09682af02d40961802"
@@ -2835,7 +3259,7 @@ postcss-value-parser@^3.2.3:
version "3.3.0"
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15"
-postcss@^5.0.0, postcss@^5.2.8:
+postcss@^5.0.0:
version "5.2.10"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.10.tgz#b58b64e04f66f838b7bc7cb41f7dac168568a945"
dependencies:
@@ -2844,6 +3268,15 @@ postcss@^5.0.0, postcss@^5.2.8:
source-map "^0.5.6"
supports-color "^3.1.2"
+postcss@^5.2.16:
+ version "5.2.16"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.16.tgz#732b3100000f9ff8379a48a53839ed097376ad57"
+ dependencies:
+ chalk "^1.1.3"
+ js-base64 "^2.1.9"
+ source-map "^0.5.6"
+ supports-color "^3.2.3"
+
prelude-ls@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
@@ -2869,7 +3302,7 @@ process-nextick-args@~1.0.6:
version "1.0.7"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
-progress@1.1.x:
+progress@1.1.x, progress@^1.1.8:
version "1.1.8"
resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be"
@@ -2920,9 +3353,9 @@ qs@5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-5.2.0.tgz#a9f31142af468cb72b25b30136ba2456834916be"
-qs@6.2.1:
- version "6.2.1"
- resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.1.tgz#ce03c5ff0935bc1d9d69a9f14cbd18e568d67625"
+qs@6.4.0, qs@~6.4.0:
+ version "6.4.0"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
qs@~1.2.0:
version "1.2.2"
@@ -3048,6 +3481,14 @@ readdirp@^2.0.0:
readable-stream "^2.0.2"
set-immediate-shim "^1.0.1"
+readline2@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35"
+ dependencies:
+ code-point-at "^1.0.0"
+ is-fullwidth-code-point "^1.0.0"
+ mute-stream "0.0.5"
+
readline2@~0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/readline2/-/readline2-0.1.1.tgz#99443ba6e83b830ef3051bfd7dc241a82728d568"
@@ -3055,6 +3496,12 @@ readline2@~0.1.0:
mute-stream "0.0.4"
strip-ansi "^2.0.1"
+rechoir@^0.6.2:
+ version "0.6.2"
+ resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
+ dependencies:
+ resolve "^1.1.6"
+
redent@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde"
@@ -3111,7 +3558,55 @@ request-replay@~0.2.0:
dependencies:
retry "~0.6.0"
-request@2.79.0, request@^2.40.0, request@^2.72.0, request@^2.79.0:
+request@2.81.0, request@^2.79.0:
+ version "2.81.0"
+ resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
+ dependencies:
+ aws-sign2 "~0.6.0"
+ aws4 "^1.2.1"
+ caseless "~0.12.0"
+ combined-stream "~1.0.5"
+ extend "~3.0.0"
+ forever-agent "~0.6.1"
+ form-data "~2.1.1"
+ har-validator "~4.2.1"
+ hawk "~3.1.3"
+ http-signature "~1.1.0"
+ is-typedarray "~1.0.0"
+ isstream "~0.1.2"
+ json-stringify-safe "~5.0.1"
+ mime-types "~2.1.7"
+ oauth-sign "~0.8.1"
+ performance-now "^0.2.0"
+ qs "~6.4.0"
+ safe-buffer "^5.0.1"
+ stringstream "~0.0.4"
+ tough-cookie "~2.3.0"
+ tunnel-agent "^0.6.0"
+ uuid "^3.0.0"
+
+request@^2.40.0, request@~2.51.0:
+ version "2.51.0"
+ resolved "https://registry.yarnpkg.com/request/-/request-2.51.0.tgz#35d00bbecc012e55f907b1bd9e0dbd577bfef26e"
+ dependencies:
+ aws-sign2 "~0.5.0"
+ bl "~0.9.0"
+ caseless "~0.8.0"
+ combined-stream "~0.0.5"
+ forever-agent "~0.5.0"
+ form-data "~0.2.0"
+ hawk "1.1.1"
+ http-signature "~0.10.0"
+ json-stringify-safe "~5.0.0"
+ mime-types "~1.0.1"
+ node-uuid "~1.4.0"
+ oauth-sign "~0.5.0"
+ qs "~2.3.1"
+ stringstream "~0.0.4"
+ tough-cookie ">=0.12.0"
+ tunnel-agent "~0.4.0"
+
+request@^2.72.0:
version "2.79.0"
resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de"
dependencies:
@@ -3157,31 +3652,21 @@ request@~2.42.0:
stringstream "~0.0.4"
tough-cookie ">=0.12.0"
-request@~2.51.0:
- version "2.51.0"
- resolved "https://registry.yarnpkg.com/request/-/request-2.51.0.tgz#35d00bbecc012e55f907b1bd9e0dbd577bfef26e"
+require-uncached@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3"
dependencies:
- aws-sign2 "~0.5.0"
- bl "~0.9.0"
- caseless "~0.8.0"
- combined-stream "~0.0.5"
- forever-agent "~0.5.0"
- form-data "~0.2.0"
- hawk "1.1.1"
- http-signature "~0.10.0"
- json-stringify-safe "~5.0.0"
- mime-types "~1.0.1"
- node-uuid "~1.4.0"
- oauth-sign "~0.5.0"
- qs "~2.3.1"
- stringstream "~0.0.4"
- tough-cookie ">=0.12.0"
- tunnel-agent "~0.4.0"
+ caller-path "^0.1.0"
+ resolve-from "^1.0.0"
requires-port@1.x.x:
version "1.0.0"
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
+resolve-from@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226"
+
resolve-from@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57"
@@ -3192,7 +3677,7 @@ resolve-pkg@^0.1.0:
dependencies:
resolve-from "^2.0.0"
-resolve@1.1.x, resolve@~1.1.0:
+resolve@1.1.x, resolve@^1.1.6, resolve@~1.1.0:
version "1.1.7"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
@@ -3200,6 +3685,13 @@ resolve@^0.6.3:
version "0.6.3"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-0.6.3.tgz#dd957982e7e736debdf53b58a4dd91754575dd46"
+restore-cursor@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541"
+ dependencies:
+ exit-hook "^1.0.0"
+ onetime "^1.0.0"
+
retry@0.6.0, retry@~0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/retry/-/retry-0.6.0.tgz#1c010713279a6fd1e8def28af0c3ff1871caa537"
@@ -3210,12 +3702,18 @@ right-align@^0.1.1:
dependencies:
align-text "^0.1.1"
-rimraf@2, rimraf@^2.3.3, rimraf@^2.5.1, rimraf@^2.5.2, rimraf@~2.5.1, rimraf@~2.5.4:
+rimraf@2, rimraf@^2.5.1, rimraf@^2.5.2, rimraf@~2.5.1, rimraf@~2.5.4:
version "2.5.4"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04"
dependencies:
glob "^7.0.5"
+rimraf@^2.2.8, rimraf@^2.6.0:
+ version "2.6.1"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d"
+ dependencies:
+ glob "^7.0.5"
+
rimraf@~2.0.2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.0.3.tgz#f50a2965e7144e9afd998982f15df706730f56a9"
@@ -3226,6 +3724,16 @@ rimraf@~2.2.0, rimraf@~2.2.8:
version "2.2.8"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582"
+run-async@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389"
+ dependencies:
+ once "^1.3.0"
+
+rx-lite@^3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102"
+
rx@^2.2.27:
version "2.5.3"
resolved "https://registry.yarnpkg.com/rx/-/rx-2.5.3.tgz#21adc7d80f02002af50dae97fd9dbf248755f566"
@@ -3248,11 +3756,7 @@ semver-diff@^0.1.0:
dependencies:
semver "^2.2.1"
-"semver@2 || 3 || 4", "semver@2 || 3 || 4 || 5", semver@~4.3.3:
- version "4.3.6"
- resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da"
-
-semver@^2.2.1, semver@~2.3.0:
+"semver@2 || 3 || 4", "semver@2 || 3 || 4 || 5", semver@^2.2.1, semver@~2.3.0:
version "2.3.2"
resolved "https://registry.yarnpkg.com/semver/-/semver-2.3.2.tgz#b9848f25d6cf36333073ec9ef8856d42f1233e52"
@@ -3260,6 +3764,10 @@ semver@^5.0.1, semver@~5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
+semver@~4.3.3:
+ version "4.3.6"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da"
+
send@0.14.1:
version "0.14.1"
resolved "https://registry.yarnpkg.com/send/-/send-0.14.1.tgz#a954984325392f51532a7760760e459598c89f7a"
@@ -3311,6 +3819,10 @@ setprototypeof@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.2.tgz#81a552141ec104b88e89ce383103ad5c66564d08"
+setprototypeof@1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04"
+
shell-quote@~1.4.1:
version "1.4.3"
resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.4.3.tgz#952c44e0b1ed9013ef53958179cc643e8777466b"
@@ -3320,6 +3832,14 @@ shell-quote@~1.4.1:
array-reduce "~0.0.0"
jsonify "~0.0.0"
+shelljs@^0.7.5:
+ version "0.7.7"
+ resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.7.tgz#b2f5c77ef97148f4b4f6e22682e10bba8667cff1"
+ dependencies:
+ glob "^7.0.0"
+ interpret "^1.0.0"
+ rechoir "^0.6.2"
+
sigmund@~1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590"
@@ -3337,6 +3857,10 @@ sinon@1.17.7:
samsam "1.1.2"
util ">=0.10.3 <1"
+slice-ansi@0.0.4:
+ version "0.0.4"
+ resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"
+
sntp@0.2.x:
version "0.2.4"
resolved "https://registry.yarnpkg.com/sntp/-/sntp-0.2.4.tgz#fb885f18b0f3aad189f824862536bceeec750900"
@@ -3356,15 +3880,15 @@ socket.io-adapter@0.5.0:
debug "2.3.3"
socket.io-parser "2.3.1"
-socket.io-client@1.7.2:
- version "1.7.2"
- resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-1.7.2.tgz#39fdb0c3dd450e321b7e40cfd83612ec533dd644"
+socket.io-client@1.7.3:
+ version "1.7.3"
+ resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-1.7.3.tgz#b30e86aa10d5ef3546601c09cde4765e381da377"
dependencies:
backo2 "1.0.2"
component-bind "1.0.0"
component-emitter "1.2.1"
debug "2.3.3"
- engine.io-client "1.8.2"
+ engine.io-client "1.8.3"
has-binary "0.1.7"
indexof "0.0.1"
object-component "0.0.3"
@@ -3381,16 +3905,16 @@ socket.io-parser@2.3.1:
isarray "0.0.1"
json3 "3.3.2"
-socket.io@1.7.2:
- version "1.7.2"
- resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-1.7.2.tgz#83bbbdf2e79263b378900da403e7843e05dc3b71"
+socket.io@1.7.3:
+ version "1.7.3"
+ resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-1.7.3.tgz#b8af9caba00949e568e369f1327ea9be9ea2461b"
dependencies:
debug "2.3.3"
- engine.io "1.8.2"
+ engine.io "1.8.3"
has-binary "0.1.7"
object-assign "4.1.0"
socket.io-adapter "0.5.0"
- socket.io-client "1.7.2"
+ socket.io-client "1.7.3"
socket.io-parser "2.3.1"
source-map@^0.4.4:
@@ -3448,7 +3972,7 @@ sshpk@^1.7.0:
jsbn "~0.1.0"
tweetnacl "~0.14.0"
-statuses@1, "statuses@>= 1.3.1 < 2", statuses@~1.3.0:
+statuses@1, "statuses@>= 1.3.1 < 2", statuses@~1.3.0, statuses@~1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e"
@@ -3470,6 +3994,13 @@ string-width@^1.0.1:
is-fullwidth-code-point "^1.0.0"
strip-ansi "^3.0.0"
+string-width@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e"
+ dependencies:
+ is-fullwidth-code-point "^2.0.0"
+ strip-ansi "^3.0.0"
+
string_decoder@~0.10.x:
version "0.10.31"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
@@ -3512,6 +4043,10 @@ strip-bom@^2.0.0:
dependencies:
is-utf8 "^0.2.0"
+strip-bom@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
+
strip-indent@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2"
@@ -3522,6 +4057,10 @@ strip-json-comments@^1.0.2, strip-json-comments@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91"
+strip-json-comments@~2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+
supports-color@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a"
@@ -3534,12 +4073,23 @@ supports-color@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
-supports-color@^3.1.0, supports-color@^3.1.2:
+supports-color@^3.1.0, supports-color@^3.1.2, supports-color@^3.2.3:
version "3.2.3"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
dependencies:
has-flag "^1.0.0"
+table@^3.7.8:
+ version "3.8.3"
+ resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f"
+ dependencies:
+ ajv "^4.7.0"
+ ajv-keywords "^1.0.0"
+ chalk "^1.1.1"
+ lodash "^4.0.0"
+ slice-ansi "0.0.4"
+ string-width "^2.0.0"
+
tar-fs@0.5.2:
version "0.5.2"
resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-0.5.2.tgz#0f59424be7eeee45232316e302f66d3f6ea6db3e"
@@ -3587,7 +4137,7 @@ tar@~2.2.1:
fstream "^1.0.2"
inherits "2"
-text-table@^0.2.0:
+text-table@^0.2.0, text-table@~0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
@@ -3595,7 +4145,7 @@ throttleit@~0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-0.0.2.tgz#cfedf88e60c00dd9697b61fdd2a8343a9b680eaf"
-through@~2.3.4:
+through@^2.3.6, through@~2.3.4:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
@@ -3621,9 +4171,9 @@ tmp@0.0.23:
version "0.0.23"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.23.tgz#de874aa5e974a85f0a32cdfdbd74663cb3bd9c74"
-tmp@0.0.28:
- version "0.0.28"
- resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120"
+tmp@0.0.31, tmp@0.0.x:
+ version "0.0.31"
+ resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7"
dependencies:
os-tmpdir "~1.0.1"
@@ -3637,18 +4187,18 @@ touch@0.0.2:
dependencies:
nopt "~1.0.10"
-tough-cookie@>=0.12.0, tough-cookie@~2.3.0:
- version "2.3.2"
- resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a"
- dependencies:
- punycode "^1.4.1"
-
-tough-cookie@^0.12.1:
+tough-cookie@>=0.12.0, tough-cookie@^0.12.1:
version "0.12.1"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-0.12.1.tgz#8220c7e21abd5b13d96804254bd5a81ebf2c7d62"
dependencies:
punycode ">=0.2.0"
+tough-cookie@~2.3.0:
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a"
+ dependencies:
+ punycode "^1.4.1"
+
"traverse@>=0.3.0 <0.4":
version "0.3.9"
resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9"
@@ -3657,6 +4207,16 @@ trim-newlines@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"
+tryit@^1.0.1:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb"
+
+tunnel-agent@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
+ dependencies:
+ safe-buffer "^5.0.1"
+
tunnel-agent@~0.4.0, tunnel-agent@~0.4.1:
version "0.4.3"
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb"
@@ -3682,7 +4242,7 @@ typedarray@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
-uglify-js@^2.6, uglify-js@~2.7.0:
+uglify-js@^2.6:
version "2.7.5"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.7.5.tgz#4612c0c7baaee2ba7c487de4904ae122079f2ca8"
dependencies:
@@ -3691,6 +4251,14 @@ uglify-js@^2.6, uglify-js@~2.7.0:
uglify-to-browserify "~1.0.0"
yargs "~3.10.0"
+uglify-js@mishoo/UglifyJS2#harmony-v2.8.12:
+ version "2.8.12"
+ resolved "https://codeload.github.com/mishoo/UglifyJS2/tar.gz/2fd86d3cb02c2bcde81633c0096b308e2809ea00"
+ dependencies:
+ source-map "~0.5.1"
+ uglify-to-browserify "~1.0.0"
+ yargs "~3.10.0"
+
uglify-js@~2.3:
version "2.3.6"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.3.6.tgz#fa0984770b428b7a9b2a8058f46355d14fef211a"
@@ -3741,11 +4309,18 @@ user-home@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190"
-useragent@^2.1.10:
- version "2.1.11"
- resolved "https://registry.yarnpkg.com/useragent/-/useragent-2.1.11.tgz#6a026e6a6c619b46ca7a0b2fdef6c1ac3da8ca29"
+user-home@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f"
+ dependencies:
+ os-homedir "^1.0.0"
+
+useragent@^2.1.12:
+ version "2.1.12"
+ resolved "https://registry.yarnpkg.com/useragent/-/useragent-2.1.12.tgz#aa7da6cdc48bdc37ba86790871a7321d64edbaa2"
dependencies:
lru-cache "2.2.x"
+ tmp "0.0.x"
util-deprecate@~1.0.1:
version "1.0.2"
@@ -3846,9 +4421,15 @@ wrench@~1.4.3:
version "1.4.4"
resolved "https://registry.yarnpkg.com/wrench/-/wrench-1.4.4.tgz#7f523efdb71b0100e77dce834c06523cbe3d54e0"
-ws@1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.1.tgz#082ddb6c641e85d4bb451f03d52f06eabdb1f018"
+write@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757"
+ dependencies:
+ mkdirp "^0.5.1"
+
+ws@1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.2.tgz#8a244fa052401e08c9886cf44a85189e1fd4067f"
dependencies:
options ">=0.0.5"
ultron "1.0.x"