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';
28 getNormalizedActiveAddressKeys,
30 } from './getActiveKeys';
31 import { generateKeySaltAndPassphrase } from './keys';
32 import { decryptMemberToken, encryptMemberToken, generateMemberToken } from './memberToken';
33 import { generateMemberAddressKey } from './organizationKeys';
34 import { getSignedKeyListWithDeferredPublish } from './signedKeyList';
35 import { generateUserKey } from './userKeys';
37 export const getDecryptedMemberKey = async (
38 { Token, PrivateKey }: tsKey,
39 organizationKey: PrivateKeyReference
40 ): Promise<PrivateKeyReference> => {
42 throw new Error('Member token invalid');
44 const decryptedToken = await decryptMemberToken(Token, [organizationKey], [organizationKey]);
45 return CryptoProxy.importPrivateKey({ armoredKey: PrivateKey, passphrase: decryptedToken });
48 interface SetupMemberKeySharedArguments {
51 memberAddresses: tsAddress[];
53 organizationKey: PrivateKeyReference;
54 keyGenConfig: KeyGenConfig; // pqc: TODO no v6 support
55 keyTransparencyVerify: KeyTransparencyVerify;
58 export const setupMemberKeyV2 = async ({
65 keyTransparencyVerify,
66 }: SetupMemberKeySharedArguments) => {
67 const { salt: keySalt, passphrase: memberKeyPassword } = await generateKeySaltAndPassphrase(password);
69 const { privateKey: userPrivateKey, privateKeyArmored: userPrivateKeyArmored } = await generateUserKey({
70 passphrase: memberKeyPassword,
73 const memberKeyToken = generateMemberToken();
74 const privateKeyArmoredOrganization = await CryptoProxy.exportPrivateKey({
75 privateKey: userPrivateKey,
76 passphrase: memberKeyToken,
78 const organizationToken = await encryptMemberToken(memberKeyToken, organizationKey);
80 const AddressKeysWithOnSKLPublish = await Promise.all(
81 memberAddresses.map(async (address) => {
82 const { token, signature, organizationSignature, encryptedToken } = await generateAddressKeyTokens(
87 const { privateKey: addressPrivateKey, privateKeyArmored: addressPrivateKeyArmored } =
88 await generateAddressKey({
94 const newActiveKey = await getActiveKeyObject(addressPrivateKey, {
97 flags: getDefaultKeyFlags(address),
99 const updatedActiveKeys = getNormalizedActiveAddressKeys(address, { v4: [newActiveKey], v6: [] });
100 const [SignedKeyList, onSKLPublishSuccess] = await getSignedKeyListWithDeferredPublish(
103 keyTransparencyVerify
108 AddressID: address.ID,
110 PrivateKey: addressPrivateKeyArmored,
111 Token: encryptedToken,
112 Signature: signature,
113 OrgSignature: organizationSignature,
119 const AddressKeys = AddressKeysWithOnSKLPublish.map(({ addressKey }) => addressKey);
121 const { Member } = await srpVerify<{ Member: tsMember }>({
123 credentials: { password },
124 config: setupMemberKeyRoute({
128 PrivateKey: userPrivateKeyArmored,
129 OrgPrivateKey: privateKeyArmoredOrganization,
130 OrgToken: organizationToken,
137 AddressKeysWithOnSKLPublish.map(({ onSKLPublishSuccess }) =>
138 onSKLPublishSuccess ? onSKLPublishSuccess() : Promise.resolve()
142 return { Member, userPrivateKey };
145 export const getCanGenerateMemberKeys = (member: tsMember | undefined) => {
146 return member?.Private === MEMBER_PRIVATE.READABLE && !member.SSO;
149 export const getShouldSetupMemberKeys = (member: tsMember | undefined) => {
150 return !member?.Self && member?.Keys.length === 0 && getCanGenerateMemberKeys(member);
153 export const getCanGenerateMemberKeysPermissions = (
155 organizationKey: CachedOrganizationKey | undefined
157 return !!organizationKey?.privateKey && user.isAdmin && !user.isSubUser;
160 export const getCanGenerateMemberAddressKeys = ({
167 member: tsMember | undefined;
168 organizationKey: CachedOrganizationKey | undefined;
172 * Keys can be generated if the organisation key is decrypted, and you are an admin,
173 * and the member is readable, you're not an admin signed in to a readable member.
176 getCanGenerateMemberKeysPermissions(user, organizationKey) &&
177 getCanGenerateMemberKeys(member) &&
182 interface SetupMemberKeyArguments extends SetupMemberKeySharedArguments {
183 ownerAddresses: tsAddress[];
186 export const setupMemberKeys = async ({ ownerAddresses, ...rest }: SetupMemberKeyArguments) => {
187 return setupMemberKeyV2(rest);
190 interface CreateMemberAddressKeysLegacyArguments {
193 memberAddress: tsAddress;
194 memberAddressKeys: DecryptedKey[];
195 memberUserKey: PrivateKeyReference;
196 organizationKey: PrivateKeyReference;
197 keyGenConfig: KeyGenConfig;
198 keyTransparencyVerify: KeyTransparencyVerify;
201 export const createMemberAddressKeysLegacy = async ({
209 keyTransparencyVerify,
210 }: CreateMemberAddressKeysLegacyArguments) => {
211 const { privateKey, activationToken, privateKeyArmored, privateKeyArmoredOrganization, organizationToken } =
212 await generateMemberAddressKey({
213 email: memberAddress.Email,
214 primaryKey: memberUserKey,
219 const activeKeys = await getActiveAddressKeys(
221 memberAddress.SignedKeyList,
225 const newActiveKey = await getActiveKeyObject(privateKey, {
227 primary: getPrimaryFlag(activeKeys.v4),
228 flags: getDefaultKeyFlags(memberAddress),
230 const updatedActiveKeys = getNormalizedActiveAddressKeys(memberAddress, {
231 v4: [...activeKeys.v4, newActiveKey],
234 const [SignedKeyList, onSKLPublishSuccess] = await getSignedKeyListWithDeferredPublish(
237 keyTransparencyVerify
240 const { primary } = newActiveKey;
242 const { MemberKey } = await api(
243 createMemberKeyRoute({
245 AddressID: memberAddress.ID,
246 Activation: activationToken,
247 UserKey: privateKeyArmored,
248 Token: organizationToken,
249 MemberKey: privateKeyArmoredOrganization,
255 await onSKLPublishSuccess();
257 newActiveKey.ID = MemberKey.ID;
259 return updatedActiveKeys;
262 interface CreateMemberAddressKeysV2Arguments {
265 memberAddress: tsAddress;
266 memberAddressKeys: DecryptedKey[];
267 memberUserKey: PrivateKeyReference;
268 organizationKey: PrivateKeyReference;
269 keyGenConfig: KeyGenConfig;
270 keyTransparencyVerify: KeyTransparencyVerify;
273 export const createMemberAddressKeysV2 = async ({
281 keyTransparencyVerify,
282 }: CreateMemberAddressKeysV2Arguments) => {
283 const { token, signature, organizationSignature, encryptedToken } = await generateAddressKeyTokens(
288 const { privateKey: addressPrivateKey, privateKeyArmored: addressPrivateKeyArmored } = await generateAddressKey({
289 email: memberAddress.Email,
294 const activeKeys = await getActiveAddressKeys(
296 memberAddress.SignedKeyList,
300 const newActiveKey = await getActiveKeyObject(addressPrivateKey, {
302 primary: getPrimaryFlag(activeKeys.v4),
303 flags: getDefaultKeyFlags(memberAddress),
305 const updatedActiveKeys = getNormalizedActiveAddressKeys(memberAddress, {
306 v4: [...activeKeys.v4, newActiveKey],
309 const [SignedKeyList, onSKLPublishSuccess] = await getSignedKeyListWithDeferredPublish(
312 keyTransparencyVerify
315 const { primary } = newActiveKey;
317 const { MemberKey } = await api(
318 createMemberKeyRoute({
320 AddressID: memberAddress.ID,
321 PrivateKey: addressPrivateKeyArmored,
322 Token: encryptedToken,
323 Signature: signature,
324 OrgSignature: organizationSignature,
330 await onSKLPublishSuccess();
332 newActiveKey.ID = MemberKey.ID;
334 return updatedActiveKeys;
337 export const getMemberKeys = async ({
342 member: Pick<tsMember, 'Keys'>;
343 memberAddresses: tsAddress[];
344 organizationKey: KeyPair;
346 const memberUserKeys = await getDecryptedUserKeys(member.Keys, '', organizationKey);
347 const memberUserKeyPrimary = getPrimaryKey(memberUserKeys)?.privateKey;
348 if (!memberUserKeyPrimary) {
349 throw new Error('Not able to decrypt the primary member user key');
352 const memberAddressesKeys = (
354 memberAddresses.map(async (address) => {
357 keys: await getDecryptedAddressKeys(address.Keys, memberUserKeys, '', organizationKey),
359 // Some non-private members don't have keys generated
360 if (!result.keys.length) {
369 memberUserKeyPrimary,