@flowerforce/flowerbase 1.2.0 → 1.2.1-beta.10
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 +28 -3
- package/dist/auth/controller.d.ts.map +1 -1
- package/dist/auth/controller.js +57 -3
- package/dist/auth/plugins/jwt.d.ts.map +1 -1
- package/dist/auth/plugins/jwt.js +49 -3
- package/dist/auth/providers/custom-function/controller.d.ts.map +1 -1
- package/dist/auth/providers/custom-function/controller.js +19 -3
- package/dist/auth/providers/local-userpass/controller.d.ts.map +1 -1
- package/dist/auth/providers/local-userpass/controller.js +125 -71
- package/dist/auth/providers/local-userpass/dtos.d.ts +11 -2
- package/dist/auth/providers/local-userpass/dtos.d.ts.map +1 -1
- package/dist/auth/utils.d.ts +53 -14
- package/dist/auth/utils.d.ts.map +1 -1
- package/dist/auth/utils.js +46 -63
- package/dist/constants.d.ts +13 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +14 -2
- package/dist/features/functions/controller.d.ts.map +1 -1
- package/dist/features/functions/controller.js +32 -3
- package/dist/features/functions/dtos.d.ts +3 -0
- package/dist/features/functions/dtos.d.ts.map +1 -1
- package/dist/features/functions/interface.d.ts +3 -0
- package/dist/features/functions/interface.d.ts.map +1 -1
- package/dist/features/functions/utils.d.ts +2 -1
- package/dist/features/functions/utils.d.ts.map +1 -1
- package/dist/features/functions/utils.js +19 -7
- package/dist/features/rules/utils.d.ts.map +1 -1
- package/dist/features/rules/utils.js +11 -2
- package/dist/features/triggers/index.d.ts.map +1 -1
- package/dist/features/triggers/index.js +48 -7
- package/dist/features/triggers/utils.d.ts.map +1 -1
- package/dist/features/triggers/utils.js +118 -27
- package/dist/index.d.ts +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +57 -21
- package/dist/services/mongodb-atlas/index.d.ts.map +1 -1
- package/dist/services/mongodb-atlas/index.js +605 -478
- package/dist/services/mongodb-atlas/model.d.ts +2 -1
- package/dist/services/mongodb-atlas/model.d.ts.map +1 -1
- package/dist/services/mongodb-atlas/utils.d.ts +9 -2
- package/dist/services/mongodb-atlas/utils.d.ts.map +1 -1
- package/dist/services/mongodb-atlas/utils.js +113 -23
- package/dist/shared/handleUserRegistration.d.ts.map +1 -1
- package/dist/shared/handleUserRegistration.js +1 -0
- package/dist/shared/models/handleUserRegistration.model.d.ts +6 -2
- package/dist/shared/models/handleUserRegistration.model.d.ts.map +1 -1
- package/dist/utils/context/helpers.d.ts +7 -6
- package/dist/utils/context/helpers.d.ts.map +1 -1
- package/dist/utils/context/helpers.js +3 -0
- package/dist/utils/context/index.d.ts +1 -1
- package/dist/utils/context/index.d.ts.map +1 -1
- package/dist/utils/context/index.js +176 -5
- package/dist/utils/context/interface.d.ts +1 -1
- package/dist/utils/context/interface.d.ts.map +1 -1
- package/dist/utils/crypto/index.d.ts +1 -0
- package/dist/utils/crypto/index.d.ts.map +1 -1
- package/dist/utils/crypto/index.js +6 -2
- package/dist/utils/initializer/exposeRoutes.d.ts.map +1 -1
- package/dist/utils/initializer/exposeRoutes.js +11 -4
- package/dist/utils/initializer/registerPlugins.d.ts +3 -1
- package/dist/utils/initializer/registerPlugins.d.ts.map +1 -1
- package/dist/utils/initializer/registerPlugins.js +9 -6
- package/dist/utils/roles/helpers.js +11 -3
- package/dist/utils/roles/machines/commonValidators.d.ts.map +1 -1
- package/dist/utils/roles/machines/commonValidators.js +10 -6
- package/dist/utils/roles/machines/read/B/validators.d.ts +4 -0
- package/dist/utils/roles/machines/read/B/validators.d.ts.map +1 -0
- package/dist/utils/roles/machines/read/B/validators.js +8 -0
- package/dist/utils/roles/machines/read/C/index.d.ts.map +1 -1
- package/dist/utils/roles/machines/read/C/index.js +10 -7
- package/dist/utils/roles/machines/read/C/validators.d.ts +5 -0
- package/dist/utils/roles/machines/read/C/validators.d.ts.map +1 -0
- package/dist/utils/roles/machines/read/C/validators.js +29 -0
- package/dist/utils/roles/machines/read/D/index.d.ts.map +1 -1
- package/dist/utils/roles/machines/read/D/index.js +13 -11
- package/dist/utils/rules.d.ts +1 -1
- package/dist/utils/rules.d.ts.map +1 -1
- package/dist/utils/rules.js +26 -17
- package/jest.config.ts +2 -12
- package/jest.setup.ts +28 -0
- package/package.json +1 -2
- package/src/auth/controller.ts +70 -4
- package/src/auth/plugins/jwt.test.ts +93 -0
- package/src/auth/plugins/jwt.ts +62 -3
- package/src/auth/providers/custom-function/controller.ts +22 -5
- package/src/auth/providers/local-userpass/controller.ts +168 -96
- package/src/auth/providers/local-userpass/dtos.ts +13 -2
- package/src/auth/utils.ts +51 -86
- package/src/constants.ts +16 -3
- package/src/fastify.d.ts +32 -15
- package/src/features/functions/controller.ts +51 -3
- package/src/features/functions/dtos.ts +3 -0
- package/src/features/functions/interface.ts +3 -0
- package/src/features/functions/utils.ts +29 -8
- package/src/features/rules/utils.ts +11 -2
- package/src/features/triggers/index.ts +43 -1
- package/src/features/triggers/utils.ts +146 -38
- package/src/index.ts +69 -20
- package/src/services/mongodb-atlas/__tests__/findOneAndUpdate.test.ts +95 -0
- package/src/services/mongodb-atlas/__tests__/utils.test.ts +141 -0
- package/src/services/mongodb-atlas/index.ts +241 -90
- package/src/services/mongodb-atlas/model.ts +15 -2
- package/src/services/mongodb-atlas/utils.ts +158 -22
- package/src/shared/handleUserRegistration.ts +3 -3
- package/src/shared/models/handleUserRegistration.model.ts +8 -3
- package/src/types/fastify-raw-body.d.ts +22 -0
- package/src/utils/__tests__/STEP_B_STATES.test.ts +1 -1
- package/src/utils/__tests__/STEP_C_STATES.test.ts +1 -1
- package/src/utils/__tests__/STEP_D_STATES.test.ts +2 -2
- package/src/utils/__tests__/checkIsValidFieldNameFn.test.ts +9 -4
- package/src/utils/__tests__/registerPlugins.test.ts +16 -1
- package/src/utils/context/helpers.ts +3 -0
- package/src/utils/context/index.ts +238 -13
- package/src/utils/context/interface.ts +1 -1
- package/src/utils/crypto/index.ts +5 -1
- package/src/utils/initializer/exposeRoutes.ts +15 -8
- package/src/utils/initializer/registerPlugins.ts +15 -7
- package/src/utils/roles/helpers.ts +23 -5
- package/src/utils/roles/machines/commonValidators.ts +10 -5
- package/src/utils/roles/machines/read/B/validators.ts +8 -0
- package/src/utils/roles/machines/read/C/index.ts +11 -7
- package/src/utils/roles/machines/read/C/validators.ts +21 -0
- package/src/utils/roles/machines/read/D/index.ts +22 -12
- package/src/utils/rules.ts +31 -22
- package/tsconfig.spec.json +7 -0
|
@@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.generateToken = exports.comparePassword = exports.hashPassword = void 0;
|
|
15
|
+
exports.hashToken = exports.generateToken = exports.comparePassword = exports.hashPassword = void 0;
|
|
16
16
|
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
17
17
|
const node_util_1 = require("node:util");
|
|
18
18
|
const scrypt = (0, node_util_1.promisify)(node_crypto_1.default.scrypt);
|
|
@@ -47,7 +47,11 @@ exports.comparePassword = comparePassword;
|
|
|
47
47
|
* > Generate a random token
|
|
48
48
|
* @param length -> the token length
|
|
49
49
|
*/
|
|
50
|
-
const generateToken = (length =
|
|
50
|
+
const generateToken = (length = 64) => {
|
|
51
51
|
return node_crypto_1.default.randomBytes(length).toString('hex');
|
|
52
52
|
};
|
|
53
53
|
exports.generateToken = generateToken;
|
|
54
|
+
const hashToken = (token) => {
|
|
55
|
+
return node_crypto_1.default.createHash('sha256').update(token).digest('hex');
|
|
56
|
+
};
|
|
57
|
+
exports.hashToken = hashToken;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exposeRoutes.d.ts","sourceRoot":"","sources":["../../../src/utils/initializer/exposeRoutes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAOzC;;;;GAIG;AACH,eAAO,MAAM,YAAY,GAAU,SAAS,eAAe,
|
|
1
|
+
{"version":3,"file":"exposeRoutes.d.ts","sourceRoot":"","sources":["../../../src/utils/initializer/exposeRoutes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAOzC;;;;GAIG;AACH,eAAO,MAAM,YAAY,GAAU,SAAS,eAAe,kBA0E1D,CAAA"}
|
|
@@ -23,12 +23,19 @@ const crypto_1 = require("../crypto");
|
|
|
23
23
|
const exposeRoutes = (fastify) => __awaiter(void 0, void 0, void 0, function* () {
|
|
24
24
|
try {
|
|
25
25
|
fastify.get(`${constants_1.API_VERSION}/app/:appId/location`, (req) => __awaiter(void 0, void 0, void 0, function* () {
|
|
26
|
-
|
|
26
|
+
var _a, _b, _c;
|
|
27
|
+
const schema = (_a = constants_1.DEFAULT_CONFIG === null || constants_1.DEFAULT_CONFIG === void 0 ? void 0 : constants_1.DEFAULT_CONFIG.HTTPS_SCHEMA) !== null && _a !== void 0 ? _a : 'http';
|
|
28
|
+
const headerHost = (_b = req.headers.host) !== null && _b !== void 0 ? _b : 'localhost:3000';
|
|
29
|
+
const hostname = headerHost.split(':')[0];
|
|
30
|
+
const port = (_c = constants_1.DEFAULT_CONFIG === null || constants_1.DEFAULT_CONFIG === void 0 ? void 0 : constants_1.DEFAULT_CONFIG.PORT) !== null && _c !== void 0 ? _c : 3000;
|
|
31
|
+
const host = `${hostname}:${port}`;
|
|
32
|
+
const wsSchema = 'wss';
|
|
33
|
+
return {
|
|
27
34
|
deployment_model: 'LOCAL',
|
|
28
35
|
location: 'IE',
|
|
29
|
-
hostname: `${
|
|
30
|
-
ws_hostname: `${
|
|
31
|
-
}
|
|
36
|
+
hostname: `${schema}://${host}`,
|
|
37
|
+
ws_hostname: `${wsSchema}://${host}`
|
|
38
|
+
};
|
|
32
39
|
}));
|
|
33
40
|
fastify.get('/health', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
34
41
|
return ({
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { FastifyInstance } from 'fastify';
|
|
2
|
+
import { CorsConfig } from '../../';
|
|
2
3
|
import { Functions } from '../../features/functions/interface';
|
|
3
4
|
type RegisterFunction = FastifyInstance['register'];
|
|
4
5
|
type RegisterPluginsParams = {
|
|
@@ -6,6 +7,7 @@ type RegisterPluginsParams = {
|
|
|
6
7
|
mongodbUrl: string;
|
|
7
8
|
jwtSecret: string;
|
|
8
9
|
functionsList: Functions;
|
|
10
|
+
corsConfig?: CorsConfig;
|
|
9
11
|
};
|
|
10
12
|
/**
|
|
11
13
|
* > Used to register all plugins
|
|
@@ -14,6 +16,6 @@ type RegisterPluginsParams = {
|
|
|
14
16
|
* @param jwtSecret -> connection jwt
|
|
15
17
|
* @tested
|
|
16
18
|
*/
|
|
17
|
-
export declare const registerPlugins: ({ register, mongodbUrl, jwtSecret, functionsList }: RegisterPluginsParams) => Promise<void>;
|
|
19
|
+
export declare const registerPlugins: ({ register, mongodbUrl, jwtSecret, functionsList, corsConfig }: RegisterPluginsParams) => Promise<void>;
|
|
18
20
|
export {};
|
|
19
21
|
//# sourceMappingURL=registerPlugins.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registerPlugins.d.ts","sourceRoot":"","sources":["../../../src/utils/initializer/registerPlugins.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"registerPlugins.d.ts","sourceRoot":"","sources":["../../../src/utils/initializer/registerPlugins.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAEzC,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AAMnC,OAAO,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAA;AAE9D,KAAK,gBAAgB,GAAG,eAAe,CAAC,UAAU,CAAC,CAAA;AAGnD,KAAK,qBAAqB,GAAG;IAC3B,QAAQ,EAAE,gBAAgB,CAAA;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,SAAS,CAAA;IACxB,UAAU,CAAC,EAAE,UAAU,CAAA;CACxB,CAAA;AAQD;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAAU,gEAMnC,qBAAqB,kBAsBvB,CAAA"}
|
|
@@ -28,11 +28,12 @@ const constants_1 = require("../../constants");
|
|
|
28
28
|
* @param jwtSecret -> connection jwt
|
|
29
29
|
* @tested
|
|
30
30
|
*/
|
|
31
|
-
const registerPlugins = (_a) => __awaiter(void 0, [_a], void 0, function* ({ register, mongodbUrl, jwtSecret, functionsList }) {
|
|
31
|
+
const registerPlugins = (_a) => __awaiter(void 0, [_a], void 0, function* ({ register, mongodbUrl, jwtSecret, functionsList, corsConfig }) {
|
|
32
32
|
try {
|
|
33
33
|
const registersConfig = yield getRegisterConfig({
|
|
34
34
|
mongodbUrl,
|
|
35
35
|
jwtSecret,
|
|
36
|
+
corsConfig,
|
|
36
37
|
functionsList
|
|
37
38
|
});
|
|
38
39
|
registersConfig.forEach(({ plugin, options, pluginName }) => {
|
|
@@ -43,6 +44,7 @@ const registerPlugins = (_a) => __awaiter(void 0, [_a], void 0, function* ({ reg
|
|
|
43
44
|
catch (e) {
|
|
44
45
|
console.log('Registration FAILED --->', pluginName);
|
|
45
46
|
console.log('Error --->', e);
|
|
47
|
+
throw e;
|
|
46
48
|
}
|
|
47
49
|
});
|
|
48
50
|
}
|
|
@@ -57,15 +59,16 @@ exports.registerPlugins = registerPlugins;
|
|
|
57
59
|
* @param jwtSecret -> connection jwt
|
|
58
60
|
* @testable
|
|
59
61
|
*/
|
|
60
|
-
const getRegisterConfig = (_a) => __awaiter(void 0, [_a], void 0, function* ({ mongodbUrl, jwtSecret }) {
|
|
62
|
+
const getRegisterConfig = (_a) => __awaiter(void 0, [_a], void 0, function* ({ mongodbUrl, jwtSecret, corsConfig }) {
|
|
63
|
+
const corsOptions = corsConfig !== null && corsConfig !== void 0 ? corsConfig : {
|
|
64
|
+
origin: '*',
|
|
65
|
+
methods: ['POST', 'GET']
|
|
66
|
+
};
|
|
61
67
|
return [
|
|
62
68
|
{
|
|
63
69
|
pluginName: 'cors',
|
|
64
70
|
plugin: cors_1.default,
|
|
65
|
-
options:
|
|
66
|
-
origin: '*',
|
|
67
|
-
methods: ['POST', 'GET', 'DELETE']
|
|
68
|
-
}
|
|
71
|
+
options: corsOptions
|
|
69
72
|
},
|
|
70
73
|
{
|
|
71
74
|
pluginName: 'fastifyMongodb',
|
|
@@ -31,13 +31,20 @@ const evaluateExpression = (params, expression, user) => __awaiter(void 0, void
|
|
|
31
31
|
});
|
|
32
32
|
exports.evaluateExpression = evaluateExpression;
|
|
33
33
|
const evaluateComplexExpression = (condition, params, user) => __awaiter(void 0, void 0, void 0, function* () {
|
|
34
|
+
var _a;
|
|
34
35
|
const [key, config] = condition;
|
|
35
|
-
const
|
|
36
|
+
const functionConfig = config['%function'];
|
|
37
|
+
const { name, arguments: fnArguments } = functionConfig;
|
|
36
38
|
const functionsList = state_1.StateManager.select('functions');
|
|
37
39
|
const app = state_1.StateManager.select('app');
|
|
38
40
|
const currentFunction = functionsList[name];
|
|
41
|
+
const expansionContext = Object.assign(Object.assign(Object.assign({}, params.expansions), params.cursor), { '%%root': params.cursor, '%%user': user, '%%true': true, '%%false': false });
|
|
42
|
+
const expandedArguments = fnArguments && fnArguments.length
|
|
43
|
+
? ((_a = (0, rules_1.expandQuery)({ args: fnArguments }, expansionContext)
|
|
44
|
+
.args) !== null && _a !== void 0 ? _a : [])
|
|
45
|
+
: [params.cursor];
|
|
39
46
|
const response = yield (0, context_1.GenerateContext)({
|
|
40
|
-
args:
|
|
47
|
+
args: expandedArguments,
|
|
41
48
|
app,
|
|
42
49
|
rules: state_1.StateManager.select("rules"),
|
|
43
50
|
user,
|
|
@@ -45,5 +52,6 @@ const evaluateComplexExpression = (condition, params, user) => __awaiter(void 0,
|
|
|
45
52
|
functionsList,
|
|
46
53
|
services: services_1.services
|
|
47
54
|
});
|
|
48
|
-
|
|
55
|
+
const isTruthy = Boolean(response);
|
|
56
|
+
return key === '%%true' ? isTruthy : !isTruthy;
|
|
49
57
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commonValidators.d.ts","sourceRoot":"","sources":["../../../../src/utils/roles/machines/commonValidators.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAA;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAK5C,eAAO,MAAM,yBAAyB,GACpC,wBAAwB,cAAc,EACtC,aAAa,MAAM,0BAA0B,qBAS9C,CAAA;AAED,eAAO,MAAM,6BAA6B,GACxC,wBAAwB,cAAc,EACtC,aAAa,cAAc,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"commonValidators.d.ts","sourceRoot":"","sources":["../../../../src/utils/roles/machines/commonValidators.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAA;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAK5C,eAAO,MAAM,yBAAyB,GACpC,wBAAwB,cAAc,EACtC,aAAa,MAAM,0BAA0B,qBAS9C,CAAA;AAED,eAAO,MAAM,6BAA6B,GACxC,wBAAwB,cAAc,EACtC,aAAa,cAAc,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,iCAQ9C,CAAA;AAED,eAAO,MAAM,yBAAyB,GAAI,UAAU,cAAc,YAIjE,CAAA"}
|
|
@@ -12,7 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.checkFieldsPropertyExists = exports.evaluateTopLevelPermissionsFn = exports.evaluateDocumentFiltersFn = void 0;
|
|
13
13
|
const someAsync_1 = require("../../helpers/someAsync");
|
|
14
14
|
const helpers_1 = require("../helpers");
|
|
15
|
-
const readOnlyPermissions = ['read'];
|
|
15
|
+
const readOnlyPermissions = ['read', 'search'];
|
|
16
16
|
const readWritePermissions = ['write', 'delete', 'insert', ...readOnlyPermissions];
|
|
17
17
|
const evaluateDocumentFiltersFn = (_a, currentType_1) => __awaiter(void 0, [_a, currentType_1], void 0, function* ({ params, role, user }, currentType) {
|
|
18
18
|
var _b;
|
|
@@ -21,13 +21,17 @@ const evaluateDocumentFiltersFn = (_a, currentType_1) => __awaiter(void 0, [_a,
|
|
|
21
21
|
});
|
|
22
22
|
exports.evaluateDocumentFiltersFn = evaluateDocumentFiltersFn;
|
|
23
23
|
const evaluateTopLevelPermissionsFn = (_a, currentType_1) => __awaiter(void 0, [_a, currentType_1], void 0, function* ({ params, role, user }, currentType) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
const permission = role === null || role === void 0 ? void 0 : role[currentType];
|
|
25
|
+
if (typeof permission === 'undefined') {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
return yield (0, helpers_1.evaluateExpression)(params, permission, user);
|
|
27
29
|
});
|
|
28
30
|
exports.evaluateTopLevelPermissionsFn = evaluateTopLevelPermissionsFn;
|
|
29
31
|
const checkFieldsPropertyExists = ({ role }) => {
|
|
30
|
-
var _a;
|
|
31
|
-
|
|
32
|
+
var _a, _b;
|
|
33
|
+
const hasFields = !!Object.keys((_a = role === null || role === void 0 ? void 0 : role.fields) !== null && _a !== void 0 ? _a : {}).length;
|
|
34
|
+
const hasAdditional = !!Object.keys((_b = role === null || role === void 0 ? void 0 : role.additional_fields) !== null && _b !== void 0 ? _b : {}).length;
|
|
35
|
+
return hasFields || hasAdditional;
|
|
32
36
|
};
|
|
33
37
|
exports.checkFieldsPropertyExists = checkFieldsPropertyExists;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { MachineContext } from '../../interface';
|
|
2
|
+
export declare const evaluateDocumentFiltersReadFn: (context: MachineContext) => Promise<boolean>;
|
|
3
|
+
export declare const evaluateDocumentFiltersWriteFn: (context: MachineContext) => Promise<boolean>;
|
|
4
|
+
//# sourceMappingURL=validators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../../../../../../src/utils/roles/machines/read/B/validators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAGhD,eAAO,MAAM,6BAA6B,GAAI,SAAS,cAAc,qBACzB,CAAA;AAE5C,eAAO,MAAM,8BAA8B,GAAI,SAAS,cAAc,qBACzB,CAAA"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.evaluateDocumentFiltersWriteFn = exports.evaluateDocumentFiltersReadFn = void 0;
|
|
4
|
+
const commonValidators_1 = require("../../commonValidators");
|
|
5
|
+
const evaluateDocumentFiltersReadFn = (context) => (0, commonValidators_1.evaluateDocumentFiltersFn)(context, 'read');
|
|
6
|
+
exports.evaluateDocumentFiltersReadFn = evaluateDocumentFiltersReadFn;
|
|
7
|
+
const evaluateDocumentFiltersWriteFn = (context) => (0, commonValidators_1.evaluateDocumentFiltersFn)(context, 'write');
|
|
8
|
+
exports.evaluateDocumentFiltersWriteFn = evaluateDocumentFiltersWriteFn;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/utils/roles/machines/read/C/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/utils/roles/machines/read/C/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAGxC,eAAO,MAAM,aAAa,EAAE,MAyC3B,CAAA"}
|
|
@@ -10,7 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.STEP_C_STATES = void 0;
|
|
13
|
-
const
|
|
13
|
+
const validators_1 = require("./validators");
|
|
14
14
|
const utils_1 = require("../../utils");
|
|
15
15
|
exports.STEP_C_STATES = {
|
|
16
16
|
evaluateTopLevelRead: (_a) => __awaiter(void 0, [_a], void 0, function* ({ context, next, endValidation }) {
|
|
@@ -20,10 +20,13 @@ exports.STEP_C_STATES = {
|
|
|
20
20
|
step: 1,
|
|
21
21
|
stepName: 'evaluateTopLevelRead'
|
|
22
22
|
});
|
|
23
|
-
const check = yield (0,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
const check = yield (0, validators_1.evaluateTopLevelReadFn)(context);
|
|
24
|
+
if (check) {
|
|
25
|
+
return (0, validators_1.checkFieldsPropertyExists)(context)
|
|
26
|
+
? next('checkFieldsProperty')
|
|
27
|
+
: endValidation({ success: true });
|
|
28
|
+
}
|
|
29
|
+
return next('evaluateTopLevelWrite', { check });
|
|
27
30
|
}),
|
|
28
31
|
evaluateTopLevelWrite: (_a) => __awaiter(void 0, [_a], void 0, function* ({ context, next, endValidation }) {
|
|
29
32
|
var _b;
|
|
@@ -33,7 +36,7 @@ exports.STEP_C_STATES = {
|
|
|
33
36
|
step: 2,
|
|
34
37
|
stepName: 'evaluateTopLevelWrite'
|
|
35
38
|
});
|
|
36
|
-
const check = yield (0,
|
|
39
|
+
const check = yield (0, validators_1.evaluateTopLevelWriteFn)(context);
|
|
37
40
|
if (check)
|
|
38
41
|
return endValidation({ success: true });
|
|
39
42
|
return ((_b = context === null || context === void 0 ? void 0 : context.prevParams) === null || _b === void 0 ? void 0 : _b.check) === false
|
|
@@ -47,7 +50,7 @@ exports.STEP_C_STATES = {
|
|
|
47
50
|
step: 3,
|
|
48
51
|
stepName: 'checkFieldsProperty'
|
|
49
52
|
});
|
|
50
|
-
const check = (0,
|
|
53
|
+
const check = (0, validators_1.checkFieldsPropertyExists)(context);
|
|
51
54
|
return goToNextValidationStage(check ? 'checkIsValidFieldName' : 'checkAdditionalFields');
|
|
52
55
|
})
|
|
53
56
|
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { MachineContext } from '../../interface';
|
|
2
|
+
export declare const evaluateTopLevelReadFn: (context: MachineContext) => Promise<boolean | undefined>;
|
|
3
|
+
export declare const evaluateTopLevelWriteFn: (context: MachineContext) => Promise<boolean | undefined>;
|
|
4
|
+
export { checkFieldsPropertyExists } from '../../commonValidators';
|
|
5
|
+
//# sourceMappingURL=validators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../../../../../../src/utils/roles/machines/read/C/validators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAMhD,eAAO,MAAM,sBAAsB,GAAU,SAAS,cAAc,iCAKnE,CAAA;AAED,eAAO,MAAM,uBAAuB,GAAU,SAAS,cAAc,iCAKpE,CAAA;AAED,OAAO,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAA"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.checkFieldsPropertyExists = exports.evaluateTopLevelWriteFn = exports.evaluateTopLevelReadFn = void 0;
|
|
13
|
+
const commonValidators_1 = require("../../commonValidators");
|
|
14
|
+
const evaluateTopLevelReadFn = (context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
15
|
+
if (context.params.type !== 'read') {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
return (0, commonValidators_1.evaluateTopLevelPermissionsFn)(context, 'read');
|
|
19
|
+
});
|
|
20
|
+
exports.evaluateTopLevelReadFn = evaluateTopLevelReadFn;
|
|
21
|
+
const evaluateTopLevelWriteFn = (context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
22
|
+
if (!['read', 'write'].includes(context.params.type)) {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
return (0, commonValidators_1.evaluateTopLevelPermissionsFn)(context, 'write');
|
|
26
|
+
});
|
|
27
|
+
exports.evaluateTopLevelWriteFn = evaluateTopLevelWriteFn;
|
|
28
|
+
var commonValidators_2 = require("../../commonValidators");
|
|
29
|
+
Object.defineProperty(exports, "checkFieldsPropertyExists", { enumerable: true, get: function () { return commonValidators_2.checkFieldsPropertyExists; } });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/utils/roles/machines/read/D/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/utils/roles/machines/read/D/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAqBxD,eAAO,MAAM,aAAa,EAAE,MAa3B,CAAA"}
|
|
@@ -12,6 +12,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.STEP_D_STATES = void 0;
|
|
13
13
|
const utils_1 = require("../../utils");
|
|
14
14
|
const validators_1 = require("./validators");
|
|
15
|
+
const runCheckIsValidFieldName = (_a) => __awaiter(void 0, [_a], void 0, function* ({ context, endValidation }) {
|
|
16
|
+
(0, utils_1.logMachineInfo)({
|
|
17
|
+
enabled: context.enableLog,
|
|
18
|
+
machine: 'D',
|
|
19
|
+
step: 2,
|
|
20
|
+
stepName: 'checkIsValidFieldName'
|
|
21
|
+
});
|
|
22
|
+
const document = (0, validators_1.checkIsValidFieldNameFn)(context);
|
|
23
|
+
return endValidation({ success: !!Object.keys(document).length, document });
|
|
24
|
+
});
|
|
15
25
|
exports.STEP_D_STATES = {
|
|
16
26
|
checkAdditionalFields: (_a) => __awaiter(void 0, [_a], void 0, function* ({ context, next, endValidation }) {
|
|
17
27
|
(0, utils_1.logMachineInfo)({
|
|
@@ -21,16 +31,8 @@ exports.STEP_D_STATES = {
|
|
|
21
31
|
stepName: 'checkAdditionalFields'
|
|
22
32
|
});
|
|
23
33
|
const check = (0, validators_1.checkAdditionalFieldsFn)(context);
|
|
24
|
-
return check ? next('
|
|
34
|
+
return check ? next('evaluateRead') : endValidation({ success: false });
|
|
25
35
|
}),
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
enabled: context.enableLog,
|
|
29
|
-
machine: 'D',
|
|
30
|
-
step: 2,
|
|
31
|
-
stepName: 'checkIsValidFieldName'
|
|
32
|
-
});
|
|
33
|
-
const document = (0, validators_1.checkIsValidFieldNameFn)(context);
|
|
34
|
-
return endValidation({ success: !!Object.keys(document).length, document });
|
|
35
|
-
})
|
|
36
|
+
evaluateRead: runCheckIsValidFieldName,
|
|
37
|
+
checkIsValidFieldName: runCheckIsValidFieldName
|
|
36
38
|
};
|
package/dist/utils/rules.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare function expandQuery(template: Record<string, unknown>, objs: Record<string, unknown>):
|
|
1
|
+
export declare function expandQuery(template: Record<string, unknown>, objs: Record<string, unknown>): Record<string, unknown>;
|
|
2
2
|
//# sourceMappingURL=rules.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../src/utils/rules.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../src/utils/rules.ts"],"names":[],"mappings":"AAkCA,wBAAgB,WAAW,CACzB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAES,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAC9D"}
|
package/dist/utils/rules.js
CHANGED
|
@@ -5,23 +5,32 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.expandQuery = expandQuery;
|
|
7
7
|
const get_1 = __importDefault(require("lodash/get"));
|
|
8
|
-
const
|
|
9
|
-
|
|
8
|
+
const resolvePlaceholder = (value, objs) => {
|
|
9
|
+
if (!value.startsWith('%%'))
|
|
10
|
+
return value;
|
|
11
|
+
const path = value.slice(2);
|
|
12
|
+
const [rootKey, ...rest] = path.split('.');
|
|
13
|
+
const rootToken = `%%${rootKey}`;
|
|
14
|
+
const rootValue = objs[rootToken];
|
|
15
|
+
if (!rest.length) {
|
|
16
|
+
return rootValue === undefined ? value : rootValue;
|
|
17
|
+
}
|
|
18
|
+
const resolved = (0, get_1.default)(rootValue, rest.join('.'));
|
|
19
|
+
return resolved === undefined ? value : resolved;
|
|
10
20
|
};
|
|
11
|
-
|
|
21
|
+
const expandValue = (input, objs) => {
|
|
22
|
+
if (Array.isArray(input)) {
|
|
23
|
+
return input.map((item) => expandValue(item, objs));
|
|
24
|
+
}
|
|
25
|
+
if (input && typeof input === 'object') {
|
|
26
|
+
return Object.fromEntries(Object.entries(input).map(([key, val]) => [key, expandValue(val, objs)]));
|
|
27
|
+
}
|
|
28
|
+
if (typeof input === 'string') {
|
|
29
|
+
return resolvePlaceholder(input, objs);
|
|
30
|
+
}
|
|
31
|
+
return input;
|
|
32
|
+
};
|
|
33
|
+
// Espande dinamicamente i placeholder con supporto per array e percorsi annidati
|
|
12
34
|
function expandQuery(template, objs) {
|
|
13
|
-
|
|
14
|
-
const regex = /:\s*"%%([a-zA-Z0-9_.]+)"/g;
|
|
15
|
-
Object.keys(objs).forEach(() => {
|
|
16
|
-
// Espandi tutti i placeholder %%values.<nested.property>
|
|
17
|
-
const callback = (match, path) => {
|
|
18
|
-
const value = (0, get_1.default)(objs, `%%${path}`); // Recupera il valore annidato da values
|
|
19
|
-
const finalValue = typeof value === 'string' ? `"${value}"` : value && JSON.stringify(value);
|
|
20
|
-
// TODO tolto i primi : creava questo tipo di oggetto {"userId"::"%%user.id"}
|
|
21
|
-
const val = `:${value !== undefined ? finalValue : match}`; // Sostituisci se esiste, altrimenti lascia il placeholder
|
|
22
|
-
return removeExtraColons(val);
|
|
23
|
-
};
|
|
24
|
-
expandedQuery = expandedQuery.replace(regex, callback);
|
|
25
|
-
});
|
|
26
|
-
return JSON.parse(expandedQuery); // Converti la stringa JSON di nuovo in un oggetto
|
|
35
|
+
return expandValue(template, objs);
|
|
27
36
|
}
|
package/jest.config.ts
CHANGED
|
@@ -4,21 +4,11 @@ module.exports = {
|
|
|
4
4
|
'^.+\\.[tj]s$': [
|
|
5
5
|
'ts-jest',
|
|
6
6
|
{
|
|
7
|
-
tsconfig: '
|
|
7
|
+
tsconfig: '<rootDir>/tsconfig.json'
|
|
8
8
|
}
|
|
9
9
|
]
|
|
10
10
|
},
|
|
11
|
-
|
|
12
|
-
collectCoverageFrom: ['./**/*.ts'],
|
|
13
|
-
coverageDirectory: 'coverage',
|
|
14
|
-
coverageThreshold: {
|
|
15
|
-
global: {
|
|
16
|
-
branches: 50,
|
|
17
|
-
functions: 90,
|
|
18
|
-
lines: 90,
|
|
19
|
-
statements: 90
|
|
20
|
-
}
|
|
21
|
-
},
|
|
11
|
+
setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
|
|
22
12
|
testEnvironment: 'node',
|
|
23
13
|
testMatch: ['./**/*.test.ts']
|
|
24
14
|
}
|
package/jest.setup.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Blob as NodeBlob } from 'buffer'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
|
|
4
|
+
if (!process.env.FLOWERBASE_APP_PATH) {
|
|
5
|
+
process.env.FLOWERBASE_APP_PATH = path.resolve(__dirname, '../../tests/e2e/app')
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const BaseBlob = typeof globalThis.Blob !== 'undefined' ? globalThis.Blob : NodeBlob
|
|
9
|
+
|
|
10
|
+
type PolyfillFilePropertyBag = FilePropertyBag & {
|
|
11
|
+
name?: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
class FilePolyfill extends BaseBlob {
|
|
15
|
+
lastModified: number
|
|
16
|
+
name: string
|
|
17
|
+
|
|
18
|
+
constructor(bits?: Iterable<BlobPart>, options?: FilePropertyBag) {
|
|
19
|
+
super(bits, options as FilePropertyBag)
|
|
20
|
+
const fileOptions = options as PolyfillFilePropertyBag
|
|
21
|
+
this.name = fileOptions?.name ?? ''
|
|
22
|
+
this.lastModified = fileOptions?.lastModified ?? Date.now()
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (typeof globalThis.File === 'undefined') {
|
|
27
|
+
globalThis.File = FilePolyfill as unknown as typeof File
|
|
28
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flowerforce/flowerbase",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.1-beta.10",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -25,7 +25,6 @@
|
|
|
25
25
|
"@fastify/mongodb": "^9.0.1",
|
|
26
26
|
"@fastify/swagger": "^9.5.1",
|
|
27
27
|
"@fastify/swagger-ui": "^5.2.3",
|
|
28
|
-
"@sendgrid/mail": "^8.1.4",
|
|
29
28
|
"aws-sdk": "^2.1692.0",
|
|
30
29
|
"bson": "^6.8.0",
|
|
31
30
|
"dotenv": "^16.4.7",
|
package/src/auth/controller.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { ObjectId } from 'bson'
|
|
2
2
|
import { FastifyInstance } from 'fastify'
|
|
3
|
-
import { AUTH_CONFIG, DB_NAME } from '../constants'
|
|
3
|
+
import { AUTH_CONFIG, DB_NAME, DEFAULT_CONFIG } from '../constants'
|
|
4
4
|
import { SessionCreatedDto } from './dtos'
|
|
5
5
|
import { AUTH_ENDPOINTS, AUTH_ERRORS } from './utils'
|
|
6
|
+
import { hashToken } from '../utils/crypto'
|
|
6
7
|
|
|
7
8
|
const HANDLER_TYPE = 'preHandler'
|
|
8
9
|
|
|
@@ -12,9 +13,19 @@ const HANDLER_TYPE = 'preHandler'
|
|
|
12
13
|
* @param {FastifyInstance} app - The Fastify instance.
|
|
13
14
|
*/
|
|
14
15
|
export async function authController(app: FastifyInstance) {
|
|
15
|
-
const { authCollection, userCollection } = AUTH_CONFIG
|
|
16
|
+
const { authCollection, userCollection, refreshTokensCollection } = AUTH_CONFIG
|
|
16
17
|
|
|
17
18
|
const db = app.mongo.client.db(DB_NAME)
|
|
19
|
+
const refreshTokenTtlMs = DEFAULT_CONFIG.REFRESH_TOKEN_TTL_DAYS * 24 * 60 * 60 * 1000
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
await db.collection(refreshTokensCollection).createIndex(
|
|
23
|
+
{ expiresAt: 1 },
|
|
24
|
+
{ expireAfterSeconds: 0 }
|
|
25
|
+
)
|
|
26
|
+
} catch (error) {
|
|
27
|
+
console.error('Failed to ensure refresh token TTL index', error)
|
|
28
|
+
}
|
|
18
29
|
|
|
19
30
|
app.addHook(HANDLER_TYPE, app.jwtAuthentication)
|
|
20
31
|
|
|
@@ -26,6 +37,9 @@ export async function authController(app: FastifyInstance) {
|
|
|
26
37
|
* @returns {Promise<Object>} A promise resolving with the user's profile data.
|
|
27
38
|
*/
|
|
28
39
|
app.get(AUTH_ENDPOINTS.PROFILE, async function (req) {
|
|
40
|
+
if (req.user.typ !== 'access') {
|
|
41
|
+
throw new Error('Access token required')
|
|
42
|
+
}
|
|
29
43
|
const user = await db
|
|
30
44
|
.collection<Record<string, unknown>>(authCollection)
|
|
31
45
|
.findOne({ _id: ObjectId.createFromHexString(req.user.id) })
|
|
@@ -56,6 +70,21 @@ export async function authController(app: FastifyInstance) {
|
|
|
56
70
|
throw new Error(AUTH_ERRORS.INVALID_TOKEN)
|
|
57
71
|
}
|
|
58
72
|
|
|
73
|
+
const authHeader = req.headers.authorization
|
|
74
|
+
if (!authHeader?.startsWith('Bearer ')) {
|
|
75
|
+
throw new Error(AUTH_ERRORS.INVALID_TOKEN)
|
|
76
|
+
}
|
|
77
|
+
const refreshToken = authHeader.slice('Bearer '.length).trim()
|
|
78
|
+
const refreshTokenHash = hashToken(refreshToken)
|
|
79
|
+
const storedToken = await db.collection(refreshTokensCollection).findOne({
|
|
80
|
+
tokenHash: refreshTokenHash,
|
|
81
|
+
revokedAt: null,
|
|
82
|
+
expiresAt: { $gt: new Date() }
|
|
83
|
+
})
|
|
84
|
+
if (!storedToken) {
|
|
85
|
+
throw new Error(AUTH_ERRORS.INVALID_TOKEN)
|
|
86
|
+
}
|
|
87
|
+
|
|
59
88
|
const auth_user = await db
|
|
60
89
|
?.collection(authCollection)
|
|
61
90
|
.findOne({ _id: new this.mongo.ObjectId(req.user.sub) })
|
|
@@ -82,8 +111,45 @@ export async function authController(app: FastifyInstance) {
|
|
|
82
111
|
*/
|
|
83
112
|
app.delete(
|
|
84
113
|
AUTH_ENDPOINTS.SESSION,
|
|
85
|
-
async function () {
|
|
86
|
-
|
|
114
|
+
async function (req, res) {
|
|
115
|
+
const authHeader = req.headers.authorization
|
|
116
|
+
if (!authHeader?.startsWith('Bearer ')) {
|
|
117
|
+
res.status(204)
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
const refreshToken = authHeader.slice('Bearer '.length).trim()
|
|
121
|
+
const refreshTokenHash = hashToken(refreshToken)
|
|
122
|
+
const now = new Date()
|
|
123
|
+
const expiresAt = new Date(Date.now() + refreshTokenTtlMs)
|
|
124
|
+
const updateResult = await db.collection(refreshTokensCollection).findOneAndUpdate(
|
|
125
|
+
{ tokenHash: refreshTokenHash },
|
|
126
|
+
{
|
|
127
|
+
$set: {
|
|
128
|
+
revokedAt: now,
|
|
129
|
+
expiresAt
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
{ returnDocument: 'after' }
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
const fromToken = req.user?.sub
|
|
136
|
+
let userId = updateResult?.value?.userId
|
|
137
|
+
if (!userId && fromToken) {
|
|
138
|
+
try {
|
|
139
|
+
userId = new ObjectId(fromToken)
|
|
140
|
+
} catch {
|
|
141
|
+
userId = fromToken
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (userId && authCollection) {
|
|
146
|
+
await db.collection(authCollection).updateOne(
|
|
147
|
+
{ _id: userId },
|
|
148
|
+
{ $set: { lastLogoutAt: now } }
|
|
149
|
+
)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return { status: 'ok' }
|
|
87
153
|
}
|
|
88
154
|
)
|
|
89
155
|
}
|