Update selected item color in Pass menu
[ProtonMail-WebClient.git] / packages / pass / lib / search / match-url.ts
bloba5812839077a227ea9b28d5212a79d3952a9e1f9
1 import type { Item, MaybeNull } from '@proton/pass/types';
2 import { parseUrl } from '@proton/pass/utils/url/parser';
3 import { resolveDomain } from '@proton/pass/utils/url/utils';
5 export enum ItemUrlMatch {
6     TOP_MATCH = 1,
7     SUB_MATCH = 0,
8     NO_MATCH = -1,
11 /* This utility will give a score for a given login item :
12  * - priority = -1 : no match
13  * - priority = 0 : non-top level domain match
14  * - priority = 1 : direct top-level domain match */
15 export const getItemPriorityForUrl =
16     (item: Item<'login'>) =>
17     (
18         match: string,
19         options: { protocol: MaybeNull<string>; port: MaybeNull<string>; isPrivate: boolean; strict?: boolean }
20     ): ItemUrlMatch =>
21         item.content.urls.reduce<number>((priority, url) => {
22             const parsedUrl = parseUrl(url);
24             /* if an item's domain is parsed as null then
25              * we're dealing with a corrupted url */
26             if (parsedUrl.domain === null) return priority;
27             if (options.port && parsedUrl.port !== options.port) return priority;
28             if (options.protocol && parsedUrl.protocol !== options.protocol) return priority;
30             /** In strict mode :
31              * - If `match` is a top-level domain: only matches URLs without a subdomain
32              * - If `match` is a sub-domain: only matches on exact URL match */
33             const itemDomain = resolveDomain(parsedUrl);
34             if (options.strict && itemDomain !== match) return priority;
36             /* Check for strict domain match - this leverages
37              * the public suffix list from `tldts`. If dealing
38              * with a private domain, this will exclude private
39              * top-level domains when trying to match a private
40              * subdomain. */
41             const domainMatch = parsedUrl.domain === match;
43             /* If the URL we are trying to match is a non-private
44              * subdomain: allow resolving deeper subdomains for this
45              * specific subdomain. */
46             const subdomainMatch = !options?.isPrivate
47                 ? parsedUrl.subdomain && parsedUrl.subdomain.endsWith(match) && match.includes(parsedUrl.domain)
48                 : parsedUrl.subdomain === match;
50             /* no match -> skip */
51             if (!(domainMatch || subdomainMatch)) return priority;
53             return Math.max(
54                 priority,
55                 parsedUrl.isTopLevelDomain && domainMatch ? ItemUrlMatch.TOP_MATCH : ItemUrlMatch.SUB_MATCH
56             );
57         }, ItemUrlMatch.NO_MATCH);