Skip to content

Commit

Permalink
#439 - Turned authorization property from a JWS into a container object
Browse files Browse the repository at this point in the history
  • Loading branch information
thehenrytsai committed Sep 26, 2023
1 parent 39cf553 commit 37ab6ac
Show file tree
Hide file tree
Showing 43 changed files with 177 additions and 213 deletions.
6 changes: 4 additions & 2 deletions build/compile-validators.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import Ajv from 'ajv';
import mkdirp from 'mkdirp';
import standaloneCode from 'ajv/dist/standalone/index.js';

import Authorization from '../json-schemas/authorization.json' assert { type: 'json' };
import BaseAuthorizationPayload from '../json-schemas/authorization-payloads/base-authorization-payload.json' assert { type: 'json' };
import Definitions from '../json-schemas/definitions.json' assert { type: 'json' };
import EventsGet from '../json-schemas/events/events-get.json' assert { type: 'json' };
Expand All @@ -40,11 +41,12 @@ import RecordsFilter from '../json-schemas/interface-methods/records-filter.json
import RecordsQuery from '../json-schemas/interface-methods/records-query.json' assert { type: 'json' };
import RecordsRead from '../json-schemas/interface-methods/records-read.json' assert { type: 'json' };
import RecordsWrite from '../json-schemas/interface-methods/records-write.json' assert { type: 'json' };
import RecordsWriteAuthorizationPayload from '../json-schemas/authorization-payloads/records-write-authorization-payload.json' assert { type: 'json' };
import RecordsWriteAuthorSignaturePayload from '../json-schemas/authorization-payloads/records-write-authorization-payload.json' assert { type: 'json' };
import RecordsWriteUnidentified from '../json-schemas/interface-methods/records-write-unidentified.json' assert { type: 'json' };
import SnapshotsCreate from '../json-schemas/interface-methods/snapshots-create.json' assert { type: 'json' };

