mirror of
https://github.com/jonasroussel/dart_jsonwebtoken.git
synced 2025-05-17 16:15:52 +08:00
Add testable date times (#50)
* refactor: replaces DateTime.now() with clock.now() for testability * test: add tests for verify exp * Refactor JWT expiration tests --------- Co-authored-by: Jonas Roussel <go.jroussel@gmail.com>
This commit is contained in:
@ -2,12 +2,13 @@ import 'dart:collection';
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:clock/clock.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
import 'algorithms.dart';
|
||||
import 'exceptions.dart';
|
||||
import 'keys.dart';
|
||||
import 'helpers.dart';
|
||||
import 'keys.dart';
|
||||
|
||||
class JWT {
|
||||
/// Verify a token.
|
||||
@ -64,7 +65,7 @@ class JWT {
|
||||
final exp = DateTime.fromMillisecondsSinceEpoch(
|
||||
payload['exp'] * 1000,
|
||||
);
|
||||
if (exp.isBefore(DateTime.now())) {
|
||||
if (exp.isBefore(clock.now())) {
|
||||
throw JWTExpiredException();
|
||||
}
|
||||
}
|
||||
@ -74,7 +75,7 @@ class JWT {
|
||||
final nbf = DateTime.fromMillisecondsSinceEpoch(
|
||||
payload['nbf'] * 1000,
|
||||
);
|
||||
if (nbf.isAfter(DateTime.now())) {
|
||||
if (nbf.isAfter(clock.now())) {
|
||||
throw JWTNotActiveException();
|
||||
}
|
||||
}
|
||||
@ -87,7 +88,7 @@ class JWT {
|
||||
final iat = DateTime.fromMillisecondsSinceEpoch(
|
||||
payload['iat'] * 1000,
|
||||
);
|
||||
if (!iat.isAtSameMomentAs(DateTime.now())) {
|
||||
if (!iat.isAtSameMomentAs(clock.now())) {
|
||||
throw JWTInvalidException('invalid issue at');
|
||||
}
|
||||
}
|
||||
@ -265,12 +266,12 @@ class JWT {
|
||||
try {
|
||||
payload = Map<String, dynamic>.from(payload);
|
||||
|
||||
if (!noIssueAt) payload['iat'] = secondsSinceEpoch(DateTime.now());
|
||||
if (!noIssueAt) payload['iat'] = secondsSinceEpoch(clock.now());
|
||||
if (expiresIn != null) {
|
||||
payload['exp'] = secondsSinceEpoch(DateTime.now().add(expiresIn));
|
||||
payload['exp'] = secondsSinceEpoch(clock.now().add(expiresIn));
|
||||
}
|
||||
if (notBefore != null) {
|
||||
payload['nbf'] = secondsSinceEpoch(DateTime.now().add(notBefore));
|
||||
payload['nbf'] = secondsSinceEpoch(clock.now().add(notBefore));
|
||||
}
|
||||
if (audience != null) payload['aud'] = audience!.toJson();
|
||||
if (subject != null) payload['sub'] = subject;
|
||||
|
@ -17,7 +17,9 @@ dependencies:
|
||||
convert: ^3.1.1
|
||||
collection: ^1.17.1
|
||||
ed25519_edwards: ^0.3.1
|
||||
clock: ^1.1.1
|
||||
|
||||
dev_dependencies:
|
||||
fake_async: ^1.3.1
|
||||
lints: ^2.1.1
|
||||
test: ^1.24.6
|
||||
|
50
test/header_test.dart
Normal file
50
test/header_test.dart
Normal file
@ -0,0 +1,50 @@
|
||||
import 'package:clock/clock.dart';
|
||||
import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart';
|
||||
import 'package:fake_async/fake_async.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
final hsKey = SecretKey('secret passphrase');
|
||||
|
||||
void main() {
|
||||
group("JWT Header", () {
|
||||
//--------------------//
|
||||
// Expiration (exp) //
|
||||
//--------------------//
|
||||
group('exp', () {
|
||||
test('should be expired', () {
|
||||
final duration = Duration(hours: 1);
|
||||
final token = JWT({'foo': 'bar'}).sign(hsKey, expiresIn: duration);
|
||||
|
||||
fakeAsync((async) {
|
||||
async.elapse(duration);
|
||||
expect(
|
||||
() => JWT.verify(token, hsKey),
|
||||
throwsA(isA<JWTExpiredException>()),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test('should be still valid', () {
|
||||
withClock(
|
||||
Clock.fixed(DateTime(2023)),
|
||||
() {
|
||||
final duration = Duration(hours: 1);
|
||||
final token = JWT({'foo': 'bar'}).sign(hsKey, expiresIn: duration);
|
||||
|
||||
fakeAsync((async) {
|
||||
async.elapse(Duration(minutes: 30));
|
||||
expect(
|
||||
JWT.verify(token, hsKey).payload,
|
||||
equals({
|
||||
'foo': 'bar',
|
||||
'iat': 1672527600,
|
||||
'exp': 1672531200,
|
||||
}),
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
Reference in New Issue
Block a user