@skalfa/skalfa-api-core 1.0.3 → 1.0.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/CONTRIBUTING.md +45 -0
- package/LICENSE +21 -0
- package/README.md +60 -0
- package/dist/auth/auth.d.ts +18 -15
- package/dist/auth/auth.js +20 -203
- package/dist/auth/auth.js.map +1 -1
- package/dist/auth/create-access-token.d.ts +4 -0
- package/dist/auth/create-access-token.js +26 -0
- package/dist/auth/create-access-token.js.map +1 -0
- package/dist/auth/create-user-mail-token.d.ts +4 -0
- package/dist/auth/create-user-mail-token.js +19 -0
- package/dist/auth/create-user-mail-token.js.map +1 -0
- package/dist/auth/helpers/generate-agent-id.d.ts +1 -0
- package/dist/auth/helpers/generate-agent-id.js +7 -0
- package/dist/auth/helpers/generate-agent-id.js.map +1 -0
- package/dist/auth/helpers/get-request-ip.d.ts +1 -0
- package/dist/auth/helpers/get-request-ip.js +4 -0
- package/dist/auth/helpers/get-request-ip.js.map +1 -0
- package/dist/auth/helpers/get-user-permissions.d.ts +1 -0
- package/dist/auth/helpers/get-user-permissions.js +9 -0
- package/dist/auth/helpers/get-user-permissions.js.map +1 -0
- package/dist/auth/helpers/index.d.ts +3 -0
- package/dist/auth/helpers/index.js +4 -0
- package/dist/auth/helpers/index.js.map +1 -0
- package/dist/auth/list-user-sessions.d.ts +1 -0
- package/dist/auth/list-user-sessions.js +10 -0
- package/dist/auth/list-user-sessions.js.map +1 -0
- package/dist/auth/revalidate-user-permissions-by-role.d.ts +1 -0
- package/dist/auth/revalidate-user-permissions-by-role.js +12 -0
- package/dist/auth/revalidate-user-permissions-by-role.js.map +1 -0
- package/dist/auth/revalidate-user-permissions.d.ts +1 -0
- package/dist/auth/revalidate-user-permissions.js +21 -0
- package/dist/auth/revalidate-user-permissions.js.map +1 -0
- package/dist/auth/revoke-access-token.d.ts +1 -0
- package/dist/auth/revoke-access-token.js +5 -0
- package/dist/auth/revoke-access-token.js.map +1 -0
- package/dist/auth/verify-access-token.d.ts +1 -0
- package/dist/auth/verify-access-token.js +47 -0
- package/dist/auth/verify-access-token.js.map +1 -0
- package/dist/auth/verify-user-mail-token.d.ts +1 -0
- package/dist/auth/verify-user-mail-token.js +21 -0
- package/dist/auth/verify-user-mail-token.js.map +1 -0
- package/dist/commands/cli.js +18 -27
- package/dist/commands/cli.js.map +1 -1
- package/dist/commands/make/basic-controller.js +1 -1
- package/dist/commands/make/basic-controller.js.map +1 -1
- package/dist/commands/make/basic-migration.d.ts +1 -1
- package/dist/commands/make/basic-migration.js +2 -2
- package/dist/commands/make/basic-migration.js.map +1 -1
- package/dist/commands/make/basic-model.js +1 -1
- package/dist/commands/make/basic-model.js.map +1 -1
- package/dist/commands/make/basic-seeder.js +1 -1
- package/dist/commands/make/basic-seeder.js.map +1 -1
- package/dist/commands/make/blueprint.js +1 -1
- package/dist/commands/make/blueprint.js.map +1 -1
- package/dist/commands/make/da-migration.js +3 -3
- package/dist/commands/make/da-migration.js.map +1 -1
- package/dist/commands/make/mail.js +2 -2
- package/dist/commands/make/mail.js.map +1 -1
- package/dist/commands/make/notification.js +1 -1
- package/dist/commands/make/notification.js.map +1 -1
- package/dist/commands/make/queue.js +1 -1
- package/dist/commands/make/queue.js.map +1 -1
- package/dist/commands/make/resource.d.ts +2 -0
- package/dist/commands/make/resource.js +19 -0
- package/dist/commands/make/resource.js.map +1 -0
- package/dist/commands/make/skalfa-controller.d.ts +3 -0
- package/dist/commands/make/{light-controller.js → skalfa-controller.js} +9 -9
- package/dist/commands/make/skalfa-controller.js.map +1 -0
- package/dist/commands/make/skalfa-model.d.ts +3 -0
- package/dist/commands/make/{light-model.js → skalfa-model.js} +11 -11
- package/dist/commands/make/skalfa-model.js.map +1 -0
- package/dist/commands/runner/barrels.js.map +1 -1
- package/dist/commands/runner/blueprint/controller-generation.js +2 -2
- package/dist/commands/runner/blueprint/controller-generation.js.map +1 -1
- package/dist/commands/runner/blueprint/documentation-generation.js.map +1 -1
- package/dist/commands/runner/blueprint/migration-generation.js +3 -3
- package/dist/commands/runner/blueprint/migration-generation.js.map +1 -1
- package/dist/commands/runner/blueprint/model-generation.js +2 -2
- package/dist/commands/runner/blueprint/model-generation.js.map +1 -1
- package/dist/commands/runner/blueprint/runner.js +7 -8
- package/dist/commands/runner/blueprint/runner.js.map +1 -1
- package/dist/commands/runner/blueprint/seeder-generation.js +3 -3
- package/dist/commands/runner/blueprint/seeder-generation.js.map +1 -1
- package/dist/commands/runner/da-migration.js +1 -2
- package/dist/commands/runner/da-migration.js.map +1 -1
- package/dist/commands/runner/generate-docs.d.ts +2 -0
- package/dist/commands/runner/generate-docs.js +400 -0
- package/dist/commands/runner/generate-docs.js.map +1 -0
- package/dist/commands/runner/migration.js +1 -1
- package/dist/commands/runner/migration.js.map +1 -1
- package/dist/commands/runner/seeder.js +1 -1
- package/dist/commands/runner/seeder.js.map +1 -1
- package/dist/commands/stubs/index.d.ts +4 -4
- package/dist/commands/stubs/index.js +4 -4
- package/dist/commands/stubs/index.js.map +1 -1
- package/dist/context/context.js +6 -0
- package/dist/context/context.js.map +1 -1
- package/dist/controller/controller.d.ts +17 -30
- package/dist/controller/controller.js +39 -121
- package/dist/controller/controller.js.map +1 -1
- package/dist/controller/response.d.ts +6 -0
- package/dist/controller/response.js +63 -0
- package/dist/controller/response.js.map +1 -0
- package/dist/controller/storage.d.ts +9 -0
- package/dist/controller/storage.js +56 -0
- package/dist/controller/storage.js.map +1 -0
- package/dist/conversion/conversion.d.ts +3 -0
- package/dist/conversion/conversion.js +28 -4
- package/dist/conversion/conversion.js.map +1 -1
- package/dist/conversion/date.d.ts +1 -0
- package/dist/conversion/date.js +77 -0
- package/dist/conversion/date.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/logger/logger.js +33 -0
- package/dist/logger/logger.js.map +1 -1
- package/dist/mail/mail.js +6 -6
- package/dist/mail/mail.js.map +1 -1
- package/dist/middleware/access-log.d.ts +31 -0
- package/dist/middleware/access-log.js +13 -0
- package/dist/middleware/access-log.js.map +1 -0
- package/dist/middleware/auth.d.ts +37 -0
- package/dist/middleware/auth.js +16 -0
- package/dist/middleware/auth.js.map +1 -0
- package/dist/middleware/body-parse.d.ts +35 -0
- package/dist/middleware/body-parse.js +87 -0
- package/dist/middleware/body-parse.js.map +1 -0
- package/dist/middleware/context.d.ts +29 -0
- package/dist/middleware/context.js +8 -0
- package/dist/middleware/context.js.map +1 -0
- package/dist/middleware/cors.d.ts +31 -0
- package/dist/middleware/cors.js +27 -0
- package/dist/middleware/cors.js.map +1 -0
- package/dist/middleware/error-handler.d.ts +33 -0
- package/dist/middleware/error-handler.js +17 -0
- package/dist/middleware/error-handler.js.map +1 -0
- package/dist/middleware/middleware.d.ts +31 -10
- package/dist/middleware/middleware.js +41 -209
- package/dist/middleware/middleware.js.map +1 -1
- package/dist/middleware/private.d.ts +29 -0
- package/dist/middleware/private.js +8 -0
- package/dist/middleware/private.js.map +1 -0
- package/dist/middleware/rate-limiter.d.ts +32 -0
- package/dist/middleware/rate-limiter.js +30 -0
- package/dist/middleware/rate-limiter.js.map +1 -0
- package/dist/notification/index.d.ts +1 -0
- package/dist/notification/index.js +2 -0
- package/dist/notification/index.js.map +1 -0
- package/dist/notification/notification.d.ts +16 -0
- package/dist/notification/notification.js +64 -0
- package/dist/notification/notification.js.map +1 -0
- package/dist/permission/permission.js +9 -0
- package/dist/permission/permission.js.map +1 -1
- package/dist/registry/registry.d.ts +0 -6
- package/dist/registry/registry.js +6 -6
- package/dist/registry/registry.js.map +1 -1
- package/dist/storage/storage.d.ts +3 -3
- package/dist/storage/storage.js.map +1 -1
- package/dist/validation/validation.js +43 -51
- package/dist/validation/validation.js.map +1 -1
- package/package.json +4 -4
- package/src/auth/auth.ts +21 -252
- package/src/auth/create-access-token.ts +29 -0
- package/src/auth/create-user-mail-token.ts +24 -0
- package/src/auth/helpers/generate-agent-id.ts +8 -0
- package/src/auth/helpers/get-request-ip.ts +3 -0
- package/src/auth/helpers/get-user-permissions.ts +15 -0
- package/src/auth/helpers/index.ts +3 -0
- package/src/auth/list-user-sessions.ts +11 -0
- package/src/auth/revalidate-user-permissions-by-role.ts +13 -0
- package/src/auth/revalidate-user-permissions.ts +26 -0
- package/src/auth/revoke-access-token.ts +5 -0
- package/src/auth/verify-access-token.ts +56 -0
- package/src/auth/verify-user-mail-token.ts +24 -0
- package/src/commands/cli.ts +19 -29
- package/src/commands/make/basic-controller.ts +4 -2
- package/src/commands/make/basic-migration.ts +5 -3
- package/src/commands/make/basic-model.ts +3 -1
- package/src/commands/make/basic-seeder.ts +3 -1
- package/src/commands/make/blueprint.ts +3 -1
- package/src/commands/make/da-migration.ts +6 -5
- package/src/commands/make/mail.ts +4 -2
- package/src/commands/make/notification.ts +3 -1
- package/src/commands/make/queue.ts +3 -1
- package/src/commands/make/resource.ts +21 -0
- package/src/commands/make/{light-controller.ts → skalfa-controller.ts} +10 -8
- package/src/commands/make/{light-model.ts → skalfa-model.ts} +12 -10
- package/src/commands/runner/barrels.ts +4 -0
- package/src/commands/runner/blueprint/controller-generation.ts +4 -2
- package/src/commands/runner/blueprint/documentation-generation.ts +2 -0
- package/src/commands/runner/blueprint/migration-generation.ts +5 -3
- package/src/commands/runner/blueprint/model-generation.ts +4 -2
- package/src/commands/runner/blueprint/runner.ts +15 -8
- package/src/commands/runner/blueprint/seeder-generation.ts +5 -3
- package/src/commands/runner/da-migration.ts +3 -2
- package/src/commands/runner/generate-docs.ts +495 -0
- package/src/commands/runner/migration.ts +1 -1
- package/src/commands/runner/seeder.ts +1 -1
- package/src/commands/stubs/index.ts +4 -4
- package/src/context/context.ts +23 -17
- package/src/controller/controller.ts +124 -239
- package/src/controller/response.ts +78 -0
- package/src/controller/storage.ts +78 -0
- package/src/conversion/conversion.ts +90 -64
- package/src/conversion/date.ts +74 -0
- package/src/index.ts +2 -0
- package/src/logger/logger.ts +217 -176
- package/src/mail/mail.ts +85 -85
- package/src/middleware/access-log.ts +15 -0
- package/src/middleware/auth.ts +19 -0
- package/src/middleware/body-parse.ts +83 -0
- package/src/middleware/context.ts +11 -0
- package/src/middleware/cors.ts +31 -0
- package/src/middleware/error-handler.ts +20 -0
- package/src/middleware/middleware.ts +91 -288
- package/src/middleware/private.ts +8 -0
- package/src/middleware/rate-limiter.ts +41 -0
- package/src/notification/index.ts +1 -0
- package/src/notification/notification.ts +86 -0
- package/src/permission/permission.ts +140 -136
- package/src/registry/registry.ts +17 -15
- package/src/route/route.ts +11 -11
- package/src/storage/storage.ts +104 -106
- package/src/validation/validation.ts +322 -346
- package/dist/auth.util.d.ts +0 -19
- package/dist/auth.util.js +0 -183
- package/dist/auth.util.js.map +0 -1
- package/dist/commands/make/light-controller.d.ts +0 -3
- package/dist/commands/make/light-controller.js.map +0 -1
- package/dist/commands/make/light-model.d.ts +0 -3
- package/dist/commands/make/light-model.js.map +0 -1
- package/dist/context.util.d.ts +0 -7
- package/dist/context.util.js +0 -11
- package/dist/context.util.js.map +0 -1
- package/dist/controller.util.d.ts +0 -118
- package/dist/controller.util.js +0 -144
- package/dist/controller.util.js.map +0 -1
- package/dist/conversion.util.d.ts +0 -8
- package/dist/conversion.util.js +0 -52
- package/dist/conversion.util.js.map +0 -1
- package/dist/db/db.d.ts +0 -84
- package/dist/db/db.js +0 -177
- package/dist/db/db.js.map +0 -1
- package/dist/db/index.d.ts +0 -1
- package/dist/db/index.js +0 -2
- package/dist/db/index.js.map +0 -1
- package/dist/db.util.d.ts +0 -84
- package/dist/db.util.js +0 -177
- package/dist/db.util.js.map +0 -1
- package/dist/logger.util.d.ts +0 -30
- package/dist/logger.util.js +0 -126
- package/dist/logger.util.js.map +0 -1
- package/dist/mail.util.d.ts +0 -21
- package/dist/mail.util.js +0 -53
- package/dist/mail.util.js.map +0 -1
- package/dist/middleware.util.d.ts +0 -263
- package/dist/middleware.util.js +0 -233
- package/dist/middleware.util.js.map +0 -1
- package/dist/model/index.d.ts +0 -3
- package/dist/model/index.js +0 -4
- package/dist/model/index.js.map +0 -1
- package/dist/model/model.d.ts +0 -204
- package/dist/model/model.js +0 -1495
- package/dist/model/model.js.map +0 -1
- package/dist/model.util.d.ts +0 -204
- package/dist/model.util.js +0 -1495
- package/dist/model.util.js.map +0 -1
- package/dist/permission.util.d.ts +0 -38
- package/dist/permission.util.js +0 -91
- package/dist/permission.util.js.map +0 -1
- package/dist/registry.util.d.ts +0 -28
- package/dist/registry.util.js +0 -19
- package/dist/registry.util.js.map +0 -1
- package/dist/route.util.d.ts +0 -1
- package/dist/route.util.js +0 -12
- package/dist/route.util.js.map +0 -1
- package/dist/storage.util.d.ts +0 -56
- package/dist/storage.util.js +0 -82
- package/dist/storage.util.js.map +0 -1
- package/dist/validation.util.d.ts +0 -7
- package/dist/validation.util.js +0 -237
- package/dist/validation.util.js.map +0 -1
|
@@ -1,28 +1,13 @@
|
|
|
1
1
|
import validator from "validator";
|
|
2
2
|
import { db } from "@skalfa/skalfa-orm";
|
|
3
|
-
//
|
|
4
|
-
// ##
|
|
5
|
-
//
|
|
3
|
+
// =====================================>
|
|
4
|
+
// ## Validation: validate request data
|
|
5
|
+
// =====================================>
|
|
6
6
|
export async function validate(data, rules) {
|
|
7
7
|
const errors = {};
|
|
8
8
|
for (const field in rules) {
|
|
9
9
|
const fieldRules = normalizeRules(rules[field]);
|
|
10
10
|
if (field.includes("*")) {
|
|
11
|
-
// const [arrayPath, childPath] = field.split(".*.")
|
|
12
|
-
// const arr = getNestedValue(data, arrayPath)
|
|
13
|
-
// if (!Array.isArray(arr)) {
|
|
14
|
-
// addError(errors, arrayPath, `${arrayPath} harus berupa array`)
|
|
15
|
-
// continue
|
|
16
|
-
// }
|
|
17
|
-
// for (let i = 0; i < arr.length; i++) {
|
|
18
|
-
// const value = childPath
|
|
19
|
-
// ? getNestedValue(arr[i], childPath)
|
|
20
|
-
// : arr[i]
|
|
21
|
-
// const itemField = childPath
|
|
22
|
-
// ? `${arrayPath}.${i}.${childPath}`
|
|
23
|
-
// : `${arrayPath}.${i}`
|
|
24
|
-
// await checkRules({ field: itemField, value, rules: fieldRules, data, errors })
|
|
25
|
-
// }
|
|
26
11
|
const segments = field.split(".");
|
|
27
12
|
await nestedValidation({ value: data, segments, rules: fieldRules, fieldPath: "", data, errors });
|
|
28
13
|
continue;
|
|
@@ -47,12 +32,16 @@ async function checkRules({ field, value, rules, data, errors }) {
|
|
|
47
32
|
break;
|
|
48
33
|
case "string":
|
|
49
34
|
case "text":
|
|
35
|
+
if (!value)
|
|
36
|
+
break;
|
|
50
37
|
if (typeof value !== "string") {
|
|
51
38
|
addError(errors, field, `${field} harus berupa string`);
|
|
52
39
|
}
|
|
53
40
|
break;
|
|
54
41
|
case "numeric":
|
|
55
42
|
case "number":
|
|
43
|
+
if (!value)
|
|
44
|
+
break;
|
|
56
45
|
if (!validator.isNumeric(String(value))) {
|
|
57
46
|
addError(errors, field, `${field} harus berupa angka`);
|
|
58
47
|
}
|
|
@@ -63,22 +52,30 @@ async function checkRules({ field, value, rules, data, errors }) {
|
|
|
63
52
|
}
|
|
64
53
|
break;
|
|
65
54
|
case "email":
|
|
55
|
+
if (!value)
|
|
56
|
+
break;
|
|
66
57
|
if (!validator.isEmail(String(value))) {
|
|
67
58
|
addError(errors, field, `${field} harus berupa email yang valid`);
|
|
68
59
|
}
|
|
69
60
|
break;
|
|
70
61
|
case "url":
|
|
62
|
+
if (!value)
|
|
63
|
+
break;
|
|
71
64
|
if (!validator.isURL(String(value))) {
|
|
72
65
|
addError(errors, field, `${field} harus berupa URL yang valid`);
|
|
73
66
|
}
|
|
74
67
|
break;
|
|
75
68
|
case "date":
|
|
69
|
+
if (!value)
|
|
70
|
+
break;
|
|
76
71
|
if (!validator.isDate(String(value))) {
|
|
77
72
|
addError(errors, field, `${field} harus berupa tanggal yang valid`);
|
|
78
73
|
}
|
|
79
74
|
break;
|
|
80
75
|
// === LENGTH ===
|
|
81
76
|
case "min": {
|
|
77
|
+
if (!value)
|
|
78
|
+
break;
|
|
82
79
|
const min = parseInt(param);
|
|
83
80
|
if (!validator.isLength(String(value), { min })) {
|
|
84
81
|
addError(errors, field, `${field} minimal ${min} karakter`);
|
|
@@ -86,6 +83,8 @@ async function checkRules({ field, value, rules, data, errors }) {
|
|
|
86
83
|
break;
|
|
87
84
|
}
|
|
88
85
|
case "max": {
|
|
86
|
+
if (!value)
|
|
87
|
+
break;
|
|
89
88
|
const max = parseInt(param);
|
|
90
89
|
if (!validator.isLength(String(value), { max })) {
|
|
91
90
|
addError(errors, field, `${field} maksimal ${max} karakter`);
|
|
@@ -93,6 +92,8 @@ async function checkRules({ field, value, rules, data, errors }) {
|
|
|
93
92
|
break;
|
|
94
93
|
}
|
|
95
94
|
case "between": {
|
|
95
|
+
if (!value)
|
|
96
|
+
break;
|
|
96
97
|
const [minVal, maxVal] = param.split(",").map(Number);
|
|
97
98
|
if (!validator.isLength(String(value), { min: minVal, max: maxVal })) {
|
|
98
99
|
addError(errors, field, `${field} harus antara ${minVal} - ${maxVal} karakter`);
|
|
@@ -101,6 +102,8 @@ async function checkRules({ field, value, rules, data, errors }) {
|
|
|
101
102
|
}
|
|
102
103
|
// === SET MEMBERSHIP ===
|
|
103
104
|
case "in": {
|
|
105
|
+
if (!value)
|
|
106
|
+
break;
|
|
104
107
|
const allowed = param.split(",");
|
|
105
108
|
if (!allowed.includes(String(value))) {
|
|
106
109
|
addError(errors, field, `${field} harus salah satu dari: ${allowed.join(", ")}`);
|
|
@@ -108,17 +111,22 @@ async function checkRules({ field, value, rules, data, errors }) {
|
|
|
108
111
|
break;
|
|
109
112
|
}
|
|
110
113
|
case "not_in": {
|
|
114
|
+
if (!value)
|
|
115
|
+
break;
|
|
111
116
|
const notAllowed = param.split(",");
|
|
112
117
|
if (notAllowed.includes(String(value))) {
|
|
113
118
|
addError(errors, field, `${field} tidak boleh salah satu dari: ${notAllowed.join(", ")}`);
|
|
114
119
|
}
|
|
115
120
|
break;
|
|
116
121
|
}
|
|
117
|
-
case "array":
|
|
122
|
+
case "array": {
|
|
123
|
+
if (!value)
|
|
124
|
+
break;
|
|
118
125
|
if (!Array.isArray(value)) {
|
|
119
126
|
addError(errors, field, `${field} harus berupa array`);
|
|
120
127
|
}
|
|
121
128
|
break;
|
|
129
|
+
}
|
|
122
130
|
// === RELATIONAL ===
|
|
123
131
|
case "confirmed":
|
|
124
132
|
if (value !== getNestedValue(data, `${field}_confirmation`)) {
|
|
@@ -137,6 +145,8 @@ async function checkRules({ field, value, rules, data, errors }) {
|
|
|
137
145
|
break;
|
|
138
146
|
// === REGEX ===
|
|
139
147
|
case "regex":
|
|
148
|
+
if (!value)
|
|
149
|
+
break;
|
|
140
150
|
try {
|
|
141
151
|
const pattern = new RegExp(param);
|
|
142
152
|
if (!pattern.test(String(value))) {
|
|
@@ -149,14 +159,15 @@ async function checkRules({ field, value, rules, data, errors }) {
|
|
|
149
159
|
break;
|
|
150
160
|
// === DATABASE VALIDATION ===
|
|
151
161
|
case "unique": {
|
|
152
|
-
if (!
|
|
153
|
-
console.warn(`[Validation Warning] "unique" rule skipped on field "${field}" because database is not configured/installed.`);
|
|
162
|
+
if (!value)
|
|
154
163
|
break;
|
|
155
|
-
}
|
|
156
164
|
const [table, column, exceptId] = param.split(",");
|
|
157
165
|
const query = db.table(table).where(column, value);
|
|
158
166
|
if (exceptId)
|
|
159
167
|
query.whereNot("id", exceptId);
|
|
168
|
+
if (await db.schema.hasColumn(table, "deleted_at")) {
|
|
169
|
+
query.whereNull("deleted_at");
|
|
170
|
+
}
|
|
160
171
|
const existing = await query.first();
|
|
161
172
|
if (existing) {
|
|
162
173
|
addError(errors, field, `${field} sudah digunakan`);
|
|
@@ -164,12 +175,14 @@ async function checkRules({ field, value, rules, data, errors }) {
|
|
|
164
175
|
break;
|
|
165
176
|
}
|
|
166
177
|
case "exists": {
|
|
167
|
-
if (!
|
|
168
|
-
console.warn(`[Validation Warning] "exists" rule skipped on field "${field}" because database is not configured/installed.`);
|
|
178
|
+
if (!value)
|
|
169
179
|
break;
|
|
170
|
-
}
|
|
171
180
|
const [table, column] = param.split(",");
|
|
172
|
-
const
|
|
181
|
+
const query = db.table(table).where(column, value);
|
|
182
|
+
if (await db.schema.hasColumn(table, "deleted_at")) {
|
|
183
|
+
query.whereNull("deleted_at");
|
|
184
|
+
}
|
|
185
|
+
const existing = await query.first();
|
|
173
186
|
if (!existing) {
|
|
174
187
|
addError(errors, field, `${field} tidak ditemukan di ${table}`);
|
|
175
188
|
}
|
|
@@ -180,13 +193,7 @@ async function checkRules({ field, value, rules, data, errors }) {
|
|
|
180
193
|
}
|
|
181
194
|
async function nestedValidation({ value, segments, rules, fieldPath, data, errors }) {
|
|
182
195
|
if (segments.length === 0) {
|
|
183
|
-
await checkRules({
|
|
184
|
-
field: fieldPath,
|
|
185
|
-
value,
|
|
186
|
-
rules,
|
|
187
|
-
data,
|
|
188
|
-
errors
|
|
189
|
-
});
|
|
196
|
+
await checkRules({ field: fieldPath, value, rules, data, errors });
|
|
190
197
|
return;
|
|
191
198
|
}
|
|
192
199
|
const [segment, ...rest] = segments;
|
|
@@ -196,25 +203,11 @@ async function nestedValidation({ value, segments, rules, fieldPath, data, error
|
|
|
196
203
|
return;
|
|
197
204
|
}
|
|
198
205
|
for (let i = 0; i < value.length; i++) {
|
|
199
|
-
await nestedValidation({
|
|
200
|
-
value: value[i],
|
|
201
|
-
segments: rest,
|
|
202
|
-
rules,
|
|
203
|
-
fieldPath: `${fieldPath}.${i}`,
|
|
204
|
-
data,
|
|
205
|
-
errors
|
|
206
|
-
});
|
|
206
|
+
await nestedValidation({ value: value[i], segments: rest, rules, fieldPath: `${fieldPath}.${i}`, data, errors });
|
|
207
207
|
}
|
|
208
208
|
}
|
|
209
209
|
else {
|
|
210
|
-
await nestedValidation({
|
|
211
|
-
value: value?.[segment],
|
|
212
|
-
segments: rest,
|
|
213
|
-
rules,
|
|
214
|
-
fieldPath: fieldPath ? `${fieldPath}.${segment}` : segment,
|
|
215
|
-
data,
|
|
216
|
-
errors
|
|
217
|
-
});
|
|
210
|
+
await nestedValidation({ value: value?.[segment], segments: rest, rules, fieldPath: fieldPath ? `${fieldPath}.${segment}` : segment, data, errors });
|
|
218
211
|
}
|
|
219
212
|
}
|
|
220
213
|
// ==================================>
|
|
@@ -228,9 +221,8 @@ function getNestedValue(obj, path) {
|
|
|
228
221
|
.replace(/\['([^']+)'\]/g, '.$1')
|
|
229
222
|
.replace(/\["([^"]+)"\]/g, '.$1');
|
|
230
223
|
return normalizedPath.split('.').reduce((acc, key) => {
|
|
231
|
-
if (acc && Object.prototype.hasOwnProperty.call(acc, key))
|
|
224
|
+
if (acc && Object.prototype.hasOwnProperty.call(acc, key))
|
|
232
225
|
return acc[key];
|
|
233
|
-
}
|
|
234
226
|
return undefined;
|
|
235
227
|
}, obj);
|
|
236
228
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/validation/validation.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,WAAW,CAAA;AACjC,OAAO,EAAE,EAAE,EAAE,MAAM,oBAAoB,
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/validation/validation.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skalfa/skalfa-api-core",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Core
|
|
3
|
+
"version": "1.0.8",
|
|
4
|
+
"description": "Core framework engine and foundational utilities for the Skalfa API backend.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
"author": "",
|
|
16
16
|
"license": "UNLICENSED",
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@skalfa/skalfa-orm": "
|
|
18
|
+
"@skalfa/skalfa-orm": "^1.0.0",
|
|
19
19
|
"bcrypt": "^6.0.0",
|
|
20
20
|
"commander": "^12.1.0",
|
|
21
21
|
"dotenv": "^17.2.2",
|
|
22
|
-
"elysia": "
|
|
22
|
+
"elysia": "^1.2.0",
|
|
23
23
|
"nodemailer": "^7.0.9",
|
|
24
24
|
"validator": "^13.15.15"
|
|
25
25
|
},
|
package/src/auth/auth.ts
CHANGED
|
@@ -1,282 +1,51 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
1
|
+
import { createAccessToken } from './create-access-token'
|
|
2
|
+
import { revokeAccessToken } from './revoke-access-token'
|
|
3
|
+
import { verifyAccessToken } from './verify-access-token'
|
|
4
|
+
import { createUserMailToken } from './create-user-mail-token'
|
|
5
|
+
import { verifyUserMailToken } from './verify-user-mail-token'
|
|
6
|
+
import { listUserSessions } from './list-user-sessions'
|
|
7
|
+
import { revalidateUserPermissions } from './revalidate-user-permissions'
|
|
8
|
+
import { revalidateUserPermissionsByRole } from './revalidate-user-permissions-by-role'
|
|
9
|
+
|
|
10
|
+
export const TOKEN_PLAIN_LENGTH = 20
|
|
11
|
+
export const AUTH_PERMISSION = process.env.AUTH_CACHE === "true"
|
|
12
|
+
export const AUTH_CACHE = process.env.AUTH_CACHE === "true"
|
|
13
|
+
export const AUTH_CACHE_TTL = Number(process.env.AUTH_CACHE_TTL || 600)
|
|
13
14
|
|
|
14
15
|
export const auth = {
|
|
15
|
-
|
|
16
16
|
// =====================================>
|
|
17
17
|
// ## Auth: create access token with user id
|
|
18
18
|
// =====================================>
|
|
19
|
-
|
|
20
|
-
const plain = crypto.randomBytes(TOKEN_PLAIN_LENGTH).toString("hex")
|
|
21
|
-
const hash = await bcrypt.hash(plain, 10)
|
|
22
|
-
const agent = generateAgentId(req)
|
|
23
|
-
|
|
24
|
-
if (!db) {
|
|
25
|
-
// get user from db (fallback / stub for no ORM)
|
|
26
|
-
return {
|
|
27
|
-
token: `1|${plain}`,
|
|
28
|
-
tokenId: 1,
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
let permissions: string[] = []
|
|
33
|
-
if (AUTH_PERMISSION && permission) {
|
|
34
|
-
permissions = await getUserPermissions(userId)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const [row] = await db("user_access_tokens").insert({
|
|
38
|
-
user_id : userId,
|
|
39
|
-
token : hash,
|
|
40
|
-
agent : agent,
|
|
41
|
-
permissions : JSON.stringify(permissions),
|
|
42
|
-
created_at : new Date(),
|
|
43
|
-
}).returning(["id"])
|
|
44
|
-
|
|
45
|
-
return {
|
|
46
|
-
token : `${row.id}|${plain}`,
|
|
47
|
-
tokenId : row.id,
|
|
48
|
-
}
|
|
49
|
-
},
|
|
19
|
+
createAccessToken,
|
|
50
20
|
|
|
51
21
|
// =====================================>
|
|
52
22
|
// ## Auth: delete access token with user id
|
|
53
23
|
// =====================================>
|
|
54
|
-
|
|
55
|
-
if (!db) {
|
|
56
|
-
// delete user access token from db (stub for no ORM)
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
return db.table('user_access_tokens').where("id", id).delete()
|
|
60
|
-
},
|
|
24
|
+
revokeAccessToken,
|
|
61
25
|
|
|
62
26
|
// =====================================>
|
|
63
27
|
// ## Auth: verify access token
|
|
64
28
|
// =====================================>
|
|
65
|
-
|
|
66
|
-
if (!token.includes("|")) return null
|
|
67
|
-
|
|
68
|
-
const [tokenId, plain] = token.split("|", 2)
|
|
69
|
-
const agent = req ? generateAgentId(req) : ""
|
|
70
|
-
const ip = req ? getRequestIp(req) : ""
|
|
71
|
-
|
|
72
|
-
const cacheKey = `auth:token:${tokenId}`
|
|
73
|
-
|
|
74
|
-
if (AUTH_CACHE) {
|
|
75
|
-
const redis = registry.get('redis')
|
|
76
|
-
if (redis) {
|
|
77
|
-
const cached = await redis.get(cacheKey)
|
|
78
|
-
if (cached) {
|
|
79
|
-
const session = JSON.parse(cached)
|
|
80
|
-
if (session.agent !== agent) return null
|
|
81
|
-
return session
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (!db) {
|
|
87
|
-
// get user and token from db (stub for no ORM)
|
|
88
|
-
const user = { id: 1, name: "Admin", email: "admin@example.com" }
|
|
89
|
-
const tokenRecord = { id: Number(tokenId), agent, permission: [] }
|
|
90
|
-
return { user, token: tokenRecord, permissions: [] }
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const tokenRecord = await db("user_access_tokens").where("id", tokenId).first()
|
|
94
|
-
|
|
95
|
-
if (!tokenRecord) return null
|
|
96
|
-
if (tokenRecord.agent !== agent) return null
|
|
97
|
-
|
|
98
|
-
const valid = await bcrypt.compare(plain, tokenRecord.token)
|
|
99
|
-
if (!valid) return null
|
|
100
|
-
|
|
101
|
-
await db("user_access_tokens").where("id", tokenRecord.id).update({ last_used_at: new Date(), last_used_ip: ip })
|
|
102
|
-
|
|
103
|
-
const user = await db("users").where("id", tokenRecord.user_id).first()
|
|
104
|
-
|
|
105
|
-
if (AUTH_CACHE) {
|
|
106
|
-
const redis = registry.get('redis')
|
|
107
|
-
if (redis) {
|
|
108
|
-
await redis.setex(
|
|
109
|
-
cacheKey,
|
|
110
|
-
AUTH_CACHE_TTL,
|
|
111
|
-
JSON.stringify({
|
|
112
|
-
user : user,
|
|
113
|
-
agent : tokenRecord.agent,
|
|
114
|
-
permissions : tokenRecord.permission,
|
|
115
|
-
})
|
|
116
|
-
)
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return { user, token: tokenRecord, permissions: tokenRecord.permission }
|
|
121
|
-
},
|
|
29
|
+
verifyAccessToken,
|
|
122
30
|
|
|
123
31
|
// =====================================>
|
|
124
32
|
// ## Auth: create user mail token
|
|
125
33
|
// =====================================>
|
|
126
|
-
|
|
127
|
-
const token = Math.floor(100000 + Math.random() * 900000).toString()
|
|
128
|
-
|
|
129
|
-
if (!db) {
|
|
130
|
-
// create user mail token in db (stub for no ORM)
|
|
131
|
-
return {
|
|
132
|
-
token: token,
|
|
133
|
-
tokenId: 1
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const hash = crypto.createHash('sha256').update(token).digest('hex')
|
|
138
|
-
const trx = await db.transaction()
|
|
139
|
-
|
|
140
|
-
await trx.table('user_mail_tokens').insert({
|
|
141
|
-
user_id : userId,
|
|
142
|
-
token : hash,
|
|
143
|
-
created_at : new Date(),
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
const record = await trx.table('user_mail_tokens').orderBy('id', 'desc').first()
|
|
147
|
-
|
|
148
|
-
await trx.commit()
|
|
149
|
-
|
|
150
|
-
return {
|
|
151
|
-
token : token,
|
|
152
|
-
tokenId : record.id
|
|
153
|
-
}
|
|
154
|
-
},
|
|
34
|
+
createUserMailToken,
|
|
155
35
|
|
|
156
36
|
// =====================================>
|
|
157
37
|
// ## Auth: Verify user mail token
|
|
158
38
|
// =====================================>
|
|
159
|
-
|
|
160
|
-
if (!db) {
|
|
161
|
-
// verify user mail token in db (stub for no ORM)
|
|
162
|
-
return true
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
const hashedToken = crypto.createHash("sha256").update(token).digest("hex");
|
|
166
|
-
|
|
167
|
-
const record = await db.table("user_mail_tokens")
|
|
168
|
-
.where("user_id", userId)
|
|
169
|
-
.whereNull("used_at")
|
|
170
|
-
.orderBy("id", "desc")
|
|
171
|
-
.first();
|
|
172
|
-
|
|
173
|
-
if (!record) return false
|
|
174
|
-
|
|
175
|
-
if (record.token !== hashedToken) return false;
|
|
176
|
-
|
|
177
|
-
const createdAt = new Date(record.created_at);
|
|
178
|
-
const now = new Date();
|
|
179
|
-
const diffMinutes = (now.getTime() - createdAt.getTime()) / (1000 * 60);
|
|
180
|
-
|
|
181
|
-
if (diffMinutes > 10) return false;
|
|
182
|
-
|
|
183
|
-
return true;
|
|
184
|
-
},
|
|
39
|
+
verifyUserMailToken,
|
|
185
40
|
|
|
186
41
|
// =====================================>
|
|
187
42
|
// ## Auth: list user sessions
|
|
188
43
|
// =====================================>
|
|
189
|
-
|
|
190
|
-
if (!db) {
|
|
191
|
-
// list user sessions from db (stub for no ORM)
|
|
192
|
-
return []
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const rows = await db("user_access_tokens").select(["id", "agent", "created_at", "last_used_at", "last_used_ip","expired_at"]).where("user_id", userId).orderBy("last_used_at", "desc")
|
|
196
|
-
|
|
197
|
-
return rows.map((r: any) => ({
|
|
198
|
-
...r,
|
|
199
|
-
is_active : r.revoked_at === null,
|
|
200
|
-
is_current : r.id === currentTokenId,
|
|
201
|
-
}))
|
|
202
|
-
},
|
|
44
|
+
listUserSessions,
|
|
203
45
|
|
|
204
46
|
// =====================================>
|
|
205
47
|
// ## Auth: revalidate user permission
|
|
206
48
|
// =====================================>
|
|
207
|
-
revalidateUserPermissions
|
|
208
|
-
revalidateUserPermissionsByRole
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
function generateAgentId(req: Request) {
|
|
212
|
-
const ua = req.headers.get("user-agent") ?? ""
|
|
213
|
-
const acc = req.headers.get("accept") ?? ""
|
|
214
|
-
|
|
215
|
-
return crypto.createHash("sha256").update(ua + acc).digest("hex")
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
function getRequestIp(req: Request) {
|
|
219
|
-
return (req.headers.get("x-forwarded-for")?.split(",")[0]?.trim() || req.headers.get("x-real-ip") || "unknown")
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
async function getUserPermissions(userId: number): Promise<string[]> {
|
|
223
|
-
if (!db) {
|
|
224
|
-
// get user permissions from db (stub for no ORM)
|
|
225
|
-
return []
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
const roleIds = await db("user_roles").where("user_id", userId).pluck("role_id")
|
|
229
|
-
|
|
230
|
-
if (roleIds.length === 0) return []
|
|
231
|
-
|
|
232
|
-
const rows = await db("permissions").whereIn("role_id", roleIds).pluck("permissions")
|
|
233
|
-
|
|
234
|
-
return Array.from(
|
|
235
|
-
new Set(
|
|
236
|
-
rows.flatMap((p: any) => p ?? [])
|
|
237
|
-
)
|
|
238
|
-
)
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
async function revalidateUserPermissions(userId: number) {
|
|
242
|
-
if (!db) {
|
|
243
|
-
// revalidate user permissions in db (stub for no ORM)
|
|
244
|
-
return
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
const permissions = await getUserPermissions(userId)
|
|
248
|
-
|
|
249
|
-
const tokenIds = await db("user_access_tokens").where("user_id", userId).pluck("id")
|
|
250
|
-
|
|
251
|
-
if (tokenIds.length === 0) return
|
|
252
|
-
|
|
253
|
-
await db("user_access_tokens").whereIn("id", tokenIds).update({
|
|
254
|
-
permissions : JSON.stringify(permissions),
|
|
255
|
-
updated_at : new Date(),
|
|
256
|
-
})
|
|
257
|
-
|
|
258
|
-
if (AUTH_CACHE) {
|
|
259
|
-
const redis = registry.get('redis')
|
|
260
|
-
if (redis) {
|
|
261
|
-
await Promise.all(
|
|
262
|
-
tokenIds.map((id: any) => redis.del(`auth:token:${id}`))
|
|
263
|
-
)
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
async function revalidateUserPermissionsByRole(roleId: number) {
|
|
269
|
-
if (!db) {
|
|
270
|
-
// revalidate user permissions by role in db (stub for no ORM)
|
|
271
|
-
return
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
const userIds = await db("user_roles").where("role_id", roleId).pluck("user_id")
|
|
275
|
-
|
|
276
|
-
const queue = registry.get('queue')
|
|
277
|
-
if (queue) {
|
|
278
|
-
for (const userId of userIds) {
|
|
279
|
-
await queue.add("auth:revalidate-permission", { userId })
|
|
280
|
-
}
|
|
281
|
-
}
|
|
49
|
+
revalidateUserPermissions,
|
|
50
|
+
revalidateUserPermissionsByRole,
|
|
282
51
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import crypto from 'crypto'
|
|
2
|
+
import bcrypt from "bcrypt";
|
|
3
|
+
import { db } from '@skalfa/skalfa-orm'
|
|
4
|
+
import { TOKEN_PLAIN_LENGTH, AUTH_PERMISSION } from './auth'
|
|
5
|
+
import { getUserPermissions, generateAgentId } from './helpers'
|
|
6
|
+
|
|
7
|
+
export async function createAccessToken(userId: number, req: Request, permission: boolean = true) {
|
|
8
|
+
const plain = crypto.randomBytes(TOKEN_PLAIN_LENGTH).toString("hex")
|
|
9
|
+
const hash = await bcrypt.hash(plain, 10)
|
|
10
|
+
const agent = generateAgentId(req)
|
|
11
|
+
|
|
12
|
+
let permissions: string[] = []
|
|
13
|
+
if (AUTH_PERMISSION && permission) {
|
|
14
|
+
permissions = await getUserPermissions(userId)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const [row] = await db("user_access_tokens").insert({
|
|
18
|
+
user_id : userId,
|
|
19
|
+
token : hash,
|
|
20
|
+
agent : agent,
|
|
21
|
+
permissions : JSON.stringify(permissions),
|
|
22
|
+
created_at : new Date(),
|
|
23
|
+
}).returning(["id"])
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
token : `${row.id}|${plain}`,
|
|
27
|
+
tokenId : row.id,
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import crypto from 'crypto'
|
|
2
|
+
import { db } from '@skalfa/skalfa-orm'
|
|
3
|
+
|
|
4
|
+
export async function createUserMailToken(userId: number) {
|
|
5
|
+
const token = Math.floor(100000 + Math.random() * 900000).toString()
|
|
6
|
+
|
|
7
|
+
const hash = crypto.createHash('sha256').update(token).digest('hex')
|
|
8
|
+
const trx = await db.transaction()
|
|
9
|
+
|
|
10
|
+
await trx.table('user_mail_tokens').insert({
|
|
11
|
+
user_id : userId,
|
|
12
|
+
token : hash,
|
|
13
|
+
created_at : new Date(),
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
const record = await trx.table('user_mail_tokens').orderBy('id', 'desc').first()
|
|
17
|
+
|
|
18
|
+
await trx.commit()
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
token : token,
|
|
22
|
+
tokenId : record.id
|
|
23
|
+
}
|
|
24
|
+
}
|