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