Skip to content

Commit

Permalink
feat(account): move getPermissions and hasPermissions to Account
Browse files Browse the repository at this point in the history
  • Loading branch information
VictorVicente committed Jul 22, 2021
1 parent 2b098f1 commit fe4eead
Show file tree
Hide file tree
Showing 4 changed files with 332 additions and 343 deletions.
168 changes: 166 additions & 2 deletions src/api/entities/Account.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,35 @@
import BigNumber from 'bignumber.js';
import { TxTag } from 'polymesh-types/types';
import { difference, differenceBy, differenceWith, isEqual, union } from 'lodash';

import { Authorizations, Context, Entity, Identity } from '~/internal';
import { transactions } from '~/middleware/queries';
import { Query, TransactionOrderByInput } from '~/middleware/types';
import {
AccountBalance,
DefaultPortfolio,
Ensured,
ExtrinsicData,
ModuleName,
NumberedPortfolio,
Permissions,
PermissionType,
ResultSet,
SimplePermissions,
SubCallback,
TxTag,
TxTags,
UnsubCallback,
} from '~/types';
import {
addressToKey,
extrinsicIdentifierToTxTag,
identityIdToString,
portfolioToPortfolioId,
signerToString,
stringToAccountId,
txTagToExtrinsicIdentifier,
} from '~/utils/conversion';
import { assertFormatValid, calculateNextKey } from '~/utils/internal';
import { assertFormatValid, calculateNextKey, isModuleOrTagMatch } from '~/utils/internal';

