@tinacms/graphql 2.2.1 → 2.2.3

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.js CHANGED
@@ -3026,7 +3026,7 @@ var validateField = async (field) => {
3026
3026
  var package_default = {
3027
3027
  name: "@tinacms/graphql",
3028
3028
  type: "module",
3029
- version: "2.2.1",
3029
+ version: "2.2.3",
3030
3030
  main: "dist/index.js",
3031
3031
  module: "./dist/index.js",
3032
3032
  files: [
@@ -4917,7 +4917,7 @@ var updateObjectWithJsonPath = (obj, path9, oldValue, newValue) => {
4917
4917
  }
4918
4918
  return { object: obj, updated };
4919
4919
  };
4920
- var Resolver = class {
4920
+ var Resolver = class _Resolver {
4921
4921
  constructor(init) {
4922
4922
  this.init = init;
4923
4923
  this.config = init.config;
@@ -5188,8 +5188,17 @@ var Resolver = class {
5188
5188
  * path traversal attacks where a user might attempt to read or write files
5189
5189
  * outside of the intended collection.
5190
5190
  */
5191
+ static sanitizePath(input) {
5192
+ if (input.includes("\0")) {
5193
+ throw new Error("Invalid path: null bytes are not allowed");
5194
+ }
5195
+ return input.replace(/\\/g, "/");
5196
+ }
5191
5197
  validatePath = (fullPath, collection, relativePath) => {
5192
- const normalizedPath = path3.normalize(fullPath);
5198
+ if (fullPath.includes("\0")) {
5199
+ throw new Error("Invalid path: null bytes are not allowed");
5200
+ }
5201
+ const normalizedPath = path3.normalize(fullPath.replace(/\\/g, "/"));
5193
5202
  const normalizedCollectionPath = path3.normalize(collection.path);
5194
5203
  const relative = path3.relative(normalizedCollectionPath, normalizedPath);
5195
5204
  if (relative.startsWith("..")) {
@@ -5220,16 +5229,17 @@ var Resolver = class {
5220
5229
  */
5221
5230
  getValidatedPath = (collectionName, relativePath, options) => {
5222
5231
  const collection = this.getCollectionWithName(collectionName);
5223
- const pathSegments = [collection.path, relativePath];
5232
+ const sanitizedRelativePath = _Resolver.sanitizePath(relativePath);
5233
+ const pathSegments = [collection.path, sanitizedRelativePath];
5224
5234
  if (options?.extraSegments) {
5225
- pathSegments.push(...options.extraSegments);
5235
+ pathSegments.push(...options.extraSegments.map(_Resolver.sanitizePath));
5226
5236
  }
5227
5237
  const realPath = path3.join(...pathSegments);
5228
5238
  const shouldValidateExtension = options?.validateExtension !== false;
5229
5239
  this.validatePath(
5230
5240
  realPath,
5231
5241
  collection,
5232
- shouldValidateExtension ? relativePath : void 0
5242
+ shouldValidateExtension ? sanitizedRelativePath : void 0
5233
5243
  );
5234
5244
  return { collection, realPath };
5235
5245
  };
@@ -8021,14 +8031,39 @@ import path7 from "path";
8021
8031
  import fg from "fast-glob";
8022
8032
  import fs2 from "fs-extra";
8023
8033
  import normalize from "normalize-path";
8034
+ function resolveRealPath(candidate) {
8035
+ try {
8036
+ return fs2.realpathSync(candidate);
8037
+ } catch {
8038
+ const parent = path7.dirname(candidate);
8039
+ if (parent === candidate) return candidate;
8040
+ return path7.join(resolveRealPath(parent), path7.basename(candidate));
8041
+ }
8042
+ }
8024
8043
  function assertWithinBase(filepath, baseDir) {
8044
+ if (filepath.includes("\0")) {
8045
+ throw new Error("Invalid path: null bytes are not allowed");
8046
+ }
8047
+ const sanitized = filepath.replace(/\\/g, "/");
8025
8048
  const resolvedBase = path7.resolve(baseDir);
8026
- const resolved = path7.resolve(path7.join(baseDir, filepath));
8049
+ const resolved = path7.resolve(path7.join(baseDir, sanitized));
8027
8050
  if (resolved !== resolvedBase && !resolved.startsWith(resolvedBase + path7.sep)) {
8028
8051
  throw new Error(
8029
8052
  `Path traversal detected: "${filepath}" escapes the base directory`
8030
8053
  );
8031
8054
  }
8055
+ try {
8056
+ const realBase = fs2.realpathSync(resolvedBase);
8057
+ const realResolved = resolveRealPath(resolved);
8058
+ if (realResolved !== realBase && !realResolved.startsWith(realBase + path7.sep)) {
8059
+ throw new Error(
8060
+ `Path traversal detected: "${filepath}" escapes the base directory`
8061
+ );
8062
+ }
8063
+ } catch (err) {
8064
+ if (err instanceof Error && err.message.startsWith("Path traversal"))
8065
+ throw err;
8066
+ }
8032
8067
  return resolved;
8033
8068
  }
8034
8069
  var FilesystemBridge = class {
@@ -8090,7 +8125,11 @@ import { GraphQLError as GraphQLError6 } from "graphql";
8090
8125
  import git2 from "isomorphic-git";
8091
8126
  import normalize2 from "normalize-path";
8092
8127
  function assertWithinBase2(filepath, relativePath) {
8093
- const qualified = relativePath ? `${relativePath}/${filepath}` : filepath;
8128
+ if (filepath.includes("\0")) {
8129
+ throw new Error("Invalid path: null bytes are not allowed");
8130
+ }
8131
+ const sanitized = filepath.replace(/\\/g, "/");
8132
+ const qualified = relativePath ? `${relativePath}/${sanitized}` : sanitized;
8094
8133
  const normalized = path8.normalize(qualified);
8095
8134
  if (normalized.startsWith("..") || normalized.startsWith("/") || path8.isAbsolute(normalized) || relativePath && normalized !== relativePath && !normalized.startsWith(relativePath + "/")) {
8096
8135
  throw new Error(
@@ -235,6 +235,7 @@ export declare class Resolver {
235
235
  * path traversal attacks where a user might attempt to read or write files
236
236
  * outside of the intended collection.
237
237
  */
238
+ private static sanitizePath;
238
239
  private validatePath;
239
240
  /**
240
241
  * Helper method to get collection and construct validated path.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tinacms/graphql",
3
3
  "type": "module",
4
- "version": "2.2.1",
4
+ "version": "2.2.3",
5
5
  "main": "dist/index.js",
6
6
  "module": "./dist/index.js",
7
7
  "files": [
@@ -43,8 +43,8 @@
43
43
  "normalize-path": "^3.0.0",
44
44
  "readable-stream": "^4.7.0",
45
45
  "yup": "^1.6.1",
46
- "@tinacms/mdx": "2.1.0",
47
- "@tinacms/schema-tools": "2.7.0"
46
+ "@tinacms/mdx": "2.1.1",
47
+ "@tinacms/schema-tools": "2.7.1"
48
48
  },
49
49
  "publishConfig": {
50
50
  "registry": "https://registry.npmjs.org"
@@ -72,7 +72,7 @@
72
72
  "vite": "^4.5.9",
73
73
  "vitest": "^0.32.4",
74
74
  "zod": "^3.24.2",
75
- "@tinacms/schema-tools": "2.7.0",
75
+ "@tinacms/schema-tools": "2.7.1",
76
76
  "@tinacms/scripts": "1.6.0"
77
77
  },
78
78
  "scripts": {