Merge branch 'main' into fix/android-nfc

This commit is contained in:
Adam Velebil 2022-06-15 11:07:39 +02:00
commit 0b4b111acd
No known key found for this signature in database
GPG Key ID: AC6D6B9D715FC084
27 changed files with 289 additions and 81 deletions

View File

@ -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

View File

@ -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 ..

View File

@ -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)

View File

@ -278,7 +278,13 @@ class CredentialsNode(RpcNode):
if data.get_id() in self._creds:
raise ValueError("Credential already exists")
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)

View File

@ -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

View File

@ -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])])
]

View File

@ -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?>(

View File

@ -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.';
}

View File

@ -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'];
}

View File

@ -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 {
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

View File

@ -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;
}

View File

@ -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,6 +134,7 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
});
return;
}
try {
final result = await ref
.read(fidoStateProvider(widget.devicePath).notifier)
.setPin(_newPin, oldPin: oldPin);
@ -146,5 +153,20 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
}
});
});
} 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),
);
}
}
}

View File

@ -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 {
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(),

View File

@ -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,

View File

@ -250,7 +250,8 @@ class _ManagementScreenState extends ConsumerState<ManagementScreen> {
data: (info) {
bool hasConfig = info.version.major > 4;
if (hasConfig) {
canSave = !_mapEquals(
canSave = _enabled[Transport.usb] != 0 &&
!_mapEquals(
_enabled,
info.config.enabledCapabilities,
);

View File

@ -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();
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(() {
showMessage(context, 'No QR code found');
_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,9 +195,14 @@ class _OathAddAccountPageState extends ConsumerState<OathAddAccountPage> {
if (qrScanner != null) {
final b64Image = base64Encode(fileData);
final otpauth = await qrScanner.scanQr(b64Image);
if (otpauth == null) {
if (!mounted) return;
showMessage(context, 'No QR code found');
} else {
final data = CredentialData.fromUri(Uri.parse(otpauth));
_loadCredentialData(data);
}
}
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,

View File

@ -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,

View File

@ -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;

View File

@ -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);

View File

@ -4,6 +4,7 @@
list(APPEND FLUTTER_PLUGIN_LIST
desktop_drop
screen_retriever
url_launcher_linux
window_manager
)

View File

@ -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"))

View File

@ -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

View File

@ -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
View 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

View File

@ -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(

View File

@ -4,6 +4,7 @@
list(APPEND FLUTTER_PLUGIN_LIST
desktop_drop
screen_retriever
url_launcher_windows
window_manager
)

View File

@ -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