mirror of
https://github.com/Yubico/yubioath-flutter.git
synced 2024-11-25 05:52:40 +03:00
First steps of importing creds
This commit is contained in:
parent
58a5ab6c7c
commit
d6488901dd
@ -14,6 +14,11 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'package:base32/base32.dart';
|
||||||
|
import 'package:convert/convert.dart';
|
||||||
|
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
@ -125,9 +130,97 @@ class CredentialData with _$CredentialData {
|
|||||||
_$CredentialDataFromJson(json);
|
_$CredentialDataFromJson(json);
|
||||||
|
|
||||||
factory CredentialData.fromUri(Uri uri) {
|
factory CredentialData.fromUri(Uri uri) {
|
||||||
if (uri.scheme.toLowerCase() != 'otpauth') {
|
List<dynamic> read(Uint8List bytes) {
|
||||||
|
final index = bytes[0];
|
||||||
|
final sublist1 = bytes.sublist(1, index + 1);
|
||||||
|
final sublist2 = bytes.sublist(index + 1);
|
||||||
|
return [sublist1, sublist2];
|
||||||
|
}
|
||||||
|
|
||||||
|
String b32Encode(Uint8List data) {
|
||||||
|
final encodedData = base32.encode(data);
|
||||||
|
return utf8.decode(encodedData.runes.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uri.scheme.toLowerCase() == 'otpauth-migration') {
|
||||||
|
final uriString = uri.toString();
|
||||||
|
var data = Uint8List.fromList(
|
||||||
|
base64.decode(Uri.decodeComponent(uriString.split('=')[1])));
|
||||||
|
|
||||||
|
var credentials = <CredentialData>[];
|
||||||
|
|
||||||
|
var tag = data[0];
|
||||||
|
|
||||||
|
/*
|
||||||
|
Assuming the credential(s) follow the format:
|
||||||
|
cred = 0aLENGTH0aSECRET12NAME1aISSUER200128013002xxx
|
||||||
|
where xxx can be another cred.
|
||||||
|
*/
|
||||||
|
while (tag == 10) {
|
||||||
|
// 0a tag means new credential.
|
||||||
|
|
||||||
|
var length = data[1]; // The length of this credential
|
||||||
|
var secretTag = data[2];
|
||||||
|
if (secretTag != 10) {
|
||||||
|
// tag before secret is 0a hex
|
||||||
|
throw ArgumentError('Invalid scheme, no secret tag');
|
||||||
|
}
|
||||||
|
data = data.sublist(3);
|
||||||
|
|
||||||
|
final result1 = read(data);
|
||||||
|
final secret = result1[0];
|
||||||
|
data = result1[1];
|
||||||
|
final decodedSecret = b32Encode(secret);
|
||||||
|
|
||||||
|
var nameTag = data[0];
|
||||||
|
if (nameTag != 18) {
|
||||||
|
// tag before name is 12 hex
|
||||||
|
throw ArgumentError('Invalid scheme, no name tag');
|
||||||
|
}
|
||||||
|
data = data.sublist(1);
|
||||||
|
final result2 = read(data);
|
||||||
|
final name = result2[0];
|
||||||
|
data = result2[1];
|
||||||
|
|
||||||
|
var issuerTag = data[0];
|
||||||
|
var issuer;
|
||||||
|
if (issuerTag == 26) {
|
||||||
|
// tag before issuer is 1a hex, but issuer is optional.
|
||||||
|
data = data.sublist(1);
|
||||||
|
final result3 = read(data);
|
||||||
|
issuer = result3[0];
|
||||||
|
data = result3[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
final credential = CredentialData(
|
||||||
|
issuer: issuerTag != 26
|
||||||
|
? null
|
||||||
|
: utf8.decode(issuer, allowMalformed: true),
|
||||||
|
name: utf8.decode(name, allowMalformed: true),
|
||||||
|
secret: decodedSecret,
|
||||||
|
);
|
||||||
|
|
||||||
|
credentials.add(credential);
|
||||||
|
|
||||||
|
var endTag = data.sublist(0, 6);
|
||||||
|
if (hex.encode(endTag) != '200128013002') {
|
||||||
|
// At the end of every credential there is 200128013002
|
||||||
|
throw ArgumentError('Invalid scheme, no end tag');
|
||||||
|
}
|
||||||
|
data = data.sublist(6);
|
||||||
|
tag = data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print all the extracted credentials
|
||||||
|
for (var credential in credentials) {
|
||||||
|
print('${credential.issuer} (${credential.name}) ${credential.secret}');
|
||||||
|
}
|
||||||
|
|
||||||
|
return credentials[0]; // For now, return only the first credential.
|
||||||
|
} else if (uri.scheme.toLowerCase() != 'otpauth') {
|
||||||
throw ArgumentError('Invalid scheme, must be "otpauth://"');
|
throw ArgumentError('Invalid scheme, must be "otpauth://"');
|
||||||
}
|
}
|
||||||
|
|
||||||
final oathType = OathType.values.byName(uri.host.toLowerCase());
|
final oathType = OathType.values.byName(uri.host.toLowerCase());
|
||||||
final params = uri.queryParameters;
|
final params = uri.queryParameters;
|
||||||
String? issuer;
|
String? issuer;
|
||||||
|
10
pubspec.lock
10
pubspec.lock
@ -41,6 +41,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.10.0"
|
version: "2.10.0"
|
||||||
|
base32:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: base32
|
||||||
|
sha256: ddad4ebfedf93d4500818ed8e61443b734ffe7cf8a45c668c9b34ef6adde02e2
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.3"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -154,7 +162,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "1.17.0"
|
version: "1.17.0"
|
||||||
convert:
|
convert:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: convert
|
name: convert
|
||||||
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
|
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
|
||||||
|
@ -63,6 +63,8 @@ dependencies:
|
|||||||
crypto: ^3.0.2
|
crypto: ^3.0.2
|
||||||
tray_manager: ^0.2.0
|
tray_manager: ^0.2.0
|
||||||
local_notifier: ^0.1.5
|
local_notifier: ^0.1.5
|
||||||
|
base32: ^2.1.3
|
||||||
|
convert: ^3.1.1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
integration_test:
|
integration_test:
|
||||||
|
Loading…
Reference in New Issue
Block a user