password work

This commit is contained in:
Christien Rioux 2023-09-26 22:32:13 -04:00
parent 9d1eaeed4c
commit 960b8375b5
14 changed files with 77 additions and 182 deletions

View File

@ -101,7 +101,13 @@
}, },
"enter_pin_dialog": { "enter_pin_dialog": {
"enter_pin": "Enter PIN", "enter_pin": "Enter PIN",
"reenter_pin": "Re-Enter PIN To Confirm" "reenter_pin": "Re-Enter PIN To Confirm",
"pin_does_not_match": "PIN does not match"
},
"enter_password_dialog": {
"enter_password": "Enter Password",
"reenter_password": "Re-Enter Password To Confirm",
"password_does_not_match": "Password does not match"
}, },
"contact_list": { "contact_list": {
"title": "Contact List", "title": "Contact List",

View File

@ -10,12 +10,12 @@ import '../tools/tools.dart';
class EnterPinDialog extends ConsumerStatefulWidget { class EnterPinDialog extends ConsumerStatefulWidget {
const EnterPinDialog({ const EnterPinDialog({
this.matchPin, required this.reenter,
this.description, required this.description,
super.key, super.key,
}); });
final String? matchPin; final bool reenter;
final String? description; final String? description;
@override @override
@ -25,8 +25,8 @@ class EnterPinDialog extends ConsumerStatefulWidget {
void debugFillProperties(DiagnosticPropertiesBuilder properties) { void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties); super.debugFillProperties(properties);
properties properties
..add(StringProperty('matchPin', matchPin)) ..add(StringProperty('description', description))
..add(StringProperty('description', description)); ..add(DiagnosticsProperty<bool>('reenter', reenter));
} }
} }
@ -77,7 +77,7 @@ class EnterPinDialogState extends ConsumerState<EnterPinDialog> {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Text( Text(
widget.matchPin == null !widget.reenter
? translate('enter_pin_dialog.enter_pin') ? translate('enter_pin_dialog.enter_pin')
: translate('enter_pin_dialog.reenter_pin'), : translate('enter_pin_dialog.reenter_pin'),
style: theme.textTheme.titleLarge, style: theme.textTheme.titleLarge,
@ -94,23 +94,10 @@ class EnterPinDialogState extends ConsumerState<EnterPinDialog> {
inputFormatters: <TextInputFormatter>[ inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly FilteringTextInputFormatter.digitsOnly
], ],
// validator: (widget.matchPin != null)
// ? (value) => value == widget.matchPin
// ? null
// : translate('enter_pin_dialog.pin_does_not_match')
// : null,
// onClipboardFound: (value) {
// debugPrint('onClipboardFound: $value');
// pinController.setText(value);
// },
hapticFeedbackType: HapticFeedbackType.lightImpact, hapticFeedbackType: HapticFeedbackType.lightImpact,
onCompleted: (pin) { onCompleted: (pin) {
debugPrint('onCompleted: $pin');
Navigator.pop(context, pin); Navigator.pop(context, pin);
}, },
onChanged: (value) {
debugPrint('onChanged: $value');
},
cursor: Column( cursor: Column(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
@ -129,13 +116,6 @@ class EnterPinDialogState extends ConsumerState<EnterPinDialog> {
border: Border.all(color: borderColor), border: Border.all(color: borderColor),
), ),
), ),
errorText: '',
errorPinTheme: defaultPinTheme.copyWith(
decoration: BoxDecoration(
color: scale.errorScale.border,
borderRadius: BorderRadius.circular(8),
),
),
).paddingAll(16), ).paddingAll(16),
), ),
if (widget.description != null) if (widget.description != null)

View File

