Skip to content

Commit

Permalink
fix(push-notifications)!: align to RFCs 0699/0734 (#223)
Browse files Browse the repository at this point in the history
Signed-off-by: Ariel Gentile <gentilester@gmail.com>
  • Loading branch information
genaris committed Aug 14, 2023
1 parent 6827127 commit 15e9f1f
Show file tree
Hide file tree
Showing 37 changed files with 475 additions and 49 deletions.
2 changes: 1 addition & 1 deletion packages/push-notifications/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@
</p>
<br />

Push Notifications plugin for [Aries Framework JavaScript](https://github.com/hyperledger/aries-framework-javascript.git).
Push Notifications extension module for [Aries Framework JavaScript](https://github.com/hyperledger/aries-framework-javascript.git). It currently implements [Aries RFC 0734](https://github.com/hyperledger/aries-rfcs/tree/main/features/0734-push-notifications-fcm) (Firebase Cloud Messaging) and [Aries RFC 0699](https://github.com/hyperledger/aries-rfcs/tree/main/features/0699-push-notifications-apns) (Apple Push Notifications).

For documentation on installation and usage of the Push Notifications package, refer to the [Docs](https://aries.js.org/guides/0.4/extensions/push-notifications).
9 changes: 9 additions & 0 deletions packages/push-notifications/samples/sample.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ const run = async () => {

// Gets the push notification device information located at the other agent behind the connection
await agent.modules.pushNotificationsApns.getDeviceInfo('a-valid-connection')

// Sends device info as response from a get-device-info message
await agent.modules.pushNotificationsApns.deviceInfo({
connectionId: 'a-valid-connection',
threadId: 'get-device-info-msg-id',
deviceInfo: {
deviceToken: '123',
},
})
}

void run()
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,16 @@ export class PushNotificationsApnsApi {
* Response for `push-notifications-apns/get-device-info`
*
* @param connectionId The connection ID string
* @param threadId get-device-info message ID
* @param deviceInfo The APNS device info
* @returns Promise<void>
*/
public async deviceInfo(connectionId: string, deviceInfo: ApnsDeviceInfo) {
public async deviceInfo(options: { connectionId: string; threadId: string; deviceInfo: ApnsDeviceInfo }) {
const { connectionId, threadId, deviceInfo } = options
const connection = await this.connectionService.getById(this.agentContext, connectionId)
connection.assertReady()

const message = this.pushNotificationsService.createDeviceInfo(deviceInfo)
const message = this.pushNotificationsService.createDeviceInfo({ threadId, deviceInfo })

const outbound = new OutboundMessageContext(message, {
agentContext: this.agentContext,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,38 @@
import type { DependencyManager, Module } from '@aries-framework/core'
import type { DependencyManager, FeatureRegistry, Module } from '@aries-framework/core'

import { Protocol } from '@aries-framework/core'

import { PushNotificationsApnsApi } from './PushNotificationsApnsApi'
import { PushNotificationsApnsService } from './PushNotificationsApnsService'
import {
PushNotificationsApnsDeviceInfoHandler,
PushNotificationsApnsGetDeviceInfoHandler,
PushNotificationsApnsProblemReportHandler,
PushNotificationsApnsSetDeviceInfoHandler,
} from './handlers'
import { PushNotificationsApnsRole } from './models'

/**
* Module that exposes push notification get and set functionality
*/
export class PushNotificationsApnsModule implements Module {
public readonly api = PushNotificationsApnsApi

public register(dependencyManager: DependencyManager): void {
public register(dependencyManager: DependencyManager, featureRegistry: FeatureRegistry): void {
dependencyManager.registerContextScoped(PushNotificationsApnsApi)

featureRegistry.register(
new Protocol({
id: 'https://didcomm.org/push-notifications-apns/1.0',
roles: [PushNotificationsApnsRole.Sender, PushNotificationsApnsRole.Receiver],
})
)

dependencyManager.registerMessageHandlers([
new PushNotificationsApnsDeviceInfoHandler(),
new PushNotificationsApnsGetDeviceInfoHandler(),
new PushNotificationsApnsSetDeviceInfoHandler(),
new PushNotificationsApnsProblemReportHandler(),
])

dependencyManager.registerSingleton(PushNotificationsApnsService)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ export class PushNotificationsApnsService {
return new PushNotificationsApnsGetDeviceInfoMessage({})
}

public createDeviceInfo(deviceInfo: ApnsDeviceInfo) {
return new PushNotificationsApnsDeviceInfoMessage(deviceInfo)
public createDeviceInfo(options: { threadId: string; deviceInfo: ApnsDeviceInfo }) {
const { threadId, deviceInfo } = options
return new PushNotificationsApnsDeviceInfoMessage({ threadId, deviceToken: deviceInfo.deviceToken })
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { PushNotificationsApnsProblemReportReason } from './PushNotificationsApnsProblemReportReason'
import type { ProblemReportErrorOptions } from '@aries-framework/core'

import { ProblemReportError } from '@aries-framework/core'

import { PushNotificationsApnsProblemReportMessage } from '../messages'

/**
* @internal
*/
interface PushNotificationsApnsProblemReportErrorOptions extends ProblemReportErrorOptions {
problemCode: PushNotificationsApnsProblemReportReason
}

/**
* @internal
*/
export class PushNotificationsApnsProblemReportError extends ProblemReportError {
public problemReport: PushNotificationsApnsProblemReportMessage

public constructor(public message: string, { problemCode }: PushNotificationsApnsProblemReportErrorOptions) {
super(message, { problemCode })
this.problemReport = new PushNotificationsApnsProblemReportMessage({
description: {
en: message,
code: problemCode,
},
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* Push Notification APNS errors discussed in RFC 0699.
*
* @see https://github.com/hyperledger/aries-rfcs/tree/main/features/0699-push-notifications-apns#set-device-info
* @see https://github.com/hyperledger/aries-rfcs/tree/main/features/0699-push-notifications-apns#device-info
* @internal
*/
export enum PushNotificationsApnsProblemReportReason {
MissingValue = 'missing-value',
NotRegistered = 'not-registered-for-push-notifications',
}
2 changes: 2 additions & 0 deletions packages/push-notifications/src/apns/errors/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './PushNotificationsApnsProblemReportReason'
export * from './PushNotificationsApnsProblemReportError'
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { MessageHandler, MessageHandlerInboundMessage } from '@aries-framework/core'

import { PushNotificationsApnsProblemReportMessage } from '../messages'

/**
* Handler for incoming push notification problem report messages
*/
export class PushNotificationsApnsProblemReportHandler implements MessageHandler {
public supportedMessages = [PushNotificationsApnsProblemReportMessage]

/**
/* We don't really need to do anything with this at the moment
/* The result can be hooked into through the generic message processed event
*/
public async handle(inboundMessage: MessageHandlerInboundMessage<PushNotificationsApnsProblemReportHandler>) {
inboundMessage.assertReadyConnection()
}
}
1 change: 1 addition & 0 deletions packages/push-notifications/src/apns/handlers/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { PushNotificationsApnsGetDeviceInfoHandler } from './PushNotificationsApnsGetDeviceInfoHandler'
export { PushNotificationsApnsSetDeviceInfoHandler } from './PushNotificationsApnsSetDeviceInfoHandler'
export { PushNotificationsApnsDeviceInfoHandler } from './PushNotificationsApnsDeviceInfoHandler'
export { PushNotificationsApnsProblemReportHandler } from './PushNotificationsApnsProblemReportHandler'
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,26 @@ import type { ApnsDeviceInfo } from '../models'

import { AgentMessage, IsValidMessageType, parseMessageType } from '@aries-framework/core'
import { Expose } from 'class-transformer'
import { IsString } from 'class-validator'
import { IsString, ValidateIf } from 'class-validator'

interface PushNotificationsApnsDeviceInfoOptions extends ApnsDeviceInfo {
id?: string
threadId: string
}

/**
* Message to send the apns device information from another agent for push notifications
* This is used as a response for the `get-device-info` message
*
* @todo ADD RFC
* @see https://github.com/hyperledger/aries-rfcs/tree/main/features/0699-push-notifications-apns#device-info
*/
export class PushNotificationsApnsDeviceInfoMessage extends AgentMessage {
public constructor(options: PushNotificationsApnsDeviceInfoOptions) {
super()

if (options) {
this.id = options.id ?? this.generateId()
this.setThread({ threadId: options.threadId })
this.deviceToken = options.deviceToken
}
}
Expand All @@ -30,5 +32,6 @@ export class PushNotificationsApnsDeviceInfoMessage extends AgentMessage {

@Expose({ name: 'device_token' })
@IsString()
public deviceToken!: string
@ValidateIf((object, value) => value !== null)
public deviceToken!: string | null
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ interface PushNotificationsApnsGetDeviceInfoOptions {
/**
* Message to get the apns device information from another agent for push notifications
*
* @todo ADD RFC
* @see https://github.com/hyperledger/aries-rfcs/tree/main/features/0699-push-notifications-apns#get-device-info
*/
export class PushNotificationsApnsGetDeviceInfoMessage extends AgentMessage {
public constructor(options: PushNotificationsApnsGetDeviceInfoOptions) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { ProblemReportMessageOptions } from '@aries-framework/core'

import { IsValidMessageType, parseMessageType, ProblemReportMessage } from '@aries-framework/core'

export type PushNotificationsApnsProblemReportMessageOptions = ProblemReportMessageOptions

/**
* @see https://github.com/hyperledger/aries-rfcs/blob/main/features/0035-report-problem/README.md
* @internal
*/
export class PushNotificationsApnsProblemReportMessage extends ProblemReportMessage {
/**
* Create new ConnectionProblemReportMessage instance.
* @param options
*/
public constructor(options: PushNotificationsApnsProblemReportMessageOptions) {
super(options)
}

@IsValidMessageType(PushNotificationsApnsProblemReportMessage.type)
public readonly type = PushNotificationsApnsProblemReportMessage.type.messageTypeUri
public static readonly type = parseMessageType('https://didcomm.org/push-notifications-apns/1.0/problem-report')
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { ApnsDeviceInfo } from '../models'

import { AgentMessage, IsValidMessageType, parseMessageType } from '@aries-framework/core'
import { Expose } from 'class-transformer'
import { IsString } from 'class-validator'
import { IsString, ValidateIf } from 'class-validator'

interface PushNotificationsApnsSetDeviceInfoOptions extends ApnsDeviceInfo {
id?: string
Expand All @@ -11,7 +11,7 @@ interface PushNotificationsApnsSetDeviceInfoOptions extends ApnsDeviceInfo {
/**
* Message to set the apns device information at another agent for push notifications
*
* @todo ADD RFC
* @see https://github.com/hyperledger/aries-rfcs/tree/main/features/0699-push-notifications-apns#set-device-info
*/
export class PushNotificationsApnsSetDeviceInfoMessage extends AgentMessage {
public constructor(options: PushNotificationsApnsSetDeviceInfoOptions) {
Expand All @@ -25,7 +25,8 @@ export class PushNotificationsApnsSetDeviceInfoMessage extends AgentMessage {

@Expose({ name: 'device_token' })
@IsString()
public deviceToken!: string
@ValidateIf((object, value) => value !== null)
public deviceToken!: string | null

@IsValidMessageType(PushNotificationsApnsSetDeviceInfoMessage.type)
public readonly type = PushNotificationsApnsSetDeviceInfoMessage.type.messageTypeUri
Expand Down
1 change: 1 addition & 0 deletions packages/push-notifications/src/apns/messages/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { PushNotificationsApnsGetDeviceInfoMessage } from './PushNotificationsApnsGetDeviceInfoMessage'
export { PushNotificationsApnsSetDeviceInfoMessage } from './PushNotificationsApnsSetDeviceInfoMessage'
export { PushNotificationsApnsDeviceInfoMessage } from './PushNotificationsApnsDeviceInfoMessage'
export { PushNotificationsApnsProblemReportMessage } from './PushNotificationsApnsProblemReportMessage'
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export type ApnsDeviceInfo = {
deviceToken: string
deviceToken: string | null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* Push Notification FCM roles based on the flow defined in RFC 0699.
*
* @see https://github.com/hyperledger/aries-rfcs/tree/main/features/0699-push-notifications-apns#roles
* @public
*/
export enum PushNotificationsApnsRole {
Sender = 'notification-sender',
Receiver = 'notification-receiver',
}
1 change: 1 addition & 0 deletions packages/push-notifications/src/apns/models/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './ApnsDeviceInfo'
export * from './PushNotificationsApnsRole'
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,16 @@ export class PushNotificationsFcmApi {
* Response for `push-notifications-fcm/get-device-info`
*
* @param connectionId The connection ID string
* @param threadId get-device-info message ID
* @param deviceInfo The FCM device info
* @returns Promise<void>
*/
public async deviceInfo(connectionId: string, deviceInfo: FcmDeviceInfo) {
public async deviceInfo(options: { connectionId: string; threadId: string; deviceInfo: FcmDeviceInfo }) {
const { connectionId, threadId, deviceInfo } = options
const connection = await this.connectionService.getById(this.agentContext, connectionId)
connection.assertReady()

const message = this.pushNotificationsService.createDeviceInfo(deviceInfo)
const message = this.pushNotificationsService.createDeviceInfo({ threadId, deviceInfo })

const outbound = new OutboundMessageContext(message, {
agentContext: this.agentContext,
Expand Down
16 changes: 14 additions & 2 deletions packages/push-notifications/src/fcm/PushNotificationsFcmModule.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,40 @@
import type { DependencyManager, Module } from '@aries-framework/core'
import type { DependencyManager, FeatureRegistry, Module } from '@aries-framework/core'

import { Protocol } from '@aries-framework/core'

import { PushNotificationsFcmApi } from './PushNotificationsFcmApi'
import { PushNotificationsFcmService } from './PushNotificationsFcmService'
import {
PushNotificationsFcmDeviceInfoHandler,
PushNotificationsFcmGetDeviceInfoHandler,
PushNotificationsFcmProblemReportHandler,
PushNotificationsFcmSetDeviceInfoHandler,
} from './handlers'
import { PushNotificationsFcmRole } from './models'

/**
* Module that exposes push notification get and set functionality
*/
export class PushNotificationsFcmModule implements Module {
public readonly api = PushNotificationsFcmApi

public register(dependencyManager: DependencyManager): void {
public register(dependencyManager: DependencyManager, featureRegistry: FeatureRegistry): void {
dependencyManager.registerContextScoped(PushNotificationsFcmApi)

dependencyManager.registerSingleton(PushNotificationsFcmService)

featureRegistry.register(
new Protocol({
id: 'https://didcomm.org/push-notifications-fcm/1.0',
roles: [PushNotificationsFcmRole.Sender, PushNotificationsFcmRole.Receiver],
})
)

dependencyManager.registerMessageHandlers([
new PushNotificationsFcmDeviceInfoHandler(),
new PushNotificationsFcmGetDeviceInfoHandler(),
new PushNotificationsFcmSetDeviceInfoHandler(),
new PushNotificationsFcmProblemReportHandler(),
])
}
}

0 comments on commit 15e9f1f

Please sign in to comment.