getKeyFromUserIfRequired function

Future<void> getKeyFromUserIfRequired(
  1. BuildContext context,
  2. Widget child
)

Ask for the security key from the user if the security key is not available or cannot be verfied using the verification key stored in PODs.

Implementation

Future<void> getKeyFromUserIfRequired(
  BuildContext context,
  Widget child,
) async {
  if (await KeyManager.hasSecurityKey()) {
    return;
  } else {
    // Get the webId to display in the security key prompt.

    final webId = await getWebId();

    const inputKey = 'security_key';
    final formKey = GlobalKey<FormBuilderState>();

    // The security key can only be verified by deriving it (Argon2id for
    // version 2 PODs), which is asynchronous and cannot run in a synchronous
    // form validator. So the validator only checks the field is non-empty;
    // correctness is verified on submit by `KeyManager.setSecurityKey`, which
    // throws [SecurityKeyVerificationException] when the key is wrong.

    final inputField = (
      fieldKey: inputKey,
      fieldLabel: 'Security Key',
      validateFunc: (key) => (key == null || (key as String).isEmpty)
          ? 'Please enter a key'
          : null,
    );

    // Use the unified SecurityKeyUI widget with the appropriate configuration.

    final securityKeyInput = SecurityKeyUI(
      webId: webId,
      title: 'Security Key',
      message: SecurityStrings.securityKeyPrompt,
      inputFields: [inputField],
      formKey: formKey,
      submitFunc: (formDataMap) async {
        try {
          await KeyManager.setSecurityKey(formDataMap[inputKey].toString());
        } on SecurityKeyVerificationException {
          // Wrong key: show an inline error and keep the prompt open.

          formKey.currentState?.fields[inputKey]
              ?.invalidate('Incorrect Security Key');
          return;
        }
        debugPrint('Security key saved');
        if (context.mounted) Navigator.pop(context);
      },
      child: child,
    );

    if (context.mounted) {
      await Navigator.push(
        context,
        MaterialPageRoute(builder: (context) => securityKeyInput),
      );

      // Notify the global status bar notifier that the key status may have
      // changed after the user submitted (or dismissed) the key prompt.

      await securityKeyNotifier.refreshStatus();
    }
  }
}