forked from firka/student-legacy
363 lines
9.9 KiB
Dart
363 lines
9.9 KiB
Dart
// ignore_for_file: avoid_print, use_build_context_synchronously
|
|
|
|
import 'dart:convert';
|
|
import 'dart:io';
|
|
|
|
// import 'package:refilc/api/login.dart';
|
|
// import 'package:refilc/api/nonce.dart';
|
|
import 'package:refilc/api/providers/database_provider.dart';
|
|
import 'package:refilc/api/providers/user_provider.dart';
|
|
import 'package:refilc/api/providers/status_provider.dart';
|
|
import 'package:refilc/models/settings.dart';
|
|
import 'package:refilc/models/user.dart';
|
|
// import 'package:refilc/utils/jwt.dart';
|
|
import 'package:refilc_kreta_api/client/api.dart';
|
|
import 'package:http/http.dart' as http;
|
|
import 'package:http/io_client.dart' as http;
|
|
import 'dart:async';
|
|
|
|
class KretaClient {
|
|
String? accessToken;
|
|
String? refreshToken;
|
|
String? idToken;
|
|
String? userAgent;
|
|
late http.Client client;
|
|
|
|
late final SettingsProvider _settings;
|
|
late final UserProvider _user;
|
|
late final DatabaseProvider _database;
|
|
late final StatusProvider _status;
|
|
|
|
// bool _loginRefreshing = false;
|
|
|
|
KretaClient({
|
|
this.accessToken,
|
|
required SettingsProvider settings,
|
|
required UserProvider user,
|
|
required DatabaseProvider database,
|
|
required StatusProvider status,
|
|
}) : _settings = settings,
|
|
_user = user,
|
|
_database = database,
|
|
_status = status,
|
|
userAgent = settings.config.userAgent {
|
|
var ioclient = HttpClient();
|
|
ioclient.badCertificateCallback = _checkCerts;
|
|
client = http.IOClient(ioclient);
|
|
}
|
|
|
|
bool _checkCerts(X509Certificate cert, String host, int port) {
|
|
return _settings.developerMode;
|
|
}
|
|
|
|
Future<dynamic> getAPI(
|
|
String url, {
|
|
Map<String, String>? headers,
|
|
bool autoHeader = true,
|
|
bool json = true,
|
|
bool rawResponse = false,
|
|
}) async {
|
|
Map<String, String> headerMap;
|
|
|
|
if (rawResponse) json = false;
|
|
|
|
if (headers != null) {
|
|
headerMap = headers;
|
|
} else {
|
|
headerMap = {};
|
|
}
|
|
|
|
if (accessToken == null || accessToken == '') {
|
|
accessToken = _user.user?.accessToken;
|
|
}
|
|
|
|
try {
|
|
http.Response? res;
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
if (autoHeader) {
|
|
if (!headerMap.containsKey("authorization") && accessToken != null) {
|
|
headerMap["authorization"] = "Bearer $accessToken";
|
|
}
|
|
if (!headerMap.containsKey("user-agent") && userAgent != null) {
|
|
headerMap["user-agent"] = "$userAgent";
|
|
}
|
|
}
|
|
|
|
res = await client.get(Uri.parse(url), headers: headerMap);
|
|
_status.triggerRequest(res);
|
|
|
|
if (res.statusCode == 401) {
|
|
headerMap.remove("authorization");
|
|
print("DEBUG: 401 error, refreshing login");
|
|
print("DEBUG: 401 error, URL: $url");
|
|
//await refreshLogin();
|
|
} else {
|
|
break;
|
|
}
|
|
|
|
// Wait before retrying
|
|
await Future.delayed(const Duration(milliseconds: 1500));
|
|
}
|
|
|
|
if (res == null) throw "Login error";
|
|
if (res.body == 'invalid_grant' || res.body.replaceAll(' ', '') == '') {
|
|
throw "Auth error";
|
|
}
|
|
|
|
if (json) {
|
|
return jsonDecode(res.body);
|
|
} else if (rawResponse) {
|
|
return res.bodyBytes;
|
|
} else {
|
|
return res.body;
|
|
}
|
|
} on http.ClientException catch (error) {
|
|
print(
|
|
"ERROR: KretaClient.getAPI ($url) ClientException: ${error.message}");
|
|
} catch (error) {
|
|
print("ERROR: KretaClient.getAPI ($url) ${error.runtimeType}: $error");
|
|
}
|
|
}
|
|
|
|
Future<dynamic> postAPI(
|
|
String url, {
|
|
Map<String, String>? headers,
|
|
bool autoHeader = true,
|
|
bool json = true,
|
|
Object? body,
|
|
}) async {
|
|
Map<String, String> headerMap;
|
|
|
|
if (headers != null) {
|
|
headerMap = headers;
|
|
} else {
|
|
headerMap = {};
|
|
}
|
|
|
|
if (accessToken == null || accessToken == '') {
|
|
accessToken = _user.user?.accessToken;
|
|
}
|
|
|
|
try {
|
|
http.Response? res;
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
if (autoHeader) {
|
|
if (!headerMap.containsKey("authorization") && accessToken != null) {
|
|
headerMap["authorization"] = "Bearer $accessToken";
|
|
}
|
|
if (!headerMap.containsKey("user-agent") && userAgent != null) {
|
|
headerMap["user-agent"] = "$userAgent";
|
|
}
|
|
if (!headerMap.containsKey("content-type")) {
|
|
headerMap["content-type"] = "application/json";
|
|
}
|
|
if (url.contains('kommunikacio/uzenetek')) {
|
|
headerMap["X-Uzenet-Lokalizacio"] = "hu-HU";
|
|
}
|
|
}
|
|
|
|
res = await client.post(Uri.parse(url), headers: headerMap, body: body);
|
|
if (res.statusCode == 401) {
|
|
//await refreshLogin();
|
|
headerMap.remove("authorization");
|
|
} else {
|
|
break;
|
|
}
|
|
|
|
// Wait before retrying
|
|
await Future.delayed(const Duration(milliseconds: 1500));
|
|
}
|
|
|
|
if (res == null) throw "Login error";
|
|
|
|
if (json) {
|
|
print(jsonDecode(res.body));
|
|
return jsonDecode(res.body);
|
|
} else {
|
|
return res.body;
|
|
}
|
|
} on http.ClientException catch (error) {
|
|
print(
|
|
"ERROR: KretaClient.postAPI ($url) ClientException: ${error.message}");
|
|
} catch (error) {
|
|
print("ERROR: KretaClient.postAPI ($url) ${error.runtimeType}: $error");
|
|
}
|
|
}
|
|
|
|
Future<dynamic> sendFilesAPI(
|
|
String url, {
|
|
Map<String, String>? headers,
|
|
bool autoHeader = true,
|
|
Map<String, String>? body,
|
|
}) async {
|
|
Map<String, String> headerMap;
|
|
|
|
if (headers != null) {
|
|
headerMap = headers;
|
|
} else {
|
|
headerMap = {};
|
|
}
|
|
|
|
if (accessToken == null || accessToken == '') {
|
|
accessToken = _user.user?.accessToken;
|
|
}
|
|
|
|
try {
|
|
http.StreamedResponse? res;
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
if (autoHeader) {
|
|
if (!headerMap.containsKey("authorization") && accessToken != null) {
|
|
headerMap["authorization"] = "Bearer $accessToken";
|
|
}
|
|
if (!headerMap.containsKey("user-agent") && userAgent != null) {
|
|
headerMap["user-agent"] = "$userAgent";
|
|
}
|
|
if (!headerMap.containsKey("content-type")) {
|
|
headerMap["content-type"] = "multipart/form-data";
|
|
}
|
|
if (url.contains('kommunikacio/uzenetek')) {
|
|
headerMap["X-Uzenet-Lokalizacio"] = "hu-HU";
|
|
}
|
|
}
|
|
|
|
var request = http.MultipartRequest("POST", Uri.parse(url));
|
|
|
|
// request.files.add(value)
|
|
|
|
request.fields.addAll(body ?? {});
|
|
request.headers.addAll(headers ?? {});
|
|
|
|
res = await request.send();
|
|
|
|
if (res.statusCode == 401) {
|
|
headerMap.remove("authorization");
|
|
//await refreshLogin();
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (res == null) throw "Login error";
|
|
|
|
print(res.statusCode);
|
|
|
|
return res.statusCode;
|
|
} on http.ClientException catch (error) {
|
|
print(
|
|
"ERROR: KretaClient.postAPI ($url) ClientException: ${error.message}");
|
|
} catch (error) {
|
|
print("ERROR: KretaClient.postAPI ($url) ${error.runtimeType}: $error");
|
|
}
|
|
}
|
|
|
|
Future<String?> refreshLogin() async {
|
|
// if (_loginRefreshing) return null;
|
|
// _loginRefreshing = true;
|
|
|
|
User? loginUser = _user.user;
|
|
if (loginUser == null) return null;
|
|
|
|
Map<String, String> headers = {
|
|
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
|
|
"accept": "*/*",
|
|
"user-agent": "eKretaStudent/264745 CFNetwork/1494.0.7 Darwin/23.4.0",
|
|
};
|
|
|
|
if (_settings.presentationMode) {
|
|
print("DEBUG: refreshLogin: ${loginUser.id}");
|
|
} else {
|
|
print("DEBUG: refreshLogin: ${loginUser.id} ${loginUser.name}");
|
|
}
|
|
|
|
refreshToken ??= loginUser.refreshToken;
|
|
|
|
print("REFRESH TOKEN BELOW");
|
|
print(refreshToken);
|
|
|
|
print(loginUser.accessTokenExpire);
|
|
print(DateTime.now().toIso8601String());
|
|
|
|
if (!DateTime.now().isAfter(loginUser.accessTokenExpire)) {
|
|
return 'success';
|
|
}
|
|
|
|
if (refreshToken != null) {
|
|
// print("REFRESHING LOGIN");
|
|
Map? res = await postAPI(KretaAPI.login,
|
|
headers: headers,
|
|
body: User.refreshBody(
|
|
refreshToken: loginUser.refreshToken,
|
|
instituteCode: loginUser.instituteCode,
|
|
));
|
|
print("REFRESH RESPONSE BELOW");
|
|
print(res);
|
|
if (res != null) {
|
|
if (res.containsKey("error")) {
|
|
// remove user if refresh token expired
|
|
if (res["error"] == "invalid_grant") {
|
|
// remove user from app
|
|
// _user.removeUser(loginUser.id);
|
|
// await _database.store.removeUser(loginUser.id);
|
|
|
|
print("invalid refresh token (invalid_grant)");
|
|
|
|
// return error
|
|
return "refresh_token_expired";
|
|
}
|
|
}
|
|
|
|
if (res.containsKey("access_token")) {
|
|
accessToken = res["access_token"];
|
|
loginUser.accessToken = res["access_token"];
|
|
loginUser.accessTokenExpire =
|
|
DateTime.now().add(Duration(seconds: (res["expires_in"] - 30)));
|
|
_database.store.storeUser(loginUser);
|
|
_user.refresh();
|
|
}
|
|
if (res.containsKey("refresh_token")) {
|
|
refreshToken = res["refresh_token"];
|
|
loginUser.refreshToken = res["refresh_token"];
|
|
_database.store.storeUser(loginUser);
|
|
_user.refresh();
|
|
}
|
|
if (res.containsKey("id_token")) {
|
|
idToken = res["id_token"];
|
|
}
|
|
// _loginRefreshing = false;
|
|
print('successful refresh');
|
|
|
|
return 'success';
|
|
} else {
|
|
// _loginRefreshing = false;
|
|
return null;
|
|
}
|
|
} else {
|
|
// _loginRefreshing = false;
|
|
return null;
|
|
}
|
|
|
|
// return null;
|
|
}
|
|
|
|
Future<void> logout() async {
|
|
User? loginUser = _user.user;
|
|
if (loginUser == null) return;
|
|
|
|
Map<String, String> headers = {
|
|
"content-type": "application/x-www-form-urlencoded",
|
|
};
|
|
|
|
await postAPI(
|
|
KretaAPI.logout,
|
|
headers: headers,
|
|
body: User.logoutBody(
|
|
refreshToken: refreshToken!,
|
|
),
|
|
json: false,
|
|
);
|
|
}
|
|
}
|