Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: activation from non-teapot status #1608

Merged
merged 1 commit into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import 'dart:convert';

import 'package:at_onboarding_flutter/at_onboarding_flutter.dart';
import 'package:at_server_status/at_server_status.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:npt_flutter/app.dart';
import 'package:npt_flutter/features/onboarding/util/activate_util.dart';
import 'package:npt_flutter/features/onboarding/util/onboarding_util.dart';
import 'package:npt_flutter/widgets/spinner.dart';
import 'package:pin_code_fields/pin_code_fields.dart';

Expand All @@ -14,12 +16,16 @@ class ActivateAtsignDialog extends StatefulWidget {
final String apiKey;
final String atSign;
final AtOnboardingConfig config;
final bool waitForTeapot;
final NoPortsOnboardingUtil onboardingUtil;
const ActivateAtsignDialog({
super.key,
required this.atSign,
required this.apiKey,
required this.config,
required this.registrarUrl,
required this.waitForTeapot,
required this.onboardingUtil,
});

@override
Expand Down Expand Up @@ -170,6 +176,10 @@ class _ActivateAtsignDialogState extends State<ActivateAtsignDialog> {
status = ActivationStatus.activating;
});

// This does two things:
// 1. If the atSign is not in teapot, it will (assuming success)
// start activating the atSign as if you hit "Activate" in the dashboard
// 2. It will trigger the email/text OTP
var (:cramkey, :errorMessage) = await util.verifyActivation(
atsign: widget.atSign,
otp: pinController.text,
Expand All @@ -191,6 +201,41 @@ class _ActivateAtsignDialogState extends State<ActivateAtsignDialog> {
return;
}

// If the atSign wasn't in teapot when we arrived at this screen,
// we should wait until the atSign is in teapot
if (widget.waitForTeapot) {
int round = 1;
getStatus() async {
return (await widget.onboardingUtil.atServerStatus(widget.atSign)).status();
}

AtSignStatus? atSignStatus = await getStatus();
while (atSignStatus != AtSignStatus.teapot) {
// 6 * 5 = 30 seconds
// 12 * 5 = 60 seconds
if (round > 12) {
break;
}
await Future.delayed(const Duration(seconds: 5));
round++;
atSignStatus = (await getStatus());
}

// If the Atsign is still not in teapot after the waiting period
// Then return an error
if (atSignStatus != AtSignStatus.teapot) {
if (mounted) {
Navigator.of(context).pop(
AtOnboardingResult.error(message: strings.errorAuthenticationTimedOut),
);
}
return;
}
}

// Assuming we got the correct OTP, and we are in teapot,
// being activation: Generating keys, bootstrapping server, etc.
// i.e. all the stuff to go from teapot -> activated
var result = await util.onboardFromCramKey(
atsign: widget.atSign,
cramkey: cramkey,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,7 @@ class _OnboardingButtonState extends State<OnboardingButton> {
bool shouldOnboard = await selectAtsign();
if (shouldOnboard && context.mounted) {
var atsignInformation = context.read<OnboardingCubit>().state;
onboard(
atsign: atsignInformation.atSign,
rootDomain: atsignInformation.rootDomain);
onboard(atsign: atsignInformation.atSign, rootDomain: atsignInformation.rootDomain);
}
},
icon: PhosphorIcon(PhosphorIcons.arrowUpRight()),
Expand All @@ -75,10 +73,8 @@ class _OnboardingButtonState extends State<OnboardingButton> {
),
iconAlignment: IconAlignment.end,
),
_OnboardingButtonStatus.picking =>
Text(strings.onboardingButtonStatusPicking),
_OnboardingButtonStatus.processingFile =>
Text(strings.onboardingButtonStatusProcessingFile),
_OnboardingButtonStatus.picking => Text(strings.onboardingButtonStatusPicking),
_OnboardingButtonStatus.processingFile => Text(strings.onboardingButtonStatusProcessingFile),
};
}

Expand Down Expand Up @@ -109,12 +105,8 @@ class _OnboardingButtonState extends State<OnboardingButton> {
return results ?? false;
}

