X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=nixops%2Fmodules%2Fwebsites%2Ftools%2Fpeertube%2Fldap.patch;h=7ad5cc573a90f24adafec631e34355c64bce98d5;hb=0eaac6ba283159841da70fdfd74cb0ef7c6203ab;hpb=20ed2f853c57af063d27651bfd28c28ac8849414;p=perso%2FImmae%2FConfig%2FNix.git diff --git a/nixops/modules/websites/tools/peertube/ldap.patch b/nixops/modules/websites/tools/peertube/ldap.patch new file mode 100644 index 0000000..7ad5cc5 --- /dev/null +++ b/nixops/modules/websites/tools/peertube/ldap.patch @@ -0,0 +1,542 @@ +commit 45a9e4a7b1badbea15d74bd8b3990303a424dfa6 +Author: Ismaël Bouya +Date: Tue Feb 12 18:47:53 2019 +0100 + + Add LDAP authentication + +diff --git a/config/default.yaml b/config/default.yaml +index e16b8c35..eac0dd3f 100644 +--- a/config/default.yaml ++++ b/config/default.yaml +@@ -33,6 +33,9 @@ redis: + auth: null + db: 0 + ++ldap: ++ enable: false ++ + smtp: + hostname: null + port: 465 +diff --git a/config/production.yaml.example b/config/production.yaml.example +index 661eac0d..bb5ac251 100644 +--- a/config/production.yaml.example ++++ b/config/production.yaml.example +@@ -33,6 +33,17 @@ redis: + auth: null + db: 0 + ++ldap: ++ enable: true ++ # Disallow non-ldap users (it also disables root!) ++ ldap_only: true ++ url: ldap://localhost:389/dc=example,dc=com ++ bind_dn: cn=admin,dc=example,dc=com ++ bind_password: adminPass ++ base: dc=example,dc=com ++ mail_entry: "mail" ++ user_filter: "(|(email=%username%)(uid=%username%))" ++ + # SMTP server to send emails + smtp: + hostname: null +diff --git a/package.json b/package.json +index 0cf39c7e..fd1ce3ea 100644 +--- a/package.json ++++ b/package.json +@@ -125,6 +125,7 @@ + "js-yaml": "^3.5.4", + "jsonld": "^1.0.1", + "jsonld-signatures": "https://github.com/Chocobozzz/jsonld-signatures#rsa2017", ++ "ldapjs": "^1.0.2", + "lodash": "^4.17.10", + "magnet-uri": "^5.1.4", + "memoizee": "^0.4.14", +diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts +index 6f3ebb9a..fb21df37 100644 +--- a/server/initializers/constants.ts ++++ b/server/initializers/constants.ts +@@ -16,7 +16,7 @@ let config: IConfig = require('config') + + // --------------------------------------------------------------------------- + +-const LAST_MIGRATION_VERSION = 325 ++const LAST_MIGRATION_VERSION = 326 + + // --------------------------------------------------------------------------- + +@@ -177,6 +177,16 @@ const CONFIG = { + AUTH: config.has('redis.auth') ? config.get('redis.auth') : null, + DB: config.has('redis.db') ? config.get('redis.db') : null + }, ++ LDAP: { ++ ENABLE: config.has('ldap.enable') ? config.get('ldap.enable') : false, ++ LDAP_ONLY: config.has('ldap.ldap_only') ? config.get('ldap.ldap_only') : false, ++ URL: config.has('ldap.url') ? config.get('ldap.url') : null, ++ BIND_DN: config.has('ldap.bind_dn') ? config.get('ldap.bind_dn') : null, ++ BIND_PASSWORD: config.has('ldap.bind_password') ? config.get('ldap.bind_password') : null, ++ BASE: config.has('ldap.base') ? config.get('ldap.base') : null, ++ MAIL_ENTRY: config.has('ldap.mail_entry') ? config.get('ldap.mail_entry') : 'mail', ++ USER_FILTER: config.has('ldap.user_filter') ? config.get('ldap.user_filter') : '(|(email=%username%)(uid=%username%))' ++ }, + SMTP: { + HOSTNAME: config.get('smtp.hostname'), + PORT: config.get('smtp.port'), +diff --git a/server/initializers/migrations/0326-user-ldap-dn.ts b/server/initializers/migrations/0326-user-ldap-dn.ts +new file mode 100644 +index 00000000..a9d68124 +--- /dev/null ++++ b/server/initializers/migrations/0326-user-ldap-dn.ts +@@ -0,0 +1,26 @@ ++import * as Sequelize from 'sequelize' ++ ++async function up (utils: { ++ transaction: Sequelize.Transaction, ++ queryInterface: Sequelize.QueryInterface, ++ sequelize: Sequelize.Sequelize ++}): Promise { ++ ++ { ++ const data = { ++ type: Sequelize.STRING, ++ allowNull: true, ++ defaultValue: null ++ } ++ await utils.queryInterface.addColumn('user', 'ldapDn', data) ++ } ++} ++ ++function down (options) { ++ throw new Error('Not implemented.') ++} ++ ++export { ++ up, ++ down ++} +diff --git a/server/lib/oauth-model.ts b/server/lib/oauth-model.ts +index 2cd2ae97..3f14b216 100644 +--- a/server/lib/oauth-model.ts ++++ b/server/lib/oauth-model.ts +@@ -66,7 +66,13 @@ function getRefreshToken (refreshToken: string) { + async function getUser (usernameOrEmail: string, password: string) { + logger.debug('Getting User (username/email: ' + usernameOrEmail + ', password: ******).') + +- const user = await UserModel.loadByUsernameOrEmail(usernameOrEmail) ++ let user ++ if (CONFIG.LDAP.ENABLE) { ++ user = await UserModel.findOrCreateLDAPUser(usernameOrEmail) ++ } ++ if (!user && (!CONFIG.LDAP.ENABLE || !CONFIG.LDAP.LDAP_ONLY)) { ++ user = await UserModel.loadByUsernameOrEmail(usernameOrEmail) ++ } + if (!user) return null + + const passwordMatch = await user.isPasswordMatch(password) +diff --git a/server/models/account/user.ts b/server/models/account/user.ts +index 017a9665..a4d0145c 100644 +--- a/server/models/account/user.ts ++++ b/server/models/account/user.ts +@@ -1,3 +1,4 @@ ++import * as ldap from 'ldapjs' + import * as Sequelize from 'sequelize' + import { + AfterDestroy, +@@ -42,8 +43,9 @@ import { VideoChannelModel } from '../video/video-channel' + import { AccountModel } from './account' + import { NSFWPolicyType } from '../../../shared/models/videos/nsfw-policy.type' + import { values } from 'lodash' +-import { NSFW_POLICY_TYPES } from '../../initializers' ++import { CONFIG, NSFW_POLICY_TYPES } from '../../initializers' + import { clearCacheByUserId } from '../../lib/oauth-model' ++import { createUserAccountAndChannel } from '../../lib/user' + import { UserNotificationSettingModel } from './user-notification-setting' + import { VideoModel } from '../video/video' + import { ActorModel } from '../activitypub/actor' +@@ -111,6 +113,11 @@ export class UserModel extends Model { + @Column(DataType.STRING(400)) + email: string + ++ @AllowNull(true) ++ @Default(null) ++ @Column ++ ldapDn: string ++ + @AllowNull(true) + @Default(null) + @Is('UserEmailVerified', value => throwIfNotValid(value, isUserEmailVerifiedValid, 'email verified boolean')) +@@ -354,6 +361,90 @@ export class UserModel extends Model { + return UserModel.findOne(query) + } + ++ static loadByLdapDn (ldapDn: string) { ++ const query = { ++ where: { ++ ldapDn ++ } ++ } ++ ++ return UserModel.findOne(query) ++ } ++ ++ static findOrCreateLDAPUser (username: string) { ++ let userInfos ++ ++ return Promise.resolve(UserModel.findLDAPUser(username)) ++ .then((_userInfos) => { ++ userInfos = _userInfos ++ return UserModel.loadByLdapDn(userInfos['dn']) ++ }) ++ .then((user) => { ++ if (user) { ++ return user ++ } else { ++ return UserModel.createLDAPUser(username, userInfos) ++ } ++ }) ++ .catch(() => { return null }) ++ } ++ ++ static findLDAPUser (username: string) { ++ const client = ldap.createClient({ ++ url: CONFIG.LDAP.URL ++ }) ++ const filter = ldap.parseFilter(CONFIG.LDAP.USER_FILTER) ++ filter.forEach(function (element) { ++ if (element.value === '%username%') element.value = username ++ }) ++ const opts = { ++ filter, ++ scope: 'sub', ++ attributes: [ CONFIG.LDAP.MAIL_ENTRY, 'dn' ] ++ } ++ ++ return new Promise(function (resolve, reject) { ++ client.bind(CONFIG.LDAP.BIND_DN, CONFIG.LDAP.BIND_PASSWORD, function (err) { ++ if (err) reject() ++ let entries = [] ++ client.search(CONFIG.LDAP.BASE, opts, function (err, search) { ++ if (err) reject() ++ search.on('searchEntry', function (entry) { ++ entries.push(entry.object) ++ }) ++ search.on('end', function (result) { ++ if (entries.length === 1) { ++ resolve(entries[0]) ++ } else { ++ reject() ++ } ++ }) ++ }) ++ }) ++ }) ++ } ++ ++ static createLDAPUser (username: string, userInfos: {}) { ++ return Promise.resolve(userInfos) ++ .then((userInfos) => { ++ const userToCreate = new UserModel({ ++ username: username, ++ password: 'SomeInvalidPassword', ++ email: userInfos[CONFIG.LDAP.MAIL_ENTRY], ++ ldapDn: userInfos['dn'], ++ nsfwPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY, ++ autoPlayVideo: true, ++ role: UserRole.USER, ++ videoQuota: CONFIG.USER.VIDEO_QUOTA, ++ videoQuotaDaily: CONFIG.USER.VIDEO_QUOTA_DAILY, ++ emailVerified: true ++ }) ++ ++ return createUserAccountAndChannel(userToCreate) ++ }) ++ .then(({ user }) => { return user }) ++ } ++ + static loadByUsernameAndPopulateChannels (username: string) { + const query = { + where: { +@@ -516,8 +607,22 @@ export class UserModel extends Model { + return hasUserRight(this.role, right) + } + ++ static checkLDAPUser (dn: string, password: string) { ++ const client = ldap.createClient({ url: CONFIG.LDAP.URL }) ++ ++ return new Promise(function (resolve, reject) { ++ client.bind(dn, password, function (err) { ++ resolve(!err) ++ }) ++ }) ++ } ++ + isPasswordMatch (password: string) { +- return comparePassword(password, this.password) ++ if (this.ldapDn === null) { ++ return comparePassword(password, this.password) ++ } else { ++ return UserModel.checkLDAPUser(this.ldapDn, password) ++ } + } + + toFormattedJSON (): User { +diff --git a/yarn.lock b/yarn.lock +index 1e759af1..1eb61a9f 100644 +--- a/yarn.lock ++++ b/yarn.lock +@@ -674,6 +674,11 @@ asap@^2.0.0: + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= + ++asn1@0.2.3: ++ version "0.2.3" ++ resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" ++ integrity sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y= ++ + asn1@~0.2.3: + version "0.2.4" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" +@@ -681,6 +686,11 @@ asn1@~0.2.3: + dependencies: + safer-buffer "~2.1.0" + ++assert-plus@0.1.5: ++ version "0.1.5" ++ resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" ++ integrity sha1-7nQAlBMALYTOxyGcasgRgS5yMWA= ++ + assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" +@@ -779,6 +789,13 @@ backo2@1.0.2: + resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + integrity sha1-MasayLEpNjRj41s+u2n038+6eUc= + ++backoff@^2.5.0: ++ version "2.5.0" ++ resolved "https://registry.yarnpkg.com/backoff/-/backoff-2.5.0.tgz#f616eda9d3e4b66b8ca7fca79f695722c5f8e26f" ++ integrity sha1-9hbtqdPktmuMp/ynn2lXIsX44m8= ++ dependencies: ++ precond "0.2" ++ + balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" +@@ -1186,6 +1203,16 @@ bull@^3.4.2: + semver "^5.6.0" + uuid "^3.2.1" + ++bunyan@^1.8.3: ++ version "1.8.12" ++ resolved "https://registry.yarnpkg.com/bunyan/-/bunyan-1.8.12.tgz#f150f0f6748abdd72aeae84f04403be2ef113797" ++ integrity sha1-8VDw9nSKvdcq6uhPBEA74u8RN5c= ++ optionalDependencies: ++ dtrace-provider "~0.8" ++ moment "^2.10.6" ++ mv "~2" ++ safe-json-stringify "~1" ++ + busboy@^0.2.11: + version "0.2.14" + resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.14.tgz#6c2a622efcf47c57bbbe1e2a9c37ad36c7925453" +@@ -1966,7 +1993,7 @@ d@1: + dependencies: + es5-ext "^0.10.9" + +-dashdash@^1.12.0: ++dashdash@^1.12.0, dashdash@^1.14.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= +@@ -2292,6 +2319,13 @@ double-ended-queue@^2.1.0-0: + resolved "https://registry.yarnpkg.com/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz#103d3527fd31528f40188130c841efdd78264e5c" + integrity sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw= + ++dtrace-provider@~0.8: ++ version "0.8.7" ++ resolved "https://registry.yarnpkg.com/dtrace-provider/-/dtrace-provider-0.8.7.tgz#dc939b4d3e0620cfe0c1cd803d0d2d7ed04ffd04" ++ integrity sha1-3JObTT4GIM/gwc2APQ0tftBP/QQ= ++ dependencies: ++ nan "^2.10.0" ++ + duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" +@@ -2864,6 +2898,11 @@ extglob@^2.0.4: + snapdragon "^0.8.1" + to-regex "^3.0.1" + ++extsprintf@1.2.0: ++ version "1.2.0" ++ resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.2.0.tgz#5ad946c22f5b32ba7f8cd7426711c6e8a3fc2529" ++ integrity sha1-WtlGwi9bMrp/jNdCZxHG6KP8JSk= ++ + extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" +@@ -3350,6 +3389,17 @@ glob@7.1.2: + once "^1.3.0" + path-is-absolute "^1.0.0" + ++glob@^6.0.1: ++ version "6.0.4" ++ resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" ++ integrity sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI= ++ dependencies: ++ inflight "^1.0.4" ++ inherits "2" ++ minimatch "2 || 3" ++ once "^1.3.0" ++ path-is-absolute "^1.0.0" ++ + glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@~7.1.1, glob@~7.1.2: + version "7.1.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" +@@ -4522,6 +4572,30 @@ lcid@^2.0.0: + dependencies: + invert-kv "^2.0.0" + ++ldap-filter@0.2.2: ++ version "0.2.2" ++ resolved "https://registry.yarnpkg.com/ldap-filter/-/ldap-filter-0.2.2.tgz#f2b842be0b86da3352798505b31ebcae590d77d0" ++ integrity sha1-8rhCvguG2jNSeYUFsx68rlkNd9A= ++ dependencies: ++ assert-plus "0.1.5" ++ ++ldapjs@^1.0.2: ++ version "1.0.2" ++ resolved "https://registry.yarnpkg.com/ldapjs/-/ldapjs-1.0.2.tgz#544ff7032b7b83c68f0701328d9297aa694340f9" ++ integrity sha1-VE/3Ayt7g8aPBwEyjZKXqmlDQPk= ++ dependencies: ++ asn1 "0.2.3" ++ assert-plus "^1.0.0" ++ backoff "^2.5.0" ++ bunyan "^1.8.3" ++ dashdash "^1.14.0" ++ ldap-filter "0.2.2" ++ once "^1.4.0" ++ vasync "^1.6.4" ++ verror "^1.8.1" ++ optionalDependencies: ++ dtrace-provider "~0.8" ++ + leven@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" +@@ -5186,7 +5260,7 @@ minimalistic-assert@^1.0.1: + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +-minimatch@3.0.4, minimatch@^3.0.4, minimatch@~3.0.2: ++"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.4, minimatch@~3.0.2: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== +@@ -5299,6 +5373,11 @@ moment-timezone@^0.5.14, moment-timezone@^0.5.23: + resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66" + integrity sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y= + ++moment@^2.10.6: ++ version "2.24.0" ++ resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" ++ integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== ++ + morgan@^1.5.3: + version "1.9.1" + resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.9.1.tgz#0a8d16734a1d9afbc824b99df87e738e58e2da59" +@@ -5394,6 +5473,15 @@ mute-stream@~0.0.4: + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= + ++mv@~2: ++ version "2.1.1" ++ resolved "https://registry.yarnpkg.com/mv/-/mv-2.1.1.tgz#ae6ce0d6f6d5e0a4f7d893798d03c1ea9559b6a2" ++ integrity sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI= ++ dependencies: ++ mkdirp "~0.5.1" ++ ncp "~2.0.0" ++ rimraf "~2.4.0" ++ + nan@2.11.1, nan@^2.10.0, nan@^2.11.1, nan@^2.9.2: + version "2.11.1" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.11.1.tgz#90e22bccb8ca57ea4cd37cc83d3819b52eea6766" +@@ -5431,6 +5519,11 @@ ncp@1.0.x: + resolved "https://registry.yarnpkg.com/ncp/-/ncp-1.0.1.tgz#d15367e5cb87432ba117d2bf80fdf45aecfb4246" + integrity sha1-0VNn5cuHQyuhF9K/gP30Wuz7QkY= + ++ncp@~2.0.0: ++ version "2.0.0" ++ resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3" ++ integrity sha1-GVoh1sRuNh0vsSgbo4uR6d9727M= ++ + needle@^2.2.1: + version "2.2.4" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.4.tgz#51931bff82533b1928b7d1d69e01f1b00ffd2a4e" +@@ -6520,6 +6613,11 @@ prebuild-install@^5.2.0: + tunnel-agent "^0.6.0" + which-pm-runs "^1.0.0" + ++precond@0.2: ++ version "0.2.3" ++ resolved "https://registry.yarnpkg.com/precond/-/precond-0.2.3.tgz#aa9591bcaa24923f1e0f4849d240f47efc1075ac" ++ integrity sha1-qpWRvKokkj8eD0hJ0kD0fvwQdaw= ++ + prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" +@@ -7141,6 +7239,13 @@ rimraf@2, rimraf@2.x.x, rimraf@^2.2.8, rimraf@^2.4.2, rimraf@^2.5.2, rimraf@^2.5 + dependencies: + glob "^7.0.5" + ++rimraf@~2.4.0: ++ version "2.4.5" ++ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.4.5.tgz#ee710ce5d93a8fdb856fb5ea8ff0e2d75934b2da" ++ integrity sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto= ++ dependencies: ++ glob "^6.0.1" ++ + run-async@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" +@@ -7197,6 +7302,11 @@ safe-buffer@5.1.2, safe-buffer@^5.0.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, s + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + ++safe-json-stringify@~1: ++ version "1.2.0" ++ resolved "https://registry.yarnpkg.com/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz#356e44bc98f1f93ce45df14bcd7c01cda86e0afd" ++ integrity sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg== ++ + safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" +@@ -8857,7 +8967,14 @@ vary@~1.0.1: + resolved "https://registry.yarnpkg.com/vary/-/vary-1.0.1.tgz#99e4981566a286118dfb2b817357df7993376d10" + integrity sha1-meSYFWaihhGN+yuBc1ffeZM3bRA= + +-verror@1.10.0: ++vasync@^1.6.4: ++ version "1.6.4" ++ resolved "https://registry.yarnpkg.com/vasync/-/vasync-1.6.4.tgz#dfe93616ad0e7ae801b332a9d88bfc5cdc8e1d1f" ++ integrity sha1-3+k2Fq0OeugBszKp2Iv8XNyOHR8= ++ dependencies: ++ verror "1.6.0" ++ ++verror@1.10.0, verror@^1.8.1: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= +@@ -8866,6 +8983,13 @@ verror@1.10.0: + core-util-is "1.0.2" + extsprintf "^1.2.0" + ++verror@1.6.0: ++ version "1.6.0" ++ resolved "https://registry.yarnpkg.com/verror/-/verror-1.6.0.tgz#7d13b27b1facc2e2da90405eb5ea6e5bdd252ea5" ++ integrity sha1-fROyex+swuLakEBetepuW90lLqU= ++ dependencies: ++ extsprintf "1.2.0" ++ + videostream@^2.5.1: + version "2.6.0" + resolved "https://registry.yarnpkg.com/videostream/-/videostream-2.6.0.tgz#7f0b2b84bc457c12cfe599aa2345f5cc06241ab6"