mirror of
https://github.com/Yubico/yubioath-flutter.git
synced 2024-12-23 18:22:39 +03:00
Merge branch 'main' into fix/android-nfc
This commit is contained in:
commit
0b4b111acd
1
.github/workflows/linux.yml
vendored
1
.github/workflows/linux.yml
vendored
@ -56,6 +56,7 @@ jobs:
|
||||
mkdir deploy
|
||||
mv resources/com.yubico.authenticator.desktop build/linux/x64/release/bundle
|
||||
mv resources/icons/com.yubico.yubioath.png build/linux/x64/release/bundle
|
||||
mv resources/README.adoc build/linux/x64/release/bundle
|
||||
tar -czf deploy/yubioath-desktop-${REF}-linux-${{matrix.os}}.tar.gz -C build/linux/x64/release/bundle .
|
||||
|
||||
- name: Upload artifact
|
||||
|
@ -10,8 +10,8 @@ echo Generating license files...
|
||||
rmdir /s /q ..\build\windows\helper-license-venv
|
||||
poetry build
|
||||
poetry run python -m venv ..\build\windows\helper-license-venv
|
||||
..\build\windows\helper-license-venv\Scripts\pip install --upgrade pip wheel
|
||||
..\build\windows\helper-license-venv\Scripts\pip install dist\authenticator_helper-0.1.0-py3-none-any.whl pip-licenses
|
||||
..\build\windows\helper-license-venv\Scripts\python -m pip install --upgrade pip wheel
|
||||
..\build\windows\helper-license-venv\Scripts\python -m pip install dist\authenticator_helper-0.1.0-py3-none-any.whl pip-licenses
|
||||
..\build\windows\helper-license-venv\Scripts\pip-licenses --format=json --no-license-path --with-license-file --ignore-packages authenticator-helper --output-file ..\assets\licenses\helper.json
|
||||
|
||||
cd ..
|
||||
|
@ -300,7 +300,7 @@ class UsbDeviceNode(AbstractDeviceNode):
|
||||
def ccid(self):
|
||||
try:
|
||||
return self._create_connection(SmartCardConnection)
|
||||
except (ValueError, SmartcardException) as e:
|
||||
except (ValueError, SmartcardException, EstablishContextException) as e:
|
||||
logger.warning("Error opening connection", exc_info=True)
|
||||
raise ConnectionException("ccid", e)
|
||||
|
||||
@ -335,7 +335,7 @@ class ReaderDeviceNode(AbstractDeviceNode):
|
||||
connection = self._device.open_connection(SmartCardConnection)
|
||||
info = read_info(connection)
|
||||
return ConnectionNode(self._device, connection, info)
|
||||
except (ValueError, SmartcardException) as e:
|
||||
except (ValueError, SmartcardException, EstablishContextException) as e:
|
||||
logger.warning("Error opening connection", exc_info=True)
|
||||
raise ConnectionException("ccid", e)
|
||||
|
||||
@ -346,7 +346,7 @@ class ReaderDeviceNode(AbstractDeviceNode):
|
||||
info = read_info(conn)
|
||||
connection = self._device.open_connection(FidoConnection)
|
||||
return ConnectionNode(self._device, connection, info)
|
||||
except (ValueError, SmartcardException) as e:
|
||||
except (ValueError, SmartcardException, EstablishContextException) as e:
|
||||
logger.warning("Error opening connection", exc_info=True)
|
||||
raise ConnectionException("fido", e)
|
||||
|
||||
|
@ -278,7 +278,13 @@ class CredentialsNode(RpcNode):
|
||||
|
||||
if data.get_id() in self._creds:
|
||||
raise ValueError("Credential already exists")
|
||||
credential = self.session.put_credential(data, require_touch)
|
||||
try:
|
||||
credential = self.session.put_credential(data, require_touch)
|
||||
except ApduError as e:
|
||||
if e.sw == SW.INCORRECT_PARAMETERS:
|
||||
raise ValueError("Issuer/name too long")
|
||||
raise e
|
||||
|
||||
self._creds[credential.id] = credential
|
||||
return asdict(credential)
|
||||
|
||||
|
@ -2,20 +2,45 @@ import mss
|
||||
import zxingcpp
|
||||
import base64
|
||||
import io
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import tempfile
|
||||
from mss.exception import ScreenShotError
|
||||
from PIL import Image
|
||||
|
||||
|
||||
def _capture_screen():
|
||||
try:
|
||||
with mss.mss() as sct:
|
||||
monitor = sct.monitors[0] # 0 is the special "all monitors" value.
|
||||
sct_img = sct.grab(monitor) # mss format
|
||||
return Image.frombytes("RGB", sct_img.size, sct_img.bgra, "raw", "BGRX")
|
||||
except ScreenShotError:
|
||||
# One common error is that mss doesn't work with Wayland
|
||||
if sys.platform.startswith("linux"):
|
||||
# Try gnome-screenshot fallback
|
||||
fd, fname = tempfile.mkstemp(suffix=".png")
|
||||
try:
|
||||
rc = subprocess.call(["gnome-screenshot", "-f", fname]) # nosec
|
||||
if rc == 0:
|
||||
return Image.open(fname)
|
||||
except FileNotFoundError:
|
||||
pass # Fall through to ValueError
|
||||
finally:
|
||||
os.unlink(fname)
|
||||
raise ValueError("Unable to capture screenshot")
|
||||
|
||||
|
||||
def scan_qr(image_data=None):
|
||||
if image_data:
|
||||
msg = base64.b64decode(image_data)
|
||||
buf = io.BytesIO(msg)
|
||||
img = Image.open(buf)
|
||||
else:
|
||||
with mss.mss() as sct:
|
||||
monitor = sct.monitors[0] # 0 is the special "all monitors" value.
|
||||
sct_img = sct.grab(monitor) # mss format
|
||||
img = Image.frombytes("RGB", sct_img.size, sct_img.bgra, "raw", "BGRX")
|
||||
img = _capture_screen()
|
||||
|
||||
result = zxingcpp.read_barcode(img)
|
||||
if result.valid:
|
||||
return result.text
|
||||
raise ValueError("Unable to read QR code")
|
||||
return None
|
||||
|
@ -31,11 +31,11 @@ VSVersionInfo(
|
||||
'040904b0',
|
||||
[StringStruct('CompanyName', 'Yubico'),
|
||||
StringStruct('FileDescription', 'Yubico Authenticator Helper'),
|
||||
StringStruct('FileVersion', '6.0.0-alpha.3'),
|
||||
StringStruct('FileVersion', '6.0.0-dev.0'),
|
||||
StringStruct('LegalCopyright', 'Copyright (c) 2022 Yubico AB'),
|
||||
StringStruct('OriginalFilename', 'authenticator-helper.exe'),
|
||||
StringStruct('ProductName', 'Yubico Authenticator'),
|
||||
StringStruct('ProductVersion', '6.0.0-alpha.3')])
|
||||
StringStruct('ProductVersion', '6.0.0-dev.0')])
|
||||
]),
|
||||
VarFileInfo([VarStruct('Translation', [1033, 1200])])
|
||||
]
|
||||
|
@ -106,7 +106,11 @@ class CurrentAppNotifier extends StateNotifier<Application> {
|
||||
}
|
||||
|
||||
abstract class QrScanner {
|
||||
Future<String> scanQr([String? imageData]);
|
||||
/// Scans (or searches the given image) for a QR code, and decodes it.
|
||||
///
|
||||
/// The contained data is returned as a String, or null, if no QR code is
|
||||
/// found.
|
||||
Future<String?> scanQr([String? imageData]);
|
||||
}
|
||||
|
||||
final qrScannerProvider = Provider<QrScanner?>(
|
||||
|
@ -32,7 +32,7 @@ class AppFailurePage extends ConsumerWidget {
|
||||
if (Platform.isMacOS) {
|
||||
message = 'Try to remove and re-insert your YubiKey.';
|
||||
} else if (Platform.isLinux) {
|
||||
message = 'Make sure pcscd is running.';
|
||||
message = 'Make sure pcscd is installed and running.';
|
||||
} else {
|
||||
message = 'Make sure your smart card service is functioning.';
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ class RpcQrScanner implements QrScanner {
|
||||
RpcQrScanner(this._rpc);
|
||||
|
||||
@override
|
||||
Future<String> scanQr([String? imageData]) async {
|
||||
Future<String?> scanQr([String? imageData]) async {
|
||||
final result = await _rpc.command('qr', [], params: {'image': imageData});
|
||||
return result['result'];
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import 'package:logging/logging.dart';
|
||||
import 'package:yubico_authenticator/app/logging.dart';
|
||||
|
||||
import '../../app/message.dart';
|
||||
import '../../desktop/models.dart';
|
||||
import '../../widgets/responsive_dialog.dart';
|
||||
import '../state.dart';
|
||||
import '../../fido/models.dart';
|
||||
@ -92,7 +93,18 @@ class _AddFingerprintDialogState extends ConsumerState<AddFingerprintDialog>
|
||||
}, onError: (error, stacktrace) {
|
||||
_log.error('Error adding fingerprint', error, stacktrace);
|
||||
Navigator.of(context).pop();
|
||||
showMessage(context, 'Error adding fingerprint');
|
||||
final String errorMessage;
|
||||
// TODO: Make this cleaner than importing desktop specific RpcError.
|
||||
if (error is RpcError) {
|
||||
errorMessage = error.message;
|
||||
} else {
|
||||
errorMessage = error.toString();
|
||||
}
|
||||
showMessage(
|
||||
context,
|
||||
'Error adding fingerprint: $errorMessage',
|
||||
duration: const Duration(seconds: 4),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@ -108,12 +120,27 @@ class _AddFingerprintDialogState extends ConsumerState<AddFingerprintDialog>
|
||||
}
|
||||
|
||||
void _submit() async {
|
||||
await ref
|
||||
.read(fingerprintProvider(widget.devicePath).notifier)
|
||||
.renameFingerprint(_fingerprint!, _label);
|
||||
if (!mounted) return;
|
||||
Navigator.of(context).pop(true);
|
||||
showMessage(context, 'Fingerprint added');
|
||||
try {
|
||||
await ref
|
||||
.read(fingerprintProvider(widget.devicePath).notifier)
|
||||
.renameFingerprint(_fingerprint!, _label);
|
||||
if (!mounted) return;
|
||||
Navigator.of(context).pop(true);
|
||||
showMessage(context, 'Fingerprint added');
|
||||
} catch (e) {
|
||||
final String errorMessage;
|
||||
// TODO: Make this cleaner than importing desktop specific RpcError.
|
||||
if (e is RpcError) {
|
||||
errorMessage = e.message;
|
||||
} else {
|
||||
errorMessage = e.toString();
|
||||
}
|
||||
showMessage(
|
||||
context,
|
||||
'Error setting name: $errorMessage',
|
||||
duration: const Duration(seconds: 4),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -151,7 +151,7 @@ class _PinEntryFormState extends ConsumerState<_PinEntryForm> {
|
||||
return 'PIN temporarily blocked, remove and reinsert your YubiKey.';
|
||||
}
|
||||
if (_retries != null) {
|
||||
return 'Wrong PIN. $_retries attempts remaining.';
|
||||
return 'Wrong PIN. $_retries attempt(s) remaining.';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -1,12 +1,17 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
import '../../app/logging.dart';
|
||||
import '../../app/message.dart';
|
||||
import '../../app/models.dart';
|
||||
import '../../desktop/models.dart';
|
||||
import '../../widgets/responsive_dialog.dart';
|
||||
import '../models.dart';
|
||||
import '../state.dart';
|
||||
|
||||
final _log = Logger('fido.views.pin_dialog');
|
||||
|
||||
class FidoPinDialog extends ConsumerStatefulWidget {
|
||||
final DevicePath devicePath;
|
||||
final FidoState state;
|
||||
@ -68,6 +73,7 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
],
|
||||
Text(
|
||||
'Enter your new PIN. A PIN must be at least $minPinLength characters long and may contain letters, numbers and special characters.'),
|
||||
// TODO: Set max characters based on UTF-8 bytes
|
||||
TextFormField(
|
||||
initialValue: _newPin,
|
||||
autofocus: !hasPin,
|
||||
@ -128,23 +134,39 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
});
|
||||
return;
|
||||
}
|
||||
final result = await ref
|
||||
.read(fidoStateProvider(widget.devicePath).notifier)
|
||||
.setPin(_newPin, oldPin: oldPin);
|
||||
result.when(success: () {
|
||||
Navigator.of(context).pop(true);
|
||||
showMessage(context, 'PIN set');
|
||||
}, failed: (retries, authBlocked) {
|
||||
setState(() {
|
||||
if (authBlocked) {
|
||||
_currentPinError =
|
||||
'PIN has been blocked until the YubiKey is removed and reinserted';
|
||||
_currentIsWrong = true;
|
||||
} else {
|
||||
_currentPinError = 'Wrong PIN ($retries tries remaining)';
|
||||
_currentIsWrong = true;
|
||||
}
|
||||
try {
|
||||
final result = await ref
|
||||
.read(fidoStateProvider(widget.devicePath).notifier)
|
||||
.setPin(_newPin, oldPin: oldPin);
|
||||
result.when(success: () {
|
||||
Navigator.of(context).pop(true);
|
||||
showMessage(context, 'PIN set');
|
||||
}, failed: (retries, authBlocked) {
|
||||
setState(() {
|
||||
if (authBlocked) {
|
||||
_currentPinError =
|
||||
'PIN has been blocked until the YubiKey is removed and reinserted';
|
||||
_currentIsWrong = true;
|
||||
} else {
|
||||
_currentPinError = 'Wrong PIN ($retries tries remaining)';
|
||||
_currentIsWrong = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
_log.error('Failed to set PIN', e);
|
||||
final String errorMessage;
|
||||
// TODO: Make this cleaner than importing desktop specific RpcError.
|
||||
if (e is RpcError) {
|
||||
errorMessage = e.message;
|
||||
} else {
|
||||
errorMessage = e.toString();
|
||||
}
|
||||
showMessage(
|
||||
context,
|
||||
'Failed to set PIN: $errorMessage',
|
||||
duration: const Duration(seconds: 4),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../../app/message.dart';
|
||||
import '../../desktop/models.dart';
|
||||
import '../../widgets/responsive_dialog.dart';
|
||||
import '../models.dart';
|
||||
import '../state.dart';
|
||||
@ -28,12 +29,27 @@ class _RenameAccountDialogState extends ConsumerState<RenameFingerprintDialog> {
|
||||
}
|
||||
|
||||
_submit() async {
|
||||
final renamed = await ref
|
||||
.read(fingerprintProvider(widget.devicePath).notifier)
|
||||
.renameFingerprint(widget.fingerprint, _label);
|
||||
if (!mounted) return;
|
||||
Navigator.of(context).pop(renamed);
|
||||
showMessage(context, 'Fingerprint renamed');
|
||||
try {
|
||||
final renamed = await ref
|
||||
.read(fingerprintProvider(widget.devicePath).notifier)
|
||||
.renameFingerprint(widget.fingerprint, _label);
|
||||
if (!mounted) return;
|
||||
Navigator.of(context).pop(renamed);
|
||||
showMessage(context, 'Fingerprint renamed');
|
||||
} catch (e) {
|
||||
final String errorMessage;
|
||||
// TODO: Make this cleaner than importing desktop specific RpcError.
|
||||
if (e is RpcError) {
|
||||
errorMessage = e.message;
|
||||
} else {
|
||||
errorMessage = e.toString();
|
||||
}
|
||||
showMessage(
|
||||
context,
|
||||
'Error renaming: $errorMessage',
|
||||
duration: const Duration(seconds: 4),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@ -53,6 +69,7 @@ class _RenameAccountDialogState extends ConsumerState<RenameFingerprintDialog> {
|
||||
const Text('This will change the label of the fingerprint.'),
|
||||
TextFormField(
|
||||
initialValue: _label,
|
||||
// TODO: Make this field count UTF-8 bytes instead of characters.
|
||||
maxLength: 15,
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
|
@ -7,6 +7,7 @@ import 'package:yubico_authenticator/app/logging.dart';
|
||||
|
||||
import '../../app/message.dart';
|
||||
import '../../core/models.dart';
|
||||
import '../../desktop/models.dart';
|
||||
import '../../widgets/responsive_dialog.dart';
|
||||
import '../state.dart';
|
||||
import '../../fido/models.dart';
|
||||
@ -69,7 +70,18 @@ class _ResetDialogState extends ConsumerState<ResetDialog> {
|
||||
}, onError: (e) {
|
||||
_log.error('Error performing FIDO reset', e);
|
||||
Navigator.of(context).pop();
|
||||
showMessage(context, 'Error performing reset');
|
||||
final String errorMessage;
|
||||
// TODO: Make this cleaner than importing desktop specific RpcError.
|
||||
if (e is RpcError) {
|
||||
errorMessage = e.message;
|
||||
} else {
|
||||
errorMessage = e.toString();
|
||||
}
|
||||
showMessage(
|
||||
context,
|
||||
'Error performing reset: $errorMessage',
|
||||
duration: const Duration(seconds: 4),
|
||||
);
|
||||
});
|
||||
}
|
||||
: null,
|
||||
|
@ -250,10 +250,11 @@ class _ManagementScreenState extends ConsumerState<ManagementScreen> {
|
||||
data: (info) {
|
||||
bool hasConfig = info.version.major > 4;
|
||||
if (hasConfig) {
|
||||
canSave = !_mapEquals(
|
||||
_enabled,
|
||||
info.config.enabledCapabilities,
|
||||
);
|
||||
canSave = _enabled[Transport.usb] != 0 &&
|
||||
!_mapEquals(
|
||||
_enabled,
|
||||
info.config.enabledCapabilities,
|
||||
);
|
||||
} else {
|
||||
canSave = _interfaces != 0 &&
|
||||
_interfaces !=
|
||||
|
@ -11,6 +11,7 @@ import 'package:yubico_authenticator/app/logging.dart';
|
||||
import '../../app/message.dart';
|
||||
import '../../app/models.dart';
|
||||
import '../../app/state.dart';
|
||||
import '../../desktop/models.dart';
|
||||
import '../../widgets/file_drop_target.dart';
|
||||
import '../../widgets/responsive_dialog.dart';
|
||||
import '../models.dart';
|
||||
@ -57,11 +58,30 @@ class _OathAddAccountPageState extends ConsumerState<OathAddAccountPage> {
|
||||
_qrState = _QrScanState.scanning;
|
||||
});
|
||||
final otpauth = await qrScanner.scanQr();
|
||||
final data = CredentialData.fromUri(Uri.parse(otpauth));
|
||||
_loadCredentialData(data);
|
||||
} catch (e) {
|
||||
setState(() {
|
||||
if (otpauth == null) {
|
||||
if (!mounted) return;
|
||||
showMessage(context, 'No QR code found');
|
||||
setState(() {
|
||||
_qrState = _QrScanState.failed;
|
||||
});
|
||||
} else {
|
||||
final data = CredentialData.fromUri(Uri.parse(otpauth));
|
||||
_loadCredentialData(data);
|
||||
}
|
||||
} catch (e) {
|
||||
final String errorMessage;
|
||||
// TODO: Make this cleaner than importing desktop specific RpcError.
|
||||
if (e is RpcError) {
|
||||
errorMessage = e.message;
|
||||
} else {
|
||||
errorMessage = e.toString();
|
||||
}
|
||||
showMessage(
|
||||
context,
|
||||
'Failed reading QR code: $errorMessage',
|
||||
duration: const Duration(seconds: 4),
|
||||
);
|
||||
setState(() {
|
||||
_qrState = _QrScanState.failed;
|
||||
});
|
||||
}
|
||||
@ -142,7 +162,18 @@ class _OathAddAccountPageState extends ConsumerState<OathAddAccountPage> {
|
||||
// ignored
|
||||
} catch (e) {
|
||||
_log.error('Failed to add account', e);
|
||||
showMessage(context, 'Failed adding account');
|
||||
final String errorMessage;
|
||||
// TODO: Make this cleaner than importing desktop specific RpcError.
|
||||
if (e is RpcError) {
|
||||
errorMessage = e.message;
|
||||
} else {
|
||||
errorMessage = e.toString();
|
||||
}
|
||||
showMessage(
|
||||
context,
|
||||
'Failed adding account: $errorMessage',
|
||||
duration: const Duration(seconds: 4),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
setState(() {
|
||||
@ -164,8 +195,13 @@ class _OathAddAccountPageState extends ConsumerState<OathAddAccountPage> {
|
||||
if (qrScanner != null) {
|
||||
final b64Image = base64Encode(fileData);
|
||||
final otpauth = await qrScanner.scanQr(b64Image);
|
||||
final data = CredentialData.fromUri(Uri.parse(otpauth));
|
||||
_loadCredentialData(data);
|
||||
if (otpauth == null) {
|
||||
if (!mounted) return;
|
||||
showMessage(context, 'No QR code found');
|
||||
} else {
|
||||
final data = CredentialData.fromUri(Uri.parse(otpauth));
|
||||
_loadCredentialData(data);
|
||||
}
|
||||
}
|
||||
},
|
||||
child: Column(
|
||||
|
@ -1,14 +1,19 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
import '../../user_cancelled_exception.dart';
|
||||
import '../../app/logging.dart';
|
||||
import '../../app/message.dart';
|
||||
import '../../app/models.dart';
|
||||
import '../../desktop/models.dart';
|
||||
import '../../widgets/responsive_dialog.dart';
|
||||
import '../models.dart';
|
||||
import '../state.dart';
|
||||
import 'utils.dart';
|
||||
|
||||
final _log = Logger('oath.view.rename_account_dialog');
|
||||
|
||||
class RenameAccountDialog extends ConsumerStatefulWidget {
|
||||
final DeviceNode device;
|
||||
final OathCredential credential;
|
||||
@ -65,6 +70,20 @@ class _RenameAccountDialogState extends ConsumerState<RenameAccountDialog> {
|
||||
showMessage(context, 'Account renamed');
|
||||
} on UserCancelledException catch (_) {
|
||||
// ignored
|
||||
} catch (e) {
|
||||
_log.error('Failed to add account', e);
|
||||
final String errorMessage;
|
||||
// TODO: Make this cleaner than importing desktop specific RpcError.
|
||||
if (e is RpcError) {
|
||||
errorMessage = e.message;
|
||||
} else {
|
||||
errorMessage = e.toString();
|
||||
}
|
||||
showMessage(
|
||||
context,
|
||||
'Failed adding account: $errorMessage',
|
||||
duration: const Duration(seconds: 4),
|
||||
);
|
||||
}
|
||||
}
|
||||
: null,
|
||||
|
@ -1,5 +1,5 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// This file is generated by running ./set-version.py <version> <build>
|
||||
|
||||
const String version = '6.0.0-alpha.3';
|
||||
const String version = '6.0.0-dev.0';
|
||||
const int build = 59900;
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <desktop_drop/desktop_drop_plugin.h>
|
||||
#include <screen_retriever/screen_retriever_plugin.h>
|
||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||
#include <window_manager/window_manager_plugin.h>
|
||||
|
||||
@ -14,6 +15,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) desktop_drop_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopDropPlugin");
|
||||
desktop_drop_plugin_register_with_registrar(desktop_drop_registrar);
|
||||
g_autoptr(FlPluginRegistrar) screen_retriever_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverPlugin");
|
||||
screen_retriever_plugin_register_with_registrar(screen_retriever_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
|
||||
desktop_drop
|
||||
screen_retriever
|
||||
url_launcher_linux
|
||||
window_manager
|
||||
)
|
||||
|
@ -6,12 +6,14 @@ import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import desktop_drop
|
||||
import screen_retriever
|
||||
import shared_preferences_macos
|
||||
import url_launcher_macos
|
||||
import window_manager
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
DesktopDropPlugin.register(with: registry.registrar(forPlugin: "DesktopDropPlugin"))
|
||||
ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin"))
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||
WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin"))
|
||||
|
@ -2,6 +2,8 @@ PODS:
|
||||
- desktop_drop (0.0.1):
|
||||
- FlutterMacOS
|
||||
- FlutterMacOS (1.0.0)
|
||||
- screen_retriever (0.0.1):
|
||||
- FlutterMacOS
|
||||
- shared_preferences_macos (0.0.1):
|
||||
- FlutterMacOS
|
||||
- url_launcher_macos (0.0.1):
|
||||
@ -12,6 +14,7 @@ PODS:
|
||||
DEPENDENCIES:
|
||||
- desktop_drop (from `Flutter/ephemeral/.symlinks/plugins/desktop_drop/macos`)
|
||||
- FlutterMacOS (from `Flutter/ephemeral`)
|
||||
- screen_retriever (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos`)
|
||||
- shared_preferences_macos (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_macos/macos`)
|
||||
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
|
||||
- window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`)
|
||||
@ -21,6 +24,8 @@ EXTERNAL SOURCES:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/desktop_drop/macos
|
||||
FlutterMacOS:
|
||||
:path: Flutter/ephemeral
|
||||
screen_retriever:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos
|
||||
shared_preferences_macos:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_macos/macos
|
||||
url_launcher_macos:
|
||||
@ -31,6 +36,7 @@ EXTERNAL SOURCES:
|
||||
SPEC CHECKSUMS:
|
||||
desktop_drop: 69eeff437544aa619c8db7f4481b3a65f7696898
|
||||
FlutterMacOS: 57701585bf7de1b3fc2bb61f6378d73bbdea8424
|
||||
screen_retriever: 59634572a57080243dd1bf715e55b6c54f241a38
|
||||
shared_preferences_macos: a64dc611287ed6cbe28fd1297898db1336975727
|
||||
url_launcher_macos: 597e05b8e514239626bcf4a850fcf9ef5c856ec3
|
||||
window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8
|
||||
|
47
pubspec.lock
47
pubspec.lock
@ -70,14 +70,14 @@ packages:
|
||||
name: build_resolvers
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.6"
|
||||
version: "2.0.9"
|
||||
build_runner:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_runner
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.10"
|
||||
version: "2.1.11"
|
||||
build_runner_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -98,7 +98,7 @@ packages:
|
||||
name: built_value
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "8.3.0"
|
||||
version: "8.3.2"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -147,14 +147,14 @@ packages:
|
||||
name: convert
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
version: "3.0.2"
|
||||
cross_file:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cross_file
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.3.3"
|
||||
version: "0.3.3+1"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -168,7 +168,7 @@ packages:
|
||||
name: dart_style
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
version: "2.2.3"
|
||||
desktop_drop:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -189,7 +189,7 @@ packages:
|
||||
name: ffi
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
version: "2.0.0"
|
||||
file:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -203,7 +203,7 @@ packages:
|
||||
name: fixnum
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
version: "1.0.1"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
@ -227,7 +227,7 @@ packages:
|
||||
name: flutter_riverpod
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.3"
|
||||
version: "1.0.4"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
@ -244,7 +244,7 @@ packages:
|
||||
name: freezed
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.3"
|
||||
version: "2.0.3+1"
|
||||
freezed_annotation:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -258,7 +258,7 @@ packages:
|
||||
name: frontend_server_client
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
version: "2.1.3"
|
||||
fuchsia_remote_debug_protocol:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
@ -291,7 +291,7 @@ packages:
|
||||
name: http_parser
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
version: "4.0.1"
|
||||
integration_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
@ -387,7 +387,7 @@ packages:
|
||||
name: path_provider_linux
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.6"
|
||||
version: "2.1.7"
|
||||
path_provider_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -401,14 +401,14 @@ packages:
|
||||
name: path_provider_windows
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.6"
|
||||
version: "2.1.0"
|
||||
pigeon:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: pigeon
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.3"
|
||||
version: "3.1.5"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -465,6 +465,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.3"
|
||||
screen_retriever:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: screen_retriever
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.2"
|
||||
shared_preferences:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -637,7 +644,7 @@ packages:
|
||||
name: url_launcher
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.1.2"
|
||||
version: "6.1.3"
|
||||
url_launcher_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -728,14 +735,14 @@ packages:
|
||||
name: win32
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.5.2"
|
||||
version: "2.7.0"
|
||||
window_manager:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: window_manager
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.3"
|
||||
version: "0.2.5"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -749,7 +756,7 @@ packages:
|
||||
name: yaml
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
version: "3.1.1"
|
||||
sdks:
|
||||
dart: ">=2.17.0 <3.0.0"
|
||||
flutter: ">=2.10.0"
|
||||
flutter: ">=3.0.0"
|
||||
|
14
resources/README.adoc
Normal file
14
resources/README.adoc
Normal file
@ -0,0 +1,14 @@
|
||||
== Instructions for Linux
|
||||
|
||||
To run Yubico Authenticator, execute the authenticator binary by double clicking or running it from command line:
|
||||
|
||||
./authenticator
|
||||
|
||||
You will need to have pcscd installed and running for Yubico Authenticator to work.
|
||||
On Ubuntu:
|
||||
|
||||
sudo apt install pcscd
|
||||
|
||||
Note that the QR scanning feature requires gnome-screenshot when using Wayland.
|
||||
|
||||
sudo apt install gnome-screenshot
|
@ -7,12 +7,15 @@
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <desktop_drop/desktop_drop_plugin.h>
|
||||
#include <screen_retriever/screen_retriever_plugin.h>
|
||||
#include <url_launcher_windows/url_launcher_windows.h>
|
||||
#include <window_manager/window_manager_plugin.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
DesktopDropPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("DesktopDropPlugin"));
|
||||
ScreenRetrieverPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("ScreenRetrieverPlugin"));
|
||||
UrlLauncherWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
||||
WindowManagerPluginRegisterWithRegistrar(
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
desktop_drop
|
||||
screen_retriever
|
||||
url_launcher_windows
|
||||
window_manager
|
||||
)
|
||||
|
@ -69,7 +69,7 @@ IDI_APP_ICON ICON "resources\\app_icon.ico"
|
||||
#ifdef FLUTTER_BUILD_NAME
|
||||
#define VERSION_AS_STRING #FLUTTER_BUILD_NAME
|
||||
#else
|
||||
#define VERSION_AS_STRING "6.0.0-alpha.3"
|
||||
#define VERSION_AS_STRING "6.0.0-dev.0"
|
||||
#endif
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
|
Loading…
Reference in New Issue
Block a user