inibase 1.0.0-rc.12 → 1.0.0-rc.120
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/LICENSE +1 -1
- package/README.md +374 -103
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +272 -0
- package/dist/file.d.ts +140 -0
- package/dist/file.js +704 -0
- package/dist/index.d.ts +201 -0
- package/dist/index.js +1444 -0
- package/dist/utils.d.ts +205 -0
- package/dist/utils.js +520 -0
- package/dist/utils.server.d.ts +85 -0
- package/dist/utils.server.js +249 -0
- package/package.json +66 -20
- package/.env.example +0 -1
- package/file.ts +0 -674
- package/index.test.ts +0 -248
- package/index.ts +0 -1587
- package/tsconfig.json +0 -7
- package/utils.ts +0 -366
package/tsconfig.json
DELETED
package/utils.ts
DELETED
|
@@ -1,366 +0,0 @@
|
|
|
1
|
-
import { FieldType, Data, Schema } from ".";
|
|
2
|
-
import {
|
|
3
|
-
createCipheriv,
|
|
4
|
-
createDecipheriv,
|
|
5
|
-
randomBytes,
|
|
6
|
-
scryptSync,
|
|
7
|
-
timingSafeEqual,
|
|
8
|
-
type Cipher,
|
|
9
|
-
type Decipher,
|
|
10
|
-
} from "node:crypto";
|
|
11
|
-
|
|
12
|
-
export const isArrayOfObjects = (input: any): input is Record<any, any>[] =>
|
|
13
|
-
Array.isArray(input) && (input.length === 0 || input.every(isObject));
|
|
14
|
-
|
|
15
|
-
export const isArrayOfArrays = (input: any): input is any[][] =>
|
|
16
|
-
Array.isArray(input) && (input.length === 0 || input.every(Array.isArray));
|
|
17
|
-
|
|
18
|
-
export const isObject = (obj: any) =>
|
|
19
|
-
obj != null &&
|
|
20
|
-
(obj.constructor.name === "Object" ||
|
|
21
|
-
(typeof obj === "object" && !Array.isArray(obj)));
|
|
22
|
-
|
|
23
|
-
export const deepMerge = (target: any, source: any): any => {
|
|
24
|
-
for (const key in source) {
|
|
25
|
-
if (source.hasOwnProperty(key)) {
|
|
26
|
-
if (source[key] instanceof Object && target[key] instanceof Object)
|
|
27
|
-
target[key] = deepMerge(target[key], source[key]);
|
|
28
|
-
else target[key] = source[key];
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
return target;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
export const combineObjects = (objectArray: Record<string, any>[]) => {
|
|
35
|
-
const combinedValues: Record<string, any> = {};
|
|
36
|
-
|
|
37
|
-
for (const obj of objectArray as any)
|
|
38
|
-
for (const key in obj)
|
|
39
|
-
if (!combinedValues.hasOwnProperty(key)) combinedValues[key] = obj[key];
|
|
40
|
-
|
|
41
|
-
return combinedValues;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
export const isNumber = (input: any): input is number =>
|
|
45
|
-
!isNaN(parseFloat(input)) && !isNaN(input - 0);
|
|
46
|
-
|
|
47
|
-
export const isEmail = (input: any) =>
|
|
48
|
-
/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(String(input));
|
|
49
|
-
|
|
50
|
-
export const isURL = (input: any) => {
|
|
51
|
-
if (typeof input !== "string") return false;
|
|
52
|
-
if (
|
|
53
|
-
input[0] === "#" ||
|
|
54
|
-
input.startsWith("tel:") ||
|
|
55
|
-
input.startsWith("mailto:")
|
|
56
|
-
)
|
|
57
|
-
return true;
|
|
58
|
-
else if ("canParse" in URL) return URL.canParse(input);
|
|
59
|
-
else {
|
|
60
|
-
var pattern = new RegExp(
|
|
61
|
-
"^(https?:\\/\\/)?" + // protocol
|
|
62
|
-
"((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|" + // domain name
|
|
63
|
-
"((\\d{1,3}\\.){3}\\d{1,3}))" + // OR ip (v4) address
|
|
64
|
-
"(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*" + // port and path
|
|
65
|
-
"(\\?[;&a-z\\d%_.~+=-]*)?" + // query string
|
|
66
|
-
"(\\#[-a-z\\d_]*)?$",
|
|
67
|
-
"i"
|
|
68
|
-
); // fragment locator
|
|
69
|
-
return !!pattern.test(input);
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
export const isHTML = (input: any) =>
|
|
74
|
-
/<\/?\s*[a-z-][^>]*\s*>|(\&(?:[\w\d]+|#\d+|#x[a-f\d]+);)/g.test(input);
|
|
75
|
-
|
|
76
|
-
export const isString = (input: any): input is string =>
|
|
77
|
-
Object.prototype.toString.call(input) === "[object String]" &&
|
|
78
|
-
!isNumber(input) &&
|
|
79
|
-
!isBoolean(input) &&
|
|
80
|
-
!isEmail(input) &&
|
|
81
|
-
!isDate(input) &&
|
|
82
|
-
!isURL(input) &&
|
|
83
|
-
!isIP(input) &&
|
|
84
|
-
!isHTML(input);
|
|
85
|
-
|
|
86
|
-
export const isIP = (input: any) =>
|
|
87
|
-
/^(?:(?:^|\.)(?:2(?:5[0-5]|[0-4]\d)|1?\d?\d)){4}$/.test(input);
|
|
88
|
-
|
|
89
|
-
export const isBoolean = (input: any): input is boolean =>
|
|
90
|
-
typeof input === "boolean" ||
|
|
91
|
-
input === "true" ||
|
|
92
|
-
input === "false" ||
|
|
93
|
-
input === true ||
|
|
94
|
-
input === false;
|
|
95
|
-
|
|
96
|
-
export const isPassword = (input: any): input is string => input.length === 161;
|
|
97
|
-
|
|
98
|
-
export const isDate = (input: any) =>
|
|
99
|
-
!isNaN(Date.parse(String(input))) && Date.parse(String(input)) >= 0;
|
|
100
|
-
|
|
101
|
-
export const isValidID = (input: any): input is string => {
|
|
102
|
-
return typeof input === "string" && input.length === 32;
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
export const findChangedProperties = (
|
|
106
|
-
obj1: Record<string, string>,
|
|
107
|
-
obj2: Record<string, string>
|
|
108
|
-
): Record<string, string> | null => {
|
|
109
|
-
const result: Record<string, string> = {};
|
|
110
|
-
|
|
111
|
-
for (const key1 in obj1)
|
|
112
|
-
if (obj2.hasOwnProperty(key1) && obj1[key1] !== obj2[key1])
|
|
113
|
-
result[obj1[key1]] = obj2[key1];
|
|
114
|
-
|
|
115
|
-
return Object.keys(result).length ? result : null;
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
export const detectFieldType = (
|
|
119
|
-
input: any,
|
|
120
|
-
availableTypes: FieldType[]
|
|
121
|
-
): FieldType | undefined => {
|
|
122
|
-
if (!Array.isArray(input)) {
|
|
123
|
-
if (
|
|
124
|
-
(input === "0" ||
|
|
125
|
-
input === "1" ||
|
|
126
|
-
input === "true" ||
|
|
127
|
-
input === "false") &&
|
|
128
|
-
availableTypes.includes("boolean")
|
|
129
|
-
)
|
|
130
|
-
return "boolean";
|
|
131
|
-
else if (isNumber(input)) {
|
|
132
|
-
if (availableTypes.includes("table")) return "table";
|
|
133
|
-
else if (availableTypes.includes("date")) return "date";
|
|
134
|
-
else if (availableTypes.includes("number")) return "number";
|
|
135
|
-
} else if (availableTypes.includes("table") && isValidID(input))
|
|
136
|
-
return "table";
|
|
137
|
-
else if (input.includes(",") && availableTypes.includes("array"))
|
|
138
|
-
return "array";
|
|
139
|
-
else if (availableTypes.includes("email") && isEmail(input)) return "email";
|
|
140
|
-
else if (availableTypes.includes("url") && isURL(input)) return "url";
|
|
141
|
-
else if (availableTypes.includes("password") && isPassword(input))
|
|
142
|
-
return "password";
|
|
143
|
-
else if (availableTypes.includes("date") && isDate(input)) return "date";
|
|
144
|
-
else if (availableTypes.includes("string") && isString(input))
|
|
145
|
-
return "string";
|
|
146
|
-
else if (availableTypes.includes("ip") && isIP(input)) return "ip";
|
|
147
|
-
} else return "array";
|
|
148
|
-
|
|
149
|
-
return undefined;
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
export const validateFieldType = (
|
|
153
|
-
value: any,
|
|
154
|
-
fieldType: FieldType | FieldType[],
|
|
155
|
-
fieldChildrenType?: FieldType | FieldType[]
|
|
156
|
-
): boolean => {
|
|
157
|
-
if (value === null) return true;
|
|
158
|
-
if (Array.isArray(fieldType))
|
|
159
|
-
return detectFieldType(value, fieldType) !== undefined;
|
|
160
|
-
if (fieldType === "array" && fieldChildrenType && Array.isArray(value))
|
|
161
|
-
return value.some(
|
|
162
|
-
(v) =>
|
|
163
|
-
detectFieldType(
|
|
164
|
-
v,
|
|
165
|
-
Array.isArray(fieldChildrenType)
|
|
166
|
-
? fieldChildrenType
|
|
167
|
-
: [fieldChildrenType]
|
|
168
|
-
) !== undefined
|
|
169
|
-
);
|
|
170
|
-
|
|
171
|
-
switch (fieldType) {
|
|
172
|
-
case "string":
|
|
173
|
-
return isString(value);
|
|
174
|
-
case "password":
|
|
175
|
-
return isNumber(value) || isString(value) || isPassword(value);
|
|
176
|
-
case "number":
|
|
177
|
-
return isNumber(value);
|
|
178
|
-
case "html":
|
|
179
|
-
return isHTML(value);
|
|
180
|
-
case "ip":
|
|
181
|
-
return isIP(value);
|
|
182
|
-
case "boolean":
|
|
183
|
-
return isBoolean(value);
|
|
184
|
-
case "date":
|
|
185
|
-
return isDate(value);
|
|
186
|
-
case "object":
|
|
187
|
-
return isObject(value);
|
|
188
|
-
case "array":
|
|
189
|
-
return Array.isArray(value);
|
|
190
|
-
case "email":
|
|
191
|
-
return isEmail(value);
|
|
192
|
-
case "url":
|
|
193
|
-
return isURL(value);
|
|
194
|
-
case "table":
|
|
195
|
-
// feat: check if id exists
|
|
196
|
-
if (Array.isArray(value))
|
|
197
|
-
return (
|
|
198
|
-
(isArrayOfObjects(value) &&
|
|
199
|
-
value.every(
|
|
200
|
-
(element: Data) =>
|
|
201
|
-
element.hasOwnProperty("id") &&
|
|
202
|
-
(isValidID(element.id) || isNumber(element.id))
|
|
203
|
-
)) ||
|
|
204
|
-
value.every(isNumber) ||
|
|
205
|
-
isValidID(value)
|
|
206
|
-
);
|
|
207
|
-
else if (isObject(value))
|
|
208
|
-
return (
|
|
209
|
-
value.hasOwnProperty("id") &&
|
|
210
|
-
(isValidID((value as Data).id) || isNumber((value as Data).id))
|
|
211
|
-
);
|
|
212
|
-
else return isNumber(value) || isValidID(value);
|
|
213
|
-
case "id":
|
|
214
|
-
return isNumber(value) || isValidID(value);
|
|
215
|
-
default:
|
|
216
|
-
return false;
|
|
217
|
-
}
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
export const hashPassword = (password: string) => {
|
|
221
|
-
const salt = randomBytes(16).toString("hex");
|
|
222
|
-
const buf = scryptSync(password, salt, 64);
|
|
223
|
-
// return "161" length string
|
|
224
|
-
return `${buf.toString("hex")}.${salt}`;
|
|
225
|
-
};
|
|
226
|
-
|
|
227
|
-
export const comparePassword = (
|
|
228
|
-
storedPassword: string,
|
|
229
|
-
suppliedPassword: string
|
|
230
|
-
) => {
|
|
231
|
-
// split() returns array
|
|
232
|
-
const [hashedPassword, salt] = storedPassword.split(".");
|
|
233
|
-
// we need to pass buffer values to timingSafeEqual
|
|
234
|
-
const hashedPasswordBuf = Buffer.from(hashedPassword, "hex");
|
|
235
|
-
// we hash the new sign-in password
|
|
236
|
-
const suppliedPasswordBuf = scryptSync(suppliedPassword, salt, 64);
|
|
237
|
-
// compare the new supplied password with the stored hashed password
|
|
238
|
-
return timingSafeEqual(hashedPasswordBuf, suppliedPasswordBuf);
|
|
239
|
-
};
|
|
240
|
-
|
|
241
|
-
export const encodeID = (
|
|
242
|
-
id: number,
|
|
243
|
-
secretKeyOrSalt: string | number | Buffer
|
|
244
|
-
): string => {
|
|
245
|
-
let cipher: Cipher, ret: string;
|
|
246
|
-
|
|
247
|
-
if (Buffer.isBuffer(secretKeyOrSalt))
|
|
248
|
-
cipher = createCipheriv(
|
|
249
|
-
"aes-256-cbc",
|
|
250
|
-
secretKeyOrSalt,
|
|
251
|
-
secretKeyOrSalt.subarray(0, 16)
|
|
252
|
-
);
|
|
253
|
-
else {
|
|
254
|
-
const salt = scryptSync(
|
|
255
|
-
secretKeyOrSalt.toString(),
|
|
256
|
-
(process.env.INIBASE_SECRET ?? "inibase") + "_salt",
|
|
257
|
-
32
|
|
258
|
-
);
|
|
259
|
-
cipher = createCipheriv("aes-256-cbc", salt, salt.subarray(0, 16));
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
return cipher.update(id.toString(), "utf8", "hex") + cipher.final("hex");
|
|
263
|
-
};
|
|
264
|
-
|
|
265
|
-
export const decodeID = (
|
|
266
|
-
input: string,
|
|
267
|
-
secretKeyOrSalt: string | number | Buffer
|
|
268
|
-
): number => {
|
|
269
|
-
let decipher: Decipher;
|
|
270
|
-
|
|
271
|
-
if (Buffer.isBuffer(secretKeyOrSalt))
|
|
272
|
-
decipher = createDecipheriv(
|
|
273
|
-
"aes-256-cbc",
|
|
274
|
-
secretKeyOrSalt,
|
|
275
|
-
secretKeyOrSalt.subarray(0, 16)
|
|
276
|
-
);
|
|
277
|
-
else {
|
|
278
|
-
const salt = scryptSync(
|
|
279
|
-
secretKeyOrSalt.toString(),
|
|
280
|
-
(process.env.INIBASE_SECRET ?? "inibase") + "_salt",
|
|
281
|
-
32
|
|
282
|
-
);
|
|
283
|
-
decipher = createDecipheriv("aes-256-cbc", salt, salt.subarray(0, 16));
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
return Number(
|
|
287
|
-
decipher.update(input as string, "hex", "utf8") + decipher.final("utf8")
|
|
288
|
-
);
|
|
289
|
-
};
|
|
290
|
-
|
|
291
|
-
export const findLastIdNumber = (
|
|
292
|
-
schema: Schema,
|
|
293
|
-
secretKeyOrSalt: string | number | Buffer
|
|
294
|
-
): number => {
|
|
295
|
-
const lastField = schema[schema.length - 1];
|
|
296
|
-
if (lastField) {
|
|
297
|
-
if (
|
|
298
|
-
(lastField.type === "array" || lastField.type === "object") &&
|
|
299
|
-
isArrayOfObjects(lastField.children)
|
|
300
|
-
)
|
|
301
|
-
return findLastIdNumber(lastField.children as Schema, secretKeyOrSalt);
|
|
302
|
-
else if (lastField.id)
|
|
303
|
-
return isValidID(lastField.id)
|
|
304
|
-
? decodeID(lastField.id as string, secretKeyOrSalt)
|
|
305
|
-
: lastField.id;
|
|
306
|
-
}
|
|
307
|
-
return 0;
|
|
308
|
-
};
|
|
309
|
-
|
|
310
|
-
export const addIdToSchema = (
|
|
311
|
-
schema: Schema,
|
|
312
|
-
oldIndex: number = 0,
|
|
313
|
-
secretKeyOrSalt: string | number | Buffer
|
|
314
|
-
) =>
|
|
315
|
-
schema.map((field) => {
|
|
316
|
-
if (!field.id) {
|
|
317
|
-
oldIndex++;
|
|
318
|
-
field.id = encodeID(oldIndex, secretKeyOrSalt);
|
|
319
|
-
} else {
|
|
320
|
-
if (!isNumber(field.id)) oldIndex = decodeID(field.id, secretKeyOrSalt);
|
|
321
|
-
else {
|
|
322
|
-
oldIndex = field.id;
|
|
323
|
-
field.id = encodeID(field.id, secretKeyOrSalt);
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
if (
|
|
327
|
-
(field.type === "array" || field.type === "object") &&
|
|
328
|
-
isArrayOfObjects(field.children)
|
|
329
|
-
) {
|
|
330
|
-
field.children = addIdToSchema(
|
|
331
|
-
field.children as Schema,
|
|
332
|
-
oldIndex,
|
|
333
|
-
secretKeyOrSalt
|
|
334
|
-
);
|
|
335
|
-
oldIndex += field.children.length;
|
|
336
|
-
}
|
|
337
|
-
return field;
|
|
338
|
-
});
|
|
339
|
-
|
|
340
|
-
export default class Utils {
|
|
341
|
-
static isNumber = isNumber;
|
|
342
|
-
static isObject = isObject;
|
|
343
|
-
static isEmail = isEmail;
|
|
344
|
-
static isDate = isDate;
|
|
345
|
-
static isURL = isURL;
|
|
346
|
-
static isValidID = isValidID;
|
|
347
|
-
static isPassword = isPassword;
|
|
348
|
-
static deepMerge = deepMerge;
|
|
349
|
-
static combineObjects = combineObjects;
|
|
350
|
-
static isArrayOfObjects = isArrayOfObjects;
|
|
351
|
-
static findChangedProperties = findChangedProperties;
|
|
352
|
-
static detectFieldType = detectFieldType;
|
|
353
|
-
static isArrayOfArrays = isArrayOfArrays;
|
|
354
|
-
static isBoolean = isBoolean;
|
|
355
|
-
static isString = isString;
|
|
356
|
-
static isHTML = isHTML;
|
|
357
|
-
static isIP = isIP;
|
|
358
|
-
static validateFieldType = validateFieldType;
|
|
359
|
-
|
|
360
|
-
static encodeID = encodeID;
|
|
361
|
-
static decodeID = decodeID;
|
|
362
|
-
static hashPassword = hashPassword;
|
|
363
|
-
static comparePassword = comparePassword;
|
|
364
|
-
static findLastIdNumber = findLastIdNumber;
|
|
365
|
-
static addIdToSchema = addIdToSchema;
|
|
366
|
-
}
|