Skip to content

Commit

Permalink
Add encrypt and unencrypt functions
Browse files Browse the repository at this point in the history
  • Loading branch information
CodeDoctorDE committed Dec 27, 2024
1 parent 89614ab commit f8c9168
Show file tree
Hide file tree
Showing 13 changed files with 302 additions and 17 deletions.
2 changes: 1 addition & 1 deletion api/lib/src/converter/note.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ NoteData noteDataMigrator(Uint8List data, {String? password}) {
}

NoteData archiveNoteDataMigrator(Archive archive, {String? password}) {
var noteData = NoteData(archive, password: password);
var noteData = NoteData.build(archive, password: password);
var metadata = noteData.getMetadata();
if (metadata != null &&
(metadata.fileVersion ?? kFileVersion) < kFileVersion) {
Expand Down
10 changes: 5 additions & 5 deletions api/lib/src/models/data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,22 @@ final class NoteFile {
}

final class NoteData extends ArchiveData<NoteData> {
NoteData(super.archive, {super.state, super.password});
NoteData(super.archive, {super.state});
NoteData.build(super.archive, {super.password}) : super.build();

factory NoteData.fromData(Uint8List data,
{bool disableMigrations = false, String? password}) {
if (disableMigrations) {
final archive = ZipDecoder().decodeBytes(data, password: password);
return NoteData(archive, password: password);
return NoteData.build(archive, password: password);
}
return noteDataMigrator(data, password: password);
}

factory NoteData.fromArchive(Archive archive,
{bool disableMigrations = false, String? password}) {
if (disableMigrations) {
return NoteData(archive, password: password);
return NoteData.build(archive, password: password);
}
return archiveNoteDataMigrator(archive);
}
Expand All @@ -83,8 +84,7 @@ final class NoteData extends ArchiveData<NoteData> {

@override
@useResult
NoteData updateState(ArchiveState state) =>
NoteData(archive, state: state, password: password);
NoteData updateState(ArchiveState state) => NoteData(archive, state: state);

@useResult
(NoteData, String) importAsset(
Expand Down
3 changes: 3 additions & 0 deletions api/lib/src/protocol/event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,9 @@ class DocumentEvent extends ReplayEvent with _$DocumentEvent {
const factory DocumentEvent.elementsLayerConverted(List<String> elements,
[@Default('') String name]) = ElementsLayerConverted;

const factory DocumentEvent.encryptionChanged(String? password) =
EncryptionChanged;

factory DocumentEvent.fromJson(Map<String, dynamic> json) =>
_$DocumentEventFromJson(json);

Expand Down
103 changes: 103 additions & 0 deletions api/lib/src/protocol/event.freezed.dart
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ DocumentEvent _$DocumentEventFromJson(Map<String, dynamic> json) {
return AssetUpdated.fromJson(json);
case 'elementsLayerConverted':
return ElementsLayerConverted.fromJson(json);
case 'encryptionChanged':
return EncryptionChanged.fromJson(json);

default:
throw CheckedFromJsonException(json, 'type', 'DocumentEvent',
Expand Down Expand Up @@ -5908,3 +5910,104 @@ abstract class ElementsLayerConverted extends DocumentEvent {
_$$ElementsLayerConvertedImplCopyWith<_$ElementsLayerConvertedImpl>
get copyWith => throw _privateConstructorUsedError;
}

/// @nodoc
abstract class _$$EncryptionChangedImplCopyWith<$Res> {
factory _$$EncryptionChangedImplCopyWith(_$EncryptionChangedImpl value,
$Res Function(_$EncryptionChangedImpl) then) =
__$$EncryptionChangedImplCopyWithImpl<$Res>;
@useResult
$Res call({String? password});
}

/// @nodoc
class __$$EncryptionChangedImplCopyWithImpl<$Res>
extends _$DocumentEventCopyWithImpl<$Res, _$EncryptionChangedImpl>
implements _$$EncryptionChangedImplCopyWith<$Res> {
__$$EncryptionChangedImplCopyWithImpl(_$EncryptionChangedImpl _value,
$Res Function(_$EncryptionChangedImpl) _then)
: super(_value, _then);

/// Create a copy of DocumentEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? password = freezed,
}) {
return _then(_$EncryptionChangedImpl(
freezed == password
? _value.password
: password // ignore: cast_nullable_to_non_nullable
as String?,
));
}
}

/// @nodoc
@JsonSerializable()
class _$EncryptionChangedImpl extends EncryptionChanged {
const _$EncryptionChangedImpl(this.password, {final String? $type})
: $type = $type ?? 'encryptionChanged',
super._();

factory _$EncryptionChangedImpl.fromJson(Map<String, dynamic> json) =>
_$$EncryptionChangedImplFromJson(json);

@override
final String? password;

@JsonKey(name: 'type')
final String $type;

@override
String toString() {
return 'DocumentEvent.encryptionChanged(password: $password)';
}

@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$EncryptionChangedImpl &&
(identical(other.password, password) ||
other.password == password));
}

@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType, password);

/// Create a copy of DocumentEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$EncryptionChangedImplCopyWith<_$EncryptionChangedImpl> get copyWith =>
__$$EncryptionChangedImplCopyWithImpl<_$EncryptionChangedImpl>(
this, _$identity);

@override
Map<String, dynamic> toJson() {
return _$$EncryptionChangedImplToJson(
this,
);
}
}

abstract class EncryptionChanged extends DocumentEvent {
const factory EncryptionChanged(final String? password) =
_$EncryptionChangedImpl;
const EncryptionChanged._() : super._();

factory EncryptionChanged.fromJson(Map<String, dynamic> json) =
_$EncryptionChangedImpl.fromJson;

String? get password;

/// Create a copy of DocumentEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
_$$EncryptionChangedImplCopyWith<_$EncryptionChangedImpl> get copyWith =>
throw _privateConstructorUsedError;
}
13 changes: 13 additions & 0 deletions api/lib/src/protocol/event.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions api/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -322,8 +322,8 @@ packages:
dependency: "direct main"
description:
path: "packages/lw_file_system_api"
ref: ece8ec258e04b527a5289a7fe089a15c52a976e2
resolved-ref: ece8ec258e04b527a5289a7fe089a15c52a976e2
ref: a0752f136913f64a975cb8b20ccb16fb6ce37737
resolved-ref: a0752f136913f64a975cb8b20ccb16fb6ce37737
url: "https://github.com/LinwoodDev/dart_pkgs"
source: git
version: "1.0.0"
Expand Down
2 changes: 1 addition & 1 deletion api/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ dependencies:
git:
url: https://github.com/LinwoodDev/dart_pkgs
path: packages/lw_file_system_api
ref: ece8ec258e04b527a5289a7fe089a15c52a976e2
ref: a0752f136913f64a975cb8b20ccb16fb6ce37737

dev_dependencies:
test: ^1.25.3
Expand Down
8 changes: 8 additions & 0 deletions app/lib/bloc/document_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1008,6 +1008,14 @@ class DocumentBloc extends ReplayBloc<DocumentEvent, DocumentState> {
reset: true,
);
});
on<EncryptionChanged>((event, emit) {
final current = state;
if (current is! DocumentLoadSuccess) return;
var data = current.data;
final password = event.password;
data = data.changePassword(password);
_saveState(emit, state: current.copyWith(data: data));
});
}

