Skip to content

Commit

Permalink
Add permission checks to Group/Entry
Browse files Browse the repository at this point in the history
  • Loading branch information
perry-mitchell committed Apr 25, 2021
1 parent dec217b commit 5d4ec96
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 2 deletions.
11 changes: 10 additions & 1 deletion source/core/Entry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ export default class Entry extends VaultItem {
const group = vault.findGroupByID(parentGroupID);
if (!group) {
throw new Error(`Failed creating entry: no group found for ID: ${parentGroupID}`);
} else if (group.isTrash() || group.isInTrash()) {
}
group._requireWritePermission();
if (group.isTrash() || group.isInTrash()) {
throw new Error("Failed creating entry: cannot create within Trash group");
}
// Generate new entry ID
Expand All @@ -55,6 +57,7 @@ export default class Entry extends VaultItem {
* @memberof Entry
*/
delete(skipTrash: boolean = false): boolean {
this._requireWritePermission();
const trashGroup = this.vault.getTrashGroup();
const parentGroup = this.getGroup();
const canTrash = trashGroup && parentGroup && !parentGroup.isTrash() && !parentGroup.isInTrash();
Expand All @@ -81,6 +84,7 @@ export default class Entry extends VaultItem {
* @returns Self
*/
deleteAttribute(attribute: string): this {
this._requireWritePermission();
this.vault.format.deleteEntryAttribute(this.id, attribute);
return this;
}
Expand All @@ -93,6 +97,7 @@ export default class Entry extends VaultItem {
* @returns Self
*/
deleteProperty(property: string): this {
this._requireWritePermission();
this.vault.format.deleteEntryProperty(this.id, property);
return this;
}
Expand Down Expand Up @@ -220,6 +225,8 @@ export default class Entry extends VaultItem {
* @memberof Entry
*/
moveToGroup(group: Group): this {
this._requireWritePermission();
// @todo Detect moving outside of share range
this.vault.format.moveEntry(this.id, group.id);
return this;
}
Expand All @@ -232,6 +239,7 @@ export default class Entry extends VaultItem {
* @memberof Entry
*/
setAttribute(attribute: string, value: string): this {
this._requireWritePermission();
this.vault.format.setEntryAttribute(this.id, attribute, value);
return this;
}
Expand All @@ -244,6 +252,7 @@ export default class Entry extends VaultItem {
* @memberof Entry
*/
setProperty(property: string, value: string): this {
this._requireWritePermission();
this.vault.format.setEntryProperty(this.id, property, value);
return this;
}
Expand Down
13 changes: 12 additions & 1 deletion source/core/Group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ export default class Group extends VaultItem {
const group = vault.findGroupByID(parentID);
if (!group) {
throw new Error(`Failed creating group: no group found for ID: ${parentID}`);
} else if (group.isTrash() || group.isInTrash()) {
}
group._requireWritePermission();
if (group.isTrash() || group.isInTrash()) {
throw new Error("Failed creating group: cannot create within Trash group");
}
}
Expand All @@ -49,6 +51,7 @@ export default class Group extends VaultItem {
* @memberof Group
*/
createEntry(title?: string): Entry {
this._requireWritePermission();
const entry = Entry.createNew(this.vault, this.id);
if (title) {
entry.setProperty("title", title);
Expand All @@ -63,6 +66,7 @@ export default class Group extends VaultItem {
* @memberof Group
*/
createGroup(title?: string): Group {
this._requireWritePermission();
const group = Group.createNew(this.vault, this.id);
if (title) {
group.setTitle(title);
Expand All @@ -79,6 +83,7 @@ export default class Group extends VaultItem {
* @memberof Group
*/
delete(skipTrash: boolean = false): boolean {
this._requireWritePermission();
if (this.isTrash()) {
throw new Error("Trash group cannot be deleted");
}
Expand Down Expand Up @@ -112,6 +117,7 @@ export default class Group extends VaultItem {
* @memberof Group
*/
deleteAttribute(attr: string): this {
this._requireWritePermission();
this.vault.format.deleteGroupAttribute(this.id, attr);
return this;
}
Expand Down Expand Up @@ -249,6 +255,8 @@ export default class Group extends VaultItem {
* @memberof Group
*/
moveTo(target: Group | Vault): this {
this._requireWritePermission();
// @todo Detect moving outside of share range
if (this.isTrash()) {
throw new Error("Trash group cannot be moved");
}
Expand All @@ -274,6 +282,7 @@ export default class Group extends VaultItem {
// target is local, so create commands here
this.vault.format.moveGroup(this.id, targetGroupID);
} else {
this._requireMgmtPermission();
// target is in another archive, so move there
moveGroupBetweenVaults(this, target);
}
Expand All @@ -288,6 +297,7 @@ export default class Group extends VaultItem {
* @memberof Group
*/
setAttribute(attribute: string, value: string): this {
this._requireWritePermission();
this.vault.format.setGroupAttribute(this.id, attribute, value);
return this;
}
Expand All @@ -298,6 +308,7 @@ export default class Group extends VaultItem {
* @returns Returns self
*/
setTitle(title: string): this {
this._requireWritePermission();
this.vault.format.setGroupTitle(this.id, title);
return this;
}
Expand Down
58 changes: 58 additions & 0 deletions source/core/VaultItem.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { Layerr } from "layerr";
import Vault from "./Vault";
import Share from "./Share";
import { ErrorCode, SharePermission } from "../types";

/**
* Base vault member class (for Entry, Group etc.)
Expand Down Expand Up @@ -34,6 +37,15 @@ export default class VaultItem {
return this._vault.format.getItemID(this._source);
}

/**
* The share ID of the entry or group, if available
* @readonly
* @memberof VaultItem
*/
get shareID(): string | null {
return this._vault.format.getItemShareID(this._source);
}

/**
* The vault this item belongs to
* @readonly
Expand All @@ -43,6 +55,21 @@ export default class VaultItem {
return this._vault;
}

permitsManagement(): boolean {
const share = this._getShare();
return share ? share.hasPermission(SharePermission.Manage) : true;
}

permitsModification(): boolean {
const share = this._getShare();
return share ? share.hasPermission(SharePermission.Write) : true;
}

permitsViewing(): boolean {
const share = this._getShare();
return share ? share.hasPermission(SharePermission.Read) : true;
}

/**
* Clean up all of the data in the vault item
* @protected
Expand All @@ -53,6 +80,37 @@ export default class VaultItem {
this._source = null;
}

_getShare(): Share | null {
const shareID = this.shareID;
return shareID ? this._vault._shares.find(share => share.id === shareID) : null;
}

_requireMgmtPermission() {
if (!this.permitsManagement()) {
throw new Layerr(
{
info: {
code: ErrorCode.NoManagementPermission
}
},
"Management permission not granted for operation"
);
}
}

_requireWritePermission() {
if (!this.permitsModification()) {
throw new Layerr(
{
info: {
code: ErrorCode.NoWritePermission
}
},
"Write permission not granted for operation"
);
}
}

/**
* Update source references
* @protected
Expand Down
5 changes: 5 additions & 0 deletions source/io/VaultFormat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,11 @@ export default class VaultFormat extends EventEmitter {
return "";
}

getItemShareID(itemSource: FormatBGroup | FormatBEntry): ShareID | null {
notImplemented();
return null;
}

getShareID(itemSource: FormatBShare): ShareID {
notImplemented();
return "";
Expand Down
4 changes: 4 additions & 0 deletions source/io/VaultFormatB.ts
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,10 @@ export default class VaultFormatB extends VaultFormat {
return itemSource.g;
}

getItemShareID(itemSource: FormatBGroup | FormatBEntry): ShareID | null {
return itemSource.s ?? null;
}

getShareID(share: FormatBShare): ShareID {
return share.id;
}
Expand Down
5 changes: 5 additions & 0 deletions source/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ export enum EntryType {
Website = "website"
}

export enum ErrorCode {
NoManagementPermission = "perm:no-mgmt",
NoWritePermission = "perm:no-write"
}

export interface FormatAEntry {
id: EntryID;
attributes?: PropertyKeyValueObject;
Expand Down

0 comments on commit 5d4ec96

Please sign in to comment.