feat: transfer with file name

This commit is contained in:
Gringo
2026-03-01 09:41:22 +01:00
parent 46280f603c
commit 4a24d9f9e8
10 changed files with 26 additions and 12 deletions
+3 -1
View File
@@ -1,7 +1,9 @@
- [ ] Translations
- [ ] Drop file
- [ ] Keep file name
- [x] Keep file name
- [ ] Use streams
- [ ] Better UI/UX
- [ ] Remove snackbars
- [x] Use https://pub.dev/packages/webcrypto or https://pub.dev/packages/cryptography for efficient web crypto operations
- [ ] 2 options: everyone can delete with the link | only the creator can delete
- [ ] ox, os, original sha256, original size
+8 -4
View File
@@ -6,6 +6,7 @@ import 'package:file_saver/file_saver.dart';
import 'package:flutter/foundation.dart';
import 'package:get/get.dart';
import 'package:ndk/ndk.dart';
import 'package:path/path.dart' as p;
class FileShareController extends GetxController {
final _isLoading = false.obs;
@@ -13,7 +14,6 @@ class FileShareController extends GetxController {
final _error = RxnString();
final _decryptedData = Rxn<Uint8List>();
final _metadata = Rxn<FileMetadata>();
final _filename = RxnString();
final _hasStarted = false.obs;
bool get isLoading => _isLoading.value;
@@ -21,7 +21,6 @@ class FileShareController extends GetxController {
String? get error => _error.value;
Uint8List? get decryptedData => _decryptedData.value;
FileMetadata? get metadata => _metadata.value;
String? get filename => _filename.value;
bool get hasStarted => _hasStarted.value;
@override
@@ -120,10 +119,15 @@ class FileShareController extends GetxController {
try {
final mimeType = _metadata.value?.fileType ?? 'application/octet-stream';
final filename = _metadata.value?.filename ?? 'downloaded_file';
final nameWithoutExt = p.withoutExtension(filename);
final ext = p.extension(filename).replaceFirst('.', '');
await FileSaver.instance.saveFile(
name: _filename.value ?? 'downloaded_file',
name: nameWithoutExt,
bytes: _decryptedData.value!,
fileExtension: mimeType.split('/').last,
fileExtension: ext.isEmpty ? mimeType.split('/').last : ext,
mimeType: MimeType.other,
customMimeType: mimeType,
);
+1
View File
@@ -46,6 +46,7 @@ class HomePageController extends GetxController {
final sharedFile = await shareFile(
bytes: file.bytes!,
contentType: mimeType,
filename: file.name,
);
_sharedFile.value = sharedFile;
+2
View File
@@ -7,6 +7,7 @@ Future<Nip01Event> createEvent({
required String recipientPubkey,
required String key,
required String nonce,
String? filename,
}) async {
final keyPair = Bip340.generatePrivateKey();
final signer = Bip340EventSigner(
@@ -19,6 +20,7 @@ Future<Nip01Event> createEvent({
kind: 15,
tags: [
if (descriptor.type != null) ["file-type", descriptor.type!],
if (filename != null && filename.isNotEmpty) ["filename", filename],
["encryption-algorithm", "aes-gcm"],
["decryption-key", key],
["decryption-nonce", nonce],
+1 -3
View File
@@ -24,9 +24,7 @@ Future<Uint8List> decryptBlob({
0,
encryptedBytes.length - macLength,
);
final macBytes = encryptedBytes.sublist(
encryptedBytes.length - macLength,
);
final macBytes = encryptedBytes.sublist(encryptedBytes.length - macLength);
// Create secret key from bytes
final secretKey = SecretKey(keyBytes);
+4 -3
View File
@@ -17,9 +17,10 @@ Future<EncryptedBlob> encryptBlob(Uint8List bytes) async {
// Concatenate ciphertext + MAC for storage
final macBytes = secretBox.mac.bytes;
final encryptedData = Uint8List.fromList(
[...secretBox.cipherText, ...macBytes],
);
final encryptedData = Uint8List.fromList([
...secretBox.cipherText,
...macBytes,
]);
return EncryptedBlob(
bytes: encryptedData,
+2
View File
@@ -11,6 +11,7 @@ import 'package:ndk_flutter/ndk_flutter.dart';
Future<SharedFile> shareFile({
required Uint8List bytes,
String? contentType,
String? filename,
}) async {
final ndk = Ndk(
NdkConfig(
@@ -41,6 +42,7 @@ Future<SharedFile> shareFile({
recipientPubkey: recipientKeyPair.publicKey,
key: encryptedBlob.key,
nonce: encryptedBlob.nonce,
filename: filename,
);
await ndk.broadcast
+3
View File
@@ -2,6 +2,7 @@ import 'package:ndk/ndk.dart';
class FileMetadata {
final String? fileType;
final String? filename;
final String key;
final String nonce;
final String x;
@@ -10,6 +11,7 @@ class FileMetadata {
FileMetadata({
required this.fileType,
required this.filename,
required this.key,
required this.nonce,
required this.x,
@@ -20,6 +22,7 @@ class FileMetadata {
factory FileMetadata.fromEvent(Nip01Event event) {
return FileMetadata(
fileType: event.getFirstTag('file-type'),
filename: event.getFirstTag('filename'),
key: event.getFirstTag('decryption-key') ?? '',
nonce: event.getFirstTag('decryption-nonce') ?? '',
x: event.getFirstTag('x') ?? '',
+1 -1
View File
@@ -470,7 +470,7 @@ packages:
source: hosted
version: "9.3.0"
path:
dependency: transitive
dependency: "direct main"
description:
name: path
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
+1
View File
@@ -18,6 +18,7 @@ dependencies:
ndk: ^0.7.1-dev.19
ndk_flutter: ^0.0.2-dev.13
nip49: ^1.1.2
path: ^1.9.1
dev_dependencies:
flutter_test: