]>
Commit | Line | Data |
---|---|---|
7cde3b9c | 1 | import validator from 'validator' |
ff91b644 | 2 | import { PluginPackageJSON } from '../../../shared/models/plugins/plugin-package-json.model' |
345da516 C |
3 | import { PluginType } from '../../../shared/models/plugins/plugin.type' |
4 | import { CONSTRAINTS_FIELDS } from '../../initializers/constants' | |
345da516 | 5 | import { isUrlValid } from './activitypub/misc' |
ff91b644 | 6 | import { exists, isArray, isSafePath } from './misc' |
345da516 C |
7 | |
8 | const PLUGINS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.PLUGINS | |
9 | ||
10 | function isPluginTypeValid (value: any) { | |
bd45d503 C |
11 | return exists(value) && |
12 | (value === PluginType.PLUGIN || value === PluginType.THEME) | |
345da516 C |
13 | } |
14 | ||
15 | function isPluginNameValid (value: string) { | |
16 | return exists(value) && | |
17 | validator.isLength(value, PLUGINS_CONSTRAINTS_FIELDS.NAME) && | |
5644f9b0 | 18 | validator.matches(value, /^[a-z-0-9]+$/) |
345da516 C |
19 | } |
20 | ||
f023a19c C |
21 | function isNpmPluginNameValid (value: string) { |
22 | return exists(value) && | |
23 | validator.isLength(value, PLUGINS_CONSTRAINTS_FIELDS.NAME) && | |
c10b638c | 24 | validator.matches(value, /^[a-z\-._0-9]+$/) && |
f023a19c C |
25 | (value.startsWith('peertube-plugin-') || value.startsWith('peertube-theme-')) |
26 | } | |
27 | ||
345da516 C |
28 | function isPluginDescriptionValid (value: string) { |
29 | return exists(value) && validator.isLength(value, PLUGINS_CONSTRAINTS_FIELDS.DESCRIPTION) | |
30 | } | |
31 | ||
ff91b644 | 32 | function isPluginStableVersionValid (value: string) { |
345da516 C |
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 | ||
ff91b644 C |
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 | ||
345da516 C |
53 | function isPluginEngineValid (engine: any) { |
54 | return exists(engine) && exists(engine.peertube) | |
55 | } | |
56 | ||
dba85a1e | 57 | function isPluginHomepage (value: string) { |
485b2fb2 C |
58 | return exists(value) && (!value || isUrlValid(value)) |
59 | } | |
60 | ||
61 | function isPluginBugs (value: string) { | |
62 | return exists(value) && (!value || isUrlValid(value)) | |
dba85a1e C |
63 | } |
64 | ||
d75db01f | 65 | function areStaticDirectoriesValid (staticDirs: any) { |
345da516 C |
66 | if (!exists(staticDirs) || typeof staticDirs !== 'object') return false |
67 | ||
68 | for (const key of Object.keys(staticDirs)) { | |
69 | if (!isSafePath(staticDirs[key])) return false | |
70 | } | |
71 | ||
72 | return true | |
73 | } | |
74 | ||
d75db01f | 75 | function areClientScriptsValid (clientScripts: any[]) { |
345da516 C |
76 | return isArray(clientScripts) && |
77 | clientScripts.every(c => { | |
78 | return isSafePath(c.script) && isArray(c.scopes) | |
79 | }) | |
80 | } | |
81 | ||
d75db01f C |
82 | function areTranslationPathsValid (translations: any) { |
83 | if (!exists(translations) || typeof translations !== 'object') return false | |
84 | ||
85 | for (const key of Object.keys(translations)) { | |
86 | if (!isSafePath(translations[key])) return false | |
87 | } | |
88 | ||
89 | return true | |
90 | } | |
91 | ||
92 | function areCSSPathsValid (css: any[]) { | |
345da516 C |
93 | return isArray(css) && css.every(c => isSafePath(c)) |
94 | } | |
95 | ||
503c6f44 C |
96 | function isThemeNameValid (name: string) { |
97 | return isPluginNameValid(name) | |
7cd4d2ba C |
98 | } |
99 | ||
c7cdac44 | 100 | function isPackageJSONValid (packageJSON: PluginPackageJSON, pluginType: PluginType) { |
9157d598 C |
101 | let result = true |
102 | const badFields: string[] = [] | |
103 | ||
104 | if (!isNpmPluginNameValid(packageJSON.name)) { | |
105 | result = false | |
106 | badFields.push('name') | |
107 | } | |
108 | ||
109 | if (!isPluginDescriptionValid(packageJSON.description)) { | |
110 | result = false | |
111 | badFields.push('description') | |
112 | } | |
113 | ||
114 | if (!isPluginEngineValid(packageJSON.engine)) { | |
115 | result = false | |
116 | badFields.push('engine') | |
117 | } | |
118 | ||
119 | if (!isPluginHomepage(packageJSON.homepage)) { | |
120 | result = false | |
121 | badFields.push('homepage') | |
122 | } | |
123 | ||
124 | if (!exists(packageJSON.author)) { | |
125 | result = false | |
126 | badFields.push('author') | |
127 | } | |
128 | ||
129 | if (!isPluginBugs(packageJSON.bugs)) { | |
130 | result = false | |
131 | badFields.push('bugs') | |
132 | } | |
133 | ||
134 | if (pluginType === PluginType.PLUGIN && !isSafePath(packageJSON.library)) { | |
135 | result = false | |
136 | badFields.push('library') | |
137 | } | |
138 | ||
139 | if (!areStaticDirectoriesValid(packageJSON.staticDirs)) { | |
140 | result = false | |
141 | badFields.push('staticDirs') | |
142 | } | |
143 | ||
144 | if (!areCSSPathsValid(packageJSON.css)) { | |
145 | result = false | |
146 | badFields.push('css') | |
147 | } | |
148 | ||
149 | if (!areClientScriptsValid(packageJSON.clientScripts)) { | |
150 | result = false | |
151 | badFields.push('clientScripts') | |
152 | } | |
153 | ||
154 | if (!areTranslationPathsValid(packageJSON.translations)) { | |
155 | result = false | |
156 | badFields.push('translations') | |
157 | } | |
158 | ||
159 | return { result, badFields } | |
345da516 C |
160 | } |
161 | ||
162 | function isLibraryCodeValid (library: any) { | |
a1587156 C |
163 | return typeof library.register === 'function' && |
164 | typeof library.unregister === 'function' | |
345da516 C |
165 | } |
166 | ||
167 | export { | |
168 | isPluginTypeValid, | |
169 | isPackageJSONValid, | |
503c6f44 | 170 | isThemeNameValid, |
dba85a1e | 171 | isPluginHomepage, |
ff91b644 C |
172 | isPluginStableVersionValid, |
173 | isPluginStableOrUnstableVersionValid, | |
345da516 C |
174 | isPluginNameValid, |
175 | isPluginDescriptionValid, | |
f023a19c C |
176 | isLibraryCodeValid, |
177 | isNpmPluginNameValid | |
345da516 | 178 | } |