diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/helpers/custom-validators/plugins.ts | 22 | ||||
-rw-r--r-- | server/lib/plugins/yarn.ts | 4 | ||||
-rw-r--r-- | server/middlewares/validators/plugins.ts | 13 | ||||
-rw-r--r-- | server/middlewares/validators/themes.ts | 4 | ||||
-rw-r--r-- | server/models/server/plugin.ts | 9 | ||||
-rw-r--r-- | server/tests/cli/peertube.ts | 21 | ||||
-rw-r--r-- | server/tests/helpers/index.ts | 1 | ||||
-rw-r--r-- | server/tests/helpers/validator.ts | 32 | ||||
-rw-r--r-- | server/tools/peertube-plugins.ts | 2 |
9 files changed, 90 insertions, 18 deletions
diff --git a/server/helpers/custom-validators/plugins.ts b/server/helpers/custom-validators/plugins.ts index 60b29dc89..a20de0c4a 100644 --- a/server/helpers/custom-validators/plugins.ts +++ b/server/helpers/custom-validators/plugins.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import { exists, isArray, isSafePath } from './misc' | ||
2 | import validator from 'validator' | 1 | import validator from 'validator' |
2 | import { PluginPackageJSON } from '../../../shared/models/plugins/plugin-package-json.model' | ||
3 | import { PluginType } from '../../../shared/models/plugins/plugin.type' | 3 | import { PluginType } from '../../../shared/models/plugins/plugin.type' |
4 | import { CONSTRAINTS_FIELDS } from '../../initializers/constants' | 4 | import { CONSTRAINTS_FIELDS } from '../../initializers/constants' |
5 | import { PluginPackageJSON } from '../../../shared/models/plugins/plugin-package-json.model' | ||
6 | import { isUrlValid } from './activitypub/misc' | 5 | import { isUrlValid } from './activitypub/misc' |
6 | import { exists, isArray, isSafePath } from './misc' | ||
7 | 7 | ||
8 | const PLUGINS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.PLUGINS | 8 | const PLUGINS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.PLUGINS |
9 | 9 | ||
@@ -29,7 +29,7 @@ function isPluginDescriptionValid (value: string) { | |||
29 | return exists(value) && validator.isLength(value, PLUGINS_CONSTRAINTS_FIELDS.DESCRIPTION) | 29 | return exists(value) && validator.isLength(value, PLUGINS_CONSTRAINTS_FIELDS.DESCRIPTION) |
30 | } | 30 | } |
31 | 31 | ||
32 | function isPluginVersionValid (value: string) { | 32 | function isPluginStableVersionValid (value: string) { |
33 | if (!exists(value)) return false | 33 | if (!exists(value)) return false |
34 | 34 | ||
35 | const parts = (value + '').split('.') | 35 | const parts = (value + '').split('.') |
@@ -37,6 +37,19 @@ function isPluginVersionValid (value: string) { | |||
37 | return parts.length === 3 && parts.every(p => validator.isInt(p)) | 37 | return parts.length === 3 && parts.every(p => validator.isInt(p)) |
38 | } | 38 | } |
39 | 39 | ||
40 | function isPluginStableOrUnstableVersionValid (value: string) { | ||
41 | if (!exists(value)) return false | ||
42 | |||
43 | // suffix is beta.x or alpha.x | ||
44 | const [ stable, suffix ] = value.split('-') | ||
45 | if (!isPluginStableVersionValid(stable)) return false | ||
46 | |||
47 | const suffixRegex = /^(rc|alpha|beta)\.\d+$/ | ||
48 | if (suffix && !suffixRegex.test(suffix)) return false | ||
49 | |||
50 | return true | ||
51 | } | ||
52 | |||
40 | function isPluginEngineValid (engine: any) { | 53 | function isPluginEngineValid (engine: any) { |
41 | return exists(engine) && exists(engine.peertube) | 54 | return exists(engine) && exists(engine.peertube) |
42 | } | 55 | } |
@@ -156,7 +169,8 @@ export { | |||
156 | isPackageJSONValid, | 169 | isPackageJSONValid, |
157 | isThemeNameValid, | 170 | isThemeNameValid, |
158 | isPluginHomepage, | 171 | isPluginHomepage, |
159 | isPluginVersionValid, | 172 | isPluginStableVersionValid, |
173 | isPluginStableOrUnstableVersionValid, | ||
160 | isPluginNameValid, | 174 | isPluginNameValid, |
161 | isPluginDescriptionValid, | 175 | isPluginDescriptionValid, |
162 | isLibraryCodeValid, | 176 | isLibraryCodeValid, |
diff --git a/server/lib/plugins/yarn.ts b/server/lib/plugins/yarn.ts index d105b95e0..9cf6ec9e9 100644 --- a/server/lib/plugins/yarn.ts +++ b/server/lib/plugins/yarn.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { outputJSON, pathExists } from 'fs-extra' | 1 | import { outputJSON, pathExists } from 'fs-extra' |
2 | import { join } from 'path' | 2 | import { join } from 'path' |
3 | import { execShell } from '../../helpers/core-utils' | 3 | import { execShell } from '../../helpers/core-utils' |
4 | import { isNpmPluginNameValid, isPluginVersionValid } from '../../helpers/custom-validators/plugins' | 4 | import { isNpmPluginNameValid, isPluginStableOrUnstableVersionValid } from '../../helpers/custom-validators/plugins' |
5 | import { logger } from '../../helpers/logger' | 5 | import { logger } from '../../helpers/logger' |
6 | import { CONFIG } from '../../initializers/config' | 6 | import { CONFIG } from '../../initializers/config' |
7 | import { getLatestPluginVersion } from './plugin-index' | 7 | import { getLatestPluginVersion } from './plugin-index' |
@@ -69,5 +69,5 @@ function checkNpmPluginNameOrThrow (name: string) { | |||
69 | } | 69 | } |
70 | 70 | ||
71 | function checkPluginVersionOrThrow (name: string) { | 71 | function checkPluginVersionOrThrow (name: string) { |
72 | if (!isPluginVersionValid(name)) throw new Error('Invalid NPM plugin version to install') | 72 | if (!isPluginStableOrUnstableVersionValid(name)) throw new Error('Invalid NPM plugin version to install') |
73 | } | 73 | } |
diff --git a/server/middlewares/validators/plugins.ts b/server/middlewares/validators/plugins.ts index 78c030333..64bef2648 100644 --- a/server/middlewares/validators/plugins.ts +++ b/server/middlewares/validators/plugins.ts | |||
@@ -4,7 +4,12 @@ import { HttpStatusCode } from '../../../shared/models/http/http-error-codes' | |||
4 | import { PluginType } from '../../../shared/models/plugins/plugin.type' | 4 | import { PluginType } from '../../../shared/models/plugins/plugin.type' |
5 | import { InstallOrUpdatePlugin } from '../../../shared/models/plugins/server/api/install-plugin.model' | 5 | import { InstallOrUpdatePlugin } from '../../../shared/models/plugins/server/api/install-plugin.model' |
6 | import { exists, isBooleanValid, isSafePath, toBooleanOrNull, toIntOrNull } from '../../helpers/custom-validators/misc' | 6 | import { exists, isBooleanValid, isSafePath, toBooleanOrNull, toIntOrNull } from '../../helpers/custom-validators/misc' |
7 | import { isNpmPluginNameValid, isPluginNameValid, isPluginTypeValid, isPluginVersionValid } from '../../helpers/custom-validators/plugins' | 7 | import { |
8 | isNpmPluginNameValid, | ||
9 | isPluginNameValid, | ||
10 | isPluginStableOrUnstableVersionValid, | ||
11 | isPluginTypeValid | ||
12 | } from '../../helpers/custom-validators/plugins' | ||
8 | import { CONFIG } from '../../initializers/config' | 13 | import { CONFIG } from '../../initializers/config' |
9 | import { PluginManager } from '../../lib/plugins/plugin-manager' | 14 | import { PluginManager } from '../../lib/plugins/plugin-manager' |
10 | import { PluginModel } from '../../models/server/plugin' | 15 | import { PluginModel } from '../../models/server/plugin' |
@@ -19,7 +24,7 @@ const getPluginValidator = (pluginType: PluginType, withVersion = true) => { | |||
19 | if (withVersion) { | 24 | if (withVersion) { |
20 | validators.push( | 25 | validators.push( |
21 | param('pluginVersion') | 26 | param('pluginVersion') |
22 | .custom(isPluginVersionValid) | 27 | .custom(isPluginStableOrUnstableVersionValid) |
23 | ) | 28 | ) |
24 | } | 29 | } |
25 | 30 | ||
@@ -113,7 +118,7 @@ const installOrUpdatePluginValidator = [ | |||
113 | .custom(isNpmPluginNameValid), | 118 | .custom(isNpmPluginNameValid), |
114 | body('pluginVersion') | 119 | body('pluginVersion') |
115 | .optional() | 120 | .optional() |
116 | .custom(isPluginVersionValid), | 121 | .custom(isPluginStableOrUnstableVersionValid), |
117 | body('path') | 122 | body('path') |
118 | .optional() | 123 | .optional() |
119 | .custom(isSafePath), | 124 | .custom(isSafePath), |
@@ -185,7 +190,7 @@ const listAvailablePluginsValidator = [ | |||
185 | .custom(isPluginTypeValid), | 190 | .custom(isPluginTypeValid), |
186 | query('currentPeerTubeEngine') | 191 | query('currentPeerTubeEngine') |
187 | .optional() | 192 | .optional() |
188 | .custom(isPluginVersionValid), | 193 | .custom(isPluginStableOrUnstableVersionValid), |
189 | 194 | ||
190 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | 195 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
191 | if (areValidationErrors(req, res)) return | 196 | if (areValidationErrors(req, res)) return |
diff --git a/server/middlewares/validators/themes.ts b/server/middlewares/validators/themes.ts index c130801a0..080b3e096 100644 --- a/server/middlewares/validators/themes.ts +++ b/server/middlewares/validators/themes.ts | |||
@@ -2,7 +2,7 @@ import express from 'express' | |||
2 | import { param } from 'express-validator' | 2 | import { param } from 'express-validator' |
3 | import { HttpStatusCode } from '../../../shared/models/http/http-error-codes' | 3 | import { HttpStatusCode } from '../../../shared/models/http/http-error-codes' |
4 | import { isSafePath } from '../../helpers/custom-validators/misc' | 4 | import { isSafePath } from '../../helpers/custom-validators/misc' |
5 | import { isPluginNameValid, isPluginVersionValid } from '../../helpers/custom-validators/plugins' | 5 | import { isPluginNameValid, isPluginStableOrUnstableVersionValid } from '../../helpers/custom-validators/plugins' |
6 | import { PluginManager } from '../../lib/plugins/plugin-manager' | 6 | import { PluginManager } from '../../lib/plugins/plugin-manager' |
7 | import { areValidationErrors } from './shared' | 7 | import { areValidationErrors } from './shared' |
8 | 8 | ||
@@ -10,7 +10,7 @@ const serveThemeCSSValidator = [ | |||
10 | param('themeName') | 10 | param('themeName') |
11 | .custom(isPluginNameValid), | 11 | .custom(isPluginNameValid), |
12 | param('themeVersion') | 12 | param('themeVersion') |
13 | .custom(isPluginVersionValid), | 13 | .custom(isPluginStableOrUnstableVersionValid), |
14 | param('staticEndpoint') | 14 | param('staticEndpoint') |
15 | .custom(isSafePath), | 15 | .custom(isSafePath), |
16 | 16 | ||
diff --git a/server/models/server/plugin.ts b/server/models/server/plugin.ts index fa5b4cc4b..6a5d80182 100644 --- a/server/models/server/plugin.ts +++ b/server/models/server/plugin.ts | |||
@@ -7,8 +7,9 @@ import { | |||
7 | isPluginDescriptionValid, | 7 | isPluginDescriptionValid, |
8 | isPluginHomepage, | 8 | isPluginHomepage, |
9 | isPluginNameValid, | 9 | isPluginNameValid, |
10 | isPluginTypeValid, | 10 | isPluginStableOrUnstableVersionValid, |
11 | isPluginVersionValid | 11 | isPluginStableVersionValid, |
12 | isPluginTypeValid | ||
12 | } from '../../helpers/custom-validators/plugins' | 13 | } from '../../helpers/custom-validators/plugins' |
13 | import { getSort, throwIfNotValid } from '../utils' | 14 | import { getSort, throwIfNotValid } from '../utils' |
14 | 15 | ||
@@ -40,12 +41,12 @@ export class PluginModel extends Model<Partial<AttributesOnly<PluginModel>>> { | |||
40 | type: number | 41 | type: number |
41 | 42 | ||
42 | @AllowNull(false) | 43 | @AllowNull(false) |
43 | @Is('PluginVersion', value => throwIfNotValid(value, isPluginVersionValid, 'version')) | 44 | @Is('PluginVersion', value => throwIfNotValid(value, isPluginStableOrUnstableVersionValid, 'version')) |
44 | @Column | 45 | @Column |
45 | version: string | 46 | version: string |
46 | 47 | ||
47 | @AllowNull(true) | 48 | @AllowNull(true) |
48 | @Is('PluginLatestVersion', value => throwIfNotValid(value, isPluginVersionValid, 'version')) | 49 | @Is('PluginLatestVersion', value => throwIfNotValid(value, isPluginStableVersionValid, 'version')) |
49 | @Column | 50 | @Column |
50 | latestVersion: string | 51 | latestVersion: string |
51 | 52 | ||
diff --git a/server/tests/cli/peertube.ts b/server/tests/cli/peertube.ts index 9b17cdd1b..a39bcfebe 100644 --- a/server/tests/cli/peertube.ts +++ b/server/tests/cli/peertube.ts | |||
@@ -24,7 +24,13 @@ describe('Test CLI wrapper', function () { | |||
24 | before(async function () { | 24 | before(async function () { |
25 | this.timeout(30000) | 25 | this.timeout(30000) |
26 | 26 | ||
27 | server = await createSingleServer(1) | 27 | server = await createSingleServer(1, { |
28 | rates_limit: { | ||
29 | login: { | ||
30 | max: 30 | ||
31 | } | ||
32 | } | ||
33 | }) | ||
28 | await setAccessTokensToServers([ server ]) | 34 | await setAccessTokensToServers([ server ]) |
29 | 35 | ||
30 | await server.users.create({ username: 'user_1', password: 'super_password' }) | 36 | await server.users.create({ username: 'user_1', password: 'super_password' }) |
@@ -240,6 +246,19 @@ describe('Test CLI wrapper', function () { | |||
240 | 246 | ||
241 | expect(res).to.not.contain('peertube-plugin-hello-world') | 247 | expect(res).to.not.contain('peertube-plugin-hello-world') |
242 | }) | 248 | }) |
249 | |||
250 | it('Should install a plugin in requested beta version', async function () { | ||
251 | this.timeout(60000) | ||
252 | |||
253 | await cliCommand.execWithEnv(`${cmd} plugins install --npm-name peertube-plugin-hello-world --plugin-version 0.0.21-beta.1`) | ||
254 | |||
255 | const res = await cliCommand.execWithEnv(`${cmd} plugins list`) | ||
256 | |||
257 | expect(res).to.contain('peertube-plugin-hello-world') | ||
258 | expect(res).to.contain('0.0.21-beta.1') | ||
259 | |||
260 | await cliCommand.execWithEnv(`${cmd} plugins uninstall --npm-name peertube-plugin-hello-world`) | ||
261 | }) | ||
243 | }) | 262 | }) |
244 | 263 | ||
245 | describe('Manage video redundancies', function () { | 264 | describe('Manage video redundancies', function () { |
diff --git a/server/tests/helpers/index.ts b/server/tests/helpers/index.ts index 1f0e3098a..1b5c6d15b 100644 --- a/server/tests/helpers/index.ts +++ b/server/tests/helpers/index.ts | |||
@@ -5,3 +5,4 @@ import './dns' | |||
5 | import './image' | 5 | import './image' |
6 | import './markdown' | 6 | import './markdown' |
7 | import './request' | 7 | import './request' |
8 | import './validator' | ||
diff --git a/server/tests/helpers/validator.ts b/server/tests/helpers/validator.ts new file mode 100644 index 000000000..f40a3aaae --- /dev/null +++ b/server/tests/helpers/validator.ts | |||
@@ -0,0 +1,32 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import { expect } from 'chai' | ||
4 | import { isPluginStableOrUnstableVersionValid, isPluginStableVersionValid } from '@server/helpers/custom-validators/plugins' | ||
5 | |||
6 | describe('Validators', function () { | ||
7 | |||
8 | it('Should correctly check stable plugin versions', async function () { | ||
9 | expect(isPluginStableVersionValid('3.4.0')).to.be.true | ||
10 | expect(isPluginStableVersionValid('0.4.0')).to.be.true | ||
11 | expect(isPluginStableVersionValid('0.1.0')).to.be.true | ||
12 | |||
13 | expect(isPluginStableVersionValid('0.1.0-beta-1')).to.be.false | ||
14 | expect(isPluginStableVersionValid('hello')).to.be.false | ||
15 | expect(isPluginStableVersionValid('0.x.a')).to.be.false | ||
16 | }) | ||
17 | |||
18 | it('Should correctly check unstable plugin versions', async function () { | ||
19 | expect(isPluginStableOrUnstableVersionValid('3.4.0')).to.be.true | ||
20 | expect(isPluginStableOrUnstableVersionValid('0.4.0')).to.be.true | ||
21 | expect(isPluginStableOrUnstableVersionValid('0.1.0')).to.be.true | ||
22 | |||
23 | expect(isPluginStableOrUnstableVersionValid('0.1.0-beta.1')).to.be.true | ||
24 | expect(isPluginStableOrUnstableVersionValid('0.1.0-alpha.45')).to.be.true | ||
25 | expect(isPluginStableOrUnstableVersionValid('0.1.0-rc.45')).to.be.true | ||
26 | |||
27 | expect(isPluginStableOrUnstableVersionValid('hello')).to.be.false | ||
28 | expect(isPluginStableOrUnstableVersionValid('0.x.a')).to.be.false | ||
29 | expect(isPluginStableOrUnstableVersionValid('0.1.0-rc-45')).to.be.false | ||
30 | expect(isPluginStableOrUnstableVersionValid('0.1.0-rc.45d')).to.be.false | ||
31 | }) | ||
32 | }) | ||
diff --git a/server/tools/peertube-plugins.ts b/server/tools/peertube-plugins.ts index 47090b3a5..c51d9ebd1 100644 --- a/server/tools/peertube-plugins.ts +++ b/server/tools/peertube-plugins.ts | |||
@@ -69,7 +69,7 @@ async function pluginsListCLI (command: Command, options: OptionValues) { | |||
69 | 69 | ||
70 | const table = new CliTable3({ | 70 | const table = new CliTable3({ |
71 | head: [ 'name', 'version', 'homepage' ], | 71 | head: [ 'name', 'version', 'homepage' ], |
72 | colWidths: [ 50, 10, 50 ] | 72 | colWidths: [ 50, 20, 50 ] |
73 | }) as any | 73 | }) as any |
74 | 74 | ||
75 | for (const plugin of data) { | 75 | for (const plugin of data) { |