Skip to content

Commit

Permalink
Merge pull request #223 from ardriveapp/dev
Browse files Browse the repository at this point in the history
Release 1.2.0 Null Safety
  • Loading branch information
javdhu authored Oct 5, 2021
2 parents 7210aac + 55d3f95 commit dd5edd1
Show file tree
Hide file tree
Showing 129 changed files with 1,796 additions and 1,507 deletions.
7 changes: 4 additions & 3 deletions docs/private_drive_kdf_reference.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// @dart=2.9

import 'dart:convert';
import 'dart:typed_data';

Expand All @@ -7,7 +9,6 @@ import 'package:cryptography/cryptography.dart';
import 'package:uuid/uuid.dart';

void main() async {
final uuid = Uuid();

final keyByteLength = 256 ~/ 8;
final kdf = Hkdf(hmac: Hmac(Sha256()), outputLength: keyByteLength);
Expand All @@ -25,7 +26,7 @@ void main() async {
//
// There's no need to salt here since the drive id will ensure that no two drives have
// the same key even if the user reuses a password.
final driveIdBytes = uuid.parse('<drive uuid>');
final driveIdBytes = Uuid.parse('<drive uuid>');
final walletSignature = await wallet
.sign(Uint8List.fromList(utf8.encode('drive') + driveIdBytes));
final password = '<password provided by user>';
Expand All @@ -39,7 +40,7 @@ void main() async {
// Derive a file key from the user's drive key and the file id.
// We don't salt here since the file id is already random enough but
// we can salt in the future in cases where the user might want to revoke a file key they shared.
final fileIdBytes = Uint8List.fromList(uuid.parse('<file uuid>'));
final fileIdBytes = Uint8List.fromList(Uuid.parse('<file uuid>'));

final fileKey = await kdf.deriveKey(
secretKey: driveKey,
Expand Down
8 changes: 4 additions & 4 deletions lib/app_shell.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'dart:html';

import 'package:ardrive/utils/html/html_util.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
Expand All @@ -14,7 +14,7 @@ import 'components/wallet_switch_dialog.dart';
class AppShell extends StatefulWidget {
final Widget page;

AppShell({Key key, this.page}) : super(key: key);
AppShell({Key? key, required this.page}) : super(key: key);

@override
_AppShellState createState() => _AppShellState();
Expand All @@ -26,7 +26,7 @@ class _AppShellState extends State<AppShell> {
@override
Widget build(BuildContext context) => BlocBuilder<DrivesCubit, DrivesState>(
builder: (context, state) {
window.addEventListener('walletSwitch', (event) {
onArConnectWalletSwitch(() {
if (_showWalletSwitchDialog) {
showDialog(
context: context,
Expand All @@ -36,7 +36,7 @@ class _AppShellState extends State<AppShell> {
//Used to prevent the dialog being shown multiple times.
_showWalletSwitchDialog = false;
});
Widget _buildAppBar() => AppBar(
AppBar _buildAppBar() => AppBar(
// title: Image.asset(
// R.images.brand.logoHorizontalNoSubtitle,
// height: 64,
Expand Down
23 changes: 13 additions & 10 deletions lib/blocs/drive_attach/drive_attach_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,20 @@ part 'drive_attach_state.dart';

/// [DriveAttachCubit] includes logic for attaching drives to the user's profile.
class DriveAttachCubit extends Cubit<DriveAttachState> {
FormGroup form;
late FormGroup form;

final ArweaveService _arweave;
final DriveDao _driveDao;
final SyncCubit _syncBloc;
final DrivesCubit _drivesBloc;

DriveAttachCubit({
String initialDriveId,
String driveName,
@required ArweaveService arweave,
@required DriveDao driveDao,
@required SyncCubit syncBloc,
@required DrivesCubit drivesBloc,
String? initialDriveId,
String? driveName,
required ArweaveService arweave,
required DriveDao driveDao,
required SyncCubit syncBloc,
required DrivesCubit drivesBloc,
}) : _arweave = arweave,
_driveDao = driveDao,
_syncBloc = syncBloc,
Expand Down Expand Up @@ -97,13 +97,16 @@ class DriveAttachCubit extends Cubit<DriveAttachState> {
emit(DriveAttachSuccess());
}

Future<Map<String, dynamic>> _driveNameLoader(
Future<Map<String, dynamic>?> _driveNameLoader(
AbstractControl<dynamic> driveIdControl) async {
if ((driveIdControl as AbstractControl<String>).isNullOrEmpty) {
if ((driveIdControl as AbstractControl<String?>).isNull) {
return null;
}

final String driveId = driveIdControl.value;
final driveId = driveIdControl.value;
if (driveId == null) {
return null;
}
final drive = await _arweave.getLatestDriveEntityWithId(driveId);

if (drive == null) {
Expand Down
30 changes: 14 additions & 16 deletions lib/blocs/drive_create/drive_create_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class DriveCreateCubit extends Cubit<DriveCreateState> {
Validators.pattern(kTrimTrailingRegex),
],
),
'privacy': FormControl(
'privacy': FormControl<String>(
value: DrivePrivacy.private, validators: [Validators.required]),
});

Expand All @@ -29,10 +29,10 @@ class DriveCreateCubit extends Cubit<DriveCreateState> {
final DrivesCubit _drivesCubit;

DriveCreateCubit({
@required ArweaveService arweave,
@required DriveDao driveDao,
@required ProfileCubit profileCubit,
@required DrivesCubit drivesCubit,
required ArweaveService arweave,
required DriveDao driveDao,
required ProfileCubit profileCubit,
required DrivesCubit drivesCubit,
}) : _arweave = arweave,
_driveDao = driveDao,
_profileCubit = profileCubit,
Expand All @@ -46,13 +46,12 @@ class DriveCreateCubit extends Cubit<DriveCreateState> {
return;
}

final profile = _profileCubit.state as ProfileLoggedIn;
if (await _profileCubit.logoutIfWalletMismatch()) {
emit(DriveCreateWalletMismatch());
return;
}

final profile = _profileCubit.state as ProfileLoggedIn;

final minimumWalletBalance = BigInt.from(10000000);
if (profile.walletBalance <= minimumWalletBalance) {
emit(DriveCreateZeroBalance());
Expand All @@ -63,14 +62,12 @@ class DriveCreateCubit extends Cubit<DriveCreateState> {
try {
final driveName = form.control('name').value.toString().trim();
final String drivePrivacy = form.control('privacy').value;

final profile = _profileCubit.state as ProfileLoggedIn;
final walletAddress = await profile.getWalletAddress();
final walletAddress = await profile.wallet.getAddress();
final createRes = await _driveDao.createDrive(
name: driveName,
ownerAddress: walletAddress,
privacy: drivePrivacy,
getWalletSignature: profile.getRawWalletSignature,
wallet: profile.wallet,
password: profile.password,
profileKey: profile.cipherKey,
);
Expand All @@ -86,9 +83,11 @@ class DriveCreateCubit extends Cubit<DriveCreateState> {
);

// TODO: Revert back to using data bundles when the api is stable again.
final owner = await profile.getWalletOwner();
final driveTx = await _arweave.prepareEntityTx(
drive, profile.getRawWalletSignature, owner, createRes.driveKey);
drive,
profile.wallet,
createRes.driveKey,
);

final rootFolderEntity = FolderEntity(
id: drive.rootFolderId,
Expand All @@ -98,8 +97,7 @@ class DriveCreateCubit extends Cubit<DriveCreateState> {

final rootFolderTx = await _arweave.prepareEntityTx(
rootFolderEntity,
profile.getRawWalletSignature,
owner,
profile.wallet,
createRes.driveKey,
);

Expand All @@ -109,7 +107,7 @@ class DriveCreateCubit extends Cubit<DriveCreateState> {
await _driveDao.insertFolderRevision(rootFolderEntity.toRevisionCompanion(
performedAction: RevisionAction.create));

_drivesCubit.selectDrive(drive.id);
_drivesCubit.selectDrive(drive.id!);
} catch (err) {
addError(err);
}
Expand Down
73 changes: 44 additions & 29 deletions lib/blocs/drive_detail/drive_detail_cubit.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dart:async';

import 'package:ardrive/entities/constants.dart';
import 'package:ardrive/models/models.dart';
import 'package:ardrive/services/services.dart';
import 'package:bloc/bloc.dart';
Expand All @@ -19,19 +20,19 @@ class DriveDetailCubit extends Cubit<DriveDetailState> {
final DriveDao _driveDao;
final AppConfig _config;

StreamSubscription _folderSubscription;
StreamSubscription? _folderSubscription;

DriveDetailCubit({
@required this.driveId,
String initialFolderId,
@required ProfileCubit profileCubit,
@required DriveDao driveDao,
@required AppConfig config,
required this.driveId,
String? initialFolderId,
required ProfileCubit profileCubit,
required DriveDao driveDao,
required AppConfig config,
}) : _profileCubit = profileCubit,
_driveDao = driveDao,
_config = config,
super(DriveDetailLoadInProgress()) {
if (driveId == null) {
if (driveId.isEmpty) {
return;
}

Expand All @@ -42,44 +43,46 @@ class DriveDetailCubit extends Cubit<DriveDetailState> {
.folderById(driveId: driveId, folderId: initialFolderId)
.getSingleOrNull();
// Open the root folder if the deep-linked folder could not be found.
openFolder(path: folder?.path ?? '');

openFolder(path: folder?.path ?? rootPath);
// The empty string here is required to open the root folder
});
} else {
openFolder(path: '');
openFolder(path: rootPath);
}
}

void openFolder(
{@required String path,
{required String path,
DriveOrder contentOrderBy = DriveOrder.name,
OrderingMode contentOrderingMode = OrderingMode.asc}) {
emit(DriveDetailLoadInProgress());

unawaited(_folderSubscription?.cancel());

_folderSubscription =
Rx.combineLatest3<Drive, FolderWithContents, ProfileState, void>(
Rx.combineLatest3<Drive?, FolderWithContents, ProfileState, void>(
_driveDao.driveById(driveId: driveId).watchSingleOrNull(),
_driveDao.watchFolderContents(driveId,
folderPath: path,
orderBy: contentOrderBy,
orderingMode: contentOrderingMode),
_profileCubit.startWith(null),
_profileCubit.stream.startWith(ProfileCheckingAvailability()),
(drive, folderContents, _) async {
if (drive == null) {
emit(DriveDetailLoadNotFound());
return;
}

if (folderContents?.folder == null) {
if (folderContents.folder == null) {
// Emit the loading state as it can be a while between the drive being not found, then added,
// and then the folders being loaded.
emit(DriveDetailLoadInProgress());
} else {
final state = this.state is DriveDetailLoadSuccess
? this.state as DriveDetailLoadSuccess
: DriveDetailLoadSuccess();
final profile = _profileCubit.state;
}
final state = this.state is DriveDetailLoadSuccess
? this.state as DriveDetailLoadSuccess
: null;
final profile = _profileCubit.state;
if (state != null) {
emit(
state.copyWith(
currentDrive: drive,
Expand All @@ -90,6 +93,15 @@ class DriveDetailCubit extends Cubit<DriveDetailState> {
contentOrderingMode: contentOrderingMode,
),
);
} else {
emit(DriveDetailLoadSuccess(
currentDrive: drive,
hasWritePermissions: profile is ProfileLoggedIn &&
drive.ownerAddress == profile.walletAddress,
currentFolder: folderContents,
contentOrderBy: contentOrderBy,
contentOrderingMode: contentOrderingMode,
));
}
},
).listen((_) {});
Expand All @@ -103,13 +115,15 @@ class DriveDetailCubit extends Cubit<DriveDetailState> {
selectedItemIsFolder: isFolder,
);

if (state.currentDrive.isPublic && !isFolder) {
final fileWithRevisions = await _driveDao.latestFileRevisionByFileId(
driveId: driveId, fileId: state.selectedItemId);
final dataTxId = (await fileWithRevisions.getSingle()).dataTxId;
state = state.copyWith(
selectedFilePreviewUrl:
Uri.parse('${_config.defaultArweaveGatewayUrl}/${dataTxId}'));
if (state.selectedItemId != null) {
if (state.currentDrive.isPublic && !isFolder) {
final fileWithRevisions = _driveDao.latestFileRevisionByFileId(
driveId: driveId, fileId: state.selectedItemId!);
final dataTxId = (await fileWithRevisions.getSingle()).dataTxId;
state = state.copyWith(
selectedFilePreviewUrl:
Uri.parse('${_config.defaultArweaveGatewayUrl}/$dataTxId'));
}
}

emit(state);
Expand All @@ -120,9 +134,10 @@ class DriveDetailCubit extends Cubit<DriveDetailState> {
OrderingMode contentOrderingMode = OrderingMode.asc}) {
final state = this.state as DriveDetailLoadSuccess;
openFolder(
path: state.currentFolder.folder.path,
contentOrderBy: contentOrderBy,
contentOrderingMode: contentOrderingMode);
path: state.currentFolder.folder?.path ?? rootPath,
contentOrderBy: contentOrderBy,
contentOrderingMode: contentOrderingMode,
);
}

void toggleSelectedItemDetails() {
Expand Down
Loading

0 comments on commit dd5edd1

Please sign in to comment.