Skip to content

Commit

Permalink
Account version 2.0.0
Browse files Browse the repository at this point in the history
Entry files now contain entries separated by lines and indexed by their ids.
  • Loading branch information
GleammerRay committed Jan 15, 2023
1 parent c5e06d4 commit 6182f6a
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 17 deletions.
23 changes: 18 additions & 5 deletions lib/passy_data/common.dart
Expand Up @@ -8,14 +8,13 @@ import 'dart:io';

const String passyVersion = '1.2.0';
const String syncVersion = '1.0.0';
const String accountVersion = '1.1.0';
const String accountVersion = '2.0.0';

bool isLineDelimiter(String priorChar, String char, String lineDelimiter) {
if (lineDelimiter.length == 1) {
return char == lineDelimiter;
} else {
return priorChar + char == lineDelimiter;
}
return '$priorChar$char' == lineDelimiter;
}

String? readLine(RandomAccessFile raf,
Expand All @@ -25,17 +24,31 @@ String? readLine(RandomAccessFile raf,
String priorChar = '';
byte = raf.readByteSync();
while (byte != -1) {
var char = utf8.decode([byte]);
String char = utf8.decode([byte]);
if (isLineDelimiter(priorChar, char, lineDelimiter)) return line;
line += char;
priorChar = char;
byte = raf.readByteSync();
}
if (byte == -1) onEOF?.call();
onEOF?.call();
if (line.isEmpty) return null;
return line;
}

void skipLine(RandomAccessFile raf,
{String lineDelimiter = '\n', void Function()? onEOF}) {
int byte;
String priorChar = '';
byte = raf.readByteSync();
while (byte != -1) {
String char = utf8.decode([byte]);
if (isLineDelimiter(priorChar, char, lineDelimiter)) return;
priorChar = char;
byte = raf.readByteSync();
}
onEOF?.call();
}

void copyDirectorySync(Directory source, Directory destination) {
destination.createSync(recursive: true);
source.listSync(recursive: false).forEach((var entity) {
Expand Down
40 changes: 40 additions & 0 deletions lib/passy_data/legacy/convert_1d1d0_account_to_2d0d0.dart
@@ -0,0 +1,40 @@
import 'dart:io';

import 'package:encrypt/encrypt.dart';
import '../common.dart';

void convert1_1_0AccountTo2_2_0({
required String path,
required Encrypter encrypter,
}) {
// Apply the following changes to id_cards.enc, identities.enc, notes.enc, passwords.enc, payment_cards.enc:
// 1. Read the file and clear it.
// 2. Decrypt entries.
// 3. Split the decrypted entries by newlines.
// 4. Per entry, do the following:
// - 4.1. Retrieve the entry key from the first CSV value.
// - 4.2. Encrypt the entry.
// - 4.3. Join, separating with a comma (,), the entry key from 3.1 and the encrypted entry data from 3.2, adding a newline at the end.
// - 4.4. Append the result of 3.3 to the entries file.
void _convert(File file) {
String _decrypted = decrypt(file.readAsStringSync(), encrypter: encrypter);
List<String> _split = _decrypted.split('\n');
String _result = '';
for (String s in _split) {
// 4
if (s == '') continue;
String _key = s.split(',')[0];
_result += '$_key,${encrypt(s, encrypter: encrypter)}\n';
}
file.writeAsStringSync(_result);
}

_convert(File('$path${Platform.pathSeparator}id_cards.enc'));
_convert(File('$path${Platform.pathSeparator}identities.enc'));
_convert(File('$path${Platform.pathSeparator}notes.enc'));
_convert(File('$path${Platform.pathSeparator}passwords.enc'));
_convert(File('$path${Platform.pathSeparator}payment_cards.enc'));

File(path + Platform.pathSeparator + 'version.txt')
.writeAsStringSync('2.0.0');
}
5 changes: 5 additions & 0 deletions lib/passy_data/legacy/legacy.dart
@@ -1,4 +1,5 @@
import 'package:encrypt/encrypt.dart';
import 'package:passy/passy_data/legacy/convert_1d1d0_account_to_2d0d0.dart';
import 'dart:io';

import '../account_credentials.dart';
Expand Down Expand Up @@ -65,6 +66,10 @@ void convertLegacyAccount({
// Pre 1.1.0 conversion
convertPre1_1_0AccountTo1_1_0(path: path, encrypter: encrypter);
}
if (_accountVersion[1] == 1) {
// 1.1.0 conversion
convert1_1_0AccountTo2_2_0(path: path, encrypter: encrypter);
}
}
// No conversion
_versionFile.writeAsStringSync(accountVersion);
Expand Down
29 changes: 18 additions & 11 deletions lib/passy_data/passy_entries_encrypted_csv_file.dart
@@ -1,5 +1,6 @@
import 'package:encrypt/encrypt.dart';
import 'package:passy/passy_data/common.dart';
import 'package:passy/passy_data/entry_type.dart';
import 'package:passy/passy_data/passy_entry.dart';
import 'package:passy/passy_data/saveable_file_base.dart';
import 'dart:io';
Expand All @@ -24,18 +25,23 @@ class PassyEntriesEncryptedCSVFile<T extends PassyEntry<T>>
required Encrypter encrypter,
}) {
if (file.existsSync()) {
String _decrypted =
decrypt(file.readAsStringSync(), encrypter: encrypter);
List<String> _split = _decrypted.split('\n');
List<List> _decoded = [];
for (String s in _split) {
if (s == '') continue;
_decoded.add(csvDecode(s, recursive: true));
}
Map<String, T> _entries = {};
RandomAccessFile _file = file.openSync();
bool eofReached = false;
do {
String line = readLine(_file, onEOF: () => eofReached = true) ?? '';
if (line == '') continue;
List<dynamic> _decoded1 = csvDecode(line);
List<dynamic> _decoded2 = csvDecode(
decrypt(_decoded1[1], encrypter: encrypter),
recursive: true);
_entries[_decoded1[0]] =
(PassyEntry.fromCSV(entryTypeFromType(T)!)(_decoded2) as T);
} while (eofReached == false);
return PassyEntriesEncryptedCSVFile<T>(
file,
encrypter: encrypter,
value: PassyEntries<T>.fromCSV(_decoded),
value: PassyEntries<T>(entries: _entries),
);
}
file.createSync(recursive: true);
Expand All @@ -50,9 +56,10 @@ class PassyEntriesEncryptedCSVFile<T extends PassyEntry<T>>
String _save() {
String _result = '';
for (List _value in value.toCSV()) {
_result += csvEncode(_value) + '\n';
String _key = _value[0];
_result += '$_key,${encrypt(csvEncode(_value), encrypter: _encrypter)}\n';
}
return _result == '' ? '' : encrypt(_result, encrypter: _encrypter);
return _result;
}

@override
Expand Down
2 changes: 1 addition & 1 deletion lib/passy_data/passy_entry.dart
Expand Up @@ -33,7 +33,7 @@ abstract class PassyEntry<T> with JsonConvertable, CSVConvertable {
}
}

static PassyEntry Function(List csv) fromCSV(EntryType entryType) {
static PassyEntry Function(List csv) fromCSV<T>(entryType) {
switch (entryType) {
case EntryType.password:
return Password.fromCSV;
Expand Down

0 comments on commit 6182f6a

Please sign in to comment.