Add comprehensive installation and setup documentation

- Add GETTING_STARTED.md with quick start guide and development modes
- Add INSTALL.sh automated installation script
- Add INSTALLATION_CHECKLIST.md, INSTALLATION_SUCCESS.md, and INSTALLATION_SUMMARY.md
- Add QUICK_REFERENCE.md for common commands
- Add SETUP_GUIDE.md with detailed setup instructions
- Update README.md with improved project overview
- Add did-wallet app dependencies and node_modules
This commit is contained in:
Dorian
2026-01-27 17:18:21 +00:00
parent a81f655133
commit 0d073fa89e
22658 changed files with 4494151 additions and 6 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
@@ -0,0 +1 @@
{"type": "commonjs"}
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,23 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://identity.foundation/dwn/json-schemas/defs.json",
"type": "object",
"$defs": {
"base64url": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]+$"
},
"uuid": {
"type": "string",
"pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
},
"did": {
"type": "string",
"pattern": "^did:([a-z0-9]+):((?:(?:[a-zA-Z0-9._-]|(?:%[0-9a-fA-F]{2}))*:)*((?:[a-zA-Z0-9._-]|(?:%[0-9a-fA-F]{2}))+))((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\/[^#?]*)?([?][^#]*)?(#.*)?$"
},
"date-time": {
"type": "string",
"pattern": "^\\d{4}-[0-1]\\d-[0-3]\\dT(?:[0-2]\\d:[0-5]\\d:[0-5]\\d|23:59:60)\\.\\d{6}Z$"
}
}
}
@@ -0,0 +1,41 @@
import { Jws } from '../utils/jws.js';
import { Message } from './message.js';
/**
* An abstract implementation of the `MessageInterface` interface.
*/
export class AbstractMessage {
get message() {
return this._message;
}
get signer() {
return this._signer;
}
get author() {
return this._author;
}
get signaturePayload() {
return this._signaturePayload;
}
constructor(message) {
this._message = message;
if (message.authorization !== undefined) {
this._signer = Message.getSigner(message);
// if the message authorization contains author delegated grant, the author would be the grantor of the grant
// else the author would be the signer of the message
if (message.authorization.authorDelegatedGrant !== undefined) {
this._author = Message.getSigner(message.authorization.authorDelegatedGrant);
}
else {
this._author = this._signer;
}
this._signaturePayload = Jws.decodePlainObjectPayload(message.authorization.signature);
}
}
/**
* Called by `JSON.stringify(...)` automatically.
*/
toJSON() {
return this.message;
}
}
//# sourceMappingURL=abstract-message.js.map
@@ -0,0 +1 @@
{"version":3,"file":"abstract-message.js","sourceRoot":"","sources":["../../../../src/core/abstract-message.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC;;GAEG;AACH,MAAM,OAAgB,eAAe;IAEnC,IAAW,OAAO;QAChB,OAAO,IAAI,CAAC,QAAa,CAAC;IAC5B,CAAC;IAGD,IAAW,MAAM;QACf,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAGD,IAAW,MAAM;QACf,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAGD,IAAW,gBAAgB;QACzB,OAAO,IAAI,CAAC,iBAAiB,CAAC;IAChC,CAAC;IAED,YAAsB,OAAU;QAC9B,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;QAExB,IAAI,OAAO,CAAC,aAAa,KAAK,SAAS,EAAE;YACvC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YAE1C,6GAA6G;YAC7G,qDAAqD;YACrD,IAAI,OAAO,CAAC,aAAa,CAAC,oBAAoB,KAAK,SAAS,EAAE;gBAC5D,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,aAAa,CAAC,oBAAoB,CAAC,CAAC;aAC9E;iBAAM;gBACL,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;aAC7B;YAED,IAAI,CAAC,iBAAiB,GAAG,GAAG,CAAC,wBAAwB,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;SACxF;IACH,CAAC;IAED;;OAEG;IACH,MAAM;QACJ,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;CACF"}
@@ -0,0 +1,54 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { GeneralJwsVerifier } from '../jose/jws/general/verifier.js';
import { RecordsWrite } from '../interfaces/records-write.js';
import { DwnError, DwnErrorCode } from './dwn-error.js';
/**
* Verifies all the signature(s) within the authorization property.
*
* @throws {Error} if fails authentication
*/
export function authenticate(authorizationModel, didResolver) {
return __awaiter(this, void 0, void 0, function* () {
if (authorizationModel === undefined) {
throw new DwnError(DwnErrorCode.AuthenticateJwsMissing, 'Missing JWS.');
}
yield GeneralJwsVerifier.verifySignatures(authorizationModel.signature, didResolver);
if (authorizationModel.ownerSignature !== undefined) {
yield GeneralJwsVerifier.verifySignatures(authorizationModel.ownerSignature, didResolver);
}
if (authorizationModel.authorDelegatedGrant !== undefined) {
// verify the signature of the grantor of the author-delegated grant
const authorDelegatedGrant = yield RecordsWrite.parse(authorizationModel.authorDelegatedGrant);
yield GeneralJwsVerifier.verifySignatures(authorDelegatedGrant.message.authorization.signature, didResolver);
}
if (authorizationModel.ownerDelegatedGrant !== undefined) {
// verify the signature of the grantor of the owner-delegated grant
const ownerDelegatedGrant = yield RecordsWrite.parse(authorizationModel.ownerDelegatedGrant);
yield GeneralJwsVerifier.verifySignatures(ownerDelegatedGrant.message.authorization.signature, didResolver);
}
});
}
/**
* Authorizes owner authored message.
* @throws {DwnError} if fails authorization.
*/
export function authorizeOwner(tenant, incomingMessage) {
return __awaiter(this, void 0, void 0, function* () {
// if author is the same as the target tenant, we can directly grant access
if (incomingMessage.author === tenant) {
return;
}
else {
throw new DwnError(DwnErrorCode.AuthorizationAuthorNotOwner, `Message authored by ${incomingMessage.author}, not authored by expected owner ${tenant}.`);
}
});
}
//# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../../src/core/auth.ts"],"names":[],"mappings":";;;;;;;;;AAIA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAExD;;;;GAIG;AACH,MAAM,UAAgB,YAAY,CAAC,kBAAkD,EAAE,WAAwB;;QAE7G,IAAI,kBAAkB,KAAK,SAAS,EAAE;YACpC,MAAM,IAAI,QAAQ,CAAC,YAAY,CAAC,sBAAsB,EAAE,cAAc,CAAC,CAAC;SACzE;QAED,MAAM,kBAAkB,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QAErF,IAAI,kBAAkB,CAAC,cAAc,KAAK,SAAS,EAAE;YACnD,MAAM,kBAAkB,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;SAC3F;QAED,IAAI,kBAAkB,CAAC,oBAAoB,KAAK,SAAS,EAAE;YACzD,oEAAoE;YACpE,MAAM,oBAAoB,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,kBAAkB,CAAC,oBAAoB,CAAC,CAAC;YAC/F,MAAM,kBAAkB,CAAC,gBAAgB,CAAC,oBAAoB,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;SAC9G;QAED,IAAI,kBAAkB,CAAC,mBAAmB,KAAK,SAAS,EAAE;YACxD,mEAAmE;YACnE,MAAM,mBAAmB,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,kBAAkB,CAAC,mBAAmB,CAAC,CAAC;YAC7F,MAAM,kBAAkB,CAAC,gBAAgB,CAAC,mBAAmB,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;SAC7G;IACH,CAAC;CAAA;AAED;;;GAGG;AACH,MAAM,UAAgB,cAAc,CAAC,MAAc,EAAE,eAAiD;;QACpG,2EAA2E;QAC3E,IAAI,eAAe,CAAC,MAAM,KAAK,MAAM,EAAE;YACrC,OAAO;SACR;aAAM;YACL,MAAM,IAAI,QAAQ,CAChB,YAAY,CAAC,2BAA2B,EACxC,uBAAuB,eAAe,CAAC,MAAM,oCAAoC,MAAM,GAAG,CAC3F,CAAC;SACH;IACH,CAAC;CAAA"}
@@ -0,0 +1,10 @@
export class DwnConstant {
}
/**
* The maximum size of raw data that will be returned as `encodedData`.
*
* We chose 30k, as after encoding it would give plenty of headroom up to the 65k limit in most SQL variants.
* We currently encode using base64url which is a 33% increase in size.
*/
DwnConstant.maxDataSizeAllowedToBeEncoded = 30000;
//# sourceMappingURL=dwn-constant.js.map
@@ -0,0 +1 @@
{"version":3,"file":"dwn-constant.js","sourceRoot":"","sources":["../../../../src/core/dwn-constant.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,WAAW;;AACtB;;;;;GAKG;AACoB,yCAA6B,GAAG,KAAM,CAAC"}
@@ -0,0 +1,164 @@
/**
* A class that represents a DWN error.
*/
export class DwnError extends Error {
constructor(code, message) {
super(`${code}: ${message}`);
this.code = code;
this.name = 'DwnError';
}
}
/**
* DWN SDK error codes.
*/
export var DwnErrorCode;
(function (DwnErrorCode) {
DwnErrorCode["AuthenticateJwsMissing"] = "AuthenticateJwsMissing";
DwnErrorCode["AuthenticateDescriptorCidMismatch"] = "AuthenticateDescriptorCidMismatch";
DwnErrorCode["AuthenticationMoreThanOneSignatureNotSupported"] = "AuthenticationMoreThanOneSignatureNotSupported";
DwnErrorCode["AuthorizationAuthorNotOwner"] = "AuthorizationAuthorNotOwner";
DwnErrorCode["AuthorizationNotGrantedToAuthor"] = "AuthorizationNotGrantedToAuthor";
DwnErrorCode["ComputeCidCodecNotSupported"] = "ComputeCidCodecNotSupported";
DwnErrorCode["ComputeCidMultihashNotSupported"] = "ComputeCidMultihashNotSupported";
DwnErrorCode["DidMethodNotSupported"] = "DidMethodNotSupported";
DwnErrorCode["DidNotString"] = "DidNotString";
DwnErrorCode["DidNotValid"] = "DidNotValid";
DwnErrorCode["DidResolutionFailed"] = "DidResolutionFailed";
DwnErrorCode["Ed25519InvalidJwk"] = "Ed25519InvalidJwk";
DwnErrorCode["EventEmitterStreamNotOpenError"] = "EventEmitterStreamNotOpenError";
DwnErrorCode["EventsSubscribeEventStreamUnimplemented"] = "EventsSubscribeEventStreamUnimplemented";
DwnErrorCode["GeneralJwsVerifierGetPublicKeyNotFound"] = "GeneralJwsVerifierGetPublicKeyNotFound";
DwnErrorCode["GeneralJwsVerifierInvalidSignature"] = "GeneralJwsVerifierInvalidSignature";
DwnErrorCode["GrantAuthorizationGrantExpired"] = "GrantAuthorizationGrantExpired";
DwnErrorCode["GrantAuthorizationGrantMissing"] = "GrantAuthorizationGrantMissing";
DwnErrorCode["GrantAuthorizationGrantRevoked"] = "GrantAuthorizationGrantRevoked";
DwnErrorCode["GrantAuthorizationInterfaceMismatch"] = "GrantAuthorizationInterfaceMismatch";
DwnErrorCode["GrantAuthorizationMethodMismatch"] = "GrantAuthorizationMethodMismatch";
DwnErrorCode["GrantAuthorizationNotGrantedForTenant"] = "GrantAuthorizationNotGrantedForTenant";
DwnErrorCode["GrantAuthorizationNotGrantedToAuthor"] = "GrantAuthorizationNotGrantedToAuthor";
DwnErrorCode["GrantAuthorizationGrantNotYetActive"] = "GrantAuthorizationGrantNotYetActive";
DwnErrorCode["HdKeyDerivationPathInvalid"] = "HdKeyDerivationPathInvalid";
DwnErrorCode["JwsVerifySignatureUnsupportedCrv"] = "JwsVerifySignatureUnsupportedCrv";
DwnErrorCode["IndexInvalidCursorValueType"] = "IndexInvalidCursorValueType";
DwnErrorCode["IndexInvalidCursorSortProperty"] = "IndexInvalidCursorSortProperty";
DwnErrorCode["IndexInvalidSortPropertyInMemory"] = "IndexInvalidSortPropertyInMemory";
DwnErrorCode["IndexMissingIndexableProperty"] = "IndexMissingIndexableProperty";
DwnErrorCode["JwsDecodePlainObjectPayloadInvalid"] = "JwsDecodePlainObjectPayloadInvalid";
DwnErrorCode["MessageGetInvalidCid"] = "MessageGetInvalidCid";
DwnErrorCode["ParseCidCodecNotSupported"] = "ParseCidCodecNotSupported";
DwnErrorCode["ParseCidMultihashNotSupported"] = "ParseCidMultihashNotSupported";
DwnErrorCode["PermissionsProtocolValidateSchemaUnexpectedRecord"] = "PermissionsProtocolValidateSchemaUnexpectedRecord";
DwnErrorCode["PermissionsProtocolValidateScopeContextIdProhibitedProperties"] = "PermissionsProtocolValidateScopeContextIdProhibitedProperties";
DwnErrorCode["PermissionsProtocolValidateScopeSchemaProhibitedProperties"] = "PermissionsProtocolValidateScopeSchemaProhibitedProperties";
DwnErrorCode["PrivateKeySignerUnableToDeduceAlgorithm"] = "PrivateKeySignerUnableToDeduceAlgorithm";
DwnErrorCode["PrivateKeySignerUnableToDeduceKeyId"] = "PrivateKeySignerUnableToDeduceKeyId";
DwnErrorCode["PrivateKeySignerUnsupportedCurve"] = "PrivateKeySignerUnsupportedCurve";
DwnErrorCode["ProtocolAuthorizationActionNotAllowed"] = "ProtocolAuthorizationActionNotAllowed";
DwnErrorCode["ProtocolAuthorizationActionRulesNotFound"] = "ProtocolAuthorizationActionRulesNotFound";
DwnErrorCode["ProtocolAuthorizationIncorrectDataFormat"] = "ProtocolAuthorizationIncorrectDataFormat";
DwnErrorCode["ProtocolAuthorizationIncorrectContextId"] = "ProtocolAuthorizationIncorrectContextId";
DwnErrorCode["ProtocolAuthorizationIncorrectProtocolPath"] = "ProtocolAuthorizationIncorrectProtocolPath";
DwnErrorCode["ProtocolAuthorizationDuplicateRoleRecipient"] = "ProtocolAuthorizationDuplicateRoleRecipient";
DwnErrorCode["ProtocolAuthorizationInvalidSchema"] = "ProtocolAuthorizationInvalidSchema";
DwnErrorCode["ProtocolAuthorizationInvalidType"] = "ProtocolAuthorizationInvalidType";
DwnErrorCode["ProtocolAuthorizationMatchingRoleRecordNotFound"] = "ProtocolAuthorizationMatchingRoleRecordNotFound";
DwnErrorCode["ProtocolAuthorizationMaxSizeInvalid"] = "ProtocolAuthorizationMaxSizeInvalid";
DwnErrorCode["ProtocolAuthorizationMinSizeInvalid"] = "ProtocolAuthorizationMinSizeInvalid";
DwnErrorCode["ProtocolAuthorizationMissingContextId"] = "ProtocolAuthorizationMissingContextId";
DwnErrorCode["ProtocolAuthorizationMissingRuleSet"] = "ProtocolAuthorizationMissingRuleSet";
DwnErrorCode["ProtocolAuthorizationParentlessIncorrectProtocolPath"] = "ProtocolAuthorizationParentlessIncorrectProtocolPath";
DwnErrorCode["ProtocolAuthorizationNotARole"] = "ProtocolAuthorizationNotARole";
DwnErrorCode["ProtocolAuthorizationParentNotFoundConstructingRecordChain"] = "ProtocolAuthorizationParentNotFoundConstructingRecordChain";
DwnErrorCode["ProtocolAuthorizationProtocolNotFound"] = "ProtocolAuthorizationProtocolNotFound";
DwnErrorCode["ProtocolAuthorizationQueryWithoutRole"] = "ProtocolAuthorizationQueryWithoutRole";
DwnErrorCode["ProtocolAuthorizationRoleMissingRecipient"] = "ProtocolAuthorizationRoleMissingRecipient";
DwnErrorCode["ProtocolAuthorizationTagsInvalidSchema"] = "ProtocolAuthorizationTagsInvalidSchema";
DwnErrorCode["ProtocolsConfigureDuplicateActorInRuleSet"] = "ProtocolsConfigureDuplicateActorInRuleSet";
DwnErrorCode["ProtocolsConfigureDuplicateRoleInRuleSet"] = "ProtocolsConfigureDuplicateRoleInRuleSet";
DwnErrorCode["ProtocolsConfigureInvalidSize"] = "ProtocolsConfigureInvalidSize";
DwnErrorCode["ProtocolsConfigureInvalidActionMissingOf"] = "ProtocolsConfigureInvalidActionMissingOf";
DwnErrorCode["ProtocolsConfigureInvalidActionOfNotAllowed"] = "ProtocolsConfigureInvalidActionOfNotAllowed";
DwnErrorCode["ProtocolsConfigureInvalidActionDeleteWithoutCreate"] = "ProtocolsConfigureInvalidActionDeleteWithoutCreate";
DwnErrorCode["ProtocolsConfigureInvalidActionUpdateWithoutCreate"] = "ProtocolsConfigureInvalidActionUpdateWithoutCreate";
DwnErrorCode["ProtocolsConfigureInvalidRecipientOfAction"] = "ProtocolsConfigureInvalidRecipientOfAction";
DwnErrorCode["ProtocolsConfigureInvalidRuleSetRecordType"] = "ProtocolsConfigureInvalidRuleSetRecordType";
DwnErrorCode["ProtocolsConfigureInvalidTagSchema"] = "ProtocolsConfigureInvalidTagSchema";
DwnErrorCode["ProtocolsConfigureQueryNotAllowed"] = "ProtocolsConfigureQueryNotAllowed";
DwnErrorCode["ProtocolsConfigureRecordNestingDepthExceeded"] = "ProtocolsConfigureRecordNestingDepthExceeded";
DwnErrorCode["ProtocolsConfigureRoleDoesNotExistAtGivenPath"] = "ProtocolsConfigureRoleDoesNotExistAtGivenPath";
DwnErrorCode["ProtocolsConfigureUnauthorized"] = "ProtocolsConfigureUnauthorized";
DwnErrorCode["ProtocolsQueryUnauthorized"] = "ProtocolsQueryUnauthorized";
DwnErrorCode["RecordsAuthorDelegatedGrantAndIdExistenceMismatch"] = "RecordsAuthorDelegatedGrantAndIdExistenceMismatch";
DwnErrorCode["RecordsAuthorDelegatedGrantCidMismatch"] = "RecordsAuthorDelegatedGrantCidMismatch";
DwnErrorCode["RecordsAuthorDelegatedGrantGrantedToAndOwnerSignatureMismatch"] = "RecordsAuthorDelegatedGrantGrantedToAndOwnerSignatureMismatch";
DwnErrorCode["RecordsAuthorDelegatedGrantNotADelegatedGrant"] = "RecordsAuthorDelegatedGrantNotADelegatedGrant";
DwnErrorCode["RecordsDecryptNoMatchingKeyEncryptedFound"] = "RecordsDecryptNoMatchingKeyEncryptedFound";
DwnErrorCode["RecordsDeleteAuthorizationFailed"] = "RecordsDeleteAuthorizationFailed";
DwnErrorCode["RecordsQueryCreateFilterPublishedSortInvalid"] = "RecordsQueryCreateFilterPublishedSortInvalid";
DwnErrorCode["RecordsQueryParseFilterPublishedSortInvalid"] = "RecordsQueryParseFilterPublishedSortInvalid";
DwnErrorCode["RecordsGrantAuthorizationConditionPublicationProhibited"] = "RecordsGrantAuthorizationConditionPublicationProhibited";
DwnErrorCode["RecordsGrantAuthorizationConditionPublicationRequired"] = "RecordsGrantAuthorizationConditionPublicationRequired";
DwnErrorCode["RecordsGrantAuthorizationDeleteProtocolScopeMismatch"] = "RecordsGrantAuthorizationDeleteProtocolScopeMismatch";
DwnErrorCode["RecordsGrantAuthorizationQueryOrSubscribeProtocolScopeMismatch"] = "RecordsGrantAuthorizationQueryOrSubscribeProtocolScopeMismatch";
DwnErrorCode["RecordsGrantAuthorizationScopeContextIdMismatch"] = "RecordsGrantAuthorizationScopeContextIdMismatch";
DwnErrorCode["RecordsGrantAuthorizationScopeMissingProtocol"] = "RecordsGrantAuthorizationScopeMissingProtocol";
DwnErrorCode["RecordsGrantAuthorizationScopeNotRecords"] = "RecordsGrantAuthorizationScopeNotRecords";
DwnErrorCode["RecordsGrantAuthorizationScopeProtocolMismatch"] = "RecordsGrantAuthorizationScopeProtocolMismatch";
DwnErrorCode["RecordsGrantAuthorizationScopeProtocolPathMismatch"] = "RecordsGrantAuthorizationScopeProtocolPathMismatch";
DwnErrorCode["RecordsGrantAuthorizationScopeSchema"] = "RecordsGrantAuthorizationScopeSchema";
DwnErrorCode["RecordsDerivePrivateKeyUnSupportedCurve"] = "RecordsDerivePrivateKeyUnSupportedCurve";
DwnErrorCode["RecordsInvalidAncestorKeyDerivationSegment"] = "RecordsInvalidAncestorKeyDerivationSegment";
DwnErrorCode["RecordsOwnerDelegatedGrantAndIdExistenceMismatch"] = "RecordsOwnerDelegatedGrantAndIdExistenceMismatch";
DwnErrorCode["RecordsOwnerDelegatedGrantCidMismatch"] = "RecordsOwnerDelegatedGrantCidMismatch";
DwnErrorCode["RecordsOwnerDelegatedGrantGrantedToAndOwnerSignatureMismatch"] = "RecordsOwnerDelegatedGrantGrantedToAndOwnerSignatureMismatch";
DwnErrorCode["RecordsOwnerDelegatedGrantNotADelegatedGrant"] = "RecordsOwnerDelegatedGrantNotADelegatedGrant";
DwnErrorCode["RecordsProtocolContextDerivationSchemeMissingContextId"] = "RecordsProtocolContextDerivationSchemeMissingContextId";
DwnErrorCode["RecordsProtocolPathDerivationSchemeMissingProtocol"] = "RecordsProtocolPathDerivationSchemeMissingProtocol";
DwnErrorCode["RecordsQueryFilterMissingRequiredProperties"] = "RecordsQueryFilterMissingRequiredProperties";
DwnErrorCode["RecordsReadReturnedMultiple"] = "RecordsReadReturnedMultiple";
DwnErrorCode["RecordsReadAuthorizationFailed"] = "RecordsReadAuthorizationFailed";
DwnErrorCode["RecordsSubscribeEventStreamUnimplemented"] = "RecordsSubscribeEventStreamUnimplemented";
DwnErrorCode["RecordsSubscribeFilterMissingRequiredProperties"] = "RecordsSubscribeFilterMissingRequiredProperties";
DwnErrorCode["RecordsSchemasDerivationSchemeMissingSchema"] = "RecordsSchemasDerivationSchemeMissingSchema";
DwnErrorCode["RecordsWriteAttestationIntegrityMoreThanOneSignature"] = "RecordsWriteAttestationIntegrityMoreThanOneSignature";
DwnErrorCode["RecordsWriteAttestationIntegrityDescriptorCidMismatch"] = "RecordsWriteAttestationIntegrityDescriptorCidMismatch";
DwnErrorCode["RecordsWriteAttestationIntegrityInvalidPayloadProperty"] = "RecordsWriteAttestationIntegrityInvalidPayloadProperty";
DwnErrorCode["RecordsWriteAuthorizationFailed"] = "RecordsWriteAuthorizationFailed";
DwnErrorCode["RecordsWriteCreateMissingSigner"] = "RecordsWriteCreateMissingSigner";
DwnErrorCode["RecordsWriteCreateDataAndDataCidMutuallyExclusive"] = "RecordsWriteCreateDataAndDataCidMutuallyExclusive";
DwnErrorCode["RecordsWriteCreateDataCidAndDataSizeMutuallyInclusive"] = "RecordsWriteCreateDataCidAndDataSizeMutuallyInclusive";
DwnErrorCode["RecordsWriteCreateProtocolAndProtocolPathMutuallyInclusive"] = "RecordsWriteCreateProtocolAndProtocolPathMutuallyInclusive";
DwnErrorCode["RecordsWriteDataCidMismatch"] = "RecordsWriteDataCidMismatch";
DwnErrorCode["RecordsWriteDataSizeMismatch"] = "RecordsWriteDataSizeMismatch";
DwnErrorCode["RecordsWriteGetEntryIdUndefinedAuthor"] = "RecordsWriteGetEntryIdUndefinedAuthor";
DwnErrorCode["RecordsWriteGetInitialWriteNotFound"] = "RecordsWriteGetInitialWriteNotFound";
DwnErrorCode["RecordsWriteImmutablePropertyChanged"] = "RecordsWriteImmutablePropertyChanged";
DwnErrorCode["RecordsWriteMissingSigner"] = "RecordsWriteMissingSigner";
DwnErrorCode["RecordsWriteMissingDataInPrevious"] = "RecordsWriteMissingDataInPrevious";
DwnErrorCode["RecordsWriteMissingEncodedDataInPrevious"] = "RecordsWriteMissingEncodedDataInPrevious";
DwnErrorCode["RecordsWriteMissingDataStream"] = "RecordsWriteMissingDataStream";
DwnErrorCode["RecordsWriteMissingProtocol"] = "RecordsWriteMissingProtocol";
DwnErrorCode["RecordsWriteMissingSchema"] = "RecordsWriteMissingSchema";
DwnErrorCode["RecordsWriteOwnerAndTenantMismatch"] = "RecordsWriteOwnerAndTenantMismatch";
DwnErrorCode["RecordsWriteSignAsOwnerDelegateUnknownAuthor"] = "RecordsWriteSignAsOwnerDelegateUnknownAuthor";
DwnErrorCode["RecordsWriteSignAsOwnerUnknownAuthor"] = "RecordsWriteSignAsOwnerUnknownAuthor";
DwnErrorCode["RecordsWriteValidateIntegrityAttestationMismatch"] = "RecordsWriteValidateIntegrityAttestationMismatch";
DwnErrorCode["RecordsWriteValidateIntegrityContextIdMismatch"] = "RecordsWriteValidateIntegrityContextIdMismatch";
DwnErrorCode["RecordsWriteValidateIntegrityContextIdNotInSignerSignaturePayload"] = "RecordsWriteValidateIntegrityContextIdNotInSignerSignaturePayload";
DwnErrorCode["RecordsWriteValidateIntegrityDateCreatedMismatch"] = "RecordsWriteValidateIntegrityDateCreatedMismatch";
DwnErrorCode["RecordsWriteValidateIntegrityEncryptionCidMismatch"] = "RecordsWriteValidateIntegrityEncryptionCidMismatch";
DwnErrorCode["RecordsWriteValidateIntegrityRecordIdUnauthorized"] = "RecordsWriteValidateIntegrityRecordIdUnauthorized";
DwnErrorCode["SchemaValidatorAdditionalPropertyNotAllowed"] = "SchemaValidatorAdditionalPropertyNotAllowed";
DwnErrorCode["SchemaValidatorFailure"] = "SchemaValidatorFailure";
DwnErrorCode["SchemaValidatorSchemaNotFound"] = "SchemaValidatorSchemaNotFound";
DwnErrorCode["SchemaValidatorUnevaluatedPropertyNotAllowed"] = "SchemaValidatorUnevaluatedPropertyNotAllowed";
DwnErrorCode["Secp256k1KeyNotValid"] = "Secp256k1KeyNotValid";
DwnErrorCode["Secp256r1KeyNotValid"] = "Secp256r1KeyNotValid";
DwnErrorCode["TimestampInvalid"] = "TimestampInvalid";
DwnErrorCode["UrlProtocolNotNormalized"] = "UrlProtocolNotNormalized";
DwnErrorCode["UrlProtocolNotNormalizable"] = "UrlProtocolNotNormalizable";
DwnErrorCode["UrlSchemaNotNormalized"] = "UrlSchemaNotNormalized";
DwnErrorCode["UrlSchemaNotNormalizable"] = "UrlSchemaNotNormalizable";
})(DwnErrorCode || (DwnErrorCode = {}));
;
//# sourceMappingURL=dwn-error.js.map
@@ -0,0 +1 @@
{"version":3,"file":"dwn-error.js","sourceRoot":"","sources":["../../../../src/core/dwn-error.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,97 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Message } from './message.js';
import { DwnError, DwnErrorCode } from './dwn-error.js';
export class GrantAuthorization {
/**
* Performs base permissions-grant-based authorization against the given message:
* 1. Validates the `expectedGrantor` and `expectedGrantee` values against the actual values in given permission grant.
* 2. Verifies that the incoming message is within the allowed time frame of the grant, and the grant has not been revoked.
* 3. Verifies that the `interface` and `method` grant scopes match the incoming message.
*
* NOTE: Does not validate grant `conditions` or `scope` beyond `interface` and `method`
*
* @param messageStore Used to check if the grant has been revoked.
* @throws {DwnError} if validation fails
*/
static performBaseValidation(input) {
return __awaiter(this, void 0, void 0, function* () {
const { incomingMessage, expectedGrantor, expectedGrantee, permissionGrant, messageStore } = input;
const incomingMessageDescriptor = incomingMessage.descriptor;
GrantAuthorization.verifyExpectedGrantorAndGrantee(expectedGrantor, expectedGrantee, permissionGrant);
// verify that grant is active during incomingMessage's timestamp
const grantedFor = expectedGrantor; // renaming for better readability now that we have verified the grantor above
yield GrantAuthorization.verifyGrantActive(grantedFor, incomingMessageDescriptor.messageTimestamp, permissionGrant, messageStore);
// Check grant scope for interface and method
yield GrantAuthorization.verifyGrantScopeInterfaceAndMethod(incomingMessageDescriptor.interface, incomingMessageDescriptor.method, permissionGrant);
});
}
/**
* Verifies the given `expectedGrantor` and `expectedGrantee` values against
* the actual signer and recipient in given permission grant.
* @throws {DwnError} if `expectedGrantor` or `expectedGrantee` do not match the actual values in the grant.
*/
static verifyExpectedGrantorAndGrantee(expectedGrantor, expectedGrantee, permissionGrant) {
const actualGrantee = permissionGrant.grantee;
if (expectedGrantee !== actualGrantee) {
throw new DwnError(DwnErrorCode.GrantAuthorizationNotGrantedToAuthor, `Permission grant is granted to ${actualGrantee}, but need to be granted to ${expectedGrantee}`);
}
const actualGrantor = permissionGrant.grantor;
if (expectedGrantor !== actualGrantor) {
throw new DwnError(DwnErrorCode.GrantAuthorizationNotGrantedForTenant, `Permission grant is granted by ${actualGrantor}, but need to be granted by ${expectedGrantor}`);
}
}
/**
* Verify that the incoming message is within the allowed time frame of the grant,
* and the grant has not been revoked.
* @param messageStore Used to check if the grant has been revoked.
* @throws {DwnError} if incomingMessage has timestamp for a time in which the grant is not active.
*/
static verifyGrantActive(grantedFor, incomingMessageTimestamp, permissionGrant, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
// Check that incomingMessage is within the grant's time frame
if (incomingMessageTimestamp < permissionGrant.dateGranted) {
// grant is not yet active
throw new DwnError(DwnErrorCode.GrantAuthorizationGrantNotYetActive, `The message has a timestamp before the associated permission grant becomes active`);
}
if (incomingMessageTimestamp >= permissionGrant.dateExpires) {
// grant has expired
throw new DwnError(DwnErrorCode.GrantAuthorizationGrantExpired, `The message has timestamp after the expiry of the associated permission grant`);
}
// Check if grant has been revoked
const query = {
parentId: permissionGrant.id,
protocolPath: `grant/revocation`,
isLatestBaseState: true
};
const { messages: revokes } = yield messageStore.query(grantedFor, [query]);
const oldestExistingRevoke = yield Message.getOldestMessage(revokes);
if (oldestExistingRevoke !== undefined && oldestExistingRevoke.descriptor.messageTimestamp <= incomingMessageTimestamp) {
throw new DwnError(DwnErrorCode.GrantAuthorizationGrantRevoked, `Permission grant with CID ${permissionGrant.id} has been revoked`);
}
});
}
/**
* Verify that the `interface` and `method` grant scopes match the incoming message
* @param permissionGrantId Purely being passed for logging purposes.
* @throws {DwnError} if the `interface` and `method` of the incoming message do not match the scope of the permission grant.
*/
static verifyGrantScopeInterfaceAndMethod(dwnInterface, dwnMethod, permissionGrant) {
return __awaiter(this, void 0, void 0, function* () {
if (dwnInterface !== permissionGrant.scope.interface) {
throw new DwnError(DwnErrorCode.GrantAuthorizationInterfaceMismatch, `DWN Interface of incoming message is outside the scope of permission grant with ID ${permissionGrant.id}`);
}
else if (dwnMethod !== permissionGrant.scope.method) {
throw new DwnError(DwnErrorCode.GrantAuthorizationMethodMismatch, `DWN Method of incoming message is outside the scope of permission grant with ID ${permissionGrant.id}`);
}
});
}
}
//# sourceMappingURL=grant-authorization.js.map
@@ -0,0 +1 @@
{"version":3,"file":"grant-authorization.js","sourceRoot":"","sources":["../../../../src/core/grant-authorization.ts"],"names":[],"mappings":";;;;;;;;;AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAExD,MAAM,OAAO,kBAAkB;IAE7B;;;;;;;;;;OAUG;IACI,MAAM,CAAO,qBAAqB,CAAC,KAMvC;;YACD,MAAM,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,EAAE,YAAY,EAAE,GAAG,KAAK,CAAC;YAEnG,MAAM,yBAAyB,GAAG,eAAe,CAAC,UAAU,CAAC;YAE7D,kBAAkB,CAAC,+BAA+B,CAAC,eAAe,EAAE,eAAe,EAAE,eAAe,CAAC,CAAC;YAEtG,iEAAiE;YACjE,MAAM,UAAU,GAAG,eAAe,CAAC,CAAC,8EAA8E;YAClH,MAAM,kBAAkB,CAAC,iBAAiB,CACxC,UAAU,EACV,yBAAyB,CAAC,gBAAgB,EAC1C,eAAe,EACf,YAAY,CACb,CAAC;YAEF,6CAA6C;YAC7C,MAAM,kBAAkB,CAAC,kCAAkC,CACzD,yBAAyB,CAAC,SAAS,EACnC,yBAAyB,CAAC,MAAM,EAChC,eAAe,CAChB,CAAC;QACJ,CAAC;KAAA;IAED;;;;OAIG;IACK,MAAM,CAAC,+BAA+B,CAC5C,eAAuB,EACvB,eAAuB,EACvB,eAAgC;QAGhC,MAAM,aAAa,GAAG,eAAe,CAAC,OAAO,CAAC;QAC9C,IAAI,eAAe,KAAK,aAAa,EAAE;YACrC,MAAM,IAAI,QAAQ,CAChB,YAAY,CAAC,oCAAoC,EACjD,kCAAkC,aAAa,+BAA+B,eAAe,EAAE,CAChG,CAAC;SACH;QAED,MAAM,aAAa,GAAG,eAAe,CAAC,OAAO,CAAC;QAC9C,IAAI,eAAe,KAAK,aAAa,EAAE;YACrC,MAAM,IAAI,QAAQ,CAChB,YAAY,CAAC,qCAAqC,EAClD,kCAAkC,aAAa,+BAA+B,eAAe,EAAE,CAChG,CAAC;SACH;IACH,CAAC;IAED;;;;;OAKG;IACK,MAAM,CAAO,iBAAiB,CACpC,UAAkB,EAClB,wBAAgC,EAChC,eAAgC,EAChC,YAA0B;;YAE1B,8DAA8D;YAC9D,IAAI,wBAAwB,GAAG,eAAe,CAAC,WAAW,EAAE;gBAC1D,0BAA0B;gBAC1B,MAAM,IAAI,QAAQ,CAChB,YAAY,CAAC,mCAAmC,EAChD,mFAAmF,CACpF,CAAC;aACH;YAED,IAAI,wBAAwB,IAAI,eAAe,CAAC,WAAW,EAAE;gBAC3D,oBAAoB;gBACpB,MAAM,IAAI,QAAQ,CAChB,YAAY,CAAC,8BAA8B,EAC3C,+EAA+E,CAChF,CAAC;aACH;YAED,kCAAkC;YAClC,MAAM,KAAK,GAAG;gBACZ,QAAQ,EAAY,eAAe,CAAC,EAAE;gBACtC,YAAY,EAAQ,kBAAkB;gBACtC,iBAAiB,EAAG,IAAI;aACzB,CAAC;YACF,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;YAC5E,MAAM,oBAAoB,GAAG,MAAM,OAAO,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;YAErE,IAAI,oBAAoB,KAAK,SAAS,IAAI,oBAAoB,CAAC,UAAU,CAAC,gBAAgB,IAAI,wBAAwB,EAAE;gBACtH,MAAM,IAAI,QAAQ,CAChB,YAAY,CAAC,8BAA8B,EAC3C,6BAA6B,eAAe,CAAC,EAAE,mBAAmB,CACnE,CAAC;aACH;QACH,CAAC;KAAA;IAED;;;;OAIG;IACK,MAAM,CAAO,kCAAkC,CACrD,YAAoB,EACpB,SAAiB,EACjB,eAAgC;;YAGhC,IAAI,YAAY,KAAK,eAAe,CAAC,KAAK,CAAC,SAAS,EAAE;gBACpD,MAAM,IAAI,QAAQ,CAChB,YAAY,CAAC,mCAAmC,EAChD,sFAAsF,eAAe,CAAC,EAAE,EAAE,CAC3G,CAAC;aACH;iBAAM,IAAI,SAAS,KAAK,eAAe,CAAC,KAAK,CAAC,MAAM,EAAE;gBACrD,MAAM,IAAI,QAAQ,CAChB,YAAY,CAAC,gCAAgC,EAC7C,mFAAmF,eAAe,CAAC,EAAE,EAAE,CACxG,CAAC;aACH;QACH,CAAC;KAAA;CACF"}
@@ -0,0 +1,5 @@
export function messageReplyFromError(e, code) {
const detail = e instanceof Error ? e.message : 'Error';
return { status: { code, detail } };
}
//# sourceMappingURL=message-reply.js.map
@@ -0,0 +1 @@
{"version":3,"file":"message-reply.js","sourceRoot":"","sources":["../../../../src/core/message-reply.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,qBAAqB,CAAC,CAAU,EAAE,IAAY;IAE5D,MAAM,MAAM,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;IAExD,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC;AACtC,CAAC"}
@@ -0,0 +1,217 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Cid } from '../utils/cid.js';
import { Encoder } from '../utils/encoder.js';
import { GeneralJwsBuilder } from '../jose/jws/general/builder.js';
import { Jws } from '../utils/jws.js';
import { lexicographicalCompare } from '../utils/string.js';
import { removeUndefinedProperties } from '../utils/object.js';
import { validateJsonSchema } from '../schema-validator.js';
import { DwnError, DwnErrorCode } from './dwn-error.js';
/**
* A class containing utility methods for working with DWN messages.
*/
export class Message {
/**
* Validates the given message against the corresponding JSON schema.
* @throws {Error} if fails validation.
*/
static validateJsonSchema(rawMessage) {
const dwnInterface = rawMessage.descriptor.interface;
const dwnMethod = rawMessage.descriptor.method;
const schemaLookupKey = dwnInterface + dwnMethod;
// throws an error if message is invalid
validateJsonSchema(schemaLookupKey, rawMessage);
}
;
/**
* Gets the DID of the signer of the given message, returns `undefined` if message is not signed.
*/
static getSigner(message) {
if (message.authorization === undefined) {
return undefined;
}
const signer = Jws.getSignerDid(message.authorization.signature.signatures[0]);
return signer;
}
/**
* Gets the CID of the given message.
*/
static getCid(message) {
return __awaiter(this, void 0, void 0, function* () {
// NOTE: we wrap the `computeCid()` here in case that
// the message will contain properties that should not be part of the CID computation
// and we need to strip them out (like `encodedData` that we historically had for a long time),
// but we can remove this method entirely if the code becomes stable and it is apparent that the wrapper is not needed
// ^--- seems like we might need to keep this around for now.
const rawMessage = Object.assign({}, message);
if (rawMessage.encodedData) {
delete rawMessage.encodedData;
}
const cid = yield Cid.computeCid(rawMessage);
return cid;
});
}
/**
* Compares message CID in lexicographical order according to the spec.
* @returns 1 if `a` is larger than `b`; -1 if `a` is smaller/older than `b`; 0 otherwise (same message)
*/
static compareCid(a, b) {
return __awaiter(this, void 0, void 0, function* () {
// the < and > operators compare strings in lexicographical order
const cidA = yield Message.getCid(a);
const cidB = yield Message.getCid(b);
return lexicographicalCompare(cidA, cidB);
});
}
/**
* Creates the `authorization` property to be included in a DWN message.
* @param signer Message signer.
* @returns {AuthorizationModel} used as an `authorization` property.
*/
static createAuthorization(input) {
return __awaiter(this, void 0, void 0, function* () {
const { descriptor, signer, delegatedGrant, permissionGrantId, protocolRole } = input;
let delegatedGrantId;
if (delegatedGrant !== undefined) {
delegatedGrantId = yield Message.getCid(delegatedGrant);
}
const signature = yield Message.createSignature(descriptor, signer, { delegatedGrantId, permissionGrantId, protocolRole });
const authorization = {
signature
};
if (delegatedGrant !== undefined) {
authorization.authorDelegatedGrant = delegatedGrant;
}
return authorization;
});
}
/**
* Creates a generic signature from the given DWN message descriptor by including `descriptorCid` as the required property in the signature payload.
* NOTE: there is an opportunity to consolidate RecordsWrite.createSignerSignature() wth this method
*/
static createSignature(descriptor, signer, additionalPayloadProperties) {
return __awaiter(this, void 0, void 0, function* () {
const descriptorCid = yield Cid.computeCid(descriptor);
const signaturePayload = Object.assign({ descriptorCid }, additionalPayloadProperties);
removeUndefinedProperties(signaturePayload);
const signaturePayloadBytes = Encoder.objectToBytes(signaturePayload);
const builder = yield GeneralJwsBuilder.create(signaturePayloadBytes, [signer]);
const signature = builder.getJws();
return signature;
});
}
/**
* @returns newest message in the array. `undefined` if given array is empty.
*/
static getNewestMessage(messages) {
return __awaiter(this, void 0, void 0, function* () {
let currentNewestMessage = undefined;
for (const message of messages) {
if (currentNewestMessage === undefined || (yield Message.isNewer(message, currentNewestMessage))) {
currentNewestMessage = message;
}
}
return currentNewestMessage;
});
}
/**
* @returns oldest message in the array. `undefined` if given array is empty.
*/
static getOldestMessage(messages) {
return __awaiter(this, void 0, void 0, function* () {
let currentOldestMessage = undefined;
for (const message of messages) {
if (currentOldestMessage === undefined || (yield Message.isOlder(message, currentOldestMessage))) {
currentOldestMessage = message;
}
}
return currentOldestMessage;
});
}
/**
* Checks if first message is newer than second message.
* @returns `true` if `a` is newer than `b`; `false` otherwise
*/
static isNewer(a, b) {
return __awaiter(this, void 0, void 0, function* () {
const aIsNewer = ((yield Message.compareMessageTimestamp(a, b)) > 0);
return aIsNewer;
});
}
/**
* Checks if first message is older than second message.
* @returns `true` if `a` is older than `b`; `false` otherwise
*/
static isOlder(a, b) {
return __awaiter(this, void 0, void 0, function* () {
const aIsOlder = ((yield Message.compareMessageTimestamp(a, b)) < 0);
return aIsOlder;
});
}
/**
* See if the given message is signed by an author-delegate.
*/
static isSignedByAuthorDelegate(message) {
var _a;
return ((_a = message.authorization) === null || _a === void 0 ? void 0 : _a.authorDelegatedGrant) !== undefined;
}
/**
* See if the given message is signed by an owner-delegate.
*/
static isSignedByOwnerDelegate(message) {
var _a;
return ((_a = message.authorization) === null || _a === void 0 ? void 0 : _a.ownerDelegatedGrant) !== undefined;
}
/**
* Compares the `messageTimestamp` of the given messages with a fallback to message CID according to the spec.
* @returns 1 if `a` is larger/newer than `b`; -1 if `a` is smaller/older than `b`; 0 otherwise (same age)
*/
static compareMessageTimestamp(a, b) {
return __awaiter(this, void 0, void 0, function* () {
if (a.descriptor.messageTimestamp > b.descriptor.messageTimestamp) {
return 1;
}
else if (a.descriptor.messageTimestamp < b.descriptor.messageTimestamp) {
return -1;
}
// else `messageTimestamp` is the same between a and b
// compare the `dataCid` instead, the < and > operators compare strings in lexicographical order
return Message.compareCid(a, b);
});
}
/**
* Validates the structural integrity of the message signature given:
* 1. The message signature must contain exactly 1 signature
* 2. Passes JSON schema validation
* 3. The `descriptorCid` property matches the CID of the message descriptor
* NOTE: signature is NOT verified.
* @param payloadJsonSchemaKey The key to look up the JSON schema referenced in `compile-validators.js` and perform payload schema validation on.
* @returns the parsed JSON payload object if validation succeeds.
*/
static validateSignatureStructure(messageSignature, messageDescriptor, payloadJsonSchemaKey = 'GenericSignaturePayload') {
return __awaiter(this, void 0, void 0, function* () {
if (messageSignature.signatures.length !== 1) {
throw new DwnError(DwnErrorCode.AuthenticationMoreThanOneSignatureNotSupported, 'expected no more than 1 signature for authorization purpose');
}
// validate payload integrity
const payloadJson = Jws.decodePlainObjectPayload(messageSignature);
validateJsonSchema(payloadJsonSchemaKey, payloadJson);
// `descriptorCid` validation - ensure that the provided descriptorCid matches the CID of the actual message
const { descriptorCid } = payloadJson;
const expectedDescriptorCid = yield Cid.computeCid(messageDescriptor);
if (descriptorCid !== expectedDescriptorCid) {
throw new DwnError(DwnErrorCode.AuthenticateDescriptorCidMismatch, `provided descriptorCid ${descriptorCid} does not match expected CID ${expectedDescriptorCid}`);
}
return payloadJson;
});
}
}
//# sourceMappingURL=message.js.map
@@ -0,0 +1 @@
{"version":3,"file":"message.js","sourceRoot":"","sources":["../../../../src/core/message.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,608 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import Ajv from 'ajv/dist/2020.js';
import { FilterUtility } from '../utils/filter.js';
import { PermissionsProtocol } from '../protocols/permissions.js';
import { Records } from '../utils/records.js';
import { RecordsWrite } from '../interfaces/records-write.js';
import { DwnError, DwnErrorCode } from './dwn-error.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
import { ProtocolAction, ProtocolActor } from '../types/protocols-types.js';
export class ProtocolAuthorization {
/**
* Performs validation on the structure of RecordsWrite messages that use a protocol.
* @throws {Error} if validation fails.
*/
static validateReferentialIntegrity(tenant, incomingMessage, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
// fetch the protocol definition
const protocolDefinition = yield ProtocolAuthorization.fetchProtocolDefinition(tenant, incomingMessage.message.descriptor.protocol, messageStore);
// verify declared protocol type exists in protocol and that it conforms to type specification
ProtocolAuthorization.verifyType(incomingMessage.message, protocolDefinition.types);
// validate `protocolPath`
yield ProtocolAuthorization.verifyProtocolPathAndContextId(tenant, incomingMessage, messageStore);
// get the rule set for the inbound message
const ruleSet = ProtocolAuthorization.getRuleSet(incomingMessage.message.descriptor.protocolPath, protocolDefinition);
// Validate as a role record if the incoming message is writing a role record
yield ProtocolAuthorization.verifyAsRoleRecordIfNeeded(tenant, incomingMessage, ruleSet, messageStore);
// Verify size limit
ProtocolAuthorization.verifySizeLimit(incomingMessage, ruleSet);
// Verify protocol tags
ProtocolAuthorization.verifyTagsIfNeeded(incomingMessage, ruleSet);
});
}
/**
* Performs protocol-based authorization against the incoming RecordsWrite message.
* @throws {Error} if authorization fails.
*/
static authorizeWrite(tenant, incomingMessage, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
const existingInitialWrite = yield ProtocolAuthorization.fetchInitialWrite(tenant, incomingMessage.message.recordId, messageStore);
let recordChain;
if (existingInitialWrite === undefined) {
// NOTE: we can assume this message is an initial write because an existing initial write does not exist.
// Additionally, we check further down in the `RecordsWriteHandler` if the incoming message is an initialWrite,
// so we don't check explicitly here to avoid an unnecessary duplicate check.
recordChain = yield ProtocolAuthorization.constructRecordChain(tenant, incomingMessage.message.descriptor.parentId, messageStore);
}
else {
recordChain = yield ProtocolAuthorization.constructRecordChain(tenant, incomingMessage.message.recordId, messageStore);
}
// fetch the protocol definition
const protocolDefinition = yield ProtocolAuthorization.fetchProtocolDefinition(tenant, incomingMessage.message.descriptor.protocol, messageStore);
// get the rule set for the inbound message
const ruleSet = ProtocolAuthorization.getRuleSet(incomingMessage.message.descriptor.protocolPath, protocolDefinition);
// If the incoming message has `protocolRole` in the descriptor, validate the invoked role
yield ProtocolAuthorization.verifyInvokedRole(tenant, incomingMessage, incomingMessage.message.descriptor.protocol, incomingMessage.message.contextId, protocolDefinition, messageStore);
// verify method invoked against the allowed actions in the rule set
yield ProtocolAuthorization.authorizeAgainstAllowedActions(tenant, incomingMessage, ruleSet, recordChain, messageStore);
});
}
/**
* Performs protocol-based authorization against the incoming `RecordsRead` message.
* @param newestRecordsWrite The latest RecordsWrite associated with the recordId being read.
* @throws {Error} if authorization fails.
*/
static authorizeRead(tenant, incomingMessage, newestRecordsWrite, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
// fetch record chain
const recordChain = yield ProtocolAuthorization.constructRecordChain(tenant, newestRecordsWrite.message.recordId, messageStore);
// fetch the protocol definition
const protocolDefinition = yield ProtocolAuthorization.fetchProtocolDefinition(tenant, newestRecordsWrite.message.descriptor.protocol, messageStore);
// get the rule set for the inbound message
const ruleSet = ProtocolAuthorization.getRuleSet(newestRecordsWrite.message.descriptor.protocolPath, protocolDefinition);
// If the incoming message has `protocolRole` in the descriptor, validate the invoked role
yield ProtocolAuthorization.verifyInvokedRole(tenant, incomingMessage, newestRecordsWrite.message.descriptor.protocol, newestRecordsWrite.message.contextId, protocolDefinition, messageStore);
// verify method invoked against the allowed actions in the rule set
yield ProtocolAuthorization.authorizeAgainstAllowedActions(tenant, incomingMessage, ruleSet, recordChain, messageStore);
});
}
static authorizeQueryOrSubscribe(tenant, incomingMessage, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
const { protocol, protocolPath, contextId } = incomingMessage.message.descriptor.filter;
// fetch the protocol definition
const protocolDefinition = yield ProtocolAuthorization.fetchProtocolDefinition(tenant, protocol, // `authorizeQueryOrSubscribe` is only called if `protocol` is present
messageStore);
// get the rule set for the inbound message
const ruleSet = ProtocolAuthorization.getRuleSet(protocolPath, // presence of `protocolPath` is verified in `parse()`
protocolDefinition);
// If the incoming message has `protocolRole` in the descriptor, validate the invoked role
yield ProtocolAuthorization.verifyInvokedRole(tenant, incomingMessage, protocol, contextId, protocolDefinition, messageStore);
// verify method invoked against the allowed actions in the rule set
yield ProtocolAuthorization.authorizeAgainstAllowedActions(tenant, incomingMessage, ruleSet, [], // record chain is not relevant to queries or subscriptions
messageStore);
});
}
/**
* Performs protocol-based authorization against the incoming `RecordsDelete` message.
* @param newestRecordsWrite The latest `RecordsWrite` associated with the recordId being deleted.
*/
static authorizeDelete(tenant, incomingMessage, newestRecordsWrite, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
// fetch record chain
const recordChain = yield ProtocolAuthorization.constructRecordChain(tenant, incomingMessage.message.descriptor.recordId, messageStore);
// fetch the protocol definition
const protocolDefinition = yield ProtocolAuthorization.fetchProtocolDefinition(tenant, newestRecordsWrite.message.descriptor.protocol, messageStore);
// get the rule set for the inbound message
const ruleSet = ProtocolAuthorization.getRuleSet(newestRecordsWrite.message.descriptor.protocolPath, protocolDefinition);
// If the incoming message has `protocolRole` in the descriptor, validate the invoked role
yield ProtocolAuthorization.verifyInvokedRole(tenant, incomingMessage, newestRecordsWrite.message.descriptor.protocol, newestRecordsWrite.message.contextId, protocolDefinition, messageStore);
// verify method invoked against the allowed actions in the rule set
yield ProtocolAuthorization.authorizeAgainstAllowedActions(tenant, incomingMessage, ruleSet, recordChain, messageStore);
});
}
/**
* Fetches the protocol definition based on the protocol specified in the given message.
*/
static fetchProtocolDefinition(tenant, protocolUri, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
// if first-class protocol, return the definition from const object directly without going to data store
if (protocolUri === PermissionsProtocol.uri) {
return PermissionsProtocol.definition;
}
// fetch the corresponding protocol definition
const query = {
interface: DwnInterfaceName.Protocols,
method: DwnMethodName.Configure,
protocol: protocolUri
};
const { messages: protocols } = yield messageStore.query(tenant, [query]);
if (protocols.length === 0) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationProtocolNotFound, `unable to find protocol definition for ${protocolUri}`);
}
const protocolMessage = protocols[0];
return protocolMessage.descriptor.definition;
});
}
/**
* Constructs the chain of EXISTING records in the datastore where the first record is the root initial `RecordsWrite` of the record chain
* and last record is the initial `RecordsWrite` of the descendant record specified.
* @param descendantRecordId The ID of the descendent record to start constructing the record chain from by repeatedly looking up the parent.
* @returns the record chain where each record is represented by its initial `RecordsWrite`;
* returns empty array if `descendantRecordId` is `undefined`.
* @throws {DwnError} if `descendantRecordId` is defined but any initial `RecordsWrite` is not found in the chain of records.
*/
static constructRecordChain(tenant, descendantRecordId, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
if (descendantRecordId === undefined) {
return [];
}
const recordChain = [];
// keep walking up the chain from the inbound message's parent, until there is no more parent
let currentRecordId = descendantRecordId;
while (currentRecordId !== undefined) {
const initialWrite = yield ProtocolAuthorization.fetchInitialWrite(tenant, currentRecordId, messageStore);
// RecordsWrite needed should be available since we perform necessary checks at the time of writes,
// eg. check the immediate parent in `verifyProtocolPathAndContextId` at the time of writing,
// so if this condition is triggered, it means there is an unexpected bug that caused an incomplete chain.
// We add additional defensive check here because returning an unexpected/incorrect record chain could lead to security vulnerabilities.
if (initialWrite === undefined) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationParentNotFoundConstructingRecordChain, `Unexpected error that should never trigger: no parent found with ID ${currentRecordId} when constructing record chain.`);
}
recordChain.push(initialWrite);
currentRecordId = initialWrite.descriptor.parentId;
}
return recordChain.reverse(); // root record first
});
}
/**
* Fetches the initial RecordsWrite message associated with the given (tenant + recordId).
*/
static fetchInitialWrite(tenant, recordId, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
const query = {
interface: DwnInterfaceName.Records,
method: DwnMethodName.Write,
recordId: recordId
};
const { messages } = yield messageStore.query(tenant, [query]);
if (messages.length === 0) {
return undefined;
}
const initialWrite = yield RecordsWrite.getInitialWrite(messages);
return initialWrite;
});
}
/**
* Gets the rule set corresponding to the given protocolPath.
*/
static getRuleSet(protocolPath, protocolDefinition) {
const ruleSet = ProtocolAuthorization.getRuleSetAtProtocolPath(protocolPath, protocolDefinition);
if (ruleSet === undefined) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationMissingRuleSet, `No rule set defined for protocolPath ${protocolPath}`);
}
return ruleSet;
}
/**
* Verifies the `protocolPath` declared in the given message (if it is a RecordsWrite) matches the path of actual record chain.
* @throws {DwnError} if fails verification.
*/
static verifyProtocolPathAndContextId(tenant, inboundMessage, messageStore) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const declaredProtocolPath = inboundMessage.message.descriptor.protocolPath;
const declaredTypeName = ProtocolAuthorization.getTypeName(declaredProtocolPath);
const parentId = inboundMessage.message.descriptor.parentId;
if (parentId === undefined) {
if (declaredProtocolPath !== declaredTypeName) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationParentlessIncorrectProtocolPath, `Declared protocol path '${declaredProtocolPath}' is not valid for records with no parent'.`);
}
return;
}
// Else `parentId` is defined, so we need to verify both protocolPath and contextId
// fetch the parent message
const protocol = inboundMessage.message.descriptor.protocol;
const query = {
isLatestBaseState: true,
interface: DwnInterfaceName.Records,
method: DwnMethodName.Write,
protocol,
recordId: parentId
};
const { messages: parentMessages } = yield messageStore.query(tenant, [query]);
const parentMessage = parentMessages[0];
// verifying protocolPath of incoming message is a child of the parent message's protocolPath
const parentProtocolPath = (_a = parentMessage === null || parentMessage === void 0 ? void 0 : parentMessage.descriptor) === null || _a === void 0 ? void 0 : _a.protocolPath;
const expectedProtocolPath = `${parentProtocolPath}/${declaredTypeName}`;
if (expectedProtocolPath !== declaredProtocolPath) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationIncorrectProtocolPath, `Could not find matching parent record to verify declared protocol path '${declaredProtocolPath}'.`);
}
// verifying contextId of incoming message is a child of the parent message's contextId
const expectedContextId = `${parentMessage.contextId}/${inboundMessage.message.recordId}`;
const actualContextId = inboundMessage.message.contextId;
if (actualContextId !== expectedContextId) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationIncorrectContextId, `Declared contextId '${actualContextId}' is not the same as expected: '${expectedContextId}'.`);
}
});
}
/**
* Verifies the `dataFormat` and `schema` declared in the given message (if it is a RecordsWrite) matches dataFormat
* and schema of the type in the given protocol.
* @throws {DwnError} if fails verification.
*/
static verifyType(inboundMessage, protocolTypes) {
const typeNames = Object.keys(protocolTypes);
const declaredProtocolPath = inboundMessage.descriptor.protocolPath;
const declaredTypeName = ProtocolAuthorization.getTypeName(declaredProtocolPath);
if (!typeNames.includes(declaredTypeName)) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationInvalidType, `record with type ${declaredTypeName} not allowed in protocol`);
}
const protocolPath = inboundMessage.descriptor.protocolPath;
// existence of `protocolType` has already been verified
const typeName = ProtocolAuthorization.getTypeName(protocolPath);
const protocolType = protocolTypes[typeName];
// no `schema` specified in protocol definition means that any schema is allowed
const { schema } = inboundMessage.descriptor;
if (protocolType.schema !== undefined && protocolType.schema !== schema) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationInvalidSchema, `type '${typeName}' must have schema '${protocolType.schema}', \
instead has '${schema}'`);
}
// no `dataFormats` specified in protocol definition means that all dataFormats are allowed
const { dataFormat } = inboundMessage.descriptor;
if (protocolType.dataFormats !== undefined && !protocolType.dataFormats.includes(dataFormat)) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationIncorrectDataFormat, `type '${typeName}' must have data format in (${protocolType.dataFormats}), \
instead has '${dataFormat}'`);
}
}
/**
* Check if the incoming message is invoking a role. If so, validate the invoked role.
*/
static verifyInvokedRole(tenant, incomingMessage, protocolUri, contextId, protocolDefinition, messageStore) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const protocolRole = (_a = incomingMessage.signaturePayload) === null || _a === void 0 ? void 0 : _a.protocolRole;
// Only verify role if there is a role being invoked
if (protocolRole === undefined) {
return;
}
const roleRuleSet = ProtocolAuthorization.getRuleSetAtProtocolPath(protocolRole, protocolDefinition);
if (roleRuleSet === undefined || !roleRuleSet.$role) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationNotARole, `Protocol path ${protocolRole} does not match role record type.`);
}
// Construct a filter to fetch the invoked role record
const roleRecordFilter = {
interface: DwnInterfaceName.Records,
method: DwnMethodName.Write,
protocol: protocolUri,
protocolPath: protocolRole,
recipient: incomingMessage.author,
isLatestBaseState: true,
};
const ancestorSegmentCountOfRolePath = protocolRole.split('/').length - 1;
if (contextId === undefined && ancestorSegmentCountOfRolePath > 0) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationMissingContextId, 'Could not verify role because contextId is missing.');
}
// Compute `contextId` prefix filter for fetching the invoked role record if the role path is not at the root level.
// e.g. if invoked role path is `Thread/Participant`, and the `contextId` of the message is `threadX/messageY/attachmentZ`,
// then we need to add a prefix filter as `threadX` for the `contextId`
// because the `contextId` of the Participant record would be in the form of be `threadX/participantA`
if (ancestorSegmentCountOfRolePath > 0) {
const contextIdSegments = contextId.split('/'); // NOTE: currently contextId segment count is never shorter than the role path count.
const contextIdPrefix = contextIdSegments.slice(0, ancestorSegmentCountOfRolePath).join('/');
const contextIdPrefixFilter = FilterUtility.constructPrefixFilterAsRangeFilter(contextIdPrefix);
roleRecordFilter.contextId = contextIdPrefixFilter;
}
const { messages: matchingMessages } = yield messageStore.query(tenant, [roleRecordFilter]);
if (matchingMessages.length === 0) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationMatchingRoleRecordNotFound, `No matching role record found for protocol path ${protocolRole}`);
}
});
}
/**
* Returns all the ProtocolActions that would authorized the incoming message
* (but we still need to later verify if there is a rule defined that matches one of the actions).
* NOTE: the reason why there could be multiple actions is because:
* - In case of an initial RecordsWrite, the RecordsWrite can be authorized by an allow `create` or `write` rule.
* - In case of a non-initial RecordsWrite by the original record author, the RecordsWrite can be authorized by a `write` or `co-update` rule.
*
* It is important to recognize that the `write` access that allowed the original record author to create the record maybe revoked
* (e.g. by role revocation) by the time a "non-initial" write by the same author is attempted.
*/
static getActionsSeekingARuleMatch(tenant, incomingMessage, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
switch (incomingMessage.message.descriptor.method) {
case DwnMethodName.Delete:
const recordsDelete = incomingMessage;
const recordId = recordsDelete.message.descriptor.recordId;
const initialWrite = yield RecordsWrite.fetchInitialRecordsWrite(messageStore, tenant, recordId);
// if there is no initial write, then no action rule can authorize the incoming message, because we won't know who the original author is
// NOTE: purely defensive programming: currently not reachable
// because RecordsDelete handler already have an existence check prior to this method being called.
if (initialWrite === undefined) {
return [];
}
const actionsThatWouldAuthorizeDelete = [];
const prune = recordsDelete.message.descriptor.prune;
if (prune) {
actionsThatWouldAuthorizeDelete.push(ProtocolAction.CoPrune);
// A prune by the original record author can also be authorized by a 'prune' rule.
if (incomingMessage.author === initialWrite.author) {
actionsThatWouldAuthorizeDelete.push(ProtocolAction.Prune);
}
}
else {
actionsThatWouldAuthorizeDelete.push(ProtocolAction.CoDelete);
// A delete by the original record author can also be authorized by a 'delete' rule.
if (incomingMessage.author === initialWrite.author) {
actionsThatWouldAuthorizeDelete.push(ProtocolAction.Delete);
}
}
return actionsThatWouldAuthorizeDelete;
case DwnMethodName.Query:
return [ProtocolAction.Query];
case DwnMethodName.Read:
return [ProtocolAction.Read];
case DwnMethodName.Subscribe:
return [ProtocolAction.Subscribe];
case DwnMethodName.Write:
const incomingRecordsWrite = incomingMessage;
if (yield incomingRecordsWrite.isInitialWrite()) {
return [ProtocolAction.Create];
}
else {
// else incoming RecordsWrite not an initial write
const recordId = incomingMessage.message.recordId;
const initialWrite = yield RecordsWrite.fetchInitialRecordsWrite(messageStore, tenant, recordId);
// if there is no initial write to update from, then no action rule can authorize the incoming message
if (initialWrite === undefined) {
return [];
}
if (incomingMessage.author === initialWrite.author) {
// 'update' or 'co-update' action authorizes the incoming message
return [ProtocolAction.CoUpdate, ProtocolAction.Update];
}
else {
// An update by someone who is not the record author can only be authorized by a 'co-update' rule.
return [ProtocolAction.CoUpdate];
}
}
}
// purely defensive programming: should not be reachable
// setting to empty array will prevent any message from being authorized
return [];
});
}
/**
* Verifies the given message is authorized by one of the action rules in the given protocol rule set.
* @throws {Error} if action not allowed.
*/
static authorizeAgainstAllowedActions(tenant, incomingMessage, ruleSet, recordChain, messageStore) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const incomingMessageMethod = incomingMessage.message.descriptor.method;
const actionsSeekingARuleMatch = yield ProtocolAuthorization.getActionsSeekingARuleMatch(tenant, incomingMessage, messageStore);
const author = incomingMessage.author;
const actionRules = ruleSet.$actions;
// NOTE: We have already checked that the message is not from tenant, owner, or permission grant authorized prior to this method being called.
if (actionRules === undefined) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationActionRulesNotFound, `no action rule defined for Records${incomingMessageMethod}, ${author} is unauthorized`);
}
const invokedRole = (_a = incomingMessage.signaturePayload) === null || _a === void 0 ? void 0 : _a.protocolRole;
// Iterate through the action rules to find a rule that authorizes the incoming message.
for (const actionRule of actionRules) {
// If the action rule does not have an allowed action that matches an action that can authorize the message, skip to evaluate next action rule.
const ruleHasAMatchingAllowedAction = actionRule.can.some(allowedAction => actionsSeekingARuleMatch.includes(allowedAction));
if (!ruleHasAMatchingAllowedAction) {
continue;
}
// Code reaches here means this action rule has an allowed action that matches the action of the message.
// The remaining code checks the actor/author of the incoming message.
// If the action rule allows `anyone`, then no further checks are needed.
if (actionRule.who === ProtocolActor.Anyone) {
return;
}
// Since not `anyone` is allowed in this action rule, we will need to check the author of the incoming message,
// if the author of incoming message is not defined, this action rule cannot authorize the incoming message.
if (author === undefined) {
continue;
}
// go through role validation path if a role is invoked by the incoming message
if (invokedRole !== undefined) {
// When a protocol role is being invoked, we require that there is a matching `role` rule.
if (actionRule.role === invokedRole) {
// role is successfully invoked
return;
}
else {
continue;
}
}
// else we go through the actor (`who`) validation
// If `of` is not set, handle it as a special case
// NOTE: `of` is always set if `who` is set to `author` (we do this check in `validateRuleSetRecursively()`)
if (actionRule.who === ProtocolActor.Recipient && actionRule.of === undefined) {
// If the action rule specifies a recipient without `of` and the incoming message is authenticated:
// Author must be recipient of the record being accessed
let recordsWriteMessage;
if (incomingMessage.message.descriptor.method === DwnMethodName.Write) {
recordsWriteMessage = incomingMessage.message;
}
else {
// else the incoming message must be a `RecordsDelete` because only `co-update`, `co-delete`, `co-prune` are allowed recipient actions,
// (we do this check in `validateRuleSetRecursively()`)
// and we have already checked that the incoming message is not a `RecordsWrite` above which covers `co-update` path.
recordsWriteMessage = recordChain[recordChain.length - 1];
}
if (recordsWriteMessage.descriptor.recipient === author) {
return;
}
else {
continue;
}
}
// validate the actor is allowed by the current action rule
const ancestorRuleSuccess = yield ProtocolAuthorization.checkActor(author, actionRule, recordChain);
if (ancestorRuleSuccess) {
return;
}
}
// No action rules were satisfied, message is not authorized
throw new DwnError(DwnErrorCode.ProtocolAuthorizationActionNotAllowed, `Inbound message action Records${incomingMessageMethod} by author ${incomingMessage.author} not allowed.`);
});
}
/**
* Verifies that writes adhere to the $size constraints if provided
* @throws {Error} if size is exceeded.
*/
static verifySizeLimit(incomingMessage, ruleSet) {
const { min = 0, max } = ruleSet.$size || {};
const dataSize = incomingMessage.message.descriptor.dataSize;
if (dataSize < min) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationMinSizeInvalid, `data size ${dataSize} is less than allowed ${min}`);
}
if (max === undefined) {
return;
}
if (dataSize > max) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationMaxSizeInvalid, `data size ${dataSize} is more than allowed ${max}`);
}
}
static verifyTagsIfNeeded(incomingMessage, ruleSet) {
if (ruleSet.$tags !== undefined) {
const { tags = {}, protocol, protocolPath } = incomingMessage.message.descriptor;
const _a = ruleSet.$tags, { $allowUndefinedTags, $requiredTags } = _a, properties = __rest(_a, ["$allowUndefinedTags", "$requiredTags"]);
// if $allowUndefinedTags is set to false and there are properties not defined in the schema, an error is thrown
const additionalProperties = $allowUndefinedTags || false;
// if $requiredTags is set, all required tags must be present
const required = $requiredTags || [];
const ajv = new Ajv.default();
const compiledTags = ajv.compile({
type: 'object',
properties,
required,
additionalProperties,
});
const validSchema = compiledTags(tags);
if (!validSchema) {
// the `dataVar` is used to add a qualifier to the error message.
// For example. If the error is related to a tag `status` in a protocol `https://example.protocol` with the protocolPath `example/path`
// the error would be described as `https://example.protocol/example/path/$tags/status'
// without this decorator it would show up as `data/status` which may be confusing.
const schemaError = ajv.errorsText(compiledTags.errors, { dataVar: `${protocol}/${protocolPath}/$tags` });
throw new DwnError(DwnErrorCode.ProtocolAuthorizationTagsInvalidSchema, `tags schema validation error: ${schemaError}`);
}
}
}
/**
* If the given RecordsWrite is not a role record, this method does nothing and succeeds immediately.
*
* Else it verifies the validity of the given `RecordsWrite` as a role record, including:
* 1. The same role has not been assigned to the same entity/recipient.
*/
static verifyAsRoleRecordIfNeeded(tenant, incomingMessage, ruleSet, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
if (!ruleSet.$role) {
return;
}
// else this is a role record
const incomingRecordsWrite = incomingMessage;
const recipient = incomingRecordsWrite.message.descriptor.recipient;
if (recipient === undefined) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationRoleMissingRecipient, 'Role records must have a recipient');
}
const protocolPath = incomingRecordsWrite.message.descriptor.protocolPath;
const filter = {
interface: DwnInterfaceName.Records,
method: DwnMethodName.Write,
isLatestBaseState: true,
protocol: incomingRecordsWrite.message.descriptor.protocol,
protocolPath,
recipient,
};
const parentContextId = Records.getParentContextFromOfContextId(incomingRecordsWrite.message.contextId);
// if this is not the root record, add a prefix filter to the query
if (parentContextId !== '') {
const prefixFilter = FilterUtility.constructPrefixFilterAsRangeFilter(parentContextId);
filter.contextId = prefixFilter;
}
const { messages: matchingMessages } = yield messageStore.query(tenant, [filter]);
const matchingRecords = matchingMessages;
const matchingRecordsExceptIncomingRecordId = matchingRecords.filter((recordsWriteMessage) => recordsWriteMessage.recordId !== incomingRecordsWrite.message.recordId);
if (matchingRecordsExceptIncomingRecordId.length > 0) {
throw new DwnError(DwnErrorCode.ProtocolAuthorizationDuplicateRoleRecipient, `DID '${recipient}' is already recipient of a role record at protocol path '${protocolPath} under the parent context ${parentContextId}.`);
}
});
}
static getRuleSetAtProtocolPath(protocolPath, protocolDefinition) {
const protocolPathArray = protocolPath.split('/');
let currentRuleSet = protocolDefinition.structure;
let i = 0;
while (i < protocolPathArray.length) {
const currentTypeName = protocolPathArray[i];
const nextRuleSet = currentRuleSet[currentTypeName];
if (nextRuleSet === undefined) {
return undefined;
}
currentRuleSet = nextRuleSet;
i++;
}
return currentRuleSet;
}
/**
* Checks if the `who: 'author' | 'recipient'` action rule has a matching record in the record chain.
* @returns `true` if the action rule is satisfied; `false` otherwise.
*/
static checkActor(author, actionRule, recordChain) {
return __awaiter(this, void 0, void 0, function* () {
// find a message with matching protocolPath
const ancestorRecordsWrite = recordChain.find((recordsWriteMessage) => recordsWriteMessage.descriptor.protocolPath === actionRule.of);
if (ancestorRecordsWrite === undefined) {
// If this is reached, there is likely an issue with the protocol definition.
// The protocolPath to the actionRule should start with actionRule.of
// consider moving this check to ProtocolsConfigure message ingestion
return false;
}
if (actionRule.who === ProtocolActor.Recipient) {
// author of the incoming message must be the recipient of the ancestor message
return author === ancestorRecordsWrite.descriptor.recipient;
}
else { // actionRule.who === ProtocolActor.Author
// author of the incoming message must be the author of the ancestor message
const ancestorAuthor = (yield RecordsWrite.parse(ancestorRecordsWrite)).author;
return author === ancestorAuthor;
}
});
}
static getTypeName(protocolPath) {
return protocolPath.split('/').slice(-1)[0];
}
}
//# sourceMappingURL=protocol-authorization.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,170 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { GrantAuthorization } from './grant-authorization.js';
import { PermissionConditionPublication } from '../types/permission-types.js';
import { DwnError, DwnErrorCode } from './dwn-error.js';
export class RecordsGrantAuthorization {
/**
* Authorizes the given RecordsWrite in the scope of the DID given.
*/
static authorizeWrite(input) {
return __awaiter(this, void 0, void 0, function* () {
const { recordsWriteMessage, expectedGrantor, expectedGrantee, permissionGrant, messageStore } = input;
yield GrantAuthorization.performBaseValidation({
incomingMessage: recordsWriteMessage,
expectedGrantor,
expectedGrantee,
permissionGrant,
messageStore
});
// NOTE: validated the invoked permission is for Records in GrantAuthorization.performBaseValidation()
RecordsGrantAuthorization.verifyScope(recordsWriteMessage, permissionGrant.scope);
RecordsGrantAuthorization.verifyConditions(recordsWriteMessage, permissionGrant.conditions);
});
}
/**
* Authorizes a RecordsReadMessage using the given permission grant.
* @param messageStore Used to check if the given grant has been revoked.
*/
static authorizeRead(input) {
return __awaiter(this, void 0, void 0, function* () {
const { recordsReadMessage, recordsWriteMessageToBeRead, expectedGrantor, expectedGrantee, permissionGrant, messageStore } = input;
yield GrantAuthorization.performBaseValidation({
incomingMessage: recordsReadMessage,
expectedGrantor,
expectedGrantee,
permissionGrant,
messageStore
});
// NOTE: validated the invoked permission is for Records in GrantAuthorization.performBaseValidation()
RecordsGrantAuthorization.verifyScope(recordsWriteMessageToBeRead, permissionGrant.scope);
});
}
/**
* Authorizes the scope of a permission grant for RecordsQuery or RecordsSubscribe.
* @param messageStore Used to check if the grant has been revoked.
*/
static authorizeQueryOrSubscribe(input) {
return __awaiter(this, void 0, void 0, function* () {
const { incomingMessage, expectedGrantor, expectedGrantee, permissionGrant, messageStore } = input;
yield GrantAuthorization.performBaseValidation({
incomingMessage,
expectedGrantor,
expectedGrantee,
permissionGrant,
messageStore
});
// If the grant specifies a protocol, the subscribe or query must specify the same protocol.
// NOTE: validated the invoked permission is for Records in GrantAuthorization.performBaseValidation()
const permissionScope = permissionGrant.scope;
const protocolInGrant = permissionScope.protocol;
const protocolInMessage = incomingMessage.descriptor.filter.protocol;
if (protocolInGrant !== undefined && protocolInMessage !== protocolInGrant) {
throw new DwnError(DwnErrorCode.RecordsGrantAuthorizationQueryOrSubscribeProtocolScopeMismatch, `Grant protocol scope ${protocolInGrant} does not match protocol in message ${protocolInMessage}`);
}
});
}
/**
* Authorizes the scope of a permission grant for RecordsDelete.
* @param messageStore Used to check if the grant has been revoked.
*/
static authorizeDelete(input) {
return __awaiter(this, void 0, void 0, function* () {
const { recordsDeleteMessage, recordsWriteToDelete, expectedGrantor, expectedGrantee, permissionGrant, messageStore } = input;
yield GrantAuthorization.performBaseValidation({
incomingMessage: recordsDeleteMessage,
expectedGrantor,
expectedGrantee,
permissionGrant,
messageStore
});
// If the grant specifies a protocol, the delete must be deleting a record with the same protocol.
// NOTE: validated the invoked permission is for Records in GrantAuthorization.performBaseValidation()
const permissionScope = permissionGrant.scope;
const protocolInGrant = permissionScope.protocol;
const protocolOfRecordToDelete = recordsWriteToDelete.descriptor.protocol;
if (protocolInGrant !== undefined && protocolOfRecordToDelete !== protocolInGrant) {
throw new DwnError(DwnErrorCode.RecordsGrantAuthorizationDeleteProtocolScopeMismatch, `Grant protocol scope ${protocolInGrant} does not match protocol in record to delete ${protocolOfRecordToDelete}`);
}
});
}
/**
* Verifies the given record against the scope of the given grant.
*/
static verifyScope(recordsWriteMessage, grantScope) {
if (RecordsGrantAuthorization.isUnrestrictedScope(grantScope)) {
// scope has no restrictions beyond interface and method. Message is authorized to access any record.
return;
}
else if (recordsWriteMessage.descriptor.protocol !== undefined) {
// authorization of protocol records must have grants that explicitly include the protocol
RecordsGrantAuthorization.verifyProtocolRecordScope(recordsWriteMessage, grantScope);
}
else {
RecordsGrantAuthorization.verifyFlatRecordScope(recordsWriteMessage, grantScope);
}
}
/**
* Verifies a protocol record against the scope of the given grant.
*/
static verifyProtocolRecordScope(recordsWriteMessage, grantScope) {
// Protocol records must have grants specifying the protocol
if (grantScope.protocol === undefined) {
throw new DwnError(DwnErrorCode.RecordsGrantAuthorizationScopeMissingProtocol, 'Grant for protocol record must specify protocol in its scope');
}
// The record's protocol must match the protocol specified in the record
if (grantScope.protocol !== recordsWriteMessage.descriptor.protocol) {
throw new DwnError(DwnErrorCode.RecordsGrantAuthorizationScopeProtocolMismatch, `Grant scope specifies different protocol than what appears in the record`);
}
// If grant specifies a contextId, check that record falls under that contextId
if (grantScope.contextId !== undefined) {
if (recordsWriteMessage.contextId === undefined || !recordsWriteMessage.contextId.startsWith(grantScope.contextId)) {
throw new DwnError(DwnErrorCode.RecordsGrantAuthorizationScopeContextIdMismatch, `Grant scope specifies different contextId than what appears in the record`);
}
}
// If grant specifies protocolPath, check that record is at that protocolPath
if (grantScope.protocolPath !== undefined && grantScope.protocolPath !== recordsWriteMessage.descriptor.protocolPath) {
throw new DwnError(DwnErrorCode.RecordsGrantAuthorizationScopeProtocolPathMismatch, `Grant scope specifies different protocolPath than what appears in the record`);
}
}
/**
* Verifies a non-protocol record against the scope of the given grant.
*/
static verifyFlatRecordScope(recordsWriteMessage, grantScope) {
if (grantScope.schema !== undefined) {
if (grantScope.schema !== recordsWriteMessage.descriptor.schema) {
throw new DwnError(DwnErrorCode.RecordsGrantAuthorizationScopeSchema, `Record does not have schema in permission grant scope with schema '${grantScope.schema}'`);
}
}
}
/**
* Verifies grant `conditions`.
* Currently the only condition is `published` which only applies to RecordsWrites
*/
static verifyConditions(recordsWriteMessage, conditions) {
// If conditions require publication, RecordsWrite must have `published` === true
if ((conditions === null || conditions === void 0 ? void 0 : conditions.publication) === PermissionConditionPublication.Required && !recordsWriteMessage.descriptor.published) {
throw new DwnError(DwnErrorCode.RecordsGrantAuthorizationConditionPublicationRequired, 'Permission grant requires message to be published');
}
// if conditions prohibit publication, RecordsWrite must have published === false or undefined
if ((conditions === null || conditions === void 0 ? void 0 : conditions.publication) === PermissionConditionPublication.Prohibited && recordsWriteMessage.descriptor.published) {
throw new DwnError(DwnErrorCode.RecordsGrantAuthorizationConditionPublicationProhibited, 'Permission grant prohibits message from being published');
}
}
/**
* Checks if scope has no restrictions beyond interface and method.
* Grant-holder is authorized to access any record.
*/
static isUnrestrictedScope(grantScope) {
return grantScope.protocol === undefined &&
grantScope.schema === undefined;
}
}
//# sourceMappingURL=records-grant-authorization.js.map
@@ -0,0 +1 @@
{"version":3,"file":"records-grant-authorization.js","sourceRoot":"","sources":["../../../../src/core/records-grant-authorization.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
/**
* A tenant gate that treats every DID as an active tenant.
*/
export class AllowAllTenantGate {
isActiveTenant(_did) {
return __awaiter(this, void 0, void 0, function* () {
return { isActiveTenant: true };
});
}
}
//# sourceMappingURL=tenant-gate.js.map
@@ -0,0 +1 @@
{"version":3,"file":"tenant-gate.js","sourceRoot":"","sources":["../../../../src/core/tenant-gate.ts"],"names":[],"mappings":";;;;;;;;;AAyBA;;GAEG;AACH,MAAM,OAAO,kBAAkB;IAChB,cAAc,CAAC,IAAY;;YACtC,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC;QAClC,CAAC;KAAA;CACF"}
@@ -0,0 +1,150 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { AllowAllTenantGate } from './core/tenant-gate.js';
import { EventsGetHandler } from './handlers/events-get.js';
import { EventsQueryHandler } from './handlers/events-query.js';
import { EventsSubscribeHandler } from './handlers/events-subscribe.js';
import { Message } from './core/message.js';
import { messageReplyFromError } from './core/message-reply.js';
import { MessagesGetHandler } from './handlers/messages-get.js';
import { ProtocolsConfigureHandler } from './handlers/protocols-configure.js';
import { ProtocolsQueryHandler } from './handlers/protocols-query.js';
import { RecordsDeleteHandler } from './handlers/records-delete.js';
import { RecordsQueryHandler } from './handlers/records-query.js';
import { RecordsReadHandler } from './handlers/records-read.js';
import { RecordsSubscribeHandler } from './handlers/records-subscribe.js';
import { RecordsWriteHandler } from './handlers/records-write.js';
import { DidDht, DidIon, DidKey, DidResolverCacheLevel, UniversalResolver } from '@web5/dids';
import { DwnInterfaceName, DwnMethodName } from './enums/dwn-interface-method.js';
export class Dwn {
constructor(config) {
this.didResolver = config.didResolver;
this.tenantGate = config.tenantGate;
this.eventStream = config.eventStream;
this.messageStore = config.messageStore;
this.dataStore = config.dataStore;
this.eventLog = config.eventLog;
this.eventStream = config.eventStream;
this.methodHandlers = {
[DwnInterfaceName.Events + DwnMethodName.Get]: new EventsGetHandler(this.didResolver, this.eventLog),
[DwnInterfaceName.Events + DwnMethodName.Query]: new EventsQueryHandler(this.didResolver, this.eventLog),
[DwnInterfaceName.Events + DwnMethodName.Subscribe]: new EventsSubscribeHandler(this.didResolver, this.eventStream),
[DwnInterfaceName.Messages + DwnMethodName.Get]: new MessagesGetHandler(this.didResolver, this.messageStore, this.dataStore),
[DwnInterfaceName.Protocols + DwnMethodName.Configure]: new ProtocolsConfigureHandler(this.didResolver, this.messageStore, this.eventLog, this.eventStream),
[DwnInterfaceName.Protocols + DwnMethodName.Query]: new ProtocolsQueryHandler(this.didResolver, this.messageStore, this.dataStore),
[DwnInterfaceName.Records + DwnMethodName.Delete]: new RecordsDeleteHandler(this.didResolver, this.messageStore, this.dataStore, this.eventLog, this.eventStream),
[DwnInterfaceName.Records + DwnMethodName.Query]: new RecordsQueryHandler(this.didResolver, this.messageStore, this.dataStore),
[DwnInterfaceName.Records + DwnMethodName.Read]: new RecordsReadHandler(this.didResolver, this.messageStore, this.dataStore),
[DwnInterfaceName.Records + DwnMethodName.Subscribe]: new RecordsSubscribeHandler(this.didResolver, this.messageStore, this.eventStream),
[DwnInterfaceName.Records + DwnMethodName.Write]: new RecordsWriteHandler(this.didResolver, this.messageStore, this.dataStore, this.eventLog, this.eventStream)
};
}
/**
* Creates an instance of the DWN.
*/
static create(config) {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () {
(_a = config.didResolver) !== null && _a !== void 0 ? _a : (config.didResolver = new UniversalResolver({
didResolvers: [DidDht, DidIon, DidKey],
cache: new DidResolverCacheLevel({ location: 'RESOLVERCACHE' }),
}));
(_b = config.tenantGate) !== null && _b !== void 0 ? _b : (config.tenantGate = new AllowAllTenantGate());
const dwn = new Dwn(config);
yield dwn.open();
return dwn;
});
}
open() {
var _a;
return __awaiter(this, void 0, void 0, function* () {
yield this.messageStore.open();
yield this.dataStore.open();
yield this.eventLog.open();
yield ((_a = this.eventStream) === null || _a === void 0 ? void 0 : _a.open());
});
}
close() {
var _a;
return __awaiter(this, void 0, void 0, function* () {
yield ((_a = this.eventStream) === null || _a === void 0 ? void 0 : _a.close());
yield this.messageStore.close();
yield this.dataStore.close();
yield this.eventLog.close();
});
}
processMessage(tenant, rawMessage, options = {}) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const errorMessageReply = (_a = yield this.validateTenant(tenant)) !== null && _a !== void 0 ? _a : yield this.validateMessageIntegrity(rawMessage);
if (errorMessageReply !== undefined) {
return errorMessageReply;
}
const { dataStream, subscriptionHandler } = options;
const handlerKey = rawMessage.descriptor.interface + rawMessage.descriptor.method;
const methodHandlerReply = yield this.methodHandlers[handlerKey].handle({
tenant,
message: rawMessage,
dataStream,
subscriptionHandler
});
return methodHandlerReply;
});
}
/**
* Checks tenant gate to see if tenant is allowed.
* @param tenant The tenant DID to route the given message to.
* @returns GenericMessageReply if the message has an integrity error, otherwise undefined.
*/
validateTenant(tenant) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const result = yield this.tenantGate.isActiveTenant(tenant);
if (!result.isActiveTenant) {
const detail = (_a = result.detail) !== null && _a !== void 0 ? _a : `DID ${tenant} is not an active tenant.`;
return {
status: { code: 401, detail }
};
}
});
}
/**
* Validates structure of DWN message
* @param tenant The tenant DID to route the given message to.
* @param dwnMessageInterface The interface of DWN message.
* @param dwnMessageMethod The interface of DWN message.
* @returns GenericMessageReply if the message has an integrity error, otherwise undefined.
*/
validateMessageIntegrity(rawMessage) {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () {
// Verify interface and method
const dwnInterface = (_a = rawMessage === null || rawMessage === void 0 ? void 0 : rawMessage.descriptor) === null || _a === void 0 ? void 0 : _a.interface;
const dwnMethod = (_b = rawMessage === null || rawMessage === void 0 ? void 0 : rawMessage.descriptor) === null || _b === void 0 ? void 0 : _b.method;
if (dwnInterface === undefined || dwnMethod === undefined) {
return {
status: { code: 400, detail: `Both interface and method must be present, interface: ${dwnInterface}, method: ${dwnMethod}` }
};
}
// validate message structure
try {
// consider to push this down to individual handlers
Message.validateJsonSchema(rawMessage);
}
catch (error) {
return messageReplyFromError(error, 400);
}
});
}
}
;
;
//# sourceMappingURL=dwn.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,22 @@
export var DwnInterfaceName;
(function (DwnInterfaceName) {
DwnInterfaceName["Events"] = "Events";
DwnInterfaceName["Messages"] = "Messages";
DwnInterfaceName["Protocols"] = "Protocols";
DwnInterfaceName["Records"] = "Records";
})(DwnInterfaceName || (DwnInterfaceName = {}));
export var DwnMethodName;
(function (DwnMethodName) {
DwnMethodName["Configure"] = "Configure";
DwnMethodName["Create"] = "Create";
DwnMethodName["Get"] = "Get";
DwnMethodName["Grant"] = "Grant";
DwnMethodName["Query"] = "Query";
DwnMethodName["Read"] = "Read";
DwnMethodName["Request"] = "Request";
DwnMethodName["Revoke"] = "Revoke";
DwnMethodName["Write"] = "Write";
DwnMethodName["Delete"] = "Delete";
DwnMethodName["Subscribe"] = "Subscribe";
})(DwnMethodName || (DwnMethodName = {}));
//# sourceMappingURL=dwn-interface-method.js.map
@@ -0,0 +1 @@
{"version":3,"file":"dwn-interface-method.js","sourceRoot":"","sources":["../../../../src/enums/dwn-interface-method.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,gBAKX;AALD,WAAY,gBAAgB;IAC1B,qCAAiB,CAAA;IACjB,yCAAqB,CAAA;IACrB,2CAAuB,CAAA;IACvB,uCAAmB,CAAA;AACrB,CAAC,EALW,gBAAgB,KAAhB,gBAAgB,QAK3B;AAED,MAAM,CAAN,IAAY,aAYX;AAZD,WAAY,aAAa;IACvB,wCAAuB,CAAA;IACvB,kCAAiB,CAAA;IACjB,4BAAW,CAAA;IACX,gCAAe,CAAA;IACf,gCAAe,CAAA;IACf,8BAAa,CAAA;IACb,oCAAmB,CAAA;IACnB,kCAAiB,CAAA;IACjB,gCAAe,CAAA;IACf,kCAAiB,CAAA;IACjB,wCAAuB,CAAA;AACzB,CAAC,EAZW,aAAa,KAAb,aAAa,QAYxB"}
@@ -0,0 +1,60 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { EventEmitter } from 'events';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
const EVENTS_LISTENER_CHANNEL = 'events';
;
export class EventEmitterStream {
constructor(config = {}) {
this.isOpen = false;
/**
* we subscribe to the `EventEmitter` error handler with a provided handler or set one which logs the errors.
*/
this.errorHandler = (error) => { console.error('event emitter error', error); };
// we capture the rejections and currently just log the errors that are produced
this.eventEmitter = new EventEmitter({ captureRejections: true });
// number of listeners per particular eventName before a warning is emitted
// we set to 0 which represents infinity.
// https://nodejs.org/api/events.html#emittersetmaxlistenersn
this.eventEmitter.setMaxListeners(0);
if (config.errorHandler) {
this.errorHandler = config.errorHandler;
}
this.eventEmitter.on('error', this.errorHandler);
}
subscribe(tenant, id, listener) {
return __awaiter(this, void 0, void 0, function* () {
this.eventEmitter.on(`${tenant}_${EVENTS_LISTENER_CHANNEL}`, listener);
return {
id,
close: () => __awaiter(this, void 0, void 0, function* () { this.eventEmitter.off(`${tenant}_${EVENTS_LISTENER_CHANNEL}`, listener); })
};
});
}
open() {
return __awaiter(this, void 0, void 0, function* () {
this.isOpen = true;
});
}
close() {
return __awaiter(this, void 0, void 0, function* () {
this.isOpen = false;
this.eventEmitter.removeAllListeners();
});
}
emit(tenant, event, indexes) {
if (!this.isOpen) {
this.errorHandler(new DwnError(DwnErrorCode.EventEmitterStreamNotOpenError, 'a message emitted when EventEmitterStream is closed'));
return;
}
this.eventEmitter.emit(`${tenant}_${EVENTS_LISTENER_CHANNEL}`, tenant, event, indexes);
}
}
//# sourceMappingURL=event-emitter-stream.js.map
@@ -0,0 +1 @@
{"version":3,"file":"event-emitter-stream.js","sourceRoot":"","sources":["../../../../src/event-log/event-emitter-stream.ts"],"names":[],"mappings":";;;;;;;;;AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAE9D,MAAM,uBAAuB,GAAG,QAAQ,CAAC;AAQxC,CAAC;AAEF,MAAM,OAAO,kBAAkB;IAI7B,YAAY,SAAmC,EAAE;QAFzC,WAAM,GAAY,KAAK,CAAC;QAkBhC;;WAEG;QACK,iBAAY,GAAwB,CAAC,KAAK,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAlBtG,gFAAgF;QAChF,IAAI,CAAC,YAAY,GAAG,IAAI,YAAY,CAAC,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAC,CAAC;QAElE,2EAA2E;QAC3E,yCAAyC;QACzC,6DAA6D;QAC7D,IAAI,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QAErC,IAAI,MAAM,CAAC,YAAY,EAAE;YACvB,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC;SACzC;QAED,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;IACnD,CAAC;IAOK,SAAS,CAAC,MAAc,EAAE,EAAU,EAAE,QAAuB;;YACjE,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,GAAG,MAAM,IAAI,uBAAuB,EAAE,EAAE,QAAQ,CAAC,CAAC;YACvE,OAAO;gBACL,EAAE;gBACF,KAAK,EAAE,GAAwB,EAAE,gDAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,MAAM,IAAI,uBAAuB,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;aAC/G,CAAC;QACJ,CAAC;KAAA;IAEK,IAAI;;YACR,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACrB,CAAC;KAAA;IAEK,KAAK;;YACT,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;YACpB,IAAI,CAAC,YAAY,CAAC,kBAAkB,EAAE,CAAC;QACzC,CAAC;KAAA;IAED,IAAI,CAAC,MAAc,EAAE,KAAmB,EAAE,OAAkB;QAC1D,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;YAChB,IAAI,CAAC,YAAY,CAAC,IAAI,QAAQ,CAC5B,YAAY,CAAC,8BAA8B,EAC3C,qDAAqD,CACtD,CAAC,CAAC;YACH,OAAO;SACR;QACD,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,uBAAuB,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IACzF,CAAC;CACF"}
@@ -0,0 +1,63 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { createLevelDatabase } from '../store/level-wrapper.js';
import { IndexLevel } from '../store/index-level.js';
import { monotonicFactory } from 'ulidx';
export class EventLogLevel {
constructor(config) {
this.index = new IndexLevel(Object.assign({ location: 'EVENTLOG', createLevelDatabase }, config));
this.ulidFactory = monotonicFactory();
}
open() {
return __awaiter(this, void 0, void 0, function* () {
return this.index.open();
});
}
close() {
return __awaiter(this, void 0, void 0, function* () {
return this.index.close();
});
}
clear() {
return __awaiter(this, void 0, void 0, function* () {
return this.index.clear();
});
}
append(tenant, messageCid, indexes) {
return __awaiter(this, void 0, void 0, function* () {
const watermark = this.ulidFactory();
yield this.index.put(tenant, messageCid, Object.assign(Object.assign({}, indexes), { watermark }));
});
}
queryEvents(tenant, filters, cursor) {
return __awaiter(this, void 0, void 0, function* () {
const results = yield this.index.query(tenant, filters, { sortProperty: 'watermark', cursor });
return {
events: results.map(({ messageCid }) => messageCid),
cursor: IndexLevel.createCursorFromLastArrayItem(results, 'watermark'),
};
});
}
getEvents(tenant, cursor) {
return __awaiter(this, void 0, void 0, function* () {
return this.queryEvents(tenant, [], cursor);
});
}
deleteEventsByCid(tenant, messageCids) {
return __awaiter(this, void 0, void 0, function* () {
const indexDeletePromises = [];
for (const messageCid of messageCids) {
indexDeletePromises.push(this.index.delete(tenant, messageCid));
}
yield Promise.all(indexDeletePromises);
});
}
}
//# sourceMappingURL=event-log-level.js.map
@@ -0,0 +1 @@
{"version":3,"file":"event-log-level.js","sourceRoot":"","sources":["../../../../src/event-log/event-log-level.ts"],"names":[],"mappings":";;;;;;;;;AAKA,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC;AAazC,MAAM,OAAO,aAAa;IAIxB,YAAY,MAA4B;QACtC,IAAI,CAAC,KAAK,GAAG,IAAI,UAAU,iBACzB,QAAQ,EAAE,UAAU,EACpB,mBAAmB,IAChB,MAAM,EACT,CAAC;QAEH,IAAI,CAAC,WAAW,GAAG,gBAAgB,EAAE,CAAC;IACxC,CAAC;IAEK,IAAI;;YACR,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAC3B,CAAC;KAAA;IAEK,KAAK;;YACT,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QAC5B,CAAC;KAAA;IAEK,KAAK;;YACT,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QAC5B,CAAC;KAAA;IAEK,MAAM,CAAC,MAAc,EAAE,UAAkB,EAAE,OAAkB;;YACjE,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;YACrC,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,kCAAO,OAAO,KAAE,SAAS,IAAG,CAAC;QACtE,CAAC;KAAA;IAEK,WAAW,CAAC,MAAc,EAAE,OAAiB,EAAE,MAAyB;;YAC5E,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC;YAC/F,OAAO;gBACL,MAAM,EAAG,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC;gBACpD,MAAM,EAAG,UAAU,CAAC,6BAA6B,CAAC,OAAO,EAAE,WAAW,CAAC;aACxE,CAAC;QACJ,CAAC;KAAA;IAEK,SAAS,CAAC,MAAc,EAAE,MAAyB;;YACvD,OAAO,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;QAC9C,CAAC;KAAA;IAEK,iBAAiB,CAAC,MAAc,EAAE,WAA0B;;YAChE,MAAM,mBAAmB,GAAoB,EAAE,CAAC;YAChD,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE;gBACpC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;aACjE;YAED,MAAM,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;QACzC,CAAC;KAAA;CACF"}
@@ -0,0 +1,46 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { EventsGet } from '../interfaces/events-get.js';
import { messageReplyFromError } from '../core/message-reply.js';
import { authenticate, authorizeOwner } from '../core/auth.js';
export class EventsGetHandler {
constructor(didResolver, eventLog) {
this.didResolver = didResolver;
this.eventLog = eventLog;
}
handle({ tenant, message }) {
return __awaiter(this, void 0, void 0, function* () {
let eventsGet;
try {
eventsGet = yield EventsGet.parse(message);
}
catch (e) {
return messageReplyFromError(e, 400);
}
try {
yield authenticate(message.authorization, this.didResolver);
yield authorizeOwner(tenant, eventsGet);
}
catch (e) {
return messageReplyFromError(e, 401);
}
// if a cursor was provided in message, get all events _after_ the cursor.
// Otherwise, get all events.
const { cursor: queryCursor } = message.descriptor;
const { events, cursor } = yield this.eventLog.getEvents(tenant, queryCursor);
return {
status: { code: 200, detail: 'OK' },
entries: events,
cursor
};
});
}
}
//# sourceMappingURL=events-get.js.map
@@ -0,0 +1 @@
{"version":3,"file":"events-get.js","sourceRoot":"","sources":["../../../../src/handlers/events-get.ts"],"names":[],"mappings":";;;;;;;;;AAKA,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAI/D,MAAM,OAAO,gBAAgB;IAC3B,YAAoB,WAAwB,EAAU,QAAkB;QAApD,gBAAW,GAAX,WAAW,CAAa;QAAU,aAAQ,GAAR,QAAQ,CAAU;IAAG,CAAC;IAE/D,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,EAAc;;YACjD,IAAI,SAAoB,CAAC;YAEzB,IAAI;gBACF,SAAS,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;aAC5C;YAAC,OAAO,CAAC,EAAE;gBACV,OAAO,qBAAqB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;aACtC;YAED,IAAI;gBACF,MAAM,YAAY,CAAC,OAAO,CAAC,aAAa,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;gBAC5D,MAAM,cAAc,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;aACzC;YAAC,OAAO,CAAC,EAAE;gBACV,OAAO,qBAAqB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;aACtC;YAED,0EAA0E;YAC1E,6BAA6B;YAC7B,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC;YACnD,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;YAE9E,OAAO;gBACL,MAAM,EAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;gBACrC,OAAO,EAAG,MAAM;gBAChB,MAAM;aACP,CAAC;QACJ,CAAC;KAAA;CACF"}
@@ -0,0 +1,45 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Events } from '../utils/events.js';
import { EventsQuery } from '../interfaces/events-query.js';
import { messageReplyFromError } from '../core/message-reply.js';
import { authenticate, authorizeOwner } from '../core/auth.js';
export class EventsQueryHandler {
constructor(didResolver, eventLog) {
this.didResolver = didResolver;
this.eventLog = eventLog;
}
handle({ tenant, message }) {
return __awaiter(this, void 0, void 0, function* () {
let eventsQuery;
try {
eventsQuery = yield EventsQuery.parse(message);
}
catch (e) {
return messageReplyFromError(e, 400);
}
try {
yield authenticate(message.authorization, this.didResolver);
yield authorizeOwner(tenant, eventsQuery);
}
catch (e) {
return messageReplyFromError(e, 401);
}
const eventFilters = Events.convertFilters(message.descriptor.filters);
const { events, cursor } = yield this.eventLog.queryEvents(tenant, eventFilters, message.descriptor.cursor);
return {
status: { code: 200, detail: 'OK' },
entries: events,
cursor
};
});
}
}
//# sourceMappingURL=events-query.js.map
@@ -0,0 +1 @@
{"version":3,"file":"events-query.js","sourceRoot":"","sources":["../../../../src/handlers/events-query.ts"],"names":[],"mappings":";;;;;;;;;AAKA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAG/D,MAAM,OAAO,kBAAkB;IAE7B,YAAoB,WAAwB,EAAU,QAAkB;QAApD,gBAAW,GAAX,WAAW,CAAa;QAAU,aAAQ,GAAR,QAAQ,CAAU;IAAI,CAAC;IAEhE,MAAM,CAAC,EAClB,MAAM,EACN,OAAO,EACuC;;YAC9C,IAAI,WAAwB,CAAC;YAE7B,IAAI;gBACF,WAAW,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;aAChD;YAAC,OAAO,CAAC,EAAE;gBACV,OAAO,qBAAqB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;aACtC;YAED,IAAI;gBACF,MAAM,YAAY,CAAC,OAAO,CAAC,aAAa,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;gBAC5D,MAAM,cAAc,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;aAC3C;YAAC,OAAO,CAAC,EAAE;gBACV,OAAO,qBAAqB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;aACtC;YAED,MAAM,YAAY,GAAG,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YACvE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;YAE5G,OAAO;gBACL,MAAM,EAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;gBACrC,OAAO,EAAG,MAAM;gBAChB,MAAM;aACP,CAAC;QACJ,CAAC;KAAA;CACF"}
@@ -0,0 +1,57 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Events } from '../utils/events.js';
import { EventsSubscribe } from '../interfaces/events-subscribe.js';
import { FilterUtility } from '../utils/filter.js';
import { Message } from '../core/message.js';
import { messageReplyFromError } from '../core/message-reply.js';
import { authenticate, authorizeOwner } from '../core/auth.js';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
export class EventsSubscribeHandler {
constructor(didResolver, eventStream) {
this.didResolver = didResolver;
this.eventStream = eventStream;
}
handle({ tenant, message, subscriptionHandler }) {
return __awaiter(this, void 0, void 0, function* () {
if (this.eventStream === undefined) {
return messageReplyFromError(new DwnError(DwnErrorCode.EventsSubscribeEventStreamUnimplemented, 'Subscriptions are not supported'), 501);
}
let eventsSubscribe;
try {
eventsSubscribe = yield EventsSubscribe.parse(message);
}
catch (e) {
return messageReplyFromError(e, 400);
}
try {
yield authenticate(message.authorization, this.didResolver);
yield authorizeOwner(tenant, eventsSubscribe);
}
catch (error) {
return messageReplyFromError(error, 401);
}
const { filters } = message.descriptor;
const eventsFilters = Events.convertFilters(filters);
const messageCid = yield Message.getCid(message);
const listener = (eventTenant, event, eventIndexes) => {
if (tenant === eventTenant && FilterUtility.matchAnyFilter(eventIndexes, eventsFilters)) {
subscriptionHandler(event);
}
};
const subscription = yield this.eventStream.subscribe(tenant, messageCid, listener);
return {
status: { code: 200, detail: 'OK' },
subscription,
};
});
}
}
//# sourceMappingURL=events-subscribe.js.map
@@ -0,0 +1 @@
{"version":3,"file":"events-subscribe.js","sourceRoot":"","sources":["../../../../src/handlers/events-subscribe.ts"],"names":[],"mappings":";;;;;;;;;AAKA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAE9D,MAAM,OAAO,sBAAsB;IACjC,YACU,WAAwB,EACxB,WAAyB;QADzB,gBAAW,GAAX,WAAW,CAAa;QACxB,gBAAW,GAAX,WAAW,CAAc;IAChC,CAAC;IAES,MAAM,CAAC,EAClB,MAAM,EACN,OAAO,EACP,mBAAmB,EAKpB;;YACC,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE;gBAClC,OAAO,qBAAqB,CAAC,IAAI,QAAQ,CACvC,YAAY,CAAC,uCAAuC,EACpD,iCAAiC,CAClC,EAAE,GAAG,CAAC,CAAC;aACT;YAED,IAAI,eAAgC,CAAC;YACrC,IAAI;gBACF,eAAe,GAAG,MAAM,eAAe,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;aACxD;YAAC,OAAO,CAAC,EAAE;gBACV,OAAO,qBAAqB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;aACtC;YAED,IAAI;gBACF,MAAM,YAAY,CAAC,OAAO,CAAC,aAAa,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;gBAC5D,MAAM,cAAc,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;aAC/C;YAAC,OAAO,KAAK,EAAE;gBACd,OAAO,qBAAqB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;aAC1C;YAED,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC;YACvC,MAAM,aAAa,GAAG,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;YACrD,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAEjD,MAAM,QAAQ,GAAkB,CAAC,WAAW,EAAE,KAAK,EAAE,YAAY,EAAO,EAAE;gBACxE,IAAI,MAAM,KAAK,WAAW,IAAI,aAAa,CAAC,cAAc,CAAC,YAAY,EAAE,aAAa,CAAC,EAAE;oBACvF,mBAAmB,CAAC,KAAK,CAAC,CAAC;iBAC5B;YACH,CAAC,CAAC;YAEF,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;YAEpF,OAAO;gBACL,MAAM,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;gBACnC,YAAY;aACb,CAAC;QACJ,CAAC;KAAA;CACF"}
@@ -0,0 +1,76 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { messageReplyFromError } from '../core/message-reply.js';
import { MessagesGet } from '../interfaces/messages-get.js';
import { authenticate, authorizeOwner } from '../core/auth.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
export class MessagesGetHandler {
constructor(didResolver, messageStore, dataStore) {
this.didResolver = didResolver;
this.messageStore = messageStore;
this.dataStore = dataStore;
}
handle({ tenant, message }) {
return __awaiter(this, void 0, void 0, function* () {
let messagesGet;
try {
messagesGet = yield MessagesGet.parse(message);
}
catch (e) {
return messageReplyFromError(e, 400);
}
try {
yield authenticate(message.authorization, this.didResolver);
yield authorizeOwner(tenant, messagesGet);
}
catch (e) {
return messageReplyFromError(e, 401);
}
const promises = [];
const messageCids = new Set(message.descriptor.messageCids);
for (const messageCid of messageCids) {
const promise = this.messageStore.get(tenant, messageCid)
.then(message => {
return { messageCid, message };
})
.catch(_ => {
return { messageCid, message: undefined, error: `Failed to get message ${messageCid}` };
});
promises.push(promise);
}
const messages = yield Promise.all(promises);
// for every message, include associated data as `encodedData` IF:
// * its a RecordsWrite
// * the data size is equal or smaller than the size threshold
for (const entry of messages) {
const { message } = entry;
if (!message) {
continue;
}
const { interface: messageInterface, method } = message.descriptor;
if (messageInterface !== DwnInterfaceName.Records || method !== DwnMethodName.Write) {
continue;
}
// RecordsWrite specific handling, if MessageStore has embedded `encodedData` return it with the entry.
// we store `encodedData` along with the message if the data is below a certain threshold.
const recordsWrite = message;
if (recordsWrite.encodedData !== undefined) {
entry.encodedData = recordsWrite.encodedData;
delete recordsWrite.encodedData;
}
}
return {
status: { code: 200, detail: 'OK' },
entries: messages
};
});
}
}
//# sourceMappingURL=messages-get.js.map
@@ -0,0 +1 @@
{"version":3,"file":"messages-get.js","sourceRoot":"","sources":["../../../../src/handlers/messages-get.ts"],"names":[],"mappings":";;;;;;;;;AAOA,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAInF,MAAM,OAAO,kBAAkB;IAC7B,YAAoB,WAAwB,EAAU,YAA0B,EAAU,SAAoB;QAA1F,gBAAW,GAAX,WAAW,CAAa;QAAU,iBAAY,GAAZ,YAAY,CAAc;QAAU,cAAS,GAAT,SAAS,CAAW;IAAG,CAAC;IAErG,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,EAAc;;YACjD,IAAI,WAAwB,CAAC;YAE7B,IAAI;gBACF,WAAW,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;aAChD;YAAC,OAAO,CAAC,EAAE;gBACV,OAAO,qBAAqB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;aACtC;YAED,IAAI;gBACF,MAAM,YAAY,CAAC,OAAO,CAAC,aAAa,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;gBAC5D,MAAM,cAAc,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;aAC3C;YAAC,OAAO,CAAC,EAAE;gBACV,OAAO,qBAAqB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;aACtC;YAED,MAAM,QAAQ,GAAqC,EAAE,CAAC;YACtD,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;YAE5D,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE;gBACpC,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC;qBACtD,IAAI,CAAC,OAAO,CAAC,EAAE;oBACd,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;gBACjC,CAAC,CAAC;qBACD,KAAK,CAAC,CAAC,CAAC,EAAE;oBACT,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,yBAAyB,UAAU,EAAE,EAAE,CAAC;gBAC1F,CAAC,CAAC,CAAC;gBAEL,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;aACxB;YAED,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAE7C,kEAAkE;YAClE,wBAAwB;YACxB,+DAA+D;YAC/D,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE;gBAC5B,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;gBAE1B,IAAI,CAAC,OAAO,EAAE;oBACZ,SAAS;iBACV;gBAED,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC;gBACnE,IAAI,gBAAgB,KAAK,gBAAgB,CAAC,OAAO,IAAI,MAAM,KAAK,aAAa,CAAC,KAAK,EAAE;oBACnF,SAAS;iBACV;gBAED,uGAAuG;gBACvG,0FAA0F;gBAC1F,MAAM,YAAY,GAAG,OAAiC,CAAC;gBACvD,IAAI,YAAY,CAAC,WAAW,KAAK,SAAS,EAAE;oBAC1C,KAAK,CAAC,WAAW,GAAG,YAAY,CAAC,WAAW,CAAC;oBAC7C,OAAO,YAAY,CAAC,WAAW,CAAC;iBACjC;aACF;YAED,OAAO;gBACL,MAAM,EAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;gBACrC,OAAO,EAAG,QAAQ;aACnB,CAAC;QACJ,CAAC;KAAA;CACF"}
@@ -0,0 +1,107 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import { Message } from '../core/message.js';
import { messageReplyFromError } from '../core/message-reply.js';
import { ProtocolsConfigure } from '../interfaces/protocols-configure.js';
import { authenticate, authorizeOwner } from '../core/auth.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
export class ProtocolsConfigureHandler {
constructor(didResolver, messageStore, eventLog, eventStream) {
this.didResolver = didResolver;
this.messageStore = messageStore;
this.eventLog = eventLog;
this.eventStream = eventStream;
}
handle({ tenant, message, }) {
return __awaiter(this, void 0, void 0, function* () {
let protocolsConfigure;
try {
protocolsConfigure = yield ProtocolsConfigure.parse(message);
}
catch (e) {
return messageReplyFromError(e, 400);
}
// authentication & authorization
try {
yield authenticate(message.authorization, this.didResolver);
yield authorizeOwner(tenant, protocolsConfigure);
}
catch (e) {
return messageReplyFromError(e, 401);
}
// attempt to get existing protocol
const query = {
interface: DwnInterfaceName.Protocols,
method: DwnMethodName.Configure,
protocol: message.descriptor.definition.protocol
};
const { messages: existingMessages } = yield this.messageStore.query(tenant, [query]);
// find newest message, and if the incoming message is the newest
let newestMessage = yield Message.getNewestMessage(existingMessages);
let incomingMessageIsNewest = false;
if (newestMessage === undefined || (yield Message.isNewer(message, newestMessage))) {
incomingMessageIsNewest = true;
newestMessage = message;
}
// write the incoming message to DB if incoming message is newest
let messageReply;
if (incomingMessageIsNewest) {
const indexes = ProtocolsConfigureHandler.constructIndexes(protocolsConfigure);
yield this.messageStore.put(tenant, message, indexes);
const messageCid = yield Message.getCid(message);
yield this.eventLog.append(tenant, messageCid, indexes);
// only emit if the event stream is set
if (this.eventStream !== undefined) {
this.eventStream.emit(tenant, { message }, indexes);
}
messageReply = {
status: { code: 202, detail: 'Accepted' }
};
}
else {
messageReply = {
status: { code: 409, detail: 'Conflict' }
};
}
// delete all existing records that are smaller
const deletedMessageCids = [];
for (const message of existingMessages) {
if (yield Message.isNewer(newestMessage, message)) {
const messageCid = yield Message.getCid(message);
deletedMessageCids.push(messageCid);
yield this.messageStore.delete(tenant, messageCid);
}
}
yield this.eventLog.deleteEventsByCid(tenant, deletedMessageCids);
return messageReply;
});
}
;
static constructIndexes(protocolsConfigure) {
// strip out `definition` as it is not indexable
const _a = protocolsConfigure.message.descriptor, { definition } = _a, propertiesToIndex = __rest(_a, ["definition"]);
const { author } = protocolsConfigure;
const indexes = Object.assign(Object.assign({}, propertiesToIndex), { author: author, protocol: definition.protocol, published: definition.published // retain published state from definition
});
return indexes;
}
}
//# sourceMappingURL=protocols-configure.js.map
@@ -0,0 +1 @@
{"version":3,"file":"protocols-configure.js","sourceRoot":"","sources":["../../../../src/handlers/protocols-configure.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,72 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { authenticate } from '../core/auth.js';
import { DwnErrorCode } from '../core/dwn-error.js';
import { messageReplyFromError } from '../core/message-reply.js';
import { ProtocolsQuery } from '../interfaces/protocols-query.js';
import { removeUndefinedProperties } from '../utils/object.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
export class ProtocolsQueryHandler {
constructor(didResolver, messageStore, dataStore) {
this.didResolver = didResolver;
this.messageStore = messageStore;
this.dataStore = dataStore;
}
handle({ tenant, message }) {
return __awaiter(this, void 0, void 0, function* () {
let protocolsQuery;
try {
protocolsQuery = yield ProtocolsQuery.parse(message);
}
catch (e) {
return messageReplyFromError(e, 400);
}
// authentication & authorization
try {
yield authenticate(message.authorization, this.didResolver);
yield protocolsQuery.authorize(tenant, this.messageStore);
}
catch (error) {
// return public ProtocolsConfigures if query fails with a certain authentication or authorization code
if (error.code === DwnErrorCode.AuthenticateJwsMissing || // unauthenticated
error.code === DwnErrorCode.ProtocolsQueryUnauthorized) {
const entries = yield this.fetchPublishedProtocolsConfigure(tenant, protocolsQuery);
return {
status: { code: 200, detail: 'OK' },
entries
};
}
else {
return messageReplyFromError(error, 401);
}
}
const query = Object.assign(Object.assign({}, message.descriptor.filter), { interface: DwnInterfaceName.Protocols, method: DwnMethodName.Configure });
removeUndefinedProperties(query);
const { messages } = yield this.messageStore.query(tenant, [query]);
return {
status: { code: 200, detail: 'OK' },
entries: messages
};
});
}
;
/**
* Fetches only published `ProtocolsConfigure`.
*/
fetchPublishedProtocolsConfigure(tenant, protocolsQuery) {
return __awaiter(this, void 0, void 0, function* () {
// fetch all published `ProtocolConfigure` matching the query
const filter = Object.assign(Object.assign({}, protocolsQuery.message.descriptor.filter), { interface: DwnInterfaceName.Protocols, method: DwnMethodName.Configure, published: true });
const { messages: publishedProtocolsConfigure } = yield this.messageStore.query(tenant, [filter]);
return publishedProtocolsConfigure;
});
}
}
//# sourceMappingURL=protocols-query.js.map
@@ -0,0 +1 @@
{"version":3,"file":"protocols-query.js","sourceRoot":"","sources":["../../../../src/handlers/protocols-query.ts"],"names":[],"mappings":";;;;;;;;;AAMA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAClE,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAE/D,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAEnF,MAAM,OAAO,qBAAqB;IAEhC,YAAoB,WAAwB,EAAU,YAA0B,EAAS,SAAoB;QAAzF,gBAAW,GAAX,WAAW,CAAa;QAAU,iBAAY,GAAZ,YAAY,CAAc;QAAS,cAAS,GAAT,SAAS,CAAW;IAAI,CAAC;IAErG,MAAM,CAAC,EAClB,MAAM,EACN,OAAO,EAC2C;;YAElD,IAAI,cAA8B,CAAC;YACnC,IAAI;gBACF,cAAc,GAAG,MAAM,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;aACtD;YAAC,OAAO,CAAC,EAAE;gBACV,OAAO,qBAAqB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;aACtC;YAED,iCAAiC;YACjC,IAAI;gBACF,MAAM,YAAY,CAAC,OAAO,CAAC,aAAa,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;gBAC5D,MAAM,cAAc,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;aAC3D;YAAC,OAAO,KAAU,EAAE;gBAEnB,uGAAuG;gBACvG,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,CAAC,sBAAsB,IAAI,kBAAkB;oBACxE,KAAK,CAAC,IAAI,KAAK,YAAY,CAAC,0BAA0B,EAAE;oBAE1D,MAAM,OAAO,GAAgC,MAAM,IAAI,CAAC,gCAAgC,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;oBACjH,OAAO;wBACL,MAAM,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;wBACnC,OAAO;qBACR,CAAC;iBACH;qBAAM;oBACL,OAAO,qBAAqB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;iBAC1C;aACF;YAED,MAAM,KAAK,mCACN,OAAO,CAAC,UAAU,CAAC,MAAM,KAC5B,SAAS,EAAG,gBAAgB,CAAC,SAAS,EACtC,MAAM,EAAM,aAAa,CAAC,SAAS,GACpC,CAAC;YACF,yBAAyB,CAAC,KAAK,CAAC,CAAC;YAEjC,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,MAAM,EAAE,CAAE,KAAK,CAAE,CAAC,CAAC;YAEtE,OAAO;gBACL,MAAM,EAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;gBACrC,OAAO,EAAG,QAAuC;aAClD,CAAC;QACJ,CAAC;KAAA;IAAA,CAAC;IAEF;;OAEG;IACW,gCAAgC,CAAC,MAAc,EAAE,cAA8B;;YAC3F,6DAA6D;YAC7D,MAAM,MAAM,mCACP,cAAc,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,KAC3C,SAAS,EAAG,gBAAgB,CAAC,SAAS,EACtC,MAAM,EAAM,aAAa,CAAC,SAAS,EACnC,SAAS,EAAG,IAAI,GACjB,CAAC;YACF,MAAM,EAAE,QAAQ,EAAE,2BAA2B,EAAE,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,MAAM,EAAE,CAAE,MAAM,CAAE,CAAC,CAAC;YACpG,OAAO,2BAA0D,CAAC;QACpE,CAAC;KAAA;CACF"}
@@ -0,0 +1,124 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { authenticate } from '../core/auth.js';
import { Message } from '../core/message.js';
import { messageReplyFromError } from '../core/message-reply.js';
import { ProtocolAuthorization } from '../core/protocol-authorization.js';
import { RecordsDelete } from '../interfaces/records-delete.js';
import { RecordsWrite } from '../interfaces/records-write.js';
import { StorageController } from '../store/storage-controller.js';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
export class RecordsDeleteHandler {
constructor(didResolver, messageStore, dataStore, eventLog, eventStream) {
this.didResolver = didResolver;
this.messageStore = messageStore;
this.dataStore = dataStore;
this.eventLog = eventLog;
this.eventStream = eventStream;
}
handle({ tenant, message }) {
return __awaiter(this, void 0, void 0, function* () {
let recordsDelete;
try {
recordsDelete = yield RecordsDelete.parse(message);
}
catch (e) {
return messageReplyFromError(e, 400);
}
// authentication
try {
yield authenticate(message.authorization, this.didResolver);
}
catch (e) {
return messageReplyFromError(e, 401);
}
// get existing records matching the `recordId`
const query = {
interface: DwnInterfaceName.Records,
recordId: message.descriptor.recordId
};
const { messages: existingMessages } = yield this.messageStore.query(tenant, [query]);
// find which message is the newest, and if the incoming message is the newest
const newestExistingMessage = yield Message.getNewestMessage(existingMessages);
let incomingMessageIsNewest = false;
let newestMessage;
// if incoming message is newest
if (newestExistingMessage === undefined || (yield Message.isNewer(message, newestExistingMessage))) {
incomingMessageIsNewest = true;
newestMessage = message;
}
else { // existing message is the same age or newer than the incoming message
newestMessage = newestExistingMessage;
}
if (!incomingMessageIsNewest) {
return {
status: { code: 409, detail: 'Conflict' }
};
}
// return Not Found if record does not exist or is already deleted
if (newestExistingMessage === undefined || newestExistingMessage.descriptor.method === DwnMethodName.Delete) {
return {
status: { code: 404, detail: 'Not Found' }
};
}
// authorization
try {
yield RecordsDeleteHandler.authorizeRecordsDelete(tenant, recordsDelete, yield RecordsWrite.parse(newestExistingMessage), this.messageStore);
}
catch (e) {
return messageReplyFromError(e, 401);
}
const initialWrite = yield RecordsWrite.getInitialWrite(existingMessages);
const indexes = recordsDelete.constructIndexes(initialWrite);
const messageCid = yield Message.getCid(message);
yield this.messageStore.put(tenant, message, indexes);
yield this.eventLog.append(tenant, messageCid, indexes);
// only emit if the event stream is set
if (this.eventStream !== undefined) {
this.eventStream.emit(tenant, { message, initialWrite }, indexes);
}
if (message.descriptor.prune) {
// purge/hard-delete all descendent records
yield StorageController.purgeRecordDescendants(tenant, message.descriptor.recordId, this.messageStore, this.dataStore, this.eventLog);
}
// delete all existing messages that are not newest, except for the initial write
yield StorageController.deleteAllOlderMessagesButKeepInitialWrite(tenant, existingMessages, newestMessage, this.messageStore, this.dataStore, this.eventLog);
const messageReply = {
status: { code: 202, detail: 'Accepted' }
};
return messageReply;
});
}
;
/**
* Authorizes a RecordsDelete message.
*
* @param newestRecordsWrite Newest RecordsWrite of the record to be deleted.
*/
static authorizeRecordsDelete(tenant, recordsDelete, newestRecordsWrite, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
if (Message.isSignedByAuthorDelegate(recordsDelete.message)) {
yield recordsDelete.authorizeDelegate(newestRecordsWrite.message, messageStore);
}
if (recordsDelete.author === tenant) {
return;
}
else if (newestRecordsWrite.message.descriptor.protocol !== undefined) {
yield ProtocolAuthorization.authorizeDelete(tenant, recordsDelete, newestRecordsWrite, messageStore);
}
else {
throw new DwnError(DwnErrorCode.RecordsDeleteAuthorizationFailed, 'RecordsDelete message failed authorization');
}
});
}
}
;
//# sourceMappingURL=records-delete.js.map
@@ -0,0 +1 @@
{"version":3,"file":"records-delete.js","sourceRoot":"","sources":["../../../../src/handlers/records-delete.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,209 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { authenticate } from '../core/auth.js';
import { DateSort } from '../types/records-types.js';
import { Message } from '../core/message.js';
import { messageReplyFromError } from '../core/message-reply.js';
import { ProtocolAuthorization } from '../core/protocol-authorization.js';
import { Records } from '../utils/records.js';
import { RecordsQuery } from '../interfaces/records-query.js';
import { RecordsWrite } from '../interfaces/records-write.js';
import { SortDirection } from '../types/query-types.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
export class RecordsQueryHandler {
constructor(didResolver, messageStore, dataStore) {
this.didResolver = didResolver;
this.messageStore = messageStore;
this.dataStore = dataStore;
}
handle({ tenant, message }) {
return __awaiter(this, void 0, void 0, function* () {
let recordsQuery;
try {
recordsQuery = yield RecordsQuery.parse(message);
}
catch (e) {
return messageReplyFromError(e, 400);
}
let recordsWrites;
let cursor;
// if this is an anonymous query and the filter supports published records, query only published records
if (Records.filterIncludesPublishedRecords(recordsQuery.message.descriptor.filter) && recordsQuery.author === undefined) {
const results = yield this.fetchPublishedRecords(tenant, recordsQuery);
recordsWrites = results.messages;
cursor = results.cursor;
}
else {
// authentication and authorization
try {
yield authenticate(message.authorization, this.didResolver);
yield RecordsQueryHandler.authorizeRecordsQuery(tenant, recordsQuery, this.messageStore);
}
catch (e) {
return messageReplyFromError(e, 401);
}
if (recordsQuery.author === tenant) {
const results = yield this.fetchRecordsAsOwner(tenant, recordsQuery);
recordsWrites = results.messages;
cursor = results.cursor;
}
else {
const results = yield this.fetchRecordsAsNonOwner(tenant, recordsQuery);
recordsWrites = results.messages;
cursor = results.cursor;
}
}
// attach initial write if returned RecordsWrite is not initial write
for (const recordsWrite of recordsWrites) {
if (!(yield RecordsWrite.isInitialWrite(recordsWrite))) {
const initialWriteQueryResult = yield this.messageStore.query(tenant, [{ recordId: recordsWrite.recordId, isLatestBaseState: false, method: DwnMethodName.Write }]);
const initialWrite = initialWriteQueryResult.messages[0];
delete initialWrite.encodedData; // defensive measure but technically optional because we do this when an update RecordsWrite takes place
recordsWrite.initialWrite = initialWrite;
}
}
return {
status: { code: 200, detail: 'OK' },
entries: recordsWrites,
cursor
};
});
}
/**
* Convert an incoming DateSort to a sort type accepted by MessageStore
* Defaults to 'dateCreated' in Descending order if no sort is supplied.
*
* @param dateSort the optional DateSort from the RecordsQuery message descriptor.
* @returns {MessageSort} for MessageStore sorting.
*/
convertDateSort(dateSort) {
switch (dateSort) {
case DateSort.CreatedAscending:
return { dateCreated: SortDirection.Ascending };
case DateSort.CreatedDescending:
return { dateCreated: SortDirection.Descending };
case DateSort.PublishedAscending:
return { datePublished: SortDirection.Ascending };
case DateSort.PublishedDescending:
return { datePublished: SortDirection.Descending };
default:
return { dateCreated: SortDirection.Ascending };
}
}
/**
* Fetches the records as the owner of the DWN with no additional filtering.
*/
fetchRecordsAsOwner(tenant, recordsQuery) {
return __awaiter(this, void 0, void 0, function* () {
const { dateSort, filter, pagination } = recordsQuery.message.descriptor;
// fetch all published records matching the query
const queryFilter = Object.assign(Object.assign({}, Records.convertFilter(filter, dateSort)), { interface: DwnInterfaceName.Records, method: DwnMethodName.Write, isLatestBaseState: true });
const messageSort = this.convertDateSort(dateSort);
return this.messageStore.query(tenant, [queryFilter], messageSort, pagination);
});
}
/**
* Fetches the records as a non-owner.
*
* Filters can support returning both published and unpublished records,
* as well as explicitly only published or only unpublished records.
*
* A) BOTH published and unpublished:
* 1. published records; and
* 2. unpublished records intended for the query author (where `recipient` is the query author); and
* 3. unpublished records authorized by a protocol rule.
*
* B) PUBLISHED:
* 1. only published records;
*
* C) UNPUBLISHED:
* 1. unpublished records intended for the query author (where `recipient` is the query author); and
* 2. unpublished records authorized by a protocol rule.
*
*/
fetchRecordsAsNonOwner(tenant, recordsQuery) {
return __awaiter(this, void 0, void 0, function* () {
const { dateSort, pagination, filter } = recordsQuery.message.descriptor;
const filters = [];
if (Records.filterIncludesPublishedRecords(filter)) {
filters.push(RecordsQueryHandler.buildPublishedRecordsFilter(recordsQuery));
}
if (Records.filterIncludesUnpublishedRecords(filter)) {
filters.push(RecordsQueryHandler.buildUnpublishedRecordsByQueryAuthorFilter(recordsQuery));
const recipientFilter = recordsQuery.message.descriptor.filter.recipient;
if (recipientFilter === undefined || recipientFilter === recordsQuery.author) {
filters.push(RecordsQueryHandler.buildUnpublishedRecordsForQueryAuthorFilter(recordsQuery));
}
if (Records.shouldProtocolAuthorize(recordsQuery.signaturePayload)) {
filters.push(RecordsQueryHandler.buildUnpublishedProtocolAuthorizedRecordsFilter(recordsQuery));
}
}
const messageSort = this.convertDateSort(dateSort);
return this.messageStore.query(tenant, filters, messageSort, pagination);
});
}
/**
* Fetches only published records.
*/
fetchPublishedRecords(tenant, recordsQuery) {
return __awaiter(this, void 0, void 0, function* () {
const { dateSort, pagination } = recordsQuery.message.descriptor;
const filter = RecordsQueryHandler.buildPublishedRecordsFilter(recordsQuery);
const messageSort = this.convertDateSort(dateSort);
return this.messageStore.query(tenant, [filter], messageSort, pagination);
});
}
static buildPublishedRecordsFilter(recordsQuery) {
const { dateSort, filter } = recordsQuery.message.descriptor;
// fetch all published records matching the query
return Object.assign(Object.assign({}, Records.convertFilter(filter, dateSort)), { interface: DwnInterfaceName.Records, method: DwnMethodName.Write, published: true, isLatestBaseState: true });
}
/**
* Creates a filter for unpublished records that are intended for the query author (where `recipient` is the author).
*/
static buildUnpublishedRecordsForQueryAuthorFilter(recordsQuery) {
const { dateSort, filter } = recordsQuery.message.descriptor;
// include records where recipient is query author
return Object.assign(Object.assign({}, Records.convertFilter(filter, dateSort)), { interface: DwnInterfaceName.Records, method: DwnMethodName.Write, recipient: recordsQuery.author, isLatestBaseState: true, published: false });
}
/**
* Creates a filter for unpublished records that are within the specified protocol.
* Validation that `protocol` and other required protocol-related fields occurs before this method.
*/
static buildUnpublishedProtocolAuthorizedRecordsFilter(recordsQuery) {
const { dateSort, filter } = recordsQuery.message.descriptor;
return Object.assign(Object.assign({}, Records.convertFilter(filter, dateSort)), { interface: DwnInterfaceName.Records, method: DwnMethodName.Write, isLatestBaseState: true, published: false });
}
/**
* Creates a filter for only unpublished records where the author is the same as the query author.
*/
static buildUnpublishedRecordsByQueryAuthorFilter(recordsQuery) {
const { dateSort, filter } = recordsQuery.message.descriptor;
// include records where author is the same as the query author
return Object.assign(Object.assign({}, Records.convertFilter(filter, dateSort)), { author: recordsQuery.author, interface: DwnInterfaceName.Records, method: DwnMethodName.Write, isLatestBaseState: true, published: false });
}
/**
* @param messageStore Used to check if the grant has been revoked.
*/
static authorizeRecordsQuery(tenant, recordsQuery, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
if (Message.isSignedByAuthorDelegate(recordsQuery.message)) {
yield recordsQuery.authorizeDelegate(messageStore);
}
// NOTE: not all RecordsQuery messages require protocol authorization even if the filter includes protocol-related fields,
// this is because we dynamically filter out records that the caller is not authorized to see.
// Currently only run protocol authorization if message deliberately invokes a protocol role.
if (Records.shouldProtocolAuthorize(recordsQuery.signaturePayload)) {
yield ProtocolAuthorization.authorizeQueryOrSubscribe(tenant, recordsQuery, messageStore);
}
});
}
}
//# sourceMappingURL=records-query.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,138 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { authenticate } from '../core/auth.js';
import { DataStream } from '../utils/data-stream.js';
import { Encoder } from '../utils/encoder.js';
import { Message } from '../core/message.js';
import { messageReplyFromError } from '../core/message-reply.js';
import { PermissionsProtocol } from '../protocols/permissions.js';
import { ProtocolAuthorization } from '../core/protocol-authorization.js';
import { Records } from '../utils/records.js';
import { RecordsGrantAuthorization } from '../core/records-grant-authorization.js';
import { RecordsRead } from '../interfaces/records-read.js';
import { RecordsWrite } from '../interfaces/records-write.js';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
export class RecordsReadHandler {
constructor(didResolver, messageStore, dataStore) {
this.didResolver = didResolver;
this.messageStore = messageStore;
this.dataStore = dataStore;
}
handle({ tenant, message }) {
return __awaiter(this, void 0, void 0, function* () {
let recordsRead;
try {
recordsRead = yield RecordsRead.parse(message);
}
catch (e) {
return messageReplyFromError(e, 400);
}
// authentication
try {
if (recordsRead.author !== undefined) {
yield authenticate(message.authorization, this.didResolver);
}
}
catch (e) {
return messageReplyFromError(e, 401);
}
// get the latest active messages matching the supplied filter
// only RecordsWrite messages will be returned due to 'isLatestBaseState' being set to true.
const query = Object.assign({ interface: DwnInterfaceName.Records, isLatestBaseState: true }, Records.convertFilter(message.descriptor.filter));
const { messages: existingMessages } = yield this.messageStore.query(tenant, [query]);
if (existingMessages.length === 0) {
return {
status: { code: 404, detail: 'Not Found' }
};
}
else if (existingMessages.length > 1) {
return messageReplyFromError(new DwnError(DwnErrorCode.RecordsReadReturnedMultiple, 'Multiple records exist for the RecordsRead filter'), 400);
}
const matchedRecordsWrite = existingMessages[0];
try {
yield RecordsReadHandler.authorizeRecordsRead(tenant, recordsRead, yield RecordsWrite.parse(matchedRecordsWrite), this.messageStore);
}
catch (error) {
return messageReplyFromError(error, 401);
}
let data;
if (matchedRecordsWrite.encodedData !== undefined) {
const dataBytes = Encoder.base64UrlToBytes(matchedRecordsWrite.encodedData);
data = DataStream.fromBytes(dataBytes);
delete matchedRecordsWrite.encodedData;
}
else {
const result = yield this.dataStore.get(tenant, matchedRecordsWrite.recordId, matchedRecordsWrite.descriptor.dataCid);
if ((result === null || result === void 0 ? void 0 : result.dataStream) === undefined) {
return {
status: { code: 404, detail: 'Not Found' }
};
}
data = result.dataStream;
}
const record = Object.assign(Object.assign({}, matchedRecordsWrite), { data });
// attach initial write if returned RecordsWrite is not initial write
if (!(yield RecordsWrite.isInitialWrite(record))) {
const initialWriteQueryResult = yield this.messageStore.query(tenant, [{ recordId: record.recordId, isLatestBaseState: false, method: DwnMethodName.Write }]);
const initialWrite = initialWriteQueryResult.messages[0];
delete initialWrite.encodedData; // defensive measure but technically optional because we do this when an update RecordsWrite takes place
record.initialWrite = initialWrite;
}
const messageReply = {
status: { code: 200, detail: 'OK' },
record
};
return messageReply;
});
}
;
/**
* @param messageStore Used to check if the grant has been revoked.
*/
static authorizeRecordsRead(tenant, recordsRead, matchedRecordsWrite, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
if (Message.isSignedByAuthorDelegate(recordsRead.message)) {
yield recordsRead.authorizeDelegate(matchedRecordsWrite.message, messageStore);
}
const { descriptor } = matchedRecordsWrite.message;
// if author is the same as the target tenant, we can directly grant access
if (recordsRead.author === tenant) {
return;
}
else if (descriptor.published === true) {
// authentication is not required for published data
return;
}
else if (recordsRead.author !== undefined && recordsRead.author === descriptor.recipient) {
// The recipient of a message may always read it
return;
}
else if (recordsRead.author !== undefined && recordsRead.signaturePayload.permissionGrantId !== undefined) {
const permissionGrant = yield PermissionsProtocol.fetchGrant(tenant, messageStore, recordsRead.signaturePayload.permissionGrantId);
yield RecordsGrantAuthorization.authorizeRead({
recordsReadMessage: recordsRead.message,
recordsWriteMessageToBeRead: matchedRecordsWrite.message,
expectedGrantor: tenant,
expectedGrantee: recordsRead.author,
permissionGrant,
messageStore
});
}
else if (descriptor.protocol !== undefined) {
yield ProtocolAuthorization.authorizeRead(tenant, recordsRead, matchedRecordsWrite, messageStore);
}
else {
throw new DwnError(DwnErrorCode.RecordsReadAuthorizationFailed, 'message failed authorization');
}
});
}
}
//# sourceMappingURL=records-read.js.map
@@ -0,0 +1 @@
{"version":3,"file":"records-read.js","sourceRoot":"","sources":["../../../../src/handlers/records-read.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,171 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { authenticate } from '../core/auth.js';
import { FilterUtility } from '../utils/filter.js';
import { Message } from '../core/message.js';
import { messageReplyFromError } from '../core/message-reply.js';
import { ProtocolAuthorization } from '../core/protocol-authorization.js';
import { Records } from '../utils/records.js';
import { RecordsSubscribe } from '../interfaces/records-subscribe.js';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
export class RecordsSubscribeHandler {
constructor(didResolver, messageStore, eventStream) {
this.didResolver = didResolver;
this.messageStore = messageStore;
this.eventStream = eventStream;
}
handle({ tenant, message, subscriptionHandler }) {
return __awaiter(this, void 0, void 0, function* () {
if (this.eventStream === undefined) {
return messageReplyFromError(new DwnError(DwnErrorCode.RecordsSubscribeEventStreamUnimplemented, 'Subscriptions are not supported'), 501);
}
let recordsSubscribe;
try {
recordsSubscribe = yield RecordsSubscribe.parse(message);
}
catch (e) {
return messageReplyFromError(e, 400);
}
let filters = [];
// if this is an anonymous subscribe and the filter supports published records, subscribe to only published records
if (Records.filterIncludesPublishedRecords(recordsSubscribe.message.descriptor.filter) && recordsSubscribe.author === undefined) {
// build filters for a stream of published records
filters = [RecordsSubscribeHandler.buildPublishedRecordsFilter(recordsSubscribe)];
// delete the undefined authorization property else the code will encounter the following IPLD issue when attempting to generate CID:
// Error: `undefined` is not supported by the IPLD Data Model and cannot be encoded
delete message.authorization;
}
else {
// authentication and authorization
try {
yield authenticate(message.authorization, this.didResolver);
yield RecordsSubscribeHandler.authorizeRecordsSubscribe(tenant, recordsSubscribe, this.messageStore);
}
catch (error) {
return messageReplyFromError(error, 401);
}
if (recordsSubscribe.author === tenant) {
// if the subscribe author is the tenant, filter as owner.
filters = yield RecordsSubscribeHandler.filterAsOwner(recordsSubscribe);
}
else {
// otherwise build filters based on published records, permissions, or protocol rules
filters = yield RecordsSubscribeHandler.filterAsNonOwner(recordsSubscribe);
}
}
const listener = (eventTenant, event, eventIndexes) => {
if (tenant === eventTenant && FilterUtility.matchAnyFilter(eventIndexes, filters)) {
// the filters check for interface and method
// if matched the message is either a `RecordsWriteMessage` or `RecordsDeleteMessage` so we cast the event to a `RecordEvent`
subscriptionHandler(event);
}
};
const messageCid = yield Message.getCid(message);
const subscription = yield this.eventStream.subscribe(tenant, messageCid, listener);
return {
status: { code: 200, detail: 'OK' },
subscription
};
});
}
/**
* Subscribe to records as the owner of the DWN with no additional filtering.
*/
static filterAsOwner(RecordsSubscribe) {
return __awaiter(this, void 0, void 0, function* () {
const { filter } = RecordsSubscribe.message.descriptor;
const subscribeFilter = Object.assign(Object.assign({}, Records.convertFilter(filter)), { interface: DwnInterfaceName.Records, method: [DwnMethodName.Write, DwnMethodName.Delete] });
return [subscribeFilter];
});
}
/**
* Creates filters in order to subscribe to records as a non-owner.
*
* Filters can support emitting messages for both published and unpublished records,
* as well as explicitly only published or only unpublished records.
*
* A) BOTH published and unpublished:
* 1. published records; and
* 2. unpublished records intended for the subscription author (where `recipient` is the subscription author); and
* 3. unpublished records authorized by a protocol rule.
*
* B) PUBLISHED:
* 1. only published records;
*
* C) UNPUBLISHED:
* 1. unpublished records intended for the subscription author (where `recipient` is the subscription author); and
* 2. unpublished records authorized by a protocol rule.
*/
static filterAsNonOwner(recordsSubscribe) {
return __awaiter(this, void 0, void 0, function* () {
const filters = [];
const { filter } = recordsSubscribe.message.descriptor;
if (Records.filterIncludesPublishedRecords(filter)) {
filters.push(RecordsSubscribeHandler.buildPublishedRecordsFilter(recordsSubscribe));
}
if (Records.filterIncludesUnpublishedRecords(filter)) {
filters.push(RecordsSubscribeHandler.buildUnpublishedRecordsBySubscribeAuthorFilter(recordsSubscribe));
const recipientFilter = recordsSubscribe.message.descriptor.filter.recipient;
if (recipientFilter === undefined || recipientFilter === recordsSubscribe.author) {
filters.push(RecordsSubscribeHandler.buildUnpublishedRecordsForSubscribeAuthorFilter(recordsSubscribe));
}
if (Records.shouldProtocolAuthorize(recordsSubscribe.signaturePayload)) {
filters.push(RecordsSubscribeHandler.buildUnpublishedProtocolAuthorizedRecordsFilter(recordsSubscribe));
}
}
return filters;
});
}
/**
* Creates a filter for all published records matching the subscribe
*/
static buildPublishedRecordsFilter(recordsSubscribe) {
return Object.assign(Object.assign({}, Records.convertFilter(recordsSubscribe.message.descriptor.filter)), { interface: DwnInterfaceName.Records, method: [DwnMethodName.Write, DwnMethodName.Delete], published: true });
}
/**
* Creates a filter for unpublished records that are intended for the subscribe author (where `recipient` is the author).
*/
static buildUnpublishedRecordsForSubscribeAuthorFilter(recordsSubscribe) {
// include records where recipient is subscribe author
return Object.assign(Object.assign({}, Records.convertFilter(recordsSubscribe.message.descriptor.filter)), { interface: DwnInterfaceName.Records, method: [DwnMethodName.Write, DwnMethodName.Delete], recipient: recordsSubscribe.author, published: false });
}
/**
* Creates a filter for unpublished records that are within the specified protocol.
* Validation that `protocol` and other required protocol-related fields occurs before this method.
*/
static buildUnpublishedProtocolAuthorizedRecordsFilter(recordsSubscribe) {
return Object.assign(Object.assign({}, Records.convertFilter(recordsSubscribe.message.descriptor.filter)), { interface: DwnInterfaceName.Records, method: [DwnMethodName.Write, DwnMethodName.Delete], published: false });
}
/**
* Creates a filter for only unpublished records where the author is the same as the subscribe author.
*/
static buildUnpublishedRecordsBySubscribeAuthorFilter(recordsSubscribe) {
// include records where author is the same as the subscribe author
return Object.assign(Object.assign({}, Records.convertFilter(recordsSubscribe.message.descriptor.filter)), { author: recordsSubscribe.author, interface: DwnInterfaceName.Records, method: [DwnMethodName.Write, DwnMethodName.Delete], published: false });
}
/**
* @param messageStore Used to check if the grant has been revoked.
*/
static authorizeRecordsSubscribe(tenant, recordsSubscribe, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
if (Message.isSignedByAuthorDelegate(recordsSubscribe.message)) {
yield recordsSubscribe.authorizeDelegate(messageStore);
}
// NOTE: not all RecordsSubscribe messages require protocol authorization even if the filter includes protocol-related fields,
// this is because we dynamically filter out records that the caller is not authorized to see.
// Currently only run protocol authorization if message deliberately invokes a protocol role.
if (Records.shouldProtocolAuthorize(recordsSubscribe.signaturePayload)) {
yield ProtocolAuthorization.authorizeQueryOrSubscribe(tenant, recordsSubscribe, messageStore);
}
});
}
}
//# sourceMappingURL=records-subscribe.js.map
@@ -0,0 +1 @@
{"version":3,"file":"records-subscribe.js","sourceRoot":"","sources":["../../../../src/handlers/records-subscribe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,310 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { authenticate } from '../core/auth.js';
import { Cid } from '../utils/cid.js';
import { DataStream } from '../utils/data-stream.js';
import { DwnConstant } from '../core/dwn-constant.js';
import { Encoder } from '../utils/encoder.js';
import { Message } from '../core/message.js';
import { messageReplyFromError } from '../core/message-reply.js';
import { PermissionsProtocol } from '../protocols/permissions.js';
import { ProtocolAuthorization } from '../core/protocol-authorization.js';
import { RecordsGrantAuthorization } from '../core/records-grant-authorization.js';
import { RecordsWrite } from '../interfaces/records-write.js';
import { StorageController } from '../store/storage-controller.js';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
export class RecordsWriteHandler {
constructor(didResolver, messageStore, dataStore, eventLog, eventStream) {
this.didResolver = didResolver;
this.messageStore = messageStore;
this.dataStore = dataStore;
this.eventLog = eventLog;
this.eventStream = eventStream;
}
handle({ tenant, message, dataStream }) {
return __awaiter(this, void 0, void 0, function* () {
let recordsWrite;
try {
recordsWrite = yield RecordsWrite.parse(message);
// Protocol-authorized record specific validation
if (message.descriptor.protocol !== undefined) {
yield ProtocolAuthorization.validateReferentialIntegrity(tenant, recordsWrite, this.messageStore);
}
}
catch (e) {
return messageReplyFromError(e, 400);
}
// authentication & authorization
try {
yield authenticate(message.authorization, this.didResolver);
yield RecordsWriteHandler.authorizeRecordsWrite(tenant, recordsWrite, this.messageStore);
}
catch (e) {
return messageReplyFromError(e, 401);
}
// get existing messages matching the `recordId`
const query = {
interface: DwnInterfaceName.Records,
recordId: message.recordId
};
const { messages: existingMessages } = yield this.messageStore.query(tenant, [query]);
// if the incoming write is not the initial write, then it must not modify any immutable properties defined by the initial write
const newMessageIsInitialWrite = yield recordsWrite.isInitialWrite();
let initialWrite;
if (!newMessageIsInitialWrite) {
try {
initialWrite = yield RecordsWrite.getInitialWrite(existingMessages);
RecordsWrite.verifyEqualityOfImmutableProperties(initialWrite, message);
}
catch (e) {
return messageReplyFromError(e, 400);
}
}
const newestExistingMessage = yield Message.getNewestMessage(existingMessages);
let incomingMessageIsNewest = false;
let newestMessage; // keep reference of newest message for pruning later
if (newestExistingMessage === undefined || (yield Message.isNewer(message, newestExistingMessage))) {
incomingMessageIsNewest = true;
newestMessage = message;
}
else { // existing message is the same age or newer than the incoming message
newestMessage = newestExistingMessage;
}
if (!incomingMessageIsNewest) {
return {
status: { code: 409, detail: 'Conflict' }
};
}
try {
// NOTE: We allow isLatestBaseState to be true ONLY if the incoming message comes with data, or if the incoming message is NOT an initial write
// This would allow an initial write to be written to the DB without data, but having it not queryable,
// because query implementation filters on `isLatestBaseState` being `true`
// thus preventing a user's attempt to gain authorized access to data by referencing the dataCid of a private data in their initial writes,
// See: https://github.com/TBD54566975/dwn-sdk-js/issues/359 for more info
let isLatestBaseState = false;
let messageWithOptionalEncodedData = message;
if (dataStream !== undefined) {
messageWithOptionalEncodedData = yield this.processMessageWithDataStream(tenant, message, dataStream);
isLatestBaseState = true;
}
else {
// else data stream is NOT provided
if ((newestExistingMessage === null || newestExistingMessage === void 0 ? void 0 : newestExistingMessage.descriptor.method) === DwnMethodName.Delete) {
throw new DwnError(DwnErrorCode.RecordsWriteMissingDataStream, 'No data stream was provided with the previous message being a delete');
}
// at this point we know that newestExistingMessage exists is not a Delete
// if the incoming message is not an initial write, and no dataStream is provided, we would allow it provided it passes validation
// processMessageWithoutDataStream() abstracts that logic
if (!newMessageIsInitialWrite) {
const newestExistingWrite = newestExistingMessage;
messageWithOptionalEncodedData = yield this.processMessageWithoutDataStream(tenant, message, newestExistingWrite);
isLatestBaseState = true;
}
}
const indexes = yield recordsWrite.constructIndexes(isLatestBaseState);
yield this.messageStore.put(tenant, messageWithOptionalEncodedData, indexes);
yield this.eventLog.append(tenant, yield Message.getCid(message), indexes);
// NOTE: We only emit a `RecordsWrite` when the message is the latest base state.
// Because we allow a `RecordsWrite` which is not the latest state to be written, but not queried, we shouldn't emit it either.
// It will be emitted as a part of a subsequent next write, if it is the latest base state.
if (this.eventStream !== undefined && isLatestBaseState) {
this.eventStream.emit(tenant, { message, initialWrite }, indexes);
}
}
catch (error) {
const e = error;
if (e.code !== undefined) {
if (e.code === DwnErrorCode.RecordsWriteMissingEncodedDataInPrevious ||
e.code === DwnErrorCode.RecordsWriteMissingDataInPrevious ||
e.code === DwnErrorCode.RecordsWriteMissingDataStream ||
e.code === DwnErrorCode.RecordsWriteDataCidMismatch ||
e.code === DwnErrorCode.RecordsWriteDataSizeMismatch ||
e.code.startsWith('PermissionsProtocolValidate') ||
e.code.startsWith('SchemaValidator')) {
return messageReplyFromError(error, 400);
}
}
// else throw
throw error;
}
const messageReply = {
status: { code: 202, detail: 'Accepted' }
};
// delete all existing messages of the same record that are not newest, except for the initial write
yield StorageController.deleteAllOlderMessagesButKeepInitialWrite(tenant, existingMessages, newestMessage, this.messageStore, this.dataStore, this.eventLog);
yield this.postProcessingForCoreRecordsWrite(tenant, recordsWrite);
return messageReply;
});
}
;
static validateSchemaForCoreRecordsWrite(recordsWriteMessage, dataBytes) {
if (recordsWriteMessage.descriptor.protocol === PermissionsProtocol.uri) {
PermissionsProtocol.validateSchema(recordsWriteMessage, dataBytes);
}
}
/**
* Performs additional necessary tasks if the RecordsWrite handled is a core DWN RecordsWrite that need additional processing.
* For instance: a Permission revocation RecordsWrite.
*/
postProcessingForCoreRecordsWrite(tenant, recordsWrite) {
return __awaiter(this, void 0, void 0, function* () {
// If this message is a Permission revocation, we need to delete all grant-authorized messages with timestamp after revocation
// TODO: https://github.com/TBD54566975/dwn-sdk-js/issues/716
// This code is a direct copy and paste from the original PermissionsRevokeHandler (no longer exists),
// but it appears that there was no test for it and it does not look like the code worked:
// - not seeing `permissionGrantId` being an index
// - not seeing `this.dataStore` being called to delete actual data
// - test coverage is missing for the main delete logic
if (recordsWrite.message.descriptor.protocol === PermissionsProtocol.uri &&
recordsWrite.message.descriptor.protocolPath === PermissionsProtocol.revocationPath) {
const permissionGrantId = recordsWrite.message.descriptor.parentId;
const grantAuthorizedMessagesQuery = {
permissionGrantId,
dateCreated: { gte: recordsWrite.message.descriptor.messageTimestamp },
};
const { messages: grantAuthorizedMessagesAfterRevoke } = yield this.messageStore.query(tenant, [grantAuthorizedMessagesQuery]);
const grantAuthorizedMessageCidsAfterRevoke = [];
for (const grantAuthorizedMessage of grantAuthorizedMessagesAfterRevoke) {
const messageCid = yield Message.getCid(grantAuthorizedMessage);
yield this.messageStore.delete(tenant, messageCid);
}
this.eventLog.deleteEventsByCid(tenant, grantAuthorizedMessageCidsAfterRevoke);
}
});
}
/**
* Returns a `RecordsQueryReplyEntry` with a copy of the incoming message and the incoming data encoded to `Base64URL`.
*/
cloneAndAddEncodedData(message, dataBytes) {
return __awaiter(this, void 0, void 0, function* () {
const recordsWrite = Object.assign({}, message);
recordsWrite.encodedData = Encoder.bytesToBase64Url(dataBytes);
return recordsWrite;
});
}
processMessageWithDataStream(tenant, message, dataStream) {
return __awaiter(this, void 0, void 0, function* () {
let messageWithOptionalEncodedData = message;
// if data is below the threshold, we store it within MessageStore
if (message.descriptor.dataSize <= DwnConstant.maxDataSizeAllowedToBeEncoded) {
// validate data integrity before setting.
const dataBytes = yield DataStream.toBytes(dataStream);
const dataCid = yield Cid.computeDagPbCidFromBytes(dataBytes);
RecordsWriteHandler.validateDataIntegrity(message.descriptor.dataCid, message.descriptor.dataSize, dataCid, dataBytes.length);
RecordsWriteHandler.validateSchemaForCoreRecordsWrite(message, dataBytes);
messageWithOptionalEncodedData = yield this.cloneAndAddEncodedData(message, dataBytes);
}
else {
// split the dataStream into two: one for CID computation and one for storage
const [dataStreamCopy1, dataStreamCopy2] = DataStream.duplicateDataStream(dataStream, 2);
try {
// perform storage and CID computation in parallel
const [dataCid, DataStorePutResult] = yield Promise.all([
Cid.computeDagPbCidFromStream(dataStreamCopy1),
this.dataStore.put(tenant, message.recordId, message.descriptor.dataCid, dataStreamCopy2)
]);
RecordsWriteHandler.validateDataIntegrity(message.descriptor.dataCid, message.descriptor.dataSize, dataCid, DataStorePutResult.dataSize);
}
catch (error) {
// unwind/delete data if we have issue with storage or the data failed integrity validation
yield this.dataStore.delete(tenant, message.recordId, message.descriptor.dataCid);
throw error;
}
}
return messageWithOptionalEncodedData;
});
}
processMessageWithoutDataStream(tenant, message, newestExistingWrite) {
return __awaiter(this, void 0, void 0, function* () {
const messageWithOptionalEncodedData = Object.assign({}, message); // clone
const { dataCid, dataSize } = message.descriptor;
// Since incoming message is not an initial write, and no dataStream is provided, we first check integrity against newest existing write.
// we preform the dataCid check in case a user attempts to gain access to data by referencing a different known dataCid,
// so we insure that the data is already associated with the existing newest message
// See: https://github.com/TBD54566975/dwn-sdk-js/issues/359 for more info
RecordsWriteHandler.validateDataIntegrity(dataCid, dataSize, newestExistingWrite.descriptor.dataCid, newestExistingWrite.descriptor.dataSize);
if (dataSize <= DwnConstant.maxDataSizeAllowedToBeEncoded) {
// we encode the data from the original write if it is smaller than the data-store threshold
if (newestExistingWrite.encodedData !== undefined) {
messageWithOptionalEncodedData.encodedData = newestExistingWrite.encodedData;
}
else {
throw new DwnError(DwnErrorCode.RecordsWriteMissingEncodedDataInPrevious, `No dataStream was provided and unable to get data from previous message`);
}
}
else {
// else just make sure the data is in the data store
// attempt to retrieve the data from the previous message
const DataStoreGetResult = yield this.dataStore.get(tenant, newestExistingWrite.recordId, message.descriptor.dataCid);
if (DataStoreGetResult === undefined) {
throw new DwnError(DwnErrorCode.RecordsWriteMissingDataInPrevious, `No dataStream was provided and unable to get data from previous message`);
}
}
return messageWithOptionalEncodedData;
});
}
/**
* Validates the expected `dataCid` and `dataSize` in the descriptor vs the received data.
*
* @throws {DwnError} with `DwnErrorCode.RecordsWriteDataCidMismatch`
* if the data stream resulted in a data CID that mismatches with `dataCid` in the given message
* @throws {DwnError} with `DwnErrorCode.RecordsWriteDataSizeMismatch`
* if `dataSize` in `descriptor` given mismatches the actual data size
*/
static validateDataIntegrity(expectedDataCid, expectedDataSize, actualDataCid, actualDataSize) {
if (expectedDataCid !== actualDataCid) {
throw new DwnError(DwnErrorCode.RecordsWriteDataCidMismatch, `actual data CID ${actualDataCid} does not match dataCid in descriptor: ${expectedDataCid}`);
}
if (expectedDataSize !== actualDataSize) {
throw new DwnError(DwnErrorCode.RecordsWriteDataSizeMismatch, `actual data size ${actualDataSize} bytes does not match dataSize in descriptor: ${expectedDataSize}`);
}
}
static authorizeRecordsWrite(tenant, recordsWrite, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
// if owner signature is given (`owner` is not `undefined`), it must be the same as the tenant DID
if (recordsWrite.owner !== undefined && recordsWrite.owner !== tenant) {
throw new DwnError(DwnErrorCode.RecordsWriteOwnerAndTenantMismatch, `Owner ${recordsWrite.owner} must be the same as tenant ${tenant} when specified.`);
}
if (recordsWrite.isSignedByAuthorDelegate) {
yield recordsWrite.authorizeAuthorDelegate(messageStore);
}
if (recordsWrite.isSignedByOwnerDelegate) {
yield recordsWrite.authorizeOwnerDelegate(messageStore);
}
if (recordsWrite.owner !== undefined) {
// if incoming message is a write retained by this tenant, we by-design always allow
// NOTE: the "owner === tenant" check is already done earlier in this method
return;
}
else if (recordsWrite.author === tenant) {
// if author is the same as the target tenant, we can directly grant access
return;
}
else if (recordsWrite.author !== undefined && recordsWrite.signaturePayload.permissionGrantId !== undefined) {
const permissionGrant = yield PermissionsProtocol.fetchGrant(tenant, messageStore, recordsWrite.signaturePayload.permissionGrantId);
yield RecordsGrantAuthorization.authorizeWrite({
recordsWriteMessage: recordsWrite.message,
expectedGrantor: tenant,
expectedGrantee: recordsWrite.author,
permissionGrant,
messageStore
});
}
else if (recordsWrite.message.descriptor.protocol !== undefined) {
yield ProtocolAuthorization.authorizeWrite(tenant, recordsWrite, messageStore);
}
else {
throw new DwnError(DwnErrorCode.RecordsWriteAuthorizationFailed, 'message failed authorization');
}
});
}
}
//# sourceMappingURL=records-write.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,42 @@
export { authenticate } from './core/auth.js';
export { AllowAllTenantGate } from './core/tenant-gate.js';
export { Cid } from './utils/cid.js';
export { RecordsQuery } from './interfaces/records-query.js';
export { DataStream } from './utils/data-stream.js';
export { DateSort } from './types/records-types.js';
export { HdKey, KeyDerivationScheme } from './utils/hd-key.js';
export { Dwn } from './dwn.js';
export { DwnConstant } from './core/dwn-constant.js';
export { DwnError, DwnErrorCode } from './core/dwn-error.js';
export { DwnInterfaceName, DwnMethodName } from './enums/dwn-interface-method.js';
export { Encoder } from './utils/encoder.js';
export { EventsGet } from './interfaces/events-get.js';
export { EventsQuery } from './interfaces/events-query.js';
export { EventsSubscribe } from './interfaces/events-subscribe.js';
export { Encryption, EncryptionAlgorithm } from './utils/encryption.js';
export { RecordsWrite } from './interfaces/records-write.js';
export { executeUnlessAborted } from './utils/abort.js';
export { Jws } from './utils/jws.js';
export { Message } from './core/message.js';
export { MessagesGet } from './interfaces/messages-get.js';
export { PermissionsProtocol } from './protocols/permissions.js';
export { PrivateKeySigner } from './utils/private-key-signer.js';
export { Protocols } from './utils/protocols.js';
export { ProtocolsConfigure } from './interfaces/protocols-configure.js';
export { ProtocolsQuery } from './interfaces/protocols-query.js';
export { Records } from './utils/records.js';
export { RecordsDelete } from './interfaces/records-delete.js';
export { RecordsRead } from './interfaces/records-read.js';
export { RecordsSubscribe } from './interfaces/records-subscribe.js';
export { Secp256k1 } from './utils/secp256k1.js';
export { Secp256r1 } from './utils/secp256r1.js';
export { SortDirection } from './types/query-types.js';
export { Time } from './utils/time.js';
// concrete implementations of stores and event stream
export { DataStoreLevel } from './store/data-store-level.js';
export { EventLogLevel } from './event-log/event-log-level.js';
export { MessageStoreLevel } from './store/message-store-level.js';
export { EventEmitterStream } from './event-log/event-emitter-stream.js';
// test library exports
export { TestDataGenerator } from '../tests/utils/test-data-generator.js';
//# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAA2B,kBAAkB,EAAc,MAAM,uBAAuB,CAAC;AAChG,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAE,YAAY,EAAuB,MAAM,+BAA+B,CAAC;AAElF,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAqB,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAClF,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAClF,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAoB,MAAM,4BAA4B,CAAC;AACzE,OAAO,EAAE,WAAW,EAAsB,MAAM,8BAA8B,CAAC;AAC/E,OAAO,EAAE,eAAe,EAA0B,MAAM,kCAAkC,CAAC;AAC3F,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAAuC,YAAY,EAA0C,MAAM,+BAA+B,CAAC;AAC1I,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAErC,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAsB,MAAM,8BAA8B,CAAC;AAG/E,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAA6B,MAAM,qCAAqC,CAAC;AACpG,OAAO,EAAE,cAAc,EAAyB,MAAM,iCAAiC,CAAC;AACxF,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAwB,MAAM,gCAAgC,CAAC;AACrF,OAAO,EAAE,WAAW,EAAsB,MAAM,8BAA8B,CAAC;AAC/E,OAAO,EAAE,gBAAgB,EAA2B,MAAM,mCAAmC,CAAC;AAC9F,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAEvC,sDAAsD;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAEzE,uBAAuB;AACvB,OAAO,EAAW,iBAAiB,EAAE,MAAM,uCAAuC,CAAC"}
@@ -0,0 +1,41 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { AbstractMessage } from '../core/abstract-message.js';
import { Message } from '../core/message.js';
import { Time } from '../utils/time.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
export class EventsGet extends AbstractMessage {
static parse(message) {
return __awaiter(this, void 0, void 0, function* () {
Message.validateJsonSchema(message);
yield Message.validateSignatureStructure(message.authorization.signature, message.descriptor);
Time.validateTimestamp(message.descriptor.messageTimestamp);
return new EventsGet(message);
});
}
static create(options) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const descriptor = {
interface: DwnInterfaceName.Events,
method: DwnMethodName.Get,
messageTimestamp: (_a = options.messageTimestamp) !== null && _a !== void 0 ? _a : Time.getCurrentTimestamp(),
};
if (options.cursor) {
descriptor.cursor = options.cursor;
}
const authorization = yield Message.createAuthorization({ descriptor, signer: options.signer });
const message = { descriptor, authorization };
Message.validateJsonSchema(message);
return new EventsGet(message);
});
}
}
//# sourceMappingURL=events-get.js.map
@@ -0,0 +1 @@
{"version":3,"file":"events-get.js","sourceRoot":"","sources":["../../../../src/interfaces/events-get.ts"],"names":[],"mappings":";;;;;;;;;AAIA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAQnF,MAAM,OAAO,SAAU,SAAQ,eAAiC;IAEvD,MAAM,CAAO,KAAK,CAAC,OAAyB;;YACjD,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;YACpC,MAAM,OAAO,CAAC,0BAA0B,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;YAC9F,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;YAE5D,OAAO,IAAI,SAAS,CAAC,OAAO,CAAC,CAAC;QAChC,CAAC;KAAA;IAEM,MAAM,CAAO,MAAM,CAAC,OAAyB;;;YAClD,MAAM,UAAU,GAAwB;gBACtC,SAAS,EAAU,gBAAgB,CAAC,MAAM;gBAC1C,MAAM,EAAa,aAAa,CAAC,GAAG;gBACpC,gBAAgB,EAAG,MAAA,OAAO,CAAC,gBAAgB,mCAAI,IAAI,CAAC,mBAAmB,EAAE;aAC1E,CAAC;YAEF,IAAI,OAAO,CAAC,MAAM,EAAE;gBAClB,UAAU,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;aACpC;YAED,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,mBAAmB,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;YAChG,MAAM,OAAO,GAAG,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC;YAE9C,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;YAEpC,OAAO,IAAI,SAAS,CAAC,OAAO,CAAC,CAAC;;KAC/B;CACF"}
@@ -0,0 +1,51 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { AbstractMessage } from '../core/abstract-message.js';
import { Events } from '../utils/events.js';
import { Message } from '../core/message.js';
import { removeUndefinedProperties } from '../utils/object.js';
import { Time } from '../utils/time.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
import { validateProtocolUrlNormalized, validateSchemaUrlNormalized } from '../utils/url.js';
export class EventsQuery extends AbstractMessage {
static parse(message) {
return __awaiter(this, void 0, void 0, function* () {
Message.validateJsonSchema(message);
yield Message.validateSignatureStructure(message.authorization.signature, message.descriptor);
for (const filter of message.descriptor.filters) {
if ('protocol' in filter && filter.protocol !== undefined) {
validateProtocolUrlNormalized(filter.protocol);
}
if ('schema' in filter && filter.schema !== undefined) {
validateSchemaUrlNormalized(filter.schema);
}
}
return new EventsQuery(message);
});
}
static create(options) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const descriptor = {
interface: DwnInterfaceName.Events,
method: DwnMethodName.Query,
filters: Events.normalizeFilters(options.filters),
messageTimestamp: (_a = options.messageTimestamp) !== null && _a !== void 0 ? _a : Time.getCurrentTimestamp(),
cursor: options.cursor,
};
removeUndefinedProperties(descriptor);
const authorization = yield Message.createAuthorization({ descriptor, signer: options.signer });
const message = { descriptor, authorization };
Message.validateJsonSchema(message);
return new EventsQuery(message);
});
}
}
//# sourceMappingURL=events-query.js.map
@@ -0,0 +1 @@
{"version":3,"file":"events-query.js","sourceRoot":"","sources":["../../../../src/interfaces/events-query.ts"],"names":[],"mappings":";;;;;;;;;AAIA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,EAAE,6BAA6B,EAAE,2BAA2B,EAAE,MAAM,iBAAiB,CAAC;AAS7F,MAAM,OAAO,WAAY,SAAQ,eAAmC;IAE3D,MAAM,CAAO,KAAK,CAAC,OAA2B;;YACnD,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;YACpC,MAAM,OAAO,CAAC,0BAA0B,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;YAE9F,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,UAAU,CAAC,OAAO,EAAE;gBAC/C,IAAI,UAAU,IAAI,MAAM,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,EAAE;oBACzD,6BAA6B,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;iBAChD;gBACD,IAAI,QAAQ,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE;oBACrD,2BAA2B,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;iBAC5C;aACF;YAED,OAAO,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC;QAClC,CAAC;KAAA;IAEM,MAAM,CAAO,MAAM,CAAC,OAA2B;;;YACpD,MAAM,UAAU,GAA0B;gBACxC,SAAS,EAAU,gBAAgB,CAAC,MAAM;gBAC1C,MAAM,EAAa,aAAa,CAAC,KAAK;gBACtC,OAAO,EAAY,MAAM,CAAC,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC;gBAC3D,gBAAgB,EAAG,MAAA,OAAO,CAAC,gBAAgB,mCAAI,IAAI,CAAC,mBAAmB,EAAE;gBACzE,MAAM,EAAa,OAAO,CAAC,MAAM;aAClC,CAAC;YAEF,yBAAyB,CAAC,UAAU,CAAC,CAAC;YAEtC,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,mBAAmB,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;YAChG,MAAM,OAAO,GAAG,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC;YAE9C,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;YAEpC,OAAO,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC;;KACjC;CACF"}
@@ -0,0 +1,59 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { AbstractMessage } from '../core/abstract-message.js';
import { Message } from '../core/message.js';
import { removeUndefinedProperties } from '../utils/object.js';
import { Time } from '../utils/time.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
import { validateProtocolUrlNormalized, validateSchemaUrlNormalized } from '../utils/url.js';
export class EventsSubscribe extends AbstractMessage {
static parse(message) {
return __awaiter(this, void 0, void 0, function* () {
Message.validateJsonSchema(message);
yield Message.validateSignatureStructure(message.authorization.signature, message.descriptor);
for (const filter of message.descriptor.filters) {
if ('protocol' in filter && filter.protocol !== undefined) {
validateProtocolUrlNormalized(filter.protocol);
}
if ('schema' in filter && filter.schema !== undefined) {
validateSchemaUrlNormalized(filter.schema);
}
}
Time.validateTimestamp(message.descriptor.messageTimestamp);
return new EventsSubscribe(message);
});
}
/**
* Creates a EventsSubscribe message.
*
* @throws {DwnError} if json schema validation fails.
*/
static create(options) {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () {
const currentTime = Time.getCurrentTimestamp();
const descriptor = {
interface: DwnInterfaceName.Events,
method: DwnMethodName.Subscribe,
filters: (_a = options.filters) !== null && _a !== void 0 ? _a : [],
messageTimestamp: (_b = options.messageTimestamp) !== null && _b !== void 0 ? _b : currentTime,
};
removeUndefinedProperties(descriptor);
const authorization = yield Message.createAuthorization({
descriptor,
signer: options.signer
});
const message = { descriptor, authorization };
Message.validateJsonSchema(message);
return new EventsSubscribe(message);
});
}
}
//# sourceMappingURL=events-subscribe.js.map
@@ -0,0 +1 @@
{"version":3,"file":"events-subscribe.js","sourceRoot":"","sources":["../../../../src/interfaces/events-subscribe.ts"],"names":[],"mappings":";;;;;;;;;AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,EAAE,6BAA6B,EAAE,2BAA2B,EAAE,MAAM,iBAAiB,CAAC;AAS7F,MAAM,OAAO,eAAgB,SAAQ,eAAuC;IACnE,MAAM,CAAO,KAAK,CAAC,OAA+B;;YACvD,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;YACpC,MAAM,OAAO,CAAC,0BAA0B,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;YAE9F,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,UAAU,CAAC,OAAO,EAAE;gBAC/C,IAAI,UAAU,IAAI,MAAM,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,EAAE;oBACzD,6BAA6B,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;iBAChD;gBACD,IAAI,QAAQ,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE;oBACrD,2BAA2B,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;iBAC5C;aACF;YAED,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;YAC5D,OAAO,IAAI,eAAe,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC;KAAA;IAED;;;;OAIG;IACI,MAAM,CAAO,MAAM,CACxB,OAA+B;;;YAE/B,MAAM,WAAW,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAE/C,MAAM,UAAU,GAA8B;gBAC5C,SAAS,EAAU,gBAAgB,CAAC,MAAM;gBAC1C,MAAM,EAAa,aAAa,CAAC,SAAS;gBAC1C,OAAO,EAAY,MAAA,OAAO,CAAC,OAAO,mCAAI,EAAE;gBACxC,gBAAgB,EAAG,MAAA,OAAO,CAAC,gBAAgB,mCAAI,WAAW;aAC3D,CAAC;YAEF,yBAAyB,CAAC,UAAU,CAAC,CAAC;YAEtC,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,mBAAmB,CAAC;gBACtD,UAAU;gBACV,MAAM,EAAE,OAAO,CAAC,MAAM;aACvB,CAAC,CAAC;YAEH,MAAM,OAAO,GAA2B,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC;YACtE,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;YACpC,OAAO,IAAI,eAAe,CAAC,OAAO,CAAC,CAAC;;KACrC;CACF"}
@@ -0,0 +1,58 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { AbstractMessage } from '../core/abstract-message.js';
import { Cid } from '../utils/cid.js';
import { Message } from '../core/message.js';
import { Time } from '../utils/time.js';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
export class MessagesGet extends AbstractMessage {
static parse(message) {
return __awaiter(this, void 0, void 0, function* () {
Message.validateJsonSchema(message);
this.validateMessageCids(message.descriptor.messageCids);
yield Message.validateSignatureStructure(message.authorization.signature, message.descriptor);
Time.validateTimestamp(message.descriptor.messageTimestamp);
return new MessagesGet(message);
});
}
static create(options) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const descriptor = {
interface: DwnInterfaceName.Messages,
method: DwnMethodName.Get,
messageCids: options.messageCids,
messageTimestamp: (_a = options === null || options === void 0 ? void 0 : options.messageTimestamp) !== null && _a !== void 0 ? _a : Time.getCurrentTimestamp(),
};
const authorization = yield Message.createAuthorization({ descriptor, signer: options.signer });
const message = { descriptor, authorization };
Message.validateJsonSchema(message);
MessagesGet.validateMessageCids(options.messageCids);
return new MessagesGet(message);
});
}
/**
* validates the provided cids
* @param messageCids - the cids in question
* @throws {DwnError} if an invalid cid is found.
*/
static validateMessageCids(messageCids) {
for (const cid of messageCids) {
try {
Cid.parseCid(cid);
}
catch (_) {
throw new DwnError(DwnErrorCode.MessageGetInvalidCid, `${cid} is not a valid CID`);
}
}
}
}
//# sourceMappingURL=messages-get.js.map
@@ -0,0 +1 @@
{"version":3,"file":"messages-get.js","sourceRoot":"","sources":["../../../../src/interfaces/messages-get.ts"],"names":[],"mappings":";;;;;;;;;AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAQnF,MAAM,OAAO,WAAY,SAAQ,eAAmC;IAC3D,MAAM,CAAO,KAAK,CAAC,OAA2B;;YACnD,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;YACpC,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;YAEzD,MAAM,OAAO,CAAC,0BAA0B,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;YAC9F,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;YAE5D,OAAO,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC;QAClC,CAAC;KAAA;IAEM,MAAM,CAAO,MAAM,CAAC,OAA2B;;;YACpD,MAAM,UAAU,GAA0B;gBACxC,SAAS,EAAU,gBAAgB,CAAC,QAAQ;gBAC5C,MAAM,EAAa,aAAa,CAAC,GAAG;gBACpC,WAAW,EAAQ,OAAO,CAAC,WAAW;gBACtC,gBAAgB,EAAG,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,gBAAgB,mCAAI,IAAI,CAAC,mBAAmB,EAAE;aAC3E,CAAC;YAEF,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,mBAAmB,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;YAChG,MAAM,OAAO,GAAG,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC;YAE9C,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;YACpC,WAAW,CAAC,mBAAmB,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;YAErD,OAAO,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC;;KACjC;IAED;;;;OAIG;IACK,MAAM,CAAC,mBAAmB,CAAC,WAAqB;QACtD,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE;YAC7B,IAAI;gBACF,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;aACnB;YAAC,OAAO,CAAC,EAAE;gBACV,MAAM,IAAI,QAAQ,CAAC,YAAY,CAAC,oBAAoB,EAAE,GAAG,GAAG,qBAAqB,CAAC,CAAC;aACpF;SACF;IACH,CAAC;CACF"}
@@ -0,0 +1,244 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import { AbstractMessage } from '../core/abstract-message.js';
import Ajv from 'ajv/dist/2020.js';
import { Message } from '../core/message.js';
import { Time } from '../utils/time.js';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
import { normalizeProtocolUrl, normalizeSchemaUrl, validateProtocolUrlNormalized, validateSchemaUrlNormalized } from '../utils/url.js';
import { ProtocolAction, ProtocolActor } from '../types/protocols-types.js';
export class ProtocolsConfigure extends AbstractMessage {
static parse(message) {
return __awaiter(this, void 0, void 0, function* () {
Message.validateJsonSchema(message);
ProtocolsConfigure.validateProtocolDefinition(message.descriptor.definition);
yield Message.validateSignatureStructure(message.authorization.signature, message.descriptor);
Time.validateTimestamp(message.descriptor.messageTimestamp);
return new ProtocolsConfigure(message);
});
}
static create(options) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const descriptor = {
interface: DwnInterfaceName.Protocols,
method: DwnMethodName.Configure,
messageTimestamp: (_a = options.messageTimestamp) !== null && _a !== void 0 ? _a : Time.getCurrentTimestamp(),
definition: ProtocolsConfigure.normalizeDefinition(options.definition)
};
const authorization = yield Message.createAuthorization({
descriptor,
signer: options.signer,
permissionGrantId: options.permissionGrantId
});
const message = { descriptor, authorization };
Message.validateJsonSchema(message);
ProtocolsConfigure.validateProtocolDefinition(message.descriptor.definition);
const protocolsConfigure = new ProtocolsConfigure(message);
return protocolsConfigure;
});
}
/**
* Performs validation on the given protocol definition that are not easy to do using a JSON schema.
*/
static validateProtocolDefinition(definition) {
const { protocol, types } = definition;
// validate protocol url
validateProtocolUrlNormalized(protocol);
// validate schema url normalized
for (const typeName in types) {
const schema = types[typeName].schema;
if (schema !== undefined) {
validateSchemaUrlNormalized(schema);
}
}
// validate `structure
ProtocolsConfigure.validateStructure(definition);
}
static validateStructure(definition) {
// gather all declared record types
const recordTypes = Object.keys(definition.types);
// gather all roles
const roles = ProtocolsConfigure.fetchAllRolePathsRecursively('', definition.structure, []);
// validate the entire rule set structure recursively
ProtocolsConfigure.validateRuleSetRecursively({
ruleSet: definition.structure,
ruleSetProtocolPath: '',
recordTypes,
roles
});
}
/**
* Parses the given rule set hierarchy to get all the role protocol paths.
* @throws DwnError if the hierarchy depth goes beyond 10 levels.
*/
static fetchAllRolePathsRecursively(ruleSetProtocolPath, ruleSet, roles) {
// Limit the depth of the record hierarchy to 10 levels
// There is opportunity to optimize here to avoid repeated string splitting
if (ruleSetProtocolPath.split('/').length > 10) {
throw new DwnError(DwnErrorCode.ProtocolsConfigureRecordNestingDepthExceeded, 'Record nesting depth exceeded 10 levels.');
}
for (const recordType in ruleSet) {
// ignore non-nested-record properties
if (recordType.startsWith('$')) {
continue;
}
const childRuleSet = ruleSet[recordType];
let childRuleSetProtocolPath;
if (ruleSetProtocolPath === '') {
childRuleSetProtocolPath = recordType;
}
else {
childRuleSetProtocolPath = `${ruleSetProtocolPath}/${recordType}`;
}
// if this is a role record, add it to the list, else continue to traverse
if (childRuleSet.$role) {
roles.push(childRuleSetProtocolPath);
}
else {
ProtocolsConfigure.fetchAllRolePathsRecursively(childRuleSetProtocolPath, childRuleSet, roles);
}
}
return roles;
}
/**
* Validates the given rule set structure then recursively validates its nested child rule sets.
*/
static validateRuleSetRecursively(input) {
var _a;
const { ruleSet, ruleSetProtocolPath, recordTypes, roles } = input;
// Validate $actions in the rule set
if (ruleSet.$size !== undefined) {
const { min = 0, max } = ruleSet.$size;
if (max !== undefined && max < min) {
throw new DwnError(DwnErrorCode.ProtocolsConfigureInvalidSize, `Invalid size range found: max limit ${max} less than min limit ${min} at protocol path '${ruleSetProtocolPath}'`);
}
}
if (ruleSet.$tags) {
const ajv = new Ajv.default();
const _b = ruleSet.$tags, { $allowUndefinedTags, $requiredTags } = _b, tagProperties = __rest(_b, ["$allowUndefinedTags", "$requiredTags"]);
// we validate each tag's expected schema to ensure it is a valid JSON schema
for (const tag in tagProperties) {
const tagSchemaDefinition = tagProperties[tag];
if (!ajv.validateSchema(tagSchemaDefinition)) {
const schemaError = ajv.errorsText(ajv.errors, { dataVar: `${ruleSetProtocolPath}/$tags/${tag}` });
throw new DwnError(DwnErrorCode.ProtocolsConfigureInvalidTagSchema, `tags schema validation error: ${schemaError}`);
}
}
}
// validate each action rule
const actionRules = (_a = ruleSet.$actions) !== null && _a !== void 0 ? _a : [];
for (let i = 0; i < actionRules.length; i++) {
const actionRule = actionRules[i];
// Validate the `role` property of an `action` if exists.
if (actionRule.role !== undefined) {
// make sure the role contains a valid protocol paths to a role record
if (!roles.includes(actionRule.role)) {
throw new DwnError(DwnErrorCode.ProtocolsConfigureRoleDoesNotExistAtGivenPath, `Role in action ${JSON.stringify(actionRule)} for rule set ${ruleSetProtocolPath} does not exist.`);
}
}
// Validate that if `who` is set to `anyone` then `of` is not set
if (actionRule.who === 'anyone' && actionRule.of) {
throw new DwnError(DwnErrorCode.ProtocolsConfigureInvalidActionOfNotAllowed, `'of' is not allowed at rule set protocol path (${ruleSetProtocolPath})`);
}
// Validate that if `who === recipient` and `of === undefined`, then `can` can only contain `co-update`, `co-delete`, and `co-prune`.
// We do not allow `read`, `write`, or `query` in the `can` array because:
// - `read` - Recipients are always allowed to `read`.
// - `write` - Entails ability to create and update.
// Since `of` is undefined, it implies the recipient of THIS record,
// there is no 'recipient' until this record has been created, so it makes no sense to allow recipient to write this record.
// - `query` - Only authorized using roles, so allowing direct recipients to query is outside the scope.
if (actionRule.who === ProtocolActor.Recipient && actionRule.of === undefined) {
// throw if `can` contains a value that is not `co-update`, `co-delete`, or `co-prune`
const hasDisallowedAction = actionRule.can.some(action => ![ProtocolAction.CoUpdate, ProtocolAction.CoDelete, ProtocolAction.CoPrune].includes(action));
if (hasDisallowedAction) {
throw new DwnError(DwnErrorCode.ProtocolsConfigureInvalidRecipientOfAction, 'Rules for `recipient` without `of` property must have `can` containing only `co-update`, `co-delete`, and `co-prune`.');
}
}
// Validate that if `who` is set to `author` then `of` is set
if (actionRule.who === ProtocolActor.Author && !actionRule.of) {
throw new DwnError(DwnErrorCode.ProtocolsConfigureInvalidActionMissingOf, `'of' is required when 'author' is specified as 'who'`);
}
// validate that if `can` contains `update` or `delete`, it must also contain `create`
if (actionRule.can !== undefined) {
if (actionRule.can.includes(ProtocolAction.Update) && !actionRule.can.includes(ProtocolAction.Create)) {
throw new DwnError(DwnErrorCode.ProtocolsConfigureInvalidActionUpdateWithoutCreate, `Action rule ${JSON.stringify(actionRule)} contains 'update' action but missing the required 'create' action.`);
}
if (actionRule.can.includes(ProtocolAction.Delete) && !actionRule.can.includes(ProtocolAction.Create)) {
throw new DwnError(DwnErrorCode.ProtocolsConfigureInvalidActionDeleteWithoutCreate, `Action rule ${JSON.stringify(actionRule)} contains 'delete' action but missing the required 'create' action.`);
}
}
// Validate that there are no duplicate actors or roles in the remaining action rules:
// ie. no two action rules can have the same combination of `who` + `of` or `role`.
// NOTE: we only need to check the remaining action rules that have yet to go through action rule validation loop, as a perf shortcut.
for (let j = i + 1; j < actionRules.length; j++) {
const otherActionRule = actionRules[j];
if (actionRule.who !== undefined) {
if (actionRule.who === otherActionRule.who && actionRule.of === otherActionRule.of) {
throw new DwnError(DwnErrorCode.ProtocolsConfigureDuplicateActorInRuleSet, `More than one action rule per actor ${actionRule.who} of ${actionRule.of} not allowed within a rule set: ${JSON.stringify(actionRule)}`);
}
}
else {
// else implicitly a role-based action rule
if (actionRule.role === otherActionRule.role) {
throw new DwnError(DwnErrorCode.ProtocolsConfigureDuplicateRoleInRuleSet, `More than one action rule per role ${actionRule.role} not allowed within a rule set: ${JSON.stringify(actionRule)}`);
}
}
}
}
// Validate nested rule sets
for (const recordType in ruleSet) {
if (recordType.startsWith('$')) {
continue;
}
if (!recordTypes.includes(recordType)) {
throw new DwnError(DwnErrorCode.ProtocolsConfigureInvalidRuleSetRecordType, `Rule set ${recordType} is not declared as an allowed type in the protocol definition.`);
}
const childRuleSet = ruleSet[recordType];
let childRuleSetProtocolPath;
if (ruleSetProtocolPath === '') {
childRuleSetProtocolPath = recordType; // case of initial definition structure
}
else {
childRuleSetProtocolPath = `${ruleSetProtocolPath}/${recordType}`;
}
ProtocolsConfigure.validateRuleSetRecursively({
ruleSet: childRuleSet,
ruleSetProtocolPath: childRuleSetProtocolPath,
recordTypes,
roles
});
}
}
static normalizeDefinition(definition) {
const typesCopy = Object.assign({}, definition.types);
// Normalize schema url
for (const typeName in typesCopy) {
const schema = typesCopy[typeName].schema;
if (schema !== undefined) {
typesCopy[typeName].schema = normalizeSchemaUrl(schema);
}
}
return Object.assign(Object.assign({}, definition), { protocol: normalizeProtocolUrl(definition.protocol), types: typesCopy });
}
}
//# sourceMappingURL=protocols-configure.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,84 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { AbstractMessage } from '../core/abstract-message.js';
import { GrantAuthorization } from '../core/grant-authorization.js';
import { Message } from '../core/message.js';
import { PermissionsProtocol } from '../protocols/permissions.js';
import { removeUndefinedProperties } from '../utils/object.js';
import { Time } from '../utils/time.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
import { normalizeProtocolUrl, validateProtocolUrlNormalized } from '../utils/url.js';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
export class ProtocolsQuery extends AbstractMessage {
static parse(message) {
return __awaiter(this, void 0, void 0, function* () {
if (message.authorization !== undefined) {
yield Message.validateSignatureStructure(message.authorization.signature, message.descriptor);
}
if (message.descriptor.filter !== undefined) {
validateProtocolUrlNormalized(message.descriptor.filter.protocol);
}
Time.validateTimestamp(message.descriptor.messageTimestamp);
return new ProtocolsQuery(message);
});
}
static create(options) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const descriptor = {
interface: DwnInterfaceName.Protocols,
method: DwnMethodName.Query,
messageTimestamp: (_a = options.messageTimestamp) !== null && _a !== void 0 ? _a : Time.getCurrentTimestamp(),
filter: options.filter ? ProtocolsQuery.normalizeFilter(options.filter) : undefined,
};
// delete all descriptor properties that are `undefined` else the code will encounter the following IPLD issue when attempting to generate CID:
// Error: `undefined` is not supported by the IPLD Data Model and cannot be encoded
removeUndefinedProperties(descriptor);
// only generate the `authorization` property if signature input is given
let authorization;
if (options.signer !== undefined) {
authorization = yield Message.createAuthorization({
descriptor,
signer: options.signer,
permissionGrantId: options.permissionGrantId
});
}
const message = { descriptor, authorization };
Message.validateJsonSchema(message);
const protocolsQuery = new ProtocolsQuery(message);
return protocolsQuery;
});
}
static normalizeFilter(filter) {
return Object.assign(Object.assign({}, filter), { protocol: normalizeProtocolUrl(filter.protocol) });
}
authorize(tenant, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
// if author is the same as the target tenant, we can directly grant access
if (this.author === tenant) {
return;
}
else if (this.author !== undefined && this.signaturePayload.permissionGrantId) {
const permissionGrant = yield PermissionsProtocol.fetchGrant(tenant, messageStore, this.signaturePayload.permissionGrantId);
yield GrantAuthorization.performBaseValidation({
incomingMessage: this.message,
expectedGrantor: tenant,
expectedGrantee: this.author,
permissionGrant,
messageStore
});
}
else {
throw new DwnError(DwnErrorCode.ProtocolsQueryUnauthorized, 'The ProtocolsQuery failed authorization');
}
});
}
}
//# sourceMappingURL=protocols-query.js.map
@@ -0,0 +1 @@
{"version":3,"file":"protocols-query.js","sourceRoot":"","sources":["../../../../src/interfaces/protocols-query.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,95 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { AbstractMessage } from '../core/abstract-message.js';
import { Message } from '../core/message.js';
import { PermissionGrant } from '../protocols/permission-grant.js';
import { Records } from '../utils/records.js';
import { RecordsGrantAuthorization } from '../core/records-grant-authorization.js';
import { removeUndefinedProperties } from '../utils/object.js';
import { Time } from '../utils/time.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
export class RecordsDelete extends AbstractMessage {
static parse(message) {
return __awaiter(this, void 0, void 0, function* () {
let signaturePayload;
if (message.authorization !== undefined) {
signaturePayload = yield Message.validateSignatureStructure(message.authorization.signature, message.descriptor);
}
yield Records.validateDelegatedGrantReferentialIntegrity(message, signaturePayload);
Time.validateTimestamp(message.descriptor.messageTimestamp);
const recordsDelete = new RecordsDelete(message);
return recordsDelete;
});
}
/**
* Creates a RecordsDelete message.
* @param options.recordId If `undefined`, will be auto-filled as a originating message as convenience for developer.
* @param options.messageTimestamp If `undefined`, it will be auto-filled with current time.
*/
static create(options) {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () {
const recordId = options.recordId;
const currentTime = Time.getCurrentTimestamp();
const descriptor = {
interface: DwnInterfaceName.Records,
method: DwnMethodName.Delete,
messageTimestamp: (_a = options.messageTimestamp) !== null && _a !== void 0 ? _a : currentTime,
recordId,
prune: (_b = options.prune) !== null && _b !== void 0 ? _b : false
};
const authorization = yield Message.createAuthorization({
descriptor,
signer: options.signer,
protocolRole: options.protocolRole,
delegatedGrant: options.delegatedGrant
});
const message = { descriptor, authorization };
Message.validateJsonSchema(message);
return new RecordsDelete(message);
});
}
/**
* Indexed properties needed for MessageStore indexing.
*/
constructIndexes(initialWrite) {
const message = this.message;
const descriptor = Object.assign({}, message.descriptor);
// we add the immutable properties from the initial RecordsWrite message in order to use them when querying relevant deletes.
const { protocol, protocolPath, recipient, schema, parentId, dateCreated } = initialWrite.descriptor;
// NOTE: the "trick" not may not be apparent on how a query is able to omit deleted records:
// we intentionally not add index for `isLatestBaseState` at all, this means that upon a successful delete,
// no messages with the record ID will match any query because queries by design filter by `isLatestBaseState = true`,
// `isLatestBaseState` for the initial delete would have been toggled to `false`
const indexes = Object.assign({
// isLatestBaseState : "true", // intentionally showing that this index is omitted
protocol, protocolPath, recipient, schema, parentId, dateCreated, contextId: initialWrite.contextId, author: this.author }, descriptor);
removeUndefinedProperties(indexes);
return indexes;
}
/*
* Authorizes the delegate who signed the message.
* @param messageStore Used to check if the grant has been revoked.
*/
authorizeDelegate(recordsWriteToDelete, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
const delegatedGrant = yield PermissionGrant.parse(this.message.authorization.authorDelegatedGrant);
yield RecordsGrantAuthorization.authorizeDelete({
recordsDeleteMessage: this.message,
recordsWriteToDelete,
expectedGrantor: this.author,
expectedGrantee: this.signer,
permissionGrant: delegatedGrant,
messageStore
});
});
}
}
//# sourceMappingURL=records-delete.js.map
@@ -0,0 +1 @@
{"version":3,"file":"records-delete.js","sourceRoot":"","sources":["../../../../src/interfaces/records-delete.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,104 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { AbstractMessage } from '../core/abstract-message.js';
import { DateSort } from '../types/records-types.js';
import { Message } from '../core/message.js';
import { PermissionGrant } from '../protocols/permission-grant.js';
import { Records } from '../utils/records.js';
import { RecordsGrantAuthorization } from '../core/records-grant-authorization.js';
import { removeUndefinedProperties } from '../utils/object.js';
import { Time } from '../utils/time.js';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
import { validateProtocolUrlNormalized, validateSchemaUrlNormalized } from '../utils/url.js';
/**
* A class representing a RecordsQuery DWN message.
*/
export class RecordsQuery extends AbstractMessage {
static parse(message) {
return __awaiter(this, void 0, void 0, function* () {
if (message.descriptor.filter.published === false) {
if (message.descriptor.dateSort === DateSort.PublishedAscending || message.descriptor.dateSort === DateSort.PublishedDescending) {
throw new DwnError(DwnErrorCode.RecordsQueryParseFilterPublishedSortInvalid, `queries must not filter for \`published:false\` and sort by ${message.descriptor.dateSort}`);
}
}
let signaturePayload;
if (message.authorization !== undefined) {
signaturePayload = yield Message.validateSignatureStructure(message.authorization.signature, message.descriptor);
}
yield Records.validateDelegatedGrantReferentialIntegrity(message, signaturePayload);
if ((signaturePayload === null || signaturePayload === void 0 ? void 0 : signaturePayload.protocolRole) !== undefined) {
if (message.descriptor.filter.protocolPath === undefined) {
throw new DwnError(DwnErrorCode.RecordsQueryFilterMissingRequiredProperties, 'Role-authorized queries must include `protocolPath` in the filter');
}
}
if (message.descriptor.filter.protocol !== undefined) {
validateProtocolUrlNormalized(message.descriptor.filter.protocol);
}
if (message.descriptor.filter.schema !== undefined) {
validateSchemaUrlNormalized(message.descriptor.filter.schema);
}
Time.validateTimestamp(message.descriptor.messageTimestamp);
return new RecordsQuery(message);
});
}
static create(options) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const descriptor = {
interface: DwnInterfaceName.Records,
method: DwnMethodName.Query,
messageTimestamp: (_a = options.messageTimestamp) !== null && _a !== void 0 ? _a : Time.getCurrentTimestamp(),
filter: Records.normalizeFilter(options.filter),
dateSort: options.dateSort,
pagination: options.pagination,
};
if (options.filter.published === false) {
if (options.dateSort === DateSort.PublishedAscending || options.dateSort === DateSort.PublishedDescending) {
throw new DwnError(DwnErrorCode.RecordsQueryCreateFilterPublishedSortInvalid, `queries must not filter for \`published:false\` and sort by ${options.dateSort}`);
}
}
// delete all descriptor properties that are `undefined` else the code will encounter the following IPLD issue when attempting to generate CID:
// Error: `undefined` is not supported by the IPLD Data Model and cannot be encoded
removeUndefinedProperties(descriptor);
// only generate the `authorization` property if signature input is given
const signer = options.signer;
let authorization;
if (signer) {
authorization = yield Message.createAuthorization({
descriptor,
signer,
protocolRole: options.protocolRole,
delegatedGrant: options.delegatedGrant
});
}
const message = { descriptor, authorization };
Message.validateJsonSchema(message);
return new RecordsQuery(message);
});
}
/**
* Authorizes the delegate who signed this message.
* @param messageStore Used to check if the grant has been revoked.
*/
authorizeDelegate(messageStore) {
return __awaiter(this, void 0, void 0, function* () {
const delegatedGrant = yield PermissionGrant.parse(this.message.authorization.authorDelegatedGrant);
yield RecordsGrantAuthorization.authorizeQueryOrSubscribe({
incomingMessage: this.message,
expectedGrantee: this.signer,
expectedGrantor: this.author,
permissionGrant: delegatedGrant,
messageStore
});
});
}
}
//# sourceMappingURL=records-query.js.map
@@ -0,0 +1 @@
{"version":3,"file":"records-query.js","sourceRoot":"","sources":["../../../../src/interfaces/records-query.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,84 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { AbstractMessage } from '../core/abstract-message.js';
import { Message } from '../core/message.js';
import { PermissionGrant } from '../protocols/permission-grant.js';
import { Records } from '../utils/records.js';
import { RecordsGrantAuthorization } from '../core/records-grant-authorization.js';
import { removeUndefinedProperties } from '../utils/object.js';
import { Time } from '../utils/time.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
export class RecordsRead extends AbstractMessage {
static parse(message) {
return __awaiter(this, void 0, void 0, function* () {
let signaturePayload;
if (message.authorization !== undefined) {
signaturePayload = yield Message.validateSignatureStructure(message.authorization.signature, message.descriptor);
}
yield Records.validateDelegatedGrantReferentialIntegrity(message, signaturePayload);
Time.validateTimestamp(message.descriptor.messageTimestamp);
const recordsRead = new RecordsRead(message);
return recordsRead;
});
}
/**
* Creates a RecordsRead message.
* @param options.recordId If `undefined`, will be auto-filled as a originating message as convenience for developer.
* @param options.date If `undefined`, it will be auto-filled with current time.
*
* @throws {DwnError} when a combination of required RecordsReadOptions are missing
*/
static create(options) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const { filter, signer, permissionGrantId, protocolRole } = options;
const currentTime = Time.getCurrentTimestamp();
const descriptor = {
interface: DwnInterfaceName.Records,
method: DwnMethodName.Read,
filter: Records.normalizeFilter(filter),
messageTimestamp: (_a = options.messageTimestamp) !== null && _a !== void 0 ? _a : currentTime,
};
removeUndefinedProperties(descriptor);
// only generate the `authorization` property if signature input is given
let authorization = undefined;
if (signer !== undefined) {
authorization = yield Message.createAuthorization({
descriptor,
signer,
permissionGrantId,
protocolRole,
delegatedGrant: options.delegatedGrant
});
}
const message = { descriptor, authorization };
Message.validateJsonSchema(message);
return new RecordsRead(message);
});
}
/**
* Authorizes the delegate who signed this message.
* @param messageStore Used to check if the grant has been revoked.
*/
authorizeDelegate(matchedRecordsWrite, messageStore) {
return __awaiter(this, void 0, void 0, function* () {
const delegatedGrant = yield PermissionGrant.parse(this.message.authorization.authorDelegatedGrant);
yield RecordsGrantAuthorization.authorizeRead({
recordsReadMessage: this.message,
recordsWriteMessageToBeRead: matchedRecordsWrite,
expectedGrantor: this.author,
expectedGrantee: this.signer,
permissionGrant: delegatedGrant,
messageStore
});
});
}
}
//# sourceMappingURL=records-read.js.map
@@ -0,0 +1 @@
{"version":3,"file":"records-read.js","sourceRoot":"","sources":["../../../../src/interfaces/records-read.ts"],"names":[],"mappings":";;;;;;;;;AAIA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,yBAAyB,EAAE,MAAM,wCAAwC,CAAC;AACnF,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAmBnF,MAAM,OAAO,WAAY,SAAQ,eAAmC;IAE3D,MAAM,CAAO,KAAK,CAAC,OAA2B;;YACnD,IAAI,gBAAgB,CAAC;YACrB,IAAI,OAAO,CAAC,aAAa,KAAK,SAAS,EAAE;gBACvC,gBAAgB,GAAG,MAAM,OAAO,CAAC,0BAA0B,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;aAClH;YAED,MAAM,OAAO,CAAC,0CAA0C,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;YAEpF,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;YAE5D,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC;YAC7C,OAAO,WAAW,CAAC;QACrB,CAAC;KAAA;IAED;;;;;;OAMG;IACI,MAAM,CAAO,MAAM,CAAC,OAA2B;;;YACpD,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC;YACpE,MAAM,WAAW,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAE/C,MAAM,UAAU,GAA0B;gBACxC,SAAS,EAAU,gBAAgB,CAAC,OAAO;gBAC3C,MAAM,EAAa,aAAa,CAAC,IAAI;gBACrC,MAAM,EAAa,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC;gBAClD,gBAAgB,EAAG,MAAA,OAAO,CAAC,gBAAgB,mCAAI,WAAW;aAC3D,CAAC;YAEF,yBAAyB,CAAC,UAAU,CAAC,CAAC;YAEtC,yEAAyE;YACzE,IAAI,aAAa,GAAG,SAAS,CAAC;YAC9B,IAAI,MAAM,KAAK,SAAS,EAAE;gBACxB,aAAa,GAAG,MAAM,OAAO,CAAC,mBAAmB,CAAC;oBAChD,UAAU;oBACV,MAAM;oBACN,iBAAiB;oBACjB,YAAY;oBACZ,cAAc,EAAE,OAAO,CAAC,cAAc;iBACvC,CAAC,CAAC;aACJ;YACD,MAAM,OAAO,GAAuB,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC;YAElE,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;YAEpC,OAAO,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC;;KACjC;IAED;;;OAGG;IACU,iBAAiB,CAAC,mBAAwC,EAAE,YAA0B;;YACjG,MAAM,cAAc,GAAG,MAAM,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,aAAc,CAAC,oBAAqB,CAAC,CAAC;YACtG,MAAM,yBAAyB,CAAC,aAAa,CAAC;gBAC5C,kBAAkB,EAAY,IAAI,CAAC,OAAO;gBAC1C,2BAA2B,EAAG,mBAAmB;gBACjD,eAAe,EAAe,IAAI,CAAC,MAAO;gBAC1C,eAAe,EAAe,IAAI,CAAC,MAAO;gBAC1C,eAAe,EAAe,cAAc;gBAC5C,YAAY;aACb,CAAC,CAAC;QACL,CAAC;KAAA;CACF"}
@@ -0,0 +1,91 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { AbstractMessage } from '../core/abstract-message.js';
import { Message } from '../core/message.js';
import { PermissionGrant } from '../protocols/permission-grant.js';
import { Records } from '../utils/records.js';
import { RecordsGrantAuthorization } from '../core/records-grant-authorization.js';
import { removeUndefinedProperties } from '../utils/object.js';
import { Time } from '../utils/time.js';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
import { validateProtocolUrlNormalized, validateSchemaUrlNormalized } from '../utils/url.js';
/**
* A class representing a RecordsSubscribe DWN message.
*/
export class RecordsSubscribe extends AbstractMessage {
static parse(message) {
return __awaiter(this, void 0, void 0, function* () {
let signaturePayload;
if (message.authorization !== undefined) {
signaturePayload = yield Message.validateSignatureStructure(message.authorization.signature, message.descriptor);
}
yield Records.validateDelegatedGrantReferentialIntegrity(message, signaturePayload);
if ((signaturePayload === null || signaturePayload === void 0 ? void 0 : signaturePayload.protocolRole) !== undefined) {
if (message.descriptor.filter.protocolPath === undefined) {
throw new DwnError(DwnErrorCode.RecordsSubscribeFilterMissingRequiredProperties, 'Role-authorized subscriptions must include `protocolPath` in the filter');
}
}
if (message.descriptor.filter.protocol !== undefined) {
validateProtocolUrlNormalized(message.descriptor.filter.protocol);
}
if (message.descriptor.filter.schema !== undefined) {
validateSchemaUrlNormalized(message.descriptor.filter.schema);
}
Time.validateTimestamp(message.descriptor.messageTimestamp);
return new RecordsSubscribe(message);
});
}
static create(options) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const descriptor = {
interface: DwnInterfaceName.Records,
method: DwnMethodName.Subscribe,
messageTimestamp: (_a = options.messageTimestamp) !== null && _a !== void 0 ? _a : Time.getCurrentTimestamp(),
filter: Records.normalizeFilter(options.filter),
};
// delete all descriptor properties that are `undefined` else the code will encounter the following IPLD issue when attempting to generate CID:
// Error: `undefined` is not supported by the IPLD Data Model and cannot be encoded
removeUndefinedProperties(descriptor);
// only generate the `authorization` property if signature input is given
const signer = options.signer;
let authorization;
if (signer) {
authorization = yield Message.createAuthorization({
descriptor,
signer,
protocolRole: options.protocolRole,
delegatedGrant: options.delegatedGrant
});
}
const message = { descriptor, authorization };
Message.validateJsonSchema(message);
return new RecordsSubscribe(message);
});
}
/**
* Authorizes the delegate who signed the message.
* @param messageStore Used to check if the grant has been revoked.
*/
authorizeDelegate(messageStore) {
return __awaiter(this, void 0, void 0, function* () {
const delegatedGrant = yield PermissionGrant.parse(this.message.authorization.authorDelegatedGrant);
yield RecordsGrantAuthorization.authorizeQueryOrSubscribe({
incomingMessage: this.message,
expectedGrantor: this.author,
expectedGrantee: this.signer,
permissionGrant: delegatedGrant,
messageStore
});
});
}
}
//# sourceMappingURL=records-subscribe.js.map
@@ -0,0 +1 @@
{"version":3,"file":"records-subscribe.js","sourceRoot":"","sources":["../../../../src/interfaces/records-subscribe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,766 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import { Cid } from '../utils/cid.js';
import { Encoder } from '../utils/encoder.js';
import { Encryption } from '../utils/encryption.js';
import { EncryptionAlgorithm } from '../utils/encryption.js';
import { GeneralJwsBuilder } from '../jose/jws/general/builder.js';
import { Jws } from '../utils/jws.js';
import { KeyDerivationScheme } from '../utils/hd-key.js';
import { Message } from '../core/message.js';
import { PermissionGrant } from '../protocols/permission-grant.js';
import { Records } from '../utils/records.js';
import { RecordsGrantAuthorization } from '../core/records-grant-authorization.js';
import { removeUndefinedProperties } from '../utils/object.js';
import { Secp256k1 } from '../utils/secp256k1.js';
import { Time } from '../utils/time.js';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
import { normalizeProtocolUrl, normalizeSchemaUrl, validateProtocolUrlNormalized, validateSchemaUrlNormalized } from '../utils/url.js';
/**
* A class representing a RecordsWrite DWN message.
* NOTE: Unable to extend `AbstractMessage` directly because the incompatible `_message` type, which is not just a generic `<M>` type.
*/
export class RecordsWrite {
/**
* Valid JSON message representing this RecordsWrite.
* @throws `DwnErrorCode.RecordsWriteMissingSigner` if the message is not signed yet.
*/
get message() {
if (this._message.authorization === undefined) {
throw new DwnError(DwnErrorCode.RecordsWriteMissingSigner, 'This RecordsWrite is not yet signed, JSON message cannot be generated from an incomplete state.');
}
return this._message;
}
get author() {
return this._author;
}
get signaturePayload() {
return this._signaturePayload;
}
/**
* The owner DID of the message if owner signature is present in the message; `undefined` otherwise.
* This is the logical owner of the message, not to be confused with the actual signer of the owner signature,
* this is because the signer of the owner signature may not be the actual DWN owner, but a delegate authorized by the owner.
*/
get owner() {
return this._owner;
}
/**
* Decoded owner signature payload.
*/
get ownerSignaturePayload() {
return this._ownerSignaturePayload;
}
/**
* If this message is signed by an author-delegate.
*/
get isSignedByAuthorDelegate() {
return Message.isSignedByAuthorDelegate(this._message);
}
/**
* If this message is signed by an owner-delegate.
*/
get isSignedByOwnerDelegate() {
return Message.isSignedByOwnerDelegate(this._message);
}
/**
* Gets the signer of this message.
* This is not to be confused with the logical author of the message.
*/
get signer() {
return Message.getSigner(this._message);
}
/**
* Gets the signer of owner signature; `undefined` if owner signature is not present in the message.
* This is not to be confused with the logical owner {@link #owner} of the message,
* this is because the signer of the owner signature may not be the actual DWN owner, but a delegate authorized by the owner.
* In the case that the owner signature is signed by the actual DWN owner, this value will be the same as {@link #owner}.
*/
get ownerSignatureSigner() {
var _a;
if (((_a = this._message.authorization) === null || _a === void 0 ? void 0 : _a.ownerSignature) === undefined) {
return undefined;
}
const signer = Jws.getSignerDid(this._message.authorization.ownerSignature.signatures[0]);
return signer;
}
constructor(message, parentContextId) {
this.parentContextId = parentContextId;
this._message = message;
if (message.authorization !== undefined) {
this._author = Records.getAuthor(message);
this._signaturePayload = Jws.decodePlainObjectPayload(message.authorization.signature);
if (message.authorization.ownerSignature !== undefined) {
// if the message authorization contains owner delegated grant, the owner would be the grantor of the grant
// else the owner would be the signer of the owner signature
if (message.authorization.ownerDelegatedGrant !== undefined) {
this._owner = Message.getSigner(message.authorization.ownerDelegatedGrant);
}
else {
this._owner = Jws.getSignerDid(message.authorization.ownerSignature.signatures[0]);
}
this._ownerSignaturePayload = Jws.decodePlainObjectPayload(message.authorization.ownerSignature);
}
}
this.attesters = RecordsWrite.getAttesters(message);
// consider converting isInitialWrite() & getEntryId() into properties for performance and convenience
}
/**
* Parses a RecordsWrite message and returns a {RecordsWrite} instance.
*/
static parse(recordsWriteMessage) {
return __awaiter(this, void 0, void 0, function* () {
// Make a copy so that the stored copy is not subject to external, unexpected modification.
const message = JSON.parse(JSON.stringify(recordsWriteMessage));
// asynchronous checks that are required by the constructor to initialize members properly
yield Message.validateSignatureStructure(message.authorization.signature, message.descriptor, 'RecordsWriteSignaturePayload');
if (message.authorization.ownerSignature !== undefined) {
yield Message.validateSignatureStructure(message.authorization.ownerSignature, message.descriptor);
}
yield RecordsWrite.validateAttestationIntegrity(message);
const recordsWrite = new RecordsWrite(message);
yield recordsWrite.validateIntegrity(); // RecordsWrite specific data integrity check
return recordsWrite;
});
}
/**
* Creates a RecordsWrite message.
* @param options.recordId If `undefined`, will be auto-filled as the initial message as convenience for developer.
* @param options.data Data used to compute the `dataCid`, must be the encrypted data bytes if `options.encryptionInput` is given.
* Must specify `options.dataCid` if `undefined`.
* @param options.dataCid CID of the data that is already stored in the DWN. Must specify `options.data` if `undefined`.
* @param options.dataSize Size of data in number of bytes. Must be defined if `options.dataCid` is defined; must be `undefined` otherwise.
* @param options.dateCreated If `undefined`, it will be auto-filled with current time.
* @param options.messageTimestamp If `undefined`, it will be auto-filled with current time.
* @param options.parentContextId Must be given if this message is for a non-root protocol record.
* If not given, it either means this write is for a root protocol record or a flat-space record.
*/
static create(options) {
var _a, _b, _c, _d;
return __awaiter(this, void 0, void 0, function* () {
if ((options.protocol === undefined && options.protocolPath !== undefined) ||
(options.protocol !== undefined && options.protocolPath === undefined)) {
throw new DwnError(DwnErrorCode.RecordsWriteCreateProtocolAndProtocolPathMutuallyInclusive, '`protocol` and `protocolPath` must both be defined or undefined at the same time');
}
if ((options.data === undefined && options.dataCid === undefined) ||
(options.data !== undefined && options.dataCid !== undefined)) {
throw new DwnError(DwnErrorCode.RecordsWriteCreateDataAndDataCidMutuallyExclusive, 'one and only one parameter between `data` and `dataCid` is required');
}
if ((options.dataCid === undefined && options.dataSize !== undefined) ||
(options.dataCid !== undefined && options.dataSize === undefined)) {
throw new DwnError(DwnErrorCode.RecordsWriteCreateDataCidAndDataSizeMutuallyInclusive, '`dataCid` and `dataSize` must both be defined or undefined at the same time');
}
if (options.signer === undefined && options.delegatedGrant !== undefined) {
throw new DwnError(DwnErrorCode.RecordsWriteCreateMissingSigner, '`signer` must be given when `delegatedGrant` is given');
}
const dataCid = (_a = options.dataCid) !== null && _a !== void 0 ? _a : yield Cid.computeDagPbCidFromBytes(options.data);
const dataSize = (_b = options.dataSize) !== null && _b !== void 0 ? _b : options.data.length;
const currentTime = Time.getCurrentTimestamp();
const descriptor = {
interface: DwnInterfaceName.Records,
method: DwnMethodName.Write,
protocol: options.protocol !== undefined ? normalizeProtocolUrl(options.protocol) : undefined,
protocolPath: options.protocolPath,
recipient: options.recipient,
schema: options.schema !== undefined ? normalizeSchemaUrl(options.schema) : undefined,
tags: options.tags,
parentId: RecordsWrite.getRecordIdFromContextId(options.parentContextId),
dataCid,
dataSize,
dateCreated: (_c = options.dateCreated) !== null && _c !== void 0 ? _c : currentTime,
messageTimestamp: (_d = options.messageTimestamp) !== null && _d !== void 0 ? _d : currentTime,
published: options.published,
datePublished: options.datePublished,
dataFormat: options.dataFormat
};
// generate `datePublished` if the message is to be published but `datePublished` is not given
if (options.published === true &&
options.datePublished === undefined) {
descriptor.datePublished = currentTime;
}
// delete all descriptor properties that are `undefined` else the code will encounter the following IPLD issue when attempting to generate CID:
// Error: `undefined` is not supported by the IPLD Data Model and cannot be encoded
removeUndefinedProperties(descriptor);
// `recordId` computation
const recordId = options.recordId;
// `attestation` generation
const descriptorCid = yield Cid.computeCid(descriptor);
const attestation = yield RecordsWrite.createAttestation(descriptorCid, options.attestationSigners);
// `encryption` generation
const encryption = yield RecordsWrite.createEncryptionProperty(descriptor, options.encryptionInput);
const message = {
recordId,
descriptor
};
// assign optional properties only if they exist
if (attestation !== undefined) {
message.attestation = attestation;
}
if (encryption !== undefined) {
message.encryption = encryption;
}
const recordsWrite = new RecordsWrite(message, options.parentContextId);
if (options.signer !== undefined) {
yield recordsWrite.sign({
signer: options.signer,
delegatedGrant: options.delegatedGrant,
permissionGrantId: options.permissionGrantId,
protocolRole: options.protocolRole
});
}
return recordsWrite;
});
}
static getRecordIdFromContextId(contextId) {
return contextId === null || contextId === void 0 ? void 0 : contextId.split('/').filter(segment => segment !== '').pop();
}
/**
* Convenience method that creates a message by:
* 1. Copying over immutable properties from the given source message
* 2. Copying over mutable properties that are not overwritten from the given source message
* 3. Replace the mutable properties that are given new value
* @param options.recordsWriteMessage Message that the new RecordsWrite will be based from.
* @param options.messageTimestamp The new date the record is modified. If not given, current time will be used .
* @param options.data The new data or the record. If not given, data from given message will be used.
* @param options.published The new published state. If not given, then will be set to `true` if {options.messageTimestamp} is given;
* else the state from given message will be used.
* @param options.publishedDate The new date the record is modified. If not given, then:
* - will not be set if the record will be unpublished as the result of this RecordsWrite; else
* - will be set to the same published date as the given message if it wss already published; else
* - will be set to current time (because this is a toggle from unpublished to published)
*/
static createFrom(options) {
var _a, _b, _c, _d;
return __awaiter(this, void 0, void 0, function* () {
const sourceMessage = options.recordsWriteMessage;
const sourceRecordsWrite = yield RecordsWrite.parse(sourceMessage);
const currentTime = Time.getCurrentTimestamp();
// inherit published value from parent if neither published nor datePublished is specified
const published = (_a = options.published) !== null && _a !== void 0 ? _a : (options.datePublished ? true : sourceMessage.descriptor.published);
// use current time if published but no explicit time given
let datePublished = undefined;
// if given explicitly published dated
if (options.datePublished) {
datePublished = options.datePublished;
}
else {
// if this RecordsWrite will publish the record
if (published) {
// the parent was already published, inherit the same published date
if (sourceMessage.descriptor.published) {
datePublished = sourceMessage.descriptor.datePublished;
}
else {
// this is a toggle from unpublished to published, use current time
datePublished = currentTime;
}
}
}
const createOptions = {
// immutable properties below, just copy from the source message
recipient: sourceMessage.descriptor.recipient,
recordId: sourceMessage.recordId,
dateCreated: sourceMessage.descriptor.dateCreated,
protocol: sourceMessage.descriptor.protocol,
protocolPath: sourceMessage.descriptor.protocolPath,
schema: sourceMessage.descriptor.schema,
parentContextId: Records.getParentContextFromOfContextId(sourceMessage.contextId),
// mutable properties below
messageTimestamp: (_b = options.messageTimestamp) !== null && _b !== void 0 ? _b : currentTime,
published,
datePublished,
tags: options.tags,
data: options.data,
dataCid: options.data ? undefined : sourceMessage.descriptor.dataCid,
dataSize: options.data ? undefined : sourceMessage.descriptor.dataSize,
dataFormat: (_c = options.dataFormat) !== null && _c !== void 0 ? _c : sourceMessage.descriptor.dataFormat,
protocolRole: (_d = options.protocolRole) !== null && _d !== void 0 ? _d : sourceRecordsWrite.signaturePayload.protocolRole,
delegatedGrant: options.delegatedGrant,
// finally still need signers
signer: options.signer,
attestationSigners: options.attestationSigners
};
const recordsWrite = yield RecordsWrite.create(createOptions);
return recordsWrite;
});
}
/**
* Called by `JSON.stringify(...)` automatically.
*/
toJSON() {
return this.message;
}
/**
* Encrypts the symmetric encryption key using the public keys given and attach the resulting `encryption` property to the RecordsWrite.
*/
encryptSymmetricEncryptionKey(encryptionInput) {
return __awaiter(this, void 0, void 0, function* () {
this._message.encryption = yield RecordsWrite.createEncryptionProperty(this._message.descriptor, encryptionInput);
// opportunity here to re-sign instead of remove
delete this._message.authorization;
this._signaturePayload = undefined;
this._author = undefined;
});
}
/**
* Signs the RecordsWrite, the signer is commonly the author, but can also be a delegate.
*/
sign(options) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const { signer, delegatedGrant, permissionGrantId, protocolRole } = options;
// compute delegated grant ID and author if delegated grant is given
let delegatedGrantId;
let authorDid;
if (delegatedGrant !== undefined) {
delegatedGrantId = yield Message.getCid(delegatedGrant);
authorDid = Jws.getSignerDid(delegatedGrant.authorization.signature.signatures[0]);
}
else {
authorDid = Jws.extractDid(signer.keyId);
}
const descriptor = this._message.descriptor;
const descriptorCid = yield Cid.computeCid(descriptor);
// compute `recordId` if not given at construction time
this._message.recordId = (_a = this._message.recordId) !== null && _a !== void 0 ? _a : yield RecordsWrite.getEntryId(authorDid, descriptor);
// compute `contextId` if this is a protocol-space record
if (this._message.descriptor.protocol !== undefined) {
// if `parentContextId` is not given, this is a root protocol record
if (this.parentContextId === undefined || this.parentContextId === '') {
this._message.contextId = this._message.recordId;
}
else {
// else this is a non-root protocol record
this._message.contextId = this.parentContextId + '/' + this._message.recordId;
}
}
// `signature` generation
const signature = yield RecordsWrite.createSignerSignature({
recordId: this._message.recordId,
contextId: this._message.contextId,
descriptorCid,
attestation: this._message.attestation,
encryption: this._message.encryption,
signer,
delegatedGrantId,
permissionGrantId,
protocolRole
});
this._message.authorization = { signature };
if (delegatedGrant !== undefined) {
this._message.authorization.authorDelegatedGrant = delegatedGrant;
}
// there is opportunity to optimize here as the payload is constructed within `createAuthorization(...)`
this._signaturePayload = Jws.decodePlainObjectPayload(signature);
this._author = authorDid;
});
}
/**
* Signs the `RecordsWrite` as the DWN owner.
* This is used when the DWN owner wants to retain a copy of a message that the owner did not author.
* NOTE: requires the `RecordsWrite` to already have the author's signature.
*/
signAsOwner(signer) {
return __awaiter(this, void 0, void 0, function* () {
if (this._author === undefined) {
throw new DwnError(DwnErrorCode.RecordsWriteSignAsOwnerUnknownAuthor, 'Unable to sign as owner without message signature because owner needs to sign over `recordId` which depends on author DID.');
}
const descriptor = this._message.descriptor;
const ownerSignature = yield Message.createSignature(descriptor, signer);
this._message.authorization.ownerSignature = ownerSignature;
this._ownerSignaturePayload = Jws.decodePlainObjectPayload(ownerSignature);
this._owner = Jws.extractDid(signer.keyId);
;
});
}
/**
* Signs the `RecordsWrite` as the DWN owner-delegate.
* This is used when a DWN owner-delegate wants to retain a copy of a message that the owner did not author.
* NOTE: requires the `RecordsWrite` to already have the author's signature.
*/
signAsOwnerDelegate(signer, delegatedGrant) {
return __awaiter(this, void 0, void 0, function* () {
if (this._author === undefined) {
throw new DwnError(DwnErrorCode.RecordsWriteSignAsOwnerDelegateUnknownAuthor, 'Unable to sign as owner delegate without message signature because owner delegate needs to sign over `recordId` which depends on author DID.');
}
const delegatedGrantId = yield Message.getCid(delegatedGrant);
const descriptor = this._message.descriptor;
const ownerSignature = yield Message.createSignature(descriptor, signer, { delegatedGrantId });
this._message.authorization.ownerSignature = ownerSignature;
this._message.authorization.ownerDelegatedGrant = delegatedGrant;
this._ownerSignaturePayload = Jws.decodePlainObjectPayload(ownerSignature);
this._owner = Jws.getSignerDid(delegatedGrant.authorization.signature.signatures[0]);
});
}
/**
* Validates the integrity of the RecordsWrite message assuming the message passed basic schema validation.
* There is opportunity to integrate better with `validateSchema(...)`
*/
validateIntegrity() {
return __awaiter(this, void 0, void 0, function* () {
// if the new message is the initial write
const isInitialWrite = yield this.isInitialWrite();
if (isInitialWrite) {
// `messageTimestamp` and `dateCreated` equality check
const dateRecordCreated = this.message.descriptor.dateCreated;
const messageTimestamp = this.message.descriptor.messageTimestamp;
if (messageTimestamp !== dateRecordCreated) {
throw new DwnError(DwnErrorCode.RecordsWriteValidateIntegrityDateCreatedMismatch, `messageTimestamp ${messageTimestamp} must match dateCreated ${dateRecordCreated} for the initial write`);
}
// if the message is also a protocol context root, the `contextId` must match the expected deterministic value
if (this.message.descriptor.protocol !== undefined &&
this.message.descriptor.parentId === undefined) {
const expectedContextId = yield this.getEntryId();
if (this.message.contextId !== expectedContextId) {
throw new DwnError(DwnErrorCode.RecordsWriteValidateIntegrityContextIdMismatch, `contextId in message: ${this.message.contextId} does not match deterministic contextId: ${expectedContextId}`);
}
}
}
// NOTE: validateSignatureStructure() call earlier enforces the presence of `authorization` and thus `signature` in RecordsWrite
const signaturePayload = this.signaturePayload;
// make sure the `recordId` in message is the same as the `recordId` in the payload of the message signature
if (this.message.recordId !== signaturePayload.recordId) {
throw new DwnError(DwnErrorCode.RecordsWriteValidateIntegrityRecordIdUnauthorized, `recordId in message ${this.message.recordId} does not match recordId in authorization: ${signaturePayload.recordId}`);
}
// if `contextId` is given in message, make sure the same `contextId` is in the payload of the message signature
if (this.message.contextId !== signaturePayload.contextId) {
throw new DwnError(DwnErrorCode.RecordsWriteValidateIntegrityContextIdNotInSignerSignaturePayload, `contextId in message ${this.message.contextId} does not match contextId in authorization: ${signaturePayload.contextId}`);
}
yield Records.validateDelegatedGrantReferentialIntegrity(this.message, signaturePayload, this.ownerSignaturePayload);
// if `attestation` is given in message, make sure the correct `attestationCid` is in the payload of the message signature
if (signaturePayload.attestationCid !== undefined) {
const expectedAttestationCid = yield Cid.computeCid(this.message.attestation);
const actualAttestationCid = signaturePayload.attestationCid;
if (actualAttestationCid !== expectedAttestationCid) {
throw new DwnError(DwnErrorCode.RecordsWriteValidateIntegrityAttestationMismatch, `CID ${expectedAttestationCid} of attestation property in message does not match attestationCid in authorization: ${actualAttestationCid}`);
}
}
// if `encryption` is given in message, make sure the correct `encryptionCid` is in the payload of the message signature
if (signaturePayload.encryptionCid !== undefined) {
const expectedEncryptionCid = yield Cid.computeCid(this.message.encryption);
const actualEncryptionCid = signaturePayload.encryptionCid;
if (actualEncryptionCid !== expectedEncryptionCid) {
throw new DwnError(DwnErrorCode.RecordsWriteValidateIntegrityEncryptionCidMismatch, `CID ${expectedEncryptionCid} of encryption property in message does not match encryptionCid in authorization: ${actualEncryptionCid}`);
}
}
if (this.message.descriptor.protocol !== undefined) {
validateProtocolUrlNormalized(this.message.descriptor.protocol);
}
if (this.message.descriptor.schema !== undefined) {
validateSchemaUrlNormalized(this.message.descriptor.schema);
}
Time.validateTimestamp(this.message.descriptor.messageTimestamp);
Time.validateTimestamp(this.message.descriptor.dateCreated);
if (this.message.descriptor.datePublished) {
Time.validateTimestamp(this.message.descriptor.datePublished);
}
});
}
/**
* Validates the structural integrity of the `attestation` property.
* NOTE: signature is not verified.
*/
static validateAttestationIntegrity(message) {
return __awaiter(this, void 0, void 0, function* () {
if (message.attestation === undefined) {
return;
}
// TODO: multi-attesters to be unblocked by #205 - Revisit database interfaces (https://github.com/TBD54566975/dwn-sdk-js/issues/205)
if (message.attestation.signatures.length !== 1) {
throw new DwnError(DwnErrorCode.RecordsWriteAttestationIntegrityMoreThanOneSignature, `Currently implementation only supports 1 attester, but got ${message.attestation.signatures.length}`);
}
const payloadJson = Jws.decodePlainObjectPayload(message.attestation);
const { descriptorCid } = payloadJson;
// `descriptorCid` validation - ensure that the provided descriptorCid matches the CID of the actual message
const expectedDescriptorCid = yield Cid.computeCid(message.descriptor);
if (descriptorCid !== expectedDescriptorCid) {
throw new DwnError(DwnErrorCode.RecordsWriteAttestationIntegrityDescriptorCidMismatch, `descriptorCid ${descriptorCid} does not match expected descriptorCid ${expectedDescriptorCid}`);
}
// check to ensure that no other unexpected properties exist in payload.
const propertyCount = Object.keys(payloadJson).length;
if (propertyCount > 1) {
throw new DwnError(DwnErrorCode.RecordsWriteAttestationIntegrityInvalidPayloadProperty, `Only 'descriptorCid' is allowed in attestation payload, but got ${propertyCount} properties.`);
}
});
}
;
/**
* Computes the deterministic Entry ID of this message.
*/
getEntryId() {
return __awaiter(this, void 0, void 0, function* () {
const entryId = yield RecordsWrite.getEntryId(this.author, this.message.descriptor);
return entryId;
});
}
;
/**
* Computes the deterministic Entry ID of this message.
*/
static getEntryId(author, descriptor) {
return __awaiter(this, void 0, void 0, function* () {
if (author === undefined) {
throw new DwnError(DwnErrorCode.RecordsWriteGetEntryIdUndefinedAuthor, 'Property `author` is needed to compute entry ID.');
}
const entryIdInput = Object.assign({}, descriptor);
entryIdInput.author = author;
const cid = yield Cid.computeCid(entryIdInput);
return cid;
});
}
;
/**
* Checks if the given message is the initial entry of a record.
*/
isInitialWrite() {
return __awaiter(this, void 0, void 0, function* () {
const entryId = yield this.getEntryId();
return (entryId === this.message.recordId);
});
}
constructIndexes(isLatestBaseState) {
return __awaiter(this, void 0, void 0, function* () {
const message = this.message;
// we want to process tags separately from the rest of descriptors as it is an object and not a primitive KeyValue type.
const _a = message.descriptor, { tags } = _a, descriptor = __rest(_a, ["tags"]);
delete descriptor.published; // handle `published` specifically further down
let indexes = Object.assign(Object.assign({}, descriptor), { isLatestBaseState, published: !!message.descriptor.published, author: this.author, recordId: message.recordId, entryId: yield RecordsWrite.getEntryId(this.author, this.message.descriptor) });
// in order to avoid name clashes with first-class index keys
// we build the indexes with `tag.property_name` for each tag property.
// we only index tags if the message is the latest base state, as that's the only time filtering for tags is relevant.
if (tags !== undefined && isLatestBaseState === true) {
const flattenedTags = Records.buildTagIndexes(Object.assign({}, tags));
indexes = Object.assign(Object.assign({}, indexes), flattenedTags);
}
// add additional indexes to optional values if given
// TODO: index multi-attesters to be unblocked by #205 - Revisit database interfaces (https://github.com/TBD54566975/dwn-sdk-js/issues/205)
if (this.attesters.length > 0) {
indexes.attester = this.attesters[0];
}
if (message.contextId !== undefined) {
indexes.contextId = message.contextId;
}
return indexes;
});
}
/**
* Authorizes the author-delegate who signed this message.
* @param messageStore Used to check if the grant has been revoked.
*/
authorizeAuthorDelegate(messageStore) {
return __awaiter(this, void 0, void 0, function* () {
const delegatedGrant = yield PermissionGrant.parse(this.message.authorization.authorDelegatedGrant);
yield RecordsGrantAuthorization.authorizeWrite({
recordsWriteMessage: this.message,
expectedGrantor: this.author,
expectedGrantee: this.signer,
permissionGrant: delegatedGrant,
messageStore
});
});
}
/**
* Authorizes the owner-delegate who signed this message.
* @param messageStore Used to check if the grant has been revoked.
*/
authorizeOwnerDelegate(messageStore) {
return __awaiter(this, void 0, void 0, function* () {
const delegatedGrant = yield PermissionGrant.parse(this.message.authorization.ownerDelegatedGrant);
yield RecordsGrantAuthorization.authorizeWrite({
recordsWriteMessage: this.message,
expectedGrantor: this.owner,
expectedGrantee: this.ownerSignatureSigner,
permissionGrant: delegatedGrant,
messageStore
});
});
}
/**
* Checks if the given message is the initial entry of a record.
*/
static isInitialWrite(message) {
return __awaiter(this, void 0, void 0, function* () {
// can't be the initial write if the message is not a Records Write
if (message.descriptor.interface !== DwnInterfaceName.Records ||
message.descriptor.method !== DwnMethodName.Write) {
return false;
}
const recordsWriteMessage = message;
const author = Records.getAuthor(recordsWriteMessage);
const entryId = yield RecordsWrite.getEntryId(author, recordsWriteMessage.descriptor);
return (entryId === recordsWriteMessage.recordId);
});
}
/**
* Creates the `encryption` property if encryption input is given. Else `undefined` is returned.
* @param descriptor Descriptor of the `RecordsWrite` message which contains the information need by key path derivation schemes.
*/
static createEncryptionProperty(descriptor, encryptionInput) {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () {
if (encryptionInput === undefined) {
return undefined;
}
// encrypt the data encryption key once per encryption input
const keyEncryption = [];
for (const keyEncryptionInput of encryptionInput.keyEncryptionInputs) {
if (keyEncryptionInput.derivationScheme === KeyDerivationScheme.ProtocolPath && descriptor.protocol === undefined) {
throw new DwnError(DwnErrorCode.RecordsWriteMissingProtocol, '`protocols` encryption scheme cannot be applied to record without the `protocol` property.');
}
if (keyEncryptionInput.derivationScheme === KeyDerivationScheme.Schemas && descriptor.schema === undefined) {
throw new DwnError(DwnErrorCode.RecordsWriteMissingSchema, '`schemas` encryption scheme cannot be applied to record without the `schema` property.');
}
// NOTE: right now only `ECIES-ES256K` algorithm is supported for asymmetric encryption,
// so we will assume that's the algorithm without additional switch/if statements
const publicKeyBytes = Secp256k1.publicJwkToBytes(keyEncryptionInput.publicKey);
const keyEncryptionOutput = yield Encryption.eciesSecp256k1Encrypt(publicKeyBytes, encryptionInput.key);
const encryptedKey = Encoder.bytesToBase64Url(keyEncryptionOutput.ciphertext);
const ephemeralPublicKey = yield Secp256k1.publicKeyToJwk(keyEncryptionOutput.ephemeralPublicKey);
const keyEncryptionInitializationVector = Encoder.bytesToBase64Url(keyEncryptionOutput.initializationVector);
const messageAuthenticationCode = Encoder.bytesToBase64Url(keyEncryptionOutput.messageAuthenticationCode);
const encryptedKeyData = {
rootKeyId: keyEncryptionInput.publicKeyId,
algorithm: (_a = keyEncryptionInput.algorithm) !== null && _a !== void 0 ? _a : EncryptionAlgorithm.EciesSecp256k1,
derivationScheme: keyEncryptionInput.derivationScheme,
ephemeralPublicKey,
initializationVector: keyEncryptionInitializationVector,
messageAuthenticationCode,
encryptedKey
};
// we need to attach the actual public key if derivation scheme is protocol-context,
// so that the responder to this message is able to encrypt the message/symmetric key using the same protocol-context derived public key,
// without needing the knowledge of the corresponding private key
if (keyEncryptionInput.derivationScheme === KeyDerivationScheme.ProtocolContext) {
encryptedKeyData.derivedPublicKey = keyEncryptionInput.publicKey;
}
keyEncryption.push(encryptedKeyData);
}
const encryption = {
algorithm: (_b = encryptionInput.algorithm) !== null && _b !== void 0 ? _b : EncryptionAlgorithm.Aes256Ctr,
initializationVector: Encoder.bytesToBase64Url(encryptionInput.initializationVector),
keyEncryption
};
return encryption;
});
}
/**
* Creates the `attestation` property of a RecordsWrite message if given signature inputs; returns `undefined` otherwise.
*/
static createAttestation(descriptorCid, signers) {
return __awaiter(this, void 0, void 0, function* () {
if (signers === undefined || signers.length === 0) {
return undefined;
}
const attestationPayload = { descriptorCid };
const attestationPayloadBytes = Encoder.objectToBytes(attestationPayload);
const builder = yield GeneralJwsBuilder.create(attestationPayloadBytes, signers);
return builder.getJws();
});
}
/**
* Creates the `signature` property in the `authorization` of a `RecordsWrite` message.
*/
static createSignerSignature(input) {
return __awaiter(this, void 0, void 0, function* () {
const { recordId, contextId, descriptorCid, attestation, encryption, signer, delegatedGrantId, permissionGrantId, protocolRole } = input;
const attestationCid = attestation ? yield Cid.computeCid(attestation) : undefined;
const encryptionCid = encryption ? yield Cid.computeCid(encryption) : undefined;
const signaturePayload = {
recordId,
descriptorCid,
contextId,
attestationCid,
encryptionCid,
delegatedGrantId,
permissionGrantId,
protocolRole
};
removeUndefinedProperties(signaturePayload);
const signaturePayloadBytes = Encoder.objectToBytes(signaturePayload);
const builder = yield GeneralJwsBuilder.create(signaturePayloadBytes, [signer]);
const signature = builder.getJws();
return signature;
});
}
/**
* Gets the initial write from the given list of `RecordsWrite`.
*/
static getInitialWrite(messages) {
return __awaiter(this, void 0, void 0, function* () {
for (const message of messages) {
if (yield RecordsWrite.isInitialWrite(message)) {
return message;
}
}
throw new DwnError(DwnErrorCode.RecordsWriteGetInitialWriteNotFound, `Initial write is not found.`);
});
}
/**
* Verifies that immutable properties of the two given messages are identical.
* @throws {Error} if immutable properties between two RecordsWrite message
*/
static verifyEqualityOfImmutableProperties(existingWriteMessage, newMessage) {
const mutableDescriptorProperties = ['dataCid', 'dataSize', 'dataFormat', 'datePublished', 'published', 'messageTimestamp', 'tags'];
// get distinct property names that exist in either the existing message given or new message
let descriptorPropertyNames = [];
descriptorPropertyNames.push(...Object.keys(existingWriteMessage.descriptor));
descriptorPropertyNames.push(...Object.keys(newMessage.descriptor));
descriptorPropertyNames = [...new Set(descriptorPropertyNames)]; // step to remove duplicates
// ensure all immutable properties are not modified
for (const descriptorPropertyName of descriptorPropertyNames) {
// if property is supposed to be immutable
if (mutableDescriptorProperties.indexOf(descriptorPropertyName) === -1) {
const valueInExistingWrite = existingWriteMessage.descriptor[descriptorPropertyName];
const valueInNewMessage = newMessage.descriptor[descriptorPropertyName];
if (valueInNewMessage !== valueInExistingWrite) {
throw new DwnError(DwnErrorCode.RecordsWriteImmutablePropertyChanged, `${descriptorPropertyName} is an immutable property: cannot change '${valueInExistingWrite}' to '${valueInNewMessage}'`);
}
}
}
return true;
}
/**
* Gets the DID of the attesters of the given message.
*/
static getAttesters(message) {
var _a, _b;
const attestationSignatures = (_b = (_a = message.attestation) === null || _a === void 0 ? void 0 : _a.signatures) !== null && _b !== void 0 ? _b : [];
const attesters = attestationSignatures.map((signature) => Jws.getSignerDid(signature));
return attesters;
}
/**
* Fetches the initial RecordsWrite of a record.
* @returns The initial RecordsWrite if found; `undefined` if the record is not found.
*/
static fetchInitialRecordsWrite(messageStore, tenant, recordId) {
return __awaiter(this, void 0, void 0, function* () {
const query = { entryId: recordId };
const { messages } = yield messageStore.query(tenant, [query]);
if (messages.length === 0) {
return undefined;
}
const initialRecordsWrite = yield RecordsWrite.parse(messages[0]);
return initialRecordsWrite;
});
}
}
//# sourceMappingURL=records-write.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,51 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import * as Ed25519 from '@noble/ed25519';
import { Encoder } from '../../../utils/encoder.js';
import { DwnError, DwnErrorCode } from '../../../core/dwn-error.js';
function validateKey(jwk) {
if (jwk.kty !== 'OKP' || jwk.crv !== 'Ed25519') {
throw new DwnError(DwnErrorCode.Ed25519InvalidJwk, 'invalid jwk. kty MUST be OKP. crv MUST be Ed25519');
}
}
function publicKeyToJwk(publicKeyBytes) {
const x = Encoder.bytesToBase64Url(publicKeyBytes);
const publicJwk = {
alg: 'EdDSA',
kty: 'OKP',
crv: 'Ed25519',
x
};
return publicJwk;
}
export const ed25519 = {
sign: (content, privateJwk) => __awaiter(void 0, void 0, void 0, function* () {
validateKey(privateJwk);
const privateKeyBytes = Encoder.base64UrlToBytes(privateJwk.d);
return Ed25519.signAsync(content, privateKeyBytes);
}),
verify: (content, signature, publicJwk) => __awaiter(void 0, void 0, void 0, function* () {
validateKey(publicJwk);
const publicKeyBytes = Encoder.base64UrlToBytes(publicJwk.x);
return Ed25519.verifyAsync(signature, content, publicKeyBytes);
}),
generateKeyPair: () => __awaiter(void 0, void 0, void 0, function* () {
const privateKeyBytes = Ed25519.utils.randomPrivateKey();
const publicKeyBytes = yield Ed25519.getPublicKeyAsync(privateKeyBytes);
const d = Encoder.bytesToBase64Url(privateKeyBytes);
const publicJwk = publicKeyToJwk(publicKeyBytes);
const privateJwk = Object.assign(Object.assign({}, publicJwk), { d });
return { publicJwk, privateJwk };
}),
publicKeyToJwk: (publicKeyBytes) => __awaiter(void 0, void 0, void 0, function* () {
return publicKeyToJwk(publicKeyBytes);
})
};
//# sourceMappingURL=ed25519.js.map
@@ -0,0 +1 @@
{"version":3,"file":"ed25519.js","sourceRoot":"","sources":["../../../../../../src/jose/algorithms/signing/ed25519.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAG1C,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAEpE,SAAS,WAAW,CAAC,GAA2B;IAC9C,IAAI,GAAG,CAAC,GAAG,KAAK,KAAK,IAAI,GAAG,CAAC,GAAG,KAAK,SAAS,EAAE;QAC9C,MAAM,IAAI,QAAQ,CAAC,YAAY,CAAC,iBAAiB,EAAE,mDAAmD,CAAC,CAAC;KACzG;AACH,CAAC;AAED,SAAS,cAAc,CAAC,cAA0B;IAChD,MAAM,CAAC,GAAG,OAAO,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC;IAEnD,MAAM,SAAS,GAAc;QAC3B,GAAG,EAAG,OAAO;QACb,GAAG,EAAG,KAAK;QACX,GAAG,EAAG,SAAS;QACf,CAAC;KACF,CAAC;IAEF,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAuB;IACzC,IAAI,EAAE,CAAO,OAAmB,EAAE,UAAsB,EAAuB,EAAE;QAC/E,WAAW,CAAC,UAAU,CAAC,CAAC;QAExB,MAAM,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAE/D,OAAO,OAAO,CAAC,SAAS,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;IACrD,CAAC,CAAA;IAED,MAAM,EAAE,CAAO,OAAmB,EAAE,SAAqB,EAAE,SAAoB,EAAoB,EAAE;QACnG,WAAW,CAAC,SAAS,CAAC,CAAC;QAEvB,MAAM,cAAc,GAAG,OAAO,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAE7D,OAAO,OAAO,CAAC,WAAW,CAAC,SAAS,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC;IACjE,CAAC,CAAA;IAED,eAAe,EAAE,GAAkE,EAAE;QACnF,MAAM,eAAe,GAAG,OAAO,CAAC,KAAK,CAAC,gBAAgB,EAAE,CAAC;QACzD,MAAM,cAAc,GAAG,MAAM,OAAO,CAAC,iBAAiB,CAAC,eAAe,CAAC,CAAC;QAExE,MAAM,CAAC,GAAG,OAAO,CAAC,gBAAgB,CAAC,eAAe,CAAC,CAAC;QAEpD,MAAM,SAAS,GAAG,cAAc,CAAC,cAAc,CAAC,CAAC;QACjD,MAAM,UAAU,mCAAoB,SAAS,KAAE,CAAC,GAAE,CAAC;QAEnD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC;IACnC,CAAC,CAAA;IAED,cAAc,EAAE,CAAO,cAA0B,EAAsB,EAAE;QACvE,OAAO,cAAc,CAAC,cAAc,CAAC,CAAC;IACxC,CAAC,CAAA;CACF,CAAC"}
@@ -0,0 +1,20 @@
import { ed25519 } from './ed25519.js';
import { Secp256k1 } from '../../../utils/secp256k1.js';
import { Secp256r1 } from '../../../utils/secp256r1.js';
// the key should be the appropriate `crv` value
export const signatureAlgorithms = {
'Ed25519': ed25519,
'secp256k1': {
sign: Secp256k1.sign,
verify: Secp256k1.verify,
generateKeyPair: Secp256k1.generateKeyPair,
publicKeyToJwk: Secp256k1.publicKeyToJwk
},
'P-256': {
sign: Secp256r1.sign,
verify: Secp256r1.verify,
generateKeyPair: Secp256r1.generateKeyPair,
publicKeyToJwk: Secp256r1.publicKeyToJwk,
},
};
//# sourceMappingURL=signature-algorithms.js.map
@@ -0,0 +1 @@
{"version":3,"file":"signature-algorithms.js","sourceRoot":"","sources":["../../../../../../src/jose/algorithms/signing/signature-algorithms.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAExD,gDAAgD;AAChD,MAAM,CAAC,MAAM,mBAAmB,GAAuC;IACrE,SAAS,EAAK,OAAO;IACrB,WAAW,EAAG;QACZ,IAAI,EAAc,SAAS,CAAC,IAAI;QAChC,MAAM,EAAY,SAAS,CAAC,MAAM;QAClC,eAAe,EAAG,SAAS,CAAC,eAAe;QAC3C,cAAc,EAAI,SAAS,CAAC,cAAc;KAC3C;IACD,OAAO,EAAE;QACP,IAAI,EAAc,SAAS,CAAC,IAAI;QAChC,MAAM,EAAY,SAAS,CAAC,MAAM;QAClC,eAAe,EAAG,SAAS,CAAC,eAAe;QAC3C,cAAc,EAAI,SAAS,CAAC,cAAc;KAC3C;CACF,CAAC"}
@@ -0,0 +1,47 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Encoder } from '../../../utils/encoder.js';
export class GeneralJwsBuilder {
constructor(jws) {
this.jws = jws;
}
static create(payload, signers = []) {
return __awaiter(this, void 0, void 0, function* () {
const jws = {
payload: Encoder.bytesToBase64Url(payload),
signatures: []
};
const builder = new GeneralJwsBuilder(jws);
for (const signer of signers) {
yield builder.addSignature(signer);
}
return builder;
});
}
addSignature(signer) {
return __awaiter(this, void 0, void 0, function* () {
const protectedHeader = {
kid: signer.keyId,
alg: signer.algorithm
};
const protectedHeaderString = JSON.stringify(protectedHeader);
const protectedHeaderBase64UrlString = Encoder.stringToBase64Url(protectedHeaderString);
const signingInputString = `${protectedHeaderBase64UrlString}.${this.jws.payload}`;
const signingInputBytes = Encoder.stringToBytes(signingInputString);
const signatureBytes = yield signer.sign(signingInputBytes);
const signature = Encoder.bytesToBase64Url(signatureBytes);
this.jws.signatures.push({ protected: protectedHeaderBase64UrlString, signature });
});
}
getJws() {
return this.jws;
}
}
//# sourceMappingURL=builder.js.map
@@ -0,0 +1 @@
{"version":3,"file":"builder.js","sourceRoot":"","sources":["../../../../../../src/jose/jws/general/builder.ts"],"names":[],"mappings":";;;;;;;;;AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAEpD,MAAM,OAAO,iBAAiB;IAG5B,YAAoB,GAAe;QACjC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;IAED,MAAM,CAAO,MAAM,CAAC,OAAmB,EAAE,UAAoB,EAAE;;YAC7D,MAAM,GAAG,GAAe;gBACtB,OAAO,EAAM,OAAO,CAAC,gBAAgB,CAAC,OAAO,CAAC;gBAC9C,UAAU,EAAG,EAAE;aAChB,CAAC;YAEF,MAAM,OAAO,GAAG,IAAI,iBAAiB,CAAC,GAAG,CAAC,CAAC;YAE3C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE;gBAC5B,MAAM,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;aACpC;YAED,OAAO,OAAO,CAAC;QACjB,CAAC;KAAA;IAEK,YAAY,CAAC,MAAc;;YAC/B,MAAM,eAAe,GAAG;gBACtB,GAAG,EAAG,MAAM,CAAC,KAAK;gBAClB,GAAG,EAAG,MAAM,CAAC,SAAS;aACvB,CAAC;YACF,MAAM,qBAAqB,GAAG,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;YAC9D,MAAM,8BAA8B,GAAG,OAAO,CAAC,iBAAiB,CAAC,qBAAqB,CAAC,CAAC;YAExF,MAAM,kBAAkB,GAAG,GAAG,8BAA8B,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;YACnF,MAAM,iBAAiB,GAAG,OAAO,CAAC,aAAa,CAAC,kBAAkB,CAAC,CAAC;YAEpE,MAAM,cAAc,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;YAC5D,MAAM,SAAS,GAAG,OAAO,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC;YAE3D,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,8BAA8B,EAAE,SAAS,EAAE,CAAC,CAAC;QACrF,CAAC;KAAA;IAED,MAAM;QACJ,OAAO,IAAI,CAAC,GAAG,CAAC;IAClB,CAAC;CACF"}
@@ -0,0 +1,97 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Jws } from '../../../utils/jws.js';
import { MemoryCache } from '../../../utils/memory-cache.js';
import { validateJsonSchema } from '../../../schema-validator.js';
import { DwnError, DwnErrorCode } from '../../../core/dwn-error.js';
/**
* Verifies the signature(s) of a General JWS.
*/
export class GeneralJwsVerifier {
constructor(cache) {
this.cache = cache || new MemoryCache(600);
}
static get singleton() {
if (GeneralJwsVerifier._singleton === undefined) {
GeneralJwsVerifier._singleton = new GeneralJwsVerifier();
}
return GeneralJwsVerifier._singleton;
}
/**
* Verifies the signatures of the given General JWS.
* @returns the list of signers that have valid signatures.
*/
static verifySignatures(jws, didResolver) {
return __awaiter(this, void 0, void 0, function* () {
return yield GeneralJwsVerifier.singleton.verifySignatures(jws, didResolver);
});
}
/**
* Verifies the signatures of the given General JWS.
* @returns the list of signers that have valid signatures.
*/
verifySignatures(jws, didResolver) {
return __awaiter(this, void 0, void 0, function* () {
const signers = [];
for (const signatureEntry of jws.signatures) {
let isVerified;
const kid = Jws.getKid(signatureEntry);
const cacheKey = `${signatureEntry.protected}.${jws.payload}.${signatureEntry.signature}`;
const cachedValue = yield this.cache.get(cacheKey);
// explicit `undefined` check to differentiate `false`
if (cachedValue === undefined) {
const publicJwk = yield GeneralJwsVerifier.getPublicKey(kid, didResolver);
isVerified = yield Jws.verifySignature(jws.payload, signatureEntry, publicJwk);
yield this.cache.set(cacheKey, isVerified);
}
else {
isVerified = cachedValue;
}
const did = Jws.extractDid(kid);
if (isVerified) {
signers.push(did);
}
else {
throw new DwnError(DwnErrorCode.GeneralJwsVerifierInvalidSignature, `Signature verification failed for ${did}`);
}
}
return { signers };
});
}
/**
* Gets the public key given a fully qualified key ID (`kid`) by resolving the DID to its DID Document.
*/
static getPublicKey(kid, didResolver) {
return __awaiter(this, void 0, void 0, function* () {
// `resolve` throws exception if DID is invalid, DID method is not supported,
// or resolving DID fails
const did = Jws.extractDid(kid);
const { didDocument } = yield didResolver.resolve(did);
const { verificationMethod: verificationMethods = [] } = didDocument || {};
let verificationMethod;
for (const method of verificationMethods) {
// consider optimizing using a set for O(1) lookups if needed
// key ID in DID Document may or may not be fully qualified. e.g.
// `did:ion:alice#key1` or `#key1`
if (kid.endsWith(method.id)) {
verificationMethod = method;
break;
}
}
if (!verificationMethod) {
throw new DwnError(DwnErrorCode.GeneralJwsVerifierGetPublicKeyNotFound, 'public key needed to verify signature not found in DID Document');
}
validateJsonSchema('JwkVerificationMethod', verificationMethod);
const { publicKeyJwk: publicJwk } = verificationMethod;
return publicJwk;
});
}
}
//# sourceMappingURL=verifier.js.map
@@ -0,0 +1 @@
{"version":3,"file":"verifier.js","sourceRoot":"","sources":["../../../../../../src/jose/jws/general/verifier.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Encoder } from '../utils/encoder.js';
import { Message } from '../core/message.js';
/**
* A class representing a Permission Grant for a more convenient abstraction.
*/
export class PermissionGrant {
static parse(message) {
return __awaiter(this, void 0, void 0, function* () {
const permissionGrant = new PermissionGrant(message);
return permissionGrant;
});
}
/**
* Creates a Permission Grant abstraction for
*/
constructor(message) {
// properties derived from the generic DWN message properties
this.id = message.recordId;
this.grantor = Message.getSigner(message);
this.grantee = message.descriptor.recipient;
this.dateGranted = message.descriptor.dateCreated;
// properties from the data payload itself.
const permissionGrantEncoded = message.encodedData;
const permissionGrant = Encoder.base64UrlToObject(permissionGrantEncoded);
this.dateExpires = permissionGrant.dateExpires;
this.delegated = permissionGrant.delegated;
this.description = permissionGrant.description;
this.requestId = permissionGrant.requestId;
this.scope = permissionGrant.scope;
this.conditions = permissionGrant.conditions;
}
}
//# sourceMappingURL=permission-grant.js.map
@@ -0,0 +1 @@
{"version":3,"file":"permission-grant.js","sourceRoot":"","sources":["../../../../src/protocols/permission-grant.ts"],"names":[],"mappings":";;;;;;;;;AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAG7C;;GAEG;AACH,MAAM,OAAO,eAAe;IAoDnB,MAAM,CAAO,KAAK,CAAC,OAA4B;;YACpD,MAAM,eAAe,GAAG,IAAI,eAAe,CAAC,OAAO,CAAC,CAAC;YACrD,OAAO,eAAe,CAAC;QACzB,CAAC;KAAA;IAED;;OAEG;IACH,YAAoB,OAA4B;QAC9C,6DAA6D;QAC7D,IAAI,CAAC,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC;QAC3B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,OAAO,CAAE,CAAC;QAC3C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,SAAU,CAAC;QAC7C,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC;QAElD,2CAA2C;QAC3C,MAAM,sBAAsB,GAAI,OAAkC,CAAC,WAAY,CAAC;QAChF,MAAM,eAAe,GAAG,OAAO,CAAC,iBAAiB,CAAC,sBAAsB,CAAwB,CAAC;QACjG,IAAI,CAAC,WAAW,GAAG,eAAe,CAAC,WAAW,CAAC;QAC/C,IAAI,CAAC,SAAS,GAAG,eAAe,CAAC,SAAS,CAAC;QAC3C,IAAI,CAAC,WAAW,GAAG,eAAe,CAAC,WAAW,CAAC;QAC/C,IAAI,CAAC,SAAS,GAAG,eAAe,CAAC,SAAS,CAAC;QAC3C,IAAI,CAAC,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC;QACnC,IAAI,CAAC,UAAU,GAAG,eAAe,CAAC,UAAU,CAAC;IAC/C,CAAC;CACF"}
@@ -0,0 +1,276 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Encoder } from '../utils/encoder.js';
import { PermissionGrant } from './permission-grant.js';
import { RecordsWrite } from '../../src/interfaces/records-write.js';
import { Time } from '../utils/time.js';
import { validateJsonSchema } from '../schema-validator.js';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
import { normalizeProtocolUrl, normalizeSchemaUrl } from '../utils/url.js';
/**
* This is a first-class DWN protocol for managing permission grants of a given DWN.
*/
export class PermissionsProtocol {
static parseRequest(base64UrlEncodedRequest) {
return Encoder.base64UrlToObject(base64UrlEncodedRequest);
}
/**
* Convenience method to create a permission request.
*/
static createRequest(options) {
return __awaiter(this, void 0, void 0, function* () {
const scope = PermissionsProtocol.normalizePermissionScope(options.scope);
const permissionRequestData = {
description: options.description,
delegated: options.delegated,
scope,
conditions: options.conditions,
};
const permissionRequestBytes = Encoder.objectToBytes(permissionRequestData);
const recordsWrite = yield RecordsWrite.create({
signer: options.signer,
messageTimestamp: options.dateRequested,
protocol: PermissionsProtocol.uri,
protocolPath: PermissionsProtocol.requestPath,
dataFormat: 'application/json',
data: permissionRequestBytes,
});
return {
recordsWrite,
permissionRequestData,
permissionRequestBytes
};
});
}
/**
* Convenience method to create a permission grant.
*/
static createGrant(options) {
return __awaiter(this, void 0, void 0, function* () {
const scope = PermissionsProtocol.normalizePermissionScope(options.scope);
const permissionGrantData = {
dateExpires: options.dateExpires,
requestId: options.requestId,
description: options.description,
delegated: options.delegated,
scope,
conditions: options.conditions,
};
const permissionGrantBytes = Encoder.objectToBytes(permissionGrantData);
const recordsWrite = yield RecordsWrite.create({
signer: options.signer,
messageTimestamp: options.dateGranted,
dateCreated: options.dateGranted,
recipient: options.grantedTo,
protocol: PermissionsProtocol.uri,
protocolPath: PermissionsProtocol.grantPath,
dataFormat: 'application/json',
data: permissionGrantBytes,
});
const dataEncodedMessage = Object.assign(Object.assign({}, recordsWrite.message), { encodedData: Encoder.bytesToBase64Url(permissionGrantBytes) });
return {
recordsWrite,
permissionGrantData,
permissionGrantBytes,
dataEncodedMessage
};
});
}
/**
* Convenience method to create a permission revocation.
*/
static createRevocation(options) {
return __awaiter(this, void 0, void 0, function* () {
const permissionRevocationData = {
description: options.description,
};
const permissionRevocationBytes = Encoder.objectToBytes(permissionRevocationData);
const recordsWrite = yield RecordsWrite.create({
signer: options.signer,
parentContextId: options.grantId,
protocol: PermissionsProtocol.uri,
protocolPath: PermissionsProtocol.revocationPath,
dataFormat: 'application/json',
data: permissionRevocationBytes,
});
return {
recordsWrite,
permissionRevocationData,
permissionRevocationBytes
};
});
}
/**
* Validates the given Permissions protocol RecordsWrite. It can be a request, grant, or revocation.
*/
static validateSchema(recordsWriteMessage, dataBytes) {
const dataString = Encoder.bytesToString(dataBytes);
const dataObject = JSON.parse(dataString);
if (recordsWriteMessage.descriptor.protocolPath === PermissionsProtocol.requestPath) {
validateJsonSchema('PermissionRequestData', dataObject);
}
else if (recordsWriteMessage.descriptor.protocolPath === PermissionsProtocol.grantPath) {
validateJsonSchema('PermissionGrantData', dataObject);
// more nuanced validation that are annoying/difficult to do using JSON schema
const permissionGrantData = dataObject;
PermissionsProtocol.validateScope(permissionGrantData.scope);
Time.validateTimestamp(permissionGrantData.dateExpires);
}
else if (recordsWriteMessage.descriptor.protocolPath === PermissionsProtocol.revocationPath) {
validateJsonSchema('PermissionRevocationData', dataObject);
}
else {
// defensive programming, should be unreachable externally
throw new DwnError(DwnErrorCode.PermissionsProtocolValidateSchemaUnexpectedRecord, `Unexpected permission record: ${recordsWriteMessage.descriptor.protocolPath}`);
}
}
/**
* Fetches PermissionGrant with the specified `recordID`.
* @returns the PermissionGrant matching the `recordId` specified.
* @throws {Error} if PermissionGrant does not exist
*/
static fetchGrant(tenant, messageStore, permissionGrantId) {
return __awaiter(this, void 0, void 0, function* () {
const grantQuery = {
recordId: permissionGrantId,
isLatestBaseState: true
};
const { messages } = yield messageStore.query(tenant, [grantQuery]);
const possibleGrantMessage = messages[0];
const dwnInterface = possibleGrantMessage === null || possibleGrantMessage === void 0 ? void 0 : possibleGrantMessage.descriptor.interface;
const dwnMethod = possibleGrantMessage === null || possibleGrantMessage === void 0 ? void 0 : possibleGrantMessage.descriptor.method;
if (dwnInterface !== DwnInterfaceName.Records ||
dwnMethod !== DwnMethodName.Write ||
possibleGrantMessage.descriptor.protocolPath !== PermissionsProtocol.grantPath) {
throw new DwnError(DwnErrorCode.GrantAuthorizationGrantMissing, `Could not find permission grant with record ID ${permissionGrantId}.`);
}
const permissionGrantMessage = possibleGrantMessage;
const permissionGrant = yield PermissionGrant.parse(permissionGrantMessage);
return permissionGrant;
});
}
/**
* Normalizes the given permission scope if needed.
* @returns The normalized permission scope.
*/
static normalizePermissionScope(permissionScope) {
const scope = Object.assign({}, permissionScope);
if (PermissionsProtocol.isRecordPermissionScope(scope)) {
// normalize protocol and schema URLs if they are present
if (scope.protocol !== undefined) {
scope.protocol = normalizeProtocolUrl(scope.protocol);
}
if (scope.schema !== undefined) {
scope.schema = normalizeSchemaUrl(scope.schema);
}
}
return scope;
}
/**
* Type guard to determine if the scope is a record permission scope.
*/
static isRecordPermissionScope(scope) {
return scope.interface === 'Records';
}
/**
* Validates scope.
*/
static validateScope(scope) {
if (!this.isRecordPermissionScope(scope)) {
return;
}
// else we are dealing with a RecordsPermissionScope
// `schema` scopes may not have protocol-related fields
if (scope.schema !== undefined) {
if (scope.protocol !== undefined || scope.contextId !== undefined || scope.protocolPath) {
throw new DwnError(DwnErrorCode.PermissionsProtocolValidateScopeSchemaProhibitedProperties, 'Permission grants that have `schema` present cannot also have protocol-related properties present');
}
}
if (scope.protocol !== undefined) {
// `contextId` and `protocolPath` are mutually exclusive
if (scope.contextId !== undefined && scope.protocolPath !== undefined) {
throw new DwnError(DwnErrorCode.PermissionsProtocolValidateScopeContextIdProhibitedProperties, 'Permission grants cannot have both `contextId` and `protocolPath` present');
}
}
}
}
/**
* The URI of the DWN Permissions protocol.
*/
PermissionsProtocol.uri = 'https://tbd.website/dwn/permissions';
/**
* The protocol path of the `request` record.
*/
PermissionsProtocol.requestPath = 'request';
/**
* The protocol path of the `grant` record.
*/
PermissionsProtocol.grantPath = 'grant';
/**
* The protocol path of the `revocation` record.
*/
PermissionsProtocol.revocationPath = 'grant/revocation';
/**
* The definition of the Permissions protocol.
*/
PermissionsProtocol.definition = {
published: true,
protocol: PermissionsProtocol.uri,
types: {
request: {
dataFormats: ['application/json']
},
grant: {
dataFormats: ['application/json']
},
revocation: {
dataFormats: ['application/json']
}
},
structure: {
request: {
$size: {
max: 10000
},
$actions: [
{
who: 'anyone',
can: ['create']
}
]
},
grant: {
$size: {
max: 10000
},
$actions: [
{
who: 'recipient',
of: 'grant',
can: ['read', 'query']
}
],
revocation: {
$size: {
max: 10000
},
$actions: [
{
who: 'anyone',
can: ['read']
}
]
}
}
}
};
;
//# sourceMappingURL=permissions.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,37 @@
import * as precompiledValidators from '../generated/precompiled-validators.js';
import { DwnError, DwnErrorCode } from './core/dwn-error.js';
/**
* Validates the given payload using JSON schema keyed by the given schema name. Throws if the given payload fails validation.
* @param schemaName the schema name use to look up the JSON schema to be used for schema validation.
* The list of schema names can be found in compile-validators.js
* @param payload javascript object to be validated
*/
export function validateJsonSchema(schemaName, payload) {
// const validateFn = validator.getSchema(schemaName);
const validateFn = precompiledValidators[schemaName];
if (!validateFn) {
throw new DwnError(DwnErrorCode.SchemaValidatorSchemaNotFound, `schema for ${schemaName} not found.`);
}
validateFn(payload);
if (!validateFn.errors) {
return;
}
// AJV is configured by default to stop validating after the 1st error is encountered which means
// there will only ever be one error;
const [errorObj] = validateFn.errors;
let { instancePath, message, keyword } = errorObj;
if (!instancePath) {
instancePath = schemaName;
}
// handle a few frequently occurred errors to give more meaningful error for debugging
if (keyword === 'additionalProperties') {
const keyword = errorObj.params.additionalProperty;
throw new DwnError(DwnErrorCode.SchemaValidatorAdditionalPropertyNotAllowed, `${message}: ${instancePath}: ${keyword}`);
}
if (keyword === 'unevaluatedProperties') {
const keyword = errorObj.params.unevaluatedProperty;
throw new DwnError(DwnErrorCode.SchemaValidatorUnevaluatedPropertyNotAllowed, `${message}: ${instancePath}: ${keyword}`);
}
throw new DwnError(DwnErrorCode.SchemaValidatorFailure, `${instancePath}: ${message}`);
}
//# sourceMappingURL=schema-validator.js.map
@@ -0,0 +1 @@
{"version":3,"file":"schema-validator.js","sourceRoot":"","sources":["../../../src/schema-validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,qBAAqB,MAAM,wCAAwC,CAAC;AAChF,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAE7D;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,UAAkB,EAAE,OAAY;IACjE,sDAAsD;IACtD,MAAM,UAAU,GAAI,qBAA6B,CAAC,UAAU,CAAC,CAAC;IAE9D,IAAI,CAAC,UAAU,EAAE;QACf,MAAM,IAAI,QAAQ,CAAC,YAAY,CAAC,6BAA6B,EAAE,cAAc,UAAU,aAAa,CAAC,CAAC;KACvG;IAED,UAAU,CAAC,OAAO,CAAC,CAAC;IAEpB,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE;QACtB,OAAO;KACR;IAED,iGAAiG;IACjG,qCAAqC;IACrC,MAAM,CAAE,QAAQ,CAAE,GAAG,UAAU,CAAC,MAAM,CAAC;IACvC,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,QAAQ,CAAC;IAElD,IAAI,CAAC,YAAY,EAAE;QACjB,YAAY,GAAG,UAAU,CAAC;KAC3B;IAED,sFAAsF;IAEtF,IAAI,OAAO,KAAK,sBAAsB,EAAE;QACtC,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,kBAAkB,CAAC;QACnD,MAAM,IAAI,QAAQ,CAAC,YAAY,CAAC,2CAA2C,EAAE,GAAG,OAAO,KAAK,YAAY,KAAK,OAAO,EAAE,CAAC,CAAC;KACzH;IAED,IAAI,OAAO,KAAK,uBAAuB,EAAE;QACvC,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,mBAAmB,CAAC;QACpD,MAAM,IAAI,QAAQ,CAAC,YAAY,CAAC,4CAA4C,EAAE,GAAG,OAAO,KAAK,YAAY,KAAK,OAAO,EAAE,CAAC,CAAC;KAC1H;IAED,MAAM,IAAI,QAAQ,CAAC,YAAY,CAAC,sBAAsB,EAAE,GAAG,YAAY,KAAK,OAAO,EAAE,CAAC,CAAC;AACzF,CAAC"}
@@ -0,0 +1,186 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __asyncValues = (this && this.__asyncValues) || function (o) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var m = o[Symbol.asyncIterator], i;
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
};
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var g = generator.apply(thisArg, _arguments || []), i, q = [];
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
function fulfill(value) { resume("next", value); }
function reject(value) { resume("throw", value); }
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
};
import { CID } from 'multiformats';
import { createLevelDatabase, LevelWrapper } from './level-wrapper.js';
// `level` works in Node.js 12+ and Electron 5+ on Linux, Mac OS, Windows and
// FreeBSD, including any future Node.js and Electron release thanks to Node-API, including ARM
// platforms like Raspberry Pi and Android, as well as in Chrome, Firefox, Edge, Safari, iOS Safari
// and Chrome for Android.
/**
* Blockstore implementation using LevelDB for storing the actual messages (in the case of MessageStore)
* or the data associated with messages (in the case of a DataStore).
*/
export class BlockstoreLevel {
constructor(config, db) {
this.config = Object.assign({ createLevelDatabase }, config);
this.db = db !== null && db !== void 0 ? db : new LevelWrapper(Object.assign(Object.assign({}, this.config), { valueEncoding: 'binary' }));
}
open() {
return __awaiter(this, void 0, void 0, function* () {
return this.db.open();
});
}
close() {
return __awaiter(this, void 0, void 0, function* () {
return this.db.close();
});
}
partition(name) {
return __awaiter(this, void 0, void 0, function* () {
const db = yield this.db.partition(name);
return new BlockstoreLevel(Object.assign(Object.assign({}, this.config), { location: '' }), db);
});
}
put(key, val, options) {
return __awaiter(this, void 0, void 0, function* () {
yield this.db.put(String(key), val, options);
return CID.parse(key.toString());
});
}
get(key, options) {
return __awaiter(this, void 0, void 0, function* () {
const result = yield this.db.get(String(key), options);
return result;
});
}
has(key, options) {
return __awaiter(this, void 0, void 0, function* () {
return this.db.has(String(key), options);
});
}
delete(key, options) {
return __awaiter(this, void 0, void 0, function* () {
return this.db.delete(String(key), options);
});
}
isEmpty(options) {
return __awaiter(this, void 0, void 0, function* () {
return this.db.isEmpty(options);
});
}
putMany(source, options) {
return __asyncGenerator(this, arguments, function* putMany_1() {
var _a, e_1, _b, _c;
try {
for (var _d = true, source_1 = __asyncValues(source), source_1_1; source_1_1 = yield __await(source_1.next()), _a = source_1_1.done, !_a; _d = true) {
_c = source_1_1.value;
_d = false;
const entry = _c;
yield __await(this.put(entry.cid, entry.block, options));
yield yield __await(entry.cid);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (!_d && !_a && (_b = source_1.return)) yield __await(_b.call(source_1));
}
finally { if (e_1) throw e_1.error; }
}
});
}
getMany(source, options) {
return __asyncGenerator(this, arguments, function* getMany_1() {
var _a, e_2, _b, _c;
try {
for (var _d = true, source_2 = __asyncValues(source), source_2_1; source_2_1 = yield __await(source_2.next()), _a = source_2_1.done, !_a; _d = true) {
_c = source_2_1.value;
_d = false;
const key = _c;
yield yield __await({
cid: key,
block: yield __await(this.get(key, options))
});
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (!_d && !_a && (_b = source_2.return)) yield __await(_b.call(source_2));
}
finally { if (e_2) throw e_2.error; }
}
});
}
getAll(options) {
return __asyncGenerator(this, arguments, function* getAll_1() {
var _a, e_3, _b, _c;
// @ts-expect-error keyEncoding is 'buffer' but types for db.iterator always return the key type as 'string'
const li = this.db.iterator({
keys: true,
keyEncoding: 'buffer'
}, options);
try {
for (var _d = true, li_1 = __asyncValues(li), li_1_1; li_1_1 = yield __await(li_1.next()), _a = li_1_1.done, !_a; _d = true) {
_c = li_1_1.value;
_d = false;
const [key, value] = _c;
yield yield __await({ cid: CID.decode(key), block: value });
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (!_d && !_a && (_b = li_1.return)) yield __await(_b.call(li_1));
}
finally { if (e_3) throw e_3.error; }
}
});
}
deleteMany(source, options) {
return __asyncGenerator(this, arguments, function* deleteMany_1() {
var _a, e_4, _b, _c;
try {
for (var _d = true, source_3 = __asyncValues(source), source_3_1; source_3_1 = yield __await(source_3.next()), _a = source_3_1.done, !_a; _d = true) {
_c = source_3_1.value;
_d = false;
const key = _c;
yield __await(this.delete(key, options));
yield yield __await(key);
}
}
catch (e_4_1) { e_4 = { error: e_4_1 }; }
finally {
try {
if (!_d && !_a && (_b = source_3.return)) yield __await(_b.call(source_3));
}
finally { if (e_4) throw e_4.error; }
}
});
}
/**
* deletes all entries
*/
clear() {
return __awaiter(this, void 0, void 0, function* () {
return this.db.clear();
});
}
}
//# sourceMappingURL=blockstore-level.js.map
@@ -0,0 +1 @@
{"version":3,"file":"blockstore-level.js","sourceRoot":"","sources":["../../../../src/store/blockstore-level.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,167 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __asyncValues = (this && this.__asyncValues) || function (o) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var m = o[Symbol.asyncIterator], i;
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
};
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var g = generator.apply(thisArg, _arguments || []), i, q = [];
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
function fulfill(value) { resume("next", value); }
function reject(value) { resume("throw", value); }
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
};
import { CID } from 'multiformats';
/**
* Mock implementation for the Blockstore interface.
*
* WARNING!!! Purely to be used with `ipfs-unixfs-importer` to compute CID without needing consume any memory.
* This is particularly useful when dealing with large files and a necessity in a large-scale production service environment.
*/
export class BlockstoreMock {
open() {
return __awaiter(this, void 0, void 0, function* () {
});
}
close() {
return __awaiter(this, void 0, void 0, function* () {
});
}
put(key, _val, _options) {
return __awaiter(this, void 0, void 0, function* () {
return key;
});
}
get(_key, _options) {
return __awaiter(this, void 0, void 0, function* () {
return new Uint8Array();
});
}
has(_key, _options) {
return __awaiter(this, void 0, void 0, function* () {
return false;
});
}
delete(_key, _options) {
return __awaiter(this, void 0, void 0, function* () {
});
}
isEmpty(_options) {
return __awaiter(this, void 0, void 0, function* () {
return true;
});
}
putMany(source, options) {
return __asyncGenerator(this, arguments, function* putMany_1() {
var _a, e_1, _b, _c;
try {
for (var _d = true, source_1 = __asyncValues(source), source_1_1; source_1_1 = yield __await(source_1.next()), _a = source_1_1.done, !_a; _d = true) {
_c = source_1_1.value;
_d = false;
const entry = _c;
yield __await(this.put(entry.cid, entry.block, options));
yield yield __await(entry.cid);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (!_d && !_a && (_b = source_1.return)) yield __await(_b.call(source_1));
}
finally { if (e_1) throw e_1.error; }
}
});
}
getMany(source, options) {
return __asyncGenerator(this, arguments, function* getMany_1() {
var _a, e_2, _b, _c;
try {
for (var _d = true, source_2 = __asyncValues(source), source_2_1; source_2_1 = yield __await(source_2.next()), _a = source_2_1.done, !_a; _d = true) {
_c = source_2_1.value;
_d = false;
const key = _c;
yield yield __await({
cid: key,
block: yield __await(this.get(key, options))
});
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (!_d && !_a && (_b = source_2.return)) yield __await(_b.call(source_2));
}
finally { if (e_2) throw e_2.error; }
}
});
}
getAll(options) {
return __asyncGenerator(this, arguments, function* getAll_1() {
var _a, e_3, _b, _c;
// @ts-expect-error keyEncoding is 'buffer' but types for db.iterator always return the key type as 'string'
const li = this.db.iterator({
keys: true,
keyEncoding: 'buffer'
}, options);
try {
for (var _d = true, li_1 = __asyncValues(li), li_1_1; li_1_1 = yield __await(li_1.next()), _a = li_1_1.done, !_a; _d = true) {
_c = li_1_1.value;
_d = false;
const [key, value] = _c;
yield yield __await({ cid: CID.decode(key), block: value });
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (!_d && !_a && (_b = li_1.return)) yield __await(_b.call(li_1));
}
finally { if (e_3) throw e_3.error; }
}
});
}
deleteMany(source, options) {
return __asyncGenerator(this, arguments, function* deleteMany_1() {
var _a, e_4, _b, _c;
try {
for (var _d = true, source_3 = __asyncValues(source), source_3_1; source_3_1 = yield __await(source_3.next()), _a = source_3_1.done, !_a; _d = true) {
_c = source_3_1.value;
_d = false;
const key = _c;
yield __await(this.delete(key, options));
yield yield __await(key);
}
}
catch (e_4_1) { e_4 = { error: e_4_1 }; }
finally {
try {
if (!_d && !_a && (_b = source_3.return)) yield __await(_b.call(source_3));
}
finally { if (e_4) throw e_4.error; }
}
});
}
/**
* deletes all entries
*/
clear() {
return __awaiter(this, void 0, void 0, function* () {
});
}
}
//# sourceMappingURL=blockstore-mock.js.map
@@ -0,0 +1 @@
{"version":3,"file":"blockstore-mock.js","sourceRoot":"","sources":["../../../../src/store/blockstore-mock.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAInC;;;;;GAKG;AACH,MAAM,OAAO,cAAc;IAEnB,IAAI;;QACV,CAAC;KAAA;IAEK,KAAK;;QACX,CAAC;KAAA;IAEK,GAAG,CAAC,GAAQ,EAAE,IAAgB,EAAE,QAAuB;;YAC3D,OAAO,GAAG,CAAC;QACb,CAAC;KAAA;IAEK,GAAG,CAAC,IAAS,EAAE,QAAuB;;YAC1C,OAAO,IAAI,UAAU,EAAE,CAAC;QAC1B,CAAC;KAAA;IAEK,GAAG,CAAC,IAAS,EAAE,QAAuB;;YAC1C,OAAO,KAAK,CAAC;QACf,CAAC;KAAA;IAEK,MAAM,CAAC,IAAS,EAAE,QAAuB;;QAC/C,CAAC;KAAA;IAEK,OAAO,CAAC,QAAuB;;YACnC,OAAO,IAAI,CAAC;QACd,CAAC;KAAA;IAEO,OAAO,CAAC,MAA2B,EAAE,OAAsB;;;;gBACjE,KAA0B,eAAA,WAAA,cAAA,MAAM,CAAA,YAAA,qFAAE;oBAAR,sBAAM;oBAAN,WAAM;oBAArB,MAAM,KAAK,KAAA,CAAA;oBACpB,cAAM,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA,CAAC;oBAEhD,oBAAM,KAAK,CAAC,GAAG,CAAA,CAAC;iBACjB;;;;;;;;;QACH,CAAC;KAAA;IAEO,OAAO,CAAC,MAA0B,EAAE,OAAsB;;;;gBAChE,KAAwB,eAAA,WAAA,cAAA,MAAM,CAAA,YAAA,qFAAE;oBAAR,sBAAM;oBAAN,WAAM;oBAAnB,MAAM,GAAG,KAAA,CAAA;oBAClB,oBAAM;wBACJ,GAAG,EAAK,GAAG;wBACX,KAAK,EAAG,cAAM,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;qBACrC,CAAA,CAAC;iBACH;;;;;;;;;QACH,CAAC;KAAA;IAEO,MAAM,CAAC,OAAsB;;;YACnC,4GAA4G;YAC5G,MAAM,EAAE,GAA6C,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC;gBACpE,IAAI,EAAU,IAAI;gBAClB,WAAW,EAAG,QAAQ;aACvB,EAAE,OAAO,CAAC,CAAC;;gBAEZ,KAAiC,eAAA,OAAA,cAAA,EAAE,CAAA,QAAA,yEAAE;oBAAJ,kBAAE;oBAAF,WAAE;oBAAxB,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,KAAA,CAAA;oBAC3B,oBAAM,EAAE,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA,CAAC;iBAC9C;;;;;;;;;QACH,CAAC;KAAA;IAEO,UAAU,CAAC,MAA0B,EAAE,OAAsB;;;;gBACnE,KAAwB,eAAA,WAAA,cAAA,MAAM,CAAA,YAAA,qFAAE;oBAAR,sBAAM;oBAAN,WAAM;oBAAnB,MAAM,GAAG,KAAA,CAAA;oBAClB,cAAM,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA,CAAC;oBAEhC,oBAAM,GAAG,CAAA,CAAC;iBACX;;;;;;;;;QACH,CAAC;KAAA;IAED;;OAEG;IACG,KAAK;;QACX,CAAC;KAAA;CACF"}
@@ -0,0 +1,136 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __asyncValues = (this && this.__asyncValues) || function (o) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var m = o[Symbol.asyncIterator], i;
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
};
import { BlockstoreLevel } from './blockstore-level.js';
import { createLevelDatabase } from './level-wrapper.js';
import { exporter } from 'ipfs-unixfs-exporter';
import { importer } from 'ipfs-unixfs-importer';
import { Readable } from 'readable-stream';
/**
* A simple implementation of {@link DataStore} that works in both the browser and server-side.
* Leverages LevelDB under the hood.
*
* It has the following structure (`+` represents an additional sublevel/partition):
* 'data' + <tenant> + <recordId> + <dataCid> -> <data>
*/
export class DataStoreLevel {
constructor(config = {}) {
this.config = Object.assign({ blockstoreLocation: 'DATASTORE', createLevelDatabase }, config);
this.blockstore = new BlockstoreLevel({
location: this.config.blockstoreLocation,
createLevelDatabase: this.config.createLevelDatabase,
});
}
open() {
return __awaiter(this, void 0, void 0, function* () {
yield this.blockstore.open();
});
}
close() {
return __awaiter(this, void 0, void 0, function* () {
yield this.blockstore.close();
});
}
put(tenant, recordId, dataCid, dataStream) {
var _a, e_1, _b, _c;
var _d, _e;
return __awaiter(this, void 0, void 0, function* () {
const blockstoreForData = yield this.getBlockstoreForStoringData(tenant, recordId, dataCid);
const asyncDataBlocks = importer([{ content: dataStream }], blockstoreForData, { cidVersion: 1 });
// NOTE: the last block contains the root CID as well as info to derive the data size
let dataDagRoot;
try {
for (var _f = true, asyncDataBlocks_1 = __asyncValues(asyncDataBlocks), asyncDataBlocks_1_1; asyncDataBlocks_1_1 = yield asyncDataBlocks_1.next(), _a = asyncDataBlocks_1_1.done, !_a; _f = true) {
_c = asyncDataBlocks_1_1.value;
_f = false;
dataDagRoot = _c;
;
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (!_f && !_a && (_b = asyncDataBlocks_1.return)) yield _b.call(asyncDataBlocks_1);
}
finally { if (e_1) throw e_1.error; }
}
return {
dataSize: Number((_e = (_d = dataDagRoot.unixfs) === null || _d === void 0 ? void 0 : _d.fileSize()) !== null && _e !== void 0 ? _e : dataDagRoot.size)
};
});
}
get(tenant, recordId, dataCid) {
return __awaiter(this, void 0, void 0, function* () {
const blockstoreForData = yield this.getBlockstoreForStoringData(tenant, recordId, dataCid);
const exists = yield blockstoreForData.has(dataCid);
if (!exists) {
return undefined;
}
// data is chunked into dag-pb unixfs blocks. re-inflate the chunks.
const dataDagRoot = yield exporter(dataCid, blockstoreForData);
const contentIterator = dataDagRoot.content();
const dataStream = new Readable({
read() {
return __awaiter(this, void 0, void 0, function* () {
const result = yield contentIterator.next();
if (result.done) {
this.push(null); // end the stream
}
else {
this.push(result.value);
}
});
}
});
let dataSize = dataDagRoot.size;
if (dataDagRoot.type === 'file' || dataDagRoot.type === 'directory') {
dataSize = dataDagRoot.unixfs.fileSize();
}
return {
dataSize: Number(dataSize),
dataStream,
};
});
}
delete(tenant, recordId, dataCid) {
return __awaiter(this, void 0, void 0, function* () {
const blockstoreForData = yield this.getBlockstoreForStoringData(tenant, recordId, dataCid);
yield blockstoreForData.clear();
});
}
/**
* Deletes everything in the store. Mainly used in tests.
*/
clear() {
return __awaiter(this, void 0, void 0, function* () {
yield this.blockstore.clear();
});
}
/**
* Gets the blockstore used for storing data for the given `tenant -> `recordId` -> `dataCid`.
*/
getBlockstoreForStoringData(tenant, recordId, dataCid) {
return __awaiter(this, void 0, void 0, function* () {
const dataPartitionName = 'data';
const blockstoreForData = yield this.blockstore.partition(dataPartitionName);
const blockstoreOfGivenTenant = yield blockstoreForData.partition(tenant);
const blockstoreOfGivenRecordId = yield blockstoreOfGivenTenant.partition(recordId);
const blockstoreOfGivenDataCidOfRecordId = yield blockstoreOfGivenRecordId.partition(dataCid);
return blockstoreOfGivenDataCidOfRecordId;
});
}
}
//# sourceMappingURL=data-store-level.js.map
@@ -0,0 +1 @@
{"version":3,"file":"data-store-level.js","sourceRoot":"","sources":["../../../../src/store/data-store-level.ts"],"names":[],"mappings":"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"}

Some files were not shown because too many files have changed in this diff Show More