1 import type { Draft, EditDraft, NewDraft } from '@proton/pass/store/reducers';
2 import type { Item, ItemExtraField, ItemRevision, ItemType, LoginItem, UniqueItem } from '@proton/pass/types';
3 import { ItemFlag, ItemState } from '@proton/pass/types';
4 import { and, not, or } from '@proton/pass/utils/fp/predicates';
5 import { deobfuscate } from '@proton/pass/utils/obfuscate/xor';
6 import { parseUrl } from '@proton/pass/utils/url/parser';
7 import type { URLComponents } from '@proton/pass/utils/url/types';
8 import { urlEq } from '@proton/pass/utils/url/utils';
10 export const isAliasItem = (item: Item): item is Item<'alias'> => item.type === 'alias';
11 export const isCCItem = (item: Item): item is Item<'creditCard'> => item.type === 'creditCard';
12 export const isLoginItem = (item: Item): item is Item<'login'> => item.type === 'login';
13 export const isNoteItem = (item: Item): item is Item<'note'> => item.type === 'note';
15 export const isItemType =
16 <T extends ItemType>(type: T) =>
17 <R extends ItemRevision>(item: R): item is R & ItemRevision<T> =>
18 item.data.type === type;
20 export const isPasskeyItem = (item: Item): item is Item<'login'> =>
21 isLoginItem(item) && (item.content.passkeys ?? []).length > 0;
24 <T extends UniqueItem>(a: T) =>
26 a.shareId === b.shareId && a.itemId === b.itemId;
28 export const belongsToShare =
30 <T extends UniqueItem>(item: T): boolean =>
31 item.shareId === shareId;
33 export const belongsToShares =
34 (shareIds?: string[]) =>
35 <T extends UniqueItem>(item: T): boolean =>
36 shareIds ? shareIds.includes(item.shareId) : true;
38 export const matchesLoginPassword =
40 (item: ItemRevision<'login'>): boolean =>
41 deobfuscate(item.data.content.password) === password;
43 export const matchesLoginURL = (url: URLComponents) => (item: ItemRevision<'login'>) => {
44 if (item.data.content.urls.length === 0) return false;
45 return item.data.content.urls.some((itemURL) => urlEq(url, parseUrl(itemURL)));
48 export const isTrashed = ({ state }: ItemRevision) => state === ItemState.Trashed;
49 export const isActive = not(isTrashed);
51 export const isEditItemDraft = (draft?: Draft): draft is EditDraft => draft?.mode === 'edit';
52 export const isNewItemDraft = (draft?: Draft): draft is NewDraft => draft?.mode === 'new';
54 export const isPinned = ({ pinned }: ItemRevision) => pinned;
57 (bitFlag: ItemFlag) =>
58 ({ flags }: ItemRevision) =>
59 (flags & bitFlag) === bitFlag;
61 export const isHealthCheckSkipped = hasItemFlag(ItemFlag.SkipHealthCheck);
62 export const isBreached = hasItemFlag(ItemFlag.EmailBreached);
63 export const isMonitored = not(isHealthCheckSkipped);
64 export const isAliasDisabled = hasItemFlag(ItemFlag.AliasDisabled);
66 export const isActiveMonitored = and(isActive, isMonitored);
67 export const isExcluded = and(isActive, not(isMonitored));
69 export const hasEmail = (email: string) => (item: LoginItem) =>
70 Boolean(item.data.content.itemEmail.v && deobfuscate(item.data.content.itemEmail) === email);
72 export const hasUsername = (username: string) => (item: LoginItem) =>
73 Boolean(item.data.content.itemUsername.v && deobfuscate(item.data.content.itemUsername) === username);
75 export const hasUserIdentifier = (userIdentifier: string) => (item: LoginItem) =>
76 or(hasEmail(userIdentifier), hasUsername(userIdentifier))(item);
78 export const hasDomain = (item: LoginItem) => item.data.content.urls.length > 0;
80 export const hasOTP = ({ data: { content, extraFields } }: LoginItem) =>
81 Boolean(content.totpUri.v || extraFields.some((field) => field.type === 'totp' && field.data.totpUri.v));
83 export const isExtraOTPField = (field: ItemExtraField): field is ItemExtraField<'totp'> => field.type === 'totp';