Update selected item color in Pass menu
[ProtonMail-WebClient.git] / packages / pass / store / sagas / items / item-creation.saga.ts
blobe98a542d00cbeb8b08489caf33ad95ddfe49d25a
1 import type { Action } from 'redux';
2 import { all, put, takeEvery } from 'redux-saga/effects';
4 import { parseItemRevision } from '@proton/pass/lib/items/item.parser';
5 import { createAlias, createItem, createItemWithAlias } from '@proton/pass/lib/items/item.requests';
6 import { createTelemetryEvent } from '@proton/pass/lib/telemetry/event';
7 import { itemCreationFailure, itemCreationIntent, itemCreationSuccess } from '@proton/pass/store/actions';
8 import { aliasOptionsRequest } from '@proton/pass/store/actions/requests';
9 import { requestInvalidate } from '@proton/pass/store/request/actions';
10 import type { RootSagaOptions } from '@proton/pass/store/types';
11 import type { ItemRevision, ItemRevisionContentsResponse } from '@proton/pass/types';
12 import { TelemetryEventName, TelemetryItemType } from '@proton/pass/types/data/telemetry';
13 import { deobfuscate } from '@proton/pass/utils/obfuscate/xor';
15 type ItemCreationAction = ReturnType<typeof itemCreationIntent>;
16 type ItemWithAliasCreationAction = ItemCreationAction & { payload: { type: 'login'; extraData: { withAlias: true } } };
18 const singleItemCreation = (action: Action): action is ItemCreationAction =>
19     itemCreationIntent.match(action) && (action.payload.type === 'login' ? !action.payload.extraData.withAlias : true);
21 const withAliasItemCreation = (action: Action): action is ItemWithAliasCreationAction =>
22     itemCreationIntent.match(action) && action.payload.type === 'login' && action.payload.extraData.withAlias;
24 function* singleItemCreationWorker({ onItemsUpdated, getTelemetry }: RootSagaOptions, action: ItemCreationAction) {
25     const {
26         payload: createIntent,
27         meta: { callback: onItemCreationIntentProcessed },
28     } = action;
29     const { shareId, optimisticId } = createIntent;
30     const isAlias = createIntent.type === 'alias';
31     const telemetry = getTelemetry();
33     try {
34         const encryptedItem: ItemRevisionContentsResponse = yield isAlias
35             ? createAlias(createIntent)
36             : createItem(createIntent);
38         const item: ItemRevision = yield parseItemRevision(shareId, encryptedItem);
40         const itemCreationSuccessAction = itemCreationSuccess({ optimisticId, shareId, item });
41         yield put(itemCreationSuccessAction);
42         yield isAlias && put(requestInvalidate(aliasOptionsRequest(shareId))); /* reset alias options */
44         void telemetry?.push(
45             createTelemetryEvent(TelemetryEventName.ItemCreation, {}, { type: TelemetryItemType[item.data.type] })
46         );
48         if (item.data.type === 'login' && deobfuscate(item.data.content.totpUri)) {
49             void telemetry?.push(createTelemetryEvent(TelemetryEventName.TwoFACreation, {}, {}));
50         }
52         onItemCreationIntentProcessed?.(itemCreationSuccessAction);
53         onItemsUpdated?.();
54     } catch (e) {
55         const itemCreationFailureAction = itemCreationFailure({ optimisticId, shareId }, e);
56         yield put(itemCreationFailureAction);
58         onItemCreationIntentProcessed?.(itemCreationFailureAction);
59     }
62 function* withAliasCreationWorker(
63     { onItemsUpdated, getTelemetry }: RootSagaOptions,
64     { payload: createIntent }: ItemWithAliasCreationAction
65 ) {
66     const { shareId, optimisticId } = createIntent;
67     const telemetry = getTelemetry();
68     try {
69         const [encryptedLoginItem, encryptedAliasItem]: ItemRevisionContentsResponse[] =
70             yield createItemWithAlias(createIntent);
72         const loginItem: ItemRevision = yield parseItemRevision(shareId, encryptedLoginItem);
73         const aliasItem: ItemRevision = yield parseItemRevision(shareId, encryptedAliasItem);
75         yield put(itemCreationSuccess({ optimisticId, shareId, item: loginItem, alias: aliasItem }));
76         yield put(requestInvalidate(aliasOptionsRequest(shareId))); /* reset alias options */
78         void telemetry?.push(
79             createTelemetryEvent(TelemetryEventName.ItemCreation, {}, { type: TelemetryItemType[loginItem.data.type] })
80         );
81         void telemetry?.push(
82             createTelemetryEvent(TelemetryEventName.ItemCreation, {}, { type: TelemetryItemType[aliasItem.data.type] })
83         );
84         if (loginItem.data.type === 'login' && deobfuscate(loginItem.data.content.totpUri)) {
85             void telemetry?.push(createTelemetryEvent(TelemetryEventName.TwoFACreation, {}, {}));
86         }
88         onItemsUpdated?.();
89     } catch (err: unknown) {
90         const itemCreationFailureAction = itemCreationFailure({ optimisticId, shareId }, err);
91         yield put(itemCreationFailureAction);
92     }
95 export default function* watcher(options: RootSagaOptions) {
96     yield all([
97         takeEvery(singleItemCreation, singleItemCreationWorker, options),
98         takeEvery(withAliasItemCreation, withAliasCreationWorker, options),
99     ]);