Skip to content

Commit ffdd155

Browse files
julio-rocketchatsampaiodiegokodiakhq[bot]
authored
chore: replace suretype with zod (#35154)
Co-authored-by: Diego Sampaio <chinello@gmail.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
1 parent ffc258d commit ffdd155

File tree

7 files changed

+240
-319
lines changed

7 files changed

+240
-319
lines changed

apps/meteor/app/cloud/server/functions/getWorkspaceLicense.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { Cloud, Serialized } from '@rocket.chat/core-typings';
22
import { Settings } from '@rocket.chat/models';
33
import { serverFetch as fetch } from '@rocket.chat/server-fetch';
4-
import { v, compile } from 'suretype';
4+
import { z } from 'zod';
55

66
import { callbacks } from '../../../../lib/callbacks';
77
import { CloudWorkspaceConnectionError } from '../../../../lib/errors/CloudWorkspaceConnectionError';
@@ -11,17 +11,14 @@ import { settings } from '../../../settings/server';
1111
import { LICENSE_VERSION } from '../license';
1212
import { getWorkspaceAccessToken } from './getWorkspaceAccessToken';
1313

14-
const workspaceLicensePayloadSchema = v.object({
15-
version: v.number().required(),
16-
address: v.string().required(),
17-
license: v.string().required(),
18-
updatedAt: v.string().format('date-time').required(),
19-
modules: v.string().required(),
20-
expireAt: v.string().format('date-time').required(),
14+
const workspaceLicensePayloadSchema = z.object({
15+
version: z.number(),
16+
address: z.string(),
17+
license: z.string(),
18+
updatedAt: z.string().datetime(),
19+
expireAt: z.string().datetime(),
2120
});
2221

23-
const assertWorkspaceLicensePayload = compile(workspaceLicensePayloadSchema);
24-
2522
const fetchCloudWorkspaceLicensePayload = async ({ token }: { token: string }): Promise<Serialized<Cloud.WorkspaceLicensePayload>> => {
2623
const workspaceRegistrationClientUri = settings.get<string>('Cloud_Workspace_Registration_Client_Uri');
2724
const response = await fetch(`${workspaceRegistrationClientUri}/license`, {
@@ -44,14 +41,19 @@ const fetchCloudWorkspaceLicensePayload = async ({ token }: { token: string }):
4441

4542
const payload = await response.json();
4643

47-
assertWorkspaceLicensePayload(payload);
44+
const assertWorkspaceLicensePayload = workspaceLicensePayloadSchema.safeParse(payload);
45+
46+
if (!assertWorkspaceLicensePayload.success) {
47+
SystemLogger.error({ msg: 'workspaceLicensePayloadSchema failed type validation', errors: assertWorkspaceLicensePayload.error.errors });
48+
}
4849

4950
return payload;
5051
};
5152

5253
export async function getWorkspaceLicense() {
5354
const currentLicense = await Settings.findOne('Cloud_Workspace_License');
5455
// it should never happen, since even if the license is not found, it will return an empty settings
56+
5557
if (!currentLicense?._updatedAt) {
5658
throw new CloudWorkspaceLicenseError('Failed to retrieve current license');
5759
}

apps/meteor/app/cloud/server/functions/syncWorkspace/announcementSync.ts

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { type Cloud, type Serialized } from '@rocket.chat/core-typings';
22
import { serverFetch as fetch } from '@rocket.chat/server-fetch';
3-
import { v, compile } from 'suretype';
3+
import { z } from 'zod';
44

55
import { CloudWorkspaceConnectionError } from '../../../../../lib/errors/CloudWorkspaceConnectionError';
66
import { CloudWorkspaceRegistrationError } from '../../../../../lib/errors/CloudWorkspaceRegistrationError';
@@ -11,38 +11,38 @@ import { CloudWorkspaceAccessTokenEmptyError, getWorkspaceAccessToken } from '..
1111
import { retrieveRegistrationStatus } from '../retrieveRegistrationStatus';
1212
import { handleAnnouncementsOnWorkspaceSync, handleNpsOnWorkspaceSync } from './handleCommsSync';
1313

14-
const workspaceCommPayloadSchema = v.object({
15-
workspaceId: v.string().required(),
16-
publicKey: v.string(),
17-
nps: v.object({
18-
id: v.string().required(),
19-
startAt: v.string().format('date-time').required(),
20-
expireAt: v.string().format('date-time').required(),
21-
}),
22-
announcements: v.object({
23-
create: v.array(
24-
v.object({
25-
_id: v.string().required(),
26-
_updatedAt: v.string().format('date-time').required(),
27-
selector: v.object({
28-
roles: v.array(v.string()),
14+
const workspaceCommPayloadSchema = z.object({
15+
workspaceId: z.string().optional(),
16+
publicKey: z.string().optional(),
17+
nps: z
18+
.object({
19+
id: z.string(),
20+
startAt: z.string().datetime(),
21+
expireAt: z.string().datetime(),
22+
})
23+
.optional(),
24+
announcements: z.object({
25+
create: z.array(
26+
z.object({
27+
_id: z.string(),
28+
_updatedAt: z.string().datetime().optional(),
29+
selector: z.object({
30+
roles: z.array(z.string()),
2931
}),
30-
platform: v.array(v.string().enum('web', 'mobile')).required(),
31-
expireAt: v.string().format('date-time').required(),
32-
startAt: v.string().format('date-time').required(),
33-
createdBy: v.string().enum('cloud', 'system').required(),
34-
createdAt: v.string().format('date-time').required(),
35-
dictionary: v.object({}).additional(v.object({}).additional(v.string())),
36-
view: v.any(),
37-
surface: v.string().enum('banner', 'modal').required(),
32+
platform: z.array(z.enum(['web', 'mobile'])),
33+
expireAt: z.string().datetime(),
34+
startAt: z.string().datetime(),
35+
createdBy: z.enum(['cloud', 'system']),
36+
createdAt: z.string().datetime(),
37+
dictionary: z.record(z.record(z.string())).optional(),
38+
view: z.unknown(),
39+
surface: z.enum(['banner', 'modal']),
3840
}),
3941
),
40-
delete: v.array(v.string()),
42+
delete: z.array(z.string()).optional(),
4143
}),
4244
});
4345

44-
const assertWorkspaceCommPayload = compile(workspaceCommPayloadSchema);
45-
4646
const fetchCloudAnnouncementsSync = async ({
4747
token,
4848
data,
@@ -70,7 +70,12 @@ const fetchCloudAnnouncementsSync = async ({
7070

7171
const payload = await response.json();
7272

73-
assertWorkspaceCommPayload(payload);
73+
const assertWorkspaceCommPayload = workspaceCommPayloadSchema.safeParse(payload);
74+
75+
if (!assertWorkspaceCommPayload.success) {
76+
SystemLogger.error({ msg: 'workspaceCommPayloadSchema failed type validation', errors: assertWorkspaceCommPayload.error.errors });
77+
}
78+
7479
return payload;
7580
};
7681

apps/meteor/app/cloud/server/functions/syncWorkspace/fetchWorkspaceSyncPayload.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
11
import type { Cloud, Serialized } from '@rocket.chat/core-typings';
22
import { serverFetch as fetch } from '@rocket.chat/server-fetch';
3-
import { v, compile } from 'suretype';
3+
import { z } from 'zod';
44

55
import { CloudWorkspaceConnectionError } from '../../../../../lib/errors/CloudWorkspaceConnectionError';
6+
import { SystemLogger } from '../../../../../server/lib/logger/system';
67
import { settings } from '../../../../settings/server';
78

8-
const workspaceSyncPayloadSchema = v.object({
9-
workspaceId: v.string().required(),
10-
publicKey: v.string(),
11-
license: v.string().required(),
9+
const workspaceSyncPayloadSchema = z.object({
10+
workspaceId: z.string(),
11+
publicKey: z.string().optional(),
12+
license: z.string(),
1213
});
1314

14-
const assertWorkspaceSyncPayload = compile(workspaceSyncPayloadSchema);
15-
1615
export async function fetchWorkspaceSyncPayload({
1716
token,
1817
data,
@@ -36,7 +35,11 @@ export async function fetchWorkspaceSyncPayload({
3635

3736
const payload = await response.json();
3837

39-
assertWorkspaceSyncPayload(payload);
38+
const assertWorkspaceSyncPayload = workspaceSyncPayloadSchema.safeParse(payload);
39+
40+
if (!assertWorkspaceSyncPayload.success) {
41+
SystemLogger.error({ msg: 'workspaceCommPayloadSchema failed type validation', errors: assertWorkspaceSyncPayload.error.errors });
42+
}
4043

4144
return payload;
4245
}

apps/meteor/app/cloud/server/functions/syncWorkspace/legacySyncWorkspace.ts

Lines changed: 60 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { type Cloud, type Serialized } from '@rocket.chat/core-typings';
22
import { Settings } from '@rocket.chat/models';
33
import { serverFetch as fetch } from '@rocket.chat/server-fetch';
4-
import { v, compile } from 'suretype';
4+
import { z } from 'zod';
55

66
import { CloudWorkspaceConnectionError } from '../../../../../lib/errors/CloudWorkspaceConnectionError';
77
import { CloudWorkspaceRegistrationError } from '../../../../../lib/errors/CloudWorkspaceRegistrationError';
@@ -14,76 +14,72 @@ import { getWorkspaceLicense } from '../getWorkspaceLicense';
1414
import { retrieveRegistrationStatus } from '../retrieveRegistrationStatus';
1515
import { handleBannerOnWorkspaceSync, handleNpsOnWorkspaceSync } from './handleCommsSync';
1616

17-
const workspaceClientPayloadSchema = v.object({
18-
workspaceId: v.string().required(),
19-
publicKey: v.string(),
20-
trial: v.object({
21-
trialing: v.boolean().required(),
22-
trialID: v.string().required(),
23-
endDate: v.string().format('date-time').required(),
24-
marketing: v
25-
.object({
26-
utmContent: v.string().required(),
27-
utmMedium: v.string().required(),
28-
utmSource: v.string().required(),
29-
utmCampaign: v.string().required(),
30-
})
31-
.required(),
32-
DowngradesToPlan: v
33-
.object({
34-
id: v.string().required(),
35-
})
36-
.required(),
37-
trialRequested: v.boolean().required(),
38-
}),
39-
nps: v.object({
40-
id: v.string().required(),
41-
startAt: v.string().format('date-time').required(),
42-
expireAt: v.string().format('date-time').required(),
17+
const workspaceClientPayloadSchema = z.object({
18+
workspaceId: z.string(),
19+
publicKey: z.string().optional(),
20+
trial: z
21+
.object({
22+
trialing: z.boolean(),
23+
trialID: z.string(),
24+
endDate: z.string().datetime(),
25+
marketing: z.object({
26+
utmContent: z.string(),
27+
utmMedium: z.string(),
28+
utmSource: z.string(),
29+
utmCampaign: z.string(),
30+
}),
31+
DowngradesToPlan: z.object({
32+
id: z.string(),
33+
}),
34+
trialRequested: z.boolean(),
35+
})
36+
.optional(),
37+
nps: z.object({
38+
id: z.string(),
39+
startAt: z.string().datetime(),
40+
expireAt: z.string().datetime(),
4341
}),
44-
banners: v.array(
45-
v.object({
46-
_id: v.string().required(),
47-
_updatedAt: v.string().format('date-time').required(),
48-
platform: v.array(v.string()).required(),
49-
expireAt: v.string().format('date-time').required(),
50-
startAt: v.string().format('date-time').required(),
51-
roles: v.array(v.string()),
52-
createdBy: v.object({
53-
_id: v.string().required(),
54-
username: v.string(),
42+
banners: z.array(
43+
z.object({
44+
_id: z.string(),
45+
_updatedAt: z.string().datetime(),
46+
platform: z.array(z.string()),
47+
expireAt: z.string().datetime(),
48+
startAt: z.string().datetime(),
49+
roles: z.array(z.string()).optional(),
50+
createdBy: z.object({
51+
_id: z.string(),
52+
username: z.string().optional(),
5553
}),
56-
createdAt: v.string().format('date-time').required(),
57-
view: v.any(),
58-
active: v.boolean(),
59-
inactivedAt: v.string().format('date-time'),
60-
snapshot: v.string(),
54+
createdAt: z.string().datetime(),
55+
view: z.any(),
56+
active: z.boolean().optional(),
57+
inactivedAt: z.string().datetime().optional(),
58+
snapshot: z.string().optional(),
6159
}),
6260
),
63-
announcements: v.object({
64-
create: v.array(
65-
v.object({
66-
_id: v.string().required(),
67-
_updatedAt: v.string().format('date-time').required(),
68-
selector: v.object({
69-
roles: v.array(v.string()),
61+
announcements: z.object({
62+
create: z.array(
63+
z.object({
64+
_id: z.string(),
65+
_updatedAt: z.string().datetime(),
66+
selector: z.object({
67+
roles: z.array(z.string()),
7068
}),
71-
platform: v.array(v.string().enum('web', 'mobile')).required(),
72-
expireAt: v.string().format('date-time').required(),
73-
startAt: v.string().format('date-time').required(),
74-
createdBy: v.string().enum('cloud', 'system').required(),
75-
createdAt: v.string().format('date-time').required(),
76-
dictionary: v.object({}).additional(v.object({}).additional(v.string())),
77-
view: v.any(),
78-
surface: v.string().enum('banner', 'modal').required(),
69+
platform: z.array(z.enum(['web', 'mobile'])),
70+
expireAt: z.string().datetime(),
71+
startAt: z.string().datetime(),
72+
createdBy: z.enum(['cloud', 'system']),
73+
createdAt: z.string().datetime(),
74+
dictionary: z.record(z.record(z.string())),
75+
view: z.any(),
76+
surface: z.enum(['banner', 'modal']),
7977
}),
8078
),
81-
delete: v.array(v.string()),
79+
delete: z.array(z.string()),
8280
}),
8381
});
8482

85-
const assertWorkspaceClientPayload = compile(workspaceClientPayloadSchema);
86-
8783
/** @deprecated */
8884
const fetchWorkspaceClientPayload = async ({
8985
token,
@@ -117,7 +113,9 @@ const fetchWorkspaceClientPayload = async ({
117113
return undefined;
118114
}
119115

120-
if (!assertWorkspaceClientPayload(payload)) {
116+
const assertWorkspaceClientPayload = workspaceClientPayloadSchema.safeParse(payload);
117+
118+
if (!assertWorkspaceClientPayload.success) {
121119
throw new CloudWorkspaceConnectionError('Invalid response from Rocket.Chat Cloud');
122120
}
123121

0 commit comments

Comments
 (0)