export interface UniqueIdentifiers {
address: string;
Expand Down Expand Up @@ -226,6 +236,160 @@ export class Account extends Entity<UniqueIdentifiers, string> {
return identity.areSecondaryKeysFrozen();
}

/**
* Retrieve the Permissions this Signer has as a Signing Key for its corresponding Identity
*/
public async getPermissions(): Promise<Permissions> {
const { context, address } = this;

const currentIdentity = await context.getCurrentIdentity();

const [primaryKey, secondaryKeys] = await Promise.all([
currentIdentity.getPrimaryKey(),
currentIdentity.getSecondaryKeys(),
]);

if (address === primaryKey) {
return {
tokens: null,
transactions: null,
transactionGroups: [],
portfolios: null,
};
}

// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const key = secondaryKeys.find(({ signer }) => address === signerToString(signer))!;

return key.permissions;
}

/**
* Check if this Account possesses certain Permissions for its corresponding Identity
*/
public async hasPermissions(permissions: SimplePermissions): Promise<boolean> {
const { tokens, transactions, portfolios } = permissions;

const {
tokens: currentTokens,
transactions: currentTransactions,
portfolios: currentPortfolios,
} = await this.getPermissions();

let hasTokens;
if (currentTokens === null) {
hasTokens = true;
} else if (tokens === null) {
hasTokens = false;
} else if (tokens) {
const { type: tokensType, values: tokensValues } = currentTokens;
if (tokens.length === 0) {
hasTokens = true;
} else {
if (tokensType === PermissionType.Include) {
hasTokens = !differenceBy(tokens, tokensValues, 'ticker').length;
} else {
hasTokens = differenceBy(tokens, tokensValues, 'ticker').length === tokens.length;
}
}
} else {
hasTokens = true;
}

// these transactions are allowed to any account, independent of permissions
const exemptedTransactions: (TxTag | ModuleName)[] = [
...difference(Object.values(TxTags.balances), [
TxTags.balances.DepositBlockRewardReserveBalance,
TxTags.balances.BurnAccountBalance,
]),
ModuleName.Staking,
ModuleName.Sudo,
ModuleName.Session,
ModuleName.Authorship,
ModuleName.Babe,
ModuleName.FinalityTracker,
ModuleName.Grandpa,
ModuleName.ImOnline,
ModuleName.Indices,
ModuleName.Scheduler,
ModuleName.System,
ModuleName.Timestamp,
];

let hasTransactions;
if (currentTransactions === null) {
hasTransactions = true;
} else if (transactions === null) {
hasTransactions = false;
} else if (transactions) {
const {
type: transactionsType,
values: transactionsValues,
exceptions = [],
} = currentTransactions;
if (transactions.length === 0) {
hasTransactions = true;
} else {
if (transactionsType === PermissionType.Include) {
const includedTransactions = differenceWith(
union(transactionsValues, exemptedTransactions),
exceptions,
isModuleOrTagMatch
);
hasTransactions = transactions.every(
tag => !!includedTransactions.find(included => isModuleOrTagMatch(included, tag))
);
} else {
const excludedTransactions = differenceWith(
transactionsValues,
exemptedTransactions,
exceptions,
isModuleOrTagMatch
);
hasTransactions = !transactions.some(
tag => !!excludedTransactions.find(excluded => isModuleOrTagMatch(excluded, tag))
);
}
}
} else {
hasTransactions = true;
}

let hasPortfolios;
if (currentPortfolios === null) {
hasPortfolios = true;
} else if (portfolios === null) {
hasPortfolios = false;
} else if (portfolios) {
const { type: portfoliosType, values: portfoliosValues } = currentPortfolios;

if (portfolios.length === 0) {
hasPortfolios = true;
} else {
const portfolioComparator = (
a: DefaultPortfolio | NumberedPortfolio,
b: DefaultPortfolio | NumberedPortfolio
) => {
const aId = portfolioToPortfolioId(a);
const bId = portfolioToPortfolioId(b);

return isEqual(aId, bId);
};
if (portfoliosType === PermissionType.Include) {
hasPortfolios = !differenceWith(portfolios, portfoliosValues, portfolioComparator).length;
} else {
hasPortfolios =
differenceWith(portfolios, portfoliosValues, portfolioComparator).length ===
portfolios.length;
}
}
} else {
hasPortfolios = true;
}

return hasTokens && hasTransactions && hasPortfolios;
}

/**
* Return the Account's address
*/
Expand Down
171 changes: 2 additions & 169 deletions src/api/entities/CurrentAccount.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,7 @@
import { difference, differenceBy, differenceWith, isEqual, union } from 'lodash';

import { UniqueIdentifiers } from '~/api/entities/Account';
import { Account, Context, CurrentIdentity, leaveIdentity } from '~/internal';
import {
DefaultPortfolio,
ModuleName,
NumberedPortfolio,
Permissions,
PermissionType,
ProcedureMethod,
SimplePermissions,
TxTag,
TxTags,
} from '~/types';
import { portfolioToPortfolioId, signerToString } from '~/utils/conversion';
import { createProcedureMethod, isModuleOrTagMatch } from '~/utils/internal';
import { ProcedureMethod } from '~/types';
import { createProcedureMethod } from '~/utils/internal';

/**
* Represents the current account that is bound to the SDK instance
Expand Down Expand Up @@ -45,158 +32,4 @@ export class CurrentAccount extends Account {

return identity && new CurrentIdentity({ did: identity.did }, this.context);
}

/**
* Retrieve the Permissions this Signer has as a Signing Key for its corresponding Identity
*/
public async getPermissions(): Promise<Permissions> {
const { context, address } = this;

const currentIdentity = await context.getCurrentIdentity();

const [primaryKey, secondaryKeys] = await Promise.all([
currentIdentity.getPrimaryKey(),
currentIdentity.getSecondaryKeys(),
]);

if (address === primaryKey) {
return {
tokens: null,
transactions: null,
transactionGroups: [],
portfolios: null,
};
}

// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const key = secondaryKeys.find(({ signer }) => address === signerToString(signer))!;

return key.permissions;
}

/**
* Check if this Account possesses certain Permissions for its corresponding Identity
*/
public async hasPermissions(permissions: SimplePermissions): Promise<boolean> {
const { tokens, transactions, portfolios } = permissions;

const {
tokens: currentTokens,
transactions: currentTransactions,
portfolios: currentPortfolios,
} = await this.getPermissions();

let hasTokens;
if (currentTokens === null) {
hasTokens = true;
} else if (tokens === null) {
hasTokens = false;
} else if (tokens) {
const { type: tokensType, values: tokensValues } = currentTokens;
if (tokens.length === 0) {
hasTokens = true;
} else {
if (tokensType === PermissionType.Include) {
hasTokens = !differenceBy(tokens, tokensValues, 'ticker').length;
} else {
hasTokens = differenceBy(tokens, tokensValues, 'ticker').length === tokens.length;
}
}
} else {
hasTokens = true;
}

// these transactions are allowed to any account, independent of permissions
const exemptedTransactions: (TxTag | ModuleName)[] = [
...difference(Object.values(TxTags.balances), [
TxTags.balances.DepositBlockRewardReserveBalance,
TxTags.balances.BurnAccountBalance,
]),
ModuleName.Staking,
ModuleName.Sudo,
ModuleName.Session,
ModuleName.Authorship,
ModuleName.Babe,
ModuleName.FinalityTracker,
ModuleName.Grandpa,
ModuleName.ImOnline,
ModuleName.Indices,
ModuleName.Scheduler,
ModuleName.System,
ModuleName.Timestamp,
];

let hasTransactions;
if (currentTransactions === null) {
hasTransactions = true;
} else if (transactions === null) {
hasTransactions = false;
} else if (transactions) {
const {
type: transactionsType,
values: transactionsValues,
exceptions = [],
} = currentTransactions;
if (transactions.length === 0) {
hasTransactions = true;
} else {
if (transactionsType === PermissionType.Include) {
const includedTransactions = differenceWith(
union(transactionsValues, exemptedTransactions),
exceptions,
isModuleOrTagMatch
);
hasTransactions = transactions.every(
tag => !!includedTransactions.find(included => isModuleOrTagMatch(included, tag))
);
} else {
const excludedTransactions = differenceWith(
transactionsValues,
exemptedTransactions,
exceptions,
isModuleOrTagMatch
);
hasTransactions = !transactions.some(
tag => !!excludedTransactions.find(excluded => isModuleOrTagMatch(excluded, tag))
);
}
}
} else {
hasTransactions = true;
}

let hasPortfolios;
if (currentPortfolios === null) {
hasPortfolios = true;
} else if (portfolios === null) {
hasPortfolios = false;
} else if (portfolios) {
const { type: portfoliosType, values: portfoliosValues } = currentPortfolios;

if (portfolios.length === 0) {
hasPortfolios = true;
} else {
const portfolioComparator = (
a: DefaultPortfolio | NumberedPortfolio,
b: DefaultPortfolio | NumberedPortfolio
) => {
const aId = portfolioToPortfolioId(a);
const bId = portfolioToPortfolioId(b);

return isEqual(aId, bId);
};
if (portfoliosType === PermissionType.Include) {
hasPortfolios = !differenceWith(portfolios, portfoliosValues, portfolioComparator).length;
} else {
hasPortfolios =
differenceWith(portfolios, portfoliosValues, portfolioComparator).length ===
portfolios.length;
}
}
} else {
hasPortfolios = true;
}

return hasTokens && hasTransactions && hasPortfolios;
}
}

0 comments on commit fe4eead

Please sign in to comment.