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

Flothjl/dwnerror standardization #591

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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