@flowfuse/nr-launcher 3.1.1-df4cf86-202609281615.0 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
#### 3.1.1: Release
|
|
2
|
+
|
|
3
|
+
- fix: Refuse deleting the file store root and sibling paths that share its prefix (#634)
|
|
4
|
+
- chore: Override moment (#633)
|
|
5
|
+
- chore: Override uuid@8 to 11.1.1 (#632)
|
|
6
|
+
- Bump brace-expansion (#629)
|
|
7
|
+
- Bump serialize-javascript from 7.1.1 to 7.1.2 (#631)
|
|
8
|
+
- Bump fastify from 5.12.1 to 5.12.5 (#630)
|
|
9
|
+
- Bump fast-uri (#628)
|
|
10
|
+
- Bump ip-address from 10.4.0 to 10.7.2 (#627)
|
|
11
|
+
- Bump multer from 2.3.0 to 2.4.0 (#626)
|
|
12
|
+
- Update versions of nr-mqtt & nr-tables (#625)
|
|
13
|
+
- Update File-Server reference (#624)
|
|
14
|
+
|
|
1
15
|
#### 3.1.0: Release
|
|
2
16
|
|
|
3
17
|
- Update launcher to assistant@0.20 (#622)
|
package/lib/files/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const { mkdir, readdir, rm, rename, stat, writeFile } = require('fs/promises')
|
|
2
2
|
const { existsSync } = require('fs')
|
|
3
|
-
const { dirname, join, normalize } = require('path')
|
|
3
|
+
const { dirname, join, normalize, sep } = require('path')
|
|
4
4
|
const multer = require('multer')
|
|
5
5
|
|
|
6
6
|
const filesInterface = (app, settings) => {
|
|
@@ -9,11 +9,18 @@ const filesInterface = (app, settings) => {
|
|
|
9
9
|
const storage = multer.memoryStorage()
|
|
10
10
|
const upload = multer({ storage })
|
|
11
11
|
|
|
12
|
+
const resolvePath = (path = '') => {
|
|
13
|
+
const fullPath = normalize(join(BASE_PATH, path))
|
|
14
|
+
return fullPath.replace(/[\\/]+$/, '')
|
|
15
|
+
}
|
|
16
|
+
const isInsideBase = (fullPath) => fullPath.startsWith(BASE_PATH + sep)
|
|
17
|
+
const isBaseOrInside = (fullPath) => fullPath === BASE_PATH || isInsideBase(fullPath)
|
|
18
|
+
|
|
12
19
|
const regex = /^\/flowforge\/files\/_\/(.*)$/
|
|
13
20
|
|
|
14
21
|
const listDirectory = async (path = '') => {
|
|
15
|
-
const fullPath =
|
|
16
|
-
if (fullPath
|
|
22
|
+
const fullPath = resolvePath(path)
|
|
23
|
+
if (isBaseOrInside(fullPath)) {
|
|
17
24
|
const files = await readdir(fullPath, { withFileTypes: true })
|
|
18
25
|
const response = {
|
|
19
26
|
meta: { },
|
|
@@ -58,9 +65,9 @@ const filesInterface = (app, settings) => {
|
|
|
58
65
|
})
|
|
59
66
|
|
|
60
67
|
app.put(regex, async (request, reply) => {
|
|
61
|
-
const fullPath =
|
|
62
|
-
const newPath =
|
|
63
|
-
if (fullPath
|
|
68
|
+
const fullPath = resolvePath(request.params[0])
|
|
69
|
+
const newPath = resolvePath(request.body.path)
|
|
70
|
+
if (isInsideBase(fullPath) && isInsideBase(newPath)) {
|
|
64
71
|
if (existsSync(fullPath) && existsSync(dirname(newPath))) {
|
|
65
72
|
try {
|
|
66
73
|
await rename(fullPath, newPath)
|
|
@@ -76,12 +83,12 @@ const filesInterface = (app, settings) => {
|
|
|
76
83
|
})
|
|
77
84
|
|
|
78
85
|
app.post(regex, upload.single('file'), async (request, reply) => {
|
|
79
|
-
const startPath =
|
|
80
|
-
if (startPath
|
|
86
|
+
const startPath = resolvePath(request.params[0])
|
|
87
|
+
if (isBaseOrInside(startPath)) {
|
|
81
88
|
if (request.get('content-type') === 'application/json') {
|
|
82
89
|
const newPath = request.body.path
|
|
83
|
-
const fullPath =
|
|
84
|
-
if (fullPath
|
|
90
|
+
const fullPath = resolvePath(join(startPath.slice(BASE_PATH.length), newPath))
|
|
91
|
+
if (isBaseOrInside(fullPath)) {
|
|
85
92
|
try {
|
|
86
93
|
await mkdir(fullPath, { recursive: true })
|
|
87
94
|
reply.status(201).send()
|
|
@@ -93,7 +100,9 @@ const filesInterface = (app, settings) => {
|
|
|
93
100
|
}
|
|
94
101
|
} else if (request.get('content-type').startsWith('multipart/form-data')) {
|
|
95
102
|
const targetDir = dirname(startPath)
|
|
96
|
-
if (
|
|
103
|
+
if (!isInsideBase(startPath)) {
|
|
104
|
+
reply.status(403).send()
|
|
105
|
+
} else if (existsSync(targetDir)) {
|
|
97
106
|
await writeFile(startPath, request.file.buffer)
|
|
98
107
|
reply.status(201).send()
|
|
99
108
|
} else {
|
|
@@ -108,8 +117,8 @@ const filesInterface = (app, settings) => {
|
|
|
108
117
|
})
|
|
109
118
|
|
|
110
119
|
app.delete(regex, async (request, reply) => {
|
|
111
|
-
const fullPath =
|
|
112
|
-
if (fullPath
|
|
120
|
+
const fullPath = resolvePath(request.params[0])
|
|
121
|
+
if (isInsideBase(fullPath)) {
|
|
113
122
|
if (existsSync(fullPath)) {
|
|
114
123
|
try {
|
|
115
124
|
await rm(fullPath, {
|