mirror of
https://gitlab.com/veilid/veilidchat.git
synced 2024-09-20 21:45:36 +00:00
250 lines
7.7 KiB
Dart
250 lines
7.7 KiB
Dart
import 'dart:typed_data';
|
|
|
|
import 'package:change_case/change_case.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
|
import 'package:uuid/uuid.dart';
|
|
import 'package:veilid/veilid.dart';
|
|
|
|
part 'entities.freezed.dart';
|
|
part 'entities.g.dart';
|
|
|
|
// A record of a chunk of messages as reconciled from a conversation
|
|
//
|
|
// DHT Key (Private): messagesKey
|
|
// DHT Secret: messagesSecret
|
|
// Encryption: Symmetric(messagesSecret)
|
|
|
|
@freezed
|
|
class Messages with _$Messages {
|
|
const factory Messages(
|
|
{required Profile profile,
|
|
required Identity identity,
|
|
required bool available}) = _Messages;
|
|
|
|
factory Messages.fromJson(Map<String, dynamic> json) =>
|
|
_$MessagesFromJson(json);
|
|
}
|
|
|
|
// A record of a 1-1 chat that is synchronized between
|
|
// two users. Backed up on a DHT key. Visible and encrypted
|
|
// for the other party
|
|
//
|
|
// DHT Key (UnicastOutbox): conversationPublicKey
|
|
// DHT Secret: conversationSecret
|
|
// Encryption: DH(IdentityA, IdentityB)
|
|
|
|
@freezed
|
|
class Conversation with _$Conversation {
|
|
const factory Conversation(
|
|
{required Profile profile,
|
|
required Identity identity,
|
|
required bool available}) = _Contact;
|
|
|
|
factory Conversation.fromJson(Map<String, dynamic> json) =>
|
|
_$ConversationFromJson(json);
|
|
}
|
|
|
|
// A record of a contact that has accepted a contact invitation
|
|
// Contains a copy of the most recent remote profile as well as
|
|
// a locally edited profile.
|
|
// Contains a copy of the most recent identity from the contact's
|
|
// Master identity dht key
|
|
// Contains
|
|
@freezed
|
|
class Contact with _$Contact {
|
|
const factory Contact({
|
|
// Profile as locally edited
|
|
required Profile localProfile,
|
|
// Profile from remote conversation
|
|
required Profile remoteProfile,
|
|
// Identity from remote conversation
|
|
required Identity identity,
|
|
// xxx
|
|
required bool available,
|
|
}) = _Contact;
|
|
|
|
factory Contact.fromJson(Map<String, dynamic> json) =>
|
|
_$ContactFromJson(json);
|
|
}
|
|
|
|
// Publicly shared profile information for both contacts and accounts
|
|
// Contains:
|
|
// Name - Friendly name
|
|
// Title - Title of user
|
|
// Icon - Little picture to represent user in contact list
|
|
//
|
|
// DHT Key: None
|
|
// Encryption: None
|
|
@freezed
|
|
class Profile with _$Profile {
|
|
const factory Profile({
|
|
// Friendy name
|
|
required String name,
|
|
// Title of user
|
|
required String title,
|
|
// Status/away message
|
|
required String status,
|
|
// Icon DHTData
|
|
required TypedKey icon,
|
|
}) = _Profile;
|
|
factory Profile.fromJson(Map<String, dynamic> json) =>
|
|
_$ProfileFromJson(json);
|
|
}
|
|
|
|
// A linked list of DHT subvalues
|
|
|
|
// A record of an individual account
|
|
// DHT Key (Private): accountPublicKey
|
|
// DHT Secret: accountSecretKey
|
|
@freezed
|
|
class Account with _$Account {
|
|
const factory Account({
|
|
// The user's profile that gets shared with contacts
|
|
required Profile profile,
|
|
// Invisibility makes you always look 'Offline'
|
|
required bool invisible,
|
|
// Auto-away sets 'away' mode after an inactivity time
|
|
required autoAwayTimeoutSec,
|
|
// The contacts for this account
|
|
required DHTListRef<Contact> contacts,
|
|
}) = _Account;
|
|
|
|
factory Account.fromJson(Map<String, dynamic> json) =>
|
|
_$AccountFromJson(json);
|
|
}
|
|
|
|
// Identity Key points to accounts associated with this identity
|
|
// accounts field has a map of service name or uuid to account key pairs
|
|
// DHT Key (Private): identityPublicKey
|
|
// DHT Secret: identitySecretKey (stored encrypted with unlock code in local table store)
|
|
@freezed
|
|
class Identity with _$Identity {
|
|
const factory Identity({
|
|
// Top level account data key
|
|
required TypedKey accountPublicKey,
|
|
// Top level account data secret
|
|
required SecretKey accountSecretKey,
|
|
}) = _Identity;
|
|
|
|
factory Identity.fromJson(Map<String, dynamic> json) =>
|
|
_$IdentityFromJson(json);
|
|
}
|
|
|
|
// Identity Master key structure for created account
|
|
// Master key allows for regeneration of identity DHT record
|
|
// Bidirectional Master<->Identity signature allows for
|
|
// chain of identity ownership for account recovery process
|
|
//
|
|
// Backed by a DHT key at masterPublicKey, the secret is kept
|
|
// completely offline and only written to upon account recovery
|
|
//
|
|
// DHT Key (Public): masterPublicKey
|
|
// DHT Secret: masterSecretKey (kept offline)
|
|
// Encryption: None
|
|
@freezed
|
|
class IdentityMaster with _$IdentityMaster {
|
|
const factory IdentityMaster(
|
|
{required TypedKey identityPublicKey,
|
|
required TypedKey masterPublicKey,
|
|
required Signature identitySignature,
|
|
required Signature masterSignature}) = _IdentityMaster;
|
|
|
|
factory IdentityMaster.fromJson(Map<String, dynamic> json) =>
|
|
_$IdentityMasterFromJson(json);
|
|
}
|
|
|
|
// Local account identitySecretKey is potentially encrypted with a key
|
|
// using the following mechanisms
|
|
// * None : no key, bytes are unencrypted
|
|
// * Pin : Code is a numeric pin (4-256 numeric digits) hashed with Argon2
|
|
// * Password: Code is a UTF-8 string that is hashed with Argon2
|
|
enum EncryptionKeyType {
|
|
none,
|
|
pin,
|
|
password;
|
|
|
|
String toJson() => name.toPascalCase();
|
|
factory EncryptionKeyType.fromJson(String j) =>
|
|
EncryptionKeyType.values.byName(j.toCamelCase());
|
|
}
|
|
|
|
// Local Accounts are stored in a table locally and not backed by a DHT key
|
|
// and represents the accounts that have been added/imported
|
|
// on the current device.
|
|
// Stores a copy of the IdentityMaster associated with the account
|
|
// and the identitySecretKey optionally encrypted by an unlock code
|
|
// This is the root of the account information tree for VeilidChat
|
|
//
|
|
@freezed
|
|
class LocalAccount with _$LocalAccount {
|
|
const factory LocalAccount({
|
|
// The master key record for the account, containing the identityPublicKey
|
|
required IdentityMaster identityMaster,
|
|
// The encrypted identity secret that goes with the identityPublicKey
|
|
required Uint8List identitySecretKeyBytes,
|
|
// The kind of encryption input used on the account
|
|
required EncryptionKeyType encryptionKeyType,
|
|
// If account is not hidden, password can be retrieved via
|
|
required bool biometricsEnabled,
|
|
// Keep account hidden unless account password is entered
|
|
// (tries all hidden accounts with auth method (no biometrics))
|
|
required bool hiddenAccount,
|
|
}) = _LocalAccount;
|
|
|
|
factory LocalAccount.fromJson(Map<String, dynamic> json) =>
|
|
_$LocalAccountFromJson(json);
|
|
}
|
|
|
|
// Each theme supports light and dark mode, optionally selected by the
|
|
// operating system
|
|
enum DarkModePreference {
|
|
system,
|
|
light,
|
|
dark;
|
|
|
|
String toJson() => name.toPascalCase();
|
|
factory DarkModePreference.fromJson(String j) =>
|
|
DarkModePreference.values.byName(j.toCamelCase());
|
|
}
|
|
|
|
// Lock preference changes how frequently the messenger locks its
|
|
// interface and requires the identitySecretKey to be entered (pin/password/etc)
|
|
@freezed
|
|
class LockPreference with _$LockPreference {
|
|
const factory LockPreference({
|
|
required int inactivityLockSecs,
|
|
required bool lockWhenSwitching,
|
|
required bool lockWithSystemLock,
|
|
}) = _LockPreference;
|
|
|
|
factory LockPreference.fromJson(Map<String, dynamic> json) =>
|
|
_$LockPreferenceFromJson(json);
|
|
}
|
|
|
|
// Preferences are stored in a table locally and globally affect all
|
|
// accounts imported/added and the app in general
|
|
@freezed
|
|
class Preferences with _$Preferences {
|
|
const factory Preferences({
|
|
required DarkModePreference darkMode,
|
|
required Uuid activeTheme,
|
|
required LockPreference locking,
|
|
}) = _Preferences;
|
|
|
|
factory Preferences.fromJson(Map<String, dynamic> json) =>
|
|
_$PreferencesFromJson(json);
|
|
}
|
|
|
|
// Themes are stored in a table locally and referenced by their UUID
|
|
@freezed
|
|
class Theme with _$Theme {
|
|
const factory Theme({
|
|
required Uuid uuid,
|
|
required String name,
|
|
required Map<DarkModePreference, ThemeData> modeData,
|
|
}) = _Theme;
|
|
|
|
factory Theme.fromJson(Map<String, dynamic> json) => _$ThemeFromJson(json);
|
|
}
|