inibase 1.0.0-rc.6 → 1.0.0-rc.8
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 +1 -55
- package/file.ts +70 -26
- package/index.test.ts +8 -2
- package/index.ts +176 -242
- package/package.json +5 -5
- package/utils.server.ts +79 -0
- package/utils.ts +77 -86
package/package.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "inibase",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.8",
|
|
4
4
|
"description": "File-based Relational Database for large data",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"test": "npx tsx watch ./index.test.ts"
|
|
9
|
+
},
|
|
7
10
|
"repository": {
|
|
8
11
|
"type": "git",
|
|
9
12
|
"url": "git+https://github.com/inicontent/inibase.git"
|
|
@@ -31,8 +34,5 @@
|
|
|
31
34
|
"homepage": "https://github.com/inicontent/inibase#readme",
|
|
32
35
|
"devDependencies": {
|
|
33
36
|
"@types/node": "^20.8.6"
|
|
34
|
-
},
|
|
35
|
-
"scripts": {
|
|
36
|
-
"test": "npx tsx watch ./index.test.ts"
|
|
37
37
|
}
|
|
38
|
-
}
|
|
38
|
+
}
|
package/utils.server.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import {
|
|
2
|
+
scryptSync,
|
|
3
|
+
randomBytes,
|
|
4
|
+
timingSafeEqual,
|
|
5
|
+
createDecipheriv,
|
|
6
|
+
createCipheriv,
|
|
7
|
+
Cipher,
|
|
8
|
+
Decipher,
|
|
9
|
+
} from "node:crypto";
|
|
10
|
+
|
|
11
|
+
export const hashPassword = (password: string) => {
|
|
12
|
+
const salt = randomBytes(16).toString("hex");
|
|
13
|
+
const buf = scryptSync(password, salt, 64);
|
|
14
|
+
// return "161" length string
|
|
15
|
+
return `${buf.toString("hex")}.${salt}`;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const comparePassword = (
|
|
19
|
+
storedPassword: string,
|
|
20
|
+
suppliedPassword: string
|
|
21
|
+
) => {
|
|
22
|
+
// split() returns array
|
|
23
|
+
const [hashedPassword, salt] = storedPassword.split(".");
|
|
24
|
+
// we need to pass buffer values to timingSafeEqual
|
|
25
|
+
const hashedPasswordBuf = Buffer.from(hashedPassword, "hex");
|
|
26
|
+
// we hash the new sign-in password
|
|
27
|
+
const suppliedPasswordBuf = scryptSync(suppliedPassword, salt, 64);
|
|
28
|
+
// compare the new supplied password with the stored hashed password
|
|
29
|
+
return timingSafeEqual(hashedPasswordBuf, suppliedPasswordBuf);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const encodeID = (
|
|
33
|
+
id: number,
|
|
34
|
+
secretKey: string | number | Buffer
|
|
35
|
+
): string => {
|
|
36
|
+
let cipher: Cipher, ret: string;
|
|
37
|
+
|
|
38
|
+
if (Buffer.isBuffer(secretKey))
|
|
39
|
+
cipher = createCipheriv(
|
|
40
|
+
"aes-256-cbc",
|
|
41
|
+
secretKey,
|
|
42
|
+
secretKey.subarray(0, 16)
|
|
43
|
+
);
|
|
44
|
+
else {
|
|
45
|
+
const salt = scryptSync(secretKey.toString(), "salt", 32);
|
|
46
|
+
cipher = createCipheriv("aes-256-cbc", salt, salt.subarray(0, 16));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return cipher.update(id.toString(), "utf8", "hex") + cipher.final("hex");
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const decodeID = (
|
|
53
|
+
input: string,
|
|
54
|
+
secretKey: string | number | Buffer
|
|
55
|
+
): number => {
|
|
56
|
+
let decipher: Decipher;
|
|
57
|
+
|
|
58
|
+
if (Buffer.isBuffer(secretKey))
|
|
59
|
+
decipher = createDecipheriv(
|
|
60
|
+
"aes-256-cbc",
|
|
61
|
+
secretKey,
|
|
62
|
+
secretKey.subarray(0, 16)
|
|
63
|
+
);
|
|
64
|
+
else {
|
|
65
|
+
const salt = scryptSync(secretKey.toString(), "salt", 32);
|
|
66
|
+
decipher = createDecipheriv("aes-256-cbc", salt, salt.subarray(0, 16));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return Number(
|
|
70
|
+
decipher.update(input as string, "hex", "utf8") + decipher.final("utf8")
|
|
71
|
+
);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export default class Utils {
|
|
75
|
+
static encodeID = encodeID;
|
|
76
|
+
static decodeID = decodeID;
|
|
77
|
+
static hashPassword = hashPassword;
|
|
78
|
+
static comparePassword = comparePassword;
|
|
79
|
+
}
|
package/utils.ts
CHANGED
|
@@ -1,13 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
scryptSync,
|
|
3
|
-
randomBytes,
|
|
4
|
-
timingSafeEqual,
|
|
5
|
-
createDecipheriv,
|
|
6
|
-
createCipheriv,
|
|
7
|
-
Cipher,
|
|
8
|
-
Decipher,
|
|
9
|
-
} from "node:crypto";
|
|
10
|
-
import { FieldType } from ".";
|
|
1
|
+
import { FieldType, Data } from ".";
|
|
11
2
|
|
|
12
3
|
export const isArrayOfObjects = (arr: any) => {
|
|
13
4
|
return Array.isArray(arr) && (arr.length === 0 || arr.every(isObject));
|
|
@@ -80,69 +71,6 @@ export const isPassword = (input: any) => input.length === 161;
|
|
|
80
71
|
export const isDate = (input: any) =>
|
|
81
72
|
!isNaN(Date.parse(String(input))) && Date.parse(String(input)) >= 0;
|
|
82
73
|
|
|
83
|
-
export const hashPassword = (password: string) => {
|
|
84
|
-
const salt = randomBytes(16).toString("hex");
|
|
85
|
-
const buf = scryptSync(password, salt, 64);
|
|
86
|
-
// return "161" length string
|
|
87
|
-
return `${buf.toString("hex")}.${salt}`;
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
export const comparePassword = (
|
|
91
|
-
storedPassword: string,
|
|
92
|
-
suppliedPassword: string
|
|
93
|
-
) => {
|
|
94
|
-
// split() returns array
|
|
95
|
-
const [hashedPassword, salt] = storedPassword.split(".");
|
|
96
|
-
// we need to pass buffer values to timingSafeEqual
|
|
97
|
-
const hashedPasswordBuf = Buffer.from(hashedPassword, "hex");
|
|
98
|
-
// we hash the new sign-in password
|
|
99
|
-
const suppliedPasswordBuf = scryptSync(suppliedPassword, salt, 64);
|
|
100
|
-
// compare the new supplied password with the stored hashed password
|
|
101
|
-
return timingSafeEqual(hashedPasswordBuf, suppliedPasswordBuf);
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
export const encodeID = (
|
|
105
|
-
id: number,
|
|
106
|
-
secretKey: string | number | Buffer
|
|
107
|
-
): string => {
|
|
108
|
-
let cipher: Cipher, ret: string;
|
|
109
|
-
|
|
110
|
-
if (Buffer.isBuffer(secretKey))
|
|
111
|
-
cipher = createCipheriv(
|
|
112
|
-
"aes-256-cbc",
|
|
113
|
-
secretKey,
|
|
114
|
-
secretKey.subarray(0, 16)
|
|
115
|
-
);
|
|
116
|
-
else {
|
|
117
|
-
const salt = scryptSync(secretKey.toString(), "salt", 32);
|
|
118
|
-
cipher = createCipheriv("aes-256-cbc", salt, salt.subarray(0, 16));
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return cipher.update(id.toString(), "utf8", "hex") + cipher.final("hex");
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
export const decodeID = (
|
|
125
|
-
input: string,
|
|
126
|
-
secretKey: string | number | Buffer
|
|
127
|
-
): number => {
|
|
128
|
-
let decipher: Decipher;
|
|
129
|
-
|
|
130
|
-
if (Buffer.isBuffer(secretKey))
|
|
131
|
-
decipher = createDecipheriv(
|
|
132
|
-
"aes-256-cbc",
|
|
133
|
-
secretKey,
|
|
134
|
-
secretKey.subarray(0, 16)
|
|
135
|
-
);
|
|
136
|
-
else {
|
|
137
|
-
const salt = scryptSync(secretKey.toString(), "salt", 32);
|
|
138
|
-
decipher = createDecipheriv("aes-256-cbc", salt, salt.subarray(0, 16));
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
return Number(
|
|
142
|
-
decipher.update(input as string, "hex", "utf8") + decipher.final("utf8")
|
|
143
|
-
);
|
|
144
|
-
};
|
|
145
|
-
|
|
146
74
|
export const isValidID = (input: any): boolean => {
|
|
147
75
|
return Array.isArray(input)
|
|
148
76
|
? input.every(isValidID)
|
|
@@ -175,30 +103,94 @@ export const detectFieldType = (
|
|
|
175
103
|
availableTypes.includes("boolean")
|
|
176
104
|
)
|
|
177
105
|
return "boolean";
|
|
178
|
-
else if (
|
|
106
|
+
else if (isNumber(input)) {
|
|
179
107
|
if (availableTypes.includes("table")) return "table";
|
|
180
108
|
else if (availableTypes.includes("date")) return "date";
|
|
181
109
|
else if (availableTypes.includes("number")) return "number";
|
|
182
110
|
} else if (input.includes(",") && availableTypes.includes("array"))
|
|
183
111
|
return "array";
|
|
184
|
-
else if (availableTypes.includes("email") &&
|
|
185
|
-
|
|
186
|
-
else if (availableTypes.includes("
|
|
187
|
-
else if (availableTypes.includes("password") && Utils.isPassword(input))
|
|
112
|
+
else if (availableTypes.includes("email") && isEmail(input)) return "email";
|
|
113
|
+
else if (availableTypes.includes("url") && isURL(input)) return "url";
|
|
114
|
+
else if (availableTypes.includes("password") && isPassword(input))
|
|
188
115
|
return "password";
|
|
189
|
-
else if (availableTypes.includes("date") &&
|
|
190
|
-
|
|
191
|
-
else if (availableTypes.includes("string") && Utils.isString(input))
|
|
116
|
+
else if (availableTypes.includes("date") && isDate(input)) return "date";
|
|
117
|
+
else if (availableTypes.includes("string") && isString(input))
|
|
192
118
|
return "string";
|
|
193
|
-
else if (availableTypes.includes("ip") &&
|
|
119
|
+
else if (availableTypes.includes("ip") && isIP(input)) return "ip";
|
|
194
120
|
} else return "array";
|
|
195
121
|
|
|
196
122
|
return undefined;
|
|
197
123
|
};
|
|
198
124
|
|
|
125
|
+
export const validateFieldType = (
|
|
126
|
+
value: any,
|
|
127
|
+
fieldType: FieldType | FieldType[],
|
|
128
|
+
fieldChildrenType?: FieldType | FieldType[]
|
|
129
|
+
): boolean => {
|
|
130
|
+
if (value === null) return true;
|
|
131
|
+
if (Array.isArray(fieldType))
|
|
132
|
+
return detectFieldType(value, fieldType) !== undefined;
|
|
133
|
+
if (fieldType === "array" && fieldChildrenType && Array.isArray(value))
|
|
134
|
+
return value.some(
|
|
135
|
+
(v) =>
|
|
136
|
+
detectFieldType(
|
|
137
|
+
v,
|
|
138
|
+
Array.isArray(fieldChildrenType)
|
|
139
|
+
? fieldChildrenType
|
|
140
|
+
: [fieldChildrenType]
|
|
141
|
+
) !== undefined
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
switch (fieldType) {
|
|
145
|
+
case "string":
|
|
146
|
+
return isString(value);
|
|
147
|
+
case "password":
|
|
148
|
+
return isNumber(value) || isString(value) || isPassword(value);
|
|
149
|
+
case "number":
|
|
150
|
+
return isNumber(value);
|
|
151
|
+
case "html":
|
|
152
|
+
return isHTML(value);
|
|
153
|
+
case "ip":
|
|
154
|
+
return isIP(value);
|
|
155
|
+
case "boolean":
|
|
156
|
+
return isBoolean(value);
|
|
157
|
+
case "date":
|
|
158
|
+
return isDate(value);
|
|
159
|
+
case "object":
|
|
160
|
+
return isObject(value);
|
|
161
|
+
case "array":
|
|
162
|
+
return Array.isArray(value);
|
|
163
|
+
case "email":
|
|
164
|
+
return isEmail(value);
|
|
165
|
+
case "url":
|
|
166
|
+
return isURL(value);
|
|
167
|
+
case "table":
|
|
168
|
+
// feat: check if id exists
|
|
169
|
+
if (Array.isArray(value))
|
|
170
|
+
return (
|
|
171
|
+
(isArrayOfObjects(value) &&
|
|
172
|
+
value.every(
|
|
173
|
+
(element: Data) =>
|
|
174
|
+
element.hasOwnProperty("id") &&
|
|
175
|
+
(isValidID(element.id) || isNumber(element.id))
|
|
176
|
+
)) ||
|
|
177
|
+
value.every(isNumber) ||
|
|
178
|
+
isValidID(value)
|
|
179
|
+
);
|
|
180
|
+
else if (isObject(value))
|
|
181
|
+
return (
|
|
182
|
+
value.hasOwnProperty("id") &&
|
|
183
|
+
(isValidID((value as Data).id) || isNumber((value as Data).id))
|
|
184
|
+
);
|
|
185
|
+
else return isNumber(value) || isValidID(value);
|
|
186
|
+
case "id":
|
|
187
|
+
return isNumber(value) || isValidID(value);
|
|
188
|
+
default:
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
|
|
199
193
|
export default class Utils {
|
|
200
|
-
static encodeID = encodeID;
|
|
201
|
-
static decodeID = decodeID;
|
|
202
194
|
static isNumber = isNumber;
|
|
203
195
|
static isObject = isObject;
|
|
204
196
|
static isEmail = isEmail;
|
|
@@ -206,10 +198,8 @@ export default class Utils {
|
|
|
206
198
|
static isURL = isURL;
|
|
207
199
|
static isValidID = isValidID;
|
|
208
200
|
static isPassword = isPassword;
|
|
209
|
-
static hashPassword = hashPassword;
|
|
210
201
|
static deepMerge = deepMerge;
|
|
211
202
|
static combineObjects = combineObjects;
|
|
212
|
-
static comparePassword = comparePassword;
|
|
213
203
|
static isArrayOfObjects = isArrayOfObjects;
|
|
214
204
|
static findChangedProperties = findChangedProperties;
|
|
215
205
|
static detectFieldType = detectFieldType;
|
|
@@ -218,4 +208,5 @@ export default class Utils {
|
|
|
218
208
|
static isString = isString;
|
|
219
209
|
static isHTML = isHTML;
|
|
220
210
|
static isIP = isIP;
|
|
211
|
+
static validateFieldType = validateFieldType;
|
|
221
212
|
}
|