Skip to content

Commit

Permalink
Merge PR Yubico#1347.
Browse files Browse the repository at this point in the history
  • Loading branch information
elibon99 committed Jan 24, 2024
2 parents e58a25e + 74a6ac0 commit 59ef573
Show file tree
Hide file tree
Showing 10 changed files with 123 additions and 44 deletions.
20 changes: 16 additions & 4 deletions helper/helper/qr.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from .base import RpcException
import mss
import zxingcpp
import base64
Expand All @@ -21,7 +22,7 @@
import subprocess # nosec
import tempfile
from mss.exception import ScreenShotError
from PIL import Image
from PIL import Image, UnidentifiedImageError


def _capture_screen():
Expand Down Expand Up @@ -64,11 +65,22 @@ def _capture_screen():
raise ValueError("Unable to capture screenshot")


class InvalidImageException(RpcException):
def __init__(self):
super().__init__(
"invalid-image",
"The provided file is not a valid image",
)


def scan_qr(image_data=None):
if image_data:
msg = base64.b64decode(image_data)
buf = io.BytesIO(msg)
img = Image.open(buf)
try:
msg = base64.b64decode(image_data)
buf = io.BytesIO(msg)
img = Image.open(buf)
except UnidentifiedImageError:
raise InvalidImageException()
else:
img = _capture_screen()