void _saveState(
Expand Down
12 changes: 11 additions & 1 deletion app/lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -645,5 +645,15 @@
"high": "High",
"highDescription": "Description: Maximizes quality at the cost of performance. Bakes an image covering 2 times the visible area, ensuring seamless rendering even during rapid scrolling or zooming.",
"renderResolution": "Render resolution",
"translate": "Translate"
"translate": "Translate",
"unencrypted": "Unencrypted",
"encrypted": "Decrypted",
"encryptDocumentMessage": "Click to encrypt the document",
"unencryptDocumentMessage": "Click to unencrypt the document",
"unencrypt": "Unencrypt",
"encrypt": "Encrypt",
"encryptWarning": "This will encrypt the document. You will need to remember the password to decrypt it.",
"unencryptWarning": "This will unencrypt the document. The password will be removed and everyone with access will be able to open it.",
"confirmPassword": "Confirm password",
"passwordMismatch": "The passwords do not match"
}
143 changes: 142 additions & 1 deletion app/lib/selections/utilities.dart
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ class _UtilitiesViewState extends State<_UtilitiesView>
state.save();
},
),
const SizedBox(height: 20),
const SizedBox(height: 8),
TextFormField(
minLines: 3,
maxLines: 5,
Expand Down Expand Up @@ -182,6 +182,147 @@ class _UtilitiesViewState extends State<_UtilitiesView>
child:
Text(AppLocalizations.of(context).captureThumbnail),
),
MenuItemButton(
leadingIcon: Tooltip(
message: state.data.isEncrypted
? AppLocalizations.of(context).encrypted
: AppLocalizations.of(context).unencrypted,
child: Icon(
state.data.isEncrypted
? PhosphorIconsLight.lock
: PhosphorIconsLight.lockOpen,
),
),
child: Text(
state.data.isEncrypted
? AppLocalizations.of(context).unencrypt
: AppLocalizations.of(context).encrypt,
),
onPressed: () async {
if (state.data.isEncrypted) {
final result = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title:
Text(AppLocalizations.of(context).unencrypt),
content: Text(AppLocalizations.of(context)
.unencryptWarning),
actions: [
TextButton(
onPressed: () =>
Navigator.pop(context, false),
child: Text(MaterialLocalizations.of(context)
.cancelButtonLabel),
),
TextButton(
onPressed: () => Navigator.pop(context, true),
child: Text(MaterialLocalizations.of(context)
.okButtonLabel),
),
],
),
);
if (result != true) return;
context
.read<DocumentBloc>()
.add(EncryptionChanged(null));
} else {
String password = '';
bool showPassword = false,
showConfirmPassword = false;
final formKey = GlobalKey<FormState>();
final result = await showDialog<bool>(
context: context,
builder: (context) => StatefulBuilder(
builder: (context, setState) => Form(
key: formKey,
child: AlertDialog(
title: Text(
AppLocalizations.of(context).encrypt),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextFormField(
decoration: InputDecoration(
labelText:
AppLocalizations.of(context)
.password,
filled: true,
suffixIcon: IconButton(
icon: Icon(showPassword
? PhosphorIconsLight.eye
: PhosphorIconsLight.eyeSlash),
onPressed: () => setState(
() =>
showPassword = !showPassword,
),
),
),
obscureText: !showPassword,
autofocus: true,
onChanged: (value) => password = value,
validator: (value) =>
value?.isEmpty ?? true
? AppLocalizations.of(context)
.shouldNotEmpty
: null,
),
const SizedBox(height: 8),
TextFormField(
decoration: InputDecoration(
labelText:
AppLocalizations.of(context)
.confirmPassword,
filled: true,
suffixIcon: IconButton(
icon: Icon(showConfirmPassword
? PhosphorIconsLight.eye
: PhosphorIconsLight.eyeSlash),
onPressed: () => setState(
() => showConfirmPassword =
!showConfirmPassword,
),
),
),
obscureText: !showConfirmPassword,
validator: (value) => value != password
? AppLocalizations.of(context)
.passwordMismatch
: null,
),
],
),
actions: [
TextButton(
onPressed: () =>
Navigator.pop(context, false),
child: Text(
MaterialLocalizations.of(context)
.cancelButtonLabel),
),
TextButton(
onPressed: () {
if (formKey.currentState?.validate() ??
false) {
Navigator.pop(context, true);
}
},
child: Text(
MaterialLocalizations.of(context)
.okButtonLabel),
),
],
),
),
),
);
if (result != true) return;
context
.read<DocumentBloc>()
.add(EncryptionChanged(password));
}
},
)
],
),
Column(children: [
Expand Down
Loading

0 comments on commit f8c9168

Please sign in to comment.