aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--client/src/app/account/account-settings/account-settings.component.html3
-rw-r--r--client/src/app/account/account-settings/account-settings.component.scss10
-rw-r--r--client/src/app/account/account-settings/account-settings.component.ts14
-rw-r--r--client/src/app/core/server/server.service.ts11
-rw-r--r--package.json1
-rw-r--r--server.ts2
-rw-r--r--server/controllers/api/config.ts15
-rw-r--r--server/helpers/custom-validators/activitypub/actor.ts4
-rw-r--r--server/helpers/custom-validators/activitypub/misc.ts2
-rw-r--r--server/initializers/constants.ts12
-rw-r--r--server/middlewares/validators/users.ts11
-rw-r--r--server/models/activitypub/actor.ts16
-rw-r--r--server/models/server/server.ts2
-rw-r--r--server/tests/api/check-params/users.ts8
-rw-r--r--server/tests/api/fixtures/avatar-big.pngbin0 -> 146585 bytes
-rw-r--r--shared/models/server-config.model.ts13
-rw-r--r--yarn.lock132
17 files changed, 226 insertions, 30 deletions
diff --git a/client/src/app/account/account-settings/account-settings.component.html b/client/src/app/account/account-settings/account-settings.component.html
index fe345207a..0d1637c40 100644
--- a/client/src/app/account/account-settings/account-settings.component.html
+++ b/client/src/app/account/account-settings/account-settings.component.html
@@ -9,8 +9,9 @@
9 9
10<div class="button-file"> 10<div class="button-file">
11 <span>Change your avatar</span> 11 <span>Change your avatar</span>
12 <input #avatarfileInput type="file" name="avatarfile" id="avatarfile" (change)="changeAvatar()" /> 12 <input #avatarfileInput type="file" name="avatarfile" id="avatarfile" [accept]="avatarExtensions" (change)="changeAvatar()" />
13</div> 13</div>
14<div class="file-max-size">(extensions: {{ avatarExtensions }}, max size: {{ maxAvatarSize | bytes }})</div>
14 15
15<div class="account-title">Account settings</div> 16<div class="account-title">Account settings</div>
16<my-account-change-password></my-account-change-password> 17<my-account-change-password></my-account-change-password>
diff --git a/client/src/app/account/account-settings/account-settings.component.scss b/client/src/app/account/account-settings/account-settings.component.scss
index accd65214..c8a27dbcd 100644
--- a/client/src/app/account/account-settings/account-settings.component.scss
+++ b/client/src/app/account/account-settings/account-settings.component.scss
@@ -22,11 +22,19 @@
22} 22}
23 23
24.button-file { 24.button-file {
25 @include peertube-button-file(auto); 25 @include peertube-button-file(160px);
26 26
27 margin-top: 10px; 27 margin-top: 10px;
28} 28}
29 29
30.file-max-size {
31 display: inline-block;
32 font-size: 13px;
33
34 position: relative;
35 top: -10px;
36}
37
30.account-title { 38.account-title {
31 text-transform: uppercase; 39 text-transform: uppercase;
32 color: $orange-color; 40 color: $orange-color;
diff --git a/client/src/app/account/account-settings/account-settings.component.ts b/client/src/app/account/account-settings/account-settings.component.ts
index 3e03085ce..d5f5ff30f 100644
--- a/client/src/app/account/account-settings/account-settings.component.ts
+++ b/client/src/app/account/account-settings/account-settings.component.ts
@@ -1,9 +1,8 @@
1import { HttpEventType, HttpResponse } from '@angular/common/http'
2import { Component, OnInit, ViewChild } from '@angular/core' 1import { Component, OnInit, ViewChild } from '@angular/core'
3import { NotificationsService } from 'angular2-notifications' 2import { NotificationsService } from 'angular2-notifications'
4import { VideoPrivacy } from '../../../../../shared/models/videos'
5import { User } from '../../shared'
6import { AuthService } from '../../core' 3import { AuthService } from '../../core'
4import { ServerService } from '../../core/server'
5import { User } from '../../shared'
7import { UserService } from '../../shared/users' 6import { UserService } from '../../shared/users'
8 7
9@Component({ 8@Component({
@@ -19,6 +18,7 @@ export class AccountSettingsComponent implements OnInit {
19 constructor ( 18 constructor (
20 private userService: UserService, 19 private userService: UserService,
21 private authService: AuthService, 20 private authService: AuthService,
21 private serverService: ServerService,
22 private notificationsService: NotificationsService 22 private notificationsService: NotificationsService
23 ) {} 23 ) {}
24 24
@@ -47,4 +47,12 @@ export class AccountSettingsComponent implements OnInit {
47 err => this.notificationsService.error('Error', err.message) 47 err => this.notificationsService.error('Error', err.message)
48 ) 48 )
49 } 49 }
50
51 get maxAvatarSize () {
52 return this.serverService.getConfig().avatar.file.size.max
53 }
54
55 get avatarExtensions () {
56 return this.serverService.getConfig().avatar.file.extensions.join(',')
57 }
50} 58}
diff --git a/client/src/app/core/server/server.service.ts b/client/src/app/core/server/server.service.ts
index a5be9e199..45f68b434 100644
--- a/client/src/app/core/server/server.service.ts
+++ b/client/src/app/core/server/server.service.ts
@@ -21,6 +21,17 @@ export class ServerService {
21 }, 21 },
22 transcoding: { 22 transcoding: {
23 enabledResolutions: [] 23 enabledResolutions: []
24 },
25 avatar: {
26 file: {
27 size: { max: 0 },
28 extensions: []
29 }
30 },
31 video: {
32 file: {
33 extensions: []
34 }
24 } 35 }
25 } 36 }
26 private videoCategories: Array<{ id: number, label: string }> = [] 37 private videoCategories: Array<{ id: number, label: string }> = []
diff --git a/package.json b/package.json
index f6e10d709..adaccaf37 100644
--- a/package.json
+++ b/package.json
@@ -86,6 +86,7 @@
86 "scripty": "^1.5.0", 86 "scripty": "^1.5.0",
87 "sequelize": "4.25.2", 87 "sequelize": "4.25.2",
88 "sequelize-typescript": "^0.6.1", 88 "sequelize-typescript": "^0.6.1",
89 "sharp": "^0.18.4",
89 "ts-node": "^3.3.0", 90 "ts-node": "^3.3.0",
90 "typescript": "^2.5.2", 91 "typescript": "^2.5.2",
91 "uuid": "^3.1.0", 92 "uuid": "^3.1.0",
diff --git a/server.ts b/server.ts
index 05fc39acb..e46ff85c7 100644
--- a/server.ts
+++ b/server.ts
@@ -164,7 +164,7 @@ function onDatabaseInitDone () {
164 .then(() => { 164 .then(() => {
165 // ----------- Make the server listening ----------- 165 // ----------- Make the server listening -----------
166 server.listen(port, () => { 166 server.listen(port, () => {
167 VideosPreviewCache.Instance.init(CONFIG.CACHE.PREVIEWS.SIZE) 167 VideosPreviewCache.Instance.init(CONFIG.CACHE.PREVIEWS.FILE_SIZE)
168 activitypubHttpJobScheduler.activate() 168 activitypubHttpJobScheduler.activate()
169 transcodingJobScheduler.activate() 169 transcodingJobScheduler.activate()
170 170
diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts
index 2f1132904..35c89835b 100644
--- a/server/controllers/api/config.ts
+++ b/server/controllers/api/config.ts
@@ -1,7 +1,7 @@
1import * as express from 'express' 1import * as express from 'express'
2import { isSignupAllowed } from '../../helpers/utils' 2import { isSignupAllowed } from '../../helpers/utils'
3 3
4import { CONFIG } from '../../initializers' 4import { CONFIG, CONSTRAINTS_FIELDS } from '../../initializers'
5import { asyncMiddleware } from '../../middlewares' 5import { asyncMiddleware } from '../../middlewares'
6import { ServerConfig } from '../../../shared' 6import { ServerConfig } from '../../../shared'
7 7
@@ -24,6 +24,19 @@ async function getConfig (req: express.Request, res: express.Response, next: exp
24 }, 24 },
25 transcoding: { 25 transcoding: {
26 enabledResolutions 26 enabledResolutions
27 },
28 avatar: {
29 file: {
30 size: {
31 max: CONSTRAINTS_FIELDS.ACTORS.AVATAR.FILE_SIZE.max
32 },
33 extensions: CONSTRAINTS_FIELDS.ACTORS.AVATAR.EXTNAME
34 }
35 },
36 video: {
37 file: {
38 extensions: CONSTRAINTS_FIELDS.VIDEOS.EXTNAME
39 }
27 } 40 }
28 } 41 }
29 42
diff --git a/server/helpers/custom-validators/activitypub/actor.ts b/server/helpers/custom-validators/activitypub/actor.ts
index 630bace30..700e06007 100644
--- a/server/helpers/custom-validators/activitypub/actor.ts
+++ b/server/helpers/custom-validators/activitypub/actor.ts
@@ -24,7 +24,7 @@ function isActorPublicKeyValid (publicKey: string) {
24 typeof publicKey === 'string' && 24 typeof publicKey === 'string' &&
25 publicKey.startsWith('-----BEGIN PUBLIC KEY-----') && 25 publicKey.startsWith('-----BEGIN PUBLIC KEY-----') &&
26 publicKey.indexOf('-----END PUBLIC KEY-----') !== -1 && 26 publicKey.indexOf('-----END PUBLIC KEY-----') !== -1 &&
27 validator.isLength(publicKey, CONSTRAINTS_FIELDS.ACTOR.PUBLIC_KEY) 27 validator.isLength(publicKey, CONSTRAINTS_FIELDS.ACTORS.PUBLIC_KEY)
28} 28}
29 29
30const actorNameRegExp = new RegExp('[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_]+') 30const actorNameRegExp = new RegExp('[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_]+')
@@ -42,7 +42,7 @@ function isActorPrivateKeyValid (privateKey: string) {
42 privateKey.startsWith('-----BEGIN RSA PRIVATE KEY-----') && 42 privateKey.startsWith('-----BEGIN RSA PRIVATE KEY-----') &&
43 // Sometimes there is a \n at the end, so just assert the string contains the end mark 43 // Sometimes there is a \n at the end, so just assert the string contains the end mark
44 privateKey.indexOf('-----END RSA PRIVATE KEY-----') !== -1 && 44 privateKey.indexOf('-----END RSA PRIVATE KEY-----') !== -1 &&
45 validator.isLength(privateKey, CONSTRAINTS_FIELDS.ACTOR.PRIVATE_KEY) 45 validator.isLength(privateKey, CONSTRAINTS_FIELDS.ACTORS.PRIVATE_KEY)
46} 46}
47 47
48function isRemoteActorValid (remoteActor: any) { 48function isRemoteActorValid (remoteActor: any) {
diff --git a/server/helpers/custom-validators/activitypub/misc.ts b/server/helpers/custom-validators/activitypub/misc.ts
index aa6ffc9bd..75d308e9d 100644
--- a/server/helpers/custom-validators/activitypub/misc.ts
+++ b/server/helpers/custom-validators/activitypub/misc.ts
@@ -17,7 +17,7 @@ function isActivityPubUrlValid (url: string) {
17 isURLOptions.require_tld = false 17 isURLOptions.require_tld = false
18 } 18 }
19 19
20 return exists(url) && validator.isURL('' + url, isURLOptions) && validator.isLength('' + url, CONSTRAINTS_FIELDS.ACTOR.URL) 20 return exists(url) && validator.isURL('' + url, isURLOptions) && validator.isLength('' + url, CONSTRAINTS_FIELDS.ACTORS.URL)
21} 21}
22 22
23function isBaseActivityValid (activity: any, type: string) { 23function isBaseActivityValid (activity: any, type: string) {
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts
index 31bb6c981..aefb91537 100644
--- a/server/initializers/constants.ts
+++ b/server/initializers/constants.ts
@@ -133,9 +133,6 @@ const CONFIG = {
133 } 133 }
134} 134}
135 135
136const AVATARS_DIR = {
137 ACCOUNT: join(CONFIG.STORAGE.AVATARS_DIR, 'account')
138}
139// --------------------------------------------------------------------------- 136// ---------------------------------------------------------------------------
140 137
141const CONSTRAINTS_FIELDS = { 138const CONSTRAINTS_FIELDS = {
@@ -169,12 +166,15 @@ const CONSTRAINTS_FIELDS = {
169 FILE_SIZE: { min: 10 }, 166 FILE_SIZE: { min: 10 },
170 URL: { min: 3, max: 2000 } // Length 167 URL: { min: 3, max: 2000 } // Length
171 }, 168 },
172 ACTOR: { 169 ACTORS: {
173 PUBLIC_KEY: { min: 10, max: 5000 }, // Length 170 PUBLIC_KEY: { min: 10, max: 5000 }, // Length
174 PRIVATE_KEY: { min: 10, max: 5000 }, // Length 171 PRIVATE_KEY: { min: 10, max: 5000 }, // Length
175 URL: { min: 3, max: 2000 }, // Length 172 URL: { min: 3, max: 2000 }, // Length
176 AVATAR: { 173 AVATAR: {
177 EXTNAME: [ '.png', '.jpeg', '.jpg' ] 174 EXTNAME: [ '.png', '.jpeg', '.jpg' ],
175 FILE_SIZE: {
176 max: 2 * 1024 * 1024 // 2MB
177 }
178 } 178 }
179 }, 179 },
180 VIDEO_EVENTS: { 180 VIDEO_EVENTS: {
@@ -345,6 +345,7 @@ if (isTestInstance() === true) {
345 REMOTE_SCHEME.WS = 'ws' 345 REMOTE_SCHEME.WS = 'ws'
346 STATIC_MAX_AGE = '0' 346 STATIC_MAX_AGE = '0'
347 ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE = 2 347 ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE = 2
348 CONSTRAINTS_FIELDS.ACTORS.AVATAR.FILE_SIZE.max = 100 * 1024 // 100KB
348} 349}
349 350
350CONFIG.WEBSERVER.URL = sanitizeUrl(CONFIG.WEBSERVER.SCHEME + '://' + CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT) 351CONFIG.WEBSERVER.URL = sanitizeUrl(CONFIG.WEBSERVER.SCHEME + '://' + CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT)
@@ -372,7 +373,6 @@ export {
372 PREVIEWS_SIZE, 373 PREVIEWS_SIZE,
373 REMOTE_SCHEME, 374 REMOTE_SCHEME,
374 FOLLOW_STATES, 375 FOLLOW_STATES,
375 AVATARS_DIR,
376 SERVER_ACTOR_NAME, 376 SERVER_ACTOR_NAME,
377 PRIVATE_RSA_KEY_SIZE, 377 PRIVATE_RSA_KEY_SIZE,
378 SORTABLE_COLUMNS, 378 SORTABLE_COLUMNS,
diff --git a/server/middlewares/validators/users.ts b/server/middlewares/validators/users.ts
index 7c77e9a39..7de3e442c 100644
--- a/server/middlewares/validators/users.ts
+++ b/server/middlewares/validators/users.ts
@@ -12,6 +12,7 @@ import { isSignupAllowed } from '../../helpers/utils'
12import { CONSTRAINTS_FIELDS } from '../../initializers' 12import { CONSTRAINTS_FIELDS } from '../../initializers'
13import { UserModel } from '../../models/account/user' 13import { UserModel } from '../../models/account/user'
14import { areValidationErrors } from './utils' 14import { areValidationErrors } from './utils'
15import Multer = require('multer')
15 16
16const usersAddValidator = [ 17const usersAddValidator = [
17 body('username').custom(isUserUsernameValid).withMessage('Should have a valid username (lowercase alphanumeric characters)'), 18 body('username').custom(isUserUsernameValid).withMessage('Should have a valid username (lowercase alphanumeric characters)'),
@@ -100,7 +101,7 @@ const usersUpdateMeValidator = [
100const usersUpdateMyAvatarValidator = [ 101const usersUpdateMyAvatarValidator = [
101 body('avatarfile').custom((value, { req }) => isAvatarFile(req.files)).withMessage( 102 body('avatarfile').custom((value, { req }) => isAvatarFile(req.files)).withMessage(
102 'This file is not supported. Please, make sure it is of the following type : ' 103 'This file is not supported. Please, make sure it is of the following type : '
103 + CONSTRAINTS_FIELDS.ACTOR.AVATAR.EXTNAME.join(', ') 104 + CONSTRAINTS_FIELDS.ACTORS.AVATAR.EXTNAME.join(', ')
104 ), 105 ),
105 106
106 (req: express.Request, res: express.Response, next: express.NextFunction) => { 107 (req: express.Request, res: express.Response, next: express.NextFunction) => {
@@ -108,6 +109,14 @@ const usersUpdateMyAvatarValidator = [
108 109
109 if (areValidationErrors(req, res)) return 110 if (areValidationErrors(req, res)) return
110 111
112 const imageFile = req.files['avatarfile'][0] as Express.Multer.File
113 if (imageFile.size > CONSTRAINTS_FIELDS.ACTORS.AVATAR.FILE_SIZE.max) {
114 res.status(400)
115 .send({ error: `The size of the avatar is too big (>${CONSTRAINTS_FIELDS.ACTORS.AVATAR.FILE_SIZE.max}).` })
116 .end()
117 return
118 }
119
111 return next() 120 return next()
112 } 121 }
113] 122]
diff --git a/server/models/activitypub/actor.ts b/server/models/activitypub/actor.ts
index a12f3ec9e..ff5ab2e32 100644
--- a/server/models/activitypub/actor.ts
+++ b/server/models/activitypub/actor.ts
@@ -87,17 +87,17 @@ export class ActorModel extends Model<ActorModel> {
87 87
88 @AllowNull(false) 88 @AllowNull(false)
89 @Is('ActorUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'url')) 89 @Is('ActorUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'url'))
90 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max)) 90 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max))
91 url: string 91 url: string
92 92
93 @AllowNull(true) 93 @AllowNull(true)
94 @Is('ActorPublicKey', value => throwIfNotValid(value, isActorPublicKeyValid, 'public key')) 94 @Is('ActorPublicKey', value => throwIfNotValid(value, isActorPublicKeyValid, 'public key'))
95 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.PUBLIC_KEY.max)) 95 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.PUBLIC_KEY.max))
96 publicKey: string 96 publicKey: string
97 97
98 @AllowNull(true) 98 @AllowNull(true)
99 @Is('ActorPublicKey', value => throwIfNotValid(value, isActorPrivateKeyValid, 'private key')) 99 @Is('ActorPublicKey', value => throwIfNotValid(value, isActorPrivateKeyValid, 'private key'))
100 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.PRIVATE_KEY.max)) 100 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.PRIVATE_KEY.max))
101 privateKey: string 101 privateKey: string
102 102
103 @AllowNull(false) 103 @AllowNull(false)
@@ -112,27 +112,27 @@ export class ActorModel extends Model<ActorModel> {
112 112
113 @AllowNull(false) 113 @AllowNull(false)
114 @Is('ActorInboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'inbox url')) 114 @Is('ActorInboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'inbox url'))
115 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max)) 115 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max))
116 inboxUrl: string 116 inboxUrl: string
117 117
118 @AllowNull(false) 118 @AllowNull(false)
119 @Is('ActorOutboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'outbox url')) 119 @Is('ActorOutboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'outbox url'))
120 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max)) 120 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max))
121 outboxUrl: string 121 outboxUrl: string
122 122
123 @AllowNull(false) 123 @AllowNull(false)
124 @Is('ActorSharedInboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'shared inbox url')) 124 @Is('ActorSharedInboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'shared inbox url'))
125 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max)) 125 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max))
126 sharedInboxUrl: string 126 sharedInboxUrl: string
127 127
128 @AllowNull(false) 128 @AllowNull(false)
129 @Is('ActorFollowersUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'followers url')) 129 @Is('ActorFollowersUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'followers url'))
130 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max)) 130 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max))
131 followersUrl: string 131 followersUrl: string
132 132
133 @AllowNull(false) 133 @AllowNull(false)
134 @Is('ActorFollowingUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'following url')) 134 @Is('ActorFollowingUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'following url'))
135 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max)) 135 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max))
136 followingUrl: string 136 followingUrl: string
137 137
138 @CreatedAt 138 @CreatedAt
diff --git a/server/models/server/server.ts b/server/models/server/server.ts
index d35aa0ca4..122e5f74f 100644
--- a/server/models/server/server.ts
+++ b/server/models/server/server.ts
@@ -27,7 +27,7 @@ export class ServerModel extends Model<ServerModel> {
27 @AllowNull(false) 27 @AllowNull(false)
28 @Default(SERVERS_SCORE.BASE) 28 @Default(SERVERS_SCORE.BASE)
29 @IsInt 29 @IsInt
30 @Max(SERVERS_SCORE.MAX) 30 @Max(SERVERS_SCORE.max)
31 @Column 31 @Column
32 score: number 32 score: number
33 33
diff --git a/server/tests/api/check-params/users.ts b/server/tests/api/check-params/users.ts
index 33d92ac24..14fcf8703 100644
--- a/server/tests/api/check-params/users.ts
+++ b/server/tests/api/check-params/users.ts
@@ -276,6 +276,14 @@ describe('Test users API validators', function () {
276 await makePostUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches }) 276 await makePostUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches })
277 }) 277 })
278 278
279 it('Should fail with a big file', async function () {
280 const fields = {}
281 const attaches = {
282 'avatarfile': join(__dirname, '..', 'fixtures', 'avatar-big.png')
283 }
284 await makePostUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches })
285 })
286
279 it('Should succeed with the correct params', async function () { 287 it('Should succeed with the correct params', async function () {
280 const fields = {} 288 const fields = {}
281 const attaches = { 289 const attaches = {
diff --git a/server/tests/api/fixtures/avatar-big.png b/server/tests/api/fixtures/avatar-big.png
new file mode 100644
index 000000000..e593e40da
--- /dev/null
+++ b/server/tests/api/fixtures/avatar-big.png
Binary files differ
diff --git a/shared/models/server-config.model.ts b/shared/models/server-config.model.ts
index 8de808e60..d0b2e40de 100644
--- a/shared/models/server-config.model.ts
+++ b/shared/models/server-config.model.ts
@@ -5,4 +5,17 @@ export interface ServerConfig {
5 transcoding: { 5 transcoding: {
6 enabledResolutions: number[] 6 enabledResolutions: number[]
7 } 7 }
8 avatar: {
9 file: {
10 size: {
11 max: number
12 },
13 extensions: string[]
14 }
15 }
16 video: {
17 file: {
18 extensions: string[]
19 }
20 }
8} 21}
diff --git a/yarn.lock b/yarn.lock
index 101428df8..67337c08b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -756,6 +756,15 @@ caseless@~0.12.0:
756 version "0.12.0" 756 version "0.12.0"
757 resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" 757 resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
758 758
759caw@^2.0.0:
760 version "2.0.1"
761 resolved "https://registry.yarnpkg.com/caw/-/caw-2.0.1.tgz#6c3ca071fc194720883c2dc5da9b074bfc7e9e95"
762 dependencies:
763 get-proxy "^2.0.0"
764 isurl "^1.0.0-alpha5"
765 tunnel-agent "^0.6.0"
766 url-to-options "^1.0.1"
767
759chai@^4.1.1: 768chai@^4.1.1:
760 version "4.1.2" 769 version "4.1.2"
761 resolved "https://registry.yarnpkg.com/chai/-/chai-4.1.2.tgz#0f64584ba642f0f2ace2806279f4f06ca23ad73c" 770 resolved "https://registry.yarnpkg.com/chai/-/chai-4.1.2.tgz#0f64584ba642f0f2ace2806279f4f06ca23ad73c"
@@ -878,16 +887,30 @@ code-point-at@^1.0.0:
878 version "1.1.0" 887 version "1.1.0"
879 resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" 888 resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
880 889
881color-convert@^1.9.0: 890color-convert@^1.9.0, color-convert@^1.9.1:
882 version "1.9.1" 891 version "1.9.1"
883 resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" 892 resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed"
884 dependencies: 893 dependencies:
885 color-name "^1.1.1" 894 color-name "^1.1.1"
886 895
887color-name@^1.1.1: 896color-name@^1.0.0, color-name@^1.1.1:
888 version "1.1.3" 897 version "1.1.3"
889 resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 898 resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
890 899
900color-string@^1.5.2:
901 version "1.5.2"
902 resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.2.tgz#26e45814bc3c9a7cbd6751648a41434514a773a9"
903 dependencies:
904 color-name "^1.0.0"
905 simple-swizzle "^0.2.2"
906
907color@^2.0.0:
908 version "2.0.1"
909 resolved "https://registry.yarnpkg.com/color/-/color-2.0.1.tgz#e4ed78a3c4603d0891eba5430b04b86314f4c839"
910 dependencies:
911 color-convert "^1.9.1"
912 color-string "^1.5.2"
913
891colors@1.0.x: 914colors@1.0.x:
892 version "1.0.3" 915 version "1.0.3"
893 resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" 916 resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b"
@@ -945,6 +968,13 @@ concurrently@^3.1.0:
945 supports-color "^3.2.3" 968 supports-color "^3.2.3"
946 tree-kill "^1.1.0" 969 tree-kill "^1.1.0"
947 970
971config-chain@^1.1.11:
972 version "1.1.11"
973 resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.11.tgz#aba09747dfbe4c3e70e766a6e41586e1859fc6f2"
974 dependencies:
975 ini "^1.3.4"
976 proto-list "~1.2.1"
977
948config@^1.14.0: 978config@^1.14.0:
949 version "1.28.1" 979 version "1.28.1"
950 resolved "https://registry.yarnpkg.com/config/-/config-1.28.1.tgz#7625d2a1e4c90f131d8a73347982d93c3873282d" 980 resolved "https://registry.yarnpkg.com/config/-/config-1.28.1.tgz#7625d2a1e4c90f131d8a73347982d93c3873282d"
@@ -1161,6 +1191,10 @@ destroy@~1.0.4:
1161 version "1.0.4" 1191 version "1.0.4"
1162 resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" 1192 resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
1163 1193
1194detect-libc@^0.2.0:
1195 version "0.2.0"
1196 resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-0.2.0.tgz#47fdf567348a17ec25fcbf0b9e446348a76f9fb5"
1197
1164detect-libc@^1.0.2: 1198detect-libc@^1.0.2:
1165 version "1.0.3" 1199 version "1.0.3"
1166 resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" 1200 resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
@@ -1887,6 +1921,12 @@ get-func-name@^2.0.0:
1887 version "2.0.0" 1921 version "2.0.0"
1888 resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" 1922 resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41"
1889 1923
1924get-proxy@^2.0.0:
1925 version "2.1.0"
1926 resolved "https://registry.yarnpkg.com/get-proxy/-/get-proxy-2.1.0.tgz#349f2b4d91d44c4d4d4e9cba2ad90143fac5ef93"
1927 dependencies:
1928 npm-conf "^1.1.0"
1929
1890get-stdin@^5.0.1: 1930get-stdin@^5.0.1:
1891 version "5.0.1" 1931 version "5.0.1"
1892 resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398" 1932 resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398"
@@ -2016,6 +2056,16 @@ has-flag@^2.0.0:
2016 version "2.0.0" 2056 version "2.0.0"
2017 resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" 2057 resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51"
2018 2058
2059has-symbol-support-x@^1.4.1:
2060 version "1.4.1"
2061 resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.1.tgz#66ec2e377e0c7d7ccedb07a3a84d77510ff1bc4c"
2062
2063has-to-string-tag-x@^1.2.0:
2064 version "1.4.1"
2065 resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d"
2066 dependencies:
2067 has-symbol-support-x "^1.4.1"
2068
2019has-unicode@^2.0.0: 2069has-unicode@^2.0.0:
2020 version "2.0.1" 2070 version "2.0.1"
2021 resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" 2071 resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
@@ -2196,6 +2246,10 @@ is-arrayish@^0.2.1:
2196 version "0.2.1" 2246 version "0.2.1"
2197 resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" 2247 resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
2198 2248
2249is-arrayish@^0.3.1:
2250 version "0.3.1"
2251 resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.1.tgz#c2dfc386abaa0c3e33c48db3fe87059e69065efd"
2252
2199is-ascii@^1.0.0: 2253is-ascii@^1.0.0:
2200 version "1.0.0" 2254 version "1.0.0"
2201 resolved "https://registry.yarnpkg.com/is-ascii/-/is-ascii-1.0.0.tgz#f02ad0259a0921cd199ff21ce1b09e0f6b4e3929" 2255 resolved "https://registry.yarnpkg.com/is-ascii/-/is-ascii-1.0.0.tgz#f02ad0259a0921cd199ff21ce1b09e0f6b4e3929"
@@ -2300,6 +2354,10 @@ is-obj@^1.0.0:
2300 version "1.0.1" 2354 version "1.0.1"
2301 resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" 2355 resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
2302 2356
2357is-object@^1.0.1:
2358 version "1.0.1"
2359 resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470"
2360
2303is-path-cwd@^1.0.0: 2361is-path-cwd@^1.0.0:
2304 version "1.0.0" 2362 version "1.0.0"
2305 resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" 2363 resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d"
@@ -2380,6 +2438,13 @@ isstream@0.1.x, isstream@~0.1.2:
2380 version "0.1.2" 2438 version "0.1.2"
2381 resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" 2439 resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
2382 2440
2441isurl@^1.0.0-alpha5:
2442 version "1.0.0"
2443 resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67"
2444 dependencies:
2445 has-to-string-tag-x "^1.2.0"
2446 is-object "^1.0.1"
2447
2383js-string-escape@1.0.1: 2448js-string-escape@1.0.1:
2384 version "1.0.1" 2449 version "1.0.1"
2385 resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" 2450 resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef"
@@ -2779,6 +2844,18 @@ minimist@^1.1.0, minimist@^1.1.1, minimist@^1.2.0:
2779 version "1.2.0" 2844 version "1.2.0"
2780 resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" 2845 resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
2781 2846
2847minipass@^2.0.2, minipass@^2.2.1:
2848 version "2.2.1"
2849 resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.2.1.tgz#5ada97538b1027b4cf7213432428578cb564011f"
2850 dependencies:
2851 yallist "^3.0.0"
2852
2853minizlib@^1.0.3:
2854 version "1.1.0"
2855 resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb"
2856 dependencies:
2857 minipass "^2.2.1"
2858
2782mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1: 2859mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1:
2783 version "0.5.1" 2860 version "0.5.1"
2784 resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 2861 resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
@@ -2867,7 +2944,7 @@ nan@2.6.2:
2867 version "2.6.2" 2944 version "2.6.2"
2868 resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.2.tgz#e4ff34e6c95fdfb5aecc08de6596f43605a7db45" 2945 resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.2.tgz#e4ff34e6c95fdfb5aecc08de6596f43605a7db45"
2869 2946
2870nan@^2.3.0, nan@^2.7.0: 2947nan@^2.3.0, nan@^2.6.2, nan@^2.7.0:
2871 version "2.8.0" 2948 version "2.8.0"
2872 resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a" 2949 resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a"
2873 2950
@@ -2969,6 +3046,13 @@ normalize-path@^2.0.0, normalize-path@^2.0.1:
2969 dependencies: 3046 dependencies:
2970 remove-trailing-separator "^1.0.1" 3047 remove-trailing-separator "^1.0.1"
2971 3048
3049npm-conf@^1.1.0:
3050 version "1.1.3"
3051 resolved "https://registry.yarnpkg.com/npm-conf/-/npm-conf-1.1.3.tgz#256cc47bd0e218c259c4e9550bf413bc2192aff9"
3052 dependencies:
3053 config-chain "^1.1.11"
3054 pify "^3.0.0"
3055
2972npm-run-path@^2.0.0: 3056npm-run-path@^2.0.0:
2973 version "2.0.2" 3057 version "2.0.2"
2974 resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" 3058 resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
@@ -3399,6 +3483,10 @@ promisify-any@2.0.1:
3399 co-bluebird "^1.1.0" 3483 co-bluebird "^1.1.0"
3400 is-generator "^1.0.2" 3484 is-generator "^1.0.2"
3401 3485
3486proto-list@~1.2.1:
3487 version "1.2.4"
3488 resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
3489
3402proxy-addr@~2.0.2: 3490proxy-addr@~2.0.2:
3403 version "2.0.2" 3491 version "2.0.2"
3404 resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.2.tgz#6571504f47bb988ec8180253f85dd7e14952bdec" 3492 resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.2.tgz#6571504f47bb988ec8180253f85dd7e14952bdec"
@@ -3828,6 +3916,18 @@ setprototypeof@1.1.0:
3828 version "1.1.0" 3916 version "1.1.0"
3829 resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" 3917 resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
3830 3918
3919sharp@^0.18.4:
3920 version "0.18.4"
3921 resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.18.4.tgz#fe329c0f06896c28aa24376df1fff02ae57f2d34"
3922 dependencies:
3923 caw "^2.0.0"
3924 color "^2.0.0"
3925 detect-libc "^0.2.0"
3926 nan "^2.6.2"
3927 semver "^5.3.0"
3928 simple-get "^2.7.0"
3929 tar "^3.1.5"
3930
3831shebang-command@^1.2.0: 3931shebang-command@^1.2.0:
3832 version "1.2.0" 3932 version "1.2.0"
3833 resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" 3933 resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
@@ -3866,7 +3966,7 @@ simple-get@^1.4.2:
3866 unzip-response "^1.0.0" 3966 unzip-response "^1.0.0"
3867 xtend "^4.0.0" 3967 xtend "^4.0.0"
3868 3968
3869simple-get@^2.0.0, simple-get@^2.2.1: 3969simple-get@^2.0.0, simple-get@^2.2.1, simple-get@^2.7.0:
3870 version "2.7.0" 3970 version "2.7.0"
3871 resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.7.0.tgz#ad37f926d08129237ff08c4f2edfd6f10e0380b5" 3971 resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.7.0.tgz#ad37f926d08129237ff08c4f2edfd6f10e0380b5"
3872 dependencies: 3972 dependencies:
@@ -3890,6 +3990,12 @@ simple-sha1@^2.0.0, simple-sha1@^2.0.8, simple-sha1@^2.1.0:
3890 dependencies: 3990 dependencies:
3891 rusha "^0.8.1" 3991 rusha "^0.8.1"
3892 3992
3993simple-swizzle@^0.2.2:
3994 version "0.2.2"
3995 resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
3996 dependencies:
3997 is-arrayish "^0.3.1"
3998
3893simple-websocket@^5.0.0: 3999simple-websocket@^5.0.0:
3894 version "5.1.0" 4000 version "5.1.0"
3895 resolved "https://registry.yarnpkg.com/simple-websocket/-/simple-websocket-5.1.0.tgz#9fc2e4127f217ace4871f10c56bd21c85ecca21d" 4001 resolved "https://registry.yarnpkg.com/simple-websocket/-/simple-websocket-5.1.0.tgz#9fc2e4127f217ace4871f10c56bd21c85ecca21d"
@@ -4209,6 +4315,16 @@ tar@^2.2.1:
4209 fstream "^1.0.2" 4315 fstream "^1.0.2"
4210 inherits "2" 4316 inherits "2"
4211 4317
4318tar@^3.1.5:
4319 version "3.2.1"
4320 resolved "https://registry.yarnpkg.com/tar/-/tar-3.2.1.tgz#9aa8e41c88f09e76c166075bc71f93d5166e61b1"
4321 dependencies:
4322 chownr "^1.0.1"
4323 minipass "^2.0.2"
4324 minizlib "^1.0.3"
4325 mkdirp "^0.5.0"
4326 yallist "^3.0.2"
4327
4212term-size@^1.2.0: 4328term-size@^1.2.0:
4213 version "1.2.0" 4329 version "1.2.0"
4214 resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69" 4330 resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69"
@@ -4459,6 +4575,10 @@ url-parse-lax@^1.0.0:
4459 dependencies: 4575 dependencies:
4460 prepend-http "^1.0.1" 4576 prepend-http "^1.0.1"
4461 4577
4578url-to-options@^1.0.1:
4579 version "1.0.1"
4580 resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9"
4581
4462user-home@^2.0.0: 4582user-home@^2.0.0:
4463 version "2.0.0" 4583 version "2.0.0"
4464 resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" 4584 resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f"
@@ -4674,6 +4794,10 @@ yallist@^2.1.2:
4674 version "2.1.2" 4794 version "2.1.2"
4675 resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" 4795 resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
4676 4796
4797yallist@^3.0.0, yallist@^3.0.2:
4798 version "3.0.2"
4799 resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9"
4800
4677yargs-parser@^8.0.0: 4801yargs-parser@^8.0.0:
4678 version "8.0.0" 4802 version "8.0.0"
4679 resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.0.0.tgz#21d476330e5a82279a4b881345bf066102e219c6" 4803 resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.0.0.tgz#21d476330e5a82279a4b881345bf066102e219c6"