1
0

lido_api.dart 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. //import 'package:html';
  2. import 'dart:convert';
  3. import 'dart:developer';
  4. import 'dart:io';
  5. import 'package:flutter_riverpod/flutter_riverpod.dart';
  6. import 'package:hive_flutter/hive_flutter.dart';
  7. import 'package:http/http.dart' as http;
  8. import 'package:flutter/foundation.dart';
  9. import 'package:jiffy/jiffy.dart';
  10. import 'package:tp5/core/utils.dart';
  11. final lidoapiProvider = Provider<LidoApi>((ref) {
  12. return LidoApi();
  13. });
  14. class LidoApi {
  15. //static const url = "https://tar.lido.aero";
  16. static const url =
  17. kIsWeb ? "https://proxy.fares.cyou" : "https://tar.lido.aero";
  18. //static const url = "https://proxy.fares.cyou";
  19. static const realurl = "https://tar.lido.aero";
  20. final timeout = Duration(seconds: 7);
  21. LidoApi({this.username = "", this.password = ""});
  22. bool logged = false;
  23. String username;
  24. String password;
  25. String get cookie =>
  26. "${cookieMap.keys.fold("", (t, e) => (t == "") ? "$e=${cookieMap[e]}" : "$t; $e=${cookieMap[e]}")};SameSite=None; Secure";
  27. Map cookieMap = {};
  28. Map<String, String> get headers => {
  29. "Accept": "application/vnd.lsy.lido.lcb.v1.hal+json",
  30. "Accept-Encoding": "gzip, deflate, br",
  31. "Accept-Language": "en",
  32. "Connection": "keep-alive",
  33. "Content-Type": "application/json;charset=UTF-8",
  34. //"Host": Uri.parse(realurl).host,
  35. "Origin": Uri.parse(realurl).host,
  36. //"sec-ch-ua":'" Not A;Brand";v="99", "Chromium";v="101", "Google Chrome";v="101"',
  37. // "sec-ch-ua-mobile": "?0",
  38. // "sec-ch-ua-platform": "Windows",
  39. // "Sec-Fetch-Dest": "empty",
  40. // "Sec-Fetch-Mode": "cors",
  41. // "Sec-Fetch-Site": "same-origin",
  42. "User-Agent":
  43. 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36',
  44. "X-lido-applicationId": "lido-lcb",
  45. "X-lido-clientId": "lido-lcb-web",
  46. "X-lido-customerId": "TAR",
  47. "X-lido-operatingAirline": "",
  48. "X-lido-timeStamp": DateTime.now().toUtc().toIso8601String(),
  49. "X-lido-traceId": "0c497133-2a92-45a0-8ffe-a03c77852201",
  50. "cookie": "SERVERID=docker2; $cookie",
  51. "X-lido-csrf": cookieMap["lido_csrf"] ?? "",
  52. };
  53. Future logout() async {
  54. var response = await http.post(Uri.parse('${url}USR/actionLogout.jsp'),
  55. body: {"Cookie": cookie});
  56. logged = false;
  57. }
  58. bool credSaved() {
  59. return (Hive.box("profile").get("lido_user", defaultValue: "") != "") &&
  60. (Hive.box("profile").get("lido_pass", defaultValue: "") != "");
  61. }
  62. Future login({String? user, String? pass}) async {
  63. username = user ?? Hive.box("profile").get("lido_user", defaultValue: "");
  64. password = pass ?? Hive.box("profile").get("lido_pass", defaultValue: "");
  65. try {
  66. var response = await http
  67. .get(
  68. Uri.parse(
  69. '$url/lido/las/login.jsp?DESMON_RESULT_PAGE=$realurl/briefing//'),
  70. )
  71. .timeout(timeout);
  72. cookieMap.addAll(_getcookies(response.headers["set-cookie"] ??
  73. response.headers["_set-cookie"] ??
  74. ""));
  75. //print(response.headers);
  76. response = await http.post(
  77. Uri.parse('$url/lido/las/dwr/call/plaincall/LoginBean.login.dwr'),
  78. body: {
  79. "callCount": "1",
  80. "nextReverseAjaxIndex": "0",
  81. "c0-scriptName": "LoginBean",
  82. "c0-methodName": "login",
  83. "c0-id": "0",
  84. "c0-param0": "string:$username",
  85. "c0-param1": "string:$password",
  86. "c0-param2": "string:",
  87. "c0-param3": "string:LIDO",
  88. "c0-param4": "string:en",
  89. "batchId": "0",
  90. "instanceId": "0",
  91. "page":
  92. "/lido/las/login.jsp?DESMON_RESULT_PAGE=$realurl/briefing&DESMON_CODE=LAS_002&DESMON_LANG=en",
  93. "scriptSessionId":
  94. "lSUqDnaTyhevHY6vpNvPdIR~IuUygzP8a2p/kYr1m2p-BgwpWJ4*a"
  95. },
  96. headers: {});
  97. cookieMap.addAll(_getcookies(response.headers["set-cookie"] ?? ""));
  98. //log("lidoapi: login : $username $password ${response.statusCode} ${response.body}");
  99. final message = RegExp(r'(?<=errorMessage2:")(.+)(?=",)')
  100. .firstMatch(response.body)
  101. ?.group(0) ??
  102. RegExp(r'(?<=errorMessage1:")(.+)(?=",)')
  103. .firstMatch(response.body)
  104. ?.group(0);
  105. final errorcode = RegExp(r'(?<=errorCode:)(.+?)(?=,)')
  106. .firstMatch(response.body)
  107. ?.group(0) ??
  108. "xx";
  109. // print(errorcode);
  110. final changepass = RegExp(r'(?<=forcePasswdChange:)(.+)(?=,)')
  111. .firstMatch(response.body)
  112. ?.group(0) ==
  113. "true";
  114. logged = errorcode == "null";
  115. cookieMap = (!logged) ? {} : cookieMap;
  116. // log("api lido 4d login \nuser:$username\npass:$password\nstatuscode${response.statusCode}\nlogged:$logged\nmsg:$message");
  117. log("api lido 4d login errorcode: $errorcode");
  118. //invalide username or password
  119. if (errorcode == "LAS_112" && (user == null) && (pass == null)) {
  120. await Hive.box("profile").delete("lido_user");
  121. await Hive.box("profile").delete("lido_pass");
  122. await Hive.box("profile").put("lido_user_old", username);
  123. await Hive.box("profile").put("lido_pass_old", pass);
  124. }
  125. return {
  126. 'error': logged ? null : message,
  127. 'data': {"logged": logged, "message": message},
  128. 'meta': {
  129. "changepass": changepass,
  130. "user": username,
  131. "pass": password,
  132. "cookie": cookieMap,
  133. "errorcode": errorcode
  134. }
  135. };
  136. } catch (e) {
  137. return {
  138. 'error': e.toString(),
  139. 'data': {"logged": false},
  140. 'meta': {"user": username, "pass": password, "cookie": null}
  141. };
  142. }
  143. }
  144. Future getDoc(String link,
  145. {String? mediaType, bool loginfirst = false}) async {
  146. try {
  147. if (loginfirst) {
  148. final out = await login();
  149. if (!logged) return out;
  150. }
  151. final murl = link.replaceFirst(realurl, url);
  152. var response = await http.get(
  153. Uri.parse(murl)
  154. // .replace(queryParameters: {}),
  155. ,
  156. headers: {"X-lido-businessId": "ViewBP", ...headers});
  157. // log(response.headers.toString());
  158. Map decodedresponse;
  159. print("lidoapi: getdoc: ${response.statusCode} ");
  160. // try {
  161. // decodedresponse = json.decode(response.body) ?? {};
  162. // } catch (e) {
  163. // decodedresponse = {
  164. // "body": response.body,
  165. // "response": response.statusCode
  166. // };
  167. // }
  168. //log("lidoapi: getDoc: responsestatus: ${response.body}");
  169. if (!loginfirst && response.statusCode != 200) {
  170. return await getDoc(link, mediaType: mediaType, loginfirst: true);
  171. }
  172. // String? message = decodedresponse["errorsAndWarnings"]?["warnings"]?[0]
  173. // ?["message"] ??
  174. // decodedresponse["errorsAndWarnings"]?["errors"]?[0]?["message"] ??
  175. // ((response.statusCode == 200) ? null : "ERR");
  176. // log("lidoapi: getDoc: success: ${decodedresponse["content"]}");
  177. return {
  178. 'error': response.statusCode >= 300 ? response.statusCode : null,
  179. 'data': response.body,
  180. 'meta': {"user": username, "pass": password, "cookie": cookieMap}
  181. };
  182. } catch (e) {
  183. return {'error': e.toString(), 'data': {}, 'meta': {}};
  184. }
  185. }
  186. Future list(
  187. {Jiffy? start,
  188. Jiffy? end,
  189. String dep = "",
  190. String des = "",
  191. String al = "",
  192. String fnum = "",
  193. bool loginfirst = false}) async {
  194. final key =
  195. "${start?.format(pattern: "yyyyMMdd_HH_mm") ?? ""} $dep $des $al $fnum";
  196. try {
  197. if (loginfirst) {
  198. final out = await login();
  199. if (!logged) return out;
  200. }
  201. final startdate = (start ?? (Jiffy.now().toUtc().subtract(hours: 12)))
  202. .millisecondsSinceEpoch;
  203. final enddate = (end ??
  204. Jiffy.parseFromMillisecondsSinceEpoch(startdate).add(hours: 48))
  205. .millisecondsSinceEpoch;
  206. var response = await http.get(
  207. Uri.parse(
  208. "$url/lido/lcb/ui/flights?page=0&size=100&startDateTime=1653148128544&endDateTime=1653191328544")
  209. .replace(queryParameters: {
  210. "page": "0",
  211. "size": "1000",
  212. "startDateTime": startdate.toString(),
  213. "endDateTime": enddate.toString(),
  214. ...(al != "" ? {"commAirLine": al} : {}),
  215. ...(fnum != "" ? {"flightNumber": fnum} : {}),
  216. ...(dep != "" ? {"departure": dep} : {}),
  217. ...(des != "" ? {"destination": des} : {}),
  218. }),
  219. headers: {"X-lido-businessId": "SearchFlights", ...headers});
  220. //log(response.headers.toString());
  221. Map decodedresponse;
  222. // print("${response.body}");
  223. try {
  224. decodedresponse = json.decode(response.body) ?? {};
  225. } catch (e) {
  226. decodedresponse = {
  227. "body": response.body,
  228. "response": response.statusCode
  229. };
  230. }
  231. //log("lidoapi: list: responsestatus: ${response.statusCode}");
  232. if (!loginfirst && response.statusCode != 200) {
  233. return await list(
  234. al: al,
  235. fnum: fnum,
  236. dep: dep,
  237. des: des,
  238. start: start,
  239. end: end,
  240. loginfirst: true);
  241. }
  242. String? message = decodedresponse["errorsAndWarnings"]?["warnings"]?[0]
  243. ?["message"] ??
  244. decodedresponse["errorsAndWarnings"]?["errors"]?[0]?["message"] ??
  245. ((response.statusCode == 200) ? null : "ERR");
  246. // log("lidoapi: list: success: ${decodedresponse["content"]}");
  247. Map res = {
  248. 'error': message,
  249. 'data': (message == null) ? decodedresponse["content"] : null,
  250. 'meta': {
  251. "legs": (decodedresponse["totalElements"] ?? 0) > 0
  252. ? decodedresponse["content"].fold([], (t, e) {
  253. t.add(e["leg"]["legidentifier"]);
  254. return t;
  255. })
  256. : [],
  257. "user": username,
  258. "pass": password,
  259. "nb": decodedresponse["totalElements"] ?? 0,
  260. "cookie": cookieMap
  261. }
  262. };
  263. // cache response if success
  264. Hive.box("lido").put(key, json.encode(res));
  265. return res;
  266. } catch (e) {
  267. print("lidoapi: list:");
  268. final res = {
  269. 'error': e.toString(),
  270. 'data': {},
  271. 'meta': {},
  272. 'cache': json.decode(Hive.box("lido").get(key, defaultValue: "{}"))
  273. };
  274. return res;
  275. }
  276. }
  277. Future ofp(
  278. {required String legid,
  279. String? brieflink,
  280. bool loginfirst = false}) async {
  281. try {
  282. if (loginfirst) {
  283. final out = await login();
  284. if (!logged) return out;
  285. }
  286. // brieflink = res["data"]?[0]?["_links"]?["self"]?["href"];
  287. // legid = res["data"]?[0]?["leg"]?["legidentifier"];
  288. brieflink = brieflink ?? "$url/lido/lcb/ui/$legid/briefing";
  289. var response = await http.put(Uri.parse(brieflink),
  290. headers: {
  291. "X-lido-businessId": 'SearchBP',
  292. ...headers,
  293. },
  294. //body: json.encode(({"commercialAirline": al,"flightNumber": fnum,"operationalSuffix": "","date": dateoforigin.toString()
  295. body: json.encode(({
  296. "categories": [
  297. "OFP",
  298. "IWFR",
  299. "ATS",
  300. "DISP",
  301. "NOTAM",
  302. "SIGWXROUTE",
  303. "VERTPROF",
  304. "CREWINFO",
  305. "UAD",
  306. "RAIM",
  307. "VAATCA",
  308. "CDA",
  309. "DISMAP",
  310. "DMS",
  311. "ABD",
  312. "OFPDLK",
  313. "TLR",
  314. // "OFP",
  315. // "NOTAM",
  316. // // "APTDXML",
  317. // "SOFP",
  318. // "CDA",
  319. // "RADAR",
  320. // "OFPDLK",
  321. // // "ATSXML",
  322. // // "REGWXXML",
  323. // "WXSIGWX",
  324. // "SIGWXROUTE",
  325. // "VAATCA",
  326. // // "ASPDXML",
  327. // // "NOTAMXML",
  328. // "OTS",
  329. // "SFC",
  330. // "WINDDATA",
  331. // // "RAIMXML",
  332. // "TLR",
  333. // // "ARPTWXXML",
  334. // "SOFPINFO",
  335. // // "HAZARDADVISORYXML",
  336. // "IWFRXML",
  337. // "OFPNLXML",
  338. // "VERTPROF",
  339. // "SOFPSUM",
  340. // "APLI",
  341. // "RAIM",
  342. // "UAD",
  343. // "DISMAP",
  344. // "WXSATWX"
  345. // "APLI",
  346. // "APTDXML",
  347. // "SOFP",
  348. // "CDA",
  349. // "RADAR",
  350. // "OFPDLK",
  351. // "ATSXML",
  352. // "REGWXXML",
  353. // "WXSIGWX",
  354. // "SIGWXROUTE",
  355. // "VAATCA",
  356. // "ASPDXML",
  357. // "NOTAMXML",
  358. // "OTS",
  359. // "SFC",
  360. // "WINDDATA",
  361. // "RAIMXML",
  362. // "ARPTWXXML",
  363. // "SOFPINFO",
  364. // "IWFRXML",
  365. // "OFPNLXML",
  366. // "VERTPROF",
  367. // "SOFPSUM",
  368. // "RAIM",
  369. // "UAD",
  370. // "DISMAP",
  371. // "WXSATWX"
  372. ],
  373. })));
  374. //log(response.body);
  375. Map decodedresponse;
  376. try {
  377. decodedresponse = (json.decode(response.body) ?? {});
  378. } catch (e) {
  379. decodedresponse = {};
  380. }
  381. String? message = decodedresponse["errorsAndWarnings"]?["warnings"]?[0]
  382. ?["message"] ??
  383. decodedresponse["errorsAndWarnings"]?["errors"]?[0]?["message"] ??
  384. ((response.statusCode == 201) ? null : "ERR");
  385. log("lidoapi: ofp: statuscode: ${response.statusCode} msg: $message");
  386. return {
  387. 'error': (message == null) ? null : message,
  388. 'data': decodedresponse,
  389. 'meta': {
  390. "user": username,
  391. "pass": password,
  392. "cookie": cookieMap,
  393. "legid": legid
  394. }
  395. };
  396. } catch (e) {
  397. return {'error': e.toString(), 'data': {}, 'meta': {}};
  398. }
  399. }
  400. Future ofppdf(
  401. {required String legid, String? fileid, bool loginfirst = false}) async {
  402. try {
  403. if (loginfirst) {
  404. final out = await login();
  405. if (!logged) return out;
  406. }
  407. var response = await http.put(
  408. Uri.parse("$url/lido/lcb/ui/briefing/multi/print?force=true"),
  409. headers: {
  410. "Accept":
  411. "application/vnd.lsy.lido.lcb.v1.hal+json,application/pdf",
  412. //"Accept-Encoding": "gzip, deflate, br",
  413. "Accept-Language": "en",
  414. "Connection": "keep-alive",
  415. "Content-Type": "application/json;charset=UTF-8",
  416. "Cookie": cookie,
  417. //"host": Uri.parse(realurl).host,
  418. "Origin": Uri.parse(realurl).host,
  419. // "sec-ch-ua":'" Not A;Brand";v="99", "Chromium";v="101", "Google Chrome";v="101"',
  420. "User-Agent":
  421. "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36",
  422. "X-lido-applicationId": "lido-lcb",
  423. "X-lido-businessId": "printBP",
  424. "X-lido-clientId": "lido-lcb-web",
  425. "X-lido-csrf": cookieMap["lido_csrf"] ?? "",
  426. "X-lido-customerId": "TAR",
  427. "X-lido-operatingAirline": "TU",
  428. "X-lido-timeStamp": "2022-05-25T06:29:56.659Z",
  429. "X-lido-traceId": "3cbab7e0-56ca-49ec-b158-8899c0d3bbbb",
  430. },
  431. body: json.encode({
  432. "legIdentifiers": [legid],
  433. "categories": [
  434. "OFP",
  435. "ATS",
  436. "CREWINFO",
  437. "DISP",
  438. "IWFR",
  439. "NOTAM",
  440. "UAD",
  441. "WXSIGWX",
  442. "VERTPROF",
  443. "RAIM",
  444. "DMS",
  445. "WXNOTAM",
  446. "ABD",
  447. "SIGWXROUTE",
  448. //"WXSATWX"
  449. ],
  450. "merge": false,
  451. "quickprint": false,
  452. "weatherDataRequired": false,
  453. }));
  454. if (!loginfirst && response.statusCode > 201) {
  455. return ofppdf(legid: legid, fileid: fileid, loginfirst: true);
  456. }
  457. // log("lidoapi: pdfofp2: status: ${response.statusCode} fileid: $fileid ");
  458. //final id ="${DateFormat("yyyyMMdd").format(DateTime.fromMillisecondsSinceEpoch(dateoforigin))}_${dep}_${des}_$al$fnum";
  459. final ok = response.headers.containsKey("content-disposition");
  460. // log("lidoapi: pdfofp2: status: ${response.headers} ");
  461. final xfileid = fileid ?? PathTo().lidoFile("$legid.pdf");
  462. if (ok) {
  463. await downloadPdf(response, xfileid);
  464. }
  465. final res = {
  466. 'error': (ok) ? null : "no PDF downloaded",
  467. 'data': (ok)
  468. ? {
  469. "downloaded": true,
  470. "fileid": xfileid,
  471. }
  472. : {
  473. "downloaded": false,
  474. "fileid": null,
  475. },
  476. 'meta': {"user": username, "pass": password, "cookie": cookieMap}
  477. };
  478. return res;
  479. } catch (e) {
  480. final res = {
  481. 'error': e.toString(),
  482. 'data': {
  483. {
  484. "downloaded": false,
  485. "fileid": null,
  486. }
  487. },
  488. 'meta': {}
  489. };
  490. final xfileid = fileid ?? PathTo().lidoFile("$legid.pdf");
  491. if (File(xfileid).existsSync()) {
  492. res["cache"] = xfileid;
  493. }
  494. return res;
  495. }
  496. }
  497. Map<String, String> _getcookies(String cookiesData,
  498. {List<String> vars = const [
  499. "lido_auth",
  500. "lido_csrf",
  501. "JSESSIONID",
  502. "SERVERID"
  503. ]}) {
  504. Map<String, String> cookies = {};
  505. for (var title in vars) {
  506. if (cookiesData.contains(title)) {
  507. List at =
  508. (RegExp(r'(' + title + ')(.*?)[^;]+').stringMatch(cookiesData) ??
  509. "")
  510. .split('=');
  511. cookies[title] = at[1];
  512. }
  513. }
  514. return cookies;
  515. }
  516. Future<void> downloadPdf(http.Response response, String fileid) async {
  517. try {
  518. if (response.statusCode == 201) {
  519. final pdfBytes = response.bodyBytes;
  520. final file = File(fileid);
  521. await file.writeAsBytes(pdfBytes);
  522. print('PDF downloaded and saved to $fileid');
  523. } else {
  524. print('Error downloading PDF: ${response.statusCode}');
  525. }
  526. } catch (e) {
  527. print('Error downloading file: $e');
  528. }
  529. }
  530. }