Future<void> onboard(
{required String atsign,
required String rootDomain,
bool isFromInitState = false}) async {
var atSigns =
await KeyChainManager.getInstance().getAtSignListFromKeychain();
Future<void> onboard({required String atsign, required String rootDomain, bool isFromInitState = false}) async {
var atSigns = await KeyChainManager.getInstance().getAtSignListFromKeychain();
var apiKey = await Constants.appAPIKey;
var config = AtOnboardingConfig(
atClientPreference: await loadAtClientPreference(rootDomain),
Expand Down Expand Up @@ -163,8 +155,7 @@ class _OnboardingButtonState extends State<OnboardingButton> {
SnackBar(
backgroundColor: Colors.red,
content: Text(
onboardingResult?.message ??
AppLocalizations.of(context)!.onboardingError,
onboardingResult?.message ?? AppLocalizations.of(context)!.onboardingError,
),
),
);
Expand All @@ -174,8 +165,7 @@ class _OnboardingButtonState extends State<OnboardingButton> {
}
}

Future<AtOnboardingResult?> handleAtsignByStatus(
String atsign, NoPortsOnboardingUtil util) async {
Future<AtOnboardingResult?> handleAtsignByStatus(String atsign, NoPortsOnboardingUtil util) async {
AtStatus status;

try {
Expand All @@ -187,8 +177,8 @@ class _OnboardingButtonState extends State<OnboardingButton> {
}
AtOnboardingResult? result;
if (!mounted) return null;

switch (status.status()) {
var initialStatus = status.status();
switch (initialStatus) {
// Automatically start activation with the already entered atSign
case AtSignStatus.unavailable:
case AtSignStatus.teapot:
Expand All @@ -201,12 +191,9 @@ class _OnboardingButtonState extends State<OnboardingButton> {
break;
}
AtOnboardingConstants.setApiKey(apiKey);
AtOnboardingConstants.rootDomain =
util.config.atClientPreference.rootDomain;
AtOnboardingConstants.rootDomain = util.config.atClientPreference.rootDomain;

await AtOnboardingLocalizations.load(
LanguageUtil.getLanguageFromLocale(Locale(Platform.localeName))
.locale);
await AtOnboardingLocalizations.load(LanguageUtil.getLanguageFromLocale(Locale(Platform.localeName)).locale);
if (!mounted) return null;
Map<String, String> apis = {
"root.atsign.org": "my.atsign.com",
Expand All @@ -227,19 +214,18 @@ class _OnboardingButtonState extends State<OnboardingButton> {
apiKey: apiKey,
config: util.config,
registrarUrl: regUrl,
onboardingUtil: util,
waitForTeapot: initialStatus != AtSignStatus.teapot,
),
);

if (result is AtOnboardingResult) {
//Update primary atsign after onboard success
if (result.status == AtOnboardingResultStatus.success &&
result.atsign != null) {
if (result.status == AtOnboardingResultStatus.success && result.atsign != null) {
var onboardingService = OnboardingService.getInstance();
bool res = await onboardingService.changePrimaryAtsign(
atsign: result.atsign!);
bool res = await onboardingService.changePrimaryAtsign(atsign: result.atsign!);
if (!res) {
result = AtOnboardingResult.error(
message: strings.errorSwitchAtSignFailed);
result = AtOnboardingResult.error(message: strings.errorSwitchAtSignFailed);
}
}
}
Expand All @@ -262,8 +248,7 @@ class _OnboardingButtonState extends State<OnboardingButton> {
return result;
}

Future<AtOnboardingResult?> handleFileUploadStatusStream(
Stream<FileUploadStatus> statusStream, String atsign) async {
Future<AtOnboardingResult?> handleFileUploadStatusStream(Stream<FileUploadStatus> statusStream, String atsign) async {
AtOnboardingResult? result;
outer:
await for (FileUploadStatus status in statusStream) {
Expand Down
4 changes: 2 additions & 2 deletions packages/dart/npt_flutter/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.1.4+4
version: 1.1.5+5
msix_config:
display_name: "NoPorts Desktop"
publisher_display_name: Atsign Inc
identity_name: TheCompany.NoPortsDesktop
publisher: CN=BBFE1D0B-F713-4C7F-B375-5EA851CBB1FF
msix_version: 1.1.4.4
msix_version: 1.1.5.0
logo_path: "assets/logo.png"
capabilities: internetClient
store: true
Expand Down
Loading