mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-31 06:55:59 +00:00
.well-known domain support (#1956)
* add well-known setting [wip] * should work * fix * minor fix (tested and working)
This commit is contained in:
parent
f072bc8dce
commit
60e7dcffa9
9 changed files with 147 additions and 1 deletions
|
@ -293,6 +293,7 @@ class BackupService {
|
|||
final lookupsUnstoppableDomains = data[PreferencesKey.lookupsUnstoppableDomains] as bool?;
|
||||
final lookupsOpenAlias = data[PreferencesKey.lookupsOpenAlias] as bool?;
|
||||
final lookupsENS = data[PreferencesKey.lookupsENS] as bool?;
|
||||
final lookupsWellKnown = data[PreferencesKey.lookupsWellKnown] as bool?;
|
||||
final syncAll = data[PreferencesKey.syncAllKey] as bool?;
|
||||
final syncMode = data[PreferencesKey.syncModeKey] as int?;
|
||||
final autoGenerateSubaddressStatus =
|
||||
|
@ -403,6 +404,9 @@ class BackupService {
|
|||
|
||||
if (lookupsENS != null) await _sharedPreferences.setBool(PreferencesKey.lookupsENS, lookupsENS);
|
||||
|
||||
if (lookupsWellKnown != null)
|
||||
await _sharedPreferences.setBool(PreferencesKey.lookupsWellKnown, lookupsWellKnown);
|
||||
|
||||
if (syncAll != null) await _sharedPreferences.setBool(PreferencesKey.syncAllKey, syncAll);
|
||||
|
||||
if (syncMode != null) await _sharedPreferences.setInt(PreferencesKey.syncModeKey, syncMode);
|
||||
|
@ -542,6 +546,8 @@ class BackupService {
|
|||
_sharedPreferences.getBool(PreferencesKey.lookupsUnstoppableDomains),
|
||||
PreferencesKey.lookupsOpenAlias: _sharedPreferences.getBool(PreferencesKey.lookupsOpenAlias),
|
||||
PreferencesKey.lookupsENS: _sharedPreferences.getBool(PreferencesKey.lookupsENS),
|
||||
PreferencesKey.lookupsWellKnown:
|
||||
_sharedPreferences.getBool(PreferencesKey.lookupsWellKnown),
|
||||
PreferencesKey.syncModeKey: _sharedPreferences.getInt(PreferencesKey.syncModeKey),
|
||||
PreferencesKey.syncAllKey: _sharedPreferences.getBool(PreferencesKey.syncAllKey),
|
||||
PreferencesKey.autoGenerateSubaddressStatusKey:
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'package:cake_wallet/entities/openalias_record.dart';
|
|||
import 'package:cake_wallet/entities/parsed_address.dart';
|
||||
import 'package:cake_wallet/entities/unstoppable_domain_address.dart';
|
||||
import 'package:cake_wallet/entities/emoji_string_extension.dart';
|
||||
import 'package:cake_wallet/entities/wellknown_record.dart';
|
||||
import 'package:cake_wallet/exchange/provider/thorchain_exchange.provider.dart';
|
||||
import 'package:cake_wallet/mastodon/mastodon_api.dart';
|
||||
import 'package:cake_wallet/nostr/nostr_api.dart';
|
||||
|
@ -208,6 +209,17 @@ class AddressResolver {
|
|||
}
|
||||
}
|
||||
|
||||
// .well-known scheme:
|
||||
if (text.contains('.') && text.contains('@')) {
|
||||
if (settingsStore.lookupsWellKnown) {
|
||||
final record =
|
||||
await WellKnownRecord.fetchAddressAndName(formattedName: text, currency: currency);
|
||||
if (record != null) {
|
||||
return ParsedAddress.fetchWellKnownAddress(address: record.address, name: text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!text.startsWith('@') && text.contains('@') && !text.contains('.')) {
|
||||
final bool isFioRegistered = await FioAddressProvider.checkAvail(text);
|
||||
if (isFioRegistered) {
|
||||
|
|
|
@ -12,7 +12,8 @@ enum ParseFrom {
|
|||
contact,
|
||||
mastodon,
|
||||
nostr,
|
||||
thorChain
|
||||
thorChain,
|
||||
wellKnown
|
||||
}
|
||||
|
||||
class ParsedAddress {
|
||||
|
@ -142,6 +143,14 @@ class ParsedAddress {
|
|||
);
|
||||
}
|
||||
|
||||
factory ParsedAddress.fetchWellKnownAddress({required String address, required String name}) {
|
||||
return ParsedAddress(
|
||||
addresses: [address],
|
||||
name: name,
|
||||
parseFrom: ParseFrom.wellKnown,
|
||||
);
|
||||
}
|
||||
|
||||
final List<String> addresses;
|
||||
final String name;
|
||||
final String description;
|
||||
|
|
|
@ -76,6 +76,7 @@ class PreferencesKey {
|
|||
static const lookupsUnstoppableDomains = 'looks_up_unstoppable_domain';
|
||||
static const lookupsOpenAlias = 'looks_up_open_alias';
|
||||
static const lookupsENS = 'looks_up_ens';
|
||||
static const lookupsWellKnown = 'looks_up_well_known';
|
||||
static const showCameraConsent = 'show_camera_consent';
|
||||
|
||||
static String moneroWalletUpdateV1Key(String name) =>
|
||||
|
|
92
lib/entities/wellknown_record.dart
Normal file
92
lib/entities/wellknown_record.dart
Normal file
|
@ -0,0 +1,92 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
class WellKnownRecord {
|
||||
WellKnownRecord({
|
||||
required this.address,
|
||||
required this.name,
|
||||
});
|
||||
|
||||
final String name;
|
||||
final String address;
|
||||
|
||||
static Future<String?> checkWellKnownUsername(String username, CryptoCurrency currency) async {
|
||||
String jsonLocation = "";
|
||||
switch (currency) {
|
||||
case CryptoCurrency.nano:
|
||||
jsonLocation = "nano-currency";
|
||||
break;
|
||||
// TODO: add other currencies
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
// split the string by the @ symbol:
|
||||
try {
|
||||
final List<String> splitStrs = username.split("@");
|
||||
String name = splitStrs.first.toLowerCase();
|
||||
final String domain = splitStrs.last;
|
||||
|
||||
if (splitStrs.length == 3) {
|
||||
// for username like @alice@domain.org instead of alice@domain.org
|
||||
name = splitStrs[1];
|
||||
}
|
||||
|
||||
if (name.isEmpty) {
|
||||
name = "_";
|
||||
}
|
||||
|
||||
// lookup domain/.well-known/nano-currency.json and check if it has a nano address:
|
||||
final http.Response response = await http.get(
|
||||
Uri.parse("https://$domain/.well-known/$jsonLocation.json?names=$name"),
|
||||
headers: <String, String>{"Accept": "application/json"},
|
||||
);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
return null;
|
||||
}
|
||||
final Map<String, dynamic> decoded = json.decode(response.body) as Map<String, dynamic>;
|
||||
|
||||
// Access the first element in the names array and retrieve its address
|
||||
final List<dynamic> names = decoded["names"] as List<dynamic>;
|
||||
for (final dynamic item in names) {
|
||||
if (item["name"].toLowerCase() == name) {
|
||||
return item["address"] as String;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
printV("error checking well-known username: $e");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static String formatDomainName(String name) {
|
||||
String formattedName = name;
|
||||
|
||||
if (name.contains("@")) {
|
||||
formattedName = name.replaceAll("@", ".");
|
||||
}
|
||||
|
||||
return formattedName;
|
||||
}
|
||||
|
||||
static Future<WellKnownRecord?> fetchAddressAndName({
|
||||
required String formattedName,
|
||||
required CryptoCurrency currency,
|
||||
}) async {
|
||||
String name = formattedName;
|
||||
|
||||
print("formattedName: $formattedName");
|
||||
|
||||
final address = await checkWellKnownUsername(formattedName, currency);
|
||||
|
||||
if (address == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return WellKnownRecord(address: address, name: name);
|
||||
}
|
||||
}
|
|
@ -30,6 +30,11 @@ Future<String> extractAddressFromParsed(
|
|||
content = S.of(context).extracted_address_content('${parsedAddress.name} (OpenAlias)');
|
||||
address = parsedAddress.addresses.first;
|
||||
break;
|
||||
case ParseFrom.wellKnown:
|
||||
title = S.of(context).address_detected;
|
||||
content = S.of(context).extracted_address_content('${parsedAddress.name} (Well-Known)');
|
||||
address = parsedAddress.addresses.first;
|
||||
break;
|
||||
case ParseFrom.fio:
|
||||
title = S.of(context).address_detected;
|
||||
content = S.of(context).extracted_address_content('${parsedAddress.name} (FIO)');
|
||||
|
|
|
@ -45,6 +45,10 @@ class DomainLookupsPage extends BasePage {
|
|||
title: 'Ethereum Name Service',
|
||||
value: _privacySettingsViewModel.looksUpENS,
|
||||
onValueChange: (_, bool value) => _privacySettingsViewModel.setLookupsENS(value)),
|
||||
SettingsSwitcherCell(
|
||||
title: '.well-known',
|
||||
value: _privacySettingsViewModel.looksUpWellKnown,
|
||||
onValueChange: (_, bool value) => _privacySettingsViewModel.setLookupsWellKnown(value)),
|
||||
|
||||
//if (!isHaven) it does not work correctly
|
||||
],
|
||||
|
|
|
@ -115,6 +115,7 @@ abstract class SettingsStoreBase with Store {
|
|||
required this.lookupsUnstoppableDomains,
|
||||
required this.lookupsOpenAlias,
|
||||
required this.lookupsENS,
|
||||
required this.lookupsWellKnown,
|
||||
required this.customBitcoinFeeRate,
|
||||
required this.silentPaymentsCardDisplay,
|
||||
required this.silentPaymentsAlwaysScan,
|
||||
|
@ -459,6 +460,11 @@ abstract class SettingsStoreBase with Store {
|
|||
reaction((_) => lookupsENS,
|
||||
(bool looksUpENS) => _sharedPreferences.setBool(PreferencesKey.lookupsENS, looksUpENS));
|
||||
|
||||
reaction(
|
||||
(_) => lookupsWellKnown,
|
||||
(bool looksUpWellKnown) =>
|
||||
_sharedPreferences.setBool(PreferencesKey.lookupsWellKnown, looksUpWellKnown));
|
||||
|
||||
// secure storage keys:
|
||||
reaction(
|
||||
(_) => allowBiometricalAuthentication,
|
||||
|
@ -772,6 +778,8 @@ abstract class SettingsStoreBase with Store {
|
|||
@observable
|
||||
bool lookupsENS;
|
||||
|
||||
@observable
|
||||
bool lookupsWellKnown;
|
||||
@observable
|
||||
SyncMode currentSyncMode;
|
||||
|
||||
|
@ -967,6 +975,7 @@ abstract class SettingsStoreBase with Store {
|
|||
sharedPreferences.getBool(PreferencesKey.lookupsUnstoppableDomains) ?? true;
|
||||
final lookupsOpenAlias = sharedPreferences.getBool(PreferencesKey.lookupsOpenAlias) ?? true;
|
||||
final lookupsENS = sharedPreferences.getBool(PreferencesKey.lookupsENS) ?? true;
|
||||
final lookupsWellKnown = sharedPreferences.getBool(PreferencesKey.lookupsWellKnown) ?? true;
|
||||
final customBitcoinFeeRate = sharedPreferences.getInt(PreferencesKey.customBitcoinFeeRate) ?? 1;
|
||||
final silentPaymentsCardDisplay =
|
||||
sharedPreferences.getBool(PreferencesKey.silentPaymentsCardDisplay) ?? true;
|
||||
|
@ -1245,6 +1254,7 @@ abstract class SettingsStoreBase with Store {
|
|||
lookupsUnstoppableDomains: lookupsUnstoppableDomains,
|
||||
lookupsOpenAlias: lookupsOpenAlias,
|
||||
lookupsENS: lookupsENS,
|
||||
lookupsWellKnown: lookupsWellKnown,
|
||||
customBitcoinFeeRate: customBitcoinFeeRate,
|
||||
silentPaymentsCardDisplay: silentPaymentsCardDisplay,
|
||||
silentPaymentsAlwaysScan: silentPaymentsAlwaysScan,
|
||||
|
@ -1414,6 +1424,7 @@ abstract class SettingsStoreBase with Store {
|
|||
sharedPreferences.getBool(PreferencesKey.lookupsUnstoppableDomains) ?? true;
|
||||
lookupsOpenAlias = sharedPreferences.getBool(PreferencesKey.lookupsOpenAlias) ?? true;
|
||||
lookupsENS = sharedPreferences.getBool(PreferencesKey.lookupsENS) ?? true;
|
||||
lookupsWellKnown = sharedPreferences.getBool(PreferencesKey.lookupsWellKnown) ?? true;
|
||||
customBitcoinFeeRate = sharedPreferences.getInt(PreferencesKey.customBitcoinFeeRate) ?? 1;
|
||||
silentPaymentsCardDisplay =
|
||||
sharedPreferences.getBool(PreferencesKey.silentPaymentsCardDisplay) ?? true;
|
||||
|
|
|
@ -94,6 +94,9 @@ abstract class PrivacySettingsViewModelBase with Store {
|
|||
@computed
|
||||
bool get looksUpENS => _settingsStore.lookupsENS;
|
||||
|
||||
@computed
|
||||
bool get looksUpWellKnown => _settingsStore.lookupsWellKnown;
|
||||
|
||||
bool get canUseEtherscan => _wallet.type == WalletType.ethereum;
|
||||
|
||||
bool get canUsePolygonScan => _wallet.type == WalletType.polygon;
|
||||
|
@ -130,6 +133,9 @@ abstract class PrivacySettingsViewModelBase with Store {
|
|||
@action
|
||||
void setLookupsENS(bool value) => _settingsStore.lookupsENS = value;
|
||||
|
||||
@action
|
||||
void setLookupsWellKnown(bool value) => _settingsStore.lookupsWellKnown = value;
|
||||
|
||||
@action
|
||||
void setLookupsYatService(bool value) => _settingsStore.lookupsYatService = value;
|
||||
|
||||
|
|
Loading…
Reference in a new issue