1 import type { PrivateKeyReference } from '@proton/crypto';
2 import { CryptoProxy } from '@proton/crypto';
3 import { getDecryptedAddressKeys } from '@proton/shared/lib/keys/getDecryptedAddressKeys';
4 import { getDecryptedUserKeys } from '@proton/shared/lib/keys/getDecryptedUserKeys';
5 import { getPrimaryKey } from '@proton/shared/lib/keys/getPrimaryKey';
6 import { getDefaultKeyFlags } from '@proton/shared/lib/keys/keyFlags';
7 import isTruthy from '@proton/utils/isTruthy';
9 import { createMemberKeyRoute, setupMemberKeyRoute } from '../api/memberKeys';
10 import { MEMBER_PRIVATE } from '../constants';
13 CachedOrganizationKey,
17 KeyTransparencyVerify,
22 } from '../interfaces';
23 import { srpVerify } from '../srp';
24 import { generateAddressKey, generateAddressKeyTokens } from './addressKeys';
25 import { getActiveKeyObject, getActiveKeys, getNormalizedActiveKeys, getPrimaryFlag } from './getActiveKeys';
26 import { generateKeySaltAndPassphrase } from './keys';
27 import { decryptMemberToken, encryptMemberToken, generateMemberToken } from './memberToken';
28 import { generateMemberAddressKey } from './organizationKeys';
29 import { getSignedKeyListWithDeferredPublish } from './signedKeyList';
30 import { generateUserKey } from './userKeys';
32 export const getDecryptedMemberKey = async (
33 { Token, PrivateKey }: tsKey,
34 organizationKey: PrivateKeyReference
35 ): Promise<PrivateKeyReference> => {
37 throw new Error('Member token invalid');
39 const decryptedToken = await decryptMemberToken(Token, [organizationKey], [organizationKey]);
40 return CryptoProxy.importPrivateKey({ armoredKey: PrivateKey, passphrase: decryptedToken });
43 interface SetupMemberKeySharedArguments {
46 memberAddresses: tsAddress[];
48 organizationKey: PrivateKeyReference;
49 keyGenConfig: KeyGenConfig;
50 keyTransparencyVerify: KeyTransparencyVerify;
53 export const setupMemberKeyV2 = async ({
60 keyTransparencyVerify,
61 }: SetupMemberKeySharedArguments) => {
62 const { salt: keySalt, passphrase: memberKeyPassword } = await generateKeySaltAndPassphrase(password);
64 const { privateKey: userPrivateKey, privateKeyArmored: userPrivateKeyArmored } = await generateUserKey({
65 passphrase: memberKeyPassword,
68 const memberKeyToken = generateMemberToken();
69 const privateKeyArmoredOrganization = await CryptoProxy.exportPrivateKey({
70 privateKey: userPrivateKey,
71 passphrase: memberKeyToken,
73 const organizationToken = await encryptMemberToken(memberKeyToken, organizationKey);
75 const AddressKeysWithOnSKLPublish = await Promise.all(
76 memberAddresses.map(async (address) => {
77 const { token, signature, organizationSignature, encryptedToken } = await generateAddressKeyTokens(
82 const { privateKey: addressPrivateKey, privateKeyArmored: addressPrivateKeyArmored } =
83 await generateAddressKey({
89 const newActiveKey = await getActiveKeyObject(addressPrivateKey, {
92 flags: getDefaultKeyFlags(address),
94 const updatedActiveKeys = getNormalizedActiveKeys(address, [newActiveKey]);
95 const [SignedKeyList, onSKLPublishSuccess] = await getSignedKeyListWithDeferredPublish(
103 AddressID: address.ID,
105 PrivateKey: addressPrivateKeyArmored,
106 Token: encryptedToken,
107 Signature: signature,
108 OrgSignature: organizationSignature,
114 const AddressKeys = AddressKeysWithOnSKLPublish.map(({ addressKey }) => addressKey);
116 const { Member } = await srpVerify<{ Member: tsMember }>({
118 credentials: { password },
119 config: setupMemberKeyRoute({
123 PrivateKey: userPrivateKeyArmored,
124 OrgPrivateKey: privateKeyArmoredOrganization,
125 OrgToken: organizationToken,
132 AddressKeysWithOnSKLPublish.map(({ onSKLPublishSuccess }) =>
133 onSKLPublishSuccess ? onSKLPublishSuccess() : Promise.resolve()
137 return { Member, userPrivateKey };
140 export const getCanGenerateMemberKeys = (member: tsMember | undefined) => {
141 return member?.Private === MEMBER_PRIVATE.READABLE && !member.SSO;
144 export const getShouldSetupMemberKeys = (member: tsMember | undefined) => {
145 return !member?.Self && member?.Keys.length === 0 && getCanGenerateMemberKeys(member);
148 export const getCanGenerateMemberKeysPermissions = (
150 organizationKey: CachedOrganizationKey | undefined
152 return !!organizationKey?.privateKey && user.isAdmin && !user.isSubUser;
155 export const getCanGenerateMemberAddressKeys = ({
162 member: tsMember | undefined;
163 organizationKey: CachedOrganizationKey | undefined;
167 * Keys can be generated if the organisation key is decrypted, and you are an admin,
168 * and the member is readable, you're not an admin signed in to a readable member.
171 getCanGenerateMemberKeysPermissions(user, organizationKey) &&
172 getCanGenerateMemberKeys(member) &&
177 interface SetupMemberKeyArguments extends SetupMemberKeySharedArguments {
178 ownerAddresses: tsAddress[];
181 export const setupMemberKeys = async ({ ownerAddresses, ...rest }: SetupMemberKeyArguments) => {
182 return setupMemberKeyV2(rest);
185 interface CreateMemberAddressKeysLegacyArguments {
188 memberAddress: tsAddress;
189 memberAddressKeys: DecryptedKey[];
190 memberUserKey: PrivateKeyReference;
191 organizationKey: PrivateKeyReference;
192 keyGenConfig: KeyGenConfig;
193 keyTransparencyVerify: KeyTransparencyVerify;
196 export const createMemberAddressKeysLegacy = async ({
204 keyTransparencyVerify,
205 }: CreateMemberAddressKeysLegacyArguments) => {
206 const { privateKey, activationToken, privateKeyArmored, privateKeyArmoredOrganization, organizationToken } =
207 await generateMemberAddressKey({
208 email: memberAddress.Email,
209 primaryKey: memberUserKey,
214 const activeKeys = await getActiveKeys(
216 memberAddress.SignedKeyList,
220 const newActiveKey = await getActiveKeyObject(privateKey, {
222 primary: getPrimaryFlag(activeKeys),
223 flags: getDefaultKeyFlags(memberAddress),
225 const updatedActiveKeys = getNormalizedActiveKeys(memberAddress, [...activeKeys, newActiveKey]);
226 const [SignedKeyList, onSKLPublishSuccess] = await getSignedKeyListWithDeferredPublish(
229 keyTransparencyVerify
232 const { primary } = newActiveKey;
234 const { MemberKey } = await api(
235 createMemberKeyRoute({
237 AddressID: memberAddress.ID,
238 Activation: activationToken,
239 UserKey: privateKeyArmored,
240 Token: organizationToken,
241 MemberKey: privateKeyArmoredOrganization,
247 await onSKLPublishSuccess();
249 newActiveKey.ID = MemberKey.ID;
251 return updatedActiveKeys;
254 interface CreateMemberAddressKeysV2Arguments {
257 memberAddress: tsAddress;
258 memberAddressKeys: DecryptedKey[];
259 memberUserKey: PrivateKeyReference;
260 organizationKey: PrivateKeyReference;
261 keyGenConfig: KeyGenConfig;
262 keyTransparencyVerify: KeyTransparencyVerify;
265 export const createMemberAddressKeysV2 = async ({
273 keyTransparencyVerify,
274 }: CreateMemberAddressKeysV2Arguments) => {
275 const { token, signature, organizationSignature, encryptedToken } = await generateAddressKeyTokens(
280 const { privateKey: addressPrivateKey, privateKeyArmored: addressPrivateKeyArmored } = await generateAddressKey({
281 email: memberAddress.Email,
286 const activeKeys = await getActiveKeys(
288 memberAddress.SignedKeyList,
292 const newActiveKey = await getActiveKeyObject(addressPrivateKey, {
294 primary: getPrimaryFlag(activeKeys),
295 flags: getDefaultKeyFlags(memberAddress),
297 const updatedActiveKeys = getNormalizedActiveKeys(memberAddress, [...activeKeys, newActiveKey]);
298 const [SignedKeyList, onSKLPublishSuccess] = await getSignedKeyListWithDeferredPublish(
301 keyTransparencyVerify
304 const { primary } = newActiveKey;
306 const { MemberKey } = await api(
307 createMemberKeyRoute({
309 AddressID: memberAddress.ID,
310 PrivateKey: addressPrivateKeyArmored,
311 Token: encryptedToken,
312 Signature: signature,
313 OrgSignature: organizationSignature,
319 await onSKLPublishSuccess();
321 newActiveKey.ID = MemberKey.ID;
323 return updatedActiveKeys;
326 export const getMemberKeys = async ({
331 member: Pick<tsMember, 'Keys'>;
332 memberAddresses: tsAddress[];
333 organizationKey: KeyPair;
335 const memberUserKeys = await getDecryptedUserKeys(member.Keys, '', organizationKey);
336 const memberUserKeyPrimary = getPrimaryKey(memberUserKeys)?.privateKey;
337 if (!memberUserKeyPrimary) {
338 throw new Error('Not able to decrypt the primary member user key');
341 const memberAddressesKeys = (
343 memberAddresses.map(async (address) => {
346 keys: await getDecryptedAddressKeys(address.Keys, memberUserKeys, '', organizationKey),
348 // Some non-private members don't have keys generated
349 if (!result.keys.length) {
358 memberUserKeyPrimary,