Expand Down
7 changes: 7 additions & 0 deletions lib/l10n/app_de.arb
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,13 @@
"l_qr_scanned": "QR-Code aufgenommen",
"l_invalid_qr": "Ungültiger QR-Code",
"l_qr_not_found": "Kein QR-Code gefunden",
"l_qr_file_too_large": null,
"@l_qr_file_too_large": {
"placeholders": {
"max": {}
}
},
"l_qr_invalid_image_file": null,
"l_qr_select_file": null,
"l_qr_not_read": "Fehler beim Lesen des QR-Codes: {message}",
"@l_qr_not_read": {
Expand Down
7 changes: 7 additions & 0 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,13 @@
"l_qr_scanned": "Scanned QR code",
"l_invalid_qr": "Invalid QR code",
"l_qr_not_found": "No QR code found",
"l_qr_file_too_large": "File too large (max {max})",
"@l_qr_file_too_large": {
"placeholders": {
"max": {}
}
},
"l_qr_invalid_image_file": "Invalid image file",
"l_qr_select_file": "Select file with QR code",
"l_qr_not_read": "Failed reading QR code: {message}",
"@l_qr_not_read": {
Expand Down
7 changes: 7 additions & 0 deletions lib/l10n/app_fr.arb
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,13 @@
"l_qr_scanned": "QR code scanné",
"l_invalid_qr": "QR code invalide",
"l_qr_not_found": "Aucun QR code trouvé",
"l_qr_file_too_large": null,
"@l_qr_file_too_large": {
"placeholders": {
"max": {}
}
},
"l_qr_invalid_image_file": null,
"l_qr_select_file": null,
"l_qr_not_read": "Erreur de lecture du QR code: {message}",
"@l_qr_not_read": {
Expand Down
7 changes: 7 additions & 0 deletions lib/l10n/app_ja.arb
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,13 @@
"l_qr_scanned": "スキャンしたQRコード",
"l_invalid_qr": "無効なQRコード",
"l_qr_not_found": "QRコードが見つかりませんでした",
"l_qr_file_too_large": null,
"@l_qr_file_too_large": {
"placeholders": {
"max": {}
}
},
"l_qr_invalid_image_file": null,
"l_qr_select_file": null,
"l_qr_not_read": "QRコードの読み取りに失敗しました:{message}",
"@l_qr_not_read": {
Expand Down
7 changes: 7 additions & 0 deletions lib/l10n/app_pl.arb
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,13 @@
"l_qr_scanned": "Zeskanowany kod QR",
"l_invalid_qr": "Nieprawidłowy kod QR",
"l_qr_not_found": "Nie znaleziono kodu QR",
"l_qr_file_too_large": null,
"@l_qr_file_too_large": {
"placeholders": {
"max": {}
}
},
"l_qr_invalid_image_file": null,
"l_qr_select_file": "Wybierz plik z kodem QR",
"l_qr_not_read": "Odczytanie kodu QR nie powiodło się: {message}",
"@l_qr_not_read": {
Expand Down
23 changes: 8 additions & 15 deletions lib/oath/views/add_account_dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
* limitations under the License.
*/

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
Expand Down Expand Up @@ -55,19 +53,14 @@ class _AddAccountDialogState extends ConsumerState<AddAccountDialog> {
onFileDropped: (file) async {
Navigator.of(context).pop();
if (qrScanner != null) {
final fileData = await file.readAsBytes();
final b64Image = base64Encode(fileData);
final qrData = await qrScanner.scanQr(b64Image);
await withContext(
(context) async {
if (qrData != null) {
await handleUri(context, credentials, qrData, widget.devicePath,
widget.state, l10n);
} else {
showMessage(context, l10n.l_qr_not_found);
}
},
);
final qrData =
await handleQrFile(file, context, withContext, qrScanner);
if (qrData != null) {
await withContext((context) async {
await handleUri(context, credentials, qrData, widget.devicePath,
widget.state, l10n);
});
}
}
},
overlay: FileDropOverlay(
Expand Down
16 changes: 6 additions & 10 deletions lib/oath/views/add_account_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/

import 'dart:async';
import 'dart:convert';
import 'dart:math';

import 'package:flutter/material.dart';
Expand Down Expand Up @@ -314,11 +313,10 @@ class _OathAddAccountPageState extends ConsumerState<OathAddAccountPage> {
final qrScanner = ref.read(qrScannerProvider);
final withContext = ref.read(withContextProvider);
if (qrScanner != null) {
final fileData = await file.readAsBytes();
final b64Image = base64Encode(fileData);
final qrData = await qrScanner.scanQr(b64Image);
await withContext((context) async {
if (qrData != null) {
final qrData =
await handleQrFile(file, context, withContext, qrScanner);
if (qrData != null) {
await withContext((context) async {
List<CredentialData> creds;
try {
creds = CredentialData.fromUri(Uri.parse(qrData));
Expand All @@ -333,10 +331,8 @@ class _OathAddAccountPageState extends ConsumerState<OathAddAccountPage> {
await handleUri(context, widget.credentials, qrData,
widget.devicePath, widget.state, l10n);
}
} else {
showMessage(context, l10n.l_qr_not_found);
}
});
});
}
}
},
overlay: FileDropOverlay(
Expand Down
24 changes: 9 additions & 15 deletions lib/oath/views/oath_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/

import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:flutter/material.dart';
Expand Down Expand Up @@ -144,21 +143,16 @@ class _UnlockedViewState extends ConsumerState<_UnlockedView> {
Future<void> onFileDropped(File file) async {
final qrScanner = ref.read(qrScannerProvider);
if (qrScanner != null) {
final fileData = await file.readAsBytes();
final b64Image = base64Encode(fileData);
final qrData = await qrScanner.scanQr(b64Image);
final withContext = ref.read(withContextProvider);
await withContext(
(context) async {
if (qrData != null) {
final credentials = ref.read(credentialsProvider);
await handleUri(context, credentials, qrData, widget.devicePath,
widget.oathState, l10n);
} else {
showMessage(context, l10n.l_qr_not_found);
}
},
);
final qrData =
await handleQrFile(file, context, withContext, qrScanner);
if (qrData != null) {
await withContext((context) async {
final credentials = ref.read(credentialsProvider);
await handleUri(context, credentials, qrData, widget.devicePath,
widget.oathState, l10n);
});
}
}
}

Expand Down
49 changes: 49 additions & 0 deletions lib/oath/views/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,17 @@
* limitations under the License.
*/

import 'dart:convert';
import 'dart:io';
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

import '../../app/message.dart';
import '../../app/models.dart';
import '../../app/state.dart';
import '../../desktop/models.dart';
import '../../widgets/utf8_utils.dart';
import '../keys.dart';
import '../models.dart';
Expand Down Expand Up @@ -97,3 +101,48 @@ Future<void> handleUri(
);
}
}

const maxQrFileSize = 5 * 1024 * 1024;

Future<String?> handleQrFile(File file, BuildContext context,
WithContext withContext, QrScanner qrScanner) async {
final l10n = AppLocalizations.of(context)!;
if (await file.length() > maxQrFileSize) {
await withContext((context) async {
showMessage(
context,
l10n.l_qr_not_read(
l10n.l_qr_file_too_large('${maxQrFileSize / (1024 * 1024)} MB')));
});
return null;
}

final fileData = await file.readAsBytes();
final b64Image = base64Encode(fileData);

try {
final qrData = await qrScanner.scanQr(b64Image);
if (qrData == null) {
await withContext((context) async {
showMessage(context, l10n.l_qr_not_found);
});
return null;
}
return qrData;
} catch (e) {
final String errorMessage;
if (e is RpcError) {
if (e.status == 'invalid-image') {
errorMessage = l10n.l_qr_invalid_image_file;
} else {
errorMessage = e.message;
}
} else {
errorMessage = e.toString();
}
await withContext((context) async {
showMessage(context, l10n.l_qr_not_read(errorMessage));
});
return null;
}
}

0 comments on commit 59ef573

Please sign in to comment.