inibase 1.6.4 → 1.6.6
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/README.md +5 -0
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.js +27 -11
- package/dist/utils.d.ts +10 -6
- package/dist/utils.js +18 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -634,6 +634,11 @@ const users = await db.get("user", undefined, {
|
|
|
634
634
|
columns: ["!username", "!address.street"],
|
|
635
635
|
});
|
|
636
636
|
|
|
637
|
+
// Columns accept dotted nested paths (e.g. "address.street" => nested field)
|
|
638
|
+
const nested = await db.get("user", undefined, {
|
|
639
|
+
columns: ["address.street", "hobbies.name"],
|
|
640
|
+
});
|
|
641
|
+
|
|
637
642
|
// Get all columns explicitly with the "*" wildcard
|
|
638
643
|
const all = await db.get("user", undefined, {
|
|
639
644
|
columns: ["*"],
|
package/dist/cli.js
CHANGED
|
@@ -180,7 +180,7 @@ rl.on("line", async (input) => {
|
|
|
180
180
|
break;
|
|
181
181
|
}
|
|
182
182
|
if (!isSafeName(splitedInput[1]))
|
|
183
|
-
console.log(`${textRed(" Err:")} Invalid table name
|
|
183
|
+
console.log(`${textRed(" Err:")} Invalid table name`);
|
|
184
184
|
else if (!(await isExists(join(path, splitedInput[1]))))
|
|
185
185
|
console.log(`${textRed(" Err:")} Table doesn't exist`);
|
|
186
186
|
else {
|
package/dist/index.d.ts
CHANGED
|
@@ -79,6 +79,16 @@ export default class Inibase {
|
|
|
79
79
|
constructor(database: string, mainFolder?: string, language?: ErrorLang);
|
|
80
80
|
createError(name: ErrorCode, variable?: string | number | (string | number)[]): Error;
|
|
81
81
|
private validateName;
|
|
82
|
+
/**
|
|
83
|
+
* Validates column paths used in the `columns` option.
|
|
84
|
+
*
|
|
85
|
+
* Each column may be a nested path of dot-separated names
|
|
86
|
+
* (e.g. "address.street", "hobbies.name") and may optionally
|
|
87
|
+
* start with "!" for exclusion. The "*" wildcard (select all)
|
|
88
|
+
* and its "!*" counterpart are special values and are skipped.
|
|
89
|
+
* Every segment of a path is validated individually.
|
|
90
|
+
*/
|
|
91
|
+
private validateColumns;
|
|
82
92
|
private validateSchema;
|
|
83
93
|
private getFileExtension;
|
|
84
94
|
private schemaToIdsPath;
|
package/dist/index.js
CHANGED
|
@@ -64,6 +64,28 @@ export default class Inibase {
|
|
|
64
64
|
validateName(name) {
|
|
65
65
|
Utils.validateName(name, this.language);
|
|
66
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Validates column paths used in the `columns` option.
|
|
69
|
+
*
|
|
70
|
+
* Each column may be a nested path of dot-separated names
|
|
71
|
+
* (e.g. "address.street", "hobbies.name") and may optionally
|
|
72
|
+
* start with "!" for exclusion. The "*" wildcard (select all)
|
|
73
|
+
* and its "!*" counterpart are special values and are skipped.
|
|
74
|
+
* Every segment of a path is validated individually.
|
|
75
|
+
*/
|
|
76
|
+
validateColumns(columns) {
|
|
77
|
+
for (const column of columns) {
|
|
78
|
+
if (column === "*" || column === "!*")
|
|
79
|
+
continue;
|
|
80
|
+
const path = column.startsWith("!") ? column.slice(1) : column;
|
|
81
|
+
for (const segment of path.split(".")) {
|
|
82
|
+
if (!segment)
|
|
83
|
+
this.validateName(column);
|
|
84
|
+
else
|
|
85
|
+
this.validateName(segment);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
67
89
|
validateSchema(schema) {
|
|
68
90
|
Utils.validateSchema(schema, this.language);
|
|
69
91
|
}
|
|
@@ -1109,9 +1131,7 @@ export default class Inibase {
|
|
|
1109
1131
|
options.columns = Array.isArray(options.columns)
|
|
1110
1132
|
? options.columns
|
|
1111
1133
|
: [options.columns];
|
|
1112
|
-
|
|
1113
|
-
if (column !== "*")
|
|
1114
|
-
this.validateName(column);
|
|
1134
|
+
this.validateColumns(options.columns);
|
|
1115
1135
|
if (options.columns.length && !options.columns.includes("id"))
|
|
1116
1136
|
options.columns.push("id");
|
|
1117
1137
|
}
|
|
@@ -1356,11 +1376,9 @@ export default class Inibase {
|
|
|
1356
1376
|
};
|
|
1357
1377
|
this.validateName(tableName);
|
|
1358
1378
|
if (options.columns)
|
|
1359
|
-
|
|
1379
|
+
this.validateColumns((Array.isArray(options.columns)
|
|
1360
1380
|
? options.columns
|
|
1361
|
-
: [options.columns]))
|
|
1362
|
-
if (column !== "*")
|
|
1363
|
-
this.validateName(column);
|
|
1381
|
+
: [options.columns]));
|
|
1364
1382
|
const tablePath = join(this.databasePath, tableName);
|
|
1365
1383
|
await this.getTable(tableName);
|
|
1366
1384
|
if (!globalConfig[this.databasePath].tables?.get(tableName)?.schema)
|
|
@@ -1443,11 +1461,9 @@ export default class Inibase {
|
|
|
1443
1461
|
const renameList = [];
|
|
1444
1462
|
this.validateName(tableName);
|
|
1445
1463
|
if (options.columns)
|
|
1446
|
-
|
|
1464
|
+
this.validateColumns((Array.isArray(options.columns)
|
|
1447
1465
|
? options.columns
|
|
1448
|
-
: [options.columns]))
|
|
1449
|
-
if (column !== "*")
|
|
1450
|
-
this.validateName(column);
|
|
1466
|
+
: [options.columns]));
|
|
1451
1467
|
const tablePath = join(this.databasePath, tableName);
|
|
1452
1468
|
await this.throwErrorIfTableEmpty(tableName);
|
|
1453
1469
|
let clonedData = structuredClone(data);
|
package/dist/utils.d.ts
CHANGED
|
@@ -236,13 +236,17 @@ export declare const createError: (language: ErrorLang, name: ErrorCode, variabl
|
|
|
236
236
|
/**
|
|
237
237
|
* Validates that a string is a safe name for a table, database or column.
|
|
238
238
|
*
|
|
239
|
-
*
|
|
240
|
-
*
|
|
241
|
-
*
|
|
239
|
+
* Instead of whitelisting allowed characters, this uses a blacklist that blocks
|
|
240
|
+
* only characters known to cause problems with shell commands, filesystem
|
|
241
|
+
* paths, or injection attacks. All Unicode letters (Latin, Arabic, Chinese,
|
|
242
|
+
* etc.), digits, underscores, hyphens, spaces and forward slashes are allowed.
|
|
242
243
|
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
244
|
+
* Blocked characters: null bytes, control characters, `\`, `;`, `|`, `&`,
|
|
245
|
+
* `<`, `>`, `$`, backtick, `!`, `'`, `"`, `{`, `}`, `(`, `)`, `~`, and `.`
|
|
246
|
+
* (reserved as column-path separator). Forward slash (`/`) is intentionally
|
|
247
|
+
* allowed so that nested table names like `"user/logs"` work.
|
|
248
|
+
*
|
|
249
|
+
* Leading or trailing spaces are not allowed.
|
|
246
250
|
*
|
|
247
251
|
* @param input - The value to be checked.
|
|
248
252
|
* @returns boolean - True if the name is safe to use, false otherwise.
|
package/dist/utils.js
CHANGED
|
@@ -726,13 +726,17 @@ export const createError = (language, name, variable) => {
|
|
|
726
726
|
/**
|
|
727
727
|
* Validates that a string is a safe name for a table, database or column.
|
|
728
728
|
*
|
|
729
|
-
*
|
|
730
|
-
*
|
|
731
|
-
*
|
|
729
|
+
* Instead of whitelisting allowed characters, this uses a blacklist that blocks
|
|
730
|
+
* only characters known to cause problems with shell commands, filesystem
|
|
731
|
+
* paths, or injection attacks. All Unicode letters (Latin, Arabic, Chinese,
|
|
732
|
+
* etc.), digits, underscores, hyphens, spaces and forward slashes are allowed.
|
|
732
733
|
*
|
|
733
|
-
*
|
|
734
|
-
*
|
|
735
|
-
*
|
|
734
|
+
* Blocked characters: null bytes, control characters, `\`, `;`, `|`, `&`,
|
|
735
|
+
* `<`, `>`, `$`, backtick, `!`, `'`, `"`, `{`, `}`, `(`, `)`, `~`, and `.`
|
|
736
|
+
* (reserved as column-path separator). Forward slash (`/`) is intentionally
|
|
737
|
+
* allowed so that nested table names like `"user/logs"` work.
|
|
738
|
+
*
|
|
739
|
+
* Leading or trailing spaces are not allowed.
|
|
736
740
|
*
|
|
737
741
|
* @param input - The value to be checked.
|
|
738
742
|
* @returns boolean - True if the name is safe to use, false otherwise.
|
|
@@ -741,12 +745,14 @@ export const isValidName = (input) => typeof input === "string" &&
|
|
|
741
745
|
input.length > 0 &&
|
|
742
746
|
input.length <= 255 &&
|
|
743
747
|
validNamePattern.test(input);
|
|
744
|
-
//
|
|
745
|
-
|
|
746
|
-
//
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
748
|
+
// Forbidden characters: control chars, path separators, shell metacharacters,
|
|
749
|
+
// quoting, grouping, history expansion, home-dir expansion and dot (reserved
|
|
750
|
+
// as column-path separator). The forward slash (/) is intentionally allowed
|
|
751
|
+
// so that nested table names like "user/logs" work.
|
|
752
|
+
const nameForbiddenChars = "\\x00-\\x1F\\x7F.\\\\;|&<>$`!'\\" + "{}()~";
|
|
753
|
+
// Names must be 1-255 chars, start/end with a non-forbidden non-whitespace
|
|
754
|
+
// character, and contain no forbidden characters in between.
|
|
755
|
+
const validNamePattern = new RegExp(`^[^${nameForbiddenChars}\\s\\p{Z}\\p{Cf}][^${nameForbiddenChars}\\p{Cf}]*[^${nameForbiddenChars}\\s\\p{Z}\\p{Cf}]$|^[^${nameForbiddenChars}\\s\\p{Z}\\p{Cf}]$`, "u");
|
|
750
756
|
/**
|
|
751
757
|
* Validates that a string is a safe name for a table, database or column and
|
|
752
758
|
* throws a translated `INVALID_NAME` error if it is not.
|