From 2fcea79c95cc03a0a3cdb4ece93c8e3721770e67 Mon Sep 17 00:00:00 2001 From: Jonas Roussel Date: Tue, 13 Apr 2021 18:45:19 +0200 Subject: [PATCH] v2.1.0 --- CHANGELOG.md | 5 +++ lib/src/errors.dart | 22 ++++++++++ lib/src/jwt.dart | 101 +++++++++++++++++++++++--------------------- pubspec.yaml | 6 +-- 4 files changed, 84 insertions(+), 50 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a015bd3..3dfd126 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 2.1.0 + +- When an undefined error occur `JWTUndefinedError` is thrown containing the original error in `error` property (https://github.com/jonasroussel/jsonwebtoken/issues/9) +- **BREAKING CHANGE**: `jwt.verify` no longer support `throwUndefinedErrors` parameter + ## 2.0.1 - Fixing `JWT.sign` to include `iat` & other attributes when payload is an empty Map diff --git a/lib/src/errors.dart b/lib/src/errors.dart index bf58288..ee09602 100644 --- a/lib/src/errors.dart +++ b/lib/src/errors.dart @@ -12,19 +12,41 @@ class JWTError extends Error { /// An error thrown when jwt is invalid class JWTInvalidError extends JWTError { JWTInvalidError(String message) : super(message); + + @override + String toString() => 'JWTInvalidError: $message'; } /// An error thrown when jwt is expired class JWTExpiredError extends JWTError { JWTExpiredError() : super('jwt expired'); + + @override + String toString() => 'JWTExpiredError: $message'; } /// An error thrown when jwt is not active class JWTNotActiveError extends JWTError { JWTNotActiveError() : super('jwt not active'); + + @override + String toString() => 'JWTNotActiveError: $message'; } /// An error thrown when parsing failed class JWTParseError extends JWTError { JWTParseError(String message) : super(message); + + @override + String toString() => 'JWTParseError: $message'; +} + +/// An error thrown by default +class JWTUndefinedError extends JWTError { + JWTUndefinedError(this.error) : super(error.toString()); + + final Error error; + + @override + String toString() => 'JWTUndefinedError: $message'; } diff --git a/lib/src/jwt.dart b/lib/src/jwt.dart index 58ced3d..f58d148 100644 --- a/lib/src/jwt.dart +++ b/lib/src/jwt.dart @@ -20,7 +20,6 @@ class JWT { bool checkHeaderType = true, bool checkExpiresIn = true, bool checkNotBefore = true, - bool throwUndefinedErrors = false, Duration? issueAt, String? audience, String? subject, @@ -129,10 +128,10 @@ class JWT { return JWT(payload); } } catch (ex) { - if (throwUndefinedErrors) { - rethrow; + if (ex is Error) { + throw JWTUndefinedError(ex); } else { - throw JWTInvalidError('invalid token'); + rethrow; } } } @@ -175,56 +174,64 @@ class JWT { Duration? notBefore, bool noIssueAt = false, }) { - final header = {'alg': algorithm.name, 'typ': 'JWT'}; + try { + final header = {'alg': algorithm.name, 'typ': 'JWT'}; - if (payload is Map || payload is Map) { + if (payload is Map || payload is Map) { + try { + payload = Map.from(payload); + + if (!noIssueAt) payload['iat'] = secondsSinceEpoch(DateTime.now()); + if (expiresIn != null) { + payload['exp'] = secondsSinceEpoch(DateTime.now().add(expiresIn)); + } + if (notBefore != null) { + payload['nbf'] = secondsSinceEpoch(DateTime.now().add(notBefore)); + } + if (audience != null) payload['aud'] = audience; + if (subject != null) payload['sub'] = subject; + if (issuer != null) payload['iss'] = issuer; + if (jwtId != null) payload['jti'] = jwtId; + } catch (ex) { + assert( + payload is Map, + 'If payload is a Map its must be a Map', + ); + } + } + + final b64Header = base64Unpadded(jsonBase64.encode(header)); + + String b64Payload; try { - payload = Map.from(payload); - - if (!noIssueAt) payload['iat'] = secondsSinceEpoch(DateTime.now()); - if (expiresIn != null) { - payload['exp'] = secondsSinceEpoch(DateTime.now().add(expiresIn)); - } - if (notBefore != null) { - payload['nbf'] = secondsSinceEpoch(DateTime.now().add(notBefore)); - } - if (audience != null) payload['aud'] = audience; - if (subject != null) payload['sub'] = subject; - if (issuer != null) payload['iss'] = issuer; - if (jwtId != null) payload['jti'] = jwtId; + b64Payload = base64Unpadded( + payload is String + ? base64.encode(utf8.encode(payload)) + : jsonBase64.encode(payload), + ); } catch (ex) { - assert( - payload is Map, - 'If payload is a Map its must be a Map', + throw JWTError( + 'invalid payload json format (Map keys must be String type)', ); } - } - final b64Header = base64Unpadded(jsonBase64.encode(header)); - - String b64Payload; - try { - b64Payload = base64Unpadded( - payload is String - ? base64.encode(utf8.encode(payload)) - : jsonBase64.encode(payload), - ); - } catch (ex) { - throw JWTError( - 'invalid payload json format (Map keys must be String type)', - ); - } - - final body = '$b64Header.$b64Payload'; - final signature = base64Unpadded( - base64Url.encode( - algorithm.sign( - key, - Uint8List.fromList(utf8.encode(body)), + final body = '$b64Header.$b64Payload'; + final signature = base64Unpadded( + base64Url.encode( + algorithm.sign( + key, + Uint8List.fromList(utf8.encode(body)), + ), ), - ), - ); + ); - return body + '.' + signature; + return body + '.' + signature; + } catch (ex) { + if (ex is Error) { + throw JWTUndefinedError(ex); + } else { + rethrow; + } + } } } diff --git a/pubspec.yaml b/pubspec.yaml index caa916c..3bdd737 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: dart_jsonwebtoken description: A dart implementation of the famous javascript library 'jsonwebtoken' (JWT). -version: 2.0.1 +version: 2.1.0 repository: https://github.com/jonasroussel/jsonwebtoken homepage: https://github.com/jonasroussel/jsonwebtoken#readme @@ -8,9 +8,9 @@ environment: sdk: '>=2.12.0 <3.0.0' dependencies: - crypto: ^3.0.0 + crypto: ^3.0.1 pointycastle: ^3.0.1 ed25519_edwards: ^0.1.0 dev_dependencies: - pedantic: ^1.9.2 + pedantic: ^1.11.0