@ -11,6 +11,7 @@ import '../providers/contact.dart';
import '../providers/contact_invite.dart'; import '../providers/contact_invite.dart';
import '../tools/tools.dart'; import '../tools/tools.dart';
import '../veilid_support/veilid_support.dart'; import '../veilid_support/veilid_support.dart';
import 'enter_password.dart';
import 'enter_pin.dart'; import 'enter_pin.dart';
import 'profile_widget.dart'; import 'profile_widget.dart';
@ -184,22 +185,22 @@ class PasteInviteDialogState extends ConsumerState<PasteInviteDialog> {
} }
final pin = await showDialog<String>( final pin = await showDialog<String>(
context: context, context: context,
builder: (context) => builder: (context) => EnterPinDialog(
EnterPinDialog(description: description)); reenter: false, description: description));
if (pin == null) { if (pin == null) {
return null; return null;
} }
encryptionKey = pin; encryptionKey = pin;
case EncryptionKeyType.password: case EncryptionKeyType.password:
final description = final description =
translate('contact_invite.protected_with_pin'); translate('contact_invite.protected_with_password');
if (!context.mounted) { if (!context.mounted) {
return null; return null;
} }
final password = await showDialog<String>( final password = await showDialog<String>(
context: context, context: context,
builder: (context) => builder: (context) =>
EnterPinDialog(description: description)); EnterPasswordDialog(description: description));
if (password == null) { if (password == null) {
return null; return null;
} }
@ -215,6 +216,7 @@ class PasteInviteDialogState extends ConsumerState<PasteInviteDialog> {
// Check if validation was cancelled // Check if validation was cancelled
if (validatedContactInvitation == null) { if (validatedContactInvitation == null) {
setState(() { setState(() {
_pasteTextController.text = '';
_validatingPaste = false; _validatingPaste = false;
_validInvitation = null; _validInvitation = null;
}); });
@ -233,20 +235,22 @@ class PasteInviteDialogState extends ConsumerState<PasteInviteDialog> {
switch (e.type) { switch (e.type) {
case EncryptionKeyType.none: case EncryptionKeyType.none:
errorText = translate('contact_invite.invalid_invitation'); errorText = translate('contact_invite.invalid_invitation');
case EncryptionKeyType.password:
errorText = translate('contact_invite.invalid_pin');
case EncryptionKeyType.pin: case EncryptionKeyType.pin:
errorText = translate('contact_invite.invalid_pin');
case EncryptionKeyType.password:
errorText = translate('contact_invite.invalid_password'); errorText = translate('contact_invite.invalid_password');
} }
if (context.mounted) { if (context.mounted) {
showErrorToast(context, errorText); showErrorToast(context, errorText);
} }
setState(() { setState(() {
_pasteTextController.text = '';
_validatingPaste = false; _validatingPaste = false;
_validInvitation = null; _validInvitation = null;
}); });
} on Exception catch (_) { } on Exception catch (_) {
setState(() { setState(() {
_pasteTextController.text = '';
_validatingPaste = false; _validatingPaste = false;
_validInvitation = null; _validInvitation = null;
}); });

View File

@ -14,6 +14,7 @@ import '../providers/contact_invite.dart';
import '../tools/tools.dart'; import '../tools/tools.dart';
import '../veilid_support/veilid_support.dart'; import '../veilid_support/veilid_support.dart';
import 'contact_invitation_display.dart'; import 'contact_invitation_display.dart';
import 'enter_password.dart';
import 'enter_pin.dart'; import 'enter_pin.dart';
class SendInviteDialog extends ConsumerStatefulWidget { class SendInviteDialog extends ConsumerStatefulWidget {
@ -55,7 +56,8 @@ class SendInviteDialogState extends ConsumerState<SendInviteDialog> {
final description = translate('send_invite_dialog.pin_description'); final description = translate('send_invite_dialog.pin_description');
final pin = await showDialog<String>( final pin = await showDialog<String>(
context: context, context: context,
builder: (context) => EnterPinDialog(description: description)); builder: (context) =>
EnterPinDialog(reenter: false, description: description));
if (pin == null) { if (pin == null) {
return; return;
} }
@ -66,7 +68,7 @@ class SendInviteDialogState extends ConsumerState<SendInviteDialog> {
final matchpin = await showDialog<String>( final matchpin = await showDialog<String>(
context: context, context: context,
builder: (context) => EnterPinDialog( builder: (context) => EnterPinDialog(
matchPin: pin, reenter: true,
description: description, description: description,
)); ));
if (matchpin == null) { if (matchpin == null) {
@ -91,11 +93,42 @@ class SendInviteDialogState extends ConsumerState<SendInviteDialog> {
} }
Future<void> _onPasswordEncryptionSelected(bool selected) async { Future<void> _onPasswordEncryptionSelected(bool selected) async {
setState(() { final description = translate('send_invite_dialog.password_description');
if (selected) { final password = await showDialog<String>(
context: context,
builder: (context) => EnterPasswordDialog(description: description));
if (password == null) {
return;
}
// ignore: use_build_context_synchronously
if (!context.mounted) {
return;
}
final matchpass = await showDialog<String>(
context: context,
builder: (context) => EnterPasswordDialog(
matchPass: password,
description: description,
));
if (matchpass == null) {
return;
} else if (password == matchpass) {
setState(() {
_encryptionKeyType = EncryptionKeyType.password; _encryptionKeyType = EncryptionKeyType.password;
_encryptionKey = password;
});
} else {
// ignore: use_build_context_synchronously
if (!context.mounted) {
return;
} }
}); showErrorToast(
context, translate('send_invite_dialog.password_does_not_match'));
setState(() {
_encryptionKeyType = EncryptionKeyType.none;
_encryptionKey = '';
});
}
} }
Future<void> _onGenerateButtonPressed() async { Future<void> _onGenerateButtonPressed() async {

View File

@ -1,2 +0,0 @@
export 'loggy.dart';
export 'state_logger.dart';

View File

@ -1,104 +0,0 @@
import 'dart:io' show Platform;
import 'package:ansicolor/ansicolor.dart';
import 'package:flutter/foundation.dart';
import 'package:loggy/loggy.dart';
import '../veilid_support/veilid_support.dart';
String wrapWithLogColor(LogLevel? level, String text) {
// XXX: https://github.com/flutter/flutter/issues/64491
if (!kIsWeb && Platform.isIOS) {
return text;
}
if (level == null) {
return text;
}
final pen = AnsiPen();
ansiColorDisabled = false;
switch (level) {
case LogLevel.error:
pen
..reset()
..red(bold: true);
return pen(text);
case LogLevel.warning:
pen
..reset()
..yellow(bold: true);
return pen(text);
case LogLevel.info:
pen
..reset()
..white(bold: true);
return pen(text);
case LogLevel.debug:
pen
..reset()
..green(bold: true);
return pen(text);
case traceLevel:
pen
..reset()
..blue(bold: true);
return pen(text);
}
return text;
}
extension PrettyPrintLogRecord on LogRecord {
String pretty() {
final lstr =
wrapWithLogColor(level, '[${level.toString().substring(0, 1)}]');
return '$lstr $message';
}
}
class CallbackPrinter extends LoggyPrinter {
CallbackPrinter() : super();
void Function(LogRecord)? callback;
@override
void onLog(LogRecord record) {
debugPrint(record.pretty());
callback?.call(record);
}
void setCallback(void Function(LogRecord)? cb) {
callback = cb;
}
}
CallbackPrinter globalTerminalPrinter = CallbackPrinter();
LogOptions getLogOptions(LogLevel? level) => LogOptions(
level ?? LogLevel.all,
stackTraceLevel: LogLevel.error,
);
class RootLoggy implements LoggyType {
@override
Loggy<RootLoggy> get loggy => Loggy<RootLoggy>('');
}
Loggy get log => Loggy<RootLoggy>('veilidchat');
void initLoggy() {
Loggy.initLoggy(
logPrinter: globalTerminalPrinter,
logOptions: getLogOptions(null),
);
// ignore: do_not_use_environment
const isTrace = String.fromEnvironment('LOG_TRACE') != '';
LogLevel logLevel;
if (isTrace) {
logLevel = traceLevel;
} else {
logLevel = kDebugMode ? LogLevel.debug : LogLevel.info;
}
Loggy('').level = getLogOptions(logLevel);
}

View File

@ -1,22 +0,0 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'loggy.dart';
class StateLogger extends ProviderObserver {
const StateLogger();
@override
void didUpdateProvider(
ProviderBase<Object?> provider,
Object? previousValue,
Object? newValue,
ProviderContainer container,
) {
log.debug('''
{
provider: ${provider.name ?? provider.runtimeType},
oldValue: $previousValue,
newValue: $newValue
}
''');
super.didUpdateProvider(provider, previousValue, newValue, container);
}
}

View File

@ -7,9 +7,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_translate/flutter_translate.dart'; import 'package:flutter_translate/flutter_translate.dart';
import 'app.dart'; import 'app.dart';
import 'log/log.dart';
import 'providers/window_control.dart'; import 'providers/window_control.dart';
import 'tools/theme_service.dart'; import 'tools/tools.dart';
import 'veilid_init.dart'; import 'veilid_init.dart';
void main() async { void main() async {

View File

@ -2,8 +2,8 @@ import 'dart:async';
import 'package:veilid/veilid.dart'; import 'package:veilid/veilid.dart';
import 'log/log.dart';
import 'providers/connection_state.dart'; import 'providers/connection_state.dart';
import 'tools/tools.dart';
import 'veilid_support/src/config.dart'; import 'veilid_support/src/config.dart';
import 'veilid_support/src/veilid_log.dart'; import 'veilid_support/src/veilid_log.dart';

View File

@ -15,7 +15,6 @@ import '../proto/proto.dart'
ContactResponse, ContactResponse,
SignedContactInvitation, SignedContactInvitation,
SignedContactResponse; SignedContactResponse;
import '../log/log.dart';
import '../tools/tools.dart'; import '../tools/tools.dart';
import '../veilid_support/veilid_support.dart'; import '../veilid_support/veilid_support.dart';
import 'account.dart'; import 'account.dart';
@ -345,7 +344,7 @@ Future<ValidContactInvitation?> validateContactInvitation(
final contactRequestInboxKey = final contactRequestInboxKey =
proto.TypedKeyProto.fromProto(contactInvitation.contactRequestInboxKey); proto.TypedKeyProto.fromProto(contactInvitation.contactRequestInboxKey);
late final ValidContactInvitation out; ValidContactInvitation? out;
final pool = await DHTRecordPool.instance(); final pool = await DHTRecordPool.instance();
final cs = await pool.veilid.getCryptoSystem(contactRequestInboxKey.kind); final cs = await pool.veilid.getCryptoSystem(contactRequestInboxKey.kind);
@ -365,14 +364,20 @@ Future<ValidContactInvitation?> validateContactInvitation(
// Decrypt contact request private // Decrypt contact request private
final encryptionKeyType = final encryptionKeyType =
EncryptionKeyType.fromProto(contactRequest!.encryptionKeyType); EncryptionKeyType.fromProto(contactRequest!.encryptionKeyType);
final writerSecret = await getEncryptionKeyCallback(cs, encryptionKeyType, late final SharedSecret? writerSecret;
Uint8List.fromList(contactInvitation.writerSecret)); try {
writerSecret = await getEncryptionKeyCallback(cs, encryptionKeyType,
Uint8List.fromList(contactInvitation.writerSecret));
} on Exception catch (_) {
throw ContactInviteInvalidKeyException(encryptionKeyType);
}
if (writerSecret == null) { if (writerSecret == null) {
return null; return null;
} }
final contactRequestPrivateBytes = await cs.decryptAeadWithNonce( final contactRequestPrivateBytes = await cs.decryptAeadWithNonce(
Uint8List.fromList(contactRequest.private), writerSecret); Uint8List.fromList(contactRequest.private), writerSecret);
final contactRequestPrivate = final contactRequestPrivate =
proto.ContactRequestPrivate.fromBuffer(contactRequestPrivateBytes); proto.ContactRequestPrivate.fromBuffer(contactRequestPrivateBytes);
final contactIdentityMasterRecordKey = proto.TypedKeyProto.fromProto( final contactIdentityMasterRecordKey = proto.TypedKeyProto.fromProto(
@ -385,12 +390,8 @@ Future<ValidContactInvitation?> validateContactInvitation(
// Verify // Verify
final signature = proto.SignatureProto.fromProto( final signature = proto.SignatureProto.fromProto(
signedContactInvitation.identitySignature); signedContactInvitation.identitySignature);
try { await cs.verify(contactIdentityMaster.identityPublicKey,
await cs.verify(contactIdentityMaster.identityPublicKey, contactInvitationBytes, signature);
contactInvitationBytes, signature);
} on Exception catch (_) {
throw ContactInviteInvalidKeyException(encryptionKeyType);
}
final writer = KeyPair( final writer = KeyPair(
key: proto.CryptoKeyProto.fromProto(contactRequestPrivate.writerKey), key: proto.CryptoKeyProto.fromProto(contactRequestPrivate.writerKey),

View File

@ -6,7 +6,7 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../proto/proto.dart' as proto; import '../proto/proto.dart' as proto;
import '../proto/proto.dart' show Conversation, Message; import '../proto/proto.dart' show Conversation, Message;
import '../log/loggy.dart'; import '../tools/tools.dart';
import '../veilid_init.dart'; import '../veilid_init.dart';
import '../veilid_support/veilid_support.dart'; import '../veilid_support/veilid_support.dart';
import 'account.dart'; import 'account.dart';

View File

@ -5,7 +5,6 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../entities/entities.dart'; import '../entities/entities.dart';
import '../proto/proto.dart' as proto; import '../proto/proto.dart' as proto;
import '../log/loggy.dart';
import '../tools/tools.dart'; import '../tools/tools.dart';
import '../veilid_init.dart'; import '../veilid_init.dart';
import '../veilid_support/veilid_support.dart'; import '../veilid_support/veilid_support.dart';

View File

@ -4,7 +4,6 @@ import 'package:fast_immutable_collections/fast_immutable_collections.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../entities/entities.dart'; import '../entities/entities.dart';
import '../log/loggy.dart';
import '../tools/tools.dart'; import '../tools/tools.dart';
import '../veilid_init.dart'; import '../veilid_init.dart';
import '../veilid_support/veilid_support.dart'; import '../veilid_support/veilid_support.dart';

View File

@ -1,8 +1,10 @@
export 'animations.dart'; export 'animations.dart';
export 'external_stream_state.dart'; export 'external_stream_state.dart';
export 'loggy.dart';
export 'phono_byte.dart'; export 'phono_byte.dart';
export 'radix_generator.dart'; export 'radix_generator.dart';
export 'responsive.dart'; export 'responsive.dart';
export 'secret_crypto.dart'; export 'secret_crypto.dart';
export 'state_logger.dart';
export 'theme_service.dart'; export 'theme_service.dart';
export 'widget_helpers.dart'; export 'widget_helpers.dart';