@@ -212,7 +212,7 @@ class DataSourceService @Inject()(
212
212
.exploreMappings(dataBaseDir.resolve(organizationId).resolve(datasetName).resolve(dataLayerName))
213
213
.getOrElse(Set ())
214
214
215
- private def validateDataSource (dataSource : DataSource ): Box [Unit ] = {
215
+ private def validateDataSource (dataSource : DataSource , organizationDir : Path ): Box [Unit ] = {
216
216
def Check (expression : Boolean , msg : String ): Option [String ] = if (! expression) Some (msg) else None
217
217
218
218
// Check that when mags are sorted by max dimension, all dimensions are sorted.
@@ -222,6 +222,16 @@ class DataSourceService @Inject()(
222
222
val magsYIsSorted = magsSorted.map(_.map(_.y)) == magsSorted.map(_.map(_.y).sorted)
223
223
val magsZIsSorted = magsSorted.map(_.map(_.z)) == magsSorted.map(_.map(_.z).sorted)
224
224
225
+ def pathOk (pathStr : String ): Boolean = {
226
+ val uri = new URI (pathStr)
227
+ if (DataVaultService .isRemoteScheme(uri.getScheme)) true
228
+ else {
229
+ val path = Path .of(new URI (pathStr).getPath).normalize().toAbsolutePath
230
+ val allowedParent = organizationDir.toAbsolutePath
231
+ if (path.startsWith(allowedParent)) true else false
232
+ }
233
+ }
234
+
225
235
val errors = List (
226
236
Check (dataSource.scale.factor.isStrictlyPositive, " DataSource voxel size (scale) is invalid" ),
227
237
Check (magsXIsSorted && magsYIsSorted && magsZIsSorted, " Mags do not monotonically increase in all dimensions" ),
@@ -242,6 +252,10 @@ class DataSourceService @Inject()(
242
252
Check (
243
253
dataSource.dataLayers.map(_.name).distinct.length == dataSource.dataLayers.length,
244
254
" Layer names must be unique. At least two layers have the same name."
255
+ ),
256
+ Check (
257
+ dataSource.dataLayers.flatMap(_.mags).flatMap(_.path).forall(pathOk),
258
+ " Mags with explicit paths must stay within the organization directory."
245
259
)
246
260
).flatten
247
261
@@ -252,17 +266,19 @@ class DataSourceService @Inject()(
252
266
}
253
267
}
254
268
255
- def updateDataSource (dataSource : DataSource , expectExisting : Boolean ): Fox [Unit ] =
269
+ def updateDataSource (dataSource : DataSource , expectExisting : Boolean ): Fox [Unit ] = {
270
+ val organizationDir = dataBaseDir.resolve(dataSource.id.organizationId)
271
+ val dataSourcePath = organizationDir.resolve(dataSource.id.directoryName)
256
272
for {
257
- _ <- validateDataSource(dataSource).toFox
258
- dataSourcePath = dataBaseDir.resolve(dataSource.id.organizationId).resolve(dataSource.id.directoryName)
273
+ _ <- validateDataSource(dataSource, organizationDir).toFox
259
274
propertiesFile = dataSourcePath.resolve(propertiesFileName)
260
275
_ <- Fox .runIf(! expectExisting)(ensureDirectoryBox(dataSourcePath))
261
276
_ <- Fox .runIf(! expectExisting)(bool2Fox(! Files .exists(propertiesFile))) ?~> " dataSource.alreadyPresent"
262
277
_ <- Fox .runIf(expectExisting)(backupPreviousProperties(dataSourcePath)) ?~> " Could not update datasource-properties.json"
263
278
_ <- JsonHelper .jsonToFile(propertiesFile, dataSource) ?~> " Could not update datasource-properties.json"
264
279
_ <- dataSourceRepository.updateDataSource(dataSource)
265
280
} yield ()
281
+ }
266
282
267
283
private def backupPreviousProperties (dataSourcePath : Path ): Box [Unit ] = {
268
284
val propertiesFile = dataSourcePath.resolve(propertiesFileName)
0 commit comments