From bdd46a530c95bcc2f79f1aa7d4717e9e1daed419 Mon Sep 17 00:00:00 2001 From: aet Date: Thu, 11 Nov 2021 23:56:06 -0500 Subject: [PATCH] Restructure files --- .gitignore | 1 + package.json | 1 + packages/adapters/package.json | 6 + .../src/showDirectoryPicker.ts} | 2 +- .../src/webkitdirectory.ts} | 2 +- packages/opvault.js/package.json | 2 +- packages/opvault.js/rollup.config.js | 1 - .../src/{adapters/index.d.ts => adapter.ts} | 19 +++ packages/opvault.js/src/adapters/node.ts | 20 --- .../opvault.js/src/{models => }/crypto.ts | 16 +-- packages/opvault.js/src/fs.ts | 2 +- packages/opvault.js/src/index.ts | 16 +-- packages/opvault.js/src/models/attachment.ts | 2 +- packages/opvault.js/src/models/item.ts | 4 +- packages/opvault.js/src/models/vault.ts | 4 +- packages/opvault.js/src/types.ts | 3 + .../web/scripts/build-i18n-yml-typedef.js | 9 +- packages/web/src/components/Item.tsx | 132 ++++++++++-------- packages/web/src/components/ItemDates.tsx | 4 +- .../src/components/ItemFieldContextMenu.tsx | 3 +- .../web/src/components/ItemFieldValue.tsx | 4 +- packages/web/src/i18n/index.tsx | 36 +++-- packages/web/src/i18n/texts.yml | 71 ++++++---- packages/web/src/pages/Unlock.tsx | 10 +- packages/web/src/pages/Vault.tsx | 59 +++++--- packages/web/src/pages/VaultPicker.tsx | 4 +- pnpm-lock.yaml | 11 ++ test/profile.test.ts | 4 +- test/weakMap.test.ts | 2 +- 29 files changed, 271 insertions(+), 179 deletions(-) create mode 100644 packages/adapters/package.json rename packages/{opvault.js/src/adapters/browser.ts => adapters/src/showDirectoryPicker.ts} (97%) rename packages/{opvault.js/src/adapters/webkit.ts => adapters/src/webkitdirectory.ts} (95%) rename packages/opvault.js/src/{adapters/index.d.ts => adapter.ts} (72%) delete mode 100644 packages/opvault.js/src/adapters/node.ts rename packages/opvault.js/src/{models => }/crypto.ts (92%) diff --git a/.gitignore b/.gitignore index f9dc996..1db1f31 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +drafts node_modules mochawesome-report lib diff --git a/package.json b/package.json index efe903b..8bb6a3d 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "sass": "^1.43.2", "sinon": "^11.1.2", "sinon-chai": "^3.7.0", + "tslib": "^2.3.1", "ts-node": "^10.2.1", "tsconfig-paths": "^3.11.0", "typescript": "^4.4.3" diff --git a/packages/adapters/package.json b/packages/adapters/package.json new file mode 100644 index 0000000..55d874e --- /dev/null +++ b/packages/adapters/package.json @@ -0,0 +1,6 @@ +{ + "name": "opvault-adapters", + "dependencies": { + "opvault.js": "*" + } +} diff --git a/packages/opvault.js/src/adapters/browser.ts b/packages/adapters/src/showDirectoryPicker.ts similarity index 97% rename from packages/opvault.js/src/adapters/browser.ts rename to packages/adapters/src/showDirectoryPicker.ts index 24a9a7a..6e8cfde 100644 --- a/packages/opvault.js/src/adapters/browser.ts +++ b/packages/adapters/src/showDirectoryPicker.ts @@ -1,5 +1,5 @@ import { Buffer } from "buffer" -import type { IAdapter, IFileSystem } from "./index" +import type { IAdapter, IFileSystem } from "opvault.js/src/adapter" function normalize(path: string) { return path.replace(/^\//, "") diff --git a/packages/opvault.js/src/adapters/webkit.ts b/packages/adapters/src/webkitdirectory.ts similarity index 95% rename from packages/opvault.js/src/adapters/webkit.ts rename to packages/adapters/src/webkitdirectory.ts index ef294b5..7b31c2f 100644 --- a/packages/opvault.js/src/adapters/webkit.ts +++ b/packages/adapters/src/webkitdirectory.ts @@ -1,5 +1,5 @@ import { Buffer } from "buffer" -import type { IAdapter, IFileSystem } from "./index" +import type { IAdapter, IFileSystem } from "opvault.js/src/adapter" export class FileSystem implements IFileSystem { private paths = new Set() diff --git a/packages/opvault.js/package.json b/packages/opvault.js/package.json index 7ccae87..4512f3c 100644 --- a/packages/opvault.js/package.json +++ b/packages/opvault.js/package.json @@ -4,7 +4,7 @@ "version": "0.0.1", "license": "LGPL-3.0-or-later", "scripts": { - "build": "rollup -c; cp src/adapters/index.d.ts lib/adapters/; prettier --write lib >/dev/null", + "build": "rollup -c; prettier --write lib >/dev/null", "build:docs": "typedoc --out docs src/index.ts --excludePrivate" }, "dependencies": { diff --git a/packages/opvault.js/rollup.config.js b/packages/opvault.js/rollup.config.js index 39f3185..4a2a2ce 100644 --- a/packages/opvault.js/rollup.config.js +++ b/packages/opvault.js/rollup.config.js @@ -8,7 +8,6 @@ import { dependencies } from "./package.json" export default () => ({ input: { index: "./src/index.ts", - "adapters/node": "./src/adapters/node.ts", }, external: builtinModules.concat(Object.keys(dependencies)), output: { diff --git a/packages/opvault.js/src/adapters/index.d.ts b/packages/opvault.js/src/adapter.ts similarity index 72% rename from packages/opvault.js/src/adapters/index.d.ts rename to packages/opvault.js/src/adapter.ts index 27d72c1..b6bfcae 100644 --- a/packages/opvault.js/src/adapters/index.d.ts +++ b/packages/opvault.js/src/adapter.ts @@ -1,3 +1,6 @@ +import { promises as fs, existsSync } from "fs" +import { webcrypto } from "crypto" + /** * An object that implements basic file system functionalities. */ @@ -53,3 +56,19 @@ export interface IAdapter { */ subtle: SubtleCrypto } + +/** + * Default Node.js adapter. This can be used while using `opvault.js` + * in a Node.js environment. + */ +export const nodeAdapter: IAdapter = { + fs: { + readFile: path => fs.readFile(path, "utf-8"), + readBuffer: path => fs.readFile(path), + writeFile: fs.writeFile, + readdir: fs.readdir, + isDirectory: async path => fs.stat(path).then(x => x.isDirectory()), + exists: async path => existsSync(path), + }, + subtle: (webcrypto as any).subtle, +} diff --git a/packages/opvault.js/src/adapters/node.ts b/packages/opvault.js/src/adapters/node.ts deleted file mode 100644 index 2e6cd94..0000000 --- a/packages/opvault.js/src/adapters/node.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { promises as fs, existsSync } from "fs" -import { webcrypto } from "crypto" - -import type { IAdapter } from "./index" - -/** - * Default Node.js adapter. This can be used while using `opvault.js` - * in a Node.js environment. - */ -export const nodeAdapter: IAdapter = { - fs: { - readFile: path => fs.readFile(path, "utf-8"), - readBuffer: path => fs.readFile(path), - writeFile: fs.writeFile, - readdir: fs.readdir, - isDirectory: async path => fs.stat(path).then(x => x.isDirectory()), - exists: async path => existsSync(path), - }, - subtle: (webcrypto as any).subtle, -} diff --git a/packages/opvault.js/src/models/crypto.ts b/packages/opvault.js/src/crypto.ts similarity index 92% rename from packages/opvault.js/src/models/crypto.ts rename to packages/opvault.js/src/crypto.ts index 790f853..ddcb1cd 100644 --- a/packages/opvault.js/src/models/crypto.ts +++ b/packages/opvault.js/src/crypto.ts @@ -1,12 +1,12 @@ import { Buffer } from "buffer" -import { decryptData } from "../decipher" -import type { IAdapter } from "../adapters" -import { createEventEmitter } from "../ee" -import { HMACAssertionError } from "../errors" -import type { i18n } from "../i18n" -import type { ItemDetails, Overview, Profile } from "../types" -import { setIfAbsent } from "../util" -import type { EncryptedItem } from "./item" +import { decryptData } from "./decipher" +import type { IAdapter } from "./adapter" +import { createEventEmitter } from "./ee" +import { HMACAssertionError } from "./errors" +import type { i18n } from "./i18n" +import type { ItemDetails, Overview, Profile } from "./types" +import { setIfAbsent } from "./util" +import type { EncryptedItem } from "./models/item" /** Encryption and MAC */ export interface Cipher { diff --git a/packages/opvault.js/src/fs.ts b/packages/opvault.js/src/fs.ts index 7e7320d..c7570f3 100644 --- a/packages/opvault.js/src/fs.ts +++ b/packages/opvault.js/src/fs.ts @@ -1,6 +1,6 @@ import { resolve, extname, basename } from "path" import invariant from "tiny-invariant" -import type { IFileSystem } from "./adapters" +import type { IFileSystem } from "./adapter" import { once } from "./util" export type OnePasswordFileManager = ReturnType diff --git a/packages/opvault.js/src/index.ts b/packages/opvault.js/src/index.ts index 36bd749..7542911 100644 --- a/packages/opvault.js/src/index.ts +++ b/packages/opvault.js/src/index.ts @@ -1,6 +1,6 @@ import { resolve } from "path" import { Vault } from "./models/vault" -import type { IAdapter } from "./adapters" +import type { IAdapter } from "./adapter" import { asyncMap } from "./util" export type { Vault } from "./models/vault" @@ -18,7 +18,7 @@ interface IOptions { /** * Adapter used to interact with the file system and cryptography modules */ - adapter?: IAdapter + adapter?: IAdapter | Promise } /** @@ -26,11 +26,11 @@ interface IOptions { */ export class OnePassword { readonly #path: string - readonly #adapter: IAdapter + readonly #adapter: IAdapter | Promise constructor({ path, - adapter = process.browser ? null : require("./adapters/node").nodeAdapter, + adapter = process.browser ? null! : import("./adapter").then(x => x.nodeAdapter), }: IOptions) { this.#adapter = adapter this.#path = path @@ -40,11 +40,11 @@ export class OnePassword { * @returns A list of names of profiles of the current vault. */ async getProfileNames() { - const [fs, path] = [this.#adapter.fs, this.#path] - const children = await fs.readdir(path) + const { fs } = await this.#adapter + const children = await fs.readdir(this.#path) const profiles: string[] = [] await asyncMap(children, async child => { - const fullPath = resolve(path, child) + const fullPath = resolve(this.#path, child) if ( (await fs.isDirectory(fullPath)) && (await fs.exists(resolve(fullPath, "profile.js"))) @@ -59,6 +59,6 @@ export class OnePassword { * @returns A OnePassword Vault instance. */ async getProfile(profileName: string) { - return await Vault.of(this.#path, profileName, this.#adapter) + return await Vault.of(this.#path, profileName, await this.#adapter) } } diff --git a/packages/opvault.js/src/models/attachment.ts b/packages/opvault.js/src/models/attachment.ts index da06495..1f9ef41 100644 --- a/packages/opvault.js/src/models/attachment.ts +++ b/packages/opvault.js/src/models/attachment.ts @@ -1,5 +1,5 @@ import { Buffer } from "buffer" -import type { Crypto } from "./crypto" +import type { Crypto } from "../crypto" import { invariant } from "../errors" type integer = number diff --git a/packages/opvault.js/src/models/item.ts b/packages/opvault.js/src/models/item.ts index 2a13fdc..9734a67 100644 --- a/packages/opvault.js/src/models/item.ts +++ b/packages/opvault.js/src/models/item.ts @@ -1,5 +1,5 @@ import type { ItemDetails, Overview } from "../types" -import type { Crypto } from "./crypto" +import type { Crypto } from "../crypto" import { Attachment } from "./attachment" import { NotUnlockedError } from "../errors" import type { Category } from "../models" @@ -8,7 +8,7 @@ export interface EncryptedItem { category: string // "001" /** Unix seconds */ created: integer - d: string // "b3BkYXRhMbt" + d: string // details, bass64 folder: string // 32 chars hmac: string // base64 k: string // base64 diff --git a/packages/opvault.js/src/models/vault.ts b/packages/opvault.js/src/models/vault.ts index aa8b38d..32c5efb 100644 --- a/packages/opvault.js/src/models/vault.ts +++ b/packages/opvault.js/src/models/vault.ts @@ -1,9 +1,9 @@ -import type { IAdapter } from "../adapters" +import type { IAdapter } from "../adapter" import { HMACAssertionError, invariant } from "../errors" import { OnePasswordFileManager } from "../fs" import { i18n } from "../i18n" import type { EncryptedItem } from "./item" -import { Crypto } from "./crypto" +import { Crypto } from "../crypto" import { Item } from "./item" import type { Profile } from "../types" import { WeakValueMap } from "../weakMap" diff --git a/packages/opvault.js/src/types.ts b/packages/opvault.js/src/types.ts index 31f1eeb..bf0c728 100644 --- a/packages/opvault.js/src/types.ts +++ b/packages/opvault.js/src/types.ts @@ -130,6 +130,9 @@ export interface ItemDetails { }[] /** Web form fields */ fields?: ItemField[] + /** Plain password items */ + backupKeys?: string[] + password?: string } export interface Folder { diff --git a/packages/web/scripts/build-i18n-yml-typedef.js b/packages/web/scripts/build-i18n-yml-typedef.js index 0025841..e80bd42 100755 --- a/packages/web/scripts/build-i18n-yml-typedef.js +++ b/packages/web/scripts/build-i18n-yml-typedef.js @@ -12,8 +12,13 @@ fs.writeFileSync( dtsPath, `type Translation = Record; declare const exportee: { - ${Object.keys(json) - .map(x => `${x}: Translation;`) + ${Object.entries(json) + .map( + ([category, value]) => + `${category}: {\n${Object.keys(value) + .map(key => ` ${key}: Translation;`) + .join("\n")}\n };` + ) .join("\n ")} }; export default exportee; diff --git a/packages/web/src/components/Item.tsx b/packages/web/src/components/Item.tsx index b60a93a..0d09df8 100644 --- a/packages/web/src/components/Item.tsx +++ b/packages/web/src/components/Item.tsx @@ -1,6 +1,7 @@ import styled from "@emotion/styled" import type { Attachment, AttachmentMetadata, Item, ItemField } from "opvault.js" -import { useEffect, useState } from "react" +import type { ItemDetails } from "opvault.js/src/types" +import { memo, useEffect, useState } from "react" import { useTranslate } from "../i18n" import { CategoryIcon } from "./CategoryIcon" import { ItemDates } from "./ItemDates" @@ -10,6 +11,7 @@ import { FieldTitle, ItemDetailsFieldView, } from "./ItemField" +import { PasswordFieldView } from "./ItemFieldValue" import { ItemWarning } from "./ItemWarning" interface ItemViewProps { @@ -57,6 +59,22 @@ const AttachmentContainer = styled.div` margin: 5px 0; ` +const SectionsView: React.FC<{ sections?: ItemDetails["sections"] }> = ({ sections }) => + sections?.length ? ( +
+ {sections + .filter(s => s.fields?.some(x => x.v != null)) + .map((section, i) => ( +
+ {section.title != null && {section.title}} + {section.fields?.map((field, j) => ( + + ))} +
+ ))} +
+ ) : null + const FieldsView: React.FC<{ fields?: ItemField[] }> = ({ fields }) => fields?.length ? (
@@ -71,7 +89,7 @@ const TagsView: React.FC<{ tags?: string[] }> = ({ tags }) => { if (!tags?.length) return null return ( - {t.noun_tags} + {t.noun.tags}
{tags.map((tag, i) => ( {tag} @@ -81,65 +99,69 @@ const TagsView: React.FC<{ tags?: string[] }> = ({ tags }) => { ) } -export const ItemView: React.FC = ({ className, item }) => ( - - - -
- {item.details.fields == null} - - {item.overview.title} -
-
- JSON -
-          {JSON.stringify({ overview: item.overview, details: item.details }, null, 2)}
-        
-
+const JSONView = memo<{ item: Item }>(({ item }) => ( +
+ JSON +
+      {JSON.stringify({ overview: item.overview, details: item.details }, null, 2)}
+    
+
+)) -
- {item.details.sections - ?.filter(s => s.fields?.some(x => x.v != null)) - .map((section, i) => ( -
- {section.title != null && {section.title}} - {section.fields?.map((field, j) => ( - +export const ItemView: React.FC = ({ className, item }) => { + const t = useTranslate() + return ( + + + +
+ {item.details.fields == null} + + {item.overview.title} +
+ + +
+ + + + + {item.details.notesPlain != null && ( + + notes +
+

{item.details.notesPlain}

+
+
+ )} + + {item.details.password != null && ( + + {t.label.password} + + + )} + + + + {item.attachments.length > 0 && ( + + attachments +
+ {item.attachments.map((file, i) => ( + ))}
- ))} -
+ + )} - - - {item.details.notesPlain != null && ( - notes -
-

{item.details.notesPlain}

-
+
- )} - - - - {item.attachments.length > 0 && ( - - attachments -
- {item.attachments.map((file, i) => ( - - ))} -
-
- )} - - - - - - -) + + + ) +} function AttachmentView({ file }: { file: Attachment }) { const [metadata, setMetadata] = useState() diff --git a/packages/web/src/components/ItemDates.tsx b/packages/web/src/components/ItemDates.tsx index 3a084bf..a0cf6d9 100644 --- a/packages/web/src/components/ItemDates.tsx +++ b/packages/web/src/components/ItemDates.tsx @@ -14,10 +14,10 @@ export const ItemDates: React.FC<{ item: Item }> = ({ item }) => { return (
- {t.label_last_updated}: {new Date(item.updatedAt).toLocaleString()} + {t.label.last_updated}: {new Date(item.updatedAt).toLocaleString()}
- {t.label_created_at}: {new Date(item.createdAt).toLocaleString()} + {t.label.created_at}: {new Date(item.createdAt).toLocaleString()}
) diff --git a/packages/web/src/components/ItemFieldContextMenu.tsx b/packages/web/src/components/ItemFieldContextMenu.tsx index 8c4b57f..80b6146 100644 --- a/packages/web/src/components/ItemFieldContextMenu.tsx +++ b/packages/web/src/components/ItemFieldContextMenu.tsx @@ -7,7 +7,7 @@ const Container = styled.menu` box-shadow: #0004 0px 1px 4px; left: 99%; margin-block-start: 0; - min-width: 120px; + min-width: 150px; padding-inline-start: 0; position: absolute; top: 0; @@ -39,6 +39,7 @@ const Item = styled.div` height: 2.5em; align-items: center; padding-left: 1em; + padding-right: 5px; position: relative; &:hover { background-color: #ddd; diff --git a/packages/web/src/components/ItemFieldValue.tsx b/packages/web/src/components/ItemFieldValue.tsx index 25188a3..e96b9f4 100644 --- a/packages/web/src/components/ItemFieldValue.tsx +++ b/packages/web/src/components/ItemFieldValue.tsx @@ -9,8 +9,10 @@ import { useItemFieldContextMenu } from "./ItemFieldContextMenu" const Container = styled.div`` +export { Password as PasswordFieldView } + const Password: React.FC<{ - field: ItemSection.Concealed + field: Pick }> = ({ field }) => { const [show, setShow] = useState(false) const [bigText, showBigText] = useState(false) diff --git a/packages/web/src/i18n/index.tsx b/packages/web/src/i18n/index.tsx index ad7eff4..b4f4671 100644 --- a/packages/web/src/i18n/index.tsx +++ b/packages/web/src/i18n/index.tsx @@ -1,7 +1,7 @@ import { createContext, memo, useContext, useEffect, useMemo, useState } from "react" import texts from "./texts.yml" -type Keys = keyof typeof texts +const categories = Object.keys(texts) const ALLOWED = new Set(["en", "fr"]) const LOCALSTORAGE_KEY = "preferred-locale" @@ -40,21 +40,29 @@ export function useTranslate() { const { locale } = useContext(LocaleContext) const t = useMemo( () => - new Proxy( - {}, - { - get(_, p: string) { - if ( - process.env.NODE_ENV === "development" && - !Object.prototype.hasOwnProperty.call(texts, p) - ) { - throw new Error(`t.${p} does not exist.`) + Object.fromEntries( + categories.map(category => [ + category, + new Proxy( + {}, + { + get(_, p: string) { + const obj = (texts as any)[category] + if ( + process.env.NODE_ENV === "development" && + !Object.prototype.hasOwnProperty.call(obj, p) + ) { + throw new Error(`t.${p} does not exist.`) + } + return obj[p][locale] + }, } - return (texts as any)[p][locale] - }, - } + ), + ]) ) as { - [key in Keys]: string + [category in keyof typeof texts]: { + [key in keyof typeof texts[category]]: string + } }, [locale] ) diff --git a/packages/web/src/i18n/texts.yml b/packages/web/src/i18n/texts.yml index c5735a9..4c56f0e 100644 --- a/packages/web/src/i18n/texts.yml +++ b/packages/web/src/i18n/texts.yml @@ -1,40 +1,51 @@ # /* spellchecker: disable */ -label_choose_a_vault: - en: Pick a vault - fr: Choisir un coffre +label: + choose_a_vault: + en: Pick a vault + fr: Choisir un coffre -label_no_vault_selected: - en: No vault is selected. - fr: Aucun coffre n’est sélectionné. + no_vault_selected: + en: No vault is selected. + fr: Aucun coffre n’est sélectionné. -label_last_updated: - en: Last Updated - fr: Dernière modification + last_updated: + en: Last Updated + fr: Dernière modification -label_created_at: - en: Created At - fr: Créé + created_at: + en: Created At + fr: Créé -label_password_placeholder: - en: Master Password - fr: Mot de passe principal + password_placeholder: + en: Master Password + fr: Mot de passe principal -noun_vault: - en: vault - fr: coffre + username: + en: Username + fr: Nom d’utilisateur -noun_tags: - en: tags - fr: mots-clés + password: + en: Password + fr: Mot de passe -action_lock: - en: Lock - fr: Vérouiller +noun: + vault: + en: vault + fr: coffre -action_unlock: - en: Unlock - fr: Déverouiller + tags: + en: tags + fr: mots-clés -action_go_back: - en: Back - fr: Revenir +action: + lock: + en: Lock + fr: Vérouiller + + unlock: + en: Unlock + fr: Déverouiller + + go_back: + en: Back + fr: Revenir diff --git a/packages/web/src/pages/Unlock.tsx b/packages/web/src/pages/Unlock.tsx index 2811459..d7710b8 100644 --- a/packages/web/src/pages/Unlock.tsx +++ b/packages/web/src/pages/Unlock.tsx @@ -102,17 +102,17 @@ export const Unlock: React.FC<{ return (
- + @@ -122,14 +122,14 @@ export const Unlock: React.FC<{ type="password" value={password} onChange={e => setPassword(e.currentTarget.value)} - placeholder={t.label_password_placeholder} + placeholder={t.label.password_placeholder} onKeyUp={onKeyUp} /> diff --git a/packages/web/src/pages/Vault.tsx b/packages/web/src/pages/Vault.tsx index 3e1dd6c..b6d0284 100644 --- a/packages/web/src/pages/Vault.tsx +++ b/packages/web/src/pages/Vault.tsx @@ -88,25 +88,36 @@ export const VaultView: React.FC<{ vault: Vault; onLock(): void }> = ({ arrayFrom(vault.values()).then(setItems) }, [vault]) - const filtered = useMemo( - () => - sortedItem - .filter(x => x.category !== Category.Tombstone) - .filter( - search - ? x => - stringCompare(search, x.overview.title) || - stringCompare(search, x.overview.ainfo) - : () => true - ), - [sortedItem, search] - ) + const filtered = useMemo(() => { + const items = sortedItem.filter(x => x.category !== Category.Tombstone) + let res: Item[] = items + if (search) { + res = [] + for (const x of items) { + const compare = Math.max( + stringCompare(search, x.overview.title), + stringCompare(search, x.overview.ainfo) + ) as CompareResult + switch (compare) { + case CompareResult.NoMatch: + continue + case CompareResult.Includes: + res.push(x) + break + case CompareResult.Equals: + res.unshift(x) + break + } + } + } + return res + }, [sortedItem, search]) return (
- + @@ -147,8 +158,20 @@ async function arrayFrom(generator: AsyncGenerator) { return list } -function stringCompare(search: string, source?: string) { - if (!search) return true - if (!source) return false - return source.toLocaleLowerCase().includes(search.toLocaleLowerCase()) +enum CompareResult { + NoMatch, + Includes, + Equals, +} + +function stringCompare(search: string, source?: string) { + if (!search) return CompareResult.Includes + if (!source) return CompareResult.NoMatch + source = source.toLocaleLowerCase() + search = search.toLocaleUpperCase() + const includes = source.includes(search.toLocaleLowerCase()) + if (includes) { + return source.length === search.length ? CompareResult.Equals : CompareResult.Includes + } + return CompareResult.NoMatch } diff --git a/packages/web/src/pages/VaultPicker.tsx b/packages/web/src/pages/VaultPicker.tsx index 82908cd..36b0822 100644 --- a/packages/web/src/pages/VaultPicker.tsx +++ b/packages/web/src/pages/VaultPicker.tsx @@ -87,8 +87,8 @@ const PickOPVault: React.FC<{ return ( - - {t.label_no_vault_selected} + + {t.label.no_vault_selected} ) } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3627562..4e461d7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -35,6 +35,7 @@ importers: sinon-chai: ^3.7.0 ts-node: ^10.2.1 tsconfig-paths: ^3.11.0 + tslib: ^2.3.1 typescript: ^4.4.3 devDependencies: '@types/chai': 4.2.22 @@ -68,8 +69,15 @@ importers: sinon-chai: 3.7.0_chai@4.3.4+sinon@11.1.2 ts-node: 10.2.1_8304ecd715830f7c190b4d1dea90b100 tsconfig-paths: 3.11.0 + tslib: 2.3.1 typescript: 4.4.3 + packages/adapters: + specifiers: + opvault.js: '*' + dependencies: + opvault.js: link:../opvault.js + packages/opvault.js: specifiers: '@rollup/plugin-json': ^4.1.0 @@ -137,6 +145,9 @@ importers: typescript: 4.4.3 vite: 2.6.13_sass@1.43.4 + packages/web/dist: + specifiers: {} + packages: /7zip-bin/5.1.1: diff --git a/test/profile.test.ts b/test/profile.test.ts index 7a1f65b..46e8d2a 100644 --- a/test/profile.test.ts +++ b/test/profile.test.ts @@ -2,8 +2,8 @@ import { resolve } from "path"; import { describe, it, beforeEach } from "mocha"; import { expect } from "chai"; -import type { Vault } from "../packages/opvault.js/index"; -import { OnePassword } from "../packages/opvault.js/index"; +import type { Vault } from "../packages/opvault.js/src/index"; +import { OnePassword } from "../packages/opvault.js/src/index"; describe("OnePassword", () => { const freddy = resolve(__dirname, "../freddy-2013-12-04.opvault"); diff --git a/test/weakMap.test.ts b/test/weakMap.test.ts index 9e6b493..77fada0 100644 --- a/test/weakMap.test.ts +++ b/test/weakMap.test.ts @@ -1,7 +1,7 @@ import { describe, it } from "mocha"; import { expect } from "chai"; -import { WeakValueMap } from "../packages/opvault.js/weakMap"; +import { WeakValueMap } from "../packages/opvault.js/src/weakMap"; declare const gc: () => void;