1
+ import { serializeDateTime } from '../internal/utils.js' ;
2
+ import { deserializeDateTime } from '../internal/utils.js' ;
1
3
import { serializeWebhooks } from '../schemas/webhooks.generated.js' ;
2
4
import { deserializeWebhooks } from '../schemas/webhooks.generated.js' ;
3
5
import { serializeClientError } from '../schemas/clientError.generated.js' ;
4
6
import { deserializeClientError } from '../schemas/clientError.generated.js' ;
5
7
import { serializeWebhook } from '../schemas/webhook.generated.js' ;
6
8
import { deserializeWebhook } from '../schemas/webhook.generated.js' ;
7
9
import { ResponseFormat } from '../networking/fetchOptions.generated.js' ;
10
+ import { DateTime } from '../internal/utils.js' ;
8
11
import { Webhooks } from '../schemas/webhooks.generated.js' ;
9
12
import { ClientError } from '../schemas/clientError.generated.js' ;
10
13
import { Webhook } from '../schemas/webhook.generated.js' ;
@@ -19,6 +22,10 @@ import { ByteStream } from '../internal/utils.js';
19
22
import { CancellationToken } from '../internal/utils.js' ;
20
23
import { sdToJson } from '../serialization/json.js' ;
21
24
import { SerializedData } from '../serialization/json.js' ;
25
+ import { computeWebhookSignature } from '../internal/utils.js' ;
26
+ import { dateTimeFromString } from '../internal/utils.js' ;
27
+ import { getEpochTimeInSeconds } from '../internal/utils.js' ;
28
+ import { dateTimeToEpochSeconds } from '../internal/utils.js' ;
22
29
import { sdIsEmpty } from '../serialization/json.js' ;
23
30
import { sdIsBoolean } from '../serialization/json.js' ;
24
31
import { sdIsNumber } from '../serialization/json.js' ;
@@ -117,6 +124,25 @@ export interface DeleteWebhookByIdOptionalsInput {
117
124
readonly headers ?: DeleteWebhookByIdHeaders ;
118
125
readonly cancellationToken ?: undefined | CancellationToken ;
119
126
}
127
+ export class ValidateMessageOptionals {
128
+ readonly secondaryKey ?: string = void 0 ;
129
+ readonly maxAge ?: number = 600 ;
130
+ constructor (
131
+ fields : Omit < ValidateMessageOptionals , 'secondaryKey' | 'maxAge' > &
132
+ Partial < Pick < ValidateMessageOptionals , 'secondaryKey' | 'maxAge' > > ,
133
+ ) {
134
+ if ( fields . secondaryKey !== undefined ) {
135
+ this . secondaryKey = fields . secondaryKey ;
136
+ }
137
+ if ( fields . maxAge !== undefined ) {
138
+ this . maxAge = fields . maxAge ;
139
+ }
140
+ }
141
+ }
142
+ export interface ValidateMessageOptionalsInput {
143
+ readonly secondaryKey ?: undefined | string ;
144
+ readonly maxAge ?: undefined | number ;
145
+ }
120
146
export interface GetWebhooksQueryParams {
121
147
/**
122
148
* Defines the position marker at which to begin returning results. This is
@@ -388,6 +414,7 @@ export class WebhooksManager {
388
414
| 'getWebhookById'
389
415
| 'updateWebhookById'
390
416
| 'deleteWebhookById'
417
+ | 'validateMessage'
391
418
> &
392
419
Partial < Pick < WebhooksManager , 'networkSession' > > ,
393
420
) {
@@ -615,6 +642,56 @@ export class WebhooksManager {
615
642
) ;
616
643
return void 0 ;
617
644
}
645
+ /**
646
+ * Validate a webhook message by verifying the signature and the delivery timestamp
647
+ * @param {string } body The request body of the webhook message
648
+ * @param {{
649
+ readonly [key: string]: string;
650
+ }} headers The headers of the webhook message
651
+ * @param {string } primaryKey The primary signature to verify the message with
652
+ * @param {ValidateMessageOptionalsInput } optionalsInput
653
+ * @returns {Promise<boolean> }
654
+ */
655
+ static async validateMessage (
656
+ body : string ,
657
+ headers : {
658
+ readonly [ key : string ] : string ;
659
+ } ,
660
+ primaryKey : string ,
661
+ optionalsInput : ValidateMessageOptionalsInput = { } ,
662
+ ) : Promise < boolean > {
663
+ const optionals : ValidateMessageOptionals = new ValidateMessageOptionals ( {
664
+ secondaryKey : optionalsInput . secondaryKey ,
665
+ maxAge : optionalsInput . maxAge ,
666
+ } ) ;
667
+ const secondaryKey : any = optionals . secondaryKey ;
668
+ const maxAge : any = optionals . maxAge ;
669
+ const deliveryTimestamp : DateTime = dateTimeFromString (
670
+ headers [ 'box-delivery-timestamp' ] ,
671
+ ) ;
672
+ const currentEpoch : number = getEpochTimeInSeconds ( ) ;
673
+ if (
674
+ currentEpoch - maxAge > dateTimeToEpochSeconds ( deliveryTimestamp ) ||
675
+ dateTimeToEpochSeconds ( deliveryTimestamp ) > currentEpoch
676
+ ) {
677
+ return false ;
678
+ }
679
+ if (
680
+ primaryKey &&
681
+ ( await computeWebhookSignature ( body , headers , primaryKey ) ) ==
682
+ headers [ 'box-signature-primary' ]
683
+ ) {
684
+ return true ;
685
+ }
686
+ if (
687
+ secondaryKey &&
688
+ ( await computeWebhookSignature ( body , headers , secondaryKey ) ) ==
689
+ headers [ 'box-signature-secondary' ]
690
+ ) {
691
+ return true ;
692
+ }
693
+ return false ;
694
+ }
618
695
}
619
696
export interface WebhooksManagerInput {
620
697
readonly auth ?: Authentication ;
0 commit comments