Skip to content

Commit

Permalink
#387 - DwnError standardization (#591)
Browse files Browse the repository at this point in the history
* moving from Error to DwnError
  • Loading branch information
flothjl authored Nov 2, 2023
1 parent 24d73fb commit 7d9caec
Show file tree
Hide file tree
Showing 12 changed files with 119 additions and 52 deletions.
9 changes: 6 additions & 3 deletions src/core/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export async function validateMessageSignatureIntegrity(
): Promise<{ descriptorCid: CID, [key: string]: any }> {

if (messageSignature.signatures.length !== 1) {
throw new Error('expected no more than 1 signature for authorization purpose');
throw new DwnError(DwnErrorCode.AuthenticateMoreThanOneAuthoriation, 'expected no more than 1 signature for authorization purpose');
}

// validate payload integrity
Expand All @@ -35,7 +35,10 @@ export async function validateMessageSignatureIntegrity(
const { descriptorCid } = payloadJson;
const expectedDescriptorCid = await Cid.computeCid(messageDescriptor);
if (descriptorCid !== expectedDescriptorCid) {
throw new Error(`provided descriptorCid ${descriptorCid} does not match expected CID ${expectedDescriptorCid}`);
throw new DwnError(
DwnErrorCode.AuthenticateDescriptorCidMismatch,
`provided descriptorCid ${descriptorCid} does not match expected CID ${expectedDescriptorCid}`
);
}

return payloadJson;
Expand Down Expand Up @@ -77,6 +80,6 @@ export async function authorize(tenant: string, incomingMessage: { author: strin
if (incomingMessage.author === tenant) {
return;
} else {
throw new Error('message failed authorization, permission grant check not yet implemented');
throw new DwnError(DwnErrorCode.AuthorizationUnknownAuthor, 'message failed authorization, permission grant check not yet implemented');
}
}
35 changes: 34 additions & 1 deletion src/core/dwn-error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,17 @@ export class DwnError extends Error {
*/
export enum DwnErrorCode {
AuthenticateJwsMissing = 'AuthenticateJwsMissing',
AuthenticateMoreThanOneAuthoriation = 'AuthenticateMoreThanOneAuthoriation',
AuthenticateDescriptorCidMismatch = 'AuthenticateDescriptorCidMismatch',
AuthorizationUnknownAuthor = 'AuthorizationUnknownAuthor',
AuthorizationNotGrantedToAuthor = 'AuthorizationNotGrantedToAuthor',
ComputeCidCodecNotSupported = 'ComputeCidCodecNotSupported',
ComputeCidMultihashNotSupported = 'ComputeCidMultihashNotSupported',
DidMethodNotSupported = 'DidMethodNotSupported',
DidNotString = 'DidNotString',
DidNotValid = 'DidNotValid',
DidResolutionFailed = 'DidResolutionFailed',
Ed25519InvalidJwk = 'Ed25519InvalidJwk',
GeneralJwsVerifierInvalidSignature = 'GeneralJwsVerifierInvalidSignature',
GrantAuthorizationGrantExpired = 'GrantAuthorizationGrantExpired',
GrantAuthorizationGrantMissing = 'GrantAuthorizationGrantMissing',
Expand All @@ -29,6 +35,11 @@ export enum DwnErrorCode {
GrantAuthorizationNotGrantedToAuthor = 'GrantAuthorizationNotGrantedToAuthor',
GrantAuthorizationGrantNotYetActive = 'GrantAuthorizationGrantNotYetActive',
HdKeyDerivationPathInvalid = 'HdKeyDerivationPathInvalid',
JwsVerifySignatureUnsupportedCrv = 'JwsVerifySignatureUnsupportedCrv',
JwsDecodePlainObjectPayloadInvalid = 'JwsDecodePlainObjectPayloadInvalid',
MessageGetInvalidCid = 'MessageGetInvalidCid',
ParseCidCodecNotSupported = 'ParseCidCodecNotSupported',
ParseCidMultihashNotSupported = 'ParseCidMultihashNotSupported',
PermissionsGrantGrantedByMismatch = 'PermissionsGrantGrantedByMismatch',
PermissionsGrantNotADelegatedGrant = 'PermissionsGrantNotADelegatedGrant',
PermissionsGrantScopeContextIdAndProtocolPath = 'PermissionsGrantScopeContextIdAndProtocolPath',
Expand All @@ -51,6 +62,8 @@ export enum DwnErrorCode {
ProtocolAuthorizationMissingRuleSet = 'ProtocolAuthorizationMissingRuleSet',
ProtocolAuthorizationParentlessIncorrectProtocolPath = 'ProtocolAuthorizationParentlessIncorrectProtocolPath',
ProtocolAuthorizationNotARole = 'ProtocolAuthorizationNotARole',
ProtocolAuthorizationParentNotFound = 'ProtocolAuthorizationParentNotFound',
ProtocolAuthorizationProtocolNotFound = 'ProtocolAuthorizationProtocolNotFound',
ProtocolAuthorizationQueryWithoutRole = 'ProtocolAuthorizationQueryWithoutRole',
ProtocolAuthorizationRoleMissingRecipient = 'ProtocolAuthorizationRoleMissingRecipient',
ProtocolsConfigureContextRoleAtProhibitedProtocolPath = 'ProtocolsConfigureContextRoleAtProhibitedProtocolPath',
Expand All @@ -77,11 +90,23 @@ export enum DwnErrorCode {
RecordsProtocolPathDerivationSchemeMissingProtocol = 'RecordsProtocolPathDerivationSchemeMissingProtocol',
RecordsQueryFilterMissingRequiredProperties = 'RecordsQueryFilterMissingRequiredProperties',
RecordsReadReturnedMultiple = 'RecordsReadReturnedMultiple',
RecordsReadAuthorizationFailed = 'RecordsReadAuthorizationFailed',
RecordsSchemasDerivationSchemeMissingSchema = 'RecordsSchemasDerivationSchemeMissingSchema',
RecordsWriteAttestationIntegrityMoreThanOneSignature = 'RecordsWriteAttestationIntegrityMoreThanOneSignature',
RecordsWriteAttestationIntegrityDescriptorCidMismatch = 'RecordsWriteAttestationIntegrityDescriptorCidMismatch',
RecordsWriteAttestationIntegrityInvalidPayloadProperty = 'RecordsWriteAttestationIntegrityInvalidPayloadProperty',
RecordsWriteAuthorizationFailed = 'RecordsWriteAuthorizationFailed',
RecordsWriteCreateMissingSigner = 'RecordsWriteCreateMissingSigner',
RecordsWriteCreateContextIdAndParentIdMutuallyInclusive = 'RecordsWriteCreateContextIdAndParentIdMutuallyInclusive',
RecordsWriteCreateDataAndDataCidMutuallyExclusive = 'RecordsWriteCreateDataAndDataCidMutuallyExclusive',
RecordsWriteCreateDataCidAndDataSizeMutuallyInclusive = 'RecordsWriteCreateDataCidAndDataSizeMutuallyInclusive',
RecordsWriteCreateProtocolAndProtocolPathMutuallyInclusive = 'RecordsWriteCreateProtocolAndProtocolPathMutuallyInclusive',
RecordsWriteDataCidMismatch = 'RecordsWriteDataCidMismatch',
RecordsWriteDataSizeMismatch = 'RecordsWriteDataSizeMismatch',
RecordsWriteGetEntryIdUndefinedAuthor = 'RecordsWriteGetEntryIdUndefinedAuthor',
RecordsWriteGetInitialWriteNotFound = 'RecordsWriteGetInitialWriteNotFound',
RecordsWriteImmutablePropertyChanged = 'RecordsWriteImmutablePropertyChanged',
RecordsWriteMissingAuthorizationSigner = 'RecordsWriteMissingAuthorizationSigner',
RecordsWriteMissingSigner = 'RecordsWriteMissingSigner',
RecordsWriteMissingDataInPrevious = 'RecordsWriteMissingDataInPrevious',
RecordsWriteMissingDataAssociation = 'RecordsWriteMissingDataAssociation',
Expand All @@ -90,13 +115,21 @@ export enum DwnErrorCode {
RecordsWriteMissingSchema = 'RecordsWriteMissingSchema',
RecordsWriteOwnerAndTenantMismatch = 'RecordsWriteOwnerAndTenantMismatch',
RecordsWriteSignAsOwnerUnknownAuthor = 'RecordsWriteSignAsOwnerUnknownAuthor',
RecordsWriteValidateIntegrityAttestationMismatch = 'RecordsWriteValidateIntegrityAttestationMismatch',
RecordsWriteValidateIntegrityContextIdMismatch = 'RecordsWriteValidateIntegrityContextIdMismatch',
RecordsWriteValidateIntegrityContextIdNotInSignerSignaturePayload = 'RecordsWriteValidateIntegrityContextIdNotInSignerSignaturePayload',
RecordsWriteValidateIntegrityDateCreatedMismatch = 'RecordsWriteValidateIntegrityDateCreatedMismatch',
RecordsWriteValidateIntegrityDelegatedGrantAndIdExistenceMismatch = 'RecordsWriteValidateIntegrityDelegatedGrantAndIdExistenceMismatch',
RecordsWriteValidateIntegrityEncryptionCidMismatch = 'RecordsWriteValidateIntegrityEncryptionCidMismatch',
RecordsWriteValidateIntegrityGrantedToAndSignerMismatch = 'RecordsWriteValidateIntegrityGrantedToAndSignerMismatch',
RecordsWriteValidateIntegrityRecordIdUnauthorized = 'RecordsWriteValidateIntegrityRecordIdUnauthorized',
SchemaValidatorSchemaNotFound = 'SchemaValidatorSchemaNotFound',
SchemaValidationFailure = 'SchemaValidationFailure',
Secp256k1KeyNotValid = 'Secp256k1KeyNotValid',
TimestampInvalid = 'TimestampInvalid',
UrlProtocolNotNormalized = 'UrlProtocolNotNormalized',
UrlProtocolNotNormalizable = 'UrlProtocolNotNormalizable',
UrlSchemaNotNormalized = 'UrlSchemaNotNormalized',
UrlSchemaNotNormalizable = 'UrlSchemaNotNormalizable'
UrlSchemaNotNormalizable = 'UrlSchemaNotNormalizable',
VerifierValidPublicKeyNotFound = 'VerifierValidPublicKeyNotFound',
};
17 changes: 10 additions & 7 deletions src/core/protocol-authorization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,10 +256,10 @@ export class ProtocolAuthorization {
method : DwnMethodName.Configure,
protocol : protocolUri
};
const { messages: protocols } = await messageStore.query(tenant, [ query ]);
const { messages: protocols } = await messageStore.query(tenant, [query]);

if (protocols.length === 0) {
throw new Error(`unable to find protocol definition for ${protocolUri}`);
throw new DwnError(DwnErrorCode.ProtocolAuthorizationProtocolNotFound, `unable to find protocol definition for ${protocolUri}`);
}

const protocolMessage = protocols[0] as ProtocolsConfigureMessage;
Expand Down Expand Up @@ -298,12 +298,12 @@ export class ProtocolAuthorization {
contextId,
recordId : currentParentId
};
const { messages: parentMessages } = await messageStore.query(tenant, [ query ]);
const { messages: parentMessages } = await messageStore.query(tenant, [query]);

// We already check the immediate parent in `verifyProtocolPath`, so if it triggers,
// it means a bug that caused an invalid message to be saved to the DWN.
if (parentMessages.length === 0) {
throw new Error(`no parent found with ID ${currentParentId}`);
throw new DwnError(DwnErrorCode.ProtocolAuthorizationParentNotFound, `no parent found with ID ${currentParentId}`);
}

const parent = parentMessages[0] as RecordsWriteMessage;
Expand Down Expand Up @@ -360,7 +360,7 @@ export class ProtocolAuthorization {
contextId,
recordId : parentId
};
const { messages: parentMessages } = await messageStore.query(tenant, [ query ]);
const { messages: parentMessages } = await messageStore.query(tenant, [query]);
const parentProtocolPath = (parentMessages as RecordsWriteMessage[])[0]?.descriptor?.protocolPath;
const actualProtocolPath = `${parentProtocolPath}/${declaredTypeName}`;
if (parentProtocolPath === undefined || actualProtocolPath !== declaredProtocolPath) {
Expand Down Expand Up @@ -503,7 +503,7 @@ export class ProtocolAuthorization {
return [ProtocolAction.Update];
}

// default:
// default:
// not reachable in typescript
}
}
Expand All @@ -526,7 +526,10 @@ export class ProtocolAuthorization {

// We have already checked that the message is not from tenant, owner, or permissionsGrant
if (actionRules === undefined) {
throw new Error(`no action rule defined for ${incomingMessageMethod}, ${author} is unauthorized`);
throw new DwnError(
DwnErrorCode.ProtocolAuthorizationActionNotAllowed,
`no action rule defined for ${incomingMessageMethod}, ${author} is unauthorized`
);
}

const invokedRole = incomingMessage.signaturePayload?.protocolRole;
Expand Down
3 changes: 2 additions & 1 deletion src/did/did-ion-resolver.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { DidMethodResolver, DidResolutionResult } from './did-resolver.js';
import { DwnError, DwnErrorCode } from '../index.js';

import crossFetch from 'cross-fetch';
// supports fetch in: node, browsers, and browser extensions.
Expand Down Expand Up @@ -29,7 +30,7 @@ export class DidIonResolver implements DidMethodResolver {
const response = await fetch(resolutionUrl);

if (response.status !== 200) {
throw new Error(`unable to resolve ${did}, got http status ${response.status}`);
throw new DwnError(DwnErrorCode.DidResolutionFailed, `unable to resolve ${did}, got http status ${response.status}`);
}

const didResolutionResult = await response.json();
Expand Down
5 changes: 3 additions & 2 deletions src/interfaces/messages-get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { MessagesGetDescriptor, MessagesGetMessage } from '../types/message

import { Cid } from '../utils/cid.js';
import { validateMessageSignatureIntegrity } from '../core/auth.js';
import { DwnError, DwnErrorCode } from '../index.js';
import { DwnInterfaceName, DwnMethodName, Message } from '../core/message.js';
import { getCurrentTimeInHighPrecision, validateTimestamp } from '../utils/time.js';

Expand Down Expand Up @@ -43,14 +44,14 @@ export class MessagesGet extends Message<MessagesGetMessage> {
/**
* validates the provided cids
* @param messageCids - the cids in question
* @throws {Error} if an invalid cid is found.
* @throws {DwnError} if an invalid cid is found.
*/
private static validateMessageCids(messageCids: string[]): void {
for (const cid of messageCids) {
try {
Cid.parseCid(cid);
} catch (_) {
throw new Error(`${cid} is not a valid CID`);
throw new DwnError(DwnErrorCode.MessageGetInvalidCid, `${cid} is not a valid CID`);
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/interfaces/records-read.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Records } from '../utils/records.js';
import { RecordsGrantAuthorization } from '../core/records-grant-authorization.js';
import { removeUndefinedProperties } from '../utils/object.js';
import { validateMessageSignatureIntegrity } from '../core/auth.js';
import { DwnError, DwnErrorCode } from '../index.js';
import { DwnInterfaceName, DwnMethodName } from '../core/message.js';
import { getCurrentTimeInHighPrecision, validateTimestamp } from '../utils/time.js';

Expand Down Expand Up @@ -85,7 +86,7 @@ export class RecordsRead extends Message<RecordsReadMessage> {
} else if (descriptor.protocol !== undefined) {
await ProtocolAuthorization.authorizeRead(tenant, this, newestRecordsWrite, messageStore);
} else {
throw new Error('message failed authorization');
throw new DwnError(DwnErrorCode.RecordsReadAuthorizationFailed, 'message failed authorization');
}
}
}
Loading

0 comments on commit 7d9caec

Please sign in to comment.