import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; import 'package:loris/business_logic/account/account.dart'; import 'package:url_launcher/url_launcher.dart'; import '../../global.dart' as global; import 'package:shelf/shelf.dart'; import 'package:shelf/shelf_io.dart' as shelf_io; class App { late String clientSecret; late String clientId; late String id; late String name; late String website; late String redirectUri; App( {required this.clientSecret, required this.clientId, required this.id, required this.name, required this.website, required this.redirectUri}); factory App.fromJson(Map json) { final app = App( id: json["id"].toString(), name: json["name"].toString(), website: json["website"].toString(), redirectUri: json["redirect_uri"].toString(), clientId: json["client_id"].toString(), clientSecret: json["client_secret"].toString()); _app = app; return app; } } String _authCode = ""; String _url = ""; App? _app; App? getApp() { return _app; } Response readAuthcode(Request request) { Map params = request.url.queryParameters; if (params.containsKey("code") && params["code"] != null) { String code = params["code"].toString(); _authCode = code; } return Response( 308, headers: {"Content-Type": "text/html; charset=UTF-8"}, body: "", ); } // returns status code Future handleFullOauth(String url) async { // tusky compatibility if (global.bad.contains(url)) { launchUrl( Uri(scheme: "http", path: "www.facebook.com/login.php/"), ); launchUrl( Uri(scheme: "https", path: "youtu.be/dQw4w9WgXcQ"), ); // appropriate error code return 42069; } _url = url; try { http.Response response = await doOauthFlow(); if (response.statusCode != 200) { return response.statusCode; } if (!kIsWeb) { // if this is not a web app we can simply start a server // and listen for a code there _authCode = ""; var handler = const Pipeline().addHandler(readAuthcode); var server = await shelf_io.serve(handler, 'localhost', 1312); await pollCode(); server.close(); String token = await getToken(_authCode, _app!.clientId, _app!.clientSecret, _url); await saveIdentity( token, url, _app!.clientId, _app!.clientSecret, _authCode, ); return 200; } else { return 6969696969696969; } } catch (e) { return 400; } } Future saveIdentity( String token, String baseurl, String clientId, String clientSecret, String authCode, ) async { Map headers = {"Authorization": "Bearer $token"}; headers.addAll(global.defaultHeaders); final response = await http.get( Uri.https(baseurl, "/api/v1/accounts/verify_credentials"), headers: headers, ); final instanceResponse = await http.get( Uri.https(baseurl, "/api/v1/instance"), headers: headers, ); if (response.statusCode == 200) { final account = AccountModel.fromJson(jsonDecode(response.body)); await global.settings!.addNewIdentity("${account.acct}@$baseurl"); await global.settings!.saveActiveIdentity("${account.acct}@$baseurl"); await global.settings!.identities["${account.acct}@$baseurl"]! .saveApp(clientId, clientSecret); await global.settings!.identities["${account.acct}@$baseurl"]! .saveAuthCode(authCode); await global.settings!.identities["${account.acct}@$baseurl"]! .saveInstanceUrl(baseurl); await global.settings!.identities["${account.acct}@$baseurl"]! .saveToken(token); if (instanceResponse.statusCode == 200) { await global.settings!.identities["${account.acct}@$baseurl"]! .saveWebsocketUrl( jsonDecode(instanceResponse.body)["urls"]["streaming_api"]); } } return true; } Future pollCode() async { String code = ""; while (code == "") { await Future.delayed(const Duration(seconds: 3)); code = _authCode; } return code; } Future doOauthFlow() async { String url = _url; try { http.Response response = await registerApp(url); openBrowserForAuthCode(url, _app!); return response; } catch (e) { return http.Response(jsonEncode({}), 404); } } Future registerApp(String baseurl) async { //String url = baseurl Uri."api/v1/apps"; Uri url = Uri.https(baseurl, "/api/v1/apps"); final Map params = { 'client_name': global.name, 'redirect_uris': kIsWeb ? "${Uri.base.origin}/login/redirect.html" : "http://localhost:1312", 'scopes': "read write follow push", 'website': global.website, }; final response = await http.post( url, headers: global.defaultHeaders, body: jsonEncode(params), ); print(response.body); _app = App.fromJson(jsonDecode(response.body)); return response; } Uri getAuthUrl(String baseurl, App app) { return Uri( scheme: "https", path: "$baseurl/oauth/authorize", // ignore: prefer_interpolation_to_compose_strings query: "client_id=" + app.clientId + "&scope=read+write+follow+push" + "&redirect_uri=${kIsWeb ? "${Uri.base.origin}/login/redirect.html" : "http://localhost:1312"}" + "&response_type=code"); } void openBrowserForAuthCode(String baseurl, App app) { Uri url = Uri( scheme: "https", path: "$baseurl/oauth/authorize", // ignore: prefer_interpolation_to_compose_strings query: "client_id=" + app.clientId + "&scope=read+write+follow+push" + "&redirect_uri=${kIsWeb ? "${Uri.base.origin}/login/redirect.html" : "http://localhost:1312"}" + "&response_type=code"); launchUrl( mode: LaunchMode.inAppWebView, url, webOnlyWindowName: "loris", webViewConfiguration: const WebViewConfiguration(), ); } Future getToken( String authCode, String appId, String clientSecret, String baseurl, ) async { Uri url = Uri.https(baseurl, "/oauth/token"); final args = jsonEncode({ 'grant_type': "authorization_code", 'client_id': appId, 'client_secret': clientSecret, 'redirect_uri': kIsWeb ? "${Uri.base.origin}/login/redirect.html" : "http://localhost:1312", 'scope': "read write follow push", 'code': authCode, }); final response = await http.post( url, headers: global.defaultHeaders, body: args, ); print(args); print(response.body); if (response.statusCode == 200) { final dec = jsonDecode(response.body); return dec["access_token"]!; } return ""; }