make initial push ssh keys working
This commit is contained in:
parent
e6336e057a
commit
6357c4e2ae
@ -1,4 +1,5 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:dartssh2/dartssh2.dart';
|
import 'package:dartssh2/dartssh2.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -9,11 +10,91 @@ import 'package:flutter/services.dart';
|
|||||||
|
|
||||||
// secret storage
|
// secret storage
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
|
import 'package:oauth2/oauth2.dart' as oauth2;
|
||||||
|
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<oauth2.Client> getOAuth2Client() async {
|
||||||
|
// This is a placeholder for OAuth2 client initialization.
|
||||||
|
// Replace with your actual OAuth2 client setup.
|
||||||
|
|
||||||
|
final authorizationEndpoint = Uri.parse(
|
||||||
|
'https://auth.leinelab.org/application/o/authorize/',
|
||||||
|
);
|
||||||
|
|
||||||
|
final tokenEndpoint = Uri.parse(
|
||||||
|
'https://auth.leinelab.org/application/o/token/',
|
||||||
|
);
|
||||||
|
|
||||||
|
final identifier = 'UwSMm8gTwBTUURSaxp5uPpuwX1OkGO4FRHeO9v3i';
|
||||||
|
final secret = null; // = 'my client secret';
|
||||||
|
|
||||||
|
final redirectUrl = Uri.parse('http://localhost:30165/');
|
||||||
|
|
||||||
|
final credentialsFile = File('~/.myapp/credentials.json');
|
||||||
|
|
||||||
|
//....
|
||||||
|
|
||||||
|
var exists = await credentialsFile.exists();
|
||||||
|
|
||||||
|
if (exists) {
|
||||||
|
var credentials = oauth2.Credentials.fromJson(
|
||||||
|
await credentialsFile.readAsString(),
|
||||||
|
);
|
||||||
|
return oauth2.Client(credentials, identifier: identifier, secret: secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
var grant = oauth2.AuthorizationCodeGrant(
|
||||||
|
identifier,
|
||||||
|
authorizationEndpoint,
|
||||||
|
tokenEndpoint,
|
||||||
|
secret: secret,
|
||||||
|
);
|
||||||
|
|
||||||
|
var authorizationUrl = grant.getAuthorizationUrl(
|
||||||
|
redirectUrl,
|
||||||
|
scopes: ["profile", "email", "goauthentik.io/api", "openid"],
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO: clicking the button twice might try to bind the server twice
|
||||||
|
var server = await HttpServer.bind("127.0.0.1", 30165);
|
||||||
|
|
||||||
|
await launchUrl(authorizationUrl);
|
||||||
|
|
||||||
|
var queryParameters;
|
||||||
|
|
||||||
|
await server.forEach((HttpRequest request) {
|
||||||
|
request.response.write(
|
||||||
|
'Success! You can close this window now and go back to the app.',
|
||||||
|
);
|
||||||
|
queryParameters = request.uri.queryParameters;
|
||||||
|
request.response.close();
|
||||||
|
server.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
return await grant.handleAuthorizationResponse(queryParameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
void makeAlert(BuildContext context, String title, String message) {
|
||||||
|
showDialog<String>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) => AlertDialog(
|
||||||
|
title: Text(title),
|
||||||
|
content: Text(message),
|
||||||
|
actions: <Widget>[
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(context, 'OK'),
|
||||||
|
child: const Text('OK'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Future<OpenSSHEd25519KeyPair> generateKeyPair() async {
|
Future<OpenSSHEd25519KeyPair> generateKeyPair() async {
|
||||||
final algorithm = Ed25519();
|
final algorithm = Ed25519();
|
||||||
|
|
||||||
@ -66,6 +147,122 @@ class _MyHomePageState extends State<MyHomePage> {
|
|||||||
OpenSSHEd25519KeyPair? keyPair;
|
OpenSSHEd25519KeyPair? keyPair;
|
||||||
String _output = '';
|
String _output = '';
|
||||||
String key = '';
|
String key = '';
|
||||||
|
|
||||||
|
Future<void> doOAuth() async {
|
||||||
|
final client = await getOAuth2Client();
|
||||||
|
|
||||||
|
// TODO: Handle errors better
|
||||||
|
try {
|
||||||
|
final jsonMe = await client.read(
|
||||||
|
Uri.parse('https://auth.leinelab.org/api/v3/core/users/me/'),
|
||||||
|
);
|
||||||
|
|
||||||
|
// final me = jsonDecode(jsonMe);
|
||||||
|
|
||||||
|
// final user = me['user'];
|
||||||
|
// final transformed = {
|
||||||
|
// "username": user['username'],
|
||||||
|
// "name": user['name'],
|
||||||
|
// "email": user['email'],
|
||||||
|
// "attributes.settings.locale": user['settings']['locale'],
|
||||||
|
// "attributes.sshPublicKeys":
|
||||||
|
// "foooooooobar!", // fix oder aus anderer Quelle
|
||||||
|
// "component": "ak-stage-prompt",
|
||||||
|
// };
|
||||||
|
|
||||||
|
// final push = jsonEncode(transformed);
|
||||||
|
|
||||||
|
final push =
|
||||||
|
'{"username":"lemoer","name":"Leonardo Mörlein","email":"me@irrelefant.net","attributes.settings.locale":"","attributes.sshPublicKeys":"BLA!","component":"ak-stage-prompt"}';
|
||||||
|
|
||||||
|
print(push);
|
||||||
|
|
||||||
|
final response0 = await client.get(
|
||||||
|
Uri.parse(
|
||||||
|
'https://auth.leinelab.org/api/v3/flows/instances/default-user-settings-flow/execute/',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
var sessionCookieHeader = response0.headers['set-cookie'];
|
||||||
|
if (sessionCookieHeader == null) {
|
||||||
|
throw Exception('No session cookie found in response headers.');
|
||||||
|
}
|
||||||
|
|
||||||
|
String? sessionCookie;
|
||||||
|
int index = sessionCookieHeader.indexOf(';');
|
||||||
|
sessionCookie = (index == -1)
|
||||||
|
? sessionCookieHeader
|
||||||
|
: sessionCookieHeader.substring(0, index);
|
||||||
|
|
||||||
|
final responsea = await client.get(
|
||||||
|
Uri.parse(
|
||||||
|
'https://auth.leinelab.org/api/v3/flows/executor/default-user-settings-flow/?query=',
|
||||||
|
),
|
||||||
|
headers: {'Cookie': sessionCookie},
|
||||||
|
);
|
||||||
|
|
||||||
|
print("Response A status code: ${responsea.statusCode}");
|
||||||
|
print("Response body:");
|
||||||
|
print(responsea.body);
|
||||||
|
|
||||||
|
print("Session cookie: $sessionCookie");
|
||||||
|
|
||||||
|
final response = await client.post(
|
||||||
|
Uri.parse(
|
||||||
|
'https://auth.leinelab.org/api/v3/flows/executor/default-user-settings-flow/?query=',
|
||||||
|
),
|
||||||
|
body: push,
|
||||||
|
headers: {'Content-Type': 'application/json', 'Cookie': sessionCookie},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode != 302) {
|
||||||
|
throw Exception(
|
||||||
|
"Expected a redirect (302) response, but got ${response.statusCode}",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (response.statusCode == 200) {
|
||||||
|
// print("User data updated successfully.");
|
||||||
|
// print("Response body:");
|
||||||
|
// print(response.body);
|
||||||
|
// response.headers.toString().split('\n').forEach(print);
|
||||||
|
// } else {
|
||||||
|
// print("Error updating user data: ${response.statusCode}");
|
||||||
|
// print("Response body:");
|
||||||
|
// print(response.body);
|
||||||
|
// print(response.headers.toString());
|
||||||
|
// }
|
||||||
|
|
||||||
|
final newLocation = response.headers['location'];
|
||||||
|
if (newLocation != null) {
|
||||||
|
print("Redirecting to: $newLocation");
|
||||||
|
await launchUrl(Uri.parse(newLocation));
|
||||||
|
} else {
|
||||||
|
throw Exception("No redirect location found in response headers.");
|
||||||
|
}
|
||||||
|
|
||||||
|
final responseFinal = await client.get(
|
||||||
|
Uri.parse('https://auth.leinelab.org/' + newLocation),
|
||||||
|
headers: {'Cookie': sessionCookie},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (responseFinal.statusCode == 200) {
|
||||||
|
print("User data updated successfully.");
|
||||||
|
print("responseFinal body:");
|
||||||
|
print(responseFinal.body);
|
||||||
|
responseFinal.headers.toString().split('\n').forEach(print);
|
||||||
|
} else {
|
||||||
|
print("Error updating user data: ${responseFinal.statusCode}");
|
||||||
|
print("responseFinal body:");
|
||||||
|
print(responseFinal.body);
|
||||||
|
print(responseFinal.headers.toString());
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print(e.toString());
|
||||||
|
}
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> doSSH() async {
|
Future<void> doSSH() async {
|
||||||
SSHSocket? socket;
|
SSHSocket? socket;
|
||||||
|
|
||||||
@ -151,6 +348,7 @@ class _MyHomePageState extends State<MyHomePage> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
|
TextButton(onPressed: doOAuth, child: Text("Oauth2 Login")),
|
||||||
Text('Current output:'),
|
Text('Current output:'),
|
||||||
Text(outputText, style: Theme.of(context).textTheme.headlineMedium),
|
Text(outputText, style: Theme.of(context).textTheme.headlineMedium),
|
||||||
],
|
],
|
||||||
|
@ -7,9 +7,13 @@
|
|||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
|
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
|
||||||
|
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||||
|
|
||||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||||
g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
|
g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
|
||||||
flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar);
|
flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar);
|
||||||
|
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
|
||||||
|
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
|
||||||
|
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
flutter_secure_storage_linux
|
flutter_secure_storage_linux
|
||||||
|
url_launcher_linux
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
@ -7,8 +7,12 @@ import Foundation
|
|||||||
|
|
||||||
import flutter_secure_storage_macos
|
import flutter_secure_storage_macos
|
||||||
import path_provider_foundation
|
import path_provider_foundation
|
||||||
|
import url_launcher_macos
|
||||||
|
import webview_flutter_wkwebview
|
||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
||||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||||
|
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||||
|
WebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "WebViewFlutterPlugin"))
|
||||||
}
|
}
|
||||||
|
128
app/pubspec.lock
128
app/pubspec.lock
@ -176,6 +176,22 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
http:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: http
|
||||||
|
sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.4.0"
|
||||||
|
http_parser:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: http_parser
|
||||||
|
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.1.2"
|
||||||
js:
|
js:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -240,6 +256,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.16.0"
|
version: "1.16.0"
|
||||||
|
oauth2:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: oauth2
|
||||||
|
sha256: c84470642cbb2bec450ccab2f8520c079cd1ca546a76ffd5c40589e07f4e8bf4
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.3"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -389,6 +413,70 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.4.0"
|
version: "1.4.0"
|
||||||
|
url_launcher:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: url_launcher
|
||||||
|
sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.3.1"
|
||||||
|
url_launcher_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_android
|
||||||
|
sha256: "8582d7f6fe14d2652b4c45c9b6c14c0b678c2af2d083a11b604caeba51930d79"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.3.16"
|
||||||
|
url_launcher_ios:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_ios
|
||||||
|
sha256: "7f2022359d4c099eea7df3fdf739f7d3d3b9faf3166fb1dd390775176e0b76cb"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.3.3"
|
||||||
|
url_launcher_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_linux
|
||||||
|
sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.2.1"
|
||||||
|
url_launcher_macos:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_macos
|
||||||
|
sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.2.2"
|
||||||
|
url_launcher_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_platform_interface
|
||||||
|
sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.2"
|
||||||
|
url_launcher_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_web
|
||||||
|
sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.1"
|
||||||
|
url_launcher_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_windows
|
||||||
|
sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.4"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -405,6 +493,46 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "15.0.0"
|
version: "15.0.0"
|
||||||
|
web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web
|
||||||
|
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.1"
|
||||||
|
webview_flutter:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: webview_flutter
|
||||||
|
sha256: c3e4fe614b1c814950ad07186007eff2f2e5dd2935eba7b9a9a1af8e5885f1ba
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.13.0"
|
||||||
|
webview_flutter_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: webview_flutter_android
|
||||||
|
sha256: f6e6afef6e234801da77170f7a1847ded8450778caf2fe13979d140484be3678
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.7.0"
|
||||||
|
webview_flutter_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: webview_flutter_platform_interface
|
||||||
|
sha256: f0dc2dc3a2b1e3a6abdd6801b9355ebfeb3b8f6cde6b9dc7c9235909c4a1f147
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.13.1"
|
||||||
|
webview_flutter_wkwebview:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: webview_flutter_wkwebview
|
||||||
|
sha256: a3d461fe3467014e05f3ac4962e5fdde2a4bf44c561cb53e9ae5c586600fdbc3
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.22.0"
|
||||||
win32:
|
win32:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -37,6 +37,9 @@ dependencies:
|
|||||||
dartssh2: ^2.12.0
|
dartssh2: ^2.12.0
|
||||||
cryptography: ^2.7.0
|
cryptography: ^2.7.0
|
||||||
flutter_secure_storage: ^9.2.4
|
flutter_secure_storage: ^9.2.4
|
||||||
|
oauth2: ^2.0.3
|
||||||
|
webview_flutter: ^4.13.0
|
||||||
|
url_launcher: ^6.3.1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
@ -7,8 +7,11 @@
|
|||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
|
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
|
||||||
|
#include <url_launcher_windows/url_launcher_windows.h>
|
||||||
|
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
|
FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
|
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
|
||||||
|
UrlLauncherWindowsRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
flutter_secure_storage_windows
|
flutter_secure_storage_windows
|
||||||
|
url_launcher_windows
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
Loading…
x
Reference in New Issue
Block a user