@tinacms/cli 2.5.1 → 2.5.2
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/cmds/forestry-migrate/index.d.ts +1 -1
- package/dist/cmds/forestry-migrate/util/codeTransformer.d.ts +1 -1
- package/dist/index.js +39 -28
- package/dist/next/vite/cors.d.ts +13 -1
- package/package.json +10 -11
- package/dist/server/index.d.ts +0 -4
- package/dist/server/models/media.d.ts +0 -56
- package/dist/server/routes/index.d.ts +0 -6
- package/dist/server/server.d.ts +0 -5
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Cli, Builtins } from "clipanion";
|
|
3
3
|
|
|
4
4
|
// package.json
|
|
5
|
-
var version = "2.5.
|
|
5
|
+
var version = "2.5.2";
|
|
6
6
|
|
|
7
7
|
// src/next/commands/dev-command/index.ts
|
|
8
8
|
import path10 from "path";
|
|
@@ -1699,32 +1699,30 @@ function expandOrigins(raw) {
|
|
|
1699
1699
|
const filtered = raw.filter((o) => o !== "private");
|
|
1700
1700
|
return hasPrivate ? [...filtered, PRIVATE_NETWORK_RE] : filtered;
|
|
1701
1701
|
}
|
|
1702
|
-
function
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
}
|
|
1719
|
-
} else {
|
|
1720
|
-
allowed.lastIndex = 0;
|
|
1721
|
-
if (allowed.test(origin)) {
|
|
1722
|
-
callback(null, true);
|
|
1723
|
-
return;
|
|
1724
|
-
}
|
|
1702
|
+
function isOriginAllowed(origin, allowedOrigins = []) {
|
|
1703
|
+
if (!origin) {
|
|
1704
|
+
return true;
|
|
1705
|
+
}
|
|
1706
|
+
if (LOCALHOST_RE.test(origin)) {
|
|
1707
|
+
return true;
|
|
1708
|
+
}
|
|
1709
|
+
for (const allowed of expandOrigins(allowedOrigins)) {
|
|
1710
|
+
if (typeof allowed === "string") {
|
|
1711
|
+
if (allowed === origin) {
|
|
1712
|
+
return true;
|
|
1713
|
+
}
|
|
1714
|
+
} else {
|
|
1715
|
+
allowed.lastIndex = 0;
|
|
1716
|
+
if (allowed.test(origin)) {
|
|
1717
|
+
return true;
|
|
1725
1718
|
}
|
|
1726
1719
|
}
|
|
1727
|
-
|
|
1720
|
+
}
|
|
1721
|
+
return false;
|
|
1722
|
+
}
|
|
1723
|
+
function buildCorsOriginCheck(allowedOrigins = []) {
|
|
1724
|
+
return (origin, callback) => {
|
|
1725
|
+
callback(null, isOriginAllowed(origin, allowedOrigins));
|
|
1728
1726
|
};
|
|
1729
1727
|
}
|
|
1730
1728
|
|
|
@@ -2582,9 +2580,17 @@ var devServerEndPointsPlugin = ({
|
|
|
2582
2580
|
searchIndex,
|
|
2583
2581
|
databaseLock
|
|
2584
2582
|
}) => {
|
|
2585
|
-
const
|
|
2586
|
-
|
|
2587
|
-
)
|
|
2583
|
+
const allowedOrigins = configManager.config?.server?.allowedOrigins;
|
|
2584
|
+
const corsOriginCheck = buildCorsOriginCheck(allowedOrigins);
|
|
2585
|
+
const isStateChangingRequest = (req) => {
|
|
2586
|
+
const url = req.url || "";
|
|
2587
|
+
if (url.startsWith("/media/upload")) return true;
|
|
2588
|
+
if (url.startsWith("/media") && req.method === "DELETE") return true;
|
|
2589
|
+
if (url.startsWith("/graphql") && req.method === "POST") return true;
|
|
2590
|
+
if ((url.startsWith("/searchIndex") || url.startsWith("/v2/searchIndex")) && (req.method === "POST" || req.method === "DELETE"))
|
|
2591
|
+
return true;
|
|
2592
|
+
return false;
|
|
2593
|
+
};
|
|
2588
2594
|
const plug = {
|
|
2589
2595
|
name: "graphql-endpoints",
|
|
2590
2596
|
configureServer(server) {
|
|
@@ -2607,6 +2613,11 @@ var devServerEndPointsPlugin = ({
|
|
|
2607
2613
|
config: { apiURL, searchPath: "searchIndex" },
|
|
2608
2614
|
searchIndex
|
|
2609
2615
|
});
|
|
2616
|
+
if (isStateChangingRequest(req) && !isOriginAllowed(req.headers.origin, allowedOrigins)) {
|
|
2617
|
+
res.statusCode = 403;
|
|
2618
|
+
res.end(JSON.stringify({ error: "Origin not allowed" }));
|
|
2619
|
+
return;
|
|
2620
|
+
}
|
|
2610
2621
|
if (req.url.startsWith("/media/upload")) {
|
|
2611
2622
|
await mediaRouter.handlePost(req, res);
|
|
2612
2623
|
return;
|
package/dist/next/vite/cors.d.ts
CHANGED
|
@@ -8,6 +8,18 @@
|
|
|
8
8
|
* bridge networks, etc.
|
|
9
9
|
*/
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
11
|
+
* Decide whether a request `Origin` is allowed to reach the dev server.
|
|
12
|
+
*
|
|
13
|
+
* No `Origin` (curl, same-origin, CLI tooling) and localhost are always
|
|
14
|
+
* allowed; extra `allowedOrigins` (with `'private'` expanded) match by exact
|
|
15
|
+
* string or RegExp.
|
|
16
|
+
*/
|
|
17
|
+
export declare function isOriginAllowed(origin: string | undefined, allowedOrigins?: (string | RegExp)[]): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Build a CORS `origin` callback for the `cors` npm package.
|
|
20
|
+
*
|
|
21
|
+
* NOTE: `cors` only uses this to set the `Access-Control-Allow-Origin` header;
|
|
22
|
+
* it does NOT reject disallowed requests server-side. State-changing routes
|
|
23
|
+
* must also gate on {@link isOriginAllowed} (see plugins.ts).
|
|
12
24
|
*/
|
|
13
25
|
export declare function buildCorsOriginCheck(allowedOrigins?: (string | RegExp)[]): (origin: string | undefined, callback: (err: Error | null, allow?: boolean) => void) => void;
|
package/package.json
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tinacms/cli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.5.
|
|
4
|
+
"version": "2.5.2",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"typings": "dist/index.d.ts",
|
|
7
7
|
"files": [
|
|
8
8
|
"dist",
|
|
9
|
-
"bin/*"
|
|
10
|
-
".env"
|
|
9
|
+
"bin/*"
|
|
11
10
|
],
|
|
12
11
|
"license": "Apache-2.0",
|
|
13
12
|
"bin": {
|
|
@@ -44,11 +43,11 @@
|
|
|
44
43
|
"mongodb-level": "^0.0.4",
|
|
45
44
|
"sqlite-level": "^2.1.0",
|
|
46
45
|
"ts-jest": "^29.2.5",
|
|
47
|
-
"@tinacms/scripts": "1.6.
|
|
46
|
+
"@tinacms/scripts": "1.6.2"
|
|
48
47
|
},
|
|
49
48
|
"dependencies": {
|
|
50
49
|
"@graphql-codegen/core": "^2.6.8",
|
|
51
|
-
"@graphql-codegen/plugin-helpers": "
|
|
50
|
+
"@graphql-codegen/plugin-helpers": "^7.0.1",
|
|
52
51
|
"@graphql-codegen/typescript": "^4.1.3",
|
|
53
52
|
"@graphql-codegen/typescript-operations": "^4.4.1",
|
|
54
53
|
"@graphql-codegen/visitor-plugin-common": "^4.1.2",
|
|
@@ -92,12 +91,12 @@
|
|
|
92
91
|
"vite": "^4.5.9",
|
|
93
92
|
"yup": "^1.6.1",
|
|
94
93
|
"zod": "^3.24.2",
|
|
95
|
-
"@tinacms/app": "2.5.
|
|
96
|
-
"@tinacms/
|
|
97
|
-
"@tinacms/
|
|
98
|
-
"tinacms": "
|
|
99
|
-
"
|
|
100
|
-
"@tinacms/
|
|
94
|
+
"@tinacms/app": "2.5.7",
|
|
95
|
+
"@tinacms/schema-tools": "2.8.2",
|
|
96
|
+
"@tinacms/graphql": "2.4.6",
|
|
97
|
+
"@tinacms/search": "1.2.20",
|
|
98
|
+
"tinacms": "3.9.4",
|
|
99
|
+
"@tinacms/metrics": "2.1.1"
|
|
101
100
|
},
|
|
102
101
|
"publishConfig": {
|
|
103
102
|
"registry": "https://registry.npmjs.org"
|
package/dist/server/index.d.ts
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
*/
|
|
4
|
-
interface MediaArgs {
|
|
5
|
-
searchPath: string;
|
|
6
|
-
cursor?: string;
|
|
7
|
-
limit?: string;
|
|
8
|
-
}
|
|
9
|
-
interface File {
|
|
10
|
-
src: string;
|
|
11
|
-
filename: string;
|
|
12
|
-
size: number;
|
|
13
|
-
}
|
|
14
|
-
interface ListMediaRes {
|
|
15
|
-
directories: string[];
|
|
16
|
-
files: File[];
|
|
17
|
-
cursor?: string;
|
|
18
|
-
error?: string;
|
|
19
|
-
}
|
|
20
|
-
export interface PathConfig {
|
|
21
|
-
rootPath: string;
|
|
22
|
-
publicFolder: string;
|
|
23
|
-
mediaRoot: string;
|
|
24
|
-
}
|
|
25
|
-
type SuccessRecord = {
|
|
26
|
-
ok: true;
|
|
27
|
-
} | {
|
|
28
|
-
ok: false;
|
|
29
|
-
message: string;
|
|
30
|
-
};
|
|
31
|
-
/**
|
|
32
|
-
* Handles media file operations (list, delete) for the Express-based server.
|
|
33
|
-
*
|
|
34
|
-
* @security Every method that accepts a user-supplied `searchPath` validates
|
|
35
|
-
* it against the media root using `resolveWithinBase` (list) or
|
|
36
|
-
* `resolveStrictlyWithinBase` (delete) before any filesystem access.
|
|
37
|
-
*
|
|
38
|
-
* - **list** uses `resolveWithinBase` because listing the media root itself
|
|
39
|
-
* (empty path / exact base match) is a valid operation.
|
|
40
|
-
* - **delete** uses `resolveStrictlyWithinBase` because deleting the media
|
|
41
|
-
* root directory itself must never be allowed.
|
|
42
|
-
*
|
|
43
|
-
* Both methods catch `PathTraversalError` and re-throw it so that the
|
|
44
|
-
* route handler can return a 403 response. Other errors are caught and
|
|
45
|
-
* returned as structured error responses (this avoids leaking stack traces
|
|
46
|
-
* to the client).
|
|
47
|
-
*/
|
|
48
|
-
export declare class MediaModel {
|
|
49
|
-
readonly rootPath: string;
|
|
50
|
-
readonly publicFolder: string;
|
|
51
|
-
readonly mediaRoot: string;
|
|
52
|
-
constructor({ rootPath, publicFolder, mediaRoot }: PathConfig);
|
|
53
|
-
listMedia(args: MediaArgs): Promise<ListMediaRes>;
|
|
54
|
-
deleteMedia(args: MediaArgs): Promise<SuccessRecord>;
|
|
55
|
-
}
|
|
56
|
-
export {};
|