Use classes for vault items and fields to have better control over serialization

This commit is contained in:
Martin Kleinschrodt 2020-05-13 15:00:19 +02:00
parent 1294228918
commit 7bb7839b97
13 changed files with 214 additions and 224 deletions

View File

@ -1,5 +1,5 @@
import { styleMap } from "lit-html/directives/style-map";
import { VaultItem, Field, transformedValue } from "@padloc/core/src/item";
import { VaultItem, Field } from "@padloc/core/src/item";
import { setClipboard } from "@padloc/core/src/platform";
import { shared, mixins } from "../styles";
import { BaseElement, element, html, css, property } from "./base";
@ -161,7 +161,7 @@ export class Clipboard extends BaseElement {
this.item = item;
this.field = field;
const value = await transformedValue(field);
const value = await field.transform();
setClipboard(value);
const tStart = Date.now();

View File

@ -1,5 +1,5 @@
import { Vault } from "@padloc/core/src/vault";
import { VaultItem, ItemTemplate, ITEM_TEMPLATES } from "@padloc/core/src/item";
import { VaultItem, Field, ItemTemplate, ITEM_TEMPLATES } from "@padloc/core/src/item";
import { translate as $l } from "@padloc/locale/src/translate";
import { app, router } from "../globals";
import { alert } from "../lib/dialog";
@ -139,7 +139,7 @@ export class CreateItemDialog extends Dialog<Vault, VaultItem> {
const item = await app.createItem(
"",
vault,
this._template.fields.map(f => ({ ...f, value: "" }))
this._template.fields.map(f => new Field({ ...f, value: "" }))
);
this.done(item);

View File

@ -21,7 +21,7 @@ export class FieldElement extends BaseElement {
value: string = "";
@property()
type: FieldType = "note";
type: FieldType = FieldType.Note;
@property()
private _masked: boolean = false;

View File

@ -469,18 +469,18 @@ export class ItemDialog extends Dialog<string, void> {
private _getFields() {
return [...this._fieldInputs].map((fieldEl: FieldElement) => {
return {
return new Field({
name: fieldEl.name,
value: fieldEl.value,
type: fieldEl.type
};
});
});
}
private _itemChanged() {
const item = this._item!;
this._nameInput.value = item.name;
this._fields = item.fields.map(f => ({ ...f }));
this._fields = item.fields.map(f => new Field({ ...f }));
this._tagsInput.tags = [...item.tags];
}
@ -510,7 +510,7 @@ export class ItemDialog extends Dialog<string, void> {
return;
}
this._fields.push({ name: fieldDef.name, value: "", type: fieldDef.type });
this._fields.push(new Field({ name: fieldDef.name, value: "", type: fieldDef.type }));
this.requestUpdate();
await this.updateComplete;
setTimeout(() => this._fieldInputs[this._fields.length - 1].focus(), 100);

View File

@ -1,4 +1,4 @@
import { VaultItem, Field, Tag, FIELD_DEFS } from "@padloc/core/src/item";
import { VaultItem, Field, Tag } from "@padloc/core/src/item";
import { Vault, VaultID } from "@padloc/core/src/vault";
import { translate as $l } from "@padloc/locale/src/translate";
import { debounce, wait, escapeRegex } from "@padloc/core/src/util";
@ -817,7 +817,6 @@ export class ItemsList extends StateMixin(View) {
<div class="item-fields">
${item.fields.map((f: Field, i: number) => {
const fieldDef = FIELD_DEFS[f.type] || FIELD_DEFS.text;
return html`
<div
class="item-field tap"
@ -827,7 +826,7 @@ export class ItemsList extends StateMixin(View) {
>
<div class="item-field-label">
<div class="item-field-name">
<pl-icon icon="${fieldDef.icon}"></pl-icon>
<pl-icon icon="${f.icon}"></pl-icon>
${f.name || $l("Unnamed")}
</div>
${f.type === "totp"
@ -836,7 +835,7 @@ export class ItemsList extends StateMixin(View) {
`
: html`
<div class="item-field-value">
${fieldDef.format ? fieldDef.format(f.value, true) : f.value}
${f.format(true)}
</div>
`}
</div>

View File

@ -1,7 +1,7 @@
import { unmarshal, bytesToString } from "@padloc/core/src/encoding";
import { PBES2Container } from "@padloc/core/src/container";
import { validateLegacyContainer, parseLegacyContainer } from "@padloc/core/src/legacy";
import { VaultItem, Field, createVaultItem, guessFieldType } from "@padloc/core/src/item";
import { VaultItem, Field, createVaultItem, FieldType } from "@padloc/core/src/item";
import { Err, ErrorCode } from "@padloc/core/src/error";
import { uuid } from "@padloc/core/src/util";
import { translate as $l } from "@padloc/locale/src/translate";
@ -80,11 +80,12 @@ export async function fromTable(data: string[][], nameColIndex?: number, tagsCol
if (i != nameColIndex && i != tagsColIndex && row[i]) {
const name = colNames[i];
const value = row[i];
fields.push({
name,
value,
type: guessFieldType({ name, value })
});
fields.push(
new Field().fromRaw({
name,
value
})
);
}
}
@ -132,7 +133,7 @@ export async function importLegacyContainer(container: PBES2Container) {
const items = records
.filter(({ removed }) => !removed)
.map(async ({ name = "Unnamed", fields = [], tags, category, updated, lastUsed }) => {
return {
return new VaultItem({
id: await uuid(),
name,
fields,
@ -142,7 +143,7 @@ export async function importLegacyContainer(container: PBES2Container) {
updatedBy: "",
attachments: [],
favorited: []
} as VaultItem;
});
});
return Promise.all(items);
@ -210,9 +211,9 @@ async function lpParseRow(row: string[]): Promise<VaultItem> {
const notesIndex = 3;
let fields: Field[] = [
{ name: $l("Username"), value: row[usernameIndex], type: "username" },
{ name: $l("Password"), value: row[passwordIndex], type: "password" },
{ name: $l("URL"), value: row[urlIndex], type: "url" }
new Field({ name: $l("Username"), value: row[usernameIndex], type: FieldType.Username }),
new Field({ name: $l("Password"), value: row[passwordIndex], type: FieldType.Password }),
new Field({ name: $l("URL"), value: row[urlIndex], type: FieldType.Url })
];
let notes = row[notesIndex];
@ -224,7 +225,7 @@ async function lpParseRow(row: string[]): Promise<VaultItem> {
fields = fields.filter(f => f.name != "url" && f.name != "NoteType");
} else {
// We've got a regular 'site' item, so the 'extra' column simply contains notes
fields.push({ name: $l("Notes"), value: notes, type: "note" });
fields.push(new Field({ name: $l("Notes"), value: notes, type: FieldType.Note }));
}
const dir = row[categoryIndex];

View File

@ -24,7 +24,6 @@ import {
} from "./api";
import { Client } from "./client";
import { Sender } from "./transport";
import { translate as $l } from "@padloc/locale/src/translate";
import {
DeviceInfo,
getDeviceInfo,
@ -1196,11 +1195,6 @@ export class App {
/** Creates a new [[VaultItem]] */
async createItem(name: string, vault: { id: VaultID }, fields?: Field[], tags?: Tag[]): Promise<VaultItem> {
fields = fields || [
{ name: $l("Username"), value: "", type: "username" },
{ name: $l("Password"), value: "", type: "password" },
{ name: $l("URL"), value: "", type: "url" }
];
const item = await createVaultItem(name || "", fields, tags);
if (this.account) {
item.updatedBy = this.account.id;
@ -1233,7 +1227,7 @@ export class App {
upd.favorite ? favorited.add(account.id) : favorited.delete(account.id);
}
vault.items.update({ ...item, ...upd, updatedBy: this.account!.id, favorited: [...favorited] });
vault.items.update(new VaultItem({ ...item, ...upd, updatedBy: this.account!.id, favorited: [...favorited] }));
await this.saveVault(vault);
await this.syncVault(vault);
}
@ -1279,7 +1273,7 @@ export class App {
if (items.some(item => !!item.attachments.length)) {
throw "Items with attachments cannot be moved!";
}
const newItems = await Promise.all(items.map(async item => ({ ...item, id: await uuid() })));
const newItems = await Promise.all(items.map(async item => new VaultItem({ ...item, id: await uuid() })));
await this.addItems(newItems, target);
await this.deleteItems(items);
return newItems;

View File

@ -1,4 +1,4 @@
import { bytesToBase64, base64ToBytes } from "./encoding";
import { Serializable, AsBytes } from "./encoding";
import { SimpleContainer } from "./container";
import { VaultID } from "./vault";
import { AESKeyParams } from "./crypto";
@ -60,13 +60,20 @@ function readFileAsDataURL(blob: File): Promise<string> {
export type AttachmentID = string;
export interface AttachmentInfo {
id: AttachmentID;
vault: VaultID;
name: string;
size: number;
type: string;
key: string;
export class AttachmentInfo extends Serializable {
constructor(vals: Partial<AttachmentInfo> = {}) {
super();
Object.assign(this, vals);
}
id: AttachmentID = "";
vault: VaultID = "";
name: string = "";
size: number = 0;
type: string = "";
@AsBytes()
key!: Uint8Array;
}
export class Attachment extends SimpleContainer {
@ -78,29 +85,23 @@ export class Attachment extends SimpleContainer {
uploadProgress?: RequestProgress;
downloadProgress?: RequestProgress;
constructor(info?: Partial<AttachmentInfo>) {
constructor({ key, ...info }: Partial<AttachmentInfo> = {}) {
super();
if (info) {
this.id = info.id || "";
this.vault = info.vault || "";
this.name = info.name || "";
this.size = info.size || 0;
this.type = info.type || "";
if (info.key) {
this._key = base64ToBytes(info.key);
}
}
Object.assign(this, {
_key: key,
...info
});
}
get info(): AttachmentInfo {
return {
return new AttachmentInfo({
id: this.id,
vault: this.vault,
name: this.name,
type: this.type,
size: this.size,
key: this._key ? bytesToBase64(this._key) : ""
};
key: this._key
});
}
get loaded(): boolean {

View File

@ -1,16 +1,12 @@
import { Serializable } from "./encoding";
export interface CollectionItem {
id: string;
updated?: Date;
}
import { VaultItem } from "./item";
/**
* A collection of items, used for consolidating changes made independently
* A collection of vault items items, used for consolidating changes made independently
* across multiple instances through "merging".
*/
export class Collection<T extends CollectionItem> extends Serializable implements Iterable<T> {
/** Number of items in this Collection */
export class VaultItemCollection extends Serializable implements Iterable<VaultItem> {
/** Number of items in this VaultItemCollection */
get size() {
return this._items.size;
}
@ -19,12 +15,23 @@ export class Collection<T extends CollectionItem> extends Serializable implement
return !!this._changes.size;
}
private _items: Map<string, T>;
/** Aggregated list of tags assigned to the items in this collection */
get tags(): string[] {
const tags = new Set<string>();
for (const r of this) {
for (const t of r.tags) {
tags.add(t);
}
}
return [...tags];
}
private _items: Map<string, VaultItem>;
private _changes = new Map<string, Date>();
constructor(items: T[] = []) {
constructor(items: VaultItem[] = []) {
super();
this._items = new Map(items.map(item => [item.id, item] as [string, T]));
this._items = new Map(items.map(item => [item.id, item] as [string, VaultItem]));
}
/** Get an item with a given `id` */
@ -36,7 +43,7 @@ export class Collection<T extends CollectionItem> extends Serializable implement
* Updates one or more items based on their id. If no item with the same id
* exists, the item will be added to the collection
*/
update(...items: T[]) {
update(...items: VaultItem[]) {
for (const item of items) {
item.updated = new Date();
this._items.set(item.id, item);
@ -47,7 +54,7 @@ export class Collection<T extends CollectionItem> extends Serializable implement
/**
* Removes one or more items based on their id.
*/
remove(...items: T[]) {
remove(...items: VaultItem[]) {
for (const item of items) {
this._items.delete(item.id);
this._changes.set(item.id, new Date());
@ -55,9 +62,9 @@ export class Collection<T extends CollectionItem> extends Serializable implement
}
/**
* Merges in changes from another [[Collection]] instance.
* Merges in changes from another [[VaultItemCollection]] instance.
*/
merge(coll: Collection<T>) {
merge(coll: VaultItemCollection) {
// Delete any items from this collection that don't
// exist in the other collection and haven't been changed recently
for (const item of this) {
@ -82,20 +89,17 @@ export class Collection<T extends CollectionItem> extends Serializable implement
}
}
protected _toRaw() {
protected _toRaw(version: string) {
return {
items: Array.from(this),
items: Array.from(this).map(item => item.toRaw(version)),
changes: [...this._changes]
};
}
protected _fromRaw({ items, changes }: any) {
for (const item of items) {
if (!(item.updated instanceof Date)) {
item.updated = new Date(item.updated);
}
}
this._items = new Map(items.map((item: any) => [item.id, item] as [string, T]));
this._items = new Map(
items.map((item: any) => [item.id, new VaultItem().fromRaw(item)] as [string, VaultItem])
);
this._changes = new Map<string, Date>(
changes && changes.map(([id, date]: [string, string]) => [id, new Date(date)])
);

View File

@ -1,8 +1,7 @@
import { translate as $l } from "@padloc/locale/src/translate";
import { base32ToBytes } from "./encoding";
import { base32ToBytes, Serializable, AsSerializable, AsDate } from "./encoding";
import { totp } from "./otp";
import { uuid } from "./util";
import { Collection, CollectionItem } from "./collection";
import { AccountID } from "./account";
import { AttachmentInfo } from "./attachment";
@ -12,19 +11,20 @@ export type Tag = string;
/** Unique identifier for [[VaultItem]]s */
export type VaultItemID = string;
export type FieldType =
| "username"
| "password"
| "url"
| "email"
| "date"
| "month"
| "credit"
| "phone"
| "pin"
| "totp"
| "note"
| "text";
export enum FieldType {
Username = "username",
Password = "password",
Url = "url",
Email = "email",
Date = "date",
Month = "month",
Credit = "credit",
Phone = "phone",
Pin = "pin",
Totp = "totp",
Note = "note",
Text = "text"
}
/**
* Field definition containing meta data for a certain field type
@ -50,8 +50,8 @@ export interface FieldDef {
/** Available field types and respective meta data */
export const FIELD_DEFS: { [t in FieldType]: FieldDef } = {
username: {
type: "username",
[FieldType.Username]: {
type: FieldType.Username,
pattern: ".*",
mask: false,
multiline: false,
@ -60,8 +60,8 @@ export const FIELD_DEFS: { [t in FieldType]: FieldDef } = {
return $l("Username");
}
},
password: {
type: "password",
[FieldType.Password]: {
type: FieldType.Password,
pattern: ".*",
mask: true,
multiline: true,
@ -73,8 +73,8 @@ export const FIELD_DEFS: { [t in FieldType]: FieldDef } = {
return masked ? value.replace(/./g, "\u2022") : value;
}
},
url: {
type: "url",
[FieldType.Url]: {
type: FieldType.Url,
pattern: ".*",
mask: false,
multiline: false,
@ -83,8 +83,8 @@ export const FIELD_DEFS: { [t in FieldType]: FieldDef } = {
return $l("URL");
}
},
email: {
type: "email",
[FieldType.Email]: {
type: FieldType.Email,
pattern: ".*",
mask: false,
multiline: false,
@ -93,8 +93,8 @@ export const FIELD_DEFS: { [t in FieldType]: FieldDef } = {
return $l("Email Address");
}
},
date: {
type: "date",
[FieldType.Date]: {
type: FieldType.Date,
pattern: "\\d\\d\\d\\d-\\d\\d-\\d\\d",
mask: false,
multiline: false,
@ -106,8 +106,8 @@ export const FIELD_DEFS: { [t in FieldType]: FieldDef } = {
return new Date(value).toLocaleDateString();
}
},
month: {
type: "month",
[FieldType.Month]: {
type: FieldType.Month,
pattern: "\\d\\d\\d\\d-\\d\\d",
mask: false,
multiline: false,
@ -116,8 +116,8 @@ export const FIELD_DEFS: { [t in FieldType]: FieldDef } = {
return $l("Month");
}
},
credit: {
type: "credit",
[FieldType.Credit]: {
type: FieldType.Credit,
pattern: "\\d*",
mask: true,
multiline: false,
@ -136,8 +136,8 @@ export const FIELD_DEFS: { [t in FieldType]: FieldDef } = {
return parts.join(" ");
}
},
phone: {
type: "phone",
[FieldType.Phone]: {
type: FieldType.Phone,
pattern: ".*",
mask: false,
multiline: false,
@ -146,8 +146,8 @@ export const FIELD_DEFS: { [t in FieldType]: FieldDef } = {
return $l("Phone Number");
}
},
pin: {
type: "pin",
[FieldType.Pin]: {
type: FieldType.Pin,
pattern: "\\d*",
mask: true,
multiline: false,
@ -159,8 +159,8 @@ export const FIELD_DEFS: { [t in FieldType]: FieldDef } = {
return masked ? value.replace(/./g, "\u2022") : value;
}
},
totp: {
type: "totp",
[FieldType.Totp]: {
type: FieldType.Totp,
pattern: ".*",
mask: false,
multiline: false,
@ -172,8 +172,8 @@ export const FIELD_DEFS: { [t in FieldType]: FieldDef } = {
return await totp(base32ToBytes(value));
}
},
note: {
type: "note",
[FieldType.Note]: {
type: FieldType.Note,
pattern: ".*",
mask: false,
multiline: true,
@ -182,8 +182,8 @@ export const FIELD_DEFS: { [t in FieldType]: FieldDef } = {
return $l("Note");
}
},
text: {
type: "text",
[FieldType.Text]: {
type: FieldType.Text,
pattern: ".*",
mask: false,
multiline: false,
@ -194,16 +194,44 @@ export const FIELD_DEFS: { [t in FieldType]: FieldDef } = {
}
};
export interface Field {
/** field name */
name: string;
/** field content */
value: string;
export class Field extends Serializable {
constructor(vals: Partial<Field> = {}) {
super();
Object.assign(this, vals);
}
/**
* field type, determining meta data via the corresponding field definition
* in [[FIELD_DEFS]]
*/
type: FieldType;
type: FieldType = FieldType.Text;
/** field name */
name: string = "";
/** field content */
value: string = "";
get def(): FieldDef {
return FIELD_DEFS[this.type];
}
get icon() {
return this.def.icon;
}
async transform() {
return this.def.transform ? await this.def.transform(this.value) : this.value;
}
format(masked: boolean) {
return this.def.format ? this.def.format(this.value, masked) : this.value;
}
protected _fromRaw(raw: any) {
if (!raw.type) {
raw.type = guessFieldType(raw);
}
return super._fromRaw(raw);
}
}
/** Normalizes a tag value by removing invalid characters */
@ -212,38 +240,52 @@ export function normalizeTag(tag: string): Tag {
}
/** Represents an entry within a vault */
export interface VaultItem extends CollectionItem {
export class VaultItem extends Serializable {
constructor(vals: Partial<VaultItem> = {}) {
super();
Object.assign(this, vals);
}
/** unique identfier */
id: VaultItemID;
id: VaultItemID = "";
/** item name */
name: string;
name: string = "";
/** item fields */
fields: Field[];
@AsSerializable(Field)
fields: Field[] = [];
/** array of tags assigned with this item */
tags: Tag[];
tags: Tag[] = [];
/** Date and time of last update */
@AsDate()
updated: Date = new Date();
/** [[Account]] the item was last updated by */
updatedBy: AccountID;
updatedBy: AccountID = "";
/** Last time the item was interacted with */
lastUsed: Date;
/** attachments associated with this item */
attachments: AttachmentInfo[];
@AsDate()
lastUsed: Date = new Date(0);
/** Accounts that have favorited this item */
favorited: AccountID[];
favorited: AccountID[] = [];
/** attachments associated with this item */
@AsSerializable(AttachmentInfo)
attachments: AttachmentInfo[] = [];
}
/** Creates a new vault item */
export async function createVaultItem(name: string, fields?: Field[], tags?: Tag[]): Promise<VaultItem> {
return {
id: await uuid(),
name: name,
fields: fields || [],
tags: tags || [],
updated: new Date(),
updatedBy: "",
lastUsed: new Date(0),
attachments: [],
favorited: []
};
return new VaultItem({
name,
fields,
tags,
id: await uuid()
});
}
const matchUsername = /username/i;
@ -254,14 +296,14 @@ const matchNote = /\n/;
/** Guesses the most appropriate field type based on field name and value */
export function guessFieldType({ name = "", value = "", masked }: any): FieldType {
return masked || name.match(matchPassword)
? "password"
? FieldType.Password
: name.match(matchUsername)
? "username"
? FieldType.Username
: name.match(matchUrl)
? "url"
? FieldType.Url
: value.match(matchNote)
? "note"
: "text";
? FieldType.Note
: FieldType.Text;
}
export interface ItemTemplate {
@ -280,19 +322,19 @@ export const ITEM_TEMPLATES: ItemTemplate[] = [
get name() {
return $l("Username");
},
type: "username"
type: FieldType.Username
},
{
get name() {
return $l("Password");
},
type: "password"
type: FieldType.Password
},
{
get name() {
return $l("URL");
},
type: "url"
type: FieldType.Url
}
]
},
@ -304,31 +346,31 @@ export const ITEM_TEMPLATES: ItemTemplate[] = [
get name() {
return $l("Card Number");
},
type: "credit"
type: FieldType.Credit
},
{
get name() {
return $l("Card Owner");
},
type: "text"
type: FieldType.Text
},
{
get name() {
return $l("Valid Until");
},
type: "month"
type: FieldType.Month
},
{
get name() {
return $l("CVC");
},
type: "pin"
type: FieldType.Pin
},
{
get name() {
return $l("PIN");
},
type: "pin"
type: FieldType.Pin
}
]
},
@ -340,25 +382,25 @@ export const ITEM_TEMPLATES: ItemTemplate[] = [
get name() {
return $l("Account Owner");
},
type: "text"
type: FieldType.Text
},
{
get name() {
return $l("IBAN");
},
type: "text"
type: FieldType.Text
},
{
get name() {
return $l("BIC");
},
type: "text"
type: FieldType.Text
},
{
get name() {
return $l("Card PIN");
},
type: "pin"
type: FieldType.Pin
}
]
},
@ -370,13 +412,13 @@ export const ITEM_TEMPLATES: ItemTemplate[] = [
get name() {
return $l("Name");
},
type: "text"
type: FieldType.Text
},
{
get name() {
return $l("Password");
},
type: "password"
type: FieldType.Password
}
]
},
@ -388,43 +430,43 @@ export const ITEM_TEMPLATES: ItemTemplate[] = [
get name() {
return $l("Full Name");
},
type: "text"
type: FieldType.Text
},
{
get name() {
return $l("Passport Number");
},
type: "text"
type: FieldType.Text
},
{
get name() {
return $l("Country");
},
type: "text"
type: FieldType.Text
},
{
get name() {
return $l("Birthdate");
},
type: "date"
type: FieldType.Date
},
{
get name() {
return $l("Birthplace");
},
type: "text"
type: FieldType.Text
},
{
get name() {
return $l("Issued On");
},
type: "date"
type: FieldType.Date
},
{
get name() {
return $l("Expires");
},
type: "date"
type: FieldType.Date
}
]
},
@ -436,7 +478,7 @@ export const ITEM_TEMPLATES: ItemTemplate[] = [
get name() {
return $l("Note");
},
type: "note"
type: FieldType.Note
}
]
},
@ -452,40 +494,3 @@ export const ITEM_TEMPLATES: ItemTemplate[] = [
fields: []
}
];
/** A collection of [[VaultItem]]s */
export class VaultItemCollection extends Collection<VaultItem> {
/** Aggregated list of tags assigned to the items in this collection */
get tags(): string[] {
const tags = new Set<string>();
for (const r of this) {
for (const t of r.tags) {
tags.add(t);
}
}
return [...tags];
}
protected _fromRaw(raw: any) {
return super._fromRaw({
...raw,
items: raw.items.map((item: any) => {
return {
...item,
lastUsed: new Date(item.lastUsed),
attachments: item.attachments || [],
fields: item.fields.map(({ name = "", value = "", masked, type }: any) => ({
name: name,
value: value,
type: type || guessFieldType({ name, value, masked })
}))
};
})
});
}
}
export async function transformedValue(field: Field) {
const type = FIELD_DEFS[field.type] || FIELD_DEFS.text;
return type.transform ? await type.transform(field.value) : field.value;
}

View File

@ -1,6 +1,6 @@
import { SharedContainer } from "./container";
import { Storable } from "./storage";
import { VaultItemCollection } from "./item";
import { VaultItemCollection } from "./collection";
import { Account, AccountID } from "./account";
import { OrgID } from "./org";
import { Exclude, AsDate } from "./encoding";

View File

@ -120,19 +120,6 @@ export class ExtensionApp extends App {
await this.app.storage.save(new RouterState({ path: this.router.path, params }));
}
// private async _fieldClicked({ detail: { item, index } }: CustomEvent<{ item: VaultItem; index: number }>) {
// const field = item.fields[index];
// const value = await transformedValue(field);
// const filled = await messageTab({
// type: "fillActive",
// value
// });
//
// if (filled) {
// window.close();
// }
// }
protected async _fieldDragged(e: CustomEvent<{ item: VaultItem; index: number; event: DragEvent }>) {
super._fieldDragged(e);

View File

@ -4,7 +4,6 @@ import { App } from "@padloc/core/src/app";
import { bytesToBase64, base64ToBytes } from "@padloc/core/src/encoding";
import { AjaxSender } from "@padloc/app/src/lib/ajax";
import { debounce } from "@padloc/core/src/util";
import { transformedValue } from "@padloc/core/src/item";
import { ExtensionPlatform } from "./platform";
import { Message, messageTab } from "./message";
@ -82,7 +81,7 @@ class ExtensionBackground {
}
const field = item.item.fields[index];
const value = await transformedValue(field);
const value = await field.transform()
await messageTab({
type: "fillActive",
value