]>
Commit | Line | Data |
---|---|---|
1 | import { exists, isArray, isSafePath } from './misc' | |
2 | import * as validator from 'validator' | |
3 | import { PluginType } from '../../../shared/models/plugins/plugin.type' | |
4 | import { CONSTRAINTS_FIELDS } from '../../initializers/constants' | |
5 | import { PluginPackageJson } from '../../../shared/models/plugins/plugin-package-json.model' | |
6 | import { isUrlValid } from './activitypub/misc' | |
7 | import { isThemeRegistered } from '../../lib/plugins/theme-utils' | |
8 | ||
9 | const PLUGINS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.PLUGINS | |
10 | ||
11 | function isPluginTypeValid (value: any) { | |
12 | return exists(value) && validator.isInt('' + value) && PluginType[value] !== undefined | |
13 | } | |
14 | ||
15 | function isPluginNameValid (value: string) { | |
16 | return exists(value) && | |
17 | validator.isLength(value, PLUGINS_CONSTRAINTS_FIELDS.NAME) && | |
18 | validator.matches(value, /^[a-z\-]+$/) | |
19 | } | |
20 | ||
21 | function isNpmPluginNameValid (value: string) { | |
22 | return exists(value) && | |
23 | validator.isLength(value, PLUGINS_CONSTRAINTS_FIELDS.NAME) && | |
24 | validator.matches(value, /^[a-z\-]+$/) && | |
25 | (value.startsWith('peertube-plugin-') || value.startsWith('peertube-theme-')) | |
26 | } | |
27 | ||
28 | function isPluginDescriptionValid (value: string) { | |
29 | return exists(value) && validator.isLength(value, PLUGINS_CONSTRAINTS_FIELDS.DESCRIPTION) | |
30 | } | |
31 | ||
32 | function isPluginVersionValid (value: string) { | |
33 | if (!exists(value)) return false | |
34 | ||
35 | const parts = (value + '').split('.') | |
36 | ||
37 | return parts.length === 3 && parts.every(p => validator.isInt(p)) | |
38 | } | |
39 | ||
40 | function isPluginEngineValid (engine: any) { | |
41 | return exists(engine) && exists(engine.peertube) | |
42 | } | |
43 | ||
44 | function isPluginHomepage (value: string) { | |
45 | return isUrlValid(value) | |
46 | } | |
47 | ||
48 | function isStaticDirectoriesValid (staticDirs: any) { | |
49 | if (!exists(staticDirs) || typeof staticDirs !== 'object') return false | |
50 | ||
51 | for (const key of Object.keys(staticDirs)) { | |
52 | if (!isSafePath(staticDirs[key])) return false | |
53 | } | |
54 | ||
55 | return true | |
56 | } | |
57 | ||
58 | function isClientScriptsValid (clientScripts: any[]) { | |
59 | return isArray(clientScripts) && | |
60 | clientScripts.every(c => { | |
61 | return isSafePath(c.script) && isArray(c.scopes) | |
62 | }) | |
63 | } | |
64 | ||
65 | function isCSSPathsValid (css: any[]) { | |
66 | return isArray(css) && css.every(c => isSafePath(c)) | |
67 | } | |
68 | ||
69 | function isThemeValid (name: string) { | |
70 | return isPluginNameValid(name) && isThemeRegistered(name) | |
71 | } | |
72 | ||
73 | function isPackageJSONValid (packageJSON: PluginPackageJson, pluginType: PluginType) { | |
74 | return isNpmPluginNameValid(packageJSON.name) && | |
75 | isPluginDescriptionValid(packageJSON.description) && | |
76 | isPluginEngineValid(packageJSON.engine) && | |
77 | isPluginHomepage(packageJSON.homepage) && | |
78 | exists(packageJSON.author) && | |
79 | isUrlValid(packageJSON.bugs) && | |
80 | (pluginType === PluginType.THEME || isSafePath(packageJSON.library)) && | |
81 | isStaticDirectoriesValid(packageJSON.staticDirs) && | |
82 | isCSSPathsValid(packageJSON.css) && | |
83 | isClientScriptsValid(packageJSON.clientScripts) | |
84 | } | |
85 | ||
86 | function isLibraryCodeValid (library: any) { | |
87 | return typeof library.register === 'function' | |
88 | && typeof library.unregister === 'function' | |
89 | } | |
90 | ||
91 | export { | |
92 | isPluginTypeValid, | |
93 | isPackageJSONValid, | |
94 | isThemeValid, | |
95 | isPluginHomepage, | |
96 | isPluginVersionValid, | |
97 | isPluginNameValid, | |
98 | isPluginDescriptionValid, | |
99 | isLibraryCodeValid, | |
100 | isNpmPluginNameValid | |
101 | } |