nowser add contentresolver support

This commit is contained in:
DASHU
2024-10-09 02:05:05 +08:00
parent a0c0ec78b8
commit 6660cb2805
13 changed files with 310 additions and 27 deletions

View File

@@ -34,6 +34,7 @@ import 'const/base.dart';
import 'const/colors.dart';
import 'const/router_path.dart';
import 'generated/l10n.dart';
import 'provider/android_signer_content_resolver_provider.dart';
import 'provider/data_util.dart';
import 'provider/remote_signing_provider.dart';
import 'provider/setting_provider.dart';
@@ -78,6 +79,12 @@ Future<void> main() async {
databaseFactory = databaseFactoryFfi;
}
await doInit();
runApp(MyApp());
}
Future<void> doInit() async {
keyProvider = KeyProvider();
appProvider = AppProvider();
@@ -92,8 +99,6 @@ Future<void> main() async {
settingProvider = futureResultList[0] as SettingProvider;
webProvider = WebProvider();
remoteSigningProvider = RemoteSigningProvider();
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@@ -330,3 +335,11 @@ Color _getMainColor() {
}
return color500;
}
@pragma('vm:entry-point')
Future<void> nowserSignerProviderEntrypoint() async {
// if we call content resolver this should init first, to receive request.
// so, doInit() method move to query method.
AndroidSignerContentResolverProvider(
'com.github.haorendashu.nowser.SIGN_EVENT;com.github.haorendashu.nowser.NIP04_ENCRYPT;com.github.haorendashu.nowser.NIP04_DECRYPT;com.github.haorendashu.nowser.NIP44_ENCRYPT;com.github.haorendashu.nowser.NIP44_DECRYPT;com.github.haorendashu.nowser.GET_PUBLIC_KEY');
}

View File

@@ -0,0 +1,179 @@
import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'package:android_content_provider/android_content_provider.dart';
import 'package:nostr_sdk/event.dart';
import 'package:nostr_sdk/nip19/nip19.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/provider/permission_check_mixin.dart';
import '../const/auth_result.dart';
import '../const/auth_type.dart';
import '../data/app.dart';
import '../main.dart';
class AndroidSignerContentResolverProvider extends AndroidContentProvider
with PermissionCheckMixin {
AndroidSignerContentResolverProvider(super.authority);
@override
Future<int> delete(
String uri, String? selection, List<String>? selectionArgs) async {
return 0;
}
@override
Future<String?> getType(String uri) async {
return null;
}
@override
Future<String?> insert(String uri, ContentValues? values) async {
return null;
}
bool inited = false;
@override
Future<CursorData?> query(String uri, List<String>? projection,
String? selection, List<String>? selectionArgs, String? sortOrder) async {
if (!inited) {
await doInit();
inited = true;
}
var authTypeStr =
uri.replaceAll("content://com.github.haorendashu.nowser.", "");
String authDetail = "";
String? pubkey;
String? currentUser;
if (projection != null && projection.isNotEmpty) {
authDetail = projection.first;
if (projection.length > 1) {
pubkey = projection[1];
}
if (projection.length > 2) {
currentUser = projection[2];
}
}
var authType = AuthType.GET_PUBLIC_KEY;
if (authTypeStr == "GET_PUBLIC_KEY") {
authType = AuthType.GET_PUBLIC_KEY;
} else if (authTypeStr == "SIGN_EVENT") {
authType = AuthType.SIGN_EVENT;
} else if (authTypeStr == "GET_RELAYS") {
authType = AuthType.GET_RELAYS;
} else if (authTypeStr == "NIP04_ENCRYPT") {
authType = AuthType.NIP04_ENCRYPT;
} else if (authTypeStr == "NIP04_DECRYPT") {
authType = AuthType.NIP04_DECRYPT;
} else if (authTypeStr == "NIP44_ENCRYPT") {
authType = AuthType.NIP44_ENCRYPT;
} else if (authTypeStr == "NIP44_DECRYPT") {
authType = AuthType.NIP44_DECRYPT;
}
int appType = AppType.ANDROID_APP;
String code = "com.github.haorendashu.nostrmo";
int? eventKind;
dynamic eventObj;
if (authType == AuthType.SIGN_EVENT) {
eventObj = jsonDecode(authDetail);
if (eventObj != null) {
eventKind = eventObj["kind"];
}
}
App? app;
NostrSigner? signer;
var complete = Completer();
rejectFunc(_app) {
saveAuthLog(_app, authType, eventKind, authDetail, AuthResult.REJECT);
complete.complete();
}
confirmFunc(_app, _signer) {
app = _app;
signer = _signer;
complete.complete();
}
checkPermission(null, appType, code, authType, rejectFunc, confirmFunc,
eventKind: eventKind, authDetail: authDetail);
await complete.future;
if (signer == null || app == null) {
return null;
}
MatrixCursorData? data;
if (authType == AuthType.GET_PUBLIC_KEY) {
// TODO should handle permissions
// var permissions = extra["permissions"];
var pubkey = await signer!.getPublicKey();
data =
MatrixCursorData(columnNames: ["signature"], notificationUris: [uri]);
data.addRow([Nip19.encodePubKey(pubkey!)]);
} else if (authType == AuthType.SIGN_EVENT) {
var tags = eventObj["tags"];
Event? event = Event(
app!.pubkey!, eventObj["kind"], tags ?? [], eventObj["content"],
createdAt: eventObj["created_at"]);
log(jsonEncode(event.toJson()));
event = await signer!.signEvent(event);
if (event == null) {
log("sign event fail");
return null;
}
log("sig ${event.sig}");
data = MatrixCursorData(
columnNames: ["signature", "event"], notificationUris: [uri]);
data.addRow([event.sig, jsonEncode(event.toJson())]);
} else if (authType == AuthType.GET_RELAYS) {
// TODO
} else if (authType == AuthType.NIP04_ENCRYPT) {
var result = await signer!.encrypt(pubkey, authDetail);
if (StringUtil.isNotBlank(result)) {
data = MatrixCursorData(
columnNames: ["signature"], notificationUris: [uri]);
data.addRow([result]);
}
} else if (authType == AuthType.NIP04_DECRYPT) {
var result = await signer!.decrypt(pubkey, authDetail);
if (StringUtil.isNotBlank(result)) {
data = MatrixCursorData(
columnNames: ["signature"], notificationUris: [uri]);
data.addRow([result]);
}
} else if (authType == AuthType.NIP44_ENCRYPT) {
var result = await signer!.nip44Encrypt(pubkey, authDetail);
if (StringUtil.isNotBlank(result)) {
data = MatrixCursorData(
columnNames: ["signature"], notificationUris: [uri]);
data.addRow([result]);
}
} else if (authType == AuthType.NIP44_DECRYPT) {
var result = await signer!.nip44Decrypt(pubkey, authDetail);
if (StringUtil.isNotBlank(result)) {
data = MatrixCursorData(
columnNames: ["signature"], notificationUris: [uri]);
data.addRow([result]);
}
}
return data;
}
@override
Future<int> update(String uri, ContentValues? values, String? selection,
List<String>? selectionArgs) async {
return 0;
}
}

View File

@@ -12,12 +12,14 @@ import '../const/connect_type.dart';
import '../data/app.dart';
mixin PermissionCheckMixin {
Future<void> checkPermission(BuildContext context, int appType, String code,
Future<void> checkPermission(BuildContext? context, int appType, String code,
int authType, Function(App?) reject, Function(App, NostrSigner) confirm,
{int? eventKind, String? authDetail}) async {
if (keyProvider.keys.isEmpty) {
// should add a key first
await UserLoginDialog.show(context);
if (context != null) {
await UserLoginDialog.show(context);
}
if (keyProvider.keys.isEmpty) {
return;
}
@@ -27,7 +29,9 @@ mixin PermissionCheckMixin {
if (app == null) {
// app is null, app connect
var newApp = await getApp(appType, code);
await AuthAppConnectDialog.show(context, newApp);
if (context != null) {
await AuthAppConnectDialog.show(context, newApp);
}
// reload from provider
app = appProvider.getApp(appType, code);
}
@@ -63,12 +67,14 @@ mixin PermissionCheckMixin {
return;
}
var authResult = await AuthDialog.show(context, app, authType,
eventKind: eventKind, authDetail: authDetail);
if (authResult == AuthResult.OK) {
saveAuthLog(app, authType, eventKind, authDetail, AuthResult.OK);
confirm(app, signer);
return;
if (context != null) {
var authResult = await AuthDialog.show(context, app, authType,
eventKind: eventKind, authDetail: authDetail);
if (authResult == AuthResult.OK) {
saveAuthLog(app, authType, eventKind, authDetail, AuthResult.OK);
confirm(app, signer);
return;
}
}
}