const schemas = {
Authorization,
RecordsDelete,
RecordsQuery,
RecordsWrite,
Expand All @@ -70,7 +72,7 @@ const schemas = {
PublicJwk,
SnapshotsCreate,
BaseAuthorizationPayload,
RecordsWriteAuthorizationPayload
RecordsWriteAuthorSignaturePayload
};

const ajv = new Ajv({ code: { source: true, esm: true } });
Expand Down
11 changes: 11 additions & 0 deletions json-schemas/authorization.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$id": "https://identity.foundation/dwn/json-schemas/authorization.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"additionalProperties": false,
"properties": {
"author": {
"$ref": "https://identity.foundation/dwn/json-schemas/general-jws.json"
}
}
}
2 changes: 1 addition & 1 deletion json-schemas/events/events-get.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
],
"properties": {
"authorization": {
"$ref": "https://identity.foundation/dwn/json-schemas/general-jws.json"
"$ref": "https://identity.foundation/dwn/json-schemas/authorization.json"
},
"descriptor": {
"type": "object",
Expand Down
2 changes: 1 addition & 1 deletion json-schemas/hooks/hooks-write.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
],
"properties": {
"authorization": {
"$ref": "https://identity.foundation/dwn/json-schemas/general-jws.json"
"$ref": "https://identity.foundation/dwn/json-schemas/authorization.json"
},
"descriptor": {
"type": "object",
Expand Down
2 changes: 1 addition & 1 deletion json-schemas/interface-methods/messages-get.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
],
"properties": {
"authorization": {
"$ref": "https://identity.foundation/dwn/json-schemas/general-jws.json"
"$ref": "https://identity.foundation/dwn/json-schemas/authorization.json"
},
"descriptor": {
"type": "object",
Expand Down
4 changes: 2 additions & 2 deletions json-schemas/interface-methods/permissions-grant.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"additionalProperties": false,
"properties": {
"authorization": {
"$ref": "https://identity.foundation/dwn/json-schemas/general-jws.json"
"$ref": "https://identity.foundation/dwn/json-schemas/authorization.json"
},
"delegationChain": {
"description": "the parent grant",
Expand Down Expand Up @@ -71,4 +71,4 @@
}
}
}
}
}
2 changes: 1 addition & 1 deletion json-schemas/interface-methods/permissions-request.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
],
"properties": {
"authorization": {
"$ref": "https://identity.foundation/dwn/json-schemas/general-jws.json"
"$ref": "https://identity.foundation/dwn/json-schemas/authorization.json"
},
"descriptor": {
"type": "object",
Expand Down
2 changes: 1 addition & 1 deletion json-schemas/interface-methods/permissions-revoke.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"additionalProperties": false,
"properties": {
"authorization": {
"$ref": "https://identity.foundation/dwn/json-schemas/general-jws.json"
"$ref": "https://identity.foundation/dwn/json-schemas/authorization.json"
},
"descriptor": {
"type": "object",
Expand Down
2 changes: 1 addition & 1 deletion json-schemas/interface-methods/protocols-configure.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
],
"properties": {
"authorization": {
"$ref": "https://identity.foundation/dwn/json-schemas/general-jws.json"
"$ref": "https://identity.foundation/dwn/json-schemas/authorization.json"
},
"descriptor": {
"type": "object",
Expand Down
2 changes: 1 addition & 1 deletion json-schemas/interface-methods/protocols-query.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
],
"properties": {
"authorization": {
"$ref": "https://identity.foundation/dwn/json-schemas/general-jws.json"
"$ref": "https://identity.foundation/dwn/json-schemas/authorization.json"
},
"descriptor": {
"type": "object",
Expand Down
2 changes: 1 addition & 1 deletion json-schemas/interface-methods/records-delete.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
],
"properties": {
"authorization": {
"$ref": "https://identity.foundation/dwn/json-schemas/general-jws.json"
"$ref": "https://identity.foundation/dwn/json-schemas/authorization.json"
},
"descriptor": {
"type": "object",
Expand Down
6 changes: 3 additions & 3 deletions json-schemas/interface-methods/records-query.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
],
"properties": {
"authorization": {
"$ref": "https://identity.foundation/dwn/json-schemas/general-jws.json"
"$ref": "https://identity.foundation/dwn/json-schemas/authorization.json"
},
"descriptor": {
"type": "object",
Expand Down Expand Up @@ -44,7 +44,7 @@
"properties": {
"limit": {
"type": "number",
"minimum": 1
"minimum": 1
},
"messageCid": {
"type": "string"
Expand All @@ -63,4 +63,4 @@
}
}
}
}
}
2 changes: 1 addition & 1 deletion json-schemas/interface-methods/records-read.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
],
"properties": {
"authorization": {
"$ref": "https://identity.foundation/dwn/json-schemas/general-jws.json"
"$ref": "https://identity.foundation/dwn/json-schemas/authorization.json"
},
"descriptor": {
"type": "object",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"$ref": "https://identity.foundation/dwn/json-schemas/general-jws.json"
},
"authorization": {
"$ref": "https://identity.foundation/dwn/json-schemas/general-jws.json"
"$ref": "https://identity.foundation/dwn/json-schemas/authorization.json"
},
"encryption": {
"type": "object",
Expand Down Expand Up @@ -268,4 +268,4 @@
]
}
]
}
}
2 changes: 1 addition & 1 deletion json-schemas/interface-methods/snapshots-create.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
],
"properties": {
"authorization": {
"$ref": "https://identity.foundation/dwn/json-schemas/general-jws.json"
"$ref": "https://identity.foundation/dwn/json-schemas/authorization.json"
},
"descriptor": {
"type": "object",
Expand Down
13 changes: 6 additions & 7 deletions src/core/auth.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import type { CID } from 'multiformats';
import type { DidResolver } from '../did/did-resolver.js';
import type { GeneralJws } from '../types/jws-types.js';
import type { GenericMessage } from '../types/message-types.js';
import type { Message } from './message.js';
import type { AuthorizationModel, GenericMessage } from '../types/message-types.js';

import { Cid } from '../utils/cid.js';
import { GeneralJwsVerifier } from '../jose/jws/general/verifier.js';
Expand Down Expand Up @@ -38,12 +37,12 @@ export async function validateAuthorizationIntegrity(
throw new DwnError(DwnErrorCode.AuthorizationMissing, 'Property `authorization` is missing.');
}

if (message.authorization.signatures.length !== 1) {
if (message.authorization.author.signatures.length !== 1) {
throw new Error('expected no more than 1 signature for authorization');
}

// validate payload integrity
const payloadJson = Jws.decodePlainObjectPayload(message.authorization);
const payloadJson = Jws.decodePlainObjectPayload(message.authorization.author);

validateJsonSchema(jsonSchemaKey, payloadJson);

Expand All @@ -62,12 +61,12 @@ export async function validateAuthorizationIntegrity(
* Validates the signature(s) of the given JWS.
* @throws {Error} if fails authentication
*/
export async function authenticate(jws: GeneralJws | undefined, didResolver: DidResolver): Promise<void> {
if (jws === undefined) {
export async function authenticate(authorizationModel: AuthorizationModel | undefined, didResolver: DidResolver): Promise<void> {
if (authorizationModel === undefined) {
throw new DwnError(DwnErrorCode.AuthenticateJwsMissing, 'Missing JWS.');
}

const verifier = new GeneralJwsVerifier(jws);
const verifier = new GeneralJwsVerifier(authorizationModel.author);
await verifier.verify(didResolver);
}

Expand Down
23 changes: 12 additions & 11 deletions src/core/message.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { GeneralJws } from '../types/jws-types.js';
import type { Signer } from '../types/signer.js';
import type { BaseAuthorizationPayload, Descriptor, GenericMessage } from '../types/message-types.js';
import type { AuthorizationModel, BaseAuthorizationPayload, Descriptor, GenericMessage } from '../types/message-types.js';

import { Cid } from '../utils/cid.js';
import { GeneralJwsBuilder } from '../jose/jws/general/builder.js';
Expand Down Expand Up @@ -41,7 +40,7 @@ export abstract class Message<M extends GenericMessage> {
this.message = message;

if (message.authorization !== undefined) {
this.authorizationPayload = Jws.decodePlainObjectPayload(message.authorization);
this.authorizationPayload = Jws.decodePlainObjectPayload(message.authorization.author);
this.author = Message.getAuthor(message as GenericMessage);
}
}
Expand Down Expand Up @@ -74,7 +73,7 @@ export abstract class Message<M extends GenericMessage> {
return undefined;
}

const author = Jws.getSignerDid(message.authorization.signatures[0]);
const author = Jws.getSignerDid(message.authorization.author.signatures[0]);
return author;
}

Expand Down Expand Up @@ -132,25 +131,27 @@ export abstract class Message<M extends GenericMessage> {
}

/**
* Signs over the CID of provided `descriptor`. The output is used as an `authorization` property.
* @param signatureInput - the signature material to use (e.g. key and header data)
* Creates the `authorization` as the author to be used in a DWN message.
* @param signer Signer as the author
* @returns General JWS signature used as an `authorization` property.
*/
public static async signAsAuthorization(
public static async signAuthorizationAsAuthor(
descriptor: Descriptor,
signatureInput: Signer,
signer: Signer,
additionalPayloadProperties?: { permissionsGrantId?: string, protocolRole?: string }
): Promise<GeneralJws> {
): Promise<AuthorizationModel> {
const descriptorCid = await Cid.computeCid(descriptor);

const authPayload: BaseAuthorizationPayload = { descriptorCid, ...additionalPayloadProperties };
removeUndefinedProperties(authPayload);
const authPayloadStr = JSON.stringify(authPayload);
const authPayloadBytes = new TextEncoder().encode(authPayloadStr);

const builder = await GeneralJwsBuilder.create(authPayloadBytes, [signatureInput]);
const builder = await GeneralJwsBuilder.create(authPayloadBytes, [signer]);
const authorJws = builder.getJws();

return builder.getJws();
const authorization = { author: authorJws };
return authorization;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/events-get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export class EventsGet extends Message<EventsGetMessage> {
descriptor.watermark = options.watermark;
}

const authorization = await Message.signAsAuthorization(descriptor, options.authorizationSigner);
const authorization = await Message.signAuthorizationAsAuthor(descriptor, options.authorizationSigner);
const message = { descriptor, authorization };

Message.validateJsonSchema(message);
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/hooks-write.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export class HooksWrite extends Message<HooksWriteMessage> {
// Error: `undefined` is not supported by the IPLD Data Model and cannot be encoded
removeUndefinedProperties(descriptor);

const authorization = await Message.signAsAuthorization(descriptor, options.authorizationSigner);
const authorization = await Message.signAuthorizationAsAuthor(descriptor, options.authorizationSigner);
const message = { descriptor, authorization };

Message.validateJsonSchema(message);
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/messages-get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export class MessagesGet extends Message<MessagesGetMessage> {
messageTimestamp : options?.messageTimestamp ?? getCurrentTimeInHighPrecision(),
};

const authorization = await Message.signAsAuthorization(descriptor, options.authorizationSigner);
const authorization = await Message.signAuthorizationAsAuthor(descriptor, options.authorizationSigner);
const message = { descriptor, authorization };

Message.validateJsonSchema(message);
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/permissions-grant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export class PermissionsGrant extends Message<PermissionsGrantMessage> {
// Error: `undefined` is not supported by the IPLD Data Model and cannot be encoded
removeUndefinedProperties(descriptor);

const authorization = await Message.signAsAuthorization(descriptor, options.authorizationSigner);
const authorization = await Message.signAuthorizationAsAuthor(descriptor, options.authorizationSigner);
const message: PermissionsGrantMessage = { descriptor, authorization };

Message.validateJsonSchema(message);
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/permissions-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export class PermissionsRequest extends Message<PermissionsRequestMessage> {
// Error: `undefined` is not supported by the IPLD Data Model and cannot be encoded
removeUndefinedProperties(descriptor);

const auth = await Message.signAsAuthorization(descriptor, options.authorizationSigner);
const auth = await Message.signAuthorizationAsAuthor(descriptor, options.authorizationSigner);
const message: PermissionsRequestMessage = { descriptor, authorization: auth };

Message.validateJsonSchema(message);
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/permissions-revoke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export class PermissionsRevoke extends Message<PermissionsRevokeMessage> {
permissionsGrantId : options.permissionsGrantId,
};

const authorization = await Message.signAsAuthorization(descriptor, options.authorizationSigner);
const authorization = await Message.signAuthorizationAsAuthor(descriptor, options.authorizationSigner);
const message: PermissionsRevokeMessage = { descriptor, authorization };

Message.validateJsonSchema(message);
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/protocols-configure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export class ProtocolsConfigure extends Message<ProtocolsConfigureMessage> {
definition : ProtocolsConfigure.normalizeDefinition(options.definition)
};

const authorization = await Message.signAsAuthorization(
const authorization = await Message.signAuthorizationAsAuthor(
descriptor,
options.authorizationSigner,
{ permissionsGrantId: options.permissionsGrantId }
Expand Down
6 changes: 3 additions & 3 deletions src/interfaces/protocols-query.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { GeneralJws } from '../types/jws-types.js';
import type { AuthorizationModel } from '../types/message-types.js';
import type { MessageStore } from '../types/message-store.js';
import type { Signer } from '../types/signer.js';
import type { ProtocolsQueryDescriptor, ProtocolsQueryFilter, ProtocolsQueryMessage } from '../types/protocols-types.js';
Expand Down Expand Up @@ -46,9 +46,9 @@ export class ProtocolsQuery extends Message<ProtocolsQueryMessage> {
removeUndefinedProperties(descriptor);

// only generate the `authorization` property if signature input is given
let authorization: GeneralJws | undefined;
let authorization: AuthorizationModel | undefined;
if (options.authorizationSigner !== undefined) {
authorization = await Message.signAsAuthorization(
authorization = await Message.signAuthorizationAsAuthor(
descriptor,
options.authorizationSigner,
{ permissionsGrantId: options.permissionsGrantId }
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/records-delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export class RecordsDelete extends Message<RecordsDeleteMessage> {
messageTimestamp : options.messageTimestamp ?? currentTime
};

const authorization = await Message.signAsAuthorization(descriptor, options.authorizationSigner);
const authorization = await Message.signAuthorizationAsAuthor(descriptor, options.authorizationSigner);
const message: RecordsDeleteMessage = { descriptor, authorization };

Message.validateJsonSchema(message);
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/records-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export class RecordsQuery extends Message<RecordsQueryMessage> {

// only generate the `authorization` property if signature input is given
const authorizationSigner = options.authorizationSigner;
const authorization = authorizationSigner ? await Message.signAsAuthorization(descriptor, authorizationSigner) : undefined;
const authorization = authorizationSigner ? await Message.signAuthorizationAsAuthor(descriptor, authorizationSigner) : undefined;
const message = { descriptor, authorization };

Message.validateJsonSchema(message);
Expand Down
Loading

0 comments on commit 37ab6ac

Please sign in to comment.