appstage 0.2.19 → 0.2.20
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/dist/index.cjs +26 -21
- package/dist/index.mjs +26 -21
- package/package.json +1 -1
- package/src/controllers/files.ts +41 -21
package/dist/index.cjs
CHANGED
|
@@ -90,50 +90,55 @@ const files = (params) => {
|
|
|
90
90
|
let exts = p.extensions ?? defaultExtensions;
|
|
91
91
|
let fallthrough = p.fallthrough ?? true;
|
|
92
92
|
return async (req, res, next) => {
|
|
93
|
-
let
|
|
94
|
-
if (!matches(
|
|
93
|
+
let urlPath = typeof p.path === "string" ? p.path : (p.path ?? defaultPath)(req);
|
|
94
|
+
if (!matches(urlPath, p.matches)) {
|
|
95
95
|
if (fallthrough) next();
|
|
96
96
|
else {
|
|
97
|
-
emitLog(req.app, "Unmatched path", { data: {
|
|
97
|
+
emitLog(req.app, "Unmatched path", { data: { urlPath } });
|
|
98
98
|
res.status(404).send(await req.app.renderStatus?.(req, res, {
|
|
99
99
|
code: "unmatched_path",
|
|
100
|
-
|
|
100
|
+
urlPath
|
|
101
101
|
}));
|
|
102
102
|
}
|
|
103
103
|
return;
|
|
104
104
|
}
|
|
105
|
-
if (
|
|
105
|
+
if (urlPath.includes("../")) {
|
|
106
106
|
if (fallthrough) next();
|
|
107
107
|
else {
|
|
108
|
-
emitLog(req.app, "Invalid path (potential traversal attempt)", { data: {
|
|
108
|
+
emitLog(req.app, "Invalid path (potential traversal attempt)", { data: { urlPath } });
|
|
109
109
|
res.status(400).send(await req.app.renderStatus?.(req, res, {
|
|
110
110
|
code: "invalid_path",
|
|
111
|
-
|
|
111
|
+
urlPath
|
|
112
112
|
}));
|
|
113
113
|
}
|
|
114
114
|
return;
|
|
115
115
|
}
|
|
116
116
|
let langs = (p.languages ?? defaultLanguages)(req);
|
|
117
117
|
let filePath = null;
|
|
118
|
+
let urlExt = (0, node_path.extname)(urlPath);
|
|
118
119
|
for (let k = 0; k < bases.length && filePath === null; k++) {
|
|
119
120
|
let base = bases[k];
|
|
120
|
-
if (!
|
|
121
|
-
for (let i = 0; i < langs.length && filePath === null; i++) filePath = await resolve(base, `${
|
|
122
|
-
if (filePath === null
|
|
123
|
-
|
|
124
|
-
|
|
121
|
+
if (!urlPath.endsWith("/")) {
|
|
122
|
+
for (let i = 0; i < langs.length && filePath === null; i++) filePath = await resolve(base, `${urlPath}.${langs[i]}`);
|
|
123
|
+
if (filePath === null && urlExt) {
|
|
124
|
+
let urlPathBase = urlPath.slice(0, -urlExt.length);
|
|
125
|
+
for (let i = 0; i < langs.length && filePath === null; i++) filePath = await resolve(base, `${urlPathBase}.${langs[i]}${urlExt}`);
|
|
126
|
+
}
|
|
127
|
+
if (filePath === null) filePath = await resolve(base, urlPath);
|
|
128
|
+
for (let i = 0; i < langs.length && filePath === null; i++) for (let j = 0; j < exts.length && filePath === null; j++) filePath = await resolve(base, `${urlPath}.${langs[i]}.${exts[j]}`);
|
|
129
|
+
for (let i = 0; i < exts.length && filePath === null; i++) filePath = await resolve(base, `${urlPath}.${exts[i]}`);
|
|
125
130
|
}
|
|
126
|
-
for (let i = 0; i < langs.length && filePath === null; i++) for (let j = 0; j < exts.length && filePath === null; j++) filePath = await resolve(base, `${
|
|
127
|
-
for (let i = 0; i < langs.length && filePath === null; i++) for (let j = 0; j < exts.length && filePath === null; j++) filePath = await resolve(base,
|
|
128
|
-
for (let i = 0; i < exts.length && filePath === null; i++) filePath = await resolve(base,
|
|
131
|
+
for (let i = 0; i < langs.length && filePath === null; i++) for (let j = 0; j < exts.length && filePath === null; j++) filePath = await resolve(base, `${urlPath}.${langs[i]}`, `index.${exts[j]}`);
|
|
132
|
+
for (let i = 0; i < langs.length && filePath === null; i++) for (let j = 0; j < exts.length && filePath === null; j++) filePath = await resolve(base, urlPath, `index.${langs[i]}.${exts[j]}`);
|
|
133
|
+
for (let i = 0; i < exts.length && filePath === null; i++) filePath = await resolve(base, urlPath, `index.${exts[i]}`);
|
|
129
134
|
}
|
|
130
135
|
if (filePath === null) {
|
|
131
136
|
if (fallthrough) next();
|
|
132
137
|
else {
|
|
133
|
-
emitLog(req.app, "Unknown path", { data: {
|
|
138
|
+
emitLog(req.app, "Unknown path", { data: { urlPath } });
|
|
134
139
|
res.status(404).send(await req.app.renderStatus?.(req, res, {
|
|
135
140
|
code: "unknown_path",
|
|
136
|
-
|
|
141
|
+
urlPath
|
|
137
142
|
}));
|
|
138
143
|
}
|
|
139
144
|
return;
|
|
@@ -143,17 +148,17 @@ const files = (params) => {
|
|
|
143
148
|
return;
|
|
144
149
|
}
|
|
145
150
|
let content = (await (0, node_fs_promises.readFile)(filePath)).toString();
|
|
146
|
-
let
|
|
147
|
-
let
|
|
151
|
+
let fileExt = (0, node_path.extname)(filePath);
|
|
152
|
+
let fileName = (0, node_path.basename)(filePath, fileExt);
|
|
148
153
|
for (let transform of p.transform) {
|
|
149
154
|
let result = transform(req, res, {
|
|
150
155
|
content,
|
|
151
156
|
path: filePath,
|
|
152
|
-
name
|
|
157
|
+
name: fileName
|
|
153
158
|
});
|
|
154
159
|
content = result instanceof Promise ? await result : result;
|
|
155
160
|
}
|
|
156
|
-
res.type(
|
|
161
|
+
res.type(fileExt.slice(1)).send(content);
|
|
157
162
|
};
|
|
158
163
|
};
|
|
159
164
|
|
package/dist/index.mjs
CHANGED
|
@@ -64,50 +64,55 @@ const files = (params) => {
|
|
|
64
64
|
let exts = p.extensions ?? defaultExtensions;
|
|
65
65
|
let fallthrough = p.fallthrough ?? true;
|
|
66
66
|
return async (req, res, next) => {
|
|
67
|
-
let
|
|
68
|
-
if (!matches(
|
|
67
|
+
let urlPath = typeof p.path === "string" ? p.path : (p.path ?? defaultPath)(req);
|
|
68
|
+
if (!matches(urlPath, p.matches)) {
|
|
69
69
|
if (fallthrough) next();
|
|
70
70
|
else {
|
|
71
|
-
emitLog(req.app, "Unmatched path", { data: {
|
|
71
|
+
emitLog(req.app, "Unmatched path", { data: { urlPath } });
|
|
72
72
|
res.status(404).send(await req.app.renderStatus?.(req, res, {
|
|
73
73
|
code: "unmatched_path",
|
|
74
|
-
|
|
74
|
+
urlPath
|
|
75
75
|
}));
|
|
76
76
|
}
|
|
77
77
|
return;
|
|
78
78
|
}
|
|
79
|
-
if (
|
|
79
|
+
if (urlPath.includes("../")) {
|
|
80
80
|
if (fallthrough) next();
|
|
81
81
|
else {
|
|
82
|
-
emitLog(req.app, "Invalid path (potential traversal attempt)", { data: {
|
|
82
|
+
emitLog(req.app, "Invalid path (potential traversal attempt)", { data: { urlPath } });
|
|
83
83
|
res.status(400).send(await req.app.renderStatus?.(req, res, {
|
|
84
84
|
code: "invalid_path",
|
|
85
|
-
|
|
85
|
+
urlPath
|
|
86
86
|
}));
|
|
87
87
|
}
|
|
88
88
|
return;
|
|
89
89
|
}
|
|
90
90
|
let langs = (p.languages ?? defaultLanguages)(req);
|
|
91
91
|
let filePath = null;
|
|
92
|
+
let urlExt = extname(urlPath);
|
|
92
93
|
for (let k = 0; k < bases.length && filePath === null; k++) {
|
|
93
94
|
let base = bases[k];
|
|
94
|
-
if (!
|
|
95
|
-
for (let i = 0; i < langs.length && filePath === null; i++) filePath = await resolve$1(base, `${
|
|
96
|
-
if (filePath === null
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
if (!urlPath.endsWith("/")) {
|
|
96
|
+
for (let i = 0; i < langs.length && filePath === null; i++) filePath = await resolve$1(base, `${urlPath}.${langs[i]}`);
|
|
97
|
+
if (filePath === null && urlExt) {
|
|
98
|
+
let urlPathBase = urlPath.slice(0, -urlExt.length);
|
|
99
|
+
for (let i = 0; i < langs.length && filePath === null; i++) filePath = await resolve$1(base, `${urlPathBase}.${langs[i]}${urlExt}`);
|
|
100
|
+
}
|
|
101
|
+
if (filePath === null) filePath = await resolve$1(base, urlPath);
|
|
102
|
+
for (let i = 0; i < langs.length && filePath === null; i++) for (let j = 0; j < exts.length && filePath === null; j++) filePath = await resolve$1(base, `${urlPath}.${langs[i]}.${exts[j]}`);
|
|
103
|
+
for (let i = 0; i < exts.length && filePath === null; i++) filePath = await resolve$1(base, `${urlPath}.${exts[i]}`);
|
|
99
104
|
}
|
|
100
|
-
for (let i = 0; i < langs.length && filePath === null; i++) for (let j = 0; j < exts.length && filePath === null; j++) filePath = await resolve$1(base, `${
|
|
101
|
-
for (let i = 0; i < langs.length && filePath === null; i++) for (let j = 0; j < exts.length && filePath === null; j++) filePath = await resolve$1(base,
|
|
102
|
-
for (let i = 0; i < exts.length && filePath === null; i++) filePath = await resolve$1(base,
|
|
105
|
+
for (let i = 0; i < langs.length && filePath === null; i++) for (let j = 0; j < exts.length && filePath === null; j++) filePath = await resolve$1(base, `${urlPath}.${langs[i]}`, `index.${exts[j]}`);
|
|
106
|
+
for (let i = 0; i < langs.length && filePath === null; i++) for (let j = 0; j < exts.length && filePath === null; j++) filePath = await resolve$1(base, urlPath, `index.${langs[i]}.${exts[j]}`);
|
|
107
|
+
for (let i = 0; i < exts.length && filePath === null; i++) filePath = await resolve$1(base, urlPath, `index.${exts[i]}`);
|
|
103
108
|
}
|
|
104
109
|
if (filePath === null) {
|
|
105
110
|
if (fallthrough) next();
|
|
106
111
|
else {
|
|
107
|
-
emitLog(req.app, "Unknown path", { data: {
|
|
112
|
+
emitLog(req.app, "Unknown path", { data: { urlPath } });
|
|
108
113
|
res.status(404).send(await req.app.renderStatus?.(req, res, {
|
|
109
114
|
code: "unknown_path",
|
|
110
|
-
|
|
115
|
+
urlPath
|
|
111
116
|
}));
|
|
112
117
|
}
|
|
113
118
|
return;
|
|
@@ -117,17 +122,17 @@ const files = (params) => {
|
|
|
117
122
|
return;
|
|
118
123
|
}
|
|
119
124
|
let content = (await readFile(filePath)).toString();
|
|
120
|
-
let
|
|
121
|
-
let
|
|
125
|
+
let fileExt = extname(filePath);
|
|
126
|
+
let fileName = basename(filePath, fileExt);
|
|
122
127
|
for (let transform of p.transform) {
|
|
123
128
|
let result = transform(req, res, {
|
|
124
129
|
content,
|
|
125
130
|
path: filePath,
|
|
126
|
-
name
|
|
131
|
+
name: fileName
|
|
127
132
|
});
|
|
128
133
|
content = result instanceof Promise ? await result : result;
|
|
129
134
|
}
|
|
130
|
-
res.type(
|
|
135
|
+
res.type(fileExt.slice(1)).send(content);
|
|
131
136
|
};
|
|
132
137
|
};
|
|
133
138
|
|
package/package.json
CHANGED
package/src/controllers/files.ts
CHANGED
|
@@ -88,18 +88,18 @@ export const files: Controller<string | FilesParams> = (params) => {
|
|
|
88
88
|
let fallthrough = p.fallthrough ?? true;
|
|
89
89
|
|
|
90
90
|
return async (req, res, next) => {
|
|
91
|
-
let
|
|
91
|
+
let urlPath =
|
|
92
92
|
typeof p.path === "string" ? p.path : (p.path ?? defaultPath)(req);
|
|
93
93
|
|
|
94
|
-
if (!matches(
|
|
94
|
+
if (!matches(urlPath, p.matches)) {
|
|
95
95
|
if (fallthrough) next();
|
|
96
96
|
else {
|
|
97
|
-
emitLog(req.app, "Unmatched path", { data: {
|
|
97
|
+
emitLog(req.app, "Unmatched path", { data: { urlPath } });
|
|
98
98
|
|
|
99
99
|
res.status(404).send(
|
|
100
100
|
await req.app.renderStatus?.(req, res, {
|
|
101
101
|
code: "unmatched_path",
|
|
102
|
-
|
|
102
|
+
urlPath,
|
|
103
103
|
}),
|
|
104
104
|
);
|
|
105
105
|
}
|
|
@@ -107,17 +107,17 @@ export const files: Controller<string | FilesParams> = (params) => {
|
|
|
107
107
|
return;
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
if (
|
|
110
|
+
if (urlPath.includes("../")) {
|
|
111
111
|
if (fallthrough) next();
|
|
112
112
|
else {
|
|
113
113
|
emitLog(req.app, "Invalid path (potential traversal attempt)", {
|
|
114
|
-
data: {
|
|
114
|
+
data: { urlPath },
|
|
115
115
|
});
|
|
116
116
|
|
|
117
117
|
res.status(400).send(
|
|
118
118
|
await req.app.renderStatus?.(req, res, {
|
|
119
119
|
code: "invalid_path",
|
|
120
|
-
|
|
120
|
+
urlPath,
|
|
121
121
|
}),
|
|
122
122
|
);
|
|
123
123
|
}
|
|
@@ -127,28 +127,40 @@ export const files: Controller<string | FilesParams> = (params) => {
|
|
|
127
127
|
|
|
128
128
|
let langs = (p.languages ?? defaultLanguages)(req);
|
|
129
129
|
let filePath: string | null = null;
|
|
130
|
+
let urlExt = extname(urlPath);
|
|
130
131
|
|
|
131
132
|
// Example: path = /x, langs = [en, ru], exts = [html, htm]
|
|
132
133
|
for (let k = 0; k < bases.length && filePath === null; k++) {
|
|
133
134
|
let base = bases[k];
|
|
134
135
|
|
|
135
|
-
if (!
|
|
136
|
+
if (!urlPath.endsWith("/")) {
|
|
136
137
|
// /x.en /x.ru
|
|
137
138
|
for (let i = 0; i < langs.length && filePath === null; i++)
|
|
138
|
-
filePath = await resolve(base, `${
|
|
139
|
+
filePath = await resolve(base, `${urlPath}.${langs[i]}`);
|
|
140
|
+
|
|
141
|
+
if (filePath === null && urlExt) {
|
|
142
|
+
let urlPathBase = urlPath.slice(0, -urlExt.length);
|
|
143
|
+
|
|
144
|
+
// /x.en.ext /x.ru.ext
|
|
145
|
+
for (let i = 0; i < langs.length && filePath === null; i++)
|
|
146
|
+
filePath = await resolve(
|
|
147
|
+
base,
|
|
148
|
+
`${urlPathBase}.${langs[i]}${urlExt}`,
|
|
149
|
+
);
|
|
150
|
+
}
|
|
139
151
|
|
|
140
152
|
// /x
|
|
141
|
-
if (filePath === null) filePath = await resolve(base,
|
|
153
|
+
if (filePath === null) filePath = await resolve(base, urlPath);
|
|
142
154
|
|
|
143
155
|
// /x.en.html /x.en.htm /x.ru.html /x.ru.htm
|
|
144
156
|
for (let i = 0; i < langs.length && filePath === null; i++) {
|
|
145
157
|
for (let j = 0; j < exts.length && filePath === null; j++)
|
|
146
|
-
filePath = await resolve(base, `${
|
|
158
|
+
filePath = await resolve(base, `${urlPath}.${langs[i]}.${exts[j]}`);
|
|
147
159
|
}
|
|
148
160
|
|
|
149
161
|
// /x.html /x.htm
|
|
150
162
|
for (let i = 0; i < exts.length && filePath === null; i++)
|
|
151
|
-
filePath = await resolve(base, `${
|
|
163
|
+
filePath = await resolve(base, `${urlPath}.${exts[i]}`);
|
|
152
164
|
}
|
|
153
165
|
|
|
154
166
|
// /x.en/index.html /x.en/index.htm /x.ru/index.html /x.ru/index.htm
|
|
@@ -156,7 +168,7 @@ export const files: Controller<string | FilesParams> = (params) => {
|
|
|
156
168
|
for (let j = 0; j < exts.length && filePath === null; j++)
|
|
157
169
|
filePath = await resolve(
|
|
158
170
|
base,
|
|
159
|
-
`${
|
|
171
|
+
`${urlPath}.${langs[i]}`,
|
|
160
172
|
`index.${exts[j]}`,
|
|
161
173
|
);
|
|
162
174
|
}
|
|
@@ -164,23 +176,27 @@ export const files: Controller<string | FilesParams> = (params) => {
|
|
|
164
176
|
// /x/index.en.html /x/index.en.htm /x/index.ru.html /x/index.ru.htm
|
|
165
177
|
for (let i = 0; i < langs.length && filePath === null; i++) {
|
|
166
178
|
for (let j = 0; j < exts.length && filePath === null; j++)
|
|
167
|
-
filePath = await resolve(
|
|
179
|
+
filePath = await resolve(
|
|
180
|
+
base,
|
|
181
|
+
urlPath,
|
|
182
|
+
`index.${langs[i]}.${exts[j]}`,
|
|
183
|
+
);
|
|
168
184
|
}
|
|
169
185
|
|
|
170
186
|
// /x/index.html /x/index.htm
|
|
171
187
|
for (let i = 0; i < exts.length && filePath === null; i++)
|
|
172
|
-
filePath = await resolve(base,
|
|
188
|
+
filePath = await resolve(base, urlPath, `index.${exts[i]}`);
|
|
173
189
|
}
|
|
174
190
|
|
|
175
191
|
if (filePath === null) {
|
|
176
192
|
if (fallthrough) next();
|
|
177
193
|
else {
|
|
178
|
-
emitLog(req.app, "Unknown path", { data: {
|
|
194
|
+
emitLog(req.app, "Unknown path", { data: { urlPath } });
|
|
179
195
|
|
|
180
196
|
res.status(404).send(
|
|
181
197
|
await req.app.renderStatus?.(req, res, {
|
|
182
198
|
code: "unknown_path",
|
|
183
|
-
|
|
199
|
+
urlPath,
|
|
184
200
|
}),
|
|
185
201
|
);
|
|
186
202
|
}
|
|
@@ -194,15 +210,19 @@ export const files: Controller<string | FilesParams> = (params) => {
|
|
|
194
210
|
}
|
|
195
211
|
|
|
196
212
|
let content = (await readFile(filePath)).toString();
|
|
197
|
-
let
|
|
198
|
-
let
|
|
213
|
+
let fileExt = extname(filePath);
|
|
214
|
+
let fileName = basename(filePath, fileExt);
|
|
199
215
|
|
|
200
216
|
for (let transform of p.transform) {
|
|
201
|
-
let result = transform(req, res, {
|
|
217
|
+
let result = transform(req, res, {
|
|
218
|
+
content,
|
|
219
|
+
path: filePath,
|
|
220
|
+
name: fileName,
|
|
221
|
+
});
|
|
202
222
|
|
|
203
223
|
content = result instanceof Promise ? await result : result;
|
|
204
224
|
}
|
|
205
225
|
|
|
206
|
-
res.type(
|
|
226
|
+
res.type(fileExt.slice(1)).send(content);
|
|
207
227
|
};
|
|
208
228
|
};
|