Files
upstream-rocketchat/apps/meteor/server/api/lib/getUserInfo.ts
upstream-mirror 30810eecd7
Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 2s
snapshot of https://github.com/RocketChat/Rocket.Chat.git (develop, 2026-09-16; blobs > 131072B omitted)
2026-09-16 01:21:02 +05:00

130 lines
4.8 KiB
TypeScript

import { isOAuthUser, type IMeApiUser, type IUser, type IUserEmail, type IUserCalendar } from '@rocket.chat/core-typings';
import semver from 'semver';
import { Info } from '../../../app/utils/rocketchat.info';
import { resolveUsersByIds } from '../../lib/statusVisibility/resolveUsers';
import { getURL } from '../../lib/utils/getURL';
import { getUserPreference } from '../../lib/utils/lib/getUserPreference';
import { settings } from '../../settings';
const isVerifiedEmail = (me: IUser): false | IUserEmail | undefined => {
if (!me || !Array.isArray(me.emails)) {
return false;
}
return me.emails.find((email) => email.verified);
};
const getPreferencesWithDefaults = async (me: IUser): Promise<Record<string, unknown>> => {
const defaultUserSettingPrefix = 'Accounts_Default_User_Preferences_';
const allDefaultUserSettings = settings.getByRegexp(new RegExp(`^${defaultUserSettingPrefix}.*$`));
const accumulator: Record<string, any> = {};
for (const [key] of allDefaultUserSettings) {
const settingWithoutPrefix = key.replace(defaultUserSettingPrefix, ' ').trim();
accumulator[settingWithoutPrefix] = await getUserPreference(me, settingWithoutPrefix);
}
return accumulator;
};
const filterOutdatedVersionUpdateBanners = (banners: NonNullable<IUser['banners']>): IUser['banners'] => {
return Object.fromEntries(
Object.entries(banners).filter(([id]) => {
if (!id.startsWith('versionUpdate-')) {
return true;
}
const version = id.replace('versionUpdate-', '').replace(/_/g, '.');
if (!semver.valid(version) || semver.lte(version, Info.version)) {
return false;
}
return true;
}),
);
};
/**
* Returns the user's calendar settings based on their email domain and the configured mapping.
* If the email is not provided or the domain is not found in the mapping,
* it returns the default Outlook calendar settings.
* @param email - The user's email object, which may contain the address and verification status.
* @returns The calendar settings for the user, including Outlook calendar settings if enabled.
*/
const getUserCalendar = (email: false | IUserEmail | undefined): IUserCalendar => {
const calendarSettings: IUserCalendar = {};
const outlook = {
Enabled: settings.get<boolean>('Outlook_Calendar_Enabled'),
Exchange_Url: settings.get<string>('Outlook_Calendar_Exchange_Url'),
Outlook_Url: settings.get<string>('Outlook_Calendar_Outlook_Url'),
};
const domain = email ? email.address.split('@').pop() : undefined;
const outlookCalendarUrlMapping = settings.get<string>('Outlook_Calendar_Url_Mapping');
if (domain && outlookCalendarUrlMapping && outlookCalendarUrlMapping.includes(domain)) {
try {
const mappingObject = JSON.parse(outlookCalendarUrlMapping);
const mappedSettings = mappingObject[domain];
if (mappedSettings) {
outlook.Enabled = mappedSettings.Enabled ?? outlook.Enabled;
outlook.Exchange_Url = mappedSettings.Exchange_Url ?? outlook.Exchange_Url;
outlook.Outlook_Url = mappedSettings.Outlook_Url ?? outlook.Outlook_Url;
}
} catch (error) {
console.error('Invalid Outlook Calendar URL Mapping JSON:', error);
}
}
if (outlook.Enabled) {
calendarSettings.outlook = outlook;
}
return calendarSettings;
};
export async function getUserInfo(me: IUser, pullPreferences = true): Promise<IMeApiUser> {
const verifiedEmail = isVerifiedEmail(me);
const { statusVisibilityDenied, ...savedPreferences } = me.settings?.preferences ?? {};
const preferences = pullPreferences
? {
...(await getPreferencesWithDefaults(me)),
...savedPreferences,
...(settings.get<boolean>('Accounts_StatusVisibility_Enabled') &&
statusVisibilityDenied?.length && {
statusVisibilityDenied: (await resolveUsersByIds(statusVisibilityDenied)).usernames,
}),
}
: undefined;
return {
...me,
...(me.banners && { banners: filterOutdatedVersionUpdateBanners(me.banners) }),
email: verifiedEmail ? verifiedEmail.address : undefined,
settings: {
profile: {},
...(preferences && { preferences }),
calendar: getUserCalendar(verifiedEmail),
},
avatarUrl: getURL(`/avatar/${me.username}`, { cdn: false, full: true }),
isOAuthUser: isOAuthUser(me),
...(me.services && {
services: {
...(me.services.github && { github: me.services.github as Record<string, unknown> }),
...(me.services.gitlab && { gitlab: me.services.gitlab as Record<string, unknown> }),
...(me.services.email2fa?.enabled && { email2fa: { enabled: me.services.email2fa.enabled } }),
...(me.services.totp?.enabled && { totp: { enabled: me.services.totp.enabled } }),
password: {
// The password hash shouldn't be leaked but the client may need to know if it exists.
exists: Boolean(me.services?.password?.bcrypt),
},
},
}),
// Cast needed: spread of full IUser produces a superset; runtime response schema validates the actual shape
} as IMeApiUser;
}