mirror of
https://github.com/haorendashu/nowser.git
synced 2026-01-31 07:04:28 +01:00
add buildin relay support, fix remote signer some bugs
This commit is contained in:
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +1,6 @@
|
||||
[submodule "packages/nostr_sdk"]
|
||||
path = packages/nostr_sdk
|
||||
url = git@github.com:haorendashu/nostr_sdk.git
|
||||
[submodule "packages/relay_sdk"]
|
||||
path = packages/relay_sdk
|
||||
url = git@github.com:haorendashu/relay_sdk.git
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'dart:developer';
|
||||
|
||||
import 'package:bot_toast/bot_toast.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
@@ -11,6 +12,7 @@ import 'package:nostr_sdk/utils/string_util.dart';
|
||||
import 'package:nowser/data/db.dart';
|
||||
import 'package:nowser/provider/android_signer_mixin.dart';
|
||||
import 'package:nowser/provider/app_provider.dart';
|
||||
import 'package:nowser/provider/build_in_relay_provider.dart';
|
||||
import 'package:nowser/provider/key_provider.dart';
|
||||
import 'package:nowser/provider/permission_check_mixin.dart';
|
||||
import 'package:nowser/provider/web_provider.dart';
|
||||
@@ -52,8 +54,13 @@ late RemoteSigningProvider remoteSigningProvider;
|
||||
|
||||
late Map<String, WidgetBuilder> routes;
|
||||
|
||||
late RootIsolateToken rootIsolateToken;
|
||||
|
||||
late BuildInRelayProvider buildInRelayProvider;
|
||||
|
||||
Future<void> main() async {
|
||||
WidgetsBinding widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
|
||||
rootIsolateToken = RootIsolateToken.instance!;
|
||||
|
||||
if (!PlatformUtil.isWeb() && PlatformUtil.isPC()) {
|
||||
await windowManager.ensureInitialized();
|
||||
@@ -87,6 +94,7 @@ Future<void> main() async {
|
||||
Future<void> doInit() async {
|
||||
keyProvider = KeyProvider();
|
||||
appProvider = AppProvider();
|
||||
buildInRelayProvider = BuildInRelayProvider();
|
||||
|
||||
var dataUtilTask = DataUtil.getInstance();
|
||||
var keyTask = keyProvider.init();
|
||||
@@ -156,6 +164,9 @@ class _MyApp extends State<MyApp> {
|
||||
ListenableProvider<RemoteSigningProvider>.value(
|
||||
value: remoteSigningProvider,
|
||||
),
|
||||
ListenableProvider<BuildInRelayProvider>.value(
|
||||
value: buildInRelayProvider,
|
||||
),
|
||||
],
|
||||
child: MaterialApp(
|
||||
builder: BotToastInit(),
|
||||
|
||||
128
lib/provider/build_in_relay_provider.dart
Normal file
128
lib/provider/build_in_relay_provider.dart
Normal file
@@ -0,0 +1,128 @@
|
||||
import 'package:bot_toast/bot_toast.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:nostr_sdk/relay/relay_info.dart';
|
||||
import 'package:nowser/const/base.dart';
|
||||
import 'package:relay_sdk/network/connection.dart';
|
||||
import 'package:relay_sdk/network/memory/mem_relay_client.dart';
|
||||
import 'package:relay_sdk/relay_manager.dart';
|
||||
|
||||
import '../main.dart';
|
||||
import '../util/ip_util.dart';
|
||||
|
||||
class BuildInRelayProvider extends ChangeNotifier {
|
||||
String ip = "127.0.0.1";
|
||||
|
||||
static int port = 4870;
|
||||
|
||||
RelayInfo relayInfo = RelayInfo(
|
||||
"${Base.APP_NAME}'s build-in relay",
|
||||
"This is a build-in relay for Nowser. It don't save any message and it's designed for NWC.",
|
||||
"29320975df855fe34a7b45ada2421e2c741c37c0136901fe477133a91eb18b07",
|
||||
"29320975df855fe34a7b45ada2421e2c741c37c0136901fe477133a91eb18b07",
|
||||
["47"],
|
||||
Base.APP_NAME,
|
||||
Base.VERSION_NAME);
|
||||
|
||||
RelayManager? _relayManager;
|
||||
|
||||
bool isRunning() {
|
||||
if (_relayManager != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Future<void> start() async {
|
||||
if (isRunning()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String? localIp = await IpUtil.getIp();
|
||||
if (localIp != null) {
|
||||
ip = localIp;
|
||||
}
|
||||
|
||||
try {
|
||||
var rm = _getRelayManager();
|
||||
await rm.start(relayInfo, port);
|
||||
|
||||
await Future.delayed(const Duration(seconds: 10));
|
||||
|
||||
if (_penddingMemRelayClients.isNotEmpty) {
|
||||
for (var memRelayClient in _penddingMemRelayClients) {
|
||||
rm.addMemClient(memRelayClient);
|
||||
try {
|
||||
memRelayClient.onConnected();
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
_penddingMemRelayClients.clear();
|
||||
} catch (e) {
|
||||
print(e);
|
||||
BotToast.showText(text: "Start server fail.");
|
||||
if (_relayManager != null) {
|
||||
try {
|
||||
_relayManager!.stop();
|
||||
} catch (e) {}
|
||||
}
|
||||
_relayManager = null;
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void stop() {
|
||||
if (_relayManager != null) {
|
||||
_relayManager!.stop();
|
||||
}
|
||||
|
||||
_relayManager = null;
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
RelayManager _getRelayManager() {
|
||||
if (_relayManager == null) {
|
||||
_relayManager = RelayManager(rootIsolateToken);
|
||||
_relayManager!.openFilterCheck = true;
|
||||
_relayManager!.openDB = false;
|
||||
// _relayManager!.trafficCounter = trafficCounterProvider;
|
||||
// _relayManager!.networkLogsManager = networkLogProvider;
|
||||
_relayManager!.rootIsolateToken = rootIsolateToken;
|
||||
_relayManager!.connectionListener = connectionListener;
|
||||
}
|
||||
|
||||
return _relayManager!;
|
||||
}
|
||||
|
||||
int connectionNum() {
|
||||
if (_relayManager != null) {
|
||||
return _relayManager!.getConnections().length;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
List<Connection> getConnections() {
|
||||
if (_relayManager != null) {
|
||||
return _relayManager!.getConnections();
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
void connectionListener() {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
List<MemRelayClient> _penddingMemRelayClients = [];
|
||||
|
||||
void addMemClient(MemRelayClient memRelayClient) {
|
||||
if (isRunning()) {
|
||||
_relayManager!.addMemClient(memRelayClient);
|
||||
} else {
|
||||
_penddingMemRelayClients.add(memRelayClient);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,11 +18,13 @@ import 'package:nowser/const/app_type.dart';
|
||||
import 'package:nowser/const/auth_type.dart';
|
||||
import 'package:nowser/data/app.dart';
|
||||
import 'package:nowser/provider/permission_check_mixin.dart';
|
||||
import 'package:relay_sdk/network/memory/mem_relay_client.dart';
|
||||
|
||||
import '../component/auth_dialog/auth_app_connect_dialog.dart';
|
||||
import '../data/remote_signing_info.dart';
|
||||
import '../data/remote_signing_info_db.dart';
|
||||
import '../main.dart';
|
||||
import 'build_in_relay_provider.dart';
|
||||
|
||||
class RemoteSigningProvider extends ChangeNotifier with PermissionCheckMixin {
|
||||
BuildContext? context;
|
||||
@@ -77,8 +79,18 @@ class RemoteSigningProvider extends ChangeNotifier with PermissionCheckMixin {
|
||||
|
||||
List<Relay> relays = [];
|
||||
for (var relayAddr in relayAddrs) {
|
||||
// use pubkey relace with
|
||||
var relay = RelayIsolate(relayAddr, RelayStatus(remoteSignerPubkey));
|
||||
bool isLocalRelay = false;
|
||||
Relay? relay;
|
||||
var relayStatus = RelayStatus(remoteSignerPubkey);
|
||||
if (relayAddr == "ws://localhost:${BuildInRelayProvider.port}" ||
|
||||
relayAddr == "ws://127.0.0.1:${BuildInRelayProvider.port}") {
|
||||
// use pubkey relace with
|
||||
relay = MemRelayClient(relayAddr, relayStatus);
|
||||
isLocalRelay = true;
|
||||
} else {
|
||||
// use pubkey relace with
|
||||
relay = RelayIsolate(relayAddr, relayStatus);
|
||||
}
|
||||
|
||||
var filter = Filter(
|
||||
p: [remoteSignerPubkey],
|
||||
@@ -89,7 +101,11 @@ class RemoteSigningProvider extends ChangeNotifier with PermissionCheckMixin {
|
||||
.add(["REQ", StringUtil.rndNameStr(10), filter.toJson()]);
|
||||
relay.onMessage = _onEvent;
|
||||
|
||||
relay.connect();
|
||||
if (isLocalRelay) {
|
||||
buildInRelayProvider.addMemClient(relay as MemRelayClient);
|
||||
} else {
|
||||
relay.connect();
|
||||
}
|
||||
relays.add(relay);
|
||||
}
|
||||
|
||||
@@ -122,7 +138,7 @@ class RemoteSigningProvider extends ChangeNotifier with PermissionCheckMixin {
|
||||
if (request.params.length <= 1) {
|
||||
response = NostrRemoteResponse(request.id, "", error: "params error");
|
||||
} else {
|
||||
if (request.params[0] == remoteSigningInfo.remotePubkey &&
|
||||
if (request.params[0] == remoteSignerPubkey &&
|
||||
request.params[1] == remoteSigningInfo.secret) {
|
||||
// check pass, init app
|
||||
var newApp = await getApp(appType, code);
|
||||
@@ -182,6 +198,7 @@ class RemoteSigningProvider extends ChangeNotifier with PermissionCheckMixin {
|
||||
|
||||
int? eventKind;
|
||||
String? authDetail;
|
||||
String? thirdPartyPubkey;
|
||||
int authType = AuthType.GET_PUBLIC_KEY;
|
||||
dynamic eventObj;
|
||||
|
||||
@@ -197,15 +214,19 @@ class RemoteSigningProvider extends ChangeNotifier with PermissionCheckMixin {
|
||||
authType = AuthType.GET_PUBLIC_KEY;
|
||||
} else if (request.method == "nip04_encrypt") {
|
||||
authType = AuthType.NIP04_ENCRYPT;
|
||||
thirdPartyPubkey = request.params[0];
|
||||
authDetail = request.params[1];
|
||||
} else if (request.method == "nip04_decrypt") {
|
||||
authType = AuthType.NIP04_DECRYPT;
|
||||
thirdPartyPubkey = request.params[0];
|
||||
authDetail = request.params[1];
|
||||
} else if (request.method == "nip44_encrypt") {
|
||||
authType = AuthType.NIP44_ENCRYPT;
|
||||
thirdPartyPubkey = request.params[0];
|
||||
authDetail = request.params[1];
|
||||
} else if (request.method == "nip44_decrypt") {
|
||||
authType = AuthType.NIP44_DECRYPT;
|
||||
thirdPartyPubkey = request.params[0];
|
||||
authDetail = request.params[1];
|
||||
}
|
||||
|
||||
@@ -235,16 +256,16 @@ class RemoteSigningProvider extends ChangeNotifier with PermissionCheckMixin {
|
||||
var pubkey = await signer.getPublicKey();
|
||||
response = NostrRemoteResponse(request.id, pubkey!);
|
||||
} else if (request.method == "nip04_encrypt") {
|
||||
var text = await signer.encrypt(localPubkey, authDetail);
|
||||
var text = await signer.encrypt(thirdPartyPubkey, authDetail);
|
||||
response = NostrRemoteResponse(request.id, text!);
|
||||
} else if (request.method == "nip04_decrypt") {
|
||||
var text = await signer.decrypt(localPubkey, authDetail);
|
||||
var text = await signer.decrypt(thirdPartyPubkey, authDetail);
|
||||
response = NostrRemoteResponse(request.id, text!);
|
||||
} else if (request.method == "nip44_encrypt") {
|
||||
var text = await signer.nip44Encrypt(localPubkey, authDetail);
|
||||
var text = await signer.nip44Encrypt(thirdPartyPubkey, authDetail);
|
||||
response = NostrRemoteResponse(request.id, text!);
|
||||
} else if (request.method == "nip44_decrypt") {
|
||||
var text = await signer.nip44Decrypt(localPubkey, authDetail);
|
||||
var text = await signer.nip44Decrypt(thirdPartyPubkey, authDetail);
|
||||
response = NostrRemoteResponse(request.id, text!);
|
||||
}
|
||||
|
||||
@@ -257,6 +278,8 @@ class RemoteSigningProvider extends ChangeNotifier with PermissionCheckMixin {
|
||||
Future<void> sendResponse(List<Relay> relays, NostrRemoteResponse? response,
|
||||
NostrSigner signer, String localPubkey, String remoteSignerPubkey) async {
|
||||
if (response != null) {
|
||||
// print("response:");
|
||||
// print(response.toString());
|
||||
var result = await response.encrypt(signer, localPubkey);
|
||||
Event? event = Event(
|
||||
remoteSignerPubkey,
|
||||
@@ -267,10 +290,7 @@ class RemoteSigningProvider extends ChangeNotifier with PermissionCheckMixin {
|
||||
result!);
|
||||
event = await signer.signEvent(event);
|
||||
|
||||
var signerPubkey = await signer.getPublicKey();
|
||||
// print("response:");
|
||||
if (event != null) {
|
||||
// print(event.toJson());
|
||||
for (var relay in relays) {
|
||||
relay.send(["EVENT", event.toJson()]);
|
||||
}
|
||||
@@ -290,7 +310,7 @@ class RemoteSigningProvider extends ChangeNotifier with PermissionCheckMixin {
|
||||
print("remoteSigningInfo is null");
|
||||
return;
|
||||
}
|
||||
var nostrSigner = LocalNostrSigner(remoteSigningInfo.remoteSignerKey!);
|
||||
var remoteSigner = LocalNostrSigner(remoteSigningInfo.remoteSignerKey!);
|
||||
var signer = keyProvider.getSigner(remoteSigningInfo.remotePubkey!);
|
||||
if (signer == null) {
|
||||
return;
|
||||
@@ -309,7 +329,7 @@ class RemoteSigningProvider extends ChangeNotifier with PermissionCheckMixin {
|
||||
if (event.kind == EventKind.NOSTR_REMOTE_SIGNING) {
|
||||
if (handledIds[event.id] == null) {
|
||||
var request = await NostrRemoteRequest.decrypt(
|
||||
event.content, signer, event.pubkey);
|
||||
event.content, remoteSigner, event.pubkey);
|
||||
var relays = relayMap[remoteSignerPubkey];
|
||||
if (relays == null || relays.isEmpty) {
|
||||
relays = [relay];
|
||||
@@ -341,7 +361,7 @@ class RemoteSigningProvider extends ChangeNotifier with PermissionCheckMixin {
|
||||
];
|
||||
Event? event =
|
||||
Event(remoteSignerPubkey, EventKind.AUTHENTICATION, tags, "");
|
||||
event = await nostrSigner.signEvent(event);
|
||||
event = await remoteSigner.signEvent(event);
|
||||
if (event != null) {
|
||||
relay.send(["AUTH", event.toJson()], forceSend: true);
|
||||
|
||||
|
||||
@@ -5,11 +5,14 @@ import 'package:nostr_sdk/client_utils/keys.dart';
|
||||
import 'package:nostr_sdk/nip19/nip19.dart';
|
||||
import 'package:nostr_sdk/nip46/nostr_remote_signer_info.dart';
|
||||
import 'package:nostr_sdk/utils/string_util.dart';
|
||||
import 'package:nowser/component/cust_state.dart';
|
||||
import 'package:nowser/component/qrscanner.dart';
|
||||
import 'package:nowser/component/simple_qrcode_dialog.dart';
|
||||
import 'package:nowser/data/remote_signing_info.dart';
|
||||
import 'package:nowser/data/remote_signing_info_db.dart';
|
||||
import 'package:nowser/main.dart';
|
||||
import 'package:nowser/provider/build_in_relay_provider.dart';
|
||||
import 'package:nowser/util/ip_util.dart';
|
||||
import 'package:nowser/util/router_util.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
@@ -25,15 +28,19 @@ class AddRemoteAppRouter extends StatefulWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _AddRemoteAppRouter extends State<AddRemoteAppRouter> {
|
||||
class _AddRemoteAppRouter extends CustState<AddRemoteAppRouter> {
|
||||
TextEditingController nostrconnectConn = TextEditingController();
|
||||
|
||||
TextEditingController bunkerConn = TextEditingController();
|
||||
|
||||
bool editBunker = false;
|
||||
|
||||
bool localRelay = false;
|
||||
|
||||
String? pubkey;
|
||||
|
||||
String? localIp;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@@ -47,7 +54,12 @@ class _AddRemoteAppRouter extends State<AddRemoteAppRouter> {
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Future<void> onReady(BuildContext context) async {
|
||||
localIp = await IpUtil.getIp();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget doBuild(BuildContext context) {
|
||||
var themeData = Theme.of(context);
|
||||
var textColor = themeData.textTheme.bodyMedium!.color;
|
||||
var mainColor = themeData.primaryColor;
|
||||
@@ -135,10 +147,28 @@ class _AddRemoteAppRouter extends State<AddRemoteAppRouter> {
|
||||
bunkerWidget = Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
margin: EdgeInsets.only(
|
||||
right: Base.BASE_PADDING_HALF,
|
||||
),
|
||||
child: Text("Local Relay:"),
|
||||
),
|
||||
Checkbox(
|
||||
value: localRelay,
|
||||
onChanged: onLocalRelayChange,
|
||||
),
|
||||
Expanded(child: Container()),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
child: TextField(
|
||||
decoration: InputDecoration(
|
||||
labelText: "Relay",
|
||||
enabled: !localRelay,
|
||||
),
|
||||
controller: relayAddrController,
|
||||
),
|
||||
@@ -328,12 +358,17 @@ class _AddRemoteAppRouter extends State<AddRemoteAppRouter> {
|
||||
|
||||
TextEditingController relayAddrController = TextEditingController();
|
||||
|
||||
static const String DEFAULT_RELAY = "wss://relay.nsec.app";
|
||||
|
||||
TextEditingController secretController = TextEditingController();
|
||||
|
||||
void refreshBunkerUrl() {
|
||||
remoteSignerKey = generatePrivateKey();
|
||||
secretController.text = StringUtil.rndNameStr(20);
|
||||
relayAddrController.text = "wss://relay.nsec.app";
|
||||
if (StringUtil.isBlank(localIp) ||
|
||||
!relayAddrController.text.contains(localIp!)) {
|
||||
relayAddrController.text = DEFAULT_RELAY;
|
||||
}
|
||||
|
||||
reloadBunker();
|
||||
}
|
||||
@@ -354,7 +389,12 @@ class _AddRemoteAppRouter extends State<AddRemoteAppRouter> {
|
||||
return;
|
||||
}
|
||||
|
||||
var relays = [relayAddrController.text];
|
||||
List<String> relays = [];
|
||||
if (localRelay) {
|
||||
relays.add("ws://127.0.0.1:${BuildInRelayProvider.port}");
|
||||
} else {
|
||||
relays.add(relayAddrController.text);
|
||||
}
|
||||
|
||||
var remoteSigningInfo = RemoteSigningInfo(
|
||||
remotePubkey: pubkey,
|
||||
@@ -377,4 +417,19 @@ class _AddRemoteAppRouter extends State<AddRemoteAppRouter> {
|
||||
);
|
||||
bunkerConn.text = nostrRemoteSignerInfo.toString();
|
||||
}
|
||||
|
||||
void onLocalRelayChange(bool? v) {
|
||||
if (v == true) {
|
||||
relayAddrController.text = "ws://${localIp}:${BuildInRelayProvider.port}";
|
||||
} else if (v == false) {
|
||||
relayAddrController.text = DEFAULT_RELAY;
|
||||
}
|
||||
|
||||
if (v != null) {
|
||||
setState(() {
|
||||
localRelay = v;
|
||||
});
|
||||
reloadBunker();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,9 @@ class _IndexRouter extends CustState<IndexRouter>
|
||||
Future<void> onReady(BuildContext context) async {
|
||||
await remoteSigningProvider.reload();
|
||||
await remoteSigningProvider.reloadPenddingRemoteApps();
|
||||
|
||||
// start build-in
|
||||
buildInRelayProvider.start();
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
19
lib/util/ip_util.dart
Normal file
19
lib/util/ip_util.dart
Normal file
@@ -0,0 +1,19 @@
|
||||
import 'dart:io';
|
||||
|
||||
class IpUtil {
|
||||
static Future<String?> getIp() async {
|
||||
var ips = await NetworkInterface.list();
|
||||
for (var interface in ips) {
|
||||
print('== Interface: ${interface.name} ==');
|
||||
if (interface.name == "WLAN") {
|
||||
for (var addr in interface.addresses) {
|
||||
print(
|
||||
'${addr.address} ${addr.host} ${addr.isLoopback} ${addr.rawAddress} ${addr.type.name}');
|
||||
return addr.address;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ips.first.addresses.first.address;
|
||||
}
|
||||
}
|
||||
1
packages/relay_sdk
Submodule
1
packages/relay_sdk
Submodule
Submodule packages/relay_sdk added at bef0b65fec
@@ -764,6 +764,13 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.5"
|
||||
relay_sdk:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "packages/relay_sdk"
|
||||
relative: true
|
||||
source: path
|
||||
version: "0.0.1"
|
||||
rxdart:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1090,5 +1097,5 @@ packages:
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
sdks:
|
||||
dart: ">=3.5.0 <4.0.0"
|
||||
dart: ">=3.5.3 <4.0.0"
|
||||
flutter: ">=3.24.0"
|
||||
|
||||
@@ -35,6 +35,8 @@ dependencies:
|
||||
cupertino_icons: ^1.0.6
|
||||
nostr_sdk:
|
||||
path: packages/nostr_sdk
|
||||
relay_sdk:
|
||||
path: packages/relay_sdk
|
||||
|
||||
receive_intent: ^0.2.5
|
||||
provider: ^6.1.2
|
||||
|
||||
Reference in New Issue
Block a user