@@ -60,7 +60,7 @@ internal WebPushSchemeHeadersValues(string authenticationHeaderValueParameter, s
6060 private string _publicKey ;
6161 private string _privateKey ;
6262 private ECPrivateKeyParameters _privateSigningKey ;
63- private int _expiration ;
63+ private int _relativeExpiration ;
6464
6565 private static readonly DateTime _unixEpoch = new DateTime ( 1970 , 1 , 1 , 0 , 0 , 0 ) ;
6666 private static readonly string _jwtHeaderSegment = UrlBase64Converter . ToUrlBase64String ( Encoding . UTF8 . GetBytes ( JWT_HEADER ) ) ;
@@ -149,7 +149,7 @@ public string PrivateKey
149149 /// </summary>
150150 public int Expiration
151151 {
152- get { return _expiration ; }
152+ get { return _relativeExpiration ; }
153153
154154 set
155155 {
@@ -158,9 +158,14 @@ public int Expiration
158158 throw new ArgumentOutOfRangeException ( nameof ( Expiration ) , "Expiration must be a number of seconds not longer than 24 hours" ) ;
159159 }
160160
161- _expiration = value ;
161+ _relativeExpiration = value ;
162162 }
163163 }
164+
165+ /// <summary>
166+ /// Gets or sets the token cache.
167+ /// </summary>
168+ public IVapidTokenCache TokenCache { get ; set ; }
164169 #endregion
165170
166171 #region Constructor
@@ -174,7 +179,7 @@ public VapidAuthentication(string publicKey, string privateKey)
174179 PublicKey = publicKey ;
175180 PrivateKey = privateKey ;
176181
177- _expiration = DEFAULT_EXPIRATION ;
182+ _relativeExpiration = DEFAULT_EXPIRATION ;
178183 }
179184 #endregion
180185
@@ -211,40 +216,23 @@ private string GetToken(string audience)
211216 throw new ArgumentException ( nameof ( audience ) , "Audience should be an absolute URL" ) ;
212217 }
213218
214- string jwtBodySegment = GetJwtBodySegment ( audience ) ;
219+ string token = TokenCache ? . Get ( audience ) ;
215220
216- return GenerateJwtToken ( jwtBodySegment ) ;
217- }
218-
219- private string GetJwtBodySegment ( string audience )
220- {
221- StringBuilder jwtBodyBuilder = new StringBuilder ( ) ;
222-
223- jwtBodyBuilder . Append ( JWT_BODY_AUDIENCE_PART ) . Append ( audience )
224- . Append ( JWT_BODY_EXPIRATION_PART ) . Append ( GetAbsoluteExpiration ( _expiration ) . ToString ( CultureInfo . InvariantCulture ) ) ;
225-
226- if ( _subject != null )
221+ if ( token == null )
227222 {
228- jwtBodyBuilder . Append ( JWT_BODY_SUBJECT_PART ) . Append ( _subject ) . Append ( JWT_BODY_WITH_SUBJECT_CLOSING ) ;
229- }
230- else
231- {
232- jwtBodyBuilder . Append ( JWT_BODY_WITHOUT_SUBJECT_CLOSING ) ;
233- }
223+ DateTime absoluteExpiration = DateTime . UtcNow . AddSeconds ( _relativeExpiration ) ;
234224
235- return UrlBase64Converter . ToUrlBase64String ( Encoding . UTF8 . GetBytes ( jwtBodyBuilder . ToString ( ) ) ) ;
236- }
225+ token = GenerateToken ( audience , absoluteExpiration ) ;
237226
238- private static long GetAbsoluteExpiration ( int expirationSeconds )
239- {
240- TimeSpan unixEpochOffset = DateTime . UtcNow - _unixEpoch ;
227+ TokenCache ? . Put ( audience , absoluteExpiration , token ) ;
228+ }
241229
242- return ( long ) unixEpochOffset . TotalSeconds + expirationSeconds ;
230+ return token ;
243231 }
244232
245- private string GenerateJwtToken ( string jwtBodySegment )
233+ private string GenerateToken ( string audience , DateTime absoluteExpiration )
246234 {
247- string jwtInput = _jwtHeaderSegment + JWT_SEPARATOR + jwtBodySegment ;
235+ string jwtInput = _jwtHeaderSegment + JWT_SEPARATOR + GenerateJwtBodySegment ( audience , absoluteExpiration ) ;
248236
249237 byte [ ] jwtInputHash ;
250238 using ( var sha256Hasher = SHA256 . Create ( ) )
@@ -268,6 +256,32 @@ private string GenerateJwtToken(string jwtBodySegment)
268256 return jwtInput + JWT_SEPARATOR + UrlBase64Converter . ToUrlBase64String ( combinedJwtSignature ) ;
269257 }
270258
259+ private string GenerateJwtBodySegment ( string audience , DateTime absoluteExpiration )
260+ {
261+ StringBuilder jwtBodyBuilder = new StringBuilder ( ) ;
262+
263+ jwtBodyBuilder . Append ( JWT_BODY_AUDIENCE_PART ) . Append ( audience )
264+ . Append ( JWT_BODY_EXPIRATION_PART ) . Append ( ToUnixTimeSeconds ( absoluteExpiration ) . ToString ( CultureInfo . InvariantCulture ) ) ;
265+
266+ if ( _subject != null )
267+ {
268+ jwtBodyBuilder . Append ( JWT_BODY_SUBJECT_PART ) . Append ( _subject ) . Append ( JWT_BODY_WITH_SUBJECT_CLOSING ) ;
269+ }
270+ else
271+ {
272+ jwtBodyBuilder . Append ( JWT_BODY_WITHOUT_SUBJECT_CLOSING ) ;
273+ }
274+
275+ return UrlBase64Converter . ToUrlBase64String ( Encoding . UTF8 . GetBytes ( jwtBodyBuilder . ToString ( ) ) ) ;
276+ }
277+
278+ private static long ToUnixTimeSeconds ( DateTime dateTime )
279+ {
280+ TimeSpan unixEpochOffset = dateTime - _unixEpoch ;
281+
282+ return ( long ) unixEpochOffset . TotalSeconds ;
283+ }
284+
271285 private static void ByteArrayCopyWithPadLeft ( byte [ ] sourceArray , byte [ ] destinationArray , int destinationIndex , int destinationLengthToUse )
272286 {
273287 if ( sourceArray . Length != destinationLengthToUse )
0 commit comments