Skip to content

Commit 14f6753

Browse files
committed
fix: revise api key handling
1 parent a7d5b06 commit 14f6753

File tree

5 files changed

+112
-46
lines changed

5 files changed

+112
-46
lines changed

packages/dart/npt_flutter/lib/args.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import 'dart:convert' show jsonDecode;
1+
import 'dart:io' show exit;
22

33
import 'package:args/args.dart' show ArgParser, ArgResults;
44
import 'package:npt_flutter/constants.dart';
55

66
ArgParser createArgParser() {
77
var parser = ArgParser();
8+
parser.addFlag("help", abbr: "h");
89
parser.addMultiOption(
910
"register-root",
1011
help:
@@ -33,6 +34,11 @@ ArgResults parseArgsAndHandleConstants(ArgParser parser, List<String> args) {
3334
rethrow;
3435
}
3536

37+
if (results["help"]) {
38+
// ignore: avoid_print
39+
print(parser.usage);
40+
exit(0);
41+
}
3642
if (results["include-default-roots"]) {
3743
Constants.registerDefaultRootDomains();
3844
}
@@ -66,6 +72,7 @@ ArgResults parseArgsAndHandleConstants(ArgParser parser, List<String> args) {
6672
description: root["description"]!,
6773
registrarUrl:
6874
(root["registrar-url"] is String) ? root["registrar-url"] : null,
75+
apiKey: null,
6976
));
7077
}
7178

packages/dart/npt_flutter/lib/constants.dart

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ import 'package:npt_flutter/localization/app_localizations.dart';
77
typedef RootDomainMetadata = ({
88
dynamic description,
99
String? registrarUrl,
10+
String? apiKey,
1011
});
1112
typedef RootDomainMap = Map<String, RootDomainMetadata>;
1213

1314
typedef ResolvedRootDomainMetadata = ({
1415
String description,
1516
String? registrarUrl,
17+
String? apiKey,
1618
});
1719
typedef ResolvedRootDomainMap = Map<String, ResolvedRootDomainMetadata>;
1820

@@ -37,25 +39,30 @@ class Constants {
3739
return dotenv.env["APP_API_KEY"];
3840
}
3941

42+
static Future<String?> getApiKey(String? registrarUrl) async {
43+
if (registrarUrl == null) return null;
44+
await loadDotenv();
45+
String key = "API_KEY_${registrarUrl.toUpperCase().replaceAll(".", "_")}";
46+
return dotenv.env[key];
47+
}
48+
4049
// Root Domain configuration
4150

4251
// description may be a String or String Function(BuildContext)
4352
static final RootDomainMap _rootDomainMap = {};
44-
Map<String, String> apis = {
45-
"root.atsign.org": "my.atsign.com",
46-
"root.atsign.wtf": "my.atsign.wtf",
47-
};
4853

4954
static void registerDefaultRootDomains() {
5055
registerRootDomain('root.atsign.org', (
5156
description: (BuildContext context) =>
5257
AppLocalizations.of(context)!.rootDomainDefault,
53-
registrarUrl: "my.atsign.com"
58+
registrarUrl: "my.atsign.com",
59+
apiKey: null,
5460
));
5561
registerRootDomain('vip.ve.atsign.zone', (
5662
description: (BuildContext context) =>
5763
AppLocalizations.of(context)!.rootDomainDemo,
5864
registrarUrl: null,
65+
apiKey: null, // injected via .env file
5966
));
6067
}
6168

