@internetderdinge/api 1.229.2 → 1.229.4
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/dist/src/accounts/accounts.controller.js +7 -5
- package/dist/src/accounts/accounts.service.js +4 -4
- package/dist/src/accounts/accounts.validation.js +4 -12
- package/dist/src/accounts/auth0.service.js +25 -25
- package/dist/src/devices/devices.route.js +12 -2
- package/dist/src/devicesNotifications/devicesNotifications.controller.js +1 -0
- package/dist/src/middlewares/auth.js +2 -0
- package/dist/src/middlewares/validateAdmin.js +7 -5
- package/dist/src/users/users.route.js +0 -2
- package/dist/src/users/users.service.js +2 -0
- package/dist/src/users/users.validation.js +10 -16
- package/dist/src/utils/buildRouterAndDocs.js +0 -1
- package/dist/src/utils/userName.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/accounts/accounts.controller.ts +8 -5
- package/src/accounts/accounts.service.ts +4 -4
- package/src/accounts/accounts.validation.ts +19 -24
- package/src/accounts/auth0.service.ts +20 -16
- package/src/devices/devices.route.ts +11 -0
- package/src/devicesNotifications/devicesNotifications.controller.ts +2 -0
- package/src/middlewares/auth.ts +3 -1
- package/src/middlewares/validateAdmin.ts +18 -7
- package/src/users/users.route.ts +0 -2
- package/src/users/users.service.ts +14 -0
- package/src/users/users.validation.ts +10 -17
- package/src/utils/buildRouterAndDocs.ts +0 -2
- package/src/utils/userName.ts +1 -1
|
@@ -10,13 +10,13 @@ const getAccountById = catchAsync(async (req, res) => {
|
|
|
10
10
|
throw new ApiError(httpStatus.NOT_FOUND, "Account not found");
|
|
11
11
|
}
|
|
12
12
|
res.send({
|
|
13
|
-
...account
|
|
13
|
+
...account,
|
|
14
14
|
notification: entryDeviceNotifications?.settings,
|
|
15
15
|
});
|
|
16
16
|
});
|
|
17
17
|
const setDeviceToken = catchAsync(async (req, res) => {
|
|
18
18
|
const account = await accountsService.getAccountById(req.auth.sub);
|
|
19
|
-
const devices = account.
|
|
19
|
+
const devices = account.app_metadata.devices || [];
|
|
20
20
|
const alreadyExisting = devices.find((d) => d.fck === req.body.token);
|
|
21
21
|
if (!alreadyExisting) {
|
|
22
22
|
devices.push({ fck: req.body.token });
|
|
@@ -34,7 +34,8 @@ const avatar = catchAsync(async (req, res) => {
|
|
|
34
34
|
});
|
|
35
35
|
const updateEntry = catchAsync(async (req, res) => {
|
|
36
36
|
const account = await accountsService.getAccountById(req.auth.sub);
|
|
37
|
-
|
|
37
|
+
console.log("account", account);
|
|
38
|
+
const { isSocial } = account.identities[0];
|
|
38
39
|
const { given_name, family_name, email, notification, ...updateBody } = req.body;
|
|
39
40
|
const trimmedGivenName = typeof given_name === "string" ? given_name.trim() : undefined;
|
|
40
41
|
const trimmedFamilyName = typeof family_name === "string" ? family_name.trim() : undefined;
|
|
@@ -42,7 +43,7 @@ const updateEntry = catchAsync(async (req, res) => {
|
|
|
42
43
|
const hasFamilyName = !!trimmedFamilyName;
|
|
43
44
|
const update = isSocial
|
|
44
45
|
? {
|
|
45
|
-
...account.
|
|
46
|
+
...account.app_metadata,
|
|
46
47
|
...updateBody,
|
|
47
48
|
...(hasGivenName ? { first_name: trimmedGivenName } : {}),
|
|
48
49
|
...(hasFamilyName ? { last_name: trimmedFamilyName } : {}),
|
|
@@ -75,7 +76,8 @@ const deleteCurrent = catchAsync(async (req, res) => {
|
|
|
75
76
|
});
|
|
76
77
|
const current = catchAsync(async (req, res) => {
|
|
77
78
|
const user = await accountsService.getAccountById(req.auth.sub);
|
|
78
|
-
|
|
79
|
+
console.log("user", user);
|
|
80
|
+
res.send(user);
|
|
79
81
|
});
|
|
80
82
|
const mfaEnroll = catchAsync(async (req, res) => {
|
|
81
83
|
const { mfaEnroll } = req.body;
|
|
@@ -6,7 +6,7 @@ import { auth0, mfaDisableAccount, mfaEnrollAccount } from "./auth0.service.js";
|
|
|
6
6
|
* @returns {Promise<Stock>}
|
|
7
7
|
*/
|
|
8
8
|
export const getAccountById = async (id) => {
|
|
9
|
-
return auth0.users.get(
|
|
9
|
+
return auth0.users.get(id);
|
|
10
10
|
};
|
|
11
11
|
/**
|
|
12
12
|
* Get user by email
|
|
@@ -39,20 +39,20 @@ export const mfaDisable = async (userId) => {
|
|
|
39
39
|
*/
|
|
40
40
|
export const updateMetaDataById = async (id, updateBody) => {
|
|
41
41
|
// now use the generic update and pass app_metadata
|
|
42
|
-
return auth0.users.update(
|
|
42
|
+
return auth0.users.update(id, { app_metadata: updateBody });
|
|
43
43
|
};
|
|
44
44
|
/**
|
|
45
45
|
* Update user by id
|
|
46
46
|
*/
|
|
47
47
|
export const updateUserById = async (id, updateBody) => {
|
|
48
48
|
// switch to the v3 ManagementClient users.update
|
|
49
|
-
return auth0.users.update(
|
|
49
|
+
return auth0.users.update(id, updateBody);
|
|
50
50
|
};
|
|
51
51
|
/**
|
|
52
52
|
* Delete user by id
|
|
53
53
|
*/
|
|
54
54
|
export const deleteById = async (userId) => {
|
|
55
|
-
return auth0.users.delete(
|
|
55
|
+
return auth0.users.delete(userId);
|
|
56
56
|
};
|
|
57
57
|
export default {
|
|
58
58
|
getAccountById,
|
|
@@ -23,9 +23,7 @@ export const createAccountSchema = {
|
|
|
23
23
|
export const getUsersSchema = zPagination;
|
|
24
24
|
export const getAccountSchema = {
|
|
25
25
|
params: z.object({
|
|
26
|
-
accountId: z
|
|
27
|
-
.string()
|
|
28
|
-
.openapi({
|
|
26
|
+
accountId: z.string().openapi({
|
|
29
27
|
example: process.env.SCHEMA_EXAMPLE_ACCOUNT_ID || "auth0|60452f4c0dc85b0062326",
|
|
30
28
|
description: "Auth Account ID",
|
|
31
29
|
}),
|
|
@@ -33,9 +31,7 @@ export const getAccountSchema = {
|
|
|
33
31
|
};
|
|
34
32
|
export const updateAccountSchema = {
|
|
35
33
|
params: z.object({
|
|
36
|
-
accountId: z
|
|
37
|
-
.string()
|
|
38
|
-
.openapi({
|
|
34
|
+
accountId: z.string().openapi({
|
|
39
35
|
example: process.env.SCHEMA_EXAMPLE_ACCOUNT_ID || "auth0|60452f4c0dc85b0062326",
|
|
40
36
|
description: "Auth Account ID",
|
|
41
37
|
}),
|
|
@@ -52,9 +48,7 @@ export const updateAccountSchema = {
|
|
|
52
48
|
.optional()
|
|
53
49
|
.openapi({ example: "female", description: "Gender" }),
|
|
54
50
|
email: z
|
|
55
|
-
.string()
|
|
56
|
-
.email()
|
|
57
|
-
.optional()
|
|
51
|
+
.preprocess((value) => (value === "" ? undefined : value), z.string().email().optional())
|
|
58
52
|
.openapi({ description: "User email address" }),
|
|
59
53
|
given_name: z
|
|
60
54
|
.string()
|
|
@@ -74,9 +68,7 @@ export const updateAccountSchema = {
|
|
|
74
68
|
};
|
|
75
69
|
export const deleteEntrySchema = {
|
|
76
70
|
params: z.object({
|
|
77
|
-
accountId: z
|
|
78
|
-
.string()
|
|
79
|
-
.openapi({
|
|
71
|
+
accountId: z.string().openapi({
|
|
80
72
|
example: process.env.SCHEMA_EXAMPLE_ACCOUNT_ID || "auth0|60452f4c0dc85b0062326",
|
|
81
73
|
description: "Auth Account ID",
|
|
82
74
|
}),
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
import { AuthenticationClient, ManagementClient } from "auth0";
|
|
3
|
-
import { promises as fs
|
|
3
|
+
import { promises as fs } from "fs";
|
|
4
4
|
let tokenManagementClient = {
|
|
5
5
|
clientId: process.env.AUTH0_CLIENT_ID,
|
|
6
6
|
clientSecret: process.env.AUTH0_CLIENT_SECRET,
|
|
7
7
|
};
|
|
8
8
|
//if (config.env !== 'production') {
|
|
9
|
+
/*
|
|
9
10
|
try {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
11
|
+
console.warn("Auth0 client: use local token from cache try");
|
|
12
|
+
const token = readFileSync("./token.txt", "utf8");
|
|
13
|
+
console.warn("Auth0 client: use local token from cache");
|
|
14
|
+
tokenManagementClient = { token };
|
|
15
|
+
} catch (error) {
|
|
16
|
+
console.log("Auth0 Client: use new token");
|
|
17
|
+
} */
|
|
18
18
|
//}
|
|
19
19
|
// IoT Api
|
|
20
20
|
/*
|
|
@@ -91,10 +91,10 @@ export const getAuth0Token = async () => {
|
|
|
91
91
|
pendingTokenPromise = null;
|
|
92
92
|
return cachedToken;
|
|
93
93
|
}
|
|
94
|
-
|
|
94
|
+
console.warn("Auth0 Client: Requesting new token from Auth0");
|
|
95
95
|
const tokenResponse = await auth0AuthClient.oauth.clientCredentialsGrant(grantOpts);
|
|
96
|
-
const expiresIn = tokenResponse.
|
|
97
|
-
cachedToken = tokenResponse.
|
|
96
|
+
const expiresIn = tokenResponse.expires_in || 3600;
|
|
97
|
+
cachedToken = tokenResponse.access_token;
|
|
98
98
|
tokenExpiresAt = now + expiresIn;
|
|
99
99
|
// if (process.env.NODE_ENV !== 'production') {
|
|
100
100
|
await writeTokenFile(TOKEN_FILE_PATH, cachedToken, tokenExpiresAt);
|
|
@@ -123,6 +123,7 @@ export const getAuth0ManagementToken = async () => {
|
|
|
123
123
|
pendingManagementTokenPromise = null;
|
|
124
124
|
return cachedManagementToken;
|
|
125
125
|
}
|
|
126
|
+
console.warn("Auth0 Management Client: Requesting new token from Auth0");
|
|
126
127
|
const tokenResponse = await auth0AuthClient.oauth.clientCredentialsGrant(grantOpts);
|
|
127
128
|
const expiresIn = tokenResponse.data.expires_in || 3600;
|
|
128
129
|
cachedManagementToken = tokenResponse.data.access_token;
|
|
@@ -139,42 +140,41 @@ export const auth0 = new ManagementClient({
|
|
|
139
140
|
token: getAuth0ManagementToken,
|
|
140
141
|
});
|
|
141
142
|
export const getUserIdByEmail = async (email) => {
|
|
142
|
-
|
|
143
|
-
return auth0.usersByEmail.getByEmail({ email });
|
|
143
|
+
return auth0.users.listUsersByEmail({ email });
|
|
144
144
|
};
|
|
145
145
|
export const sendVerificationEmail = async (userID) => {
|
|
146
|
-
return auth0.
|
|
146
|
+
return auth0.tickets.verifyEmail({ user_id: userID });
|
|
147
147
|
};
|
|
148
148
|
export const getUserById = async (userId) => {
|
|
149
|
-
return auth0.users.get(
|
|
149
|
+
return auth0.users.get(userId);
|
|
150
150
|
};
|
|
151
151
|
export const avatar = async (userId) => {
|
|
152
|
-
return auth0.users.get(
|
|
152
|
+
return auth0.users.get(userId);
|
|
153
153
|
};
|
|
154
154
|
export const mfaEnrollAccount = async (userId, mfaToken) => {
|
|
155
|
-
const ticketResponse = await auth0.guardian.
|
|
155
|
+
const ticketResponse = await auth0.guardian.enrollments.createTicket({
|
|
156
156
|
user_id: userId,
|
|
157
157
|
send_mail: false,
|
|
158
158
|
});
|
|
159
159
|
return ticketResponse;
|
|
160
160
|
};
|
|
161
161
|
export const mfaDisableAccount = async (userId) => {
|
|
162
|
-
await auth0.users.
|
|
162
|
+
await auth0.users.authenticationMethods.deleteAll(userId);
|
|
163
163
|
return { success: true };
|
|
164
164
|
};
|
|
165
165
|
export const getUsersByIds = async (postIDs) => {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
});
|
|
166
|
+
const userIds = postIDs.filter(Boolean);
|
|
167
|
+
if (!userIds.length)
|
|
168
|
+
return [];
|
|
169
|
+
const q = userIds.map((id) => `user_id:"${id}"`).join(" OR ");
|
|
171
170
|
const params = {
|
|
172
171
|
search_engine: "v3",
|
|
173
172
|
q,
|
|
174
173
|
per_page: 100,
|
|
175
174
|
page: 0,
|
|
176
175
|
};
|
|
177
|
-
|
|
176
|
+
const page = await auth0.users.list(params);
|
|
177
|
+
return page || [];
|
|
178
178
|
};
|
|
179
179
|
export default {
|
|
180
180
|
auth0,
|
|
@@ -7,9 +7,9 @@ import { validateQuerySearchUserAndOrganization } from "../middlewares/validateQ
|
|
|
7
7
|
import { validateDevice } from "../middlewares/validateDevice.js";
|
|
8
8
|
import * as devicesController from "./devices.controller.js";
|
|
9
9
|
import { resetDevice } from "./devices.controller.js";
|
|
10
|
-
import { createDeviceSchema, queryDevicesSchema, getDeviceSchema, getEventsSchema, pingDeviceSchema, registerDeviceSchema, ledLightSchema, rebootDeviceSchema, getImageSchema, updateSingleImageMetaSchema, uploadSingleImageSchema, resetDeviceSchema, } from "./devices.validation.js";
|
|
10
|
+
import { createDeviceSchema, queryDevicesSchema, getDeviceSchema, updateDeviceSchema, getEventsSchema, pingDeviceSchema, registerDeviceSchema, ledLightSchema, rebootDeviceSchema, getImageSchema, updateSingleImageMetaSchema, uploadSingleImageSchema, resetDeviceSchema, } from "./devices.validation.js";
|
|
11
11
|
import { deviceResponseSchema, devicesResponseSchema, eventResponseSchema, genericResponseSchema, imageResponseSchema, uploadResponseSchema, resetResponseSchema, } from "./devices.schemas.js";
|
|
12
|
-
import { validateOrganizationDelete, } from "../middlewares/validateAction.js";
|
|
12
|
+
import { validateOrganizationDelete, validateOrganizationUpdate, } from "../middlewares/validateAction.js";
|
|
13
13
|
export const devicesRouteSpecs = [
|
|
14
14
|
{
|
|
15
15
|
method: "post",
|
|
@@ -58,6 +58,16 @@ export const devicesRouteSpecs = [
|
|
|
58
58
|
{
|
|
59
59
|
method: "post",
|
|
60
60
|
path: "/:deviceId",
|
|
61
|
+
validate: [auth("manageUsers"), validateDevice, validateOrganizationUpdate],
|
|
62
|
+
requestSchema: updateDeviceSchema,
|
|
63
|
+
responseSchema: deviceResponseSchema,
|
|
64
|
+
handler: devicesController.updateEntry,
|
|
65
|
+
summary: "Update a device",
|
|
66
|
+
description: "Modify the properties of an existing device identified by its ID.",
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
method: "delete",
|
|
70
|
+
path: "/:deviceId",
|
|
61
71
|
handler: devicesController.deleteEntry,
|
|
62
72
|
summary: "Delete a device",
|
|
63
73
|
description: "Remove the specified device from the system.",
|
|
@@ -16,6 +16,7 @@ export const setDeviceToken = catchAsync(async (req, res) => {
|
|
|
16
16
|
user: res.req.auth.sub,
|
|
17
17
|
body: req.body,
|
|
18
18
|
});
|
|
19
|
+
console.log("Setting device tokenddddd for user:", res.req.auth.sub);
|
|
19
20
|
res.status(httpStatus.CREATED).send(user);
|
|
20
21
|
});
|
|
21
22
|
export const removeDeviceToken = catchAsync(async (req, res) => {
|
|
@@ -20,8 +20,10 @@ const verifyCallback = (req, resolve, reject, requiredRights) => async (err, use
|
|
|
20
20
|
resolve();
|
|
21
21
|
};
|
|
22
22
|
const auth = function authFactory(...requiredRights) {
|
|
23
|
+
console.log("Creating auth middleware with required rights:", requiredRights);
|
|
23
24
|
return async function authMiddleware(req, res, next) {
|
|
24
25
|
try {
|
|
26
|
+
console.log("Authenticating request:");
|
|
25
27
|
// Check for custom token in X-API-Key header
|
|
26
28
|
const apiKey = req.headers["x-api-key"];
|
|
27
29
|
if (apiKey && apiKey.length === 64) {
|
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
import httpStatus from
|
|
2
|
-
import ApiError from
|
|
1
|
+
import httpStatus from "http-status";
|
|
2
|
+
import ApiError from "../utils/ApiError";
|
|
3
3
|
const isAdmin = (user) => {
|
|
4
|
-
|
|
4
|
+
return false;
|
|
5
5
|
if (!user)
|
|
6
6
|
return false;
|
|
7
7
|
// return false; // TODO: Remove this line when the user object is properly defined
|
|
8
|
-
return user[
|
|
8
|
+
return user["https://memo.wirewire.de/roles"]
|
|
9
|
+
? user["https://memo.wirewire.de/roles"].includes("admin")
|
|
10
|
+
: false;
|
|
9
11
|
};
|
|
10
12
|
const validateAdmin = async (req, res, next) => {
|
|
11
13
|
if (isAdmin(req.auth)) {
|
|
12
14
|
next();
|
|
13
15
|
}
|
|
14
16
|
else {
|
|
15
|
-
next(new ApiError(httpStatus.FORBIDDEN,
|
|
17
|
+
next(new ApiError(httpStatus.FORBIDDEN, "User is not part of the admin group (validateAdmin)"));
|
|
16
18
|
}
|
|
17
19
|
};
|
|
18
20
|
export { isAdmin, validateAdmin };
|
|
@@ -108,7 +108,6 @@ export const userRouteSpecs = [
|
|
|
108
108
|
handler: userController.updateUser,
|
|
109
109
|
summary: "Update a user by ID",
|
|
110
110
|
description: "Replaces a user’s full record with the provided data.",
|
|
111
|
-
memoOnly: true,
|
|
112
111
|
},
|
|
113
112
|
{
|
|
114
113
|
method: "patch",
|
|
@@ -119,7 +118,6 @@ export const userRouteSpecs = [
|
|
|
119
118
|
handler: userController.updateUser,
|
|
120
119
|
summary: "Partially update a user by ID",
|
|
121
120
|
description: "Applies partial updates to a user’s record by ID.",
|
|
122
|
-
memoOnly: true,
|
|
123
121
|
},
|
|
124
122
|
{
|
|
125
123
|
method: "delete",
|
|
@@ -104,7 +104,9 @@ export const getUserByOwner = async (owner, organization) => {
|
|
|
104
104
|
const user = await User.findOne({ owner, organization });
|
|
105
105
|
if (!user)
|
|
106
106
|
return null;
|
|
107
|
+
console.log("Found user for owner and organization:", owner, organization, user);
|
|
107
108
|
const auth0User = await populateAuth0User(user);
|
|
109
|
+
console.log("Found user for owner and organizationddddddd:", owner, organization, user);
|
|
108
110
|
const json = user.toJSON();
|
|
109
111
|
json.auth0User = auth0User;
|
|
110
112
|
return json;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { extendZodWithOpenApi } from "@asteasolutions/zod-to-openapi";
|
|
4
|
-
import { password } from "../validations/custom.validation.js";
|
|
5
4
|
import { zPagination, zGet, zObjectId, zObjectIdFor, zPatchBody, zUpdate, zDelete, } from "../utils/zValidations.js";
|
|
6
5
|
extendZodWithOpenApi(z);
|
|
7
6
|
export const createUserSchema = {
|
|
@@ -55,19 +54,6 @@ export const getCurrentUserSchema = {
|
|
|
55
54
|
export const updateUserSchema = {
|
|
56
55
|
...zUpdate("userId"),
|
|
57
56
|
body: zPatchBody({
|
|
58
|
-
password: z
|
|
59
|
-
.string()
|
|
60
|
-
.refine((val) => {
|
|
61
|
-
try {
|
|
62
|
-
password(val);
|
|
63
|
-
return true;
|
|
64
|
-
}
|
|
65
|
-
catch {
|
|
66
|
-
return false;
|
|
67
|
-
}
|
|
68
|
-
}, { message: "Invalid password format" })
|
|
69
|
-
.optional()
|
|
70
|
-
.openapi({ description: "New user password" }),
|
|
71
57
|
name: z.string().optional().openapi({ description: "User full name" }),
|
|
72
58
|
timezone: z.string().optional().openapi({ description: "IANA timezone" }),
|
|
73
59
|
avatar: z.string().optional().openapi({ description: "Avatar URL" }),
|
|
@@ -89,7 +75,11 @@ export const updateUserSchema = {
|
|
|
89
75
|
.enum(["user", "admin", "patient", "onlyself"])
|
|
90
76
|
.optional()
|
|
91
77
|
.openapi({ description: "User role" }),
|
|
92
|
-
inviteCode: z
|
|
78
|
+
inviteCode: z
|
|
79
|
+
.string()
|
|
80
|
+
.nullable()
|
|
81
|
+
.optional()
|
|
82
|
+
.openapi({ description: "Invite code" }),
|
|
93
83
|
organization: zObjectId
|
|
94
84
|
.optional()
|
|
95
85
|
.openapi({ description: "Organization ObjectId" }),
|
|
@@ -107,7 +97,11 @@ export const updateInviteSchema = {
|
|
|
107
97
|
body: z.object({
|
|
108
98
|
organization: zObjectId.openapi({ description: "Organization ObjectId" }),
|
|
109
99
|
status: z.enum(["accepted"]).openapi({ description: "Invite status" }),
|
|
110
|
-
inviteCode: z
|
|
100
|
+
inviteCode: z
|
|
101
|
+
.string()
|
|
102
|
+
.nullable()
|
|
103
|
+
.optional()
|
|
104
|
+
.openapi({ description: "Invite code" }),
|
|
111
105
|
}),
|
|
112
106
|
};
|
|
113
107
|
export const organizationRemoveSchema = {
|
|
@@ -3,7 +3,7 @@ import { getUserById } from "../accounts/auth0.service";
|
|
|
3
3
|
const generateUserName = async (patient) => {
|
|
4
4
|
if (patient.owner) {
|
|
5
5
|
const auth0UserById = await getUserById(patient.owner);
|
|
6
|
-
patient.auth0User = auth0UserById
|
|
6
|
+
patient.auth0User = auth0UserById;
|
|
7
7
|
}
|
|
8
8
|
if (patient?.auth0User?.app_metadata?.first_name) {
|
|
9
9
|
return `${patient.auth0User.app_metadata.first_name} ${patient.auth0User.app_metadata.last_name}`;
|