Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

General Data Validation - Boundary IO locations should be doing data validation and marshalling (and the decommissioning of GenericIdTypes for all IDs) #321

Merged
merged 8 commits into from
Feb 7, 2022
73 changes: 37 additions & 36 deletions src/acl/ACL.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
import type { Permission, VaultActions, PermissionIdString } from './types';
import type {
PermissionId,
PermissionIdString,
Permission,
VaultActions,
} from './types';
import type { DB, DBLevel, DBOp } from '@matrixai/db';
import type { NodeId } from '../nodes/types';
import type { GestaltAction } from '../gestalts/types';
import type { VaultAction, VaultId } from '../vaults/types';
import type { Ref } from '../types';

import { Mutex } from 'async-mutex';
import Logger from '@matrixai/logger';
import { IdInternal, utils as idUtils } from '@matrixai/id';
import { IdInternal } from '@matrixai/id';
import {
CreateDestroyStartStop,
ready,
} from '@matrixai/async-init/dist/CreateDestroyStartStop';
import * as aclUtils from './utils';
import * as aclErrors from './errors';
import { makePermissionId } from './utils';

interface ACL extends CreateDestroyStartStop {}
@CreateDestroyStartStop(
Expand Down Expand Up @@ -49,6 +52,7 @@ class ACL {
protected aclNodesDb: DBLevel;
protected aclVaultsDb: DBLevel;
protected lock: Mutex = new Mutex();
protected generatePermId: () => PermissionId;

constructor({ db, logger }: { db: DB; logger: Logger }) {
this.logger = logger;
Expand Down Expand Up @@ -81,6 +85,7 @@ class ACL {
this.aclPermsDb = aclPermsDb;
this.aclNodesDb = aclNodesDb;
this.aclVaultsDb = aclVaultsDb;
this.generatePermId = aclUtils.createPermIdGenerator();
this.logger.info(`Started ${this.constructor.name}`);
}

Expand Down Expand Up @@ -155,9 +160,9 @@ class ACL {
Record<NodeId, Permission>
> = {};
for await (const o of this.aclNodesDb.createReadStream()) {
const nodeId = IdInternal.create<NodeId>((o as any).key);
const nodeId = IdInternal.fromBuffer<NodeId>((o as any).key);
const data = (o as any).value as Buffer;
const permId = makePermissionId(
const permId = IdInternal.fromBuffer<PermissionId>(
await this.db.deserializeDecrypt(data, true),
);
let nodePerm: Record<NodeId, Permission>;
Expand All @@ -174,7 +179,7 @@ class ACL {
} else {
const permRef = (await this.db.get(
this.aclPermsDbDomain,
idUtils.toBuffer(permId),
permId.toBuffer(),
)) as Ref<Permission>;
nodePerm = { [nodeId]: permRef.object };
permIds[permId] = nodePerm;
Expand Down Expand Up @@ -235,7 +240,7 @@ class ACL {
ops.push({
type: 'put',
domain: this.aclVaultsDbDomain,
key: idUtils.toBuffer(vaultId),
key: vaultId.toBuffer(),
value: nodeIds,
});
}
Expand Down Expand Up @@ -281,7 +286,7 @@ class ACL {
return await this._transaction(async () => {
const nodeIds = await this.db.get<Record<NodeId, null>>(
this.aclVaultsDbDomain,
idUtils.toBuffer(vaultId),
vaultId.toBuffer(),
);
if (nodeIds == null) {
return {};
Expand Down Expand Up @@ -316,11 +321,7 @@ class ACL {
for (const nodeId of nodeIdsGc) {
delete nodeIds[nodeId];
}
await this.db.put(
this.aclVaultsDbDomain,
idUtils.toBuffer(vaultId),
nodeIds,
);
await this.db.put(this.aclVaultsDbDomain, vaultId.toBuffer(), nodeIds);
}
return perms;
});
Expand All @@ -339,7 +340,7 @@ class ACL {
);
const ops: Array<DBOp> = [];
if (permId == null) {
const permId = await aclUtils.generatePermId();
const permId = await this.generatePermId();
const permRef = {
count: 1,
object: {
Expand All @@ -353,14 +354,14 @@ class ACL {
{
type: 'put',
domain: this.aclPermsDbDomain,
key: idUtils.toBuffer(permId),
key: permId.toBuffer(),
value: permRef,
},
{
type: 'put',
domain: this.aclNodesDbDomain,
key: nodeId.toBuffer(),
value: idUtils.toBuffer(permId),
value: permId.toBuffer(),
raw: true,
},
);
Expand Down Expand Up @@ -414,7 +415,7 @@ class ACL {
const nodeIds =
(await this.db.get<Record<NodeId, null>>(
this.aclVaultsDbDomain,
idUtils.toBuffer(vaultId),
vaultId.toBuffer(),
)) ?? {};
const permId = await this.db.get(
this.aclNodesDbDomain,
Expand Down Expand Up @@ -452,7 +453,7 @@ class ACL {
{
type: 'put',
domain: this.aclVaultsDbDomain,
key: idUtils.toBuffer(vaultId),
key: vaultId.toBuffer(),
value: nodeIds,
},
];
Expand All @@ -469,7 +470,7 @@ class ACL {
await this._transaction(async () => {
const nodeIds = await this.db.get<Record<NodeId, null>>(
this.aclVaultsDbDomain,
idUtils.toBuffer(vaultId),
vaultId.toBuffer(),
);
if (nodeIds == null || !(nodeId in nodeIds)) {
return;
Expand Down Expand Up @@ -527,48 +528,48 @@ class ACL {
if (permIdBuffer == null) {
continue;
}
const permId = makePermissionId(permIdBuffer);
const permId = IdInternal.fromBuffer<PermissionId>(permIdBuffer);
permIdCounts[permId] = (permIdCounts[permId] ?? 0) + 1;
}
for (const permIdString in permIdCounts) {
const permId = makePermissionId(idUtils.fromString(permIdString));
const permId = IdInternal.fromString<PermissionId>(permIdString);
const permRef = (await this.db.get(
this.aclPermsDbDomain,
idUtils.toBuffer(permId),
permId.toBuffer(),
)) as Ref<Permission>;
permRef.count = permRef.count - permIdCounts[permId];
if (permRef.count === 0) {
ops.push({
type: 'del',
domain: this.aclPermsDbDomain,
key: idUtils.toBuffer(permId),
key: permId.toBuffer(),
});
} else {
ops.push({
type: 'put',
domain: this.aclPermsDbDomain,
key: idUtils.toBuffer(permId),
key: permId.toBuffer(),
value: permRef,
});
}
}
const permId = await aclUtils.generatePermId();
const permId = await this.generatePermId();
const permRef = {
count: nodeIds.length,
object: perm,
};
ops.push({
domain: this.aclPermsDbDomain,
type: 'put',
key: idUtils.toBuffer(permId),
key: permId.toBuffer(),
value: permRef,
});
for (const nodeId of nodeIds) {
ops.push({
domain: this.aclNodesDbDomain,
type: 'put',
key: nodeId.toBuffer(),
value: idUtils.toBuffer(permId),
value: permId.toBuffer(),
raw: true,
});
}
Expand All @@ -595,7 +596,7 @@ class ACL {
);
const ops: Array<DBOp> = [];
if (permId == null) {
const permId = await aclUtils.generatePermId();
const permId = await this.generatePermId();
const permRef = {
count: 1,
object: perm,
Expand All @@ -604,14 +605,14 @@ class ACL {
{
type: 'put',
domain: this.aclPermsDbDomain,
key: idUtils.toBuffer(permId),
key: permId.toBuffer(),
value: permRef,
},
{
type: 'put',
domain: this.aclNodesDbDomain,
key: nodeId.toBuffer(),
value: idUtils.toBuffer(permId),
value: permId.toBuffer(),
raw: true,
},
);
Expand Down Expand Up @@ -685,7 +686,7 @@ class ACL {
await this._transaction(async () => {
const nodeIds = await this.db.get<Record<NodeId, null>>(
this.aclVaultsDbDomain,
idUtils.toBuffer(vaultId),
vaultId.toBuffer(),
);
if (nodeIds == null) {
return;
Expand Down Expand Up @@ -718,7 +719,7 @@ class ACL {
ops.push({
type: 'del',
domain: this.aclVaultsDbDomain,
key: idUtils.toBuffer(vaultId),
key: vaultId.toBuffer(),
});
await this.db.batch(ops);
});
Expand Down Expand Up @@ -825,7 +826,7 @@ class ACL {
): Promise<Array<DBOp>> {
const nodeIds = await this.db.get<Record<NodeId, null>>(
this.aclVaultsDbDomain,
idUtils.toBuffer(vaultId),
vaultId.toBuffer(),
);
if (nodeIds == null) {
throw new aclErrors.ErrorACLVaultIdMissing();
Expand Down Expand Up @@ -869,7 +870,7 @@ class ACL {
ops.push({
type: 'put',
domain: this.aclVaultsDbDomain,
key: idUtils.toBuffer(vaultIdJoin),
key: vaultIdJoin.toBuffer(),
value: nodeIds,
});
}
Expand All @@ -881,7 +882,7 @@ class ACL {
ops.push({
type: 'put',
domain: this.aclVaultsDbDomain,
key: idUtils.toBuffer(vaultId),
key: vaultId.toBuffer(),
value: nodeIds,
});
}
Expand Down
5 changes: 2 additions & 3 deletions src/acl/types.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import type { Opaque } from '../types';
import type { GestaltAction } from '../gestalts/types';
import type { VaultActions, VaultId } from '../vaults/types';
import type { Id, IdString } from '../GenericIdTypes';
import type { Id } from '@matrixai/id';

type PermissionId = Opaque<'PermissionId', Id>;

type PermissionIdString = Opaque<'PermissionIdString', IdString>;
type PermissionIdString = Opaque<'PermissionIdString', string>;

type Permission = {
gestalt: GestaltActions;
Expand Down
35 changes: 5 additions & 30 deletions src/acl/utils.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,9 @@
import type { Permission, PermissionId, PermissionIdString } from './types';

import type { Permission, PermissionId } from './types';
import { IdRandom } from '@matrixai/id';
import { isIdString, isId, makeIdString, makeId } from '../GenericIdTypes';

function isPermissionId(arg: any): arg is PermissionId {
return isId<PermissionId>(arg);
}

function makePermissionId(arg: any) {
return makeId<PermissionId>(arg);
}

function isPermissionIdString(arg: any): arg is PermissionIdString {
return isIdString<PermissionIdString>(arg);
}

function makePermissionIdString(arg: any) {
return makeIdString<PermissionIdString>(arg);
}

const randomIdGenerator = new IdRandom();
async function generatePermId(): Promise<PermissionId> {
return makePermissionId(randomIdGenerator.get());
function createPermIdGenerator() {
const generator = new IdRandom<PermissionId>();
return () => generator.get();
}

function permUnion(perm1: Permission, perm2: Permission): Permission {
Expand All @@ -44,11 +26,4 @@ function permUnion(perm1: Permission, perm2: Permission): Permission {
return perm;
}

export {
generatePermId,
permUnion,
isPermissionId,
makePermissionId,
isPermissionIdString,
makePermissionIdString,
};
export { createPermIdGenerator, permUnion };
14 changes: 8 additions & 6 deletions src/agent/service/nodesChainDataGet.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type * as grpc from '@grpc/grpc-js';
import type { ClaimIdString } from '../../claims/types';
import type { ClaimIdEncoded } from '../../claims/types';
import type { NodeManager } from '../../nodes';
import type * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb';
import { utils as grpcUtils } from '../../grpc';
Expand All @@ -13,12 +13,12 @@ function nodesChainDataGet({ nodeManager }: { nodeManager: NodeManager }) {
call: grpc.ServerUnaryCall<utilsPB.EmptyMessage, nodesPB.ChainData>,
callback: grpc.sendUnaryData<nodesPB.ChainData>,
): Promise<void> => {
const response = new nodesPB.ChainData();
try {
const response = new nodesPB.ChainData();
const chainData = await nodeManager.getChainData();
// Iterate through each claim in the chain, and serialize for transport
for (const c in chainData) {
const claimId = c as ClaimIdString;
const claimId = c as ClaimIdEncoded;
const claim = chainData[claimId];
const claimMessage = new nodesPB.AgentClaim();
// Will always have a payload (never undefined) so cast as string
Expand All @@ -34,10 +34,12 @@ function nodesChainDataGet({ nodeManager }: { nodeManager: NodeManager }) {
// Add the serialized claim
response.getChainDataMap().set(claimId, claimMessage);
}
} catch (err) {
callback(grpcUtils.fromError(err), response);
callback(null, response);
return;
} catch (e) {
callback(grpcUtils.fromError(e));
return;
}
callback(null, response);
};
}

Expand Down
Loading