@@ -67,13 +74,19 @@ class Constants {
6774
static bool rootDomainsIsEmpty() => _rootDomainMap.isEmpty;
6875
static ResolvedRootDomainMap getRootDomains(BuildContext context) {
6976
return _rootDomainMap.map((k, v) {
77+
late String desc;
78+
var reg = v.registrarUrl;
79+
var api = v.apiKey ?? getApiKey(reg);
7080
if (v.description is String Function(BuildContext)) {
71-
v = (
72-
description: v.description.call(context),
73-
registrarUrl: v.registrarUrl,
74-
) as ResolvedRootDomainMetadata;
81+
desc = v.description.call(context);
82+
} else {
83+
desc = v.description as String;
7584
}
76-
return MapEntry(k, v as ResolvedRootDomainMetadata);
85+
return MapEntry(
86+
k,
87+
(description: desc, registrarUrl: reg, apiKey: api)
88+
as ResolvedRootDomainMetadata,
89+
);
7790
});
7891
}
7992

packages/dart/npt_flutter/lib/features/onboarding/widgets/onboarding_button.dart

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,10 @@ class _OnboardingButtonState extends State<OnboardingButton> {
129129
bool isFromInitState = false}) async {
130130
var atSigns =
131131
await KeyChainManager.getInstance().getAtSignListFromKeychain();
132-
var apiKey = await Constants.appAPIKey;
132+
final regUrl =
133+
Constants.getRootDomains(App.navState.currentContext!)[rootDomain]
134+
?.registrarUrl;
135+
var apiKey = await Constants.getApiKey(regUrl);
133136
var config = AtOnboardingConfig(
134137
atClientPreference:
135138
await AtClientMethods.loadAtClientPreference(rootDomain),
@@ -218,10 +221,17 @@ class _OnboardingButtonState extends State<OnboardingButton> {
218221
case AtSignStatus.unavailable:
219222
case AtSignStatus.teapot:
220223
// When onboarding from teapot, set backup status to false (not atKeys not backed up)
221-
App.navState.currentContext!
222-
.read<BackupKeyCubit>()
223-
.setBackupKeyStatus(false);
224-
final apiKey = await Constants.appAPIKey;
224+
var context = App.navState.currentContext!;
225+
// ignore: use_build_context_synchronously
226+
context.read<BackupKeyCubit>().setBackupKeyStatus(false);
227+
// ignore: use_build_context_synchronously
228+
final rootDomain = context
229+
.read<OnboardingCubit>()
230+
.getRootDomain(); // Or get from your state/cubit if needed
231+
final regUrl =
232+
// ignore: use_build_context_synchronously
233+
Constants.getRootDomains(context)[rootDomain]?.registrarUrl;
234+
final apiKey = await Constants.getApiKey(regUrl);
225235

226236
if (apiKey == null) {
227237
result = AtOnboardingResult.error(
@@ -238,10 +248,8 @@ class _OnboardingButtonState extends State<OnboardingButton> {
238248
.locale);
239249
if (!mounted) return null;
240250

241-
var regUrl = Constants.getRootDomains(
242-
context)[util.config.atClientPreference.rootDomain]
243-
?.registrarUrl;
244251
result = await showDialog<AtOnboardingResult>(
252+
// ignore: use_build_context_synchronously
245253
context: context,
246254
barrierDismissible: false,
247255
builder: (context) => (regUrl == null)

packages/dart/npt_flutter/lib/widgets/custom_text_button.dart

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,23 @@ class CustomTextButton extends StatelessWidget {
4545
type = CustomListTileType.privacyPolicy;
4646

4747
const CustomTextButton.backUpYourKey(
48-
{this.iconData = Icons.bookmark_outline, this.type = CustomListTileType.backupYourKey, super.key});
48+
{this.iconData = Icons.bookmark_outline,
49+
this.type = CustomListTileType.backupYourKey,
50+
super.key});
4951

5052
const CustomTextButton.resetAtsign(
51-
{this.iconData = Icons.rotate_right, this.type = CustomListTileType.resetAtsign, super.key});
53+
{this.iconData = Icons.rotate_right,
54+
this.type = CustomListTileType.resetAtsign,
55+
super.key});
5256
const CustomTextButton.signOut(
53-
{this.iconData = Icons.logout_outlined, this.type = CustomListTileType.signOut, super.key});
57+
{this.iconData = Icons.logout_outlined,
58+
this.type = CustomListTileType.signOut,
59+
super.key});
5460

5561
const CustomTextButton.feedback(
56-
{this.iconData = Icons.feedback_outlined, this.type = CustomListTileType.feedback, super.key});
62+
{this.iconData = Icons.feedback_outlined,
63+
this.type = CustomListTileType.feedback,
64+
super.key});
5765

5866
final IconData iconData;
5967

@@ -73,17 +81,20 @@ class CustomTextButton extends StatelessWidget {
7381
path: 'info@noports.com',
7482
);
7583
if (!await launchUrl(emailUri)) {
76-
CustomSnackBar.notification(content: strings.noEmailClientAvailable);
84+
CustomSnackBar.notification(
85+
content: strings.noEmailClientAvailable);
7786
}
7887
break;
7988
case CustomListTileType.discord:
80-
final Uri url = Uri.parse('https://discord.gg/atsign-778383211214536722');
89+
final Uri url =
90+
Uri.parse('https://discord.gg/atsign-778383211214536722');
8191
if (!await launchUrl(url)) {
8292
throw Exception('Could not launch $url');
8393
}
8494
break;
8595
case CustomListTileType.faq:
86-
final Uri url = Uri.parse('https://docs.noports.com/ssh-no-ports/faq');
96+
final Uri url =
97+
Uri.parse('https://docs.noports.com/ssh-no-ports/faq');
8798
if (!await launchUrl(url)) {
8899
throw Exception('Could not launch $url');
89100
}
@@ -100,23 +111,25 @@ class CustomTextButton extends StatelessWidget {
100111
}
101112
break;
102113
case CustomListTileType.resetAtsign:
103-
final futurePreference = await AtClientMethods.loadAtClientPreference(rootDomain!);
104-
final apiKey = await Constants.appAPIKey;
114+
final futurePreference =
115+
await AtClientMethods.loadAtClientPreference(rootDomain!);
105116
if (context.mounted) {
106117
final result = await AtOnboarding.reset(
107118
context: context,
108119
config: AtOnboardingConfig(
109120
atClientPreference: futurePreference,
110121
rootEnvironment: RootEnvironment.Testing,
111122
domain: rootDomain,
112-
appAPIKey: apiKey,
123+
appAPIKey: null,
113124
),
114125
);
115-
final OnboardingService onboardingService = OnboardingService.getInstance();
126+
final OnboardingService onboardingService =
127+
OnboardingService.getInstance();
116128

117129
if (context.mounted && result == AtOnboardingResetResult.success) {
118130
onboardingService.setAtsign = null;
119-
Navigator.of(context, rootNavigator: true).pushNamedAndRemoveUntil(
131+
Navigator.of(context, rootNavigator: true)
132+
.pushNamedAndRemoveUntil(
120133
Routes.onboarding,
121134
(route) => false,
122135
);
@@ -132,7 +145,8 @@ class CustomTextButton extends StatelessWidget {
132145
);
133146

134147
if (!await launchUrl(emailUri)) {
135-
CustomSnackBar.notification(content: strings.noEmailClientAvailable);
148+
CustomSnackBar.notification(
149+
content: strings.noEmailClientAvailable);
136150
}
137151
break;
138152

@@ -176,9 +190,11 @@ class CustomTextButton extends StatelessWidget {
176190
}
177191

178192
if (type == CustomListTileType.resetAtsign) {
179-
return BlocBuilder<OnboardingCubit, AtsignInformation>(builder: (context, atsignInformation) {
193+
return BlocBuilder<OnboardingCubit, AtsignInformation>(
194+
builder: (context, atsignInformation) {
180195
return Padding(
181-
padding: const EdgeInsets.only(left: Sizes.p30, right: Sizes.p30, bottom: Sizes.p10),
196+
padding: const EdgeInsets.only(
197+
left: Sizes.p30, right: Sizes.p30, bottom: Sizes.p10),
182198
child: TextButton.icon(
183199
label: Text(getTitle(strings)),
184200
onPressed: () {
@@ -192,7 +208,8 @@ class CustomTextButton extends StatelessWidget {
192208
});
193209
}
194210
return Padding(
195-
padding: const EdgeInsets.only(left: Sizes.p30, right: Sizes.p30, bottom: Sizes.p10),
211+
padding: const EdgeInsets.only(
212+
left: Sizes.p30, right: Sizes.p30, bottom: Sizes.p10),
196213
child: TextButton.icon(
197214
label: Text(getTitle(strings)),
198215
onPressed: () {

packages/dart/npt_flutter/lib/widgets/switch_atsign_button.dart

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,11 @@ class SwitchAtsignButton extends StatelessWidget {
4242
// Select atsign to switch
4343
final atSignList = await KeychainUtil.getAtsignList();
4444
// set to dynamic to handle being popped by the AppBar back button which returns a 'StatefulElement'
45+
if (!context.mounted) return;
4546
final selectedAtSign = await showMenu<dynamic>(
4647
context: context,
47-
position:
48-
const RelativeRect.fromLTRB(-1000, 1, 0, 0), // You may want to calculate this based on tap position
48+
position: const RelativeRect.fromLTRB(-1000, 1, 0,
49+
0), // You may want to calculate this based on tap position
4950
shape: RoundedRectangleBorder(
5051
side: const BorderSide(
5152
color: AppColor.primaryColor,
@@ -70,7 +71,14 @@ class SwitchAtsignButton extends StatelessWidget {
7071
// Check for connected profiles before switching
7172
var isProfileConnected = false;
7273

73-
if (context.read<ProfilesRunningCubit>().state.socketConnectors.keys.toSet().isNotEmpty) {
74+
if (!context.mounted) return;
75+
if (context
76+
.read<ProfilesRunningCubit>()
77+
.state
78+
.socketConnectors
79+
.keys
80+
.toSet()
81+
.isNotEmpty) {
7482
log('tap triggered more than once');
7583
isProfileConnected = await showDialog(
7684
barrierDismissible: false,
@@ -84,21 +92,29 @@ class SwitchAtsignButton extends StatelessWidget {
8492
}
8593
final currentContext = App.navState.currentContext!;
8694

87-
final rootDomain =
88-
currentContext.read<OnboardingCubit>().getRootDomain(); // Or get from your state/cubit if needed
89-
final atClientPreference = await AtClientMethods.loadAtClientPreference(rootDomain);
95+
if (!currentContext.mounted) return;
96+
final rootDomain = currentContext
97+
.read<OnboardingCubit>()
98+
.getRootDomain(); // Or get from your state/cubit if needed
99+
final atClientPreference =
100+
await AtClientMethods.loadAtClientPreference(rootDomain);
90101
await preSignout();
91-
final result = await AtOnboarding.changePrimaryAtsign(atsign: selectedAtSign);
102+
final result =
103+
await AtOnboarding.changePrimaryAtsign(atsign: selectedAtSign);
92104

105+
if (!currentContext.mounted) return;
106+
final regUrl = Constants.getRootDomains(currentContext)[rootDomain]
107+
?.registrarUrl;
93108
if (result) {
94109
final onboardingResult = await AtOnboarding.onboard(
95110
atsign: selectedAtSign,
111+
// ignore: use_build_context_synchronously
96112
context: currentContext,
97113
config: AtOnboardingConfig(
98114
atClientPreference: atClientPreference,
99115
domain: rootDomain,
100116
rootEnvironment: RootEnvironment.Production,
101-
appAPIKey: await Constants.appAPIKey,
117+
appAPIKey: await Constants.getApiKey(regUrl),
102118
),
103119
);
104120
log("onboarding result: $onboardingResult");
@@ -130,7 +146,9 @@ class _HoverableMenuItemState extends State<_HoverableMenuItem> {
130146
onEnter: (_) => setState(() => _hovering = true),
131147
onExit: (_) => setState(() => _hovering = false),
132148
child: Container(
133-
color: _hovering ? AppColor.primaryColorButtonBackgroundAlt : Colors.transparent,
149+
color: _hovering
150+
? AppColor.primaryColorButtonBackgroundAlt
151+
: Colors.transparent,
134152
child: Column(
135153
crossAxisAlignment: CrossAxisAlignment.start,
136154
children: [
@@ -141,10 +159,13 @@ class _HoverableMenuItemState extends State<_HoverableMenuItem> {
141159
children: [
142160
RichText(
143161
text: TextSpan(children: [
144-
const TextSpan(text: '@', style: TextStyle(color: AppColor.primaryColor)),
162+
const TextSpan(
163+
text: '@',
164+
style: TextStyle(color: AppColor.primaryColor)),
145165
TextSpan(
146166
text: widget.atSign.split('@').last,
147-
style: Theme.of(context).textTheme.bodyMedium?.copyWith(),
167+
style:
168+
Theme.of(context).textTheme.bodyMedium?.copyWith(),
148169
),
149170
]),
150171
),

0 commit comments

Comments
 (0)