Merge remote-tracking branch 'api/td/justUseMV' into td/api

This commit is contained in:
td 2024-03-22 21:41:45 +05:30
commit 691190f07a
No known key found for this signature in database
GPG Key ID: 62A30523D4D6CE28
54 changed files with 15538 additions and 0 deletions

2406
lib/fake_matrix_api.dart Normal file

File diff suppressed because it is too large Load Diff

68
lib/matrix_api_lite.dart Normal file
View File

@ -0,0 +1,68 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
library matrix_api_lite;
export 'src/generated/model.dart';
export 'src/matrix_api.dart';
export 'src/model/algorithm_types.dart';
export 'src/model/auth/authentication_data.dart';
export 'src/model/auth/authentication_identifier.dart';
export 'src/model/auth/authentication_password.dart';
export 'src/model/auth/authentication_phone_identifier.dart';
export 'src/model/auth/authentication_recaptcha.dart';
export 'src/model/auth/authentication_third_party_identifier.dart';
export 'src/model/auth/authentication_three_pid_creds.dart';
export 'src/model/auth/authentication_token.dart';
export 'src/model/auth/authentication_types.dart';
export 'src/model/auth/authentication_user_identifier.dart';
export 'src/model/basic_event.dart';
export 'src/model/basic_event_with_sender.dart';
export 'src/model/basic_room_event.dart';
export 'src/model/event_types.dart';
export 'src/model/events/forwarded_room_key_content.dart';
export 'src/model/events/image_pack_content.dart';
export 'src/model/events/olm_plaintext_payload.dart';
export 'src/model/events/room_encrypted_content.dart';
export 'src/model/events/room_encryption_content.dart';
export 'src/model/events/room_key_content.dart';
export 'src/model/events/room_key_request_content.dart';
export 'src/model/events/secret_storage_default_key_content.dart';
export 'src/model/events/secret_storage_key_content.dart';
export 'src/model/events/tombstone_content.dart';
export 'src/model/matrix_connection_exception.dart';
export 'src/model/matrix_event.dart';
export 'src/model/matrix_exception.dart';
export 'src/model/matrix_keys.dart';
export 'src/model/message_types.dart';
export 'src/model/presence.dart';
export 'src/model/presence_content.dart';
export 'src/model/room_creation_types.dart';
export 'src/model/room_summary.dart';
export 'src/model/stripped_state_event.dart';
export 'src/model/sync_update.dart';
export 'src/utils/filter_map_extension.dart';
export 'src/utils/logs.dart';
export 'src/utils/map_copy_extension.dart';
export 'src/utils/try_get_map_extension.dart';
export 'src/values.dart';

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
import 'dart:typed_data';
class FileResponse {
FileResponse({this.contentType, required this.data});
String? contentType;
Uint8List data;
}

View File

@ -0,0 +1,6 @@
import 'fixed_model.dart';
void ignore(Object? input) {}
FileResponse ignoreFile(dynamic input) {
throw UnimplementedError();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,857 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'model.dart';
// **************************************************************************
// EnhancedEnumGenerator
// **************************************************************************
extension DirectionFromStringExtension on Iterable<Direction> {
Direction? fromString(String val) {
final override = {
'b': Direction.b,
'f': Direction.f,
}[val];
// ignore: unnecessary_this
return this.contains(override) ? override : null;
}
}
extension DirectionEnhancedEnum on Direction {
@override
// ignore: override_on_non_overriding_member
String get name => {
Direction.b: 'b',
Direction.f: 'f',
}[this]!;
bool get isB => this == Direction.b;
bool get isF => this == Direction.f;
T when<T>({
required T Function() b,
required T Function() f,
}) =>
{
Direction.b: b,
Direction.f: f,
}[this]!();
T maybeWhen<T>({
T? Function()? b,
T? Function()? f,
required T Function() orElse,
}) =>
{
Direction.b: b,
Direction.f: f,
}[this]
?.call() ??
orElse();
}
extension IncludeFromStringExtension on Iterable<Include> {
Include? fromString(String val) {
final override = {
'all': Include.all,
'participated': Include.participated,
}[val];
// ignore: unnecessary_this
return this.contains(override) ? override : null;
}
}
extension IncludeEnhancedEnum on Include {
@override
// ignore: override_on_non_overriding_member
String get name => {
Include.all: 'all',
Include.participated: 'participated',
}[this]!;
bool get isAll => this == Include.all;
bool get isParticipated => this == Include.participated;
T when<T>({
required T Function() all,
required T Function() participated,
}) =>
{
Include.all: all,
Include.participated: participated,
}[this]!();
T maybeWhen<T>({
T? Function()? all,
T? Function()? participated,
required T Function() orElse,
}) =>
{
Include.all: all,
Include.participated: participated,
}[this]
?.call() ??
orElse();
}
extension ThirdPartyIdentifierMediumFromStringExtension
on Iterable<ThirdPartyIdentifierMedium> {
ThirdPartyIdentifierMedium? fromString(String val) {
final override = {
'email': ThirdPartyIdentifierMedium.email,
'msisdn': ThirdPartyIdentifierMedium.msisdn,
}[val];
// ignore: unnecessary_this
return this.contains(override) ? override : null;
}
}
extension ThirdPartyIdentifierMediumEnhancedEnum on ThirdPartyIdentifierMedium {
@override
// ignore: override_on_non_overriding_member
String get name => {
ThirdPartyIdentifierMedium.email: 'email',
ThirdPartyIdentifierMedium.msisdn: 'msisdn',
}[this]!;
bool get isEmail => this == ThirdPartyIdentifierMedium.email;
bool get isMsisdn => this == ThirdPartyIdentifierMedium.msisdn;
T when<T>({
required T Function() email,
required T Function() msisdn,
}) =>
{
ThirdPartyIdentifierMedium.email: email,
ThirdPartyIdentifierMedium.msisdn: msisdn,
}[this]!();
T maybeWhen<T>({
T? Function()? email,
T? Function()? msisdn,
required T Function() orElse,
}) =>
{
ThirdPartyIdentifierMedium.email: email,
ThirdPartyIdentifierMedium.msisdn: msisdn,
}[this]
?.call() ??
orElse();
}
extension IdServerUnbindResultFromStringExtension
on Iterable<IdServerUnbindResult> {
IdServerUnbindResult? fromString(String val) {
final override = {
'no-support': IdServerUnbindResult.noSupport,
'success': IdServerUnbindResult.success,
}[val];
// ignore: unnecessary_this
return this.contains(override) ? override : null;
}
}
extension IdServerUnbindResultEnhancedEnum on IdServerUnbindResult {
@override
// ignore: override_on_non_overriding_member
String get name => {
IdServerUnbindResult.noSupport: 'no-support',
IdServerUnbindResult.success: 'success',
}[this]!;
bool get isNoSupport => this == IdServerUnbindResult.noSupport;
bool get isSuccess => this == IdServerUnbindResult.success;
T when<T>({
required T Function() noSupport,
required T Function() success,
}) =>
{
IdServerUnbindResult.noSupport: noSupport,
IdServerUnbindResult.success: success,
}[this]!();
T maybeWhen<T>({
T? Function()? noSupport,
T? Function()? success,
required T Function() orElse,
}) =>
{
IdServerUnbindResult.noSupport: noSupport,
IdServerUnbindResult.success: success,
}[this]
?.call() ??
orElse();
}
extension RoomVersionAvailableFromStringExtension
on Iterable<RoomVersionAvailable> {
RoomVersionAvailable? fromString(String val) {
final override = {
'stable': RoomVersionAvailable.stable,
'unstable': RoomVersionAvailable.unstable,
}[val];
// ignore: unnecessary_this
return this.contains(override) ? override : null;
}
}
extension RoomVersionAvailableEnhancedEnum on RoomVersionAvailable {
@override
// ignore: override_on_non_overriding_member
String get name => {
RoomVersionAvailable.stable: 'stable',
RoomVersionAvailable.unstable: 'unstable',
}[this]!;
bool get isStable => this == RoomVersionAvailable.stable;
bool get isUnstable => this == RoomVersionAvailable.unstable;
T when<T>({
required T Function() stable,
required T Function() unstable,
}) =>
{
RoomVersionAvailable.stable: stable,
RoomVersionAvailable.unstable: unstable,
}[this]!();
T maybeWhen<T>({
T? Function()? stable,
T? Function()? unstable,
required T Function() orElse,
}) =>
{
RoomVersionAvailable.stable: stable,
RoomVersionAvailable.unstable: unstable,
}[this]
?.call() ??
orElse();
}
extension CreateRoomPresetFromStringExtension on Iterable<CreateRoomPreset> {
CreateRoomPreset? fromString(String val) {
final override = {
'private_chat': CreateRoomPreset.privateChat,
'public_chat': CreateRoomPreset.publicChat,
'trusted_private_chat': CreateRoomPreset.trustedPrivateChat,
}[val];
// ignore: unnecessary_this
return this.contains(override) ? override : null;
}
}
extension CreateRoomPresetEnhancedEnum on CreateRoomPreset {
@override
// ignore: override_on_non_overriding_member
String get name => {
CreateRoomPreset.privateChat: 'private_chat',
CreateRoomPreset.publicChat: 'public_chat',
CreateRoomPreset.trustedPrivateChat: 'trusted_private_chat',
}[this]!;
bool get isPrivateChat => this == CreateRoomPreset.privateChat;
bool get isPublicChat => this == CreateRoomPreset.publicChat;
bool get isTrustedPrivateChat => this == CreateRoomPreset.trustedPrivateChat;
T when<T>({
required T Function() privateChat,
required T Function() publicChat,
required T Function() trustedPrivateChat,
}) =>
{
CreateRoomPreset.privateChat: privateChat,
CreateRoomPreset.publicChat: publicChat,
CreateRoomPreset.trustedPrivateChat: trustedPrivateChat,
}[this]!();
T maybeWhen<T>({
T? Function()? privateChat,
T? Function()? publicChat,
T? Function()? trustedPrivateChat,
required T Function() orElse,
}) =>
{
CreateRoomPreset.privateChat: privateChat,
CreateRoomPreset.publicChat: publicChat,
CreateRoomPreset.trustedPrivateChat: trustedPrivateChat,
}[this]
?.call() ??
orElse();
}
extension VisibilityFromStringExtension on Iterable<Visibility> {
Visibility? fromString(String val) {
final override = {
'private': Visibility.private,
'public': Visibility.public,
}[val];
// ignore: unnecessary_this
return this.contains(override) ? override : null;
}
}
extension VisibilityEnhancedEnum on Visibility {
@override
// ignore: override_on_non_overriding_member
String get name => {
Visibility.private: 'private',
Visibility.public: 'public',
}[this]!;
bool get isPrivate => this == Visibility.private;
bool get isPublic => this == Visibility.public;
T when<T>({
required T Function() private,
required T Function() public,
}) =>
{
Visibility.private: private,
Visibility.public: public,
}[this]!();
T maybeWhen<T>({
T? Function()? private,
T? Function()? public,
required T Function() orElse,
}) =>
{
Visibility.private: private,
Visibility.public: public,
}[this]
?.call() ??
orElse();
}
extension LoginTypeFromStringExtension on Iterable<LoginType> {
LoginType? fromString(String val) {
final override = {
'm.login.password': LoginType.mLoginPassword,
'm.login.token': LoginType.mLoginToken,
}[val];
// ignore: unnecessary_this
return this.contains(override) ? override : null;
}
}
extension LoginTypeEnhancedEnum on LoginType {
@override
// ignore: override_on_non_overriding_member
String get name => {
LoginType.mLoginPassword: 'm.login.password',
LoginType.mLoginToken: 'm.login.token',
}[this]!;
bool get isMLoginPassword => this == LoginType.mLoginPassword;
bool get isMLoginToken => this == LoginType.mLoginToken;
T when<T>({
required T Function() mLoginPassword,
required T Function() mLoginToken,
}) =>
{
LoginType.mLoginPassword: mLoginPassword,
LoginType.mLoginToken: mLoginToken,
}[this]!();
T maybeWhen<T>({
T? Function()? mLoginPassword,
T? Function()? mLoginToken,
required T Function() orElse,
}) =>
{
LoginType.mLoginPassword: mLoginPassword,
LoginType.mLoginToken: mLoginToken,
}[this]
?.call() ??
orElse();
}
extension PresenceTypeFromStringExtension on Iterable<PresenceType> {
PresenceType? fromString(String val) {
final override = {
'offline': PresenceType.offline,
'online': PresenceType.online,
'unavailable': PresenceType.unavailable,
}[val];
// ignore: unnecessary_this
return this.contains(override) ? override : null;
}
}
extension PresenceTypeEnhancedEnum on PresenceType {
@override
// ignore: override_on_non_overriding_member
String get name => {
PresenceType.offline: 'offline',
PresenceType.online: 'online',
PresenceType.unavailable: 'unavailable',
}[this]!;
bool get isOffline => this == PresenceType.offline;
bool get isOnline => this == PresenceType.online;
bool get isUnavailable => this == PresenceType.unavailable;
T when<T>({
required T Function() offline,
required T Function() online,
required T Function() unavailable,
}) =>
{
PresenceType.offline: offline,
PresenceType.online: online,
PresenceType.unavailable: unavailable,
}[this]!();
T maybeWhen<T>({
T? Function()? offline,
T? Function()? online,
T? Function()? unavailable,
required T Function() orElse,
}) =>
{
PresenceType.offline: offline,
PresenceType.online: online,
PresenceType.unavailable: unavailable,
}[this]
?.call() ??
orElse();
}
extension PushRuleKindFromStringExtension on Iterable<PushRuleKind> {
PushRuleKind? fromString(String val) {
final override = {
'content': PushRuleKind.content,
'override': PushRuleKind.override,
'room': PushRuleKind.room,
'sender': PushRuleKind.sender,
'underride': PushRuleKind.underride,
}[val];
// ignore: unnecessary_this
return this.contains(override) ? override : null;
}
}
extension PushRuleKindEnhancedEnum on PushRuleKind {
@override
// ignore: override_on_non_overriding_member
String get name => {
PushRuleKind.content: 'content',
PushRuleKind.override: 'override',
PushRuleKind.room: 'room',
PushRuleKind.sender: 'sender',
PushRuleKind.underride: 'underride',
}[this]!;
bool get isContent => this == PushRuleKind.content;
bool get isOverride => this == PushRuleKind.override;
bool get isRoom => this == PushRuleKind.room;
bool get isSender => this == PushRuleKind.sender;
bool get isUnderride => this == PushRuleKind.underride;
T when<T>({
required T Function() content,
required T Function() override,
required T Function() room,
required T Function() sender,
required T Function() underride,
}) =>
{
PushRuleKind.content: content,
PushRuleKind.override: override,
PushRuleKind.room: room,
PushRuleKind.sender: sender,
PushRuleKind.underride: underride,
}[this]!();
T maybeWhen<T>({
T? Function()? content,
T? Function()? override,
T? Function()? room,
T? Function()? sender,
T? Function()? underride,
required T Function() orElse,
}) =>
{
PushRuleKind.content: content,
PushRuleKind.override: override,
PushRuleKind.room: room,
PushRuleKind.sender: sender,
PushRuleKind.underride: underride,
}[this]
?.call() ??
orElse();
}
extension AccountKindFromStringExtension on Iterable<AccountKind> {
AccountKind? fromString(String val) {
final override = {
'guest': AccountKind.guest,
'user': AccountKind.user,
}[val];
// ignore: unnecessary_this
return this.contains(override) ? override : null;
}
}
extension AccountKindEnhancedEnum on AccountKind {
@override
// ignore: override_on_non_overriding_member
String get name => {
AccountKind.guest: 'guest',
AccountKind.user: 'user',
}[this]!;
bool get isGuest => this == AccountKind.guest;
bool get isUser => this == AccountKind.user;
T when<T>({
required T Function() guest,
required T Function() user,
}) =>
{
AccountKind.guest: guest,
AccountKind.user: user,
}[this]!();
T maybeWhen<T>({
T? Function()? guest,
T? Function()? user,
required T Function() orElse,
}) =>
{
AccountKind.guest: guest,
AccountKind.user: user,
}[this]
?.call() ??
orElse();
}
extension BackupAlgorithmFromStringExtension on Iterable<BackupAlgorithm> {
BackupAlgorithm? fromString(String val) {
final override = {
'm.megolm_backup.v1.curve25519-aes-sha2':
BackupAlgorithm.mMegolmBackupV1Curve25519AesSha2,
}[val];
// ignore: unnecessary_this
return this.contains(override) ? override : null;
}
}
extension BackupAlgorithmEnhancedEnum on BackupAlgorithm {
@override
// ignore: override_on_non_overriding_member
String get name => {
BackupAlgorithm.mMegolmBackupV1Curve25519AesSha2:
'm.megolm_backup.v1.curve25519-aes-sha2',
}[this]!;
bool get isMMegolmBackupV1Curve25519AesSha2 =>
this == BackupAlgorithm.mMegolmBackupV1Curve25519AesSha2;
T when<T>({
required T Function() mMegolmBackupV1Curve25519AesSha2,
}) =>
{
BackupAlgorithm.mMegolmBackupV1Curve25519AesSha2:
mMegolmBackupV1Curve25519AesSha2,
}[this]!();
T maybeWhen<T>({
T? Function()? mMegolmBackupV1Curve25519AesSha2,
required T Function() orElse,
}) =>
{
BackupAlgorithm.mMegolmBackupV1Curve25519AesSha2:
mMegolmBackupV1Curve25519AesSha2,
}[this]
?.call() ??
orElse();
}
extension MembershipFromStringExtension on Iterable<Membership> {
Membership? fromString(String val) {
final override = {
'ban': Membership.ban,
'invite': Membership.invite,
'join': Membership.join,
'knock': Membership.knock,
'leave': Membership.leave,
}[val];
// ignore: unnecessary_this
return this.contains(override) ? override : null;
}
}
extension MembershipEnhancedEnum on Membership {
@override
// ignore: override_on_non_overriding_member
String get name => {
Membership.ban: 'ban',
Membership.invite: 'invite',
Membership.join: 'join',
Membership.knock: 'knock',
Membership.leave: 'leave',
}[this]!;
bool get isBan => this == Membership.ban;
bool get isInvite => this == Membership.invite;
bool get isJoin => this == Membership.join;
bool get isKnock => this == Membership.knock;
bool get isLeave => this == Membership.leave;
T when<T>({
required T Function() ban,
required T Function() invite,
required T Function() join,
required T Function() knock,
required T Function() leave,
}) =>
{
Membership.ban: ban,
Membership.invite: invite,
Membership.join: join,
Membership.knock: knock,
Membership.leave: leave,
}[this]!();
T maybeWhen<T>({
T? Function()? ban,
T? Function()? invite,
T? Function()? join,
T? Function()? knock,
T? Function()? leave,
required T Function() orElse,
}) =>
{
Membership.ban: ban,
Membership.invite: invite,
Membership.join: join,
Membership.knock: knock,
Membership.leave: leave,
}[this]
?.call() ??
orElse();
}
extension ReceiptTypeFromStringExtension on Iterable<ReceiptType> {
ReceiptType? fromString(String val) {
final override = {
'm.fully_read': ReceiptType.mFullyRead,
'm.read': ReceiptType.mRead,
'm.read.private': ReceiptType.mReadPrivate,
}[val];
// ignore: unnecessary_this
return this.contains(override) ? override : null;
}
}
extension ReceiptTypeEnhancedEnum on ReceiptType {
@override
// ignore: override_on_non_overriding_member
String get name => {
ReceiptType.mFullyRead: 'm.fully_read',
ReceiptType.mRead: 'm.read',
ReceiptType.mReadPrivate: 'm.read.private',
}[this]!;
bool get isMFullyRead => this == ReceiptType.mFullyRead;
bool get isMRead => this == ReceiptType.mRead;
bool get isMReadPrivate => this == ReceiptType.mReadPrivate;
T when<T>({
required T Function() mFullyRead,
required T Function() mRead,
required T Function() mReadPrivate,
}) =>
{
ReceiptType.mFullyRead: mFullyRead,
ReceiptType.mRead: mRead,
ReceiptType.mReadPrivate: mReadPrivate,
}[this]!();
T maybeWhen<T>({
T? Function()? mFullyRead,
T? Function()? mRead,
T? Function()? mReadPrivate,
required T Function() orElse,
}) =>
{
ReceiptType.mFullyRead: mFullyRead,
ReceiptType.mRead: mRead,
ReceiptType.mReadPrivate: mReadPrivate,
}[this]
?.call() ??
orElse();
}
extension GroupKeyFromStringExtension on Iterable<GroupKey> {
GroupKey? fromString(String val) {
final override = {
'room_id': GroupKey.roomId,
'sender': GroupKey.sender,
}[val];
// ignore: unnecessary_this
return this.contains(override) ? override : null;
}
}
extension GroupKeyEnhancedEnum on GroupKey {
@override
// ignore: override_on_non_overriding_member
String get name => {
GroupKey.roomId: 'room_id',
GroupKey.sender: 'sender',
}[this]!;
bool get isRoomId => this == GroupKey.roomId;
bool get isSender => this == GroupKey.sender;
T when<T>({
required T Function() roomId,
required T Function() sender,
}) =>
{
GroupKey.roomId: roomId,
GroupKey.sender: sender,
}[this]!();
T maybeWhen<T>({
T? Function()? roomId,
T? Function()? sender,
required T Function() orElse,
}) =>
{
GroupKey.roomId: roomId,
GroupKey.sender: sender,
}[this]
?.call() ??
orElse();
}
extension KeyKindFromStringExtension on Iterable<KeyKind> {
KeyKind? fromString(String val) {
final override = {
'content.body': KeyKind.contentBody,
'content.name': KeyKind.contentName,
'content.topic': KeyKind.contentTopic,
}[val];
// ignore: unnecessary_this
return this.contains(override) ? override : null;
}
}
extension KeyKindEnhancedEnum on KeyKind {
@override
// ignore: override_on_non_overriding_member
String get name => {
KeyKind.contentBody: 'content.body',
KeyKind.contentName: 'content.name',
KeyKind.contentTopic: 'content.topic',
}[this]!;
bool get isContentBody => this == KeyKind.contentBody;
bool get isContentName => this == KeyKind.contentName;
bool get isContentTopic => this == KeyKind.contentTopic;
T when<T>({
required T Function() contentBody,
required T Function() contentName,
required T Function() contentTopic,
}) =>
{
KeyKind.contentBody: contentBody,
KeyKind.contentName: contentName,
KeyKind.contentTopic: contentTopic,
}[this]!();
T maybeWhen<T>({
T? Function()? contentBody,
T? Function()? contentName,
T? Function()? contentTopic,
required T Function() orElse,
}) =>
{
KeyKind.contentBody: contentBody,
KeyKind.contentName: contentName,
KeyKind.contentTopic: contentTopic,
}[this]
?.call() ??
orElse();
}
extension SearchOrderFromStringExtension on Iterable<SearchOrder> {
SearchOrder? fromString(String val) {
final override = {
'rank': SearchOrder.rank,
'recent': SearchOrder.recent,
}[val];
// ignore: unnecessary_this
return this.contains(override) ? override : null;
}
}
extension SearchOrderEnhancedEnum on SearchOrder {
@override
// ignore: override_on_non_overriding_member
String get name => {
SearchOrder.rank: 'rank',
SearchOrder.recent: 'recent',
}[this]!;
bool get isRank => this == SearchOrder.rank;
bool get isRecent => this == SearchOrder.recent;
T when<T>({
required T Function() rank,
required T Function() recent,
}) =>
{
SearchOrder.rank: rank,
SearchOrder.recent: recent,
}[this]!();
T maybeWhen<T>({
T? Function()? rank,
T? Function()? recent,
required T Function() orElse,
}) =>
{
SearchOrder.rank: rank,
SearchOrder.recent: recent,
}[this]
?.call() ??
orElse();
}
extension EventFormatFromStringExtension on Iterable<EventFormat> {
EventFormat? fromString(String val) {
final override = {
'client': EventFormat.client,
'federation': EventFormat.federation,
}[val];
// ignore: unnecessary_this
return this.contains(override) ? override : null;
}
}
extension EventFormatEnhancedEnum on EventFormat {
@override
// ignore: override_on_non_overriding_member
String get name => {
EventFormat.client: 'client',
EventFormat.federation: 'federation',
}[this]!;
bool get isClient => this == EventFormat.client;
bool get isFederation => this == EventFormat.federation;
T when<T>({
required T Function() client,
required T Function() federation,
}) =>
{
EventFormat.client: client,
EventFormat.federation: federation,
}[this]!();
T maybeWhen<T>({
T? Function()? client,
T? Function()? federation,
required T Function() orElse,
}) =>
{
EventFormat.client: client,
EventFormat.federation: federation,
}[this]
?.call() ??
orElse();
}
extension MethodFromStringExtension on Iterable<Method> {
Method? fromString(String val) {
final override = {
'crop': Method.crop,
'scale': Method.scale,
}[val];
// ignore: unnecessary_this
return this.contains(override) ? override : null;
}
}
extension MethodEnhancedEnum on Method {
@override
// ignore: override_on_non_overriding_member
String get name => {
Method.crop: 'crop',
Method.scale: 'scale',
}[this]!;
bool get isCrop => this == Method.crop;
bool get isScale => this == Method.scale;
T when<T>({
required T Function() crop,
required T Function() scale,
}) =>
{
Method.crop: crop,
Method.scale: scale,
}[this]!();
T maybeWhen<T>({
T? Function()? crop,
T? Function()? scale,
required T Function() orElse,
}) =>
{
Method.crop: crop,
Method.scale: scale,
}[this]
?.call() ??
orElse();
}

View File

@ -0,0 +1,240 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';
import 'package:http/http.dart' as http;
import '../matrix_api_lite.dart';
import 'generated/api.dart';
enum RequestType { GET, POST, PUT, DELETE }
class MatrixApi extends Api {
/// The homeserver this client is communicating with.
Uri? get homeserver => baseUri;
set homeserver(Uri? uri) => baseUri = uri;
/// This is the access token for the matrix client. When it is undefined, then
/// the user needs to sign in first.
String? get accessToken => bearerToken;
set accessToken(String? token) => bearerToken = token;
@override
Never unexpectedResponse(http.BaseResponse response, Uint8List body) {
if (response.statusCode >= 400 && response.statusCode < 500) {
final resp = json.decode(utf8.decode(body));
if (resp is Map<String, Object?>) {
throw MatrixException.fromJson(resp);
}
}
super.unexpectedResponse(response, body);
}
MatrixApi({
Uri? homeserver,
String? accessToken,
http.Client? httpClient,
}) : super(
httpClient: httpClient,
baseUri: homeserver,
bearerToken: accessToken);
/// Used for all Matrix json requests using the [c2s API](https://matrix.org/docs/spec/client_server/r0.6.0.html).
///
/// Throws: FormatException, MatrixException
///
/// You must first set [this.homeserver] and for some endpoints also
/// [this.accessToken] before you can use this! For example to send a
/// message to a Matrix room with the id '!fjd823j:example.com' you call:
/// ```
/// final resp = await request(
/// RequestType.PUT,
/// '/r0/rooms/!fjd823j:example.com/send/m.room.message/$txnId',
/// data: {
/// 'msgtype': 'm.text',
/// 'body': 'hello'
/// }
/// );
/// ```
///
Future<Map<String, Object?>> request(
RequestType type,
String action, {
dynamic data = '',
String contentType = 'application/json',
Map<String, Object?>? query,
}) async {
if (homeserver == null) {
throw ('No homeserver specified.');
}
dynamic json;
(data is! String) ? json = jsonEncode(data) : json = data;
if (data is List<int> || action.startsWith('/media/v3/upload')) json = data;
final url = homeserver!
.resolveUri(Uri(path: '_matrix$action', queryParameters: query));
final headers = <String, String>{};
if (type == RequestType.PUT || type == RequestType.POST) {
headers['Content-Type'] = contentType;
}
if (accessToken != null) {
headers['Authorization'] = 'Bearer $accessToken';
}
late http.Response resp;
Map<String, Object?>? jsonResp = <String, Object?>{};
try {
switch (type) {
case RequestType.GET:
resp = await httpClient.get(url, headers: headers);
break;
case RequestType.POST:
resp = await httpClient.post(url, body: json, headers: headers);
break;
case RequestType.PUT:
resp = await httpClient.put(url, body: json, headers: headers);
break;
case RequestType.DELETE:
resp = await httpClient.delete(url, headers: headers);
break;
}
var respBody = resp.body;
try {
respBody = utf8.decode(resp.bodyBytes);
} catch (_) {
// No-OP
}
if (resp.statusCode >= 500 && resp.statusCode < 600) {
throw Exception(respBody);
}
var jsonString = String.fromCharCodes(respBody.runes);
if (jsonString.startsWith('[') && jsonString.endsWith(']')) {
jsonString = '{"chunk":$jsonString}';
}
jsonResp = jsonDecode(jsonString)
as Map<String, Object?>?; // May throw FormatException
} catch (e, s) {
throw MatrixConnectionException(e, s);
}
if (resp.statusCode >= 400 && resp.statusCode < 500) {
throw MatrixException(resp);
}
return jsonResp!;
}
/// Publishes end-to-end encryption keys for the device.
/// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-keys-query
Future<Map<String, int>> uploadKeys(
{MatrixDeviceKeys? deviceKeys,
Map<String, Object?>? oneTimeKeys,
Map<String, Object?>? fallbackKeys}) async {
final response = await request(
RequestType.POST,
'/client/v3/keys/upload',
data: {
if (deviceKeys != null) 'device_keys': deviceKeys.toJson(),
if (oneTimeKeys != null) 'one_time_keys': oneTimeKeys,
if (fallbackKeys != null) ...{
'fallback_keys': fallbackKeys,
'org.matrix.msc2732.fallback_keys': fallbackKeys,
},
},
);
return Map<String, int>.from(response['one_time_key_counts'] as Map);
}
/// This endpoint allows the creation, modification and deletion of pushers
/// for this user ID. The behaviour of this endpoint varies depending on the
/// values in the JSON body.
///
/// See [deletePusher] to issue requests with `kind: null`.
///
/// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-pushers-set
Future<void> postPusher(Pusher pusher, {bool? append}) async {
final data = pusher.toJson();
if (append != null) {
data['append'] = append;
}
await request(
RequestType.POST,
'/client/v3/pushers/set',
data: data,
);
return;
}
/// Variant of postPusher operation that deletes pushers by setting `kind: null`.
///
/// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-pushers-set
Future<void> deletePusher(PusherId pusher) async {
final data = PusherData.fromJson(pusher.toJson()).toJson();
data['kind'] = null;
await request(
RequestType.POST,
'/client/v3/pushers/set',
data: data,
);
return;
}
/// This API provides credentials for the client to use when initiating
/// calls.
@override
Future<TurnServerCredentials> getTurnServer() async {
final json = await request(RequestType.GET, '/client/v3/voip/turnServer');
// fix invalid responses from synapse
// https://github.com/matrix-org/synapse/pull/10922
final ttl = json['ttl'];
if (ttl is double) {
json['ttl'] = ttl.toInt();
}
return TurnServerCredentials.fromJson(json);
}
@Deprecated('Use [deleteRoomKeyBySessionId] instead')
Future<RoomKeysUpdateResponse> deleteRoomKeysBySessionId(
String roomId, String sessionId, String version) async {
return deleteRoomKeyBySessionId(roomId, sessionId, version);
}
@Deprecated('Use [deleteRoomKeyBySessionId] instead')
Future<RoomKeysUpdateResponse> putRoomKeysBySessionId(String roomId,
String sessionId, String version, KeyBackupData data) async {
return putRoomKeyBySessionId(roomId, sessionId, version, data);
}
@Deprecated('Use [getRoomKeyBySessionId] instead')
Future<KeyBackupData> getRoomKeysBySessionId(
String roomId, String sessionId, String version) async {
return getRoomKeyBySessionId(roomId, sessionId, version);
}
}

View File

@ -0,0 +1,32 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
abstract class AlgorithmTypes {
static const String olmV1Curve25519AesSha2 = 'm.olm.v1.curve25519-aes-sha2';
static const String megolmV1AesSha2 = 'm.megolm.v1.aes-sha2';
static const String secretStorageV1AesHmcSha2 =
'm.secret_storage.v1.aes-hmac-sha2';
static const String megolmBackupV1Curve25519AesSha2 =
'm.megolm_backup.v1.curve25519-aes-sha2';
static const String pbkdf2 = 'm.pbkdf2';
}

View File

@ -0,0 +1,42 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
class AuthenticationData {
// Should be non-nullable according to the spec but this leads to this problem
// https://github.com/matrix-org/matrix-doc/issues/3370
String? type;
String? session;
AuthenticationData({this.type, this.session});
AuthenticationData.fromJson(Map<String, Object?> json)
: type = json['type'] as String?,
session = json['session'] as String?;
Map<String, Object?> toJson() {
final data = <String, Object?>{};
if (type != null) data['type'] = type;
if (session != null) data['session'] = session;
return data;
}
}

View File

@ -0,0 +1,55 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import 'authentication_phone_identifier.dart';
import 'authentication_third_party_identifier.dart';
import 'authentication_types.dart';
import 'authentication_user_identifier.dart';
class AuthenticationIdentifier {
String type;
AuthenticationIdentifier({required this.type});
AuthenticationIdentifier.fromJson(Map<String, Object?> json)
: type = json['type'] as String;
factory AuthenticationIdentifier.subFromJson(Map<String, Object?> json) {
switch (json['type']) {
case AuthenticationIdentifierTypes.userId:
return AuthenticationUserIdentifier.fromJson(json);
case AuthenticationIdentifierTypes.phone:
return AuthenticationPhoneIdentifier.fromJson(json);
case AuthenticationIdentifierTypes.thirdParty:
return AuthenticationThirdPartyIdentifier.fromJson(json);
default:
return AuthenticationIdentifier.fromJson(json);
}
}
Map<String, Object?> toJson() {
final data = <String, Object?>{};
data['type'] = type;
return data;
}
}

View File

@ -0,0 +1,56 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import 'authentication_data.dart';
import 'authentication_identifier.dart';
import 'authentication_types.dart';
import 'authentication_user_identifier.dart';
class AuthenticationPassword extends AuthenticationData {
String password;
/// You may want to cast this as [AuthenticationUserIdentifier] or other
/// Identifier classes extending AuthenticationIdentifier.
AuthenticationIdentifier identifier;
AuthenticationPassword(
{String? session, required this.password, required this.identifier})
: super(
type: AuthenticationTypes.password,
session: session,
);
AuthenticationPassword.fromJson(Map<String, Object?> json)
: password = json['password'] as String,
identifier = AuthenticationIdentifier.subFromJson(
json['identifier'] as Map<String, Object?>),
super.fromJson(json);
@override
Map<String, Object?> toJson() {
final data = super.toJson();
data['password'] = password;
data['identifier'] = identifier.toJson();
return data;
}
}

View File

@ -0,0 +1,46 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import 'authentication_identifier.dart';
import 'authentication_types.dart';
class AuthenticationPhoneIdentifier extends AuthenticationIdentifier {
String country;
String phone;
AuthenticationPhoneIdentifier({required this.country, required this.phone})
: super(type: AuthenticationIdentifierTypes.phone);
AuthenticationPhoneIdentifier.fromJson(Map<String, Object?> json)
: country = json['country'] as String,
phone = json['phone'] as String,
super.fromJson(json);
@override
Map<String, Object?> toJson() {
final data = super.toJson();
data['country'] = country;
data['phone'] = phone;
return data;
}
}

View File

@ -0,0 +1,46 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import 'authentication_data.dart';
import 'authentication_types.dart';
class AuthenticationRecaptcha extends AuthenticationData {
String response;
AuthenticationRecaptcha({required String session, required this.response})
: super(
type: AuthenticationTypes.recaptcha,
session: session,
);
AuthenticationRecaptcha.fromJson(Map<String, Object?> json)
: response = json['response'] as String,
super.fromJson(json);
@override
Map<String, Object?> toJson() {
final data = super.toJson();
data['response'] = response;
return data;
}
}

View File

@ -0,0 +1,47 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import 'authentication_identifier.dart';
import 'authentication_types.dart';
class AuthenticationThirdPartyIdentifier extends AuthenticationIdentifier {
String medium;
String address;
AuthenticationThirdPartyIdentifier(
{required this.medium, required this.address})
: super(type: AuthenticationIdentifierTypes.thirdParty);
AuthenticationThirdPartyIdentifier.fromJson(Map<String, Object?> json)
: medium = json['medium'] as String,
address = json['address'] as String,
super.fromJson(json);
@override
Map<String, Object?> toJson() {
final data = super.toJson();
data['medium'] = medium;
data['address'] = address;
return data;
}
}

View File

@ -0,0 +1,82 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import 'authentication_data.dart';
/// For email based identity:
/// https://matrix.org/docs/spec/client_server/r0.6.1#email-based-identity-homeserver
/// Or phone number based identity:
/// https://matrix.org/docs/spec/client_server/r0.6.1#phone-number-msisdn-based-identity-homeserver
class AuthenticationThreePidCreds extends AuthenticationData {
late ThreepidCreds threepidCreds;
AuthenticationThreePidCreds(
{String? session, required String type, required this.threepidCreds})
: super(
type: type,
session: session,
);
AuthenticationThreePidCreds.fromJson(Map<String, Object?> json)
: super.fromJson(json) {
final creds = json['threepid_creds'];
if (creds is Map<String, Object?>) {
threepidCreds = ThreepidCreds.fromJson(creds);
}
}
@override
Map<String, Object?> toJson() {
final data = super.toJson();
data['threepid_creds'] = threepidCreds.toJson();
return data;
}
}
class ThreepidCreds {
String sid;
String clientSecret;
String? idServer;
String? idAccessToken;
ThreepidCreds(
{required this.sid,
required this.clientSecret,
this.idServer,
this.idAccessToken});
ThreepidCreds.fromJson(Map<String, Object?> json)
: sid = json['sid'] as String,
clientSecret = json['client_secret'] as String,
idServer = json['id_server'] as String?,
idAccessToken = json['id_access_token'] as String?;
Map<String, Object?> toJson() {
final data = <String, Object?>{};
data['sid'] = sid;
data['client_secret'] = clientSecret;
if (idServer != null) data['id_server'] = idServer;
if (idAccessToken != null) data['id_access_token'] = idAccessToken;
return data;
}
}

View File

@ -0,0 +1,51 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import 'authentication_data.dart';
import 'authentication_types.dart';
class AuthenticationToken extends AuthenticationData {
String token;
/// removed in the unstable version of the spec
String? txnId;
AuthenticationToken({String? session, required this.token, this.txnId})
: super(
type: AuthenticationTypes.token,
session: session,
);
AuthenticationToken.fromJson(Map<String, Object?> json)
: token = json['token'] as String,
txnId = json['txn_id'] as String?,
super.fromJson(json);
@override
Map<String, Object?> toJson() {
final data = super.toJson();
data['token'] = token;
data['txn_id'] = txnId;
return data;
}
}

View File

@ -0,0 +1,39 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
abstract class AuthenticationTypes {
static const String password = 'm.login.password';
static const String recaptcha = 'm.login.recaptcha';
static const String token = 'm.login.token';
static const String oauth2 = 'm.login.oauth2';
static const String sso = 'm.login.sso';
static const String emailIdentity = 'm.login.email.identity';
static const String msisdn = 'm.login.msisdn';
static const String dummy = 'm.login.dummy';
}
abstract class AuthenticationIdentifierTypes {
static const String userId = 'm.id.user';
static const String thirdParty = 'm.id.thirdparty';
static const String phone = 'm.id.phone';
}

View File

@ -0,0 +1,43 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import 'authentication_identifier.dart';
import 'authentication_types.dart';
class AuthenticationUserIdentifier extends AuthenticationIdentifier {
String user;
AuthenticationUserIdentifier({required this.user})
: super(type: AuthenticationIdentifierTypes.userId);
AuthenticationUserIdentifier.fromJson(Map<String, Object?> json)
: user = json['user'] as String,
super.fromJson(json);
@override
Map<String, Object?> toJson() {
final data = super.toJson();
data['user'] = user;
return data;
}
}

View File

@ -0,0 +1,45 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import '../utils/map_copy_extension.dart';
class BasicEvent {
String type;
Map<String, Object?> content;
BasicEvent({
required this.type,
required this.content,
});
BasicEvent.fromJson(Map<String, Object?> json)
: type = json['type'] as String,
content = (json['content'] as Map<String, Object?>).copy();
Map<String, Object?> toJson() {
final data = <String, Object?>{};
data['type'] = type;
data['content'] = content;
return data;
}
}

View File

@ -0,0 +1,45 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import 'basic_event.dart';
class BasicEventWithSender extends BasicEvent {
String senderId;
BasicEventWithSender(
{required String type,
required Map<String, Object?> content,
required this.senderId})
: super(type: type, content: content);
BasicEventWithSender.fromJson(Map<String, Object?> json)
: senderId = json['sender'] as String,
super.fromJson(json);
@override
Map<String, Object?> toJson() {
final data = super.toJson();
data['sender'] = senderId;
return data;
}
}

View File

@ -0,0 +1,48 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import 'basic_event.dart';
class BasicRoomEvent extends BasicEvent {
String? roomId;
BasicRoomEvent({
this.roomId,
required Map<String, Object?> content,
required String type,
}) : super(
content: content,
type: type,
);
BasicRoomEvent.fromJson(Map<String, Object?> json)
: roomId = json['room_id'] as String?,
super.fromJson(json);
@override
Map<String, Object?> toJson() {
final data = super.toJson();
if (roomId != null) data['room_id'] = roomId;
return data;
}
}

View File

@ -0,0 +1,52 @@
/* MIT License
*
* Copyright (C) 2022 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import 'stripped_state_event.dart';
class ChildrenState extends StrippedStateEvent {
DateTime originServerTs;
ChildrenState({
required String type,
required Map<String, Object?> content,
required String senderId,
required String stateKey,
required this.originServerTs,
}) : super(
type: type,
content: content,
senderId: senderId,
stateKey: stateKey);
ChildrenState.fromJson(Map<String, Object?> json)
: originServerTs = DateTime.fromMillisecondsSinceEpoch(
json['origin_server_ts'] as int),
super.fromJson(json);
@override
Map<String, Object?> toJson() {
final data = super.toJson();
data['origin_server_ts'] = originServerTs.millisecondsSinceEpoch;
return data;
}
}

View File

@ -0,0 +1,97 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
abstract class EventTypes {
// Room timeline and state event types
static const String Message = 'm.room.message';
static const String Sticker = 'm.sticker';
static const String Reaction = 'm.reaction';
static const String Redaction = 'm.room.redaction';
static const String RoomAliases = 'm.room.aliases';
static const String RoomCanonicalAlias = 'm.room.canonical_alias';
static const String RoomCreate = 'm.room.create';
static const String RoomJoinRules = 'm.room.join_rules';
static const String RoomMember = 'm.room.member';
static const String RoomPowerLevels = 'm.room.power_levels';
static const String RoomName = 'm.room.name';
static const String RoomPinnedEvents = 'm.room.pinned_events';
static const String RoomTopic = 'm.room.topic';
static const String RoomAvatar = 'm.room.avatar';
static const String RoomTombstone = 'm.room.tombstone';
static const String GuestAccess = 'm.room.guest_access';
static const String HistoryVisibility = 'm.room.history_visibility';
static const String Encryption = 'm.room.encryption';
static const String Encrypted = 'm.room.encrypted';
static const String CallInvite = 'm.call.invite';
static const String CallAnswer = 'm.call.answer';
static const String CallCandidates = 'm.call.candidates';
static const String CallHangup = 'm.call.hangup';
static const String CallSelectAnswer = 'm.call.select_answer';
static const String CallReject = 'm.call.reject';
static const String CallNegotiate = 'm.call.negotiate';
static const String CallSDPStreamMetadataChanged =
'm.call.sdp_stream_metadata_changed';
static const String CallSDPStreamMetadataChangedPrefix =
'org.matrix.call.sdp_stream_metadata_changed';
static const String CallReplaces = 'm.call.replaces';
static const String CallAssertedIdentity = 'm.call.asserted_identity';
static const String CallAssertedIdentityPrefix =
'org.matrix.call.asserted_identity';
static const String GroupCallPrefix = 'org.matrix.msc3401.call';
static const String GroupCallMemberPrefix = 'org.matrix.msc3401.call.member';
static const String Unknown = 'm.unknown';
// To device event types
static const String RoomKey = 'm.room_key';
static const String ForwardedRoomKey = 'm.forwarded_room_key';
static const String RoomKeyRequest = 'm.room_key_request';
static const String KeyVerificationRequest = 'm.key.verification.request';
static const String KeyVerificationStart = 'm.key.verification.start';
static const String KeyVerificationReady = 'm.key.verification.ready';
static const String KeyVerificationDone = 'm.key.verification.done';
static const String KeyVerificationCancel = 'm.key.verification.cancel';
static const String KeyVerificationAccept = 'm.key.verification.accept';
static const String SecretRequest = 'm.secret.request';
static const String SecretSend = 'm.secret.send';
static const String Dummy = 'm.dummy';
// QR
static const String QRShow = 'm.qr_code.show.v1';
static const String QRScan = 'm.qr_code.scan.v1';
static const String Reciprocate = 'm.reciprocate.v1';
static const String Sas = 'm.sas.v1';
// Account data event types
static const String CrossSigningSelfSigning = 'm.cross_signing.self_signing';
static const String CrossSigningUserSigning = 'm.cross_signing.user_signing';
static const String CrossSigningMasterKey = 'm.cross_signing.master';
static const String MegolmBackup = 'm.megolm_backup.v1';
static const String SecretStorageDefaultKey = 'm.secret_storage.default_key';
static const String PushRules = 'm.push_rules';
static String secretStorageKey(String keyId) => 'm.secret_storage.key.$keyId';
// Spaces
static const String spaceParent = 'm.space.parent';
static const String spaceChild = 'm.space.child';
}

View File

@ -0,0 +1,56 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import '../../utils/try_get_map_extension.dart';
import '../basic_event.dart';
import 'room_key_content.dart';
extension ForwardedRoomKeyContentBasicEventExtension on BasicEvent {
ForwardedRoomKeyContent get parsedForwardedRoomKeyContent =>
ForwardedRoomKeyContent.fromJson(content);
}
class ForwardedRoomKeyContent extends RoomKeyContent {
String senderKey;
String senderClaimedEd25519Key;
List<String> forwardingCurve25519KeyChain;
ForwardedRoomKeyContent.fromJson(Map<String, Object?> json)
: senderKey = json.tryGet('sender_key', TryGet.required) ?? '',
senderClaimedEd25519Key =
json.tryGet('sender_claimed_ed25519_key', TryGet.required) ?? '',
forwardingCurve25519KeyChain = json.tryGetList(
'forwarding_curve25519_key_chain', TryGet.required) ??
[],
super.fromJson(json);
@override
Map<String, Object?> toJson() {
final data = super.toJson();
data['sender_key'] = senderKey;
data['sender_claimed_ed25519_key'] = senderClaimedEd25519Key;
data['forwarding_curve25519_key_chain'] = forwardingCurve25519KeyChain;
return data;
}
}

View File

@ -0,0 +1,174 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import '../../utils/filter_map_extension.dart';
import '../../utils/try_get_map_extension.dart';
import '../basic_event.dart';
extension ImagePackContentBasicEventExtension on BasicEvent {
ImagePackContent get parsedImagePackContent =>
ImagePackContent.fromJson(content);
}
enum ImagePackUsage {
sticker,
emoticon,
}
List<ImagePackUsage>? imagePackUsageFromJson(List<String>? json) => json
?.map((v) => {
'sticker': ImagePackUsage.sticker,
'emoticon': ImagePackUsage.emoticon,
}[v])
.whereType<ImagePackUsage>()
.toList();
List<String> imagePackUsageToJson(
List<ImagePackUsage>? usage, List<String>? prevUsage) {
final knownUsages = <String>{'sticker', 'emoticon'};
final usagesStr = usage
?.map((v) => {
ImagePackUsage.sticker: 'sticker',
ImagePackUsage.emoticon: 'emoticon',
}[v])
.whereType<String>()
.toList() ??
[];
// first we add all the unknown usages and the previous known usages which are new again
final newUsages = prevUsage
?.where((v) => !knownUsages.contains(v) || usagesStr.contains(v))
.toList() ??
[];
// now we need to add the new usages that we didn't add yet
newUsages.addAll(usagesStr.where((v) => !newUsages.contains(v)));
return newUsages;
}
class ImagePackContent {
// we want to preserve potential custom keys in this object
final Map<String, Object?> _json;
Map<String, ImagePackImageContent> images;
ImagePackPackContent pack;
ImagePackContent({required this.images, required this.pack}) : _json = {};
ImagePackContent.fromJson(Map<String, Object?> json)
: _json = Map.fromEntries(json.entries.where(
(e) => !['images', 'pack', 'emoticons', 'short'].contains(e.key))),
pack = ImagePackPackContent.fromJson(
json.tryGetMap<String, Object?>('pack') ?? {}),
images = json.tryGetMap<String, Object?>('images')?.catchMap((k, v) =>
MapEntry(
k,
ImagePackImageContent.fromJson(
v as Map<String, Object?>))) ??
// the "emoticons" key needs a small migration on the key, ":string:" --> "string"
json.tryGetMap<String, Object?>('emoticons')?.catchMap((k, v) =>
MapEntry(
k.startsWith(':') && k.endsWith(':')
? k.substring(1, k.length - 1)
: k,
ImagePackImageContent.fromJson(
v as Map<String, Object?>))) ??
// the "short" key was still just a map from shortcode to mxc uri
json.tryGetMap<String, String>('short')?.catchMap((k, v) =>
MapEntry(
k.startsWith(':') && k.endsWith(':')
? k.substring(1, k.length - 1)
: k,
ImagePackImageContent(url: Uri.parse(v)))) ??
{};
Map<String, Object?> toJson() => {
..._json,
'images': images.map((k, v) => MapEntry(k, v.toJson())),
'pack': pack.toJson(),
};
}
class ImagePackImageContent {
// we want to preserve potential custom keys in this object
final Map<String, Object?> _json;
Uri url;
String? body;
Map<String, Object?>? info;
List<ImagePackUsage>? usage;
ImagePackImageContent({required this.url, this.body, this.info, this.usage})
: _json = {};
ImagePackImageContent.fromJson(Map<String, Object?> json)
: _json = Map.fromEntries(json.entries
.where((e) => !['url', 'body', 'info'].contains(e.key))),
url = Uri.parse(json['url'] as String),
body = json.tryGet('body'),
info = json.tryGetMap<String, Object?>('info'),
usage = imagePackUsageFromJson(json.tryGetList<String>('usage'));
Map<String, Object?> toJson() {
return {
...Map.from(_json)..remove('usage'),
'url': url.toString(),
if (body != null) 'body': body,
if (info != null) 'info': info,
if (usage != null)
'usage': imagePackUsageToJson(usage, _json.tryGetList<String>('usage')),
};
}
}
class ImagePackPackContent {
// we want to preserve potential custom keys in this object
final Map<String, Object?> _json;
String? displayName;
Uri? avatarUrl;
List<ImagePackUsage>? usage;
String? attribution;
ImagePackPackContent(
{this.displayName, this.avatarUrl, this.usage, this.attribution})
: _json = {};
ImagePackPackContent.fromJson(Map<String, Object?> json)
: _json = Map.fromEntries(json.entries.where((e) =>
!['display_name', 'avatar_url', 'attribution'].contains(e.key))),
displayName = json.tryGet('display_name'),
// we default to an invalid uri
avatarUrl = Uri.tryParse(json.tryGet('avatar_url') ?? '.::'),
usage = imagePackUsageFromJson(json.tryGetList<String>('usage')),
attribution = json.tryGet('attribution');
Map<String, Object?> toJson() {
return {
...Map.from(_json)..remove('usage'),
if (displayName != null) 'display_name': displayName,
if (avatarUrl != null) 'avatar_url': avatarUrl.toString(),
if (usage != null)
'usage': imagePackUsageToJson(usage, _json.tryGetList<String>('usage')),
if (attribution != null) 'attribution': attribution,
};
}
}

View File

@ -0,0 +1,63 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import '../../utils/try_get_map_extension.dart';
class OlmPlaintextPayload {
String? type;
Map<String, Object?>? content;
String? sender;
String? recipient;
Map<String, String>? recipientKeys;
Map<String, String>? keys;
OlmPlaintextPayload({
this.type,
this.content,
this.sender,
this.recipient,
this.recipientKeys,
this.keys,
}) : super();
factory OlmPlaintextPayload.fromJson(Map<String, Object?> json) =>
OlmPlaintextPayload(
sender: json.tryGet('sender', TryGet.required),
type: json.tryGet('type', TryGet.required),
content: json.tryGetMap('content', TryGet.required),
recipient: json.tryGet('recipient', TryGet.required),
recipientKeys: json.tryGetMap('recipient_keys', TryGet.required),
keys: json.tryGetMap('keys', TryGet.required),
);
Map<String, Object?> toJson() {
final data = <String, Object?>{};
if (type != null) data['type'] = type;
if (sender != null) data['sender'] = sender;
if (content != null) data['content'] = content;
if (recipient != null) data['recipient'] = recipient;
if (recipientKeys != null) data['recipient_keys'] = recipientKeys;
if (keys != null) data['keys'] = keys;
return data;
}
}

View File

@ -0,0 +1,93 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import 'package:matrix_api_lite/src/utils/logs.dart';
import '../../utils/filter_map_extension.dart';
import '../../utils/try_get_map_extension.dart';
import '../basic_event.dart';
extension RoomEncryptedContentBasicEventExtension on BasicEvent {
RoomEncryptedContent get parsedRoomEncryptedContent =>
RoomEncryptedContent.fromJson(content);
}
class RoomEncryptedContent {
String algorithm;
String senderKey;
String? deviceId;
String? sessionId;
String? ciphertextMegolm;
Map<String, CiphertextInfo>? ciphertextOlm;
RoomEncryptedContent.fromJson(Map<String, Object?> json)
: algorithm = json.tryGet('algorithm', TryGet.required) ?? '',
senderKey = json.tryGet('sender_key', TryGet.required) ?? '',
deviceId = json.tryGet('device_id'),
sessionId = json.tryGet('session_id'),
ciphertextMegolm = json.tryGet('ciphertext', TryGet.silent),
// filter out invalid/incomplete CiphertextInfos
ciphertextOlm = json
.tryGet<Map<String, Object?>>('ciphertext', TryGet.silent)
?.catchMap((k, v) => MapEntry(
k, CiphertextInfo.fromJson(v as Map<String, Object?>)));
Map<String, Object?> toJson() {
final data = <String, Object?>{};
data['algorithm'] = algorithm;
data['sender_key'] = senderKey;
if (deviceId != null) {
data['device_id'] = deviceId;
}
if (sessionId != null) {
data['session_id'] = sessionId;
}
if (ciphertextMegolm != null) {
data['ciphertext'] = ciphertextMegolm;
}
if (ciphertextOlm != null) {
data['ciphertext'] =
ciphertextOlm!.map((k, v) => MapEntry(k, v.toJson()));
if (ciphertextMegolm != null) {
Logs().wtf(
'ciphertextOlm and ciphertextMegolm are both set, which should never happen!');
}
}
return data;
}
}
class CiphertextInfo {
String body;
int type;
CiphertextInfo.fromJson(Map<String, Object?> json)
: body = json['body'] as String,
type = json['type'] as int;
Map<String, Object?> toJson() {
final data = <String, Object?>{};
data['body'] = body;
data['type'] = type;
return data;
}
}

View File

@ -0,0 +1,53 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import '../../utils/try_get_map_extension.dart';
import '../basic_event.dart';
extension RoomEncryptionContentBasicEventExtension on BasicEvent {
RoomEncryptionContent get parsedRoomEncryptionContent =>
RoomEncryptionContent.fromJson(content);
}
class RoomEncryptionContent {
String algorithm;
int? rotationPeriodMs;
int? rotationPeriodMsgs;
RoomEncryptionContent.fromJson(Map<String, Object?> json)
: algorithm = json.tryGet('algorithm', TryGet.required) ?? '',
rotationPeriodMs = json.tryGet('rotation_period_ms'),
rotationPeriodMsgs = json.tryGet('rotation_period_msgs');
Map<String, Object?> toJson() {
final data = <String, Object?>{};
data['algorithm'] = algorithm;
if (rotationPeriodMs != null) {
data['rotation_period_ms'] = rotationPeriodMs;
}
if (rotationPeriodMsgs != null) {
data['rotation_period_msgs'] = rotationPeriodMsgs;
}
return data;
}
}

View File

@ -0,0 +1,57 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import '../../utils/try_get_map_extension.dart';
import '../basic_event.dart';
extension RoomKeyContentBasicEventExtension on BasicEvent {
RoomKeyContent get parsedRoomKeyContent => RoomKeyContent.fromJson(content);
}
class RoomKeyContent {
String algorithm;
String roomId;
String sessionId;
String sessionKey;
RoomKeyContent(
{required this.algorithm,
required this.roomId,
required this.sessionId,
required this.sessionKey});
RoomKeyContent.fromJson(Map<String, Object?> json)
: algorithm = json.tryGet('algorithm', TryGet.required) ?? '',
roomId = json.tryGet('room_id', TryGet.required) ?? '',
sessionId = json.tryGet('session_id', TryGet.required) ?? '',
sessionKey = json.tryGet('session_key', TryGet.required) ?? '';
Map<String, Object?> toJson() {
final data = <String, Object?>{};
data['algorithm'] = algorithm;
data['room_id'] = roomId;
data['session_id'] = sessionId;
data['session_key'] = sessionKey;
return data;
}
}

View File

@ -0,0 +1,83 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import '../../utils/try_get_map_extension.dart';
import '../basic_event.dart';
extension RoomKeyRequestContentBasicEventExtension on BasicEvent {
RoomKeyRequestContent get parsedRoomKeyRequestContent =>
RoomKeyRequestContent.fromJson(content);
}
class RoomKeyRequestContent {
RequestedKeyInfo? body;
String action;
String requestingDeviceId;
String requestId;
RoomKeyRequestContent.fromJson(Map<String, Object?> json)
: body = ((Map<String, Object?>? x) => x != null
? RequestedKeyInfo.fromJson(x)
: null)(json.tryGet('body')),
action = json.tryGet('action', TryGet.required) ?? '',
requestingDeviceId =
json.tryGet('requesting_device_id', TryGet.required) ?? '',
requestId = json.tryGet('request_id', TryGet.required) ?? '';
Map<String, Object?> toJson() {
final data = <String, Object?>{};
if (body != null) data['body'] = body!.toJson();
data['action'] = action;
data['requesting_device_id'] = requestingDeviceId;
data['request_id'] = requestId;
return data;
}
}
class RequestedKeyInfo {
String algorithm;
String roomId;
String sessionId;
String senderKey;
RequestedKeyInfo(
{required this.algorithm,
required this.roomId,
required this.sessionId,
required this.senderKey});
RequestedKeyInfo.fromJson(Map<String, Object?> json)
: algorithm = json.tryGet('algorithm', TryGet.required) ?? '',
roomId = json.tryGet('room_id', TryGet.required) ?? '',
sessionId = json.tryGet('session_id', TryGet.required) ?? '',
senderKey = json.tryGet('sender_key', TryGet.required) ?? '';
Map<String, Object?> toJson() {
final data = <String, Object?>{};
data['algorithm'] = algorithm;
data['room_id'] = roomId;
data['session_id'] = sessionId;
data['sender_key'] = senderKey;
return data;
}
}

View File

@ -0,0 +1,46 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import '../../utils/try_get_map_extension.dart';
import '../basic_event.dart';
extension SecretStorageDefaultKeyContentBasicEventExtension on BasicEvent {
SecretStorageDefaultKeyContent get parsedSecretStorageDefaultKeyContent =>
SecretStorageDefaultKeyContent.fromJson(content);
}
class SecretStorageDefaultKeyContent {
//TODO: Required by spec, we should require it here and make sure to catch it everywhere
String? key;
SecretStorageDefaultKeyContent({required this.key});
SecretStorageDefaultKeyContent.fromJson(Map<String, Object?> json)
: key = json.tryGet('key', TryGet.required);
Map<String, Object?> toJson() {
final data = <String, Object?>{};
if (key != null) data['key'] = key;
return data;
}
}

View File

@ -0,0 +1,86 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import '../../utils/try_get_map_extension.dart';
import '../basic_event.dart';
extension SecretStorageKeyContentBasicEventExtension on BasicEvent {
SecretStorageKeyContent get parsedSecretStorageKeyContent =>
SecretStorageKeyContent.fromJson(content);
}
class SecretStorageKeyContent {
PassphraseInfo? passphrase;
String? iv;
String? mac;
String? algorithm;
SecretStorageKeyContent();
SecretStorageKeyContent.fromJson(Map<String, Object?> json)
: passphrase = ((Map<String, Object?>? x) => x != null
? PassphraseInfo.fromJson(x)
: null)(json.tryGet('passphrase')),
iv = json.tryGet('iv'),
mac = json.tryGet('mac'),
algorithm = json.tryGet('algorithm');
Map<String, Object?> toJson() {
final data = <String, Object?>{};
if (passphrase != null) data['passphrase'] = passphrase!.toJson();
if (iv != null) data['iv'] = iv;
if (mac != null) data['mac'] = mac;
if (algorithm != null) data['algorithm'] = algorithm;
return data;
}
}
class PassphraseInfo {
//TODO: algorithm, salt, iterations are required by spec,
//TODO: we should require it here and make sure to catch it everywhere
String? algorithm;
String? salt;
int? iterations;
int? bits;
PassphraseInfo(
{required this.algorithm,
required this.salt,
required this.iterations,
this.bits});
PassphraseInfo.fromJson(Map<String, Object?> json)
: algorithm = json.tryGet('algorithm', TryGet.required),
salt = json.tryGet('salt', TryGet.required),
iterations = json.tryGet('iterations', TryGet.required),
bits = json.tryGet('bits');
Map<String, Object?> toJson() {
final data = <String, Object?>{};
data['algorithm'] = algorithm;
data['salt'] = salt;
data['iterations'] = iterations;
if (bits != null) data['bits'] = bits;
return data;
}
}

View File

@ -0,0 +1,47 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import '../../utils/try_get_map_extension.dart';
import '../basic_event.dart';
extension TombstoneContentBasicEventExtension on BasicEvent {
TombstoneContent get parsedTombstoneContent =>
TombstoneContent.fromJson(content);
}
class TombstoneContent {
String body;
String replacementRoom;
TombstoneContent.fromJson(Map<String, Object?> json)
: body = json.tryGet('body', TryGet.required) ?? '',
replacementRoom =
json.tryGet('replacement_room', TryGet.required) ?? '';
Map<String, Object?> toJson() {
final data = <String, Object?>{};
data['body'] = body;
data['replacement_room'] = replacementRoom;
return data;
}
}

View File

@ -0,0 +1,32 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
class MatrixConnectionException implements Exception {
final dynamic original;
final StackTrace stackTrace;
MatrixConnectionException(this.original, this.stackTrace);
@override
String toString() => original.toString();
}

View File

@ -0,0 +1,84 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import '../utils/map_copy_extension.dart';
import 'stripped_state_event.dart';
class MatrixEvent extends StrippedStateEvent {
String eventId;
String? roomId;
DateTime originServerTs;
Map<String, Object?>? unsigned;
Map<String, Object?>? prevContent;
String? redacts;
MatrixEvent({
required String type,
required Map<String, Object?> content,
required String senderId,
String? stateKey,
required this.eventId,
this.roomId,
required this.originServerTs,
this.unsigned,
this.prevContent,
this.redacts,
}) : super(
type: type,
content: content,
senderId: senderId,
stateKey: stateKey);
MatrixEvent.fromJson(Map<String, Object?> json)
: eventId = json['event_id'] as String,
roomId = json['room_id'] as String?,
originServerTs = DateTime.fromMillisecondsSinceEpoch(
json['origin_server_ts'] as int),
unsigned = (json['unsigned'] as Map<String, Object?>?)?.copy(),
prevContent = (json['prev_content'] as Map<String, Object?>?)?.copy(),
redacts = json['redacts'] as String?,
super.fromJson(json);
@override
Map<String, Object?> toJson() {
final data = super.toJson();
data['event_id'] = eventId;
data['origin_server_ts'] = originServerTs.millisecondsSinceEpoch;
if (unsigned != null) {
data['unsigned'] = unsigned;
}
if (prevContent != null) {
data['prev_content'] = prevContent;
}
if (roomId != null) {
data['room_id'] = roomId;
}
if (data['state_key'] == null) {
data.remove('state_key');
}
if (redacts != null) {
data['redacts'] = redacts;
}
return data;
}
}

View File

@ -0,0 +1,137 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:matrix_api_lite/matrix_api_lite.dart';
enum MatrixError {
M_UNKNOWN,
M_UNKNOWN_TOKEN,
M_NOT_FOUND,
M_FORBIDDEN,
M_LIMIT_EXCEEDED,
M_USER_IN_USE,
M_THREEPID_IN_USE,
M_THREEPID_DENIED,
M_THREEPID_NOT_FOUND,
M_THREEPID_AUTH_FAILED,
M_TOO_LARGE,
M_MISSING_PARAM,
M_UNSUPPORTED_ROOM_VERSION,
M_UNRECOGNIZED,
M_BAD_JSON,
M_NOT_JSON,
M_UNAUTHORIZED,
M_USER_DEACTIVATED,
M_INVALID_USERNAME,
M_ROOM_IN_USE,
M_INVALID_ROOM_STATE,
M_SERVER_NOT_TRUSTED,
M_INCOMPATIBLE_ROOM_VERSION,
M_BAD_STATE,
M_GUEST_ACCESS_FORBIDDEN,
M_CAPTCHA_NEEDED,
M_CAPTCHA_INVALID,
M_INVALID_PARAM,
M_EXCLUSIVE,
M_RESOURCE_LIMIT_EXCEEDED,
M_CANNOT_LEAVE_SERVER_NOTICE_ROOM,
}
/// Represents a special response from the Homeserver for errors.
class MatrixException implements Exception {
final Map<String, Object?> raw;
/// The unique identifier for this error.
String get errcode =>
raw.tryGet<String>('errcode') ??
(requireAdditionalAuthentication ? 'M_FORBIDDEN' : 'M_UNKNOWN');
/// A human readable error description.
String get errorMessage =>
raw.tryGet<String>('error') ??
(requireAdditionalAuthentication
? 'Require additional authentication'
: 'Unknown error');
/// The frozen request which triggered this Error
http.Response? response;
MatrixException(http.Response this.response)
: raw = json.decode(response.body) as Map<String, Object?>;
MatrixException.fromJson(Map<String, Object?> content) : raw = content;
@override
String toString() => '$errcode: $errorMessage';
/// Returns the errcode as an [MatrixError].
MatrixError get error => MatrixError.values.firstWhere(
(e) => e.name == errcode,
orElse: () => MatrixError.M_UNKNOWN,
);
int? get retryAfterMs => raw.tryGet<int>('retry_after_ms');
/// This is a session identifier that the client must pass back to the homeserver, if one is provided,
/// in subsequent attempts to authenticate in the same API call.
String? get session => raw.tryGet<String>('session');
/// Returns true if the server requires additional authentication.
bool get requireAdditionalAuthentication => response != null
? response!.statusCode == 401
: authenticationFlows != null;
/// For each endpoint, a server offers one or more 'flows' that the client can use
/// to authenticate itself. Each flow comprises a series of stages. If this request
/// doesn't need additional authentication, then this is null.
List<AuthenticationFlow>? get authenticationFlows => raw
.tryGet<List<Object?>>('flows')
?.whereType<Map<String, Object?>>()
.map((flow) => flow['stages'])
.whereType<List<Object?>>()
.map((stages) =>
AuthenticationFlow(List<String>.from(stages.whereType<String>())))
.toList();
/// This section contains any information that the client will need to know in order to use a given type
/// of authentication. For each authentication type presented, that type may be present as a key in this
/// dictionary. For example, the public part of an OAuth client ID could be given here.
Map<String, Object?>? get authenticationParams =>
raw.tryGetMap<String, Object?>('params');
/// Returns the list of already completed authentication flows from previous requests.
List<String> get completedAuthenticationFlows =>
raw.tryGetList<String>('completed') ?? [];
}
/// For each endpoint, a server offers one or more 'flows' that the client can use
/// to authenticate itself. Each flow comprises a series of stages
class AuthenticationFlow {
final List<String> stages;
const AuthenticationFlow(this.stages);
}

View File

@ -0,0 +1,141 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import 'package:matrix_api_lite/matrix_api_lite.dart';
abstract class MatrixSignableKey {
String userId;
String? get identifier;
Map<String, String> keys;
Map<String, Map<String, String>>? signatures;
Map<String, Object?>? unsigned;
MatrixSignableKey(this.userId, this.keys, this.signatures, {this.unsigned});
// This object is used for signing so we need the raw json too
Map<String, Object?>? _json;
MatrixSignableKey.fromJson(Map<String, Object?> json)
: _json = json,
userId = json['user_id'] as String,
keys = Map<String, String>.from(json['keys'] as Map<String, Object?>),
// we need to manually copy to ensure that our map is Map<String, Map<String, String>>
signatures = (() {
final orig = json.tryGetMap<String, Object?>('signatures');
final res = <String, Map<String, String>>{};
for (final entry
in (orig?.entries ?? <MapEntry<String, Object?>>[])) {
final deviceSigs = entry.value;
if (deviceSigs is Map<String, Object?>) {
for (final nestedEntry in deviceSigs.entries) {
final nestedValue = nestedEntry.value;
if (nestedValue is String) {
(res[entry.key] ??= <String, String>{})[nestedEntry.key] =
nestedValue;
}
}
}
}
return res;
}()),
unsigned = json.tryGetMap<String, Object?>('unsigned')?.copy();
Map<String, Object?> toJson() {
final data = _json ?? <String, Object?>{};
data['user_id'] = userId;
data['keys'] = keys;
if (signatures != null) {
data['signatures'] = signatures;
}
if (unsigned != null) {
data['unsigned'] = unsigned;
}
return data;
}
}
class MatrixCrossSigningKey extends MatrixSignableKey {
List<String> usage;
String? get publicKey => identifier;
MatrixCrossSigningKey(
String userId,
this.usage,
Map<String, String> keys,
Map<String, Map<String, String>> signatures, {
Map<String, Object?>? unsigned,
}) : super(userId, keys, signatures, unsigned: unsigned);
@override
String? get identifier => keys.values.first;
@override
MatrixCrossSigningKey.fromJson(Map<String, Object?> json)
: usage = json.tryGetList<String>('usage') ?? [],
super.fromJson(json);
@override
Map<String, Object?> toJson() {
final data = super.toJson();
data['usage'] = usage;
return data;
}
}
class MatrixDeviceKeys extends MatrixSignableKey {
String deviceId;
List<String> algorithms;
String? get deviceDisplayName =>
unsigned?.tryGet<String>('device_display_name');
MatrixDeviceKeys(
String userId,
this.deviceId,
this.algorithms,
Map<String, String> keys,
Map<String, Map<String, String>> signatures, {
Map<String, Object?>? unsigned,
}) : super(userId, keys, signatures, unsigned: unsigned);
@override
String? get identifier => deviceId;
@override
MatrixDeviceKeys.fromJson(Map<String, Object?> json)
: algorithms = json.tryGetList<String>('algorithms') ?? [],
deviceId = json['device_id'] as String,
super.fromJson(json);
@override
Map<String, Object?> toJson() {
final data = super.toJson();
data['device_id'] = deviceId;
data['algorithms'] = algorithms;
return data;
}
}

View File

@ -0,0 +1,36 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
abstract class MessageTypes {
static const String Text = 'm.text';
static const String Emote = 'm.emote';
static const String Notice = 'm.notice';
static const String Image = 'm.image';
static const String Video = 'm.video';
static const String Audio = 'm.audio';
static const String File = 'm.file';
static const String Location = 'm.location';
static const String Sticker = 'm.sticker';
static const String BadEncrypted = 'm.bad.encrypted';
static const String None = 'm.none';
}

View File

@ -0,0 +1,34 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import 'basic_event_with_sender.dart';
import 'presence_content.dart';
class Presence extends BasicEventWithSender {
PresenceContent presence;
Presence.fromJson(Map<String, Object?> json)
: presence =
PresenceContent.fromJson(json['content'] as Map<String, Object?>),
super.fromJson(json);
}

View File

@ -0,0 +1,53 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import 'package:matrix_api_lite/matrix_api_lite.dart';
class PresenceContent {
PresenceType presence;
int? lastActiveAgo;
String? statusMsg;
bool? currentlyActive;
PresenceContent.fromJson(Map<String, Object?> json)
: presence = PresenceType.values.firstWhere(
(p) => p.toString().split('.').last == json['presence']),
lastActiveAgo = json.tryGet<int>('last_active_ago'),
statusMsg = json.tryGet<String>('status_msg'),
currentlyActive = json.tryGet<bool>('currently_active');
Map<String, Object?> toJson() {
final data = <String, Object?>{};
data['presence'] = presence.toString().split('.').last;
if (lastActiveAgo != null) {
data['last_active_ago'] = lastActiveAgo;
}
if (statusMsg != null) {
data['status_msg'] = statusMsg;
}
if (currentlyActive != null) {
data['currently_active'] = currentlyActive;
}
return data;
}
}

View File

@ -0,0 +1,3 @@
abstract class RoomCreationTypes {
static const String mSpace = 'm.space';
}

View File

@ -0,0 +1,85 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import 'package:matrix_api_lite/matrix_api_lite.dart';
class RoomKeysSingleKey {
int firstMessageIndex;
int forwardedCount;
bool isVerified;
Map<String, Object?> sessionData;
RoomKeysSingleKey(
{required this.firstMessageIndex,
required this.forwardedCount,
required this.isVerified,
required this.sessionData});
RoomKeysSingleKey.fromJson(Map<String, Object?> json)
: firstMessageIndex = json['first_message_index'] as int,
forwardedCount = json['forwarded_count'] as int,
isVerified = json['is_verified'] as bool,
sessionData = json['session_data'] as Map<String, Object?>;
Map<String, Object?> toJson() {
final data = <String, Object?>{};
data['first_message_index'] = firstMessageIndex;
data['forwarded_count'] = forwardedCount;
data['is_verified'] = isVerified;
data['session_data'] = sessionData;
return data;
}
}
class RoomKeysRoom {
Map<String, RoomKeysSingleKey> sessions;
RoomKeysRoom({required this.sessions});
RoomKeysRoom.fromJson(Map<String, Object?> json)
: sessions = (json['sessions'] as Map<String, Object?>).map((k, v) =>
MapEntry(k, RoomKeysSingleKey.fromJson(v as Map<String, Object?>)));
Map<String, Object?> toJson() {
final data = <String, Object?>{};
data['sessions'] = sessions.map((k, v) => MapEntry(k, v.toJson()));
return data;
}
}
class RoomKeysUpdateResponse {
String etag;
int count;
RoomKeysUpdateResponse.fromJson(Map<String, Object?> json)
: etag = json.tryGet<String>('etag') ??
'', // synapse replies an int but docs say string?
count = json.tryGet<int>('count') ?? 0;
Map<String, Object?> toJson() {
final data = <String, Object?>{};
data['etag'] = etag;
data['count'] = count;
return data;
}
}

View File

@ -0,0 +1,49 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
class RoomSummary {
List<String>? mHeroes;
int? mJoinedMemberCount;
int? mInvitedMemberCount;
RoomSummary.fromJson(Map<String, Object?> json)
: mHeroes = json['m.heroes'] != null
? List<String>.from(json['m.heroes'] as List)
: null,
mJoinedMemberCount = json['m.joined_member_count'] as int?,
mInvitedMemberCount = json['m.invited_member_count'] as int?;
Map<String, Object?> toJson() {
final data = <String, Object?>{};
if (mHeroes != null) {
data['m.heroes'] = mHeroes;
}
if (mJoinedMemberCount != null) {
data['m.joined_member_count'] = mJoinedMemberCount;
}
if (mInvitedMemberCount != null) {
data['m.invited_member_count'] = mInvitedMemberCount;
}
return data;
}
}

View File

@ -0,0 +1,29 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/// Type of a room which is presented in a `m.room.creation` state content in
/// the `type` key.
abstract class RoomCreationTypes {
static const String mSpace = 'm.space';
static const String mDirectMessage = 'm.dm';
}

View File

@ -0,0 +1,46 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import 'package:matrix_api_lite/matrix_api_lite.dart';
class StrippedStateEvent extends BasicEventWithSender {
String? stateKey;
StrippedStateEvent(
{required String type,
required Map<String, Object?> content,
required String senderId,
this.stateKey})
: super(type: type, content: content, senderId: senderId);
StrippedStateEvent.fromJson(Map<String, Object?> json)
: stateKey = json.tryGet<String>('state_key'),
super.fromJson(json);
@override
Map<String, Object?> toJson() {
final data = super.toJson();
data['state_key'] = stateKey;
return data;
}
}

View File

@ -0,0 +1,360 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import 'package:matrix_api_lite/matrix_api_lite.dart';
class SyncUpdate {
String nextBatch;
RoomsUpdate? rooms;
List<Presence>? presence;
List<BasicEvent>? accountData;
List<BasicEventWithSender>? toDevice;
DeviceListsUpdate? deviceLists;
Map<String, int>? deviceOneTimeKeysCount;
List<String>? deviceUnusedFallbackKeyTypes;
SyncUpdate({
required this.nextBatch,
this.rooms,
this.presence,
this.accountData,
this.toDevice,
this.deviceLists,
this.deviceOneTimeKeysCount,
this.deviceUnusedFallbackKeyTypes,
});
SyncUpdate.fromJson(Map<String, Object?> json)
: nextBatch = json.tryGet<String>('next_batch') ?? '',
rooms = (() {
final temp = json.tryGetMap<String, Object?>('rooms');
return temp != null ? RoomsUpdate.fromJson(temp) : null;
}()),
presence = json
.tryGetMap<String, List<Object?>>('presence')?['events']
?.map((i) => Presence.fromJson(i as Map<String, Object?>))
.toList(),
accountData = json
.tryGetMap<String, List<Object?>>('account_data')?['events']
?.map((i) => BasicEvent.fromJson(i as Map<String, Object?>))
.toList(),
toDevice = json
.tryGetMap<String, List<Object?>>('to_device')?['events']
?.map(
(i) => BasicEventWithSender.fromJson(i as Map<String, Object?>))
.toList(),
deviceLists = (() {
final temp = json.tryGetMap<String, Object?>('device_lists');
return temp != null ? DeviceListsUpdate.fromJson(temp) : null;
}()),
deviceOneTimeKeysCount =
json.tryGetMap<String, int>('device_one_time_keys_count'),
deviceUnusedFallbackKeyTypes =
json.tryGetList<String>('device_unused_fallback_key_types') ??
json.tryGetList<String>(
'org.matrix.msc2732.device_unused_fallback_key_types');
Map<String, Object?> toJson() {
final data = <String, Object?>{};
data['next_batch'] = nextBatch;
if (rooms != null) {
data['rooms'] = rooms!.toJson();
}
if (presence != null) {
data['presence'] = {
'events': presence!.map((i) => i.toJson()).toList(),
};
}
if (accountData != null) {
data['account_data'] = {
'events': accountData!.map((i) => i.toJson()).toList(),
};
}
if (toDevice != null) {
data['to_device'] = {
'events': toDevice!.map((i) => i.toJson()).toList(),
};
}
if (deviceLists != null) {
data['device_lists'] = deviceLists!.toJson();
}
if (deviceOneTimeKeysCount != null) {
data['device_one_time_keys_count'] = deviceOneTimeKeysCount;
}
if (deviceUnusedFallbackKeyTypes != null) {
data['device_unused_fallback_key_types'] = deviceUnusedFallbackKeyTypes;
data['org.matrix.msc2732.device_unused_fallback_key_types'] =
deviceUnusedFallbackKeyTypes;
}
return data;
}
}
class RoomsUpdate {
Map<String, JoinedRoomUpdate>? join;
Map<String, InvitedRoomUpdate>? invite;
Map<String, LeftRoomUpdate>? leave;
RoomsUpdate({
this.join,
this.invite,
this.leave,
});
RoomsUpdate.fromJson(Map<String, Object?> json) {
join = json.tryGetMap<String, Object?>('join')?.catchMap((k, v) =>
MapEntry(k, JoinedRoomUpdate.fromJson(v as Map<String, Object?>)));
invite = json.tryGetMap<String, Object?>('invite')?.catchMap((k, v) =>
MapEntry(k, InvitedRoomUpdate.fromJson(v as Map<String, Object?>)));
leave = json.tryGetMap<String, Object?>('leave')?.catchMap((k, v) =>
MapEntry(k, LeftRoomUpdate.fromJson(v as Map<String, Object?>)));
}
Map<String, Object?> toJson() {
final data = <String, Object?>{};
if (join != null) {
data['join'] = join!.map((k, v) => MapEntry(k, v.toJson()));
}
if (invite != null) {
data['invite'] = invite!.map((k, v) => MapEntry(k, v.toJson()));
}
if (leave != null) {
data['leave'] = leave!.map((k, v) => MapEntry(k, v.toJson()));
}
return data;
}
}
abstract class SyncRoomUpdate {}
class JoinedRoomUpdate extends SyncRoomUpdate {
RoomSummary? summary;
List<MatrixEvent>? state;
TimelineUpdate? timeline;
List<BasicRoomEvent>? ephemeral;
List<BasicRoomEvent>? accountData;
UnreadNotificationCounts? unreadNotifications;
JoinedRoomUpdate({
this.summary,
this.state,
this.timeline,
this.ephemeral,
this.accountData,
this.unreadNotifications,
});
JoinedRoomUpdate.fromJson(Map<String, Object?> json)
: summary = json.tryGetFromJson('summary', RoomSummary.fromJson),
state = json
.tryGetMap<String, List<Object?>>('state')?['events']
?.map((i) => MatrixEvent.fromJson(i as Map<String, Object?>))
.toList(),
timeline = json.tryGetFromJson('timeline', TimelineUpdate.fromJson),
ephemeral = json
.tryGetMap<String, List<Object?>>('ephemeral')?['events']
?.map((i) => BasicRoomEvent.fromJson(i as Map<String, Object?>))
.toList(),
accountData = json
.tryGetMap<String, List<Object?>>('account_data')?['events']
?.map((i) => BasicRoomEvent.fromJson(i as Map<String, Object?>))
.toList(),
unreadNotifications = json.tryGetFromJson(
'unread_notifications', UnreadNotificationCounts.fromJson);
Map<String, Object?> toJson() {
final data = <String, Object?>{};
if (summary != null) {
data['summary'] = summary!.toJson();
}
if (state != null) {
data['state'] = {
'events': state!.map((i) => i.toJson()).toList(),
};
}
if (timeline != null) {
data['timeline'] = timeline!.toJson();
}
if (ephemeral != null) {
data['ephemeral'] = {
'events': ephemeral!.map((i) => i.toJson()).toList(),
};
}
if (accountData != null) {
data['account_data'] = {
'events': accountData!.map((i) => i.toJson()).toList(),
};
}
if (unreadNotifications != null) {
data['unread_notifications'] = unreadNotifications!.toJson();
}
return data;
}
}
class InvitedRoomUpdate extends SyncRoomUpdate {
List<StrippedStateEvent>? inviteState;
InvitedRoomUpdate({this.inviteState});
InvitedRoomUpdate.fromJson(Map<String, Object?> json)
: inviteState = json
.tryGetMap<String, List<Object?>>('invite_state')?['events']
?.map((i) => StrippedStateEvent.fromJson(i as Map<String, Object?>))
.toList();
Map<String, Object?> toJson() {
final data = <String, Object?>{};
if (inviteState != null) {
data['invite_state'] = {
'events': inviteState!.map((i) => i.toJson()).toList(),
};
}
return data;
}
}
class LeftRoomUpdate extends SyncRoomUpdate {
List<MatrixEvent>? state;
TimelineUpdate? timeline;
List<BasicRoomEvent>? accountData;
LeftRoomUpdate({
this.state,
this.timeline,
this.accountData,
});
LeftRoomUpdate.fromJson(Map<String, Object?> json)
: state = json
.tryGetMap<String, List<Object?>>('state')?['events']
?.map((i) => MatrixEvent.fromJson(i as Map<String, Object?>))
.toList(),
timeline = json.tryGetFromJson('timeline', TimelineUpdate.fromJson),
accountData = json
.tryGetMap<String, List<Object?>>('account_data')?['events']
?.map((i) => BasicRoomEvent.fromJson(i as Map<String, Object?>))
.toList();
Map<String, Object?> toJson() {
final data = <String, Object?>{};
if (state != null) {
data['state'] = {
'events': state!.map((i) => i.toJson()).toList(),
};
}
if (timeline != null) {
data['timeline'] = timeline!.toJson();
}
if (accountData != null) {
data['account_data'] = {
'events': accountData!.map((i) => i.toJson()).toList(),
};
}
return data;
}
}
class TimelineUpdate {
List<MatrixEvent>? events;
bool? limited;
String? prevBatch;
TimelineUpdate({
this.events,
this.limited,
this.prevBatch,
});
TimelineUpdate.fromJson(Map<String, Object?> json)
: events = json
.tryGetList<Map<String, Object?>>('events')
?.map((v) => MatrixEvent.fromJson(v))
.toList(),
limited = json.tryGet<bool>('limited'),
prevBatch = json.tryGet<String>('prev_batch');
Map<String, Object?> toJson() {
final data = <String, Object?>{};
if (events != null) {
data['events'] = events!.map((i) => i.toJson()).toList();
}
if (limited != null) {
data['limited'] = limited;
}
if (prevBatch != null) {
data['prev_batch'] = prevBatch;
}
return data;
}
}
class UnreadNotificationCounts {
int? highlightCount;
int? notificationCount;
UnreadNotificationCounts({
this.notificationCount,
this.highlightCount,
});
UnreadNotificationCounts.fromJson(Map<String, Object?> json)
: highlightCount = json.tryGet<int>('highlight_count'),
notificationCount = json.tryGet<int>('notification_count');
Map<String, Object?> toJson() {
final data = <String, Object?>{};
if (highlightCount != null) {
data['highlight_count'] = highlightCount;
}
if (notificationCount != null) {
data['notification_count'] = notificationCount;
}
return data;
}
}
class DeviceListsUpdate {
List<String>? changed;
List<String>? left;
DeviceListsUpdate({
this.changed,
this.left,
});
DeviceListsUpdate.fromJson(Map<String, Object?> json)
: changed = json.tryGetList<String>('changed') ?? [],
left = json.tryGetList<String>('left') ?? [];
Map<String, Object?> toJson() {
final data = <String, Object?>{};
if (changed != null) {
data['changed'] = changed;
}
if (left != null) {
data['left'] = left;
}
return data;
}
}

View File

@ -0,0 +1,14 @@
extension FilterMap<K, V> on Map<K, V> {
Map<K2, V2> filterMap<K2, V2>(MapEntry<K2, V2>? Function(K, V) f) =>
Map.fromEntries(
entries.map((e) => f(e.key, e.value)).whereType<MapEntry<K2, V2>>());
Map<K2, V2> catchMap<K2, V2>(MapEntry<K2, V2> Function(K, V) f) =>
filterMap((k, v) {
try {
return f(k, v);
} catch (_) {
return null;
}
});
}

View File

@ -0,0 +1,134 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import 'print_logs_native.dart' if (dart.library.html) 'print_logs_web.dart';
enum Level {
wtf,
error,
warning,
info,
debug,
verbose,
}
class Logs {
static final Logs _singleton = Logs._internal();
/// Override this function if you want to convert a stacktrace for some reason
/// for example to apply a source map in the browser.
static StackTrace? Function(StackTrace?) stackTraceConverter = (s) => s;
factory Logs() {
return _singleton;
}
Level level = Level.info;
bool nativeColors = true;
final List<LogEvent> outputEvents = [];
Logs._internal();
void addLogEvent(LogEvent logEvent) {
outputEvents.add(logEvent);
if (logEvent.level.index <= level.index) {
logEvent.printOut();
}
}
void wtf(String title, [Object? exception, StackTrace? stackTrace]) =>
addLogEvent(
LogEvent(
title,
exception: exception,
stackTrace: stackTraceConverter(stackTrace),
level: Level.wtf,
),
);
void e(String title, [Object? exception, StackTrace? stackTrace]) =>
addLogEvent(
LogEvent(
title,
exception: exception,
stackTrace: stackTraceConverter(stackTrace),
level: Level.error,
),
);
void w(String title, [Object? exception, StackTrace? stackTrace]) =>
addLogEvent(
LogEvent(
title,
exception: exception,
stackTrace: stackTraceConverter(stackTrace),
level: Level.warning,
),
);
void i(String title, [Object? exception, StackTrace? stackTrace]) =>
addLogEvent(
LogEvent(
title,
exception: exception,
stackTrace: stackTraceConverter(stackTrace),
level: Level.info,
),
);
void d(String title, [Object? exception, StackTrace? stackTrace]) =>
addLogEvent(
LogEvent(
title,
exception: exception,
stackTrace: stackTraceConverter(stackTrace),
level: Level.debug,
),
);
void v(String title, [Object? exception, StackTrace? stackTrace]) =>
addLogEvent(
LogEvent(
title,
exception: exception,
stackTrace: stackTraceConverter(stackTrace),
level: Level.verbose,
),
);
}
// ignore: avoid_print
class LogEvent {
final String title;
final Object? exception;
final StackTrace? stackTrace;
final Level level;
LogEvent(
this.title, {
this.exception,
this.stackTrace,
this.level = Level.debug,
});
}

View File

@ -0,0 +1,43 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
extension MapCopyExtension on Map<String, Object?> {
dynamic _copyValue(dynamic value) {
if (value is Map<String, Object?>) {
return value.copy();
}
if (value is List) {
return value.map(_copyValue).toList();
}
return value;
}
/// Deep-copies a given json map
Map<String, Object?> copy() {
final copy = Map<String, Object?>.from(this);
for (final entry in copy.entries) {
copy[entry.key] = _copyValue(entry.value);
}
return copy;
}
}

View File

@ -0,0 +1,36 @@
import 'package:matrix_api_lite/matrix_api_lite.dart';
extension PrintLogs on LogEvent {
void printOut() {
var logsStr = title;
if (exception != null) {
logsStr += ' - ${exception.toString()}';
}
if (stackTrace != null) {
logsStr += '\n${stackTrace.toString()}';
}
if (Logs().nativeColors) {
switch (level) {
case Level.wtf:
logsStr = '\x1B[31m!!!CRITICAL!!! $logsStr\x1B[0m';
break;
case Level.error:
logsStr = '\x1B[31m$logsStr\x1B[0m';
break;
case Level.warning:
logsStr = '\x1B[33m$logsStr\x1B[0m';
break;
case Level.info:
logsStr = '\x1B[32m$logsStr\x1B[0m';
break;
case Level.debug:
logsStr = '\x1B[34m$logsStr\x1B[0m';
break;
case Level.verbose:
break;
}
}
// ignore: avoid_print
print('[Matrix] $logsStr');
}
}

View File

@ -0,0 +1,35 @@
import 'dart:html';
import 'package:matrix_api_lite/matrix_api_lite.dart';
extension PrintLogs on LogEvent {
void printOut() {
var logsStr = '[Matrix] $title';
if (exception != null) {
logsStr += ' - ${exception.toString()}';
}
if (stackTrace != null) {
logsStr += '\n${stackTrace.toString()}';
}
switch (level) {
case Level.wtf:
window.console.error('!!!CRITICAL!!! $logsStr');
break;
case Level.error:
window.console.error(logsStr);
break;
case Level.warning:
window.console.warn(logsStr);
break;
case Level.info:
window.console.info(logsStr);
break;
case Level.debug:
window.console.debug(logsStr);
break;
case Level.verbose:
window.console.log(logsStr);
break;
}
}
}

View File

@ -0,0 +1,121 @@
/* MIT License
*
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import 'dart:core';
import 'logs.dart';
abstract class TryGet {
void call(String key, Type expected, Type actual);
static const TryGet required = _RequiredLog();
static const TryGet optional = _OptionalLog();
/// This is helpful if you have a field that can mean multiple things on purpose.
static const TryGet silent = _SilentLog();
}
class _RequiredLog implements TryGet {
const _RequiredLog();
@override
void call(String key, Type expected, Type actual) => Logs().w(
'Expected required "$expected" in event content for the Key "$key" but got "$actual" at ${StackTrace.current.firstLine}');
}
class _OptionalLog implements TryGet {
const _OptionalLog();
@override
void call(String key, Type expected, Type actual) {
if (actual != Null) {
Logs().w(
'Expected optional "$expected" in event content for the Key "$key" but got "$actual" at ${StackTrace.current.firstLine}');
}
}
}
class _SilentLog implements TryGet {
const _SilentLog();
@override
void call(String key, Type expected, Type actual) {}
}
extension TryGetMapExtension on Map<String, Object?> {
T? tryGet<T extends Object>(String key, [TryGet log = TryGet.optional]) {
final Object? value = this[key];
if (value is! T) {
log(key, T, value.runtimeType);
return null;
}
return value;
}
List<T>? tryGetList<T>(String key, [TryGet log = TryGet.optional]) {
final Object? value = this[key];
if (value is! List) {
log(key, T, value.runtimeType);
return null;
}
try {
// copy entries to ensure type check failures here and not an access
return value.cast<T>().toList();
} catch (_) {
Logs().v(
'Unable to create "List<$T>" in event content for the key "$key" at ${StackTrace.current.firstLine}');
return null;
}
}
Map<A, B>? tryGetMap<A, B>(String key, [TryGet log = TryGet.optional]) {
final Object? value = this[key];
if (value is! Map) {
log(key, <A, B>{}.runtimeType, value.runtimeType);
return null;
}
try {
// copy map to ensure type check failures here and not an access
return Map.from(value.cast<A, B>());
} catch (_) {
Logs().v(
'Unable to create "Map<$A,$B>" in event content for the key "$key" at ${StackTrace.current.firstLine}');
return null;
}
}
A? tryGetFromJson<A>(String key, A Function(Map<String, Object?>) fromJson,
[TryGet log = TryGet.optional]) {
final value = tryGetMap<String, Object?>(key, log);
return value != null ? fromJson(value) : null;
}
}
extension on StackTrace {
String get firstLine {
final lines = toString().split('\n');
return lines.length >= 3
? lines[2].replaceFirst('#2 ', '')
: lines.isNotEmpty
? lines.first
: '(unknown position)';
}
}

View File

@ -0,0 +1,21 @@
// OpenAPI only supports real enums (modeled as enum in generated/model.dart).
// In this file, possible values are defined manually,
// for cases where other values are allowed too.
class PushRuleAction {
static final notify = 'notify';
static final dontNotify = 'dont_notify';
static final coalesce = 'coalesce';
static final setTweak = 'set_tweak';
}
class TagType {
static final favourite = 'm.favourite';
static final lowPriority = 'm.lowpriority';
static final serverNotice = 'm.server_notice';
static bool isValid(String tag) => tag.startsWith('m.')
? [favourite, lowPriority, serverNotice].contains(tag)
: true;
}