91 lines
2.5 KiB
Dart
91 lines
2.5 KiB
Dart
import 'dart:convert';
|
|
import 'dart:developer';
|
|
|
|
import 'package:equatable/equatable.dart';
|
|
|
|
class AuthToken extends Equatable {
|
|
final String accessToken;
|
|
final DateTime expiresAt;
|
|
final bool tnc;
|
|
|
|
const AuthToken({
|
|
required this.accessToken,
|
|
required this.expiresAt,
|
|
required this.tnc,
|
|
});
|
|
|
|
factory AuthToken.fromJson(Map<String, dynamic> json) {
|
|
final token = json['token'];
|
|
return AuthToken(
|
|
accessToken: token,
|
|
expiresAt: _decodeExpiryFromToken(token), // Keep existing method for expiry
|
|
tnc: _decodeTncFromToken(token), // Use new method for tnc
|
|
);
|
|
}
|
|
|
|
static DateTime _decodeExpiryFromToken(String token) {
|
|
try {
|
|
final parts = token.split('.');
|
|
if (parts.length != 3) {
|
|
throw Exception('Invalid JWT');
|
|
}
|
|
final payload = parts[1];
|
|
// Pad the payload if necessary
|
|
String normalized = base64Url.normalize(payload);
|
|
final payloadMap = json.decode(utf8.decode(base64Url.decode(normalized)));
|
|
if (payloadMap is! Map<String, dynamic> ||
|
|
!payloadMap.containsKey('exp')) {
|
|
throw Exception('Invalid payload');
|
|
}
|
|
final exp = payloadMap['exp'];
|
|
return DateTime.fromMillisecondsSinceEpoch(exp * 1000);
|
|
} catch (e) {
|
|
// Fallback: 1 hour from now if decoding fails
|
|
log(e.toString());
|
|
return DateTime.now().add(const Duration(hours: 1));
|
|
}
|
|
}
|
|
|
|
static bool _decodeTncFromToken(String token) {
|
|
try {
|
|
final parts = token.split('.');
|
|
if (parts.length != 3) {
|
|
throw Exception('Invalid JWT format for TNC decoding');
|
|
}
|
|
final payload = parts[1];
|
|
String normalized = base64Url.normalize(payload);
|
|
final payloadMap = json.decode(utf8.decode(base64Url.decode(normalized)));
|
|
|
|
if (payloadMap is! Map<String, dynamic> || !payloadMap.containsKey('tnc')) {
|
|
// If 'tnc' is not present in the payload, default to false
|
|
return false;
|
|
}
|
|
|
|
final tncValue = payloadMap['tnc'];
|
|
|
|
// Handle different representations of 'true'
|
|
if (tncValue is bool) {
|
|
return tncValue;
|
|
}
|
|
if (tncValue is String) {
|
|
return tncValue.toLowerCase() == 'true';
|
|
}
|
|
if (tncValue is int) {
|
|
return tncValue == 1;
|
|
}
|
|
|
|
// Default to false for any other case
|
|
return false;
|
|
} catch (e) {
|
|
log('Error decoding tnc from token: $e');
|
|
// Default to false if decoding fails or 'tnc' is not found/invalid
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool get isExpired => DateTime.now().isAfter(expiresAt);
|
|
|
|
@override
|
|
List<Object> get props => [accessToken, expiresAt, tnc];
|
|
}
|