✨ Keypair Infra
This commit is contained in:
parent
56711889ab
commit
64e2644745
@ -37,6 +37,8 @@ PODS:
|
||||
- DKPhotoGallery/Resource (0.0.19):
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- fast_rsa (0.6.0):
|
||||
- Flutter
|
||||
- file_picker (0.0.1):
|
||||
- DKImagePickerController/PhotoGallery
|
||||
- Flutter
|
||||
@ -262,6 +264,7 @@ DEPENDENCIES:
|
||||
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
|
||||
- croppy (from `.symlinks/plugins/croppy/ios`)
|
||||
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
||||
- fast_rsa (from `.symlinks/plugins/fast_rsa/ios`)
|
||||
- file_picker (from `.symlinks/plugins/file_picker/ios`)
|
||||
- file_saver (from `.symlinks/plugins/file_saver/ios`)
|
||||
- firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`)
|
||||
@ -331,6 +334,8 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/croppy/ios"
|
||||
device_info_plus:
|
||||
:path: ".symlinks/plugins/device_info_plus/ios"
|
||||
fast_rsa:
|
||||
:path: ".symlinks/plugins/fast_rsa/ios"
|
||||
file_picker:
|
||||
:path: ".symlinks/plugins/file_picker/ios"
|
||||
file_saver:
|
||||
@ -411,6 +416,7 @@ SPEC CHECKSUMS:
|
||||
device_info_plus: bf2e3232933866d73fe290f2942f2156cdd10342
|
||||
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
|
||||
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
|
||||
fast_rsa: dc48fb05f26bb108863de122b2a9f5554e8e2591
|
||||
file_picker: b159e0c068aef54932bb15dc9fd1571818edaf49
|
||||
file_saver: 503e386464dbe118f630e17b4c2e1190fa0cf808
|
||||
Firebase: d80354ed7f6df5f9aca55e9eb47cc4b634735eaf
|
||||
|
@ -538,6 +538,282 @@ class SnLocalChatMessageCompanion
|
||||
}
|
||||
}
|
||||
|
||||
class $SnLocalKeyPairTable extends SnLocalKeyPair
|
||||
with TableInfo<$SnLocalKeyPairTable, SnLocalKeyPairData> {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
$SnLocalKeyPairTable(this.attachedDatabase, [this._alias]);
|
||||
static const VerificationMeta _idMeta = const VerificationMeta('id');
|
||||
@override
|
||||
late final GeneratedColumn<String> id = GeneratedColumn<String>(
|
||||
'id', aliasedName, false,
|
||||
type: DriftSqlType.string, requiredDuringInsert: true);
|
||||
static const VerificationMeta _accountIdMeta =
|
||||
const VerificationMeta('accountId');
|
||||
@override
|
||||
late final GeneratedColumn<int> accountId = GeneratedColumn<int>(
|
||||
'account_id', aliasedName, false,
|
||||
type: DriftSqlType.int, requiredDuringInsert: true);
|
||||
static const VerificationMeta _publicKeyMeta =
|
||||
const VerificationMeta('publicKey');
|
||||
@override
|
||||
late final GeneratedColumn<String> publicKey = GeneratedColumn<String>(
|
||||
'public_key', aliasedName, false,
|
||||
type: DriftSqlType.string, requiredDuringInsert: true);
|
||||
static const VerificationMeta _privateKeyMeta =
|
||||
const VerificationMeta('privateKey');
|
||||
@override
|
||||
late final GeneratedColumn<String> privateKey = GeneratedColumn<String>(
|
||||
'private_key', aliasedName, true,
|
||||
type: DriftSqlType.string, requiredDuringInsert: false);
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [id, accountId, publicKey, privateKey];
|
||||
@override
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'sn_local_key_pair';
|
||||
@override
|
||||
VerificationContext validateIntegrity(Insertable<SnLocalKeyPairData> instance,
|
||||
{bool isInserting = false}) {
|
||||
final context = VerificationContext();
|
||||
final data = instance.toColumns(true);
|
||||
if (data.containsKey('id')) {
|
||||
context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta));
|
||||
} else if (isInserting) {
|
||||
context.missing(_idMeta);
|
||||
}
|
||||
if (data.containsKey('account_id')) {
|
||||
context.handle(_accountIdMeta,
|
||||
accountId.isAcceptableOrUnknown(data['account_id']!, _accountIdMeta));
|
||||
} else if (isInserting) {
|
||||
context.missing(_accountIdMeta);
|
||||
}
|
||||
if (data.containsKey('public_key')) {
|
||||
context.handle(_publicKeyMeta,
|
||||
publicKey.isAcceptableOrUnknown(data['public_key']!, _publicKeyMeta));
|
||||
} else if (isInserting) {
|
||||
context.missing(_publicKeyMeta);
|
||||
}
|
||||
if (data.containsKey('private_key')) {
|
||||
context.handle(
|
||||
_privateKeyMeta,
|
||||
privateKey.isAcceptableOrUnknown(
|
||||
data['private_key']!, _privateKeyMeta));
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => const {};
|
||||
@override
|
||||
SnLocalKeyPairData map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
||||
return SnLocalKeyPairData(
|
||||
id: attachedDatabase.typeMapping
|
||||
.read(DriftSqlType.string, data['${effectivePrefix}id'])!,
|
||||
accountId: attachedDatabase.typeMapping
|
||||
.read(DriftSqlType.int, data['${effectivePrefix}account_id'])!,
|
||||
publicKey: attachedDatabase.typeMapping
|
||||
.read(DriftSqlType.string, data['${effectivePrefix}public_key'])!,
|
||||
privateKey: attachedDatabase.typeMapping
|
||||
.read(DriftSqlType.string, data['${effectivePrefix}private_key']),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
$SnLocalKeyPairTable createAlias(String alias) {
|
||||
return $SnLocalKeyPairTable(attachedDatabase, alias);
|
||||
}
|
||||
}
|
||||
|
||||
class SnLocalKeyPairData extends DataClass
|
||||
implements Insertable<SnLocalKeyPairData> {
|
||||
final String id;
|
||||
final int accountId;
|
||||
final String publicKey;
|
||||
final String? privateKey;
|
||||
const SnLocalKeyPairData(
|
||||
{required this.id,
|
||||
required this.accountId,
|
||||
required this.publicKey,
|
||||
this.privateKey});
|
||||
@override
|
||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, Expression>{};
|
||||
map['id'] = Variable<String>(id);
|
||||
map['account_id'] = Variable<int>(accountId);
|
||||
map['public_key'] = Variable<String>(publicKey);
|
||||
if (!nullToAbsent || privateKey != null) {
|
||||
map['private_key'] = Variable<String>(privateKey);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
SnLocalKeyPairCompanion toCompanion(bool nullToAbsent) {
|
||||
return SnLocalKeyPairCompanion(
|
||||
id: Value(id),
|
||||
accountId: Value(accountId),
|
||||
publicKey: Value(publicKey),
|
||||
privateKey: privateKey == null && nullToAbsent
|
||||
? const Value.absent()
|
||||
: Value(privateKey),
|
||||
);
|
||||
}
|
||||
|
||||
factory SnLocalKeyPairData.fromJson(Map<String, dynamic> json,
|
||||
{ValueSerializer? serializer}) {
|
||||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||
return SnLocalKeyPairData(
|
||||
id: serializer.fromJson<String>(json['id']),
|
||||
accountId: serializer.fromJson<int>(json['accountId']),
|
||||
publicKey: serializer.fromJson<String>(json['publicKey']),
|
||||
privateKey: serializer.fromJson<String?>(json['privateKey']),
|
||||
);
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> toJson({ValueSerializer? serializer}) {
|
||||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||
return <String, dynamic>{
|
||||
'id': serializer.toJson<String>(id),
|
||||
'accountId': serializer.toJson<int>(accountId),
|
||||
'publicKey': serializer.toJson<String>(publicKey),
|
||||
'privateKey': serializer.toJson<String?>(privateKey),
|
||||
};
|
||||
}
|
||||
|
||||
SnLocalKeyPairData copyWith(
|
||||
{String? id,
|
||||
int? accountId,
|
||||
String? publicKey,
|
||||
Value<String?> privateKey = const Value.absent()}) =>
|
||||
SnLocalKeyPairData(
|
||||
id: id ?? this.id,
|
||||
accountId: accountId ?? this.accountId,
|
||||
publicKey: publicKey ?? this.publicKey,
|
||||
privateKey: privateKey.present ? privateKey.value : this.privateKey,
|
||||
);
|
||||
SnLocalKeyPairData copyWithCompanion(SnLocalKeyPairCompanion data) {
|
||||
return SnLocalKeyPairData(
|
||||
id: data.id.present ? data.id.value : this.id,
|
||||
accountId: data.accountId.present ? data.accountId.value : this.accountId,
|
||||
publicKey: data.publicKey.present ? data.publicKey.value : this.publicKey,
|
||||
privateKey:
|
||||
data.privateKey.present ? data.privateKey.value : this.privateKey,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('SnLocalKeyPairData(')
|
||||
..write('id: $id, ')
|
||||
..write('accountId: $accountId, ')
|
||||
..write('publicKey: $publicKey, ')
|
||||
..write('privateKey: $privateKey')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(id, accountId, publicKey, privateKey);
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
(other is SnLocalKeyPairData &&
|
||||
other.id == this.id &&
|
||||
other.accountId == this.accountId &&
|
||||
other.publicKey == this.publicKey &&
|
||||
other.privateKey == this.privateKey);
|
||||
}
|
||||
|
||||
class SnLocalKeyPairCompanion extends UpdateCompanion<SnLocalKeyPairData> {
|
||||
final Value<String> id;
|
||||
final Value<int> accountId;
|
||||
final Value<String> publicKey;
|
||||
final Value<String?> privateKey;
|
||||
final Value<int> rowid;
|
||||
const SnLocalKeyPairCompanion({
|
||||
this.id = const Value.absent(),
|
||||
this.accountId = const Value.absent(),
|
||||
this.publicKey = const Value.absent(),
|
||||
this.privateKey = const Value.absent(),
|
||||
this.rowid = const Value.absent(),
|
||||
});
|
||||
SnLocalKeyPairCompanion.insert({
|
||||
required String id,
|
||||
required int accountId,
|
||||
required String publicKey,
|
||||
this.privateKey = const Value.absent(),
|
||||
this.rowid = const Value.absent(),
|
||||
}) : id = Value(id),
|
||||
accountId = Value(accountId),
|
||||
publicKey = Value(publicKey);
|
||||
static Insertable<SnLocalKeyPairData> custom({
|
||||
Expression<String>? id,
|
||||
Expression<int>? accountId,
|
||||
Expression<String>? publicKey,
|
||||
Expression<String>? privateKey,
|
||||
Expression<int>? rowid,
|
||||
}) {
|
||||
return RawValuesInsertable({
|
||||
if (id != null) 'id': id,
|
||||
if (accountId != null) 'account_id': accountId,
|
||||
if (publicKey != null) 'public_key': publicKey,
|
||||
if (privateKey != null) 'private_key': privateKey,
|
||||
if (rowid != null) 'rowid': rowid,
|
||||
});
|
||||
}
|
||||
|
||||
SnLocalKeyPairCompanion copyWith(
|
||||
{Value<String>? id,
|
||||
Value<int>? accountId,
|
||||
Value<String>? publicKey,
|
||||
Value<String?>? privateKey,
|
||||
Value<int>? rowid}) {
|
||||
return SnLocalKeyPairCompanion(
|
||||
id: id ?? this.id,
|
||||
accountId: accountId ?? this.accountId,
|
||||
publicKey: publicKey ?? this.publicKey,
|
||||
privateKey: privateKey ?? this.privateKey,
|
||||
rowid: rowid ?? this.rowid,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, Expression>{};
|
||||
if (id.present) {
|
||||
map['id'] = Variable<String>(id.value);
|
||||
}
|
||||
if (accountId.present) {
|
||||
map['account_id'] = Variable<int>(accountId.value);
|
||||
}
|
||||
if (publicKey.present) {
|
||||
map['public_key'] = Variable<String>(publicKey.value);
|
||||
}
|
||||
if (privateKey.present) {
|
||||
map['private_key'] = Variable<String>(privateKey.value);
|
||||
}
|
||||
if (rowid.present) {
|
||||
map['rowid'] = Variable<int>(rowid.value);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('SnLocalKeyPairCompanion(')
|
||||
..write('id: $id, ')
|
||||
..write('accountId: $accountId, ')
|
||||
..write('publicKey: $publicKey, ')
|
||||
..write('privateKey: $privateKey, ')
|
||||
..write('rowid: $rowid')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _$AppDatabase extends GeneratedDatabase {
|
||||
_$AppDatabase(QueryExecutor e) : super(e);
|
||||
$AppDatabaseManager get managers => $AppDatabaseManager(this);
|
||||
@ -545,12 +821,13 @@ abstract class _$AppDatabase extends GeneratedDatabase {
|
||||
$SnLocalChatChannelTable(this);
|
||||
late final $SnLocalChatMessageTable snLocalChatMessage =
|
||||
$SnLocalChatMessageTable(this);
|
||||
late final $SnLocalKeyPairTable snLocalKeyPair = $SnLocalKeyPairTable(this);
|
||||
@override
|
||||
Iterable<TableInfo<Table, Object?>> get allTables =>
|
||||
allSchemaEntities.whereType<TableInfo<Table, Object?>>();
|
||||
@override
|
||||
List<DatabaseSchemaEntity> get allSchemaEntities =>
|
||||
[snLocalChatChannel, snLocalChatMessage];
|
||||
[snLocalChatChannel, snLocalChatMessage, snLocalKeyPair];
|
||||
}
|
||||
|
||||
typedef $$SnLocalChatChannelTableCreateCompanionBuilder
|
||||
@ -869,6 +1146,165 @@ typedef $$SnLocalChatMessageTableProcessedTableManager = ProcessedTableManager<
|
||||
),
|
||||
SnLocalChatMessageData,
|
||||
PrefetchHooks Function()>;
|
||||
typedef $$SnLocalKeyPairTableCreateCompanionBuilder = SnLocalKeyPairCompanion
|
||||
Function({
|
||||
required String id,
|
||||
required int accountId,
|
||||
required String publicKey,
|
||||
Value<String?> privateKey,
|
||||
Value<int> rowid,
|
||||
});
|
||||
typedef $$SnLocalKeyPairTableUpdateCompanionBuilder = SnLocalKeyPairCompanion
|
||||
Function({
|
||||
Value<String> id,
|
||||
Value<int> accountId,
|
||||
Value<String> publicKey,
|
||||
Value<String?> privateKey,
|
||||
Value<int> rowid,
|
||||
});
|
||||
|
||||
class $$SnLocalKeyPairTableFilterComposer
|
||||
extends Composer<_$AppDatabase, $SnLocalKeyPairTable> {
|
||||
$$SnLocalKeyPairTableFilterComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
ColumnFilters<String> get id => $composableBuilder(
|
||||
column: $table.id, builder: (column) => ColumnFilters(column));
|
||||
|
||||
ColumnFilters<int> get accountId => $composableBuilder(
|
||||
column: $table.accountId, builder: (column) => ColumnFilters(column));
|
||||
|
||||
ColumnFilters<String> get publicKey => $composableBuilder(
|
||||
column: $table.publicKey, builder: (column) => ColumnFilters(column));
|
||||
|
||||
ColumnFilters<String> get privateKey => $composableBuilder(
|
||||
column: $table.privateKey, builder: (column) => ColumnFilters(column));
|
||||
}
|
||||
|
||||
class $$SnLocalKeyPairTableOrderingComposer
|
||||
extends Composer<_$AppDatabase, $SnLocalKeyPairTable> {
|
||||
$$SnLocalKeyPairTableOrderingComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
ColumnOrderings<String> get id => $composableBuilder(
|
||||
column: $table.id, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<int> get accountId => $composableBuilder(
|
||||
column: $table.accountId, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<String> get publicKey => $composableBuilder(
|
||||
column: $table.publicKey, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<String> get privateKey => $composableBuilder(
|
||||
column: $table.privateKey, builder: (column) => ColumnOrderings(column));
|
||||
}
|
||||
|
||||
class $$SnLocalKeyPairTableAnnotationComposer
|
||||
extends Composer<_$AppDatabase, $SnLocalKeyPairTable> {
|
||||
$$SnLocalKeyPairTableAnnotationComposer({
|
||||
required super.$db,
|
||||
required super.$table,
|
||||
super.joinBuilder,
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
GeneratedColumn<String> get id =>
|
||||
$composableBuilder(column: $table.id, builder: (column) => column);
|
||||
|
||||
GeneratedColumn<int> get accountId =>
|
||||
$composableBuilder(column: $table.accountId, builder: (column) => column);
|
||||
|
||||
GeneratedColumn<String> get publicKey =>
|
||||
$composableBuilder(column: $table.publicKey, builder: (column) => column);
|
||||
|
||||
GeneratedColumn<String> get privateKey => $composableBuilder(
|
||||
column: $table.privateKey, builder: (column) => column);
|
||||
}
|
||||
|
||||
class $$SnLocalKeyPairTableTableManager extends RootTableManager<
|
||||
_$AppDatabase,
|
||||
$SnLocalKeyPairTable,
|
||||
SnLocalKeyPairData,
|
||||
$$SnLocalKeyPairTableFilterComposer,
|
||||
$$SnLocalKeyPairTableOrderingComposer,
|
||||
$$SnLocalKeyPairTableAnnotationComposer,
|
||||
$$SnLocalKeyPairTableCreateCompanionBuilder,
|
||||
$$SnLocalKeyPairTableUpdateCompanionBuilder,
|
||||
(
|
||||
SnLocalKeyPairData,
|
||||
BaseReferences<_$AppDatabase, $SnLocalKeyPairTable, SnLocalKeyPairData>
|
||||
),
|
||||
SnLocalKeyPairData,
|
||||
PrefetchHooks Function()> {
|
||||
$$SnLocalKeyPairTableTableManager(
|
||||
_$AppDatabase db, $SnLocalKeyPairTable table)
|
||||
: super(TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
createFilteringComposer: () =>
|
||||
$$SnLocalKeyPairTableFilterComposer($db: db, $table: table),
|
||||
createOrderingComposer: () =>
|
||||
$$SnLocalKeyPairTableOrderingComposer($db: db, $table: table),
|
||||
createComputedFieldComposer: () =>
|
||||
$$SnLocalKeyPairTableAnnotationComposer($db: db, $table: table),
|
||||
updateCompanionCallback: ({
|
||||
Value<String> id = const Value.absent(),
|
||||
Value<int> accountId = const Value.absent(),
|
||||
Value<String> publicKey = const Value.absent(),
|
||||
Value<String?> privateKey = const Value.absent(),
|
||||
Value<int> rowid = const Value.absent(),
|
||||
}) =>
|
||||
SnLocalKeyPairCompanion(
|
||||
id: id,
|
||||
accountId: accountId,
|
||||
publicKey: publicKey,
|
||||
privateKey: privateKey,
|
||||
rowid: rowid,
|
||||
),
|
||||
createCompanionCallback: ({
|
||||
required String id,
|
||||
required int accountId,
|
||||
required String publicKey,
|
||||
Value<String?> privateKey = const Value.absent(),
|
||||
Value<int> rowid = const Value.absent(),
|
||||
}) =>
|
||||
SnLocalKeyPairCompanion.insert(
|
||||
id: id,
|
||||
accountId: accountId,
|
||||
publicKey: publicKey,
|
||||
privateKey: privateKey,
|
||||
rowid: rowid,
|
||||
),
|
||||
withReferenceMapper: (p0) => p0
|
||||
.map((e) => (e.readTable(table), BaseReferences(db, table, e)))
|
||||
.toList(),
|
||||
prefetchHooksCallback: null,
|
||||
));
|
||||
}
|
||||
|
||||
typedef $$SnLocalKeyPairTableProcessedTableManager = ProcessedTableManager<
|
||||
_$AppDatabase,
|
||||
$SnLocalKeyPairTable,
|
||||
SnLocalKeyPairData,
|
||||
$$SnLocalKeyPairTableFilterComposer,
|
||||
$$SnLocalKeyPairTableOrderingComposer,
|
||||
$$SnLocalKeyPairTableAnnotationComposer,
|
||||
$$SnLocalKeyPairTableCreateCompanionBuilder,
|
||||
$$SnLocalKeyPairTableUpdateCompanionBuilder,
|
||||
(
|
||||
SnLocalKeyPairData,
|
||||
BaseReferences<_$AppDatabase, $SnLocalKeyPairTable, SnLocalKeyPairData>
|
||||
),
|
||||
SnLocalKeyPairData,
|
||||
PrefetchHooks Function()>;
|
||||
|
||||
class $AppDatabaseManager {
|
||||
final _$AppDatabase _db;
|
||||
@ -877,4 +1313,6 @@ class $AppDatabaseManager {
|
||||
$$SnLocalChatChannelTableTableManager(_db, _db.snLocalChatChannel);
|
||||
$$SnLocalChatMessageTableTableManager get snLocalChatMessage =>
|
||||
$$SnLocalChatMessageTableTableManager(_db, _db.snLocalChatMessage);
|
||||
$$SnLocalKeyPairTableTableManager get snLocalKeyPair =>
|
||||
$$SnLocalKeyPairTableTableManager(_db, _db.snLocalKeyPair);
|
||||
}
|
||||
|
@ -1,32 +1,4 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:surface/types/keypair.dart';
|
||||
|
||||
class SnKeyPairConverter extends TypeConverter<SnKeyPair, String>
|
||||
with JsonTypeConverter2<SnKeyPair, String, Map<String, Object?>> {
|
||||
const SnKeyPairConverter();
|
||||
|
||||
@override
|
||||
SnKeyPair fromSql(String fromDb) {
|
||||
return fromJson(jsonDecode(fromDb) as Map<String, dynamic>);
|
||||
}
|
||||
|
||||
@override
|
||||
String toSql(SnKeyPair value) {
|
||||
return jsonEncode(toJson(value));
|
||||
}
|
||||
|
||||
@override
|
||||
SnKeyPair fromJson(Map<String, Object?> json) {
|
||||
return SnKeyPair.fromJson(json);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, Object?> toJson(SnKeyPair value) {
|
||||
return value.toJson();
|
||||
}
|
||||
}
|
||||
|
||||
class SnLocalKeyPair extends Table {
|
||||
TextColumn get id => text()();
|
||||
|
@ -25,6 +25,7 @@ import 'package:surface/providers/channel.dart';
|
||||
import 'package:surface/providers/chat_call.dart';
|
||||
import 'package:surface/providers/config.dart';
|
||||
import 'package:surface/providers/database.dart';
|
||||
import 'package:surface/providers/keypair.dart';
|
||||
import 'package:surface/providers/link_preview.dart';
|
||||
import 'package:surface/providers/navigation.dart';
|
||||
import 'package:surface/providers/notification.dart';
|
||||
@ -108,7 +109,8 @@ void main() async {
|
||||
}
|
||||
|
||||
if (!kIsWeb && Platform.isAndroid) {
|
||||
final ImagePickerPlatform imagePickerImplementation = ImagePickerPlatform.instance;
|
||||
final ImagePickerPlatform imagePickerImplementation =
|
||||
ImagePickerPlatform.instance;
|
||||
if (imagePickerImplementation is ImagePickerAndroid) {
|
||||
imagePickerImplementation.useAndroidPhotoPicker = true;
|
||||
}
|
||||
@ -160,6 +162,7 @@ class SolianApp extends StatelessWidget {
|
||||
Provider(create: (ctx) => SnStickerProvider(ctx)),
|
||||
ChangeNotifierProvider(create: (ctx) => UserProvider(ctx)),
|
||||
ChangeNotifierProvider(create: (ctx) => WebSocketProvider(ctx)),
|
||||
Provider(create: (ctx) => KeyPairProvider(ctx)),
|
||||
ChangeNotifierProvider(create: (ctx) => NotificationProvider(ctx)),
|
||||
ChangeNotifierProvider(create: (ctx) => ChatChannelProvider(ctx)),
|
||||
ChangeNotifierProvider(create: (ctx) => ChatCallProvider(ctx)),
|
||||
@ -227,7 +230,8 @@ class _AppSplashScreenState extends State<_AppSplashScreen> with TrayListener {
|
||||
if (prefs.containsKey('first_boot_time')) {
|
||||
final rawTime = prefs.getString('first_boot_time');
|
||||
final time = DateTime.tryParse(rawTime ?? '');
|
||||
if (time != null && time.isBefore(DateTime.now().subtract(const Duration(days: 3)))) {
|
||||
if (time != null &&
|
||||
time.isBefore(DateTime.now().subtract(const Duration(days: 3)))) {
|
||||
final inAppReview = InAppReview.instance;
|
||||
if (prefs.getBool('rating_requested') == true) return;
|
||||
if (await inAppReview.isAvailable()) {
|
||||
@ -258,12 +262,18 @@ class _AppSplashScreenState extends State<_AppSplashScreen> with TrayListener {
|
||||
final remoteVersionString = resp.data?['tag_name'] ?? '0.0.0+0';
|
||||
final remoteVersion = Version.parse(remoteVersionString.split('+').first);
|
||||
final localVersion = Version.parse(localVersionString.split('+').first);
|
||||
final remoteBuildNumber = int.tryParse(remoteVersionString.split('+').last) ?? 0;
|
||||
final localBuildNumber = int.tryParse(localVersionString.split('+').last) ?? 0;
|
||||
logging.info("[Update] Local: $localVersionString, Remote: $remoteVersionString");
|
||||
if ((remoteVersion > localVersion || remoteBuildNumber > localBuildNumber) && mounted) {
|
||||
final remoteBuildNumber =
|
||||
int.tryParse(remoteVersionString.split('+').last) ?? 0;
|
||||
final localBuildNumber =
|
||||
int.tryParse(localVersionString.split('+').last) ?? 0;
|
||||
logging.info(
|
||||
"[Update] Local: $localVersionString, Remote: $remoteVersionString");
|
||||
if ((remoteVersion > localVersion ||
|
||||
remoteBuildNumber > localBuildNumber) &&
|
||||
mounted) {
|
||||
final config = context.read<ConfigProvider>();
|
||||
config.setUpdate(remoteVersionString, resp.data?['body'] ?? 'No changelog');
|
||||
config.setUpdate(
|
||||
remoteVersionString, resp.data?['body'] ?? 'No changelog');
|
||||
logging.info("[Update] Update available: $remoteVersionString");
|
||||
}
|
||||
} catch (e) {
|
||||
@ -298,6 +308,9 @@ class _AppSplashScreenState extends State<_AppSplashScreen> with TrayListener {
|
||||
notify.listen();
|
||||
await notify.registerPushNotifications();
|
||||
if (!mounted) return;
|
||||
final kp = context.read<KeyPairProvider>();
|
||||
kp.listen();
|
||||
if (!mounted) return;
|
||||
final sticker = context.read<SnStickerProvider>();
|
||||
await sticker.listSticker();
|
||||
logging.info('[Bootstrap] Everything initialized!');
|
||||
@ -355,7 +368,9 @@ class _AppSplashScreenState extends State<_AppSplashScreen> with TrayListener {
|
||||
Future<void> _trayInitialization() async {
|
||||
if (kIsWeb || Platform.isAndroid || Platform.isIOS) return;
|
||||
|
||||
final icon = Platform.isWindows ? 'assets/icon/tray-icon.ico' : 'assets/icon/tray-icon.png';
|
||||
final icon = Platform.isWindows
|
||||
? 'assets/icon/tray-icon.ico'
|
||||
: 'assets/icon/tray-icon.png';
|
||||
final appVersion = await PackageInfo.fromPlatform();
|
||||
|
||||
trayManager.addListener(this);
|
||||
|
211
lib/providers/keypair.dart
Normal file
211
lib/providers/keypair.dart
Normal file
@ -0,0 +1,211 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:surface/database/database.dart';
|
||||
import 'package:surface/logger.dart';
|
||||
import 'package:surface/providers/database.dart';
|
||||
import 'package:surface/providers/userinfo.dart';
|
||||
import 'package:surface/providers/websocket.dart';
|
||||
import 'package:surface/types/keypair.dart';
|
||||
import 'package:fast_rsa/fast_rsa.dart';
|
||||
import 'package:surface/types/websocket.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
// Currently the keypair only provide RSA encryption
|
||||
// Supported by the `fast_rsa` package
|
||||
class KeyPairProvider {
|
||||
late final DatabaseProvider _dt;
|
||||
late final UserProvider _ua;
|
||||
late final WebSocketProvider _ws;
|
||||
|
||||
SnKeyPair? activeKp;
|
||||
|
||||
KeyPairProvider(BuildContext context) {
|
||||
_dt = context.read<DatabaseProvider>();
|
||||
_ua = context.read<UserProvider>();
|
||||
_ws = context.read<WebSocketProvider>();
|
||||
|
||||
reloadActive();
|
||||
}
|
||||
|
||||
void listen() {
|
||||
_ws.pk.stream.listen((event) {
|
||||
switch (event.method) {
|
||||
case 'kex.ack':
|
||||
ackKeyExchange(event);
|
||||
break;
|
||||
case 'key.ask':
|
||||
replyAskKeyExchange(event);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<String> decryptText(String text, String kpId) async {
|
||||
final kp = await (_dt.db.snLocalKeyPair.select()
|
||||
..where((e) => e.id.equals(kpId)))
|
||||
.getSingleOrNull();
|
||||
if (kp == null) throw Exception('Key pair not found');
|
||||
return await RSA.decryptPKCS1v15(text, kp.privateKey!);
|
||||
}
|
||||
|
||||
Future<String> encryptText(String text) async {
|
||||
if (activeKp == null) throw Exception('No active key pair');
|
||||
return await RSA.encryptPKCS1v15(text, activeKp!.publicKey);
|
||||
}
|
||||
|
||||
final Map<String, Completer<SnKeyPair>> _requests = {};
|
||||
|
||||
Future<SnKeyPair> askKeyExchange(int kpOwner, String kpId) async {
|
||||
if (_requests.containsKey(kpId)) return await _requests[kpId]!.future;
|
||||
|
||||
final completer = Completer<SnKeyPair>();
|
||||
_requests[kpId] = completer;
|
||||
|
||||
_ws.conn?.sink.add(
|
||||
jsonEncode(WebSocketPackage(
|
||||
method: 'key.ask',
|
||||
endpoint: 'id',
|
||||
payload: {
|
||||
'keypair_id': kpId,
|
||||
'user_id': kpOwner,
|
||||
},
|
||||
)),
|
||||
);
|
||||
|
||||
return Future.any([
|
||||
_requests[kpId]!.future,
|
||||
Future.delayed(const Duration(seconds: 60), () {
|
||||
_requests.remove(kpId);
|
||||
throw TimeoutException("Key exchange timed out");
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
Future<void> ackKeyExchange(WebSocketPackage pkt) async {
|
||||
if (pkt.payload == null) return;
|
||||
final kpMeta = SnKeyPair(
|
||||
id: pkt.payload!['keypair_id'] as String,
|
||||
accountId: pkt.payload!['user_id'] as int,
|
||||
publicKey: pkt.payload!['public_key'] as String,
|
||||
privateKey: pkt.payload?['private_key'] as String?,
|
||||
);
|
||||
|
||||
if (_requests.containsKey(kpMeta.id)) {
|
||||
_requests[kpMeta.id]!.complete(kpMeta);
|
||||
_requests.remove(kpMeta.id);
|
||||
}
|
||||
|
||||
// Save the keypair to the local database
|
||||
await _dt.db.snLocalKeyPair.insertOne(
|
||||
SnLocalKeyPairCompanion.insert(
|
||||
id: kpMeta.id,
|
||||
accountId: kpMeta.accountId,
|
||||
publicKey: kpMeta.publicKey,
|
||||
privateKey: Value(kpMeta.privateKey),
|
||||
),
|
||||
onConflict: DoUpdate(
|
||||
(_) => SnLocalKeyPairCompanion.custom(
|
||||
publicKey: Constant(kpMeta.publicKey),
|
||||
privateKey: Constant(kpMeta.privateKey),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> replyAskKeyExchange(WebSocketPackage pkt) async {
|
||||
final kpId = pkt.payload!['keypair_id'] as String;
|
||||
final userId = pkt.payload!['user_id'] as int;
|
||||
final clientId = pkt.payload!['client_id'] as String;
|
||||
|
||||
final localKp = await (_dt.db.snLocalKeyPair.select()
|
||||
..where((e) => e.id.equals(kpId))
|
||||
..limit(1))
|
||||
.getSingleOrNull();
|
||||
if (localKp == null) return;
|
||||
|
||||
logging.info(
|
||||
'[Kex] Reply to key exchange request of $kpId from user $userId',
|
||||
);
|
||||
|
||||
// We do not give the private key to the client
|
||||
_ws.conn?.sink.add(jsonEncode(
|
||||
WebSocketPackage(
|
||||
method: 'kex.ack',
|
||||
endpoint: 'id',
|
||||
payload: {
|
||||
'keypair_id': localKp.id,
|
||||
'user_id': localKp.accountId,
|
||||
'public_key': localKp.publicKey,
|
||||
'client_id': clientId,
|
||||
},
|
||||
).toJson(),
|
||||
));
|
||||
}
|
||||
|
||||
Future<SnKeyPair?> reloadActive({bool autoEnroll = true}) async {
|
||||
final kp = await (_dt.db.snLocalKeyPair.select()
|
||||
..where((e) => e.accountId.equals(_ua.user!.id))
|
||||
..where((e) => e.privateKey.isNotNull())
|
||||
..limit(1))
|
||||
.getSingleOrNull();
|
||||
|
||||
if (kp != null) {
|
||||
activeKp = SnKeyPair(
|
||||
id: kp.id,
|
||||
accountId: kp.accountId,
|
||||
publicKey: kp.publicKey,
|
||||
privateKey: kp.privateKey,
|
||||
);
|
||||
}
|
||||
|
||||
if (kp == null && autoEnroll) {
|
||||
return await enrollNew();
|
||||
}
|
||||
|
||||
return activeKp;
|
||||
}
|
||||
|
||||
Future<SnKeyPair> enrollNew() async {
|
||||
if (!_ua.isAuthorized) throw Exception('Unauthorized');
|
||||
|
||||
final existsOne = await (_dt.db.snLocalKeyPair.select()
|
||||
..where((e) => e.accountId.equals(_ua.user!.id))
|
||||
..where((e) => e.privateKey.isNotNull())
|
||||
..limit(1))
|
||||
.getSingleOrNull();
|
||||
|
||||
final id = existsOne?.id ?? const Uuid().v4();
|
||||
final kp = await RSA.generate(2048);
|
||||
final kpMeta = SnKeyPair(
|
||||
id: id,
|
||||
accountId: _ua.user!.id,
|
||||
publicKey: kp.publicKey,
|
||||
privateKey: kp.privateKey,
|
||||
);
|
||||
|
||||
// Save the keypair to the local database
|
||||
// If there is already one with private key, it will be overwritten
|
||||
await _dt.db.snLocalKeyPair.insertOne(
|
||||
SnLocalKeyPairCompanion.insert(
|
||||
id: kpMeta.id,
|
||||
accountId: kpMeta.accountId,
|
||||
publicKey: kpMeta.publicKey,
|
||||
privateKey: Value(kpMeta.privateKey),
|
||||
),
|
||||
onConflict: DoUpdate(
|
||||
(_) => SnLocalKeyPairCompanion.custom(
|
||||
publicKey: Constant(kpMeta.publicKey),
|
||||
privateKey: Constant(kpMeta.privateKey),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await reloadActive(autoEnroll: false);
|
||||
|
||||
return kpMeta;
|
||||
}
|
||||
}
|
@ -117,7 +117,8 @@ class WebSocketProvider extends ChangeNotifier {
|
||||
(event) {
|
||||
final packet = WebSocketPackage.fromJson(jsonDecode(event));
|
||||
logging.debug(
|
||||
'[Websocket] Incoming message: ${packet.method} ${packet.message}');
|
||||
'[Websocket] Incoming message: ${packet.method} ${packet.message}',
|
||||
);
|
||||
pk.sink.add(packet);
|
||||
},
|
||||
onDone: () {
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <bitsdojo_window_linux/bitsdojo_window_plugin.h>
|
||||
#include <fast_rsa/fast_rsa_plugin.h>
|
||||
#include <file_saver/file_saver_plugin.h>
|
||||
#include <file_selector_linux/file_selector_plugin.h>
|
||||
#include <flutter_timezone/flutter_timezone_plugin.h>
|
||||
@ -25,6 +26,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) bitsdojo_window_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "BitsdojoWindowPlugin");
|
||||
bitsdojo_window_plugin_register_with_registrar(bitsdojo_window_linux_registrar);
|
||||
g_autoptr(FlPluginRegistrar) fast_rsa_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FastRsaPlugin");
|
||||
fast_rsa_plugin_register_with_registrar(fast_rsa_registrar);
|
||||
g_autoptr(FlPluginRegistrar) file_saver_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSaverPlugin");
|
||||
file_saver_plugin_register_with_registrar(file_saver_registrar);
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
bitsdojo_window_linux
|
||||
fast_rsa
|
||||
file_saver
|
||||
file_selector_linux
|
||||
flutter_timezone
|
||||
|
@ -8,6 +8,7 @@ import Foundation
|
||||
import bitsdojo_window_macos
|
||||
import connectivity_plus
|
||||
import device_info_plus
|
||||
import fast_rsa
|
||||
import file_picker
|
||||
import file_saver
|
||||
import file_selector_macos
|
||||
@ -43,6 +44,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
BitsdojoWindowPlugin.register(with: registry.registrar(forPlugin: "BitsdojoWindowPlugin"))
|
||||
ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin"))
|
||||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||
FastRsaPlugin.register(with: registry.registrar(forPlugin: "FastRsaPlugin"))
|
||||
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
|
||||
FileSaverPlugin.register(with: registry.registrar(forPlugin: "FileSaverPlugin"))
|
||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||
|
16
pubspec.lock
16
pubspec.lock
@ -513,6 +513,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.2"
|
||||
fast_rsa:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: fast_rsa
|
||||
sha256: "205a36c0412b9fabebf3e18ccb5221d819cc28cfb3da988c0bf7b646368d0270"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.8.0"
|
||||
ffi:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -665,6 +673,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.70.2"
|
||||
flat_buffers:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flat_buffers
|
||||
sha256: "380bdcba5664a718bfd4ea20a45d39e13684f5318fcd8883066a55e21f37f4c3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "23.5.26"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
|
@ -137,6 +137,7 @@ dependencies:
|
||||
flutter_timezone: ^4.1.0
|
||||
flutter_map: ^8.1.0
|
||||
geolocator: ^13.0.2
|
||||
fast_rsa: ^3.8.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include <bitsdojo_window_windows/bitsdojo_window_plugin.h>
|
||||
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
|
||||
#include <fast_rsa/fast_rsa_plugin.h>
|
||||
#include <file_saver/file_saver_plugin.h>
|
||||
#include <file_selector_windows/file_selector_windows.h>
|
||||
#include <firebase_core/firebase_core_plugin_c_api.h>
|
||||
@ -35,6 +36,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
registry->GetRegistrarForPlugin("BitsdojoWindowPlugin"));
|
||||
ConnectivityPlusWindowsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin"));
|
||||
FastRsaPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FastRsaPlugin"));
|
||||
FileSaverPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FileSaverPlugin"));
|
||||
FileSelectorWindowsRegisterWithRegistrar(
|
||||
|
@ -5,6 +5,7 @@
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
bitsdojo_window_windows
|
||||
connectivity_plus
|
||||
fast_rsa
|
||||
file_saver
|
||||
file_selector_windows
|
||||
firebase_core
|
||||
|
Loading…
x
Reference in New Issue
Block a user