mirror of
https://github.com/haorendashu/nowser.git
synced 2025-12-17 01:44:19 +01:00
remote signing simple support
This commit is contained in:
41
lib/component/simple_qrcode_dialog.dart
Normal file
41
lib/component/simple_qrcode_dialog.dart
Normal file
@@ -0,0 +1,41 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:nowser/const/base.dart';
|
||||
import 'package:pretty_qr_code/pretty_qr_code.dart';
|
||||
|
||||
class SimpleQrcodeDialog extends StatefulWidget {
|
||||
String data;
|
||||
|
||||
SimpleQrcodeDialog(this.data);
|
||||
|
||||
static Future<void> show(BuildContext context, String date) async {
|
||||
return await showDialog<void>(
|
||||
context: context,
|
||||
builder: (_context) {
|
||||
return SimpleQrcodeDialog(date);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() {
|
||||
return _SimpleQrcodeDialog();
|
||||
}
|
||||
}
|
||||
|
||||
class _SimpleQrcodeDialog extends State<SimpleQrcodeDialog> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Dialog(
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(Base.BASE_PADDING * 2),
|
||||
child: PrettyQrView.data(
|
||||
data: widget.data,
|
||||
// decoration: const PrettyQrDecoration(
|
||||
// image: PrettyQrDecorationImage(
|
||||
// image: AssetImage('images/flutter.png'),
|
||||
// ),
|
||||
// ),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,7 @@ class DB {
|
||||
db.execute("create index auth_log_index on auth_log (app_id);");
|
||||
|
||||
db.execute(
|
||||
"create table remote_signing_info(id integer not null constraint remote_signing_info_pk primary key autoincrement,app_id integer,local_pubkey text,remote_signer_key text,relays text,secret text,created_at integer,updated_at integer);");
|
||||
"create table remote_signing_info(id integer not null constraint remote_signing_info_pk primary key autoincrement,app_id integer,local_pubkey text,remote_pubkey text,remote_signer_key text,relays text,secret text,created_at integer,updated_at integer);");
|
||||
|
||||
db.execute(
|
||||
"create table zap_log(id integer not null constraint zap_log_pk primary key autoincrement,app_id integer not null constraint zap_log_index unique,zap_type integer not null,num integer not null,created_at integer not null);");
|
||||
|
||||
@@ -2,6 +2,7 @@ class RemoteSigningInfo {
|
||||
int? id;
|
||||
int? appId;
|
||||
String? localPubkey;
|
||||
String? remotePubkey;
|
||||
String? remoteSignerKey;
|
||||
String? relays;
|
||||
String? secret;
|
||||
@@ -12,6 +13,7 @@ class RemoteSigningInfo {
|
||||
{this.id,
|
||||
this.appId,
|
||||
this.localPubkey,
|
||||
this.remotePubkey,
|
||||
this.remoteSignerKey,
|
||||
this.relays,
|
||||
this.secret,
|
||||
@@ -22,6 +24,7 @@ class RemoteSigningInfo {
|
||||
id = json['id'];
|
||||
appId = json['app_id'];
|
||||
localPubkey = json['local_pubkey'];
|
||||
remotePubkey = json['remote_pubkey'];
|
||||
remoteSignerKey = json['remote_signer_key'];
|
||||
relays = json['relays'];
|
||||
secret = json['secret'];
|
||||
@@ -34,6 +37,7 @@ class RemoteSigningInfo {
|
||||
data['id'] = this.id;
|
||||
data['app_id'] = this.appId;
|
||||
data['local_pubkey'] = this.localPubkey;
|
||||
data['remote_pubkey'] = this.remotePubkey;
|
||||
data['remote_signer_key'] = this.remoteSignerKey;
|
||||
data['relays'] = this.relays;
|
||||
data['secret'] = this.secret;
|
||||
|
||||
@@ -39,4 +39,10 @@ class RemoteSigningInfoDB {
|
||||
|
||||
return objs;
|
||||
}
|
||||
|
||||
static Future<int> update(RemoteSigningInfo o, {DatabaseExecutor? db}) async {
|
||||
db = await DB.getDB(db);
|
||||
return await db.update("remote_signing_info", o.toJson(),
|
||||
where: "id = ?", whereArgs: [o.id]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,8 +61,6 @@ Future<void> main() async {
|
||||
settingProvider = futureResultList[0] as SettingProvider;
|
||||
webProvider = WebProvider();
|
||||
remoteSigningProvider = RemoteSigningProvider();
|
||||
remoteSigningProvider.reload();
|
||||
remoteSigningProvider.reloadPenddingRemoteApps();
|
||||
|
||||
runApp(MyApp());
|
||||
}
|
||||
|
||||
@@ -14,10 +14,12 @@ import 'package:nostr_sdk/relay/relay_status.dart';
|
||||
import 'package:nostr_sdk/signer/local_nostr_signer.dart';
|
||||
import 'package:nostr_sdk/signer/nostr_signer.dart';
|
||||
import 'package:nostr_sdk/utils/string_util.dart';
|
||||
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 '../component/auth_dialog/auth_app_connect_dialog.dart';
|
||||
import '../data/remote_signing_info.dart';
|
||||
import '../data/remote_signing_info_db.dart';
|
||||
import '../main.dart';
|
||||
@@ -29,75 +31,157 @@ class RemoteSigningProvider extends ChangeNotifier with PermissionCheckMixin {
|
||||
context = _context;
|
||||
}
|
||||
|
||||
// localPubkey - Relay
|
||||
// remoteSignerPubkey - Relay
|
||||
Map<String, List<Relay>> relayMap = {};
|
||||
|
||||
// localPubkey - RemoteSigningInfo
|
||||
// remoteSignerPubkey - RemoteSigningInfo
|
||||
Map<String, RemoteSigningInfo> remoteSigningInfoMap = {};
|
||||
|
||||
// localPubkey - App
|
||||
// remoteSignerPubkey - App
|
||||
Map<String, App> appMap = {};
|
||||
|
||||
Future<void> reload() async {
|
||||
relayMap = {};
|
||||
remoteSigningInfoMap = {};
|
||||
appMap = {};
|
||||
|
||||
load();
|
||||
}
|
||||
|
||||
Future<void> load() async {
|
||||
var remoteAppList = appProvider.remoteAppList();
|
||||
for (var remoteApp in remoteAppList) {
|
||||
await add(remoteApp);
|
||||
await addRemoteApp(remoteApp);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> add(App remoteApp) async {
|
||||
Future<void> addRemoteApp(App remoteApp) async {
|
||||
var remoteSigningInfo = await RemoteSigningInfoDB.getByAppId(remoteApp.id!);
|
||||
if (remoteSigningInfo != null &&
|
||||
StringUtil.isNotBlank(remoteSigningInfo.remoteSignerKey) &&
|
||||
StringUtil.isNotBlank(remoteSigningInfo.remotePubkey) &&
|
||||
StringUtil.isNotBlank(remoteSigningInfo.localPubkey) &&
|
||||
StringUtil.isNotBlank(remoteSigningInfo.relays)) {
|
||||
var localPubkey = remoteSigningInfo.localPubkey!;
|
||||
var pubkey = getPublicKey(remoteSigningInfo.remoteSignerKey!);
|
||||
var relayAddrs = remoteSigningInfo.relays!.split(",");
|
||||
var relays = connectToRelay(remoteSigningInfo);
|
||||
|
||||
List<Relay> relays = [];
|
||||
for (var relayAddr in relayAddrs) {
|
||||
// use pubkey relace with
|
||||
var relay = RelayIsolate(relayAddr, RelayStatus(localPubkey));
|
||||
|
||||
var filter = Filter(p: [pubkey]);
|
||||
relay.pendingAuthedMessages
|
||||
.add(["REQ", StringUtil.rndNameStr(10), filter.toJson()]);
|
||||
relay.onMessage = _onEvent;
|
||||
|
||||
relay.connect();
|
||||
relays.add(relay);
|
||||
}
|
||||
|
||||
relayMap[localPubkey] = relays;
|
||||
remoteSigningInfoMap[localPubkey] = remoteSigningInfo;
|
||||
var remoteSignerPubkey = getPublicKey(remoteSigningInfo.remoteSignerKey!);
|
||||
remoteSigningInfoMap[remoteSignerPubkey] = remoteSigningInfo;
|
||||
appMap[remoteSignerPubkey] = remoteApp;
|
||||
relayMap[remoteSignerPubkey] = relays;
|
||||
}
|
||||
}
|
||||
|
||||
List<Relay> connectToRelay(RemoteSigningInfo remoteSigningInfo) {
|
||||
var remoteSignerPubkey = getPublicKey(remoteSigningInfo.remoteSignerKey!);
|
||||
var relayAddrs = remoteSigningInfo.relays!.split(",");
|
||||
|
||||
List<Relay> relays = [];
|
||||
for (var relayAddr in relayAddrs) {
|
||||
// use pubkey relace with
|
||||
var relay = RelayIsolate(relayAddr, RelayStatus(remoteSignerPubkey));
|
||||
|
||||
var filter = Filter(
|
||||
p: [remoteSigningInfo.remotePubkey!],
|
||||
since: DateTime.now().millisecondsSinceEpoch ~/ 1000);
|
||||
relay.pendingAuthedMessages
|
||||
.add(["REQ", StringUtil.rndNameStr(10), filter.toJson()]);
|
||||
relay.pendingMessages
|
||||
.add(["REQ", StringUtil.rndNameStr(10), filter.toJson()]);
|
||||
relay.onMessage = _onEvent;
|
||||
|
||||
relay.connect();
|
||||
relays.add(relay);
|
||||
|
||||
print("connected to relay ${relay.url}");
|
||||
}
|
||||
|
||||
return relays;
|
||||
}
|
||||
|
||||
Future<void> onRequest(
|
||||
Relay relay,
|
||||
NostrRemoteRequest request,
|
||||
RemoteSigningInfo remoteSigningInfo,
|
||||
App app,
|
||||
String localPubkey,
|
||||
App? app,
|
||||
) async {
|
||||
String localPubkey = remoteSigningInfo.localPubkey!;
|
||||
NostrSigner signer = LocalNostrSigner(remoteSigningInfo.remoteSignerKey!);
|
||||
var remoteSignerPubkey = await signer.getPublicKey();
|
||||
var appType = app.appType!;
|
||||
var code = app.code!;
|
||||
NostrSigner signerSigner =
|
||||
LocalNostrSigner(remoteSigningInfo.remoteSignerKey!);
|
||||
var remoteSignerPubkey = getPublicKey(remoteSigningInfo.remoteSignerKey!);
|
||||
var appType = AppType.REMOTE;
|
||||
var code = remoteSignerPubkey;
|
||||
|
||||
NostrRemoteResponse? response;
|
||||
if (request.method == "ping") {
|
||||
response = NostrRemoteResponse(request.id, "pong");
|
||||
|
||||
sendResponse(relay, response, signer, localPubkey, remoteSignerPubkey!);
|
||||
sendResponse(
|
||||
relay, response, signerSigner, localPubkey, remoteSignerPubkey);
|
||||
} else if (request.method == "connect") {
|
||||
if (app != null) {
|
||||
response = NostrRemoteResponse(request.id, "ack");
|
||||
} else {
|
||||
if (request.params.length <= 1) {
|
||||
response = NostrRemoteResponse(request.id, "", error: "params error");
|
||||
} else {
|
||||
if (request.params[0] == remoteSigningInfo.remotePubkey &&
|
||||
request.params[1] == remoteSigningInfo.secret) {
|
||||
// check pass, init app
|
||||
var newApp = await getApp(appType, code);
|
||||
await AuthAppConnectDialog.show(context!, newApp);
|
||||
// reload from provider
|
||||
app = appProvider.getApp(appType, code);
|
||||
if (app == null) {
|
||||
response =
|
||||
NostrRemoteResponse(request.id, "", error: "connect fail");
|
||||
} else {
|
||||
remoteSigningInfo.appId = app.id;
|
||||
remoteSigningInfo.localPubkey = localPubkey;
|
||||
remoteSigningInfo.updatedAt =
|
||||
DateTime.now().millisecondsSinceEpoch ~/ 1000;
|
||||
|
||||
RemoteSigningInfoDB.update(remoteSigningInfo);
|
||||
remoteSigningInfoMap[remoteSignerPubkey] = remoteSigningInfo;
|
||||
appMap[remoteSignerPubkey] = app;
|
||||
|
||||
_penddingRemoteApps.removeWhere((rsi) {
|
||||
if (rsi.id == remoteSigningInfo.id) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
response = NostrRemoteResponse(request.id, "ack");
|
||||
}
|
||||
} else {
|
||||
response = NostrRemoteResponse(request.id, "",
|
||||
error: "connect check fail");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (response != null) {
|
||||
sendResponse(
|
||||
relay, response, signerSigner, localPubkey, remoteSignerPubkey);
|
||||
}
|
||||
} else {
|
||||
if (remoteSigningInfo.localPubkey != localPubkey) {
|
||||
// Remote signing should connect first.
|
||||
response = NostrRemoteResponse(request.id, "",
|
||||
error: "Local pubkey not allow.");
|
||||
sendResponse(
|
||||
relay, response, signerSigner, localPubkey, remoteSignerPubkey);
|
||||
return;
|
||||
}
|
||||
if (app == null) {
|
||||
// Remote signing should connect first.
|
||||
response = NostrRemoteResponse(request.id, "",
|
||||
error: "Remote signing should connect first.");
|
||||
sendResponse(
|
||||
relay, response, signerSigner, localPubkey, remoteSignerPubkey);
|
||||
return;
|
||||
}
|
||||
|
||||
int? eventKind;
|
||||
String? authDetail;
|
||||
int authType = AuthType.GET_PUBLIC_KEY;
|
||||
@@ -130,7 +214,8 @@ class RemoteSigningProvider extends ChangeNotifier with PermissionCheckMixin {
|
||||
checkPermission(context!, appType, code, authType,
|
||||
eventKind: eventKind, authDetail: authDetail, (app) {
|
||||
response = NostrRemoteResponse(request.id, "", error: "forbid");
|
||||
sendResponse(relay, response, signer, localPubkey, remoteSignerPubkey!);
|
||||
sendResponse(
|
||||
relay, response, signerSigner, localPubkey, remoteSignerPubkey);
|
||||
}, (app, signer) async {
|
||||
if (request.method == "sign_event") {
|
||||
var tags = eventObj["tags"];
|
||||
@@ -165,7 +250,8 @@ class RemoteSigningProvider extends ChangeNotifier with PermissionCheckMixin {
|
||||
response = NostrRemoteResponse(request.id, text!);
|
||||
}
|
||||
|
||||
sendResponse(relay, response, signer, localPubkey, remoteSignerPubkey!);
|
||||
sendResponse(
|
||||
relay, response, signerSigner, localPubkey, remoteSignerPubkey);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -174,27 +260,45 @@ class RemoteSigningProvider extends ChangeNotifier with PermissionCheckMixin {
|
||||
NostrSigner signer, String localPubkey, String remoteSignerPubkey) async {
|
||||
if (response != null) {
|
||||
var result = await response.encrypt(signer, localPubkey);
|
||||
var event = Event(
|
||||
remoteSignerPubkey!,
|
||||
Event? event = Event(
|
||||
remoteSignerPubkey,
|
||||
EventKind.NOSTR_REMOTE_SIGNING,
|
||||
[
|
||||
["p", localPubkey]
|
||||
],
|
||||
result!);
|
||||
event = await signer.signEvent(event);
|
||||
|
||||
relay.send(["event", event.toJson()]);
|
||||
var signerPubkey = await signer.getPublicKey();
|
||||
print("signerPubkey $signerPubkey");
|
||||
|
||||
print("response:");
|
||||
if (event != null) {
|
||||
print(event.toJson());
|
||||
print(event.isValid);
|
||||
print(event.isSigned);
|
||||
relay.send(["EVENT", event.toJson()]);
|
||||
} else {
|
||||
print("null");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onEvent(Relay relay, List<dynamic> json) async {
|
||||
var localPubkey = relay.relayStatus.addr;
|
||||
var remoteSigningInfo = remoteSigningInfoMap[localPubkey];
|
||||
print("request");
|
||||
print(json);
|
||||
|
||||
var remoteSignerPubkey = relay.relayStatus.addr;
|
||||
var remoteSigningInfo = remoteSigningInfoMap[remoteSignerPubkey];
|
||||
if (remoteSigningInfo == null) {
|
||||
print("remoteSigningInfo is null");
|
||||
return;
|
||||
}
|
||||
var remotePubkey = getPublicKey(remoteSigningInfo.remoteSignerKey!);
|
||||
var nostrSigner = LocalNostrSigner(remoteSigningInfo.remoteSignerKey!);
|
||||
var signer = keyProvider.getSigner(remoteSigningInfo.remotePubkey!);
|
||||
if (signer == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final messageType = json[0];
|
||||
if (messageType == 'EVENT') {
|
||||
@@ -208,8 +312,11 @@ class RemoteSigningProvider extends ChangeNotifier with PermissionCheckMixin {
|
||||
|
||||
if (event.kind == EventKind.NOSTR_REMOTE_SIGNING) {
|
||||
var request = await NostrRemoteRequest.decrypt(
|
||||
event.content, nostrSigner, localPubkey);
|
||||
if (request != null) {}
|
||||
event.content, signer, event.pubkey);
|
||||
if (request != null) {
|
||||
onRequest(relay, request, remoteSigningInfo, event.pubkey,
|
||||
appMap[remoteSignerPubkey]);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
log(err.toString());
|
||||
@@ -228,7 +335,8 @@ class RemoteSigningProvider extends ChangeNotifier with PermissionCheckMixin {
|
||||
["relay", relay.url],
|
||||
["challenge", challenge]
|
||||
];
|
||||
Event? event = Event(remotePubkey, EventKind.AUTHENTICATION, tags, "");
|
||||
Event? event =
|
||||
Event(remoteSignerPubkey, EventKind.AUTHENTICATION, tags, "");
|
||||
event = await nostrSigner.signEvent(event);
|
||||
if (event != null) {
|
||||
relay.send(["AUTH", event.toJson()], forceSend: true);
|
||||
@@ -251,7 +359,7 @@ class RemoteSigningProvider extends ChangeNotifier with PermissionCheckMixin {
|
||||
|
||||
List<RemoteSigningInfo> get penddingRemoteApps => _penddingRemoteApps;
|
||||
|
||||
void addRemoteSigningInfo(RemoteSigningInfo remoteSigningInfo) {
|
||||
void saveRemoteSigningInfo(RemoteSigningInfo remoteSigningInfo) {
|
||||
RemoteSigningInfoDB.insert(remoteSigningInfo);
|
||||
reloadPenddingRemoteApps();
|
||||
notifyListeners();
|
||||
@@ -261,72 +369,22 @@ class RemoteSigningProvider extends ChangeNotifier with PermissionCheckMixin {
|
||||
var list = await RemoteSigningInfoDB.penddingRemoteSigningInfo();
|
||||
_penddingRemoteApps = list;
|
||||
notifyListeners();
|
||||
|
||||
connectPenddingRemoteApp();
|
||||
}
|
||||
|
||||
/**
|
||||
* The below code is design for relay n - remoteSignerKey n
|
||||
*/
|
||||
void connectPenddingRemoteApp() {
|
||||
for (var remoteSigningInfo in _penddingRemoteApps) {
|
||||
if (StringUtil.isNotBlank(remoteSigningInfo.remoteSignerKey) &&
|
||||
StringUtil.isNotBlank(remoteSigningInfo.remotePubkey) &&
|
||||
StringUtil.isNotBlank(remoteSigningInfo.relays)) {
|
||||
var relays = connectToRelay(remoteSigningInfo);
|
||||
|
||||
// Map<String, RelayStatus> relayStatusMap = {};
|
||||
|
||||
// // relayAddr - Relay
|
||||
// Map<String, Relay> relayMap = {};
|
||||
|
||||
// // remoteSignerPubkey - RemoteSigningInfo
|
||||
// Map<String, RemoteSigningInfo> remoteSigningInfoMap = {};
|
||||
|
||||
// Map<String, List<String>> relayToRemoteSignerPubkeys = {};
|
||||
|
||||
// Map<String, List<String>> remoteSignerPubkeyToRelays = {};
|
||||
|
||||
// /// relay - remoteSignerKey > n - n
|
||||
// /// ==>
|
||||
// /// relay - remoteSignerKey > 1 - n
|
||||
// /// remoteSigner - relay > 1 - n
|
||||
// Future<void> load() async {
|
||||
// var remoteAppList = appProvider.remoteAppList();
|
||||
// for (var remoteApp in remoteAppList) {
|
||||
// var remoteSigningInfo =
|
||||
// await RemoteSigningInfoDB.getByAppId(remoteApp.id!);
|
||||
// if (remoteSigningInfo != null &&
|
||||
// StringUtil.isNotBlank(remoteSigningInfo.remoteSignerKey) &&
|
||||
// StringUtil.isNotBlank(remoteSigningInfo.localPubkey) &&
|
||||
// StringUtil.isNotBlank(remoteSigningInfo.relays)) {
|
||||
// var pubkey = getPublicKey(remoteSigningInfo.secret!);
|
||||
// var relays = remoteSigningInfo.relays!.split(",");
|
||||
|
||||
// remoteSignerPubkeyToRelays[pubkey] = relays;
|
||||
// remoteSigningInfoMap[pubkey] = remoteSigningInfo;
|
||||
|
||||
// for (var relay in relays) {
|
||||
// relay = RelayAddrUtil.handle(relay);
|
||||
|
||||
// var pubkeys = relayToRemoteSignerPubkeys[relay];
|
||||
// if (pubkeys == null) {
|
||||
// pubkeys = [];
|
||||
// relayToRemoteSignerPubkeys[relay] = pubkeys;
|
||||
// }
|
||||
|
||||
// if (!pubkeys.contains(pubkey)) {
|
||||
// pubkeys.add(pubkey);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // data handle complete, begin to init relays
|
||||
// for (var entry in relayToRemoteSignerPubkeys.entries) {
|
||||
// var relayAddr = entry.key;
|
||||
// var pubkeys = entry.value;
|
||||
|
||||
// var relayStatus = RelayStatus(relayAddr);
|
||||
// relayStatusMap[relayAddr] = relayStatus;
|
||||
|
||||
// var relay = RelayIsolate(relayAddr, relayStatus);
|
||||
// relayMap[relayAddr] = relay;
|
||||
|
||||
// // var filter = Filter(
|
||||
// // p: pubkeys, since: DateTime.now().millisecondsSinceEpoch ~/ 1000);
|
||||
// }
|
||||
// }
|
||||
var remoteSignerPubkey =
|
||||
getPublicKey(remoteSigningInfo.remoteSignerKey!);
|
||||
remoteSigningInfoMap[remoteSignerPubkey] = remoteSigningInfo;
|
||||
relayMap[remoteSignerPubkey] = relays;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:bot_toast/bot_toast.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:nostr_sdk/client_utils/keys.dart';
|
||||
@@ -5,6 +6,7 @@ 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/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';
|
||||
@@ -13,6 +15,7 @@ import 'package:provider/provider.dart';
|
||||
|
||||
import '../../component/appbar_back_btn_component.dart';
|
||||
import '../../const/base.dart';
|
||||
import '../../generated/l10n.dart';
|
||||
import '../../provider/key_provider.dart';
|
||||
|
||||
class AddRemoteAppRouter extends StatefulWidget {
|
||||
@@ -29,6 +32,8 @@ class _AddRemoteAppRouter extends State<AddRemoteAppRouter> {
|
||||
|
||||
bool editBunker = false;
|
||||
|
||||
String? pubkey;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@@ -47,6 +52,41 @@ class _AddRemoteAppRouter extends State<AddRemoteAppRouter> {
|
||||
var textColor = themeData.textTheme.bodyMedium!.color;
|
||||
var mainColor = themeData.primaryColor;
|
||||
|
||||
var keyWidget =
|
||||
Selector<KeyProvider, List<String>>(builder: (context, pubkeys, child) {
|
||||
List<DropdownMenuItem<String>> items = [];
|
||||
for (var pubkey in pubkeys) {
|
||||
items.add(DropdownMenuItem(
|
||||
value: pubkey,
|
||||
child: Text(
|
||||
Nip19.encodePubKey(pubkey),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
if (StringUtil.isBlank(pubkey) && pubkeys.isNotEmpty) {
|
||||
pubkey = pubkeys.first;
|
||||
refreshBunkerUrl();
|
||||
}
|
||||
|
||||
return DropdownButton<String>(
|
||||
items: items,
|
||||
isExpanded: true,
|
||||
onChanged: (String? value) {
|
||||
if (StringUtil.isNotBlank(value)) {
|
||||
pubkey = value;
|
||||
refreshBunkerUrl();
|
||||
setState(() {});
|
||||
}
|
||||
},
|
||||
value: pubkey,
|
||||
);
|
||||
}, selector: (context, provider) {
|
||||
return provider.pubkeys;
|
||||
});
|
||||
|
||||
if (StringUtil.isBlank(bunkerConn.text)) {
|
||||
refreshBunkerUrl();
|
||||
}
|
||||
@@ -121,6 +161,9 @@ class _AddRemoteAppRouter extends State<AddRemoteAppRouter> {
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
child: keyWidget,
|
||||
),
|
||||
Container(
|
||||
height: 60,
|
||||
child: TabBar(
|
||||
@@ -205,9 +248,9 @@ class _AddRemoteAppRouter extends State<AddRemoteAppRouter> {
|
||||
IconButton(
|
||||
onPressed: refreshBunkerUrl,
|
||||
icon: Icon(Icons.refresh)),
|
||||
// IconButton(
|
||||
// onPressed: showBunkerUrlQRCode,
|
||||
// icon: Icon(Icons.qr_code)),
|
||||
IconButton(
|
||||
onPressed: showBunkerUrlQRCode,
|
||||
icon: Icon(Icons.qr_code)),
|
||||
IconButton(
|
||||
onPressed: copyBunkerUrl,
|
||||
icon: Icon(Icons.copy)),
|
||||
@@ -288,20 +331,27 @@ class _AddRemoteAppRouter extends State<AddRemoteAppRouter> {
|
||||
reloadBunker();
|
||||
}
|
||||
|
||||
// void showBunkerUrlQRCode() {}
|
||||
void showBunkerUrlQRCode() {
|
||||
reloadBunker();
|
||||
SimpleQrcodeDialog.show(context, bunkerConn.text);
|
||||
}
|
||||
|
||||
void copyBunkerUrl() {
|
||||
Clipboard.setData(ClipboardData(text: bunkerConn.text)).then((_) {
|
||||
// TODO
|
||||
// BotToast.showText(text: S.of(context).Copy_success);
|
||||
BotToast.showText(text: "Copy success");
|
||||
});
|
||||
}
|
||||
|
||||
void confirmBunkerUrl() {
|
||||
if (StringUtil.isBlank(pubkey)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var remoteSignerKey = remoteSignerKeyController.text;
|
||||
var relays = [relayAddrController.text];
|
||||
|
||||
var remoteSigningInfo = RemoteSigningInfo(
|
||||
remotePubkey: pubkey,
|
||||
remoteSignerKey: remoteSignerKey,
|
||||
relays: relays.join(","),
|
||||
secret: secretController.text,
|
||||
@@ -309,16 +359,17 @@ class _AddRemoteAppRouter extends State<AddRemoteAppRouter> {
|
||||
);
|
||||
remoteSigningInfo.updatedAt = remoteSigningInfo.createdAt;
|
||||
|
||||
remoteSigningProvider.addRemoteSigningInfo(remoteSigningInfo);
|
||||
remoteSigningProvider.saveRemoteSigningInfo(remoteSigningInfo);
|
||||
RouterUtil.back(context);
|
||||
}
|
||||
|
||||
void reloadBunker() {
|
||||
var remoteSignerKey = remoteSignerKeyController.text;
|
||||
var remoteSignerPubkey = getPublicKey(remoteSignerKey);
|
||||
if (StringUtil.isBlank(pubkey)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var nostrRemoteSignerInfo = NostrRemoteSignerInfo(
|
||||
remoteUserPubkey: remoteSignerPubkey,
|
||||
remoteUserPubkey: pubkey!,
|
||||
relays: [relayAddrController.text],
|
||||
optionalSecret: secretController.text,
|
||||
);
|
||||
|
||||
@@ -74,7 +74,9 @@ class _AppsRouter extends CustState<AppsRouter> {
|
||||
var length = penddingList.length;
|
||||
for (var i = 0; i < length; i++) {
|
||||
var remoteSigningInfo = penddingList[i];
|
||||
var pubkey = getPublicKey(remoteSigningInfo.remoteSignerKey!);
|
||||
if (StringUtil.isBlank(remoteSigningInfo.remotePubkey)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String connectUrlType = "bunker";
|
||||
if (StringUtil.isNotBlank(remoteSigningInfo.localPubkey)) {
|
||||
@@ -84,10 +86,10 @@ class _AppsRouter extends CustState<AppsRouter> {
|
||||
widgets.add(Container(
|
||||
child: Row(
|
||||
children: [
|
||||
Text(Nip19.encodeSimplePubKey(pubkey)),
|
||||
Text(Nip19.encodeSimplePubKey(remoteSigningInfo.remotePubkey!)),
|
||||
Expanded(
|
||||
child: Container(
|
||||
margin: EdgeInsets.only(left: Base.BASE_PADDING_HALF),
|
||||
margin: const EdgeInsets.only(left: Base.BASE_PADDING_HALF),
|
||||
child: Text(
|
||||
DateFormatUtil.format(
|
||||
remoteSigningInfo.createdAt!,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:nostr_sdk/utils/platform_util.dart';
|
||||
import 'package:nowser/component/cust_state.dart';
|
||||
import 'package:nowser/main.dart';
|
||||
import 'package:nowser/provider/web_provider.dart';
|
||||
import 'package:nowser/router/index/index_web_component.dart';
|
||||
@@ -16,12 +17,18 @@ class IndexRouter extends StatefulWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _IndexRouter extends State<IndexRouter>
|
||||
class _IndexRouter extends CustState<IndexRouter>
|
||||
with PermissionCheckMixin, AndroidSignerMixin {
|
||||
Map<String, WebViewComponent> webViewComponentMap = {};
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Future<void> onReady(BuildContext context) async {
|
||||
await remoteSigningProvider.reload();
|
||||
await remoteSigningProvider.reloadPenddingRemoteApps();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget doBuild(BuildContext context) {
|
||||
if (PlatformUtil.isAndroid()) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
handleInitialIntent(context);
|
||||
|
||||
Submodule packages/nostr_sdk updated: 456da4ab2d...592064d434
Reference in New Issue
Block a user