@@ -161,14 +161,16 @@ struct WebPushManagerTests {
161161 func decrypt(
162162 request: HTTPClientRequest ,
163163 userAgentPrivateKey: P256 . KeyAgreement . PrivateKey ,
164- userAgentKeyMaterial: UserAgentKeyMaterial
164+ userAgentKeyMaterial: UserAgentKeyMaterial ,
165+ expectedReadableBytes: Int = 4096 ,
166+ expectedRecordSize: Int = 4010
165167 ) async throws -> [ UInt8 ] {
166168 var body = try #require( try await request. body? . collect ( upTo: 16 * 1024 ) )
167- #expect( body. readableBytes == 4096 )
169+ #expect( body. readableBytes == expectedReadableBytes )
168170
169171 let salt = body. readBytes ( length: 16 )
170172 let recordSize = body. readInteger ( as: UInt32 . self)
171- #expect( try #require( recordSize) == 4010 )
173+ #expect( try #require( recordSize) == expectedRecordSize )
172174 let keyIDSize = body. readInteger ( as: UInt8 . self)
173175 let keyID = body. readBytes ( length: Int ( keyIDSize ?? 0 ) )
174176
@@ -342,8 +344,74 @@ struct WebPushManagerTests {
342344 }
343345 }
344346
345- @Test func sendMessageToNotFoundPushServerError( ) async throws {
346- await confirmation { requestWasMade in
347+ @Test func sendMessageToSubscriberWithInvalidVAPIDKey( ) async throws {
348+ await confirmation ( expectedCount: 0 ) { requestWasMade in
349+ let vapidConfiguration = VAPID . Configuration. mockedConfiguration
350+
351+ let subscriberPrivateKey = P256 . KeyAgreement. PrivateKey ( compactRepresentable: false )
352+ var authenticationSecret : [ UInt8 ] = Array ( repeating: 0 , count: 16 )
353+ for index in authenticationSecret. indices { authenticationSecret [ index] = . random( in: . min ... . max) }
354+
355+ let subscriber = Subscriber (
356+ endpoint: URL ( string: " https://example.com/subscriber " ) !,
357+ userAgentKeyMaterial: UserAgentKeyMaterial ( publicKey: subscriberPrivateKey. publicKey, authenticationSecret: Data ( authenticationSecret) ) ,
358+ vapidKeyID: . mockedKeyID2
359+ )
360+
361+ let manager = WebPushManager (
362+ vapidConfiguration: vapidConfiguration,
363+ backgroundActivityLogger: Logger ( label: " WebPushManagerTests " , factory: { PrintLogHandler ( label: $0, metadataProvider: $1) } ) ,
364+ executor: . httpClient( MockHTTPClient ( { request in
365+ requestWasMade ( )
366+ return HTTPClientResponse ( status: . created)
367+ } ) )
368+ )
369+
370+ await #expect( throws: VAPID . ConfigurationError. matchingKeyNotFound) {
371+ try await manager. send ( string: " hello " , to: subscriber)
372+ }
373+ }
374+ }
375+
376+ @Test ( . disabled( " Fails because we need a public/private key pair that fails to make a shared secret " ) )
377+ func sendMessageToSubscriberWithInvalidUserAgentKey( ) async throws {
378+ try await confirmation ( expectedCount: 0 ) { requestWasMade in
379+ let vapidConfiguration = VAPID . Configuration. mockedConfiguration
380+
381+ let privateKey = try P256 . KeyAgreement. PrivateKey ( rawRepresentation: Data ( base64Encoded: " fkqlT3FL8B34XFAmm+o6hnIfhK/nT3tB6lirzzR06I0= " ) !)
382+ let publicKey = try P256 . KeyAgreement. PublicKey ( compressedRepresentation: Data ( base64Encoded: " Ahj5uud0fNhE6YUlt8zQ2vbh0gqBiyF1qakeTq5TQ7yY " ) !)
383+ var authenticationSecret : [ UInt8 ] = Array ( repeating: 0 , count: 16 )
384+ for index in authenticationSecret. indices { authenticationSecret [ index] = . random( in: . min ... . max) }
385+
386+ let subscriber = Subscriber (
387+ endpoint: URL ( string: " https://example.com/subscriber " ) !,
388+ userAgentKeyMaterial: UserAgentKeyMaterial (
389+ publicKey: publicKey,
390+ authenticationSecret: Data ( authenticationSecret)
391+ ) ,
392+ vapidKeyID: . mockedKeyID1
393+ )
394+
395+ let manager = WebPushManager (
396+ vapidConfiguration: vapidConfiguration,
397+ backgroundActivityLogger: Logger ( label: " WebPushManagerTests " , factory: { PrintLogHandler ( label: $0, metadataProvider: $1) } ) ,
398+ executor: . httpClient(
399+ MockHTTPClient ( { request in
400+ requestWasMade ( )
401+ return HTTPClientResponse ( status: . created)
402+ } ) ,
403+ privateKey
404+ )
405+ )
406+
407+ await #expect( throws: BadSubscriberError ( ) ) {
408+ try await manager. send ( string: " hello " , to: subscriber)
409+ }
410+ }
411+ }
412+
413+ @Test func sendSizeLimitMessageSucceeds( ) async throws {
414+ try await confirmation { requestWasMade in
347415 let vapidConfiguration = VAPID . Configuration. makeTesting ( )
348416
349417 let subscriberPrivateKey = P256 . KeyAgreement. PrivateKey ( compactRepresentable: false )
@@ -356,6 +424,104 @@ struct WebPushManagerTests {
356424 vapidKeyID: vapidConfiguration. primaryKey!. id
357425 )
358426
427+ let manager = WebPushManager (
428+ vapidConfiguration: vapidConfiguration,
429+ backgroundActivityLogger: Logger ( label: " WebPushManagerTests " , factory: { PrintLogHandler ( label: $0, metadataProvider: $1) } ) ,
430+ executor: . httpClient( MockHTTPClient ( { request in
431+ try validateAuthotizationHeader (
432+ request: request,
433+ vapidConfiguration: vapidConfiguration,
434+ origin: " https://example.com "
435+ )
436+ #expect( request. method == . POST)
437+ #expect( request. headers [ " Content-Encoding " ] == [ " aes128gcm " ] )
438+ #expect( request. headers [ " Content-Type " ] == [ " application/octet-stream " ] )
439+ #expect( request. headers [ " TTL " ] == [ " 2592000 " ] )
440+ #expect( request. headers [ " Urgency " ] == [ " high " ] )
441+ #expect( request. headers [ " Topic " ] == [ ] ) // TODO: Update when topic is added
442+
443+ let message = try await decrypt (
444+ request: request,
445+ userAgentPrivateKey: subscriberPrivateKey,
446+ userAgentKeyMaterial: subscriber. userAgentKeyMaterial,
447+ expectedReadableBytes: 4096 ,
448+ expectedRecordSize: 4010
449+ )
450+
451+ #expect( message == Array ( repeating: 0 , count: 3993 ) )
452+
453+ requestWasMade ( )
454+ return HTTPClientResponse ( status: . created)
455+ } ) )
456+ )
457+
458+ try await manager. send ( data: Array ( repeating: 0 , count: 3993 ) , to: subscriber)
459+ }
460+ }
461+
462+ @Test func sendExtraLargeMessageCouldSucceed( ) async throws {
463+ try await confirmation { requestWasMade in
464+ let vapidConfiguration = VAPID . Configuration. makeTesting ( )
465+
466+ let subscriberPrivateKey = P256 . KeyAgreement. PrivateKey ( compactRepresentable: false )
467+ var authenticationSecret : [ UInt8 ] = Array ( repeating: 0 , count: 16 )
468+ for index in authenticationSecret. indices { authenticationSecret [ index] = . random( in: . min ... . max) }
469+
470+ let subscriber = Subscriber (
471+ endpoint: URL ( string: " https://example.com/subscriber " ) !,
472+ userAgentKeyMaterial: UserAgentKeyMaterial ( publicKey: subscriberPrivateKey. publicKey, authenticationSecret: Data ( authenticationSecret) ) ,
473+ vapidKeyID: vapidConfiguration. primaryKey!. id
474+ )
475+
476+ let manager = WebPushManager (
477+ vapidConfiguration: vapidConfiguration,
478+ backgroundActivityLogger: Logger ( label: " WebPushManagerTests " , factory: { PrintLogHandler ( label: $0, metadataProvider: $1) } ) ,
479+ executor: . httpClient( MockHTTPClient ( { request in
480+ try validateAuthotizationHeader (
481+ request: request,
482+ vapidConfiguration: vapidConfiguration,
483+ origin: " https://example.com "
484+ )
485+ #expect( request. method == . POST)
486+ #expect( request. headers [ " Content-Encoding " ] == [ " aes128gcm " ] )
487+ #expect( request. headers [ " Content-Type " ] == [ " application/octet-stream " ] )
488+ #expect( request. headers [ " TTL " ] == [ " 2592000 " ] )
489+ #expect( request. headers [ " Urgency " ] == [ " high " ] )
490+ #expect( request. headers [ " Topic " ] == [ ] ) // TODO: Update when topic is added
491+
492+ let message = try await decrypt (
493+ request: request,
494+ userAgentPrivateKey: subscriberPrivateKey,
495+ userAgentKeyMaterial: subscriber. userAgentKeyMaterial,
496+ expectedReadableBytes: 4097 ,
497+ expectedRecordSize: 4011
498+ )
499+
500+ #expect( message == Array ( repeating: 0 , count: 3994 ) )
501+
502+ requestWasMade ( )
503+ return HTTPClientResponse ( status: . created)
504+ } ) )
505+ )
506+
507+ try await manager. send ( data: Array ( repeating: 0 , count: 3994 ) , to: subscriber)
508+ }
509+ }
510+
511+ @Test func sendMessageToNotFoundPushServerError( ) async throws {
512+ await confirmation { requestWasMade in
513+ let vapidConfiguration = VAPID . Configuration. mockedConfiguration
514+
515+ let subscriberPrivateKey = P256 . KeyAgreement. PrivateKey ( compactRepresentable: false )
516+ var authenticationSecret : [ UInt8 ] = Array ( repeating: 0 , count: 16 )
517+ for index in authenticationSecret. indices { authenticationSecret [ index] = . random( in: . min ... . max) }
518+
519+ let subscriber = Subscriber (
520+ endpoint: URL ( string: " https://example.com/subscriber " ) !,
521+ userAgentKeyMaterial: UserAgentKeyMaterial ( publicKey: subscriberPrivateKey. publicKey, authenticationSecret: Data ( authenticationSecret) ) ,
522+ vapidKeyID: . mockedKeyID1
523+ )
524+
359525 let manager = WebPushManager (
360526 vapidConfiguration: vapidConfiguration,
361527 backgroundActivityLogger: Logger ( label: " WebPushManagerTests " , factory: { PrintLogHandler ( label: $0, metadataProvider: $1) } ) ,
@@ -373,7 +539,7 @@ struct WebPushManagerTests {
373539
374540 @Test func sendMessageToGonePushServerError( ) async throws {
375541 await confirmation { requestWasMade in
376- let vapidConfiguration = VAPID . Configuration. makeTesting ( )
542+ let vapidConfiguration = VAPID . Configuration. mockedConfiguration
377543
378544 let subscriberPrivateKey = P256 . KeyAgreement. PrivateKey ( compactRepresentable: false )
379545 var authenticationSecret : [ UInt8 ] = Array ( repeating: 0 , count: 16 )
@@ -382,7 +548,7 @@ struct WebPushManagerTests {
382548 let subscriber = Subscriber (
383549 endpoint: URL ( string: " https://example.com/subscriber " ) !,
384550 userAgentKeyMaterial: UserAgentKeyMaterial ( publicKey: subscriberPrivateKey. publicKey, authenticationSecret: Data ( authenticationSecret) ) ,
385- vapidKeyID: vapidConfiguration . primaryKey! . id
551+ vapidKeyID: . mockedKeyID1
386552 )
387553
388554 let manager = WebPushManager (
@@ -402,7 +568,7 @@ struct WebPushManagerTests {
402568
403569 @Test func sendMessageToUnknownPushServerError( ) async throws {
404570 await confirmation { requestWasMade in
405- let vapidConfiguration = VAPID . Configuration. makeTesting ( )
571+ let vapidConfiguration = VAPID . Configuration. mockedConfiguration
406572
407573 let subscriberPrivateKey = P256 . KeyAgreement. PrivateKey ( compactRepresentable: false )
408574 var authenticationSecret : [ UInt8 ] = Array ( repeating: 0 , count: 16 )
@@ -411,7 +577,7 @@ struct WebPushManagerTests {
411577 let subscriber = Subscriber (
412578 endpoint: URL ( string: " https://example.com/subscriber " ) !,
413579 userAgentKeyMaterial: UserAgentKeyMaterial ( publicKey: subscriberPrivateKey. publicKey, authenticationSecret: Data ( authenticationSecret) ) ,
414- vapidKeyID: vapidConfiguration . primaryKey! . id
580+ vapidKeyID: . mockedKeyID1
415581 )
416582
417583 let manager = WebPushManager (
0 commit comments