1 import { c } from 'ttag';
3 import { PLANS } from '@proton/payments';
4 import { getIsPasswordless } from '@proton/shared/lib/keys';
6 import { MEMBER_ROLE, MEMBER_SUBSCRIBER } from '../constants';
7 import type { Address, CachedOrganizationKey, Domain, Member, Organization } from '../interfaces';
8 import { DOMAIN_STATE, MEMBER_ORG_KEY_STATE } from '../interfaces';
10 export const isSuperAdmin = (members: Member[]) =>
11 (members || []).some(({ Subscriber, Self }) => Self === 1 && Subscriber === MEMBER_SUBSCRIBER.PAYER);
13 export const getHasOtherAdmins = (members: Member[]) =>
14 members.some(({ Role, Self }) => Self !== 1 && Role === MEMBER_ROLE.ORGANIZATION_ADMIN);
16 export const getNonPrivateMembers = (members: Member[]) => members.filter(({ Private }) => Private === 0);
17 export const getMemberHasAccessToOrgKey = (member: Member) =>
18 member.AccessToOrgKey === MEMBER_ORG_KEY_STATE.Active || member.AccessToOrgKey === MEMBER_ORG_KEY_STATE.Pending;
20 export const getMemberHasMissingOrgKey = (member: Member) => member.AccessToOrgKey === MEMBER_ORG_KEY_STATE.Missing;
22 export const isOrganizationDuo = (organization?: Organization) => organization?.PlanName === PLANS.DUO;
23 export const isOrganizationFamily = (organization?: Organization) => organization?.PlanName === PLANS.FAMILY;
24 export const isOrganizationPassFamily = (organization?: Organization) => organization?.PlanName === PLANS.PASS_FAMILY;
25 export const isOrganizationVisionary = (organization?: Organization) => organization?.PlanName === PLANS.VISIONARY;
27 export const getOrganizationDenomination = (organization?: Organization) => {
29 isOrganizationDuo(organization) ||
30 isOrganizationFamily(organization) ||
31 isOrganizationPassFamily(organization)
35 return 'organization';
38 export const isOrganizationB2B = (organization?: Organization) => {
44 PLANS.BUNDLE_PRO_2024,
50 ].includes(organization?.PlanName as PLANS);
53 /** True if user is part of an organization (works also for org admins) */
54 export const isOrganization = (organization?: Organization) =>
55 isOrganizationFamily(organization) ||
56 isOrganizationPassFamily(organization) ||
57 isOrganizationDuo(organization) ||
58 isOrganizationB2B(organization) ||
59 isOrganizationVisionary(organization);
61 export enum OrganizationKeyState {
69 export enum OrganizationKeyMode {
74 export const getOrganizationKeyInfo = (
75 organization: Organization | undefined,
76 organizationKey: CachedOrganizationKey | undefined,
77 addresses: Address[] | undefined
79 const organizationHasKeys = !!organization?.HasKeys && !organizationKey?.placeholder;
80 // If the user has the organization key (not the organization itself).
81 const userHasActivatedOrganizationKeys = !!organizationKey?.Key?.PrivateKey;
82 // If the user has the organization key, but it's not decrypted. Typically following a password reset
83 const userHasInactiveKey = userHasActivatedOrganizationKeys && !organizationKey?.privateKey;
84 const userHasActiveKey = organizationHasKeys && !!organizationKey?.privateKey;
85 const userHasNoKey = organizationKey?.Key.AccessToOrgKey === MEMBER_ORG_KEY_STATE.NoKey;
86 const userHasMissingKey = organizationKey?.Key.AccessToOrgKey === MEMBER_ORG_KEY_STATE.Missing;
88 if (getIsPasswordless(organizationKey?.Key)) {
89 let hasActivation = organizationHasKeys && !!organizationKey?.Key.SignatureAddress;
90 let hasActivationAddress = organizationKey?.Key.EncryptionAddressID
91 ? addresses?.find((address) => address.ID === organizationKey.Key.EncryptionAddressID)
95 mode: OrganizationKeyMode.Passwordless,
98 return OrganizationKeyState.NoKey;
100 if (!organizationHasKeys) {
101 return OrganizationKeyState.Setup;
103 if (hasActivationAddress && hasActivation) {
104 return OrganizationKeyState.Activate;
106 if (userHasInactiveKey || userHasMissingKey) {
107 return OrganizationKeyState.Inactive;
109 if (userHasActiveKey) {
110 return OrganizationKeyState.Active;
112 return OrganizationKeyState.Setup;
118 mode: OrganizationKeyMode.Legacy,
121 return OrganizationKeyState.NoKey;
123 if (!organizationHasKeys) {
124 return OrganizationKeyState.Setup;
126 // If the user does not have the organization key but the organization has keys setup, it's inactive
127 if (!userHasActivatedOrganizationKeys) {
128 return OrganizationKeyState.Activate;
130 if (userHasInactiveKey) {
131 return OrganizationKeyState.Inactive;
133 if (userHasActiveKey) {
134 return OrganizationKeyState.Active;
136 return OrganizationKeyState.Setup;
141 export type OrganizationKeyInfo = ReturnType<typeof getOrganizationKeyInfo>;
143 export const validateOrganizationKey = (info: OrganizationKeyInfo) => {
144 if (info.state === OrganizationKeyState.NoKey) {
145 return c('passwordless').t`You need access to the organization key to perform this operation.`;
147 if (info.state === OrganizationKeyState.Activate) {
148 return c('passwordless').t`The organization key must be activated first.`;
150 if (info.state === OrganizationKeyState.Inactive) {
151 return c('passwordless').t`Permission denied, administrator privileges have been restricted.`;
153 if (info.state === OrganizationKeyState.Setup) {
154 return c('passwordless').t`Organization key does not exist.`;
158 // Active domains is one that's verified or in warning state, but it can be used to create addresses to
159 export const getIsDomainActive = (domain: Domain) => {
161 (domain.State === DOMAIN_STATE.DOMAIN_STATE_VERIFIED || domain.State === DOMAIN_STATE.DOMAIN_STATE_WARN) &&
162 domain.Flags['mail-intent']