mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-06-25 08:44:08 +00:00
fix: group auto rentry when it was deleted
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
This commit is contained in:
parent
e23ac5932e
commit
e7301020f6
16 changed files with 392 additions and 162 deletions
|
|
@ -368,10 +368,12 @@ class EncryptedContent_GroupCreate extends $pb.GeneratedMessage {
|
|||
factory EncryptedContent_GroupCreate({
|
||||
$core.List<$core.int>? stateKey,
|
||||
$core.List<$core.int>? groupPublicKey,
|
||||
$core.String? groupName,
|
||||
}) {
|
||||
final result = create();
|
||||
if (stateKey != null) result.stateKey = stateKey;
|
||||
if (groupPublicKey != null) result.groupPublicKey = groupPublicKey;
|
||||
if (groupName != null) result.groupName = groupName;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -391,6 +393,7 @@ class EncryptedContent_GroupCreate extends $pb.GeneratedMessage {
|
|||
3, _omitFieldNames ? '' : 'stateKey', $pb.PbFieldType.OY)
|
||||
..a<$core.List<$core.int>>(
|
||||
4, _omitFieldNames ? '' : 'groupPublicKey', $pb.PbFieldType.OY)
|
||||
..aOS(5, _omitFieldNames ? '' : 'groupName')
|
||||
..hasRequiredFields = false;
|
||||
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
|
|
@ -433,6 +436,15 @@ class EncryptedContent_GroupCreate extends $pb.GeneratedMessage {
|
|||
$core.bool hasGroupPublicKey() => $_has(1);
|
||||
@$pb.TagNumber(4)
|
||||
void clearGroupPublicKey() => $_clearField(4);
|
||||
|
||||
@$pb.TagNumber(5)
|
||||
$core.String get groupName => $_getSZ(2);
|
||||
@$pb.TagNumber(5)
|
||||
set groupName($core.String value) => $_setString(2, value);
|
||||
@$pb.TagNumber(5)
|
||||
$core.bool hasGroupName() => $_has(2);
|
||||
@$pb.TagNumber(5)
|
||||
void clearGroupName() => $_clearField(5);
|
||||
}
|
||||
|
||||
class EncryptedContent_GroupJoin extends $pb.GeneratedMessage {
|
||||
|
|
|
|||
|
|
@ -79,16 +79,20 @@ class EncryptedContent_ErrorMessages_Type extends $pb.ProtobufEnum {
|
|||
static const EncryptedContent_ErrorMessages_Type SESSION_OUT_OF_SYNC =
|
||||
EncryptedContent_ErrorMessages_Type._(
|
||||
3, _omitEnumNames ? '' : 'SESSION_OUT_OF_SYNC');
|
||||
static const EncryptedContent_ErrorMessages_Type
|
||||
GROUP_NOT_FOUND_OR_NOT_A_MEMBER = EncryptedContent_ErrorMessages_Type._(
|
||||
4, _omitEnumNames ? '' : 'GROUP_NOT_FOUND_OR_NOT_A_MEMBER');
|
||||
|
||||
static const $core.List<EncryptedContent_ErrorMessages_Type> values =
|
||||
<EncryptedContent_ErrorMessages_Type>[
|
||||
ERROR_PROCESSING_MESSAGE_CREATED_ACCOUNT_REQUEST_INSTEAD,
|
||||
UNKNOWN_MESSAGE_TYPE,
|
||||
SESSION_OUT_OF_SYNC,
|
||||
GROUP_NOT_FOUND_OR_NOT_A_MEMBER,
|
||||
];
|
||||
|
||||
static final $core.List<EncryptedContent_ErrorMessages_Type?> _byValue =
|
||||
$pb.ProtobufEnum.$_initByValueList(values, 3);
|
||||
$pb.ProtobufEnum.$_initByValueList(values, 4);
|
||||
static EncryptedContent_ErrorMessages_Type? valueOf($core.int value) =>
|
||||
value < 0 || value >= _byValue.length ? null : _byValue[value];
|
||||
|
||||
|
|
|
|||
|
|
@ -465,6 +465,7 @@ const EncryptedContent_ErrorMessages_Type$json = {
|
|||
{'1': 'ERROR_PROCESSING_MESSAGE_CREATED_ACCOUNT_REQUEST_INSTEAD', '2': 0},
|
||||
{'1': 'UNKNOWN_MESSAGE_TYPE', '2': 2},
|
||||
{'1': 'SESSION_OUT_OF_SYNC', '2': 3},
|
||||
{'1': 'GROUP_NOT_FOUND_OR_NOT_A_MEMBER', '2': 4},
|
||||
],
|
||||
};
|
||||
|
||||
|
|
@ -474,6 +475,18 @@ const EncryptedContent_GroupCreate$json = {
|
|||
'2': [
|
||||
{'1': 'state_key', '3': 3, '4': 1, '5': 12, '10': 'stateKey'},
|
||||
{'1': 'group_public_key', '3': 4, '4': 1, '5': 12, '10': 'groupPublicKey'},
|
||||
{
|
||||
'1': 'group_name',
|
||||
'3': 5,
|
||||
'4': 1,
|
||||
'5': 9,
|
||||
'9': 0,
|
||||
'10': 'groupName',
|
||||
'17': true
|
||||
},
|
||||
],
|
||||
'8': [
|
||||
{'1': '_group_name'},
|
||||
],
|
||||
};
|
||||
|
||||
|
|
@ -975,78 +988,79 @@ final $typed_data.Uint8List encryptedContentDescriptor = $convert.base64Decode(
|
|||
'aXNjb3ZlcnlSZXF1ZXN0iAEBEl4KFXVzZXJfZGlzY292ZXJ5X3VwZGF0ZRgXIAEoCzIlLkVuY3'
|
||||
'J5cHRlZENvbnRlbnQuVXNlckRpc2NvdmVyeVVwZGF0ZUgWUhN1c2VyRGlzY292ZXJ5VXBkYXRl'
|
||||
'iAEBEmEKFmtleV92ZXJpZmljYXRpb25fcHJvb2YYGCABKAsyJi5FbmNyeXB0ZWRDb250ZW50Lk'
|
||||
'tleVZlcmlmaWNhdGlvblByb29mSBdSFGtleVZlcmlmaWNhdGlvblByb29miAEBGvABCg1FcnJv'
|
||||
'tleVZlcmlmaWNhdGlvblByb29mSBdSFGtleVZlcmlmaWNhdGlvblByb29miAEBGpYCCg1FcnJv'
|
||||
'ck1lc3NhZ2VzEjgKBHR5cGUYASABKA4yJC5FbmNyeXB0ZWRDb250ZW50LkVycm9yTWVzc2FnZX'
|
||||
'MuVHlwZVIEdHlwZRIsChJyZWxhdGVkX3JlY2VpcHRfaWQYAiABKAlSEHJlbGF0ZWRSZWNlaXB0'
|
||||
'SWQidwoEVHlwZRI8CjhFUlJPUl9QUk9DRVNTSU5HX01FU1NBR0VfQ1JFQVRFRF9BQ0NPVU5UX1'
|
||||
'JFUVVFU1RfSU5TVEVBRBAAEhgKFFVOS05PV05fTUVTU0FHRV9UWVBFEAISFwoTU0VTU0lPTl9P'
|
||||
'VVRfT0ZfU1lOQxADGlQKC0dyb3VwQ3JlYXRlEhsKCXN0YXRlX2tleRgDIAEoDFIIc3RhdGVLZX'
|
||||
'kSKAoQZ3JvdXBfcHVibGljX2tleRgEIAEoDFIOZ3JvdXBQdWJsaWNLZXkaNQoJR3JvdXBKb2lu'
|
||||
'EigKEGdyb3VwX3B1YmxpY19rZXkYASABKAxSDmdyb3VwUHVibGljS2V5GhYKFFJlc2VuZEdyb3'
|
||||
'VwUHVibGljS2V5GsgCCgtHcm91cFVwZGF0ZRIqChFncm91cF9hY3Rpb25fdHlwZRgBIAEoCVIP'
|
||||
'Z3JvdXBBY3Rpb25UeXBlEjMKE2FmZmVjdGVkX2NvbnRhY3RfaWQYAiABKANIAFIRYWZmZWN0ZW'
|
||||
'RDb250YWN0SWSIAQESKQoObmV3X2dyb3VwX25hbWUYAyABKAlIAVIMbmV3R3JvdXBOYW1liAEB'
|
||||
'ElcKJm5ld19kZWxldGVfbWVzc2FnZXNfYWZ0ZXJfbWlsbGlzZWNvbmRzGAQgASgDSAJSIm5ld0'
|
||||
'RlbGV0ZU1lc3NhZ2VzQWZ0ZXJNaWxsaXNlY29uZHOIAQFCFgoUX2FmZmVjdGVkX2NvbnRhY3Rf'
|
||||
'aWRCEQoPX25ld19ncm91cF9uYW1lQikKJ19uZXdfZGVsZXRlX21lc3NhZ2VzX2FmdGVyX21pbG'
|
||||
'xpc2Vjb25kcxqvAQoLVGV4dE1lc3NhZ2USKgoRc2VuZGVyX21lc3NhZ2VfaWQYASABKAlSD3Nl'
|
||||
'bmRlck1lc3NhZ2VJZBISCgR0ZXh0GAIgASgJUgR0ZXh0EhwKCXRpbWVzdGFtcBgDIAEoA1IJdG'
|
||||
'ltZXN0YW1wEi0KEHF1b3RlX21lc3NhZ2VfaWQYBCABKAlIAFIOcXVvdGVNZXNzYWdlSWSIAQFC'
|
||||
'EwoRX3F1b3RlX21lc3NhZ2VfaWQazgEKFUFkZGl0aW9uYWxEYXRhTWVzc2FnZRIqChFzZW5kZX'
|
||||
'JfbWVzc2FnZV9pZBgBIAEoCVIPc2VuZGVyTWVzc2FnZUlkEhwKCXRpbWVzdGFtcBgCIAEoA1IJ'
|
||||
'dGltZXN0YW1wEhIKBHR5cGUYAyABKAlSBHR5cGUSOwoXYWRkaXRpb25hbF9tZXNzYWdlX2RhdG'
|
||||
'EYBCABKAxIAFIVYWRkaXRpb25hbE1lc3NhZ2VEYXRhiAEBQhoKGF9hZGRpdGlvbmFsX21lc3Nh'
|
||||
'Z2VfZGF0YRpkCghSZWFjdGlvbhIqChF0YXJnZXRfbWVzc2FnZV9pZBgBIAEoCVIPdGFyZ2V0TW'
|
||||
'Vzc2FnZUlkEhQKBWVtb2ppGAIgASgJUgVlbW9qaRIWCgZyZW1vdmUYAyABKAhSBnJlbW92ZRq+'
|
||||
'AgoNTWVzc2FnZVVwZGF0ZRI4CgR0eXBlGAEgASgOMiQuRW5jcnlwdGVkQ29udGVudC5NZXNzYW'
|
||||
'dlVXBkYXRlLlR5cGVSBHR5cGUSLwoRc2VuZGVyX21lc3NhZ2VfaWQYAiABKAlIAFIPc2VuZGVy'
|
||||
'TWVzc2FnZUlkiAEBEj0KG211bHRpcGxlX3RhcmdldF9tZXNzYWdlX2lkcxgDIAMoCVIYbXVsdG'
|
||||
'lwbGVUYXJnZXRNZXNzYWdlSWRzEhcKBHRleHQYBCABKAlIAVIEdGV4dIgBARIcCgl0aW1lc3Rh'
|
||||
'bXAYBSABKANSCXRpbWVzdGFtcCItCgRUeXBlEgoKBkRFTEVURRAAEg0KCUVESVRfVEVYVBABEg'
|
||||
'oKBk9QRU5FRBACQhQKEl9zZW5kZXJfbWVzc2FnZV9pZEIHCgVfdGV4dBqFBgoFTWVkaWESKgoR'
|
||||
'c2VuZGVyX21lc3NhZ2VfaWQYASABKAlSD3NlbmRlck1lc3NhZ2VJZBIwCgR0eXBlGAIgASgOMh'
|
||||
'wuRW5jcnlwdGVkQ29udGVudC5NZWRpYS5UeXBlUgR0eXBlEkYKHWRpc3BsYXlfbGltaXRfaW5f'
|
||||
'bWlsbGlzZWNvbmRzGAMgASgDSABSGmRpc3BsYXlMaW1pdEluTWlsbGlzZWNvbmRziAEBEjcKF3'
|
||||
'JlcXVpcmVzX2F1dGhlbnRpY2F0aW9uGAQgASgIUhZyZXF1aXJlc0F1dGhlbnRpY2F0aW9uEhwK'
|
||||
'CXRpbWVzdGFtcBgFIAEoA1IJdGltZXN0YW1wEi0KEHF1b3RlX21lc3NhZ2VfaWQYBiABKAlIAV'
|
||||
'IOcXVvdGVNZXNzYWdlSWSIAQESKgoOZG93bmxvYWRfdG9rZW4YByABKAxIAlINZG93bmxvYWRU'
|
||||
'b2tlbogBARIqCg5lbmNyeXB0aW9uX2tleRgIIAEoDEgDUg1lbmNyeXB0aW9uS2V5iAEBEioKDm'
|
||||
'VuY3J5cHRpb25fbWFjGAkgASgMSARSDWVuY3J5cHRpb25NYWOIAQESLgoQZW5jcnlwdGlvbl9u'
|
||||
'b25jZRgKIAEoDEgFUg9lbmNyeXB0aW9uTm9uY2WIAQESOwoXYWRkaXRpb25hbF9tZXNzYWdlX2'
|
||||
'RhdGEYCyABKAxIBlIVYWRkaXRpb25hbE1lc3NhZ2VEYXRhiAEBIj4KBFR5cGUSDAoIUkVVUExP'
|
||||
'QUQQABIJCgVJTUFHRRABEgkKBVZJREVPEAISBwoDR0lGEAMSCQoFQVVESU8QBEIgCh5fZGlzcG'
|
||||
'xheV9saW1pdF9pbl9taWxsaXNlY29uZHNCEwoRX3F1b3RlX21lc3NhZ2VfaWRCEQoPX2Rvd25s'
|
||||
'b2FkX3Rva2VuQhEKD19lbmNyeXB0aW9uX2tleUIRCg9fZW5jcnlwdGlvbl9tYWNCEwoRX2VuY3'
|
||||
'J5cHRpb25fbm9uY2VCGgoYX2FkZGl0aW9uYWxfbWVzc2FnZV9kYXRhGqkBCgtNZWRpYVVwZGF0'
|
||||
'ZRI2CgR0eXBlGAEgASgOMiIuRW5jcnlwdGVkQ29udGVudC5NZWRpYVVwZGF0ZS5UeXBlUgR0eX'
|
||||
'BlEioKEXRhcmdldF9tZXNzYWdlX2lkGAIgASgJUg90YXJnZXRNZXNzYWdlSWQiNgoEVHlwZRIM'
|
||||
'CghSRU9QRU5FRBAAEgoKBlNUT1JFRBABEhQKEERFQ1JZUFRJT05fRVJST1IQAhp4Cg5Db250YW'
|
||||
'N0UmVxdWVzdBI5CgR0eXBlGAEgASgOMiUuRW5jcnlwdGVkQ29udGVudC5Db250YWN0UmVxdWVz'
|
||||
'dC5UeXBlUgR0eXBlIisKBFR5cGUSCwoHUkVRVUVTVBAAEgoKBlJFSkVDVBABEgoKBkFDQ0VQVB'
|
||||
'ACGqQCCg1Db250YWN0VXBkYXRlEjgKBHR5cGUYASABKA4yJC5FbmNyeXB0ZWRDb250ZW50LkNv'
|
||||
'bnRhY3RVcGRhdGUuVHlwZVIEdHlwZRI3ChVhdmF0YXJfc3ZnX2NvbXByZXNzZWQYAiABKAxIAF'
|
||||
'ITYXZhdGFyU3ZnQ29tcHJlc3NlZIgBARIfCgh1c2VybmFtZRgDIAEoCUgBUgh1c2VybmFtZYgB'
|
||||
'ARImCgxkaXNwbGF5X25hbWUYBCABKAlIAlILZGlzcGxheU5hbWWIAQEiHwoEVHlwZRILCgdSRV'
|
||||
'FVRVNUEAASCgoGVVBEQVRFEAFCGAoWX2F2YXRhcl9zdmdfY29tcHJlc3NlZEILCglfdXNlcm5h'
|
||||
'bWVCDwoNX2Rpc3BsYXlfbmFtZRrZAQoIUHVzaEtleXMSMwoEdHlwZRgBIAEoDjIfLkVuY3J5cH'
|
||||
'RlZENvbnRlbnQuUHVzaEtleXMuVHlwZVIEdHlwZRIaCgZrZXlfaWQYAiABKANIAFIFa2V5SWSI'
|
||||
'AQESFQoDa2V5GAMgASgMSAFSA2tleYgBARIiCgpjcmVhdGVkX2F0GAQgASgDSAJSCWNyZWF0ZW'
|
||||
'RBdIgBASIfCgRUeXBlEgsKB1JFUVVFU1QQABIKCgZVUERBVEUQAUIJCgdfa2V5X2lkQgYKBF9r'
|
||||
'ZXlCDQoLX2NyZWF0ZWRfYXQarwEKCUZsYW1lU3luYxIjCg1mbGFtZV9jb3VudGVyGAEgASgDUg'
|
||||
'xmbGFtZUNvdW50ZXISOQoZbGFzdF9mbGFtZV9jb3VudGVyX2NoYW5nZRgCIAEoA1IWbGFzdEZs'
|
||||
'YW1lQ291bnRlckNoYW5nZRIfCgtiZXN0X2ZyaWVuZBgDIAEoCFIKYmVzdEZyaWVuZBIhCgxmb3'
|
||||
'JjZV91cGRhdGUYBCABKAhSC2ZvcmNlVXBkYXRlGk0KD1R5cGluZ0luZGljYXRvchIbCglpc190'
|
||||
'eXBpbmcYASABKAhSCGlzVHlwaW5nEh0KCmNyZWF0ZWRfYXQYAiABKANSCWNyZWF0ZWRBdBo/Ch'
|
||||
'RVc2VyRGlzY292ZXJ5UmVxdWVzdBInCg9jdXJyZW50X3ZlcnNpb24YASABKAxSDmN1cnJlbnRW'
|
||||
'ZXJzaW9uGjEKE1VzZXJEaXNjb3ZlcnlVcGRhdGUSGgoIbWVzc2FnZXMYASADKAxSCG1lc3NhZ2'
|
||||
'VzGj0KFEtleVZlcmlmaWNhdGlvblByb29mEiUKDmNhbGN1bGF0ZWRfbWFjGAEgASgMUg1jYWxj'
|
||||
'dWxhdGVkTWFjQgsKCV9ncm91cF9pZEIRCg9faXNfZGlyZWN0X2NoYXRCGQoXX3NlbmRlcl9wcm'
|
||||
'9maWxlX2NvdW50ZXJCIAoeX3NlbmRlcl91c2VyX2Rpc2NvdmVyeV92ZXJzaW9uQhwKGl9hc2tf'
|
||||
'Zm9yX2ZyaWVuZF9wcm9tb3Rpb25zQhEKD19tZXNzYWdlX3VwZGF0ZUIICgZfbWVkaWFCDwoNX2'
|
||||
'1lZGlhX3VwZGF0ZUIRCg9fY29udGFjdF91cGRhdGVCEgoQX2NvbnRhY3RfcmVxdWVzdEINCgtf'
|
||||
'ZmxhbWVfc3luY0IMCgpfcHVzaF9rZXlzQgsKCV9yZWFjdGlvbkIPCg1fdGV4dF9tZXNzYWdlQg'
|
||||
'8KDV9ncm91cF9jcmVhdGVCDQoLX2dyb3VwX2pvaW5CDwoNX2dyb3VwX3VwZGF0ZUIaChhfcmVz'
|
||||
'ZW5kX2dyb3VwX3B1YmxpY19rZXlCEQoPX2Vycm9yX21lc3NhZ2VzQhoKGF9hZGRpdGlvbmFsX2'
|
||||
'RhdGFfbWVzc2FnZUITChFfdHlwaW5nX2luZGljYXRvckIZChdfdXNlcl9kaXNjb3ZlcnlfcmVx'
|
||||
'dWVzdEIYChZfdXNlcl9kaXNjb3ZlcnlfdXBkYXRlQhkKF19rZXlfdmVyaWZpY2F0aW9uX3Byb2'
|
||||
'9m');
|
||||
'SWQinAEKBFR5cGUSPAo4RVJST1JfUFJPQ0VTU0lOR19NRVNTQUdFX0NSRUFURURfQUNDT1VOVF'
|
||||
'9SRVFVRVNUX0lOU1RFQUQQABIYChRVTktOT1dOX01FU1NBR0VfVFlQRRACEhcKE1NFU1NJT05f'
|
||||
'T1VUX09GX1NZTkMQAxIjCh9HUk9VUF9OT1RfRk9VTkRfT1JfTk9UX0FfTUVNQkVSEAQahwEKC0'
|
||||
'dyb3VwQ3JlYXRlEhsKCXN0YXRlX2tleRgDIAEoDFIIc3RhdGVLZXkSKAoQZ3JvdXBfcHVibGlj'
|
||||
'X2tleRgEIAEoDFIOZ3JvdXBQdWJsaWNLZXkSIgoKZ3JvdXBfbmFtZRgFIAEoCUgAUglncm91cE'
|
||||
'5hbWWIAQFCDQoLX2dyb3VwX25hbWUaNQoJR3JvdXBKb2luEigKEGdyb3VwX3B1YmxpY19rZXkY'
|
||||
'ASABKAxSDmdyb3VwUHVibGljS2V5GhYKFFJlc2VuZEdyb3VwUHVibGljS2V5GsgCCgtHcm91cF'
|
||||
'VwZGF0ZRIqChFncm91cF9hY3Rpb25fdHlwZRgBIAEoCVIPZ3JvdXBBY3Rpb25UeXBlEjMKE2Fm'
|
||||
'ZmVjdGVkX2NvbnRhY3RfaWQYAiABKANIAFIRYWZmZWN0ZWRDb250YWN0SWSIAQESKQoObmV3X2'
|
||||
'dyb3VwX25hbWUYAyABKAlIAVIMbmV3R3JvdXBOYW1liAEBElcKJm5ld19kZWxldGVfbWVzc2Fn'
|
||||
'ZXNfYWZ0ZXJfbWlsbGlzZWNvbmRzGAQgASgDSAJSIm5ld0RlbGV0ZU1lc3NhZ2VzQWZ0ZXJNaW'
|
||||
'xsaXNlY29uZHOIAQFCFgoUX2FmZmVjdGVkX2NvbnRhY3RfaWRCEQoPX25ld19ncm91cF9uYW1l'
|
||||
'QikKJ19uZXdfZGVsZXRlX21lc3NhZ2VzX2FmdGVyX21pbGxpc2Vjb25kcxqvAQoLVGV4dE1lc3'
|
||||
'NhZ2USKgoRc2VuZGVyX21lc3NhZ2VfaWQYASABKAlSD3NlbmRlck1lc3NhZ2VJZBISCgR0ZXh0'
|
||||
'GAIgASgJUgR0ZXh0EhwKCXRpbWVzdGFtcBgDIAEoA1IJdGltZXN0YW1wEi0KEHF1b3RlX21lc3'
|
||||
'NhZ2VfaWQYBCABKAlIAFIOcXVvdGVNZXNzYWdlSWSIAQFCEwoRX3F1b3RlX21lc3NhZ2VfaWQa'
|
||||
'zgEKFUFkZGl0aW9uYWxEYXRhTWVzc2FnZRIqChFzZW5kZXJfbWVzc2FnZV9pZBgBIAEoCVIPc2'
|
||||
'VuZGVyTWVzc2FnZUlkEhwKCXRpbWVzdGFtcBgCIAEoA1IJdGltZXN0YW1wEhIKBHR5cGUYAyAB'
|
||||
'KAlSBHR5cGUSOwoXYWRkaXRpb25hbF9tZXNzYWdlX2RhdGEYBCABKAxIAFIVYWRkaXRpb25hbE'
|
||||
'1lc3NhZ2VEYXRhiAEBQhoKGF9hZGRpdGlvbmFsX21lc3NhZ2VfZGF0YRpkCghSZWFjdGlvbhIq'
|
||||
'ChF0YXJnZXRfbWVzc2FnZV9pZBgBIAEoCVIPdGFyZ2V0TWVzc2FnZUlkEhQKBWVtb2ppGAIgAS'
|
||||
'gJUgVlbW9qaRIWCgZyZW1vdmUYAyABKAhSBnJlbW92ZRq+AgoNTWVzc2FnZVVwZGF0ZRI4CgR0'
|
||||
'eXBlGAEgASgOMiQuRW5jcnlwdGVkQ29udGVudC5NZXNzYWdlVXBkYXRlLlR5cGVSBHR5cGUSLw'
|
||||
'oRc2VuZGVyX21lc3NhZ2VfaWQYAiABKAlIAFIPc2VuZGVyTWVzc2FnZUlkiAEBEj0KG211bHRp'
|
||||
'cGxlX3RhcmdldF9tZXNzYWdlX2lkcxgDIAMoCVIYbXVsdGlwbGVUYXJnZXRNZXNzYWdlSWRzEh'
|
||||
'cKBHRleHQYBCABKAlIAVIEdGV4dIgBARIcCgl0aW1lc3RhbXAYBSABKANSCXRpbWVzdGFtcCIt'
|
||||
'CgRUeXBlEgoKBkRFTEVURRAAEg0KCUVESVRfVEVYVBABEgoKBk9QRU5FRBACQhQKEl9zZW5kZX'
|
||||
'JfbWVzc2FnZV9pZEIHCgVfdGV4dBqFBgoFTWVkaWESKgoRc2VuZGVyX21lc3NhZ2VfaWQYASAB'
|
||||
'KAlSD3NlbmRlck1lc3NhZ2VJZBIwCgR0eXBlGAIgASgOMhwuRW5jcnlwdGVkQ29udGVudC5NZW'
|
||||
'RpYS5UeXBlUgR0eXBlEkYKHWRpc3BsYXlfbGltaXRfaW5fbWlsbGlzZWNvbmRzGAMgASgDSABS'
|
||||
'GmRpc3BsYXlMaW1pdEluTWlsbGlzZWNvbmRziAEBEjcKF3JlcXVpcmVzX2F1dGhlbnRpY2F0aW'
|
||||
'9uGAQgASgIUhZyZXF1aXJlc0F1dGhlbnRpY2F0aW9uEhwKCXRpbWVzdGFtcBgFIAEoA1IJdGlt'
|
||||
'ZXN0YW1wEi0KEHF1b3RlX21lc3NhZ2VfaWQYBiABKAlIAVIOcXVvdGVNZXNzYWdlSWSIAQESKg'
|
||||
'oOZG93bmxvYWRfdG9rZW4YByABKAxIAlINZG93bmxvYWRUb2tlbogBARIqCg5lbmNyeXB0aW9u'
|
||||
'X2tleRgIIAEoDEgDUg1lbmNyeXB0aW9uS2V5iAEBEioKDmVuY3J5cHRpb25fbWFjGAkgASgMSA'
|
||||
'RSDWVuY3J5cHRpb25NYWOIAQESLgoQZW5jcnlwdGlvbl9ub25jZRgKIAEoDEgFUg9lbmNyeXB0'
|
||||
'aW9uTm9uY2WIAQESOwoXYWRkaXRpb25hbF9tZXNzYWdlX2RhdGEYCyABKAxIBlIVYWRkaXRpb2'
|
||||
'5hbE1lc3NhZ2VEYXRhiAEBIj4KBFR5cGUSDAoIUkVVUExPQUQQABIJCgVJTUFHRRABEgkKBVZJ'
|
||||
'REVPEAISBwoDR0lGEAMSCQoFQVVESU8QBEIgCh5fZGlzcGxheV9saW1pdF9pbl9taWxsaXNlY2'
|
||||
'9uZHNCEwoRX3F1b3RlX21lc3NhZ2VfaWRCEQoPX2Rvd25sb2FkX3Rva2VuQhEKD19lbmNyeXB0'
|
||||
'aW9uX2tleUIRCg9fZW5jcnlwdGlvbl9tYWNCEwoRX2VuY3J5cHRpb25fbm9uY2VCGgoYX2FkZG'
|
||||
'l0aW9uYWxfbWVzc2FnZV9kYXRhGqkBCgtNZWRpYVVwZGF0ZRI2CgR0eXBlGAEgASgOMiIuRW5j'
|
||||
'cnlwdGVkQ29udGVudC5NZWRpYVVwZGF0ZS5UeXBlUgR0eXBlEioKEXRhcmdldF9tZXNzYWdlX2'
|
||||
'lkGAIgASgJUg90YXJnZXRNZXNzYWdlSWQiNgoEVHlwZRIMCghSRU9QRU5FRBAAEgoKBlNUT1JF'
|
||||
'RBABEhQKEERFQ1JZUFRJT05fRVJST1IQAhp4Cg5Db250YWN0UmVxdWVzdBI5CgR0eXBlGAEgAS'
|
||||
'gOMiUuRW5jcnlwdGVkQ29udGVudC5Db250YWN0UmVxdWVzdC5UeXBlUgR0eXBlIisKBFR5cGUS'
|
||||
'CwoHUkVRVUVTVBAAEgoKBlJFSkVDVBABEgoKBkFDQ0VQVBACGqQCCg1Db250YWN0VXBkYXRlEj'
|
||||
'gKBHR5cGUYASABKA4yJC5FbmNyeXB0ZWRDb250ZW50LkNvbnRhY3RVcGRhdGUuVHlwZVIEdHlw'
|
||||
'ZRI3ChVhdmF0YXJfc3ZnX2NvbXByZXNzZWQYAiABKAxIAFITYXZhdGFyU3ZnQ29tcHJlc3NlZI'
|
||||
'gBARIfCgh1c2VybmFtZRgDIAEoCUgBUgh1c2VybmFtZYgBARImCgxkaXNwbGF5X25hbWUYBCAB'
|
||||
'KAlIAlILZGlzcGxheU5hbWWIAQEiHwoEVHlwZRILCgdSRVFVRVNUEAASCgoGVVBEQVRFEAFCGA'
|
||||
'oWX2F2YXRhcl9zdmdfY29tcHJlc3NlZEILCglfdXNlcm5hbWVCDwoNX2Rpc3BsYXlfbmFtZRrZ'
|
||||
'AQoIUHVzaEtleXMSMwoEdHlwZRgBIAEoDjIfLkVuY3J5cHRlZENvbnRlbnQuUHVzaEtleXMuVH'
|
||||
'lwZVIEdHlwZRIaCgZrZXlfaWQYAiABKANIAFIFa2V5SWSIAQESFQoDa2V5GAMgASgMSAFSA2tl'
|
||||
'eYgBARIiCgpjcmVhdGVkX2F0GAQgASgDSAJSCWNyZWF0ZWRBdIgBASIfCgRUeXBlEgsKB1JFUV'
|
||||
'VFU1QQABIKCgZVUERBVEUQAUIJCgdfa2V5X2lkQgYKBF9rZXlCDQoLX2NyZWF0ZWRfYXQarwEK'
|
||||
'CUZsYW1lU3luYxIjCg1mbGFtZV9jb3VudGVyGAEgASgDUgxmbGFtZUNvdW50ZXISOQoZbGFzdF'
|
||||
'9mbGFtZV9jb3VudGVyX2NoYW5nZRgCIAEoA1IWbGFzdEZsYW1lQ291bnRlckNoYW5nZRIfCgti'
|
||||
'ZXN0X2ZyaWVuZBgDIAEoCFIKYmVzdEZyaWVuZBIhCgxmb3JjZV91cGRhdGUYBCABKAhSC2Zvcm'
|
||||
'NlVXBkYXRlGk0KD1R5cGluZ0luZGljYXRvchIbCglpc190eXBpbmcYASABKAhSCGlzVHlwaW5n'
|
||||
'Eh0KCmNyZWF0ZWRfYXQYAiABKANSCWNyZWF0ZWRBdBo/ChRVc2VyRGlzY292ZXJ5UmVxdWVzdB'
|
||||
'InCg9jdXJyZW50X3ZlcnNpb24YASABKAxSDmN1cnJlbnRWZXJzaW9uGjEKE1VzZXJEaXNjb3Zl'
|
||||
'cnlVcGRhdGUSGgoIbWVzc2FnZXMYASADKAxSCG1lc3NhZ2VzGj0KFEtleVZlcmlmaWNhdGlvbl'
|
||||
'Byb29mEiUKDmNhbGN1bGF0ZWRfbWFjGAEgASgMUg1jYWxjdWxhdGVkTWFjQgsKCV9ncm91cF9p'
|
||||
'ZEIRCg9faXNfZGlyZWN0X2NoYXRCGQoXX3NlbmRlcl9wcm9maWxlX2NvdW50ZXJCIAoeX3Nlbm'
|
||||
'Rlcl91c2VyX2Rpc2NvdmVyeV92ZXJzaW9uQhwKGl9hc2tfZm9yX2ZyaWVuZF9wcm9tb3Rpb25z'
|
||||
'QhEKD19tZXNzYWdlX3VwZGF0ZUIICgZfbWVkaWFCDwoNX21lZGlhX3VwZGF0ZUIRCg9fY29udG'
|
||||
'FjdF91cGRhdGVCEgoQX2NvbnRhY3RfcmVxdWVzdEINCgtfZmxhbWVfc3luY0IMCgpfcHVzaF9r'
|
||||
'ZXlzQgsKCV9yZWFjdGlvbkIPCg1fdGV4dF9tZXNzYWdlQg8KDV9ncm91cF9jcmVhdGVCDQoLX2'
|
||||
'dyb3VwX2pvaW5CDwoNX2dyb3VwX3VwZGF0ZUIaChhfcmVzZW5kX2dyb3VwX3B1YmxpY19rZXlC'
|
||||
'EQoPX2Vycm9yX21lc3NhZ2VzQhoKGF9hZGRpdGlvbmFsX2RhdGFfbWVzc2FnZUITChFfdHlwaW'
|
||||
'5nX2luZGljYXRvckIZChdfdXNlcl9kaXNjb3ZlcnlfcmVxdWVzdEIYChZfdXNlcl9kaXNjb3Zl'
|
||||
'cnlfdXBkYXRlQhkKF19rZXlfdmVyaWZpY2F0aW9uX3Byb29m');
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ message EncryptedContent {
|
|||
ERROR_PROCESSING_MESSAGE_CREATED_ACCOUNT_REQUEST_INSTEAD = 0;
|
||||
UNKNOWN_MESSAGE_TYPE = 2;
|
||||
SESSION_OUT_OF_SYNC = 3;
|
||||
GROUP_NOT_FOUND_OR_NOT_A_MEMBER = 4;
|
||||
}
|
||||
Type type = 1;
|
||||
string related_receipt_id = 2;
|
||||
|
|
@ -73,6 +74,7 @@ message EncryptedContent {
|
|||
// key for the state stored on the server
|
||||
bytes state_key = 3;
|
||||
bytes group_public_key = 4;
|
||||
optional string group_name = 5;
|
||||
}
|
||||
|
||||
message GroupJoin {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,22 @@
|
|||
import 'package:clock/clock.dart';
|
||||
import 'package:drift/drift.dart' show Value;
|
||||
import 'package:fixnum/fixnum.dart' show Int64;
|
||||
import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'
|
||||
show IdentityKeyPair;
|
||||
import 'package:twonly/locator.dart';
|
||||
import 'package:twonly/src/database/twonly.db.dart';
|
||||
import 'package:twonly/src/model/protobuf/client/generated/messages.pbserver.dart';
|
||||
import 'package:twonly/src/services/api/messages.api.dart'
|
||||
show sendCipherText, tryToSendCompleteMessage;
|
||||
import 'package:twonly/src/services/group.service.dart' show fetchGroupState;
|
||||
import 'package:twonly/src/utils/log.dart';
|
||||
|
||||
Future<void> handleErrorMessage(
|
||||
int fromUserId,
|
||||
EncryptedContent_ErrorMessages error,
|
||||
String receiptId,
|
||||
) async {
|
||||
String receiptId, {
|
||||
String? groupId,
|
||||
}) async {
|
||||
Log.error('[$receiptId] Got error from $fromUserId: $error');
|
||||
|
||||
switch (error.type) {
|
||||
|
|
@ -29,6 +36,59 @@ Future<void> handleErrorMessage(
|
|||
);
|
||||
case EncryptedContent_ErrorMessages_Type.SESSION_OUT_OF_SYNC:
|
||||
break; // The other user initiated a new signal session, so ignore the error in this case, as the new session works...
|
||||
case EncryptedContent_ErrorMessages_Type.GROUP_NOT_FOUND_OR_NOT_A_MEMBER:
|
||||
if (groupId == null) {
|
||||
Log.error(
|
||||
'[$receiptId] GROUP_NOT_FOUND_OR_NOT_A_MEMBER error received, but groupId is null.',
|
||||
);
|
||||
return;
|
||||
}
|
||||
final group = await twonlyDB.groupsDao.getGroup(groupId);
|
||||
if (group == null) {
|
||||
Log.error(
|
||||
'[$receiptId] GROUP_NOT_FOUND_OR_NOT_A_MEMBER error received, but group $groupId is not found in database.',
|
||||
);
|
||||
return;
|
||||
}
|
||||
// Update group state from the server to ensure the user is still part of the group...
|
||||
final updatedState = await fetchGroupState(group);
|
||||
if (updatedState != null) {
|
||||
final (_, state) = updatedState;
|
||||
final isStillMember = state.memberIds.contains(Int64(fromUserId));
|
||||
if (isStillMember) {
|
||||
final keyPair = IdentityKeyPair.fromSerialized(
|
||||
group.myGroupPrivateKey!,
|
||||
);
|
||||
await sendCipherText(
|
||||
fromUserId,
|
||||
EncryptedContent(
|
||||
groupId: groupId,
|
||||
groupCreate: EncryptedContent_GroupCreate(
|
||||
stateKey: group.stateEncryptionKey,
|
||||
groupPublicKey: keyPair.getPublicKey().serialize(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
final r = await twonlyDB.receiptsDao.getReceiptById(
|
||||
error.relatedReceiptId,
|
||||
);
|
||||
if (r != null) {
|
||||
await twonlyDB.receiptsDao.updateReceiptWidthUserId(
|
||||
fromUserId,
|
||||
error.relatedReceiptId,
|
||||
ReceiptsCompanion(
|
||||
markForRetry: Value(clock.now()),
|
||||
retryCount: Value(r.retryCount + 1),
|
||||
),
|
||||
);
|
||||
}
|
||||
// then resend: error.relatedReceiptId
|
||||
await tryToSendCompleteMessage(
|
||||
receiptId: error.relatedReceiptId,
|
||||
blocking: false,
|
||||
);
|
||||
} else {}
|
||||
// ignore: no_default_cases
|
||||
default:
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,9 @@ Future<void> handleGroupCreate(
|
|||
EncryptedContent_GroupCreate newGroup,
|
||||
String receiptId,
|
||||
) async {
|
||||
final user = await twonlyDB.contactsDao.getContactByUserId(fromUserId).getSingleOrNull();
|
||||
final user = await twonlyDB.contactsDao
|
||||
.getContactByUserId(fromUserId)
|
||||
.getSingleOrNull();
|
||||
if (user == null) {
|
||||
// Only contacts can invite other contacts, so this can (via the UI) not happen.
|
||||
Log.error(
|
||||
|
|
@ -43,11 +45,26 @@ Future<void> handleGroupCreate(
|
|||
stateVersionId: const Value(0),
|
||||
stateEncryptionKey: Value(Uint8List.fromList(newGroup.stateKey)),
|
||||
myGroupPrivateKey: Value(myGroupKey.serialize()),
|
||||
groupName: const Value(''),
|
||||
groupName: Value(newGroup.hasGroupName() ? newGroup.groupName : ''),
|
||||
joinedGroup: const Value(false),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
// In this case make a group state update and check if the fromUserId is still a admin. otherwise return with an log error message
|
||||
final updatedState = await fetchGroupState(group);
|
||||
if (updatedState == null) {
|
||||
Log.error(
|
||||
'[$receiptId] Received group invite/create for $groupId, but failed to fetch group state from server.',
|
||||
);
|
||||
return;
|
||||
}
|
||||
final (_, state) = updatedState;
|
||||
if (!state.adminIds.any((id) => id.toInt() == fromUserId)) {
|
||||
Log.error(
|
||||
'[$receiptId] Received group invite/create for $groupId from $fromUserId, but they are not an admin of this group.',
|
||||
);
|
||||
return;
|
||||
}
|
||||
// User was already in the group, so update leftGroup back to false
|
||||
await twonlyDB.groupsDao.updateGroup(
|
||||
groupId,
|
||||
|
|
@ -55,7 +72,6 @@ Future<void> handleGroupCreate(
|
|||
stateVersionId: const Value(0),
|
||||
stateEncryptionKey: Value(Uint8List.fromList(newGroup.stateKey)),
|
||||
myGroupPrivateKey: Value(myGroupKey.serialize()),
|
||||
groupName: const Value(''),
|
||||
joinedGroup: const Value(false),
|
||||
leftGroup: const Value(false),
|
||||
deletedContent: const Value(false),
|
||||
|
|
@ -79,18 +95,8 @@ Future<void> handleGroupCreate(
|
|||
),
|
||||
);
|
||||
|
||||
await twonlyDB.groupsDao.insertOrUpdateGroupMember(
|
||||
GroupMembersCompanion(
|
||||
groupId: Value(groupId),
|
||||
contactId: Value(fromUserId),
|
||||
memberState: const Value(
|
||||
MemberState.admin, // is the group creator, so must be admin...
|
||||
),
|
||||
groupPublicKey: Value(Uint8List.fromList(newGroup.groupPublicKey)),
|
||||
),
|
||||
);
|
||||
|
||||
// can be done in the background -> websocket message can be ACK
|
||||
// Load group members from the server as this is the single source of truth.
|
||||
// This can be done in the background, so the WebSocket message can be ACKed.
|
||||
unawaited(fetchGroupStatesForUnjoinedGroups());
|
||||
|
||||
await sendCipherTextToGroup(
|
||||
|
|
@ -113,7 +119,9 @@ Future<void> handleGroupUpdate(
|
|||
|
||||
final actionType = groupActionTypeFromString(update.groupActionType);
|
||||
if (actionType == null) {
|
||||
Log.error('[$receiptId] Group action ${update.groupActionType} is unknown ignoring.');
|
||||
Log.error(
|
||||
'[$receiptId] Group action ${update.groupActionType} is unknown ignoring.',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -177,7 +177,17 @@ Future<(Uint8List, Uint8List?)?> _tryToSendCompleteMessageInternal({
|
|||
Uint8List.fromList(message.encryptedContent),
|
||||
);
|
||||
if (cipherText == null) {
|
||||
Log.error('Could not encrypt the message. Aborting and trying again.');
|
||||
Log.error(
|
||||
'[${receipt.receiptId}] Could not encrypt the message for user ${receipt.contactId}. Aborting and trying again.',
|
||||
);
|
||||
if (receipt.messageId != null) {
|
||||
await twonlyDB.messagesDao.handleMessageAckByServer(
|
||||
receipt.contactId,
|
||||
receipt.messageId!,
|
||||
clock.now(),
|
||||
);
|
||||
}
|
||||
await twonlyDB.receiptsDao.deleteReceipt(receipt.receiptId);
|
||||
return null;
|
||||
}
|
||||
message.encryptedContent = cipherText.serialize();
|
||||
|
|
@ -435,7 +445,7 @@ Future<(Uint8List, Uint8List?)?> sendCipherText(
|
|||
final openReceipts = await twonlyDB.receiptsDao.getReceiptCountForContact(
|
||||
contactId,
|
||||
);
|
||||
if (openReceipts > 6) {
|
||||
if (openReceipts > 10) {
|
||||
// this prevents that these types of messages are send in case the receiver is offline
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -211,6 +211,8 @@ Future<void> _handleClient2ClientMessage(
|
|||
type: Message_Type.CIPHERTEXT,
|
||||
encryptedContent: encryptedContent.writeToBuffer(),
|
||||
);
|
||||
// Use Value.absent() for CIPHERTEXT messages so that insertReceipt generates a new UUID.
|
||||
// This prevents receipt ID collisions and ensures the recipient's ACK is tracked correctly.
|
||||
receiptIdDB = const Value.absent();
|
||||
} else {
|
||||
// Message was successful processed
|
||||
|
|
@ -219,8 +221,9 @@ Future<void> _handleClient2ClientMessage(
|
|||
|
||||
response ??= Message(type: Message_Type.SENDER_DELIVERY_RECEIPT);
|
||||
|
||||
String? targetReceiptId;
|
||||
try {
|
||||
await twonlyDB.receiptsDao.insertReceipt(
|
||||
final inserted = await twonlyDB.receiptsDao.insertReceipt(
|
||||
ReceiptsCompanion(
|
||||
receiptId: receiptIdDB ?? Value(receiptId),
|
||||
contactId: Value(fromUserId),
|
||||
|
|
@ -228,10 +231,18 @@ Future<void> _handleClient2ClientMessage(
|
|||
contactWillSendsReceipt: const Value(false),
|
||||
),
|
||||
);
|
||||
// Use the inserted receipt's ID because for CIPHERTEXT messages we generate a new UUID
|
||||
// (receiptIdDB is Value.absent()) to avoid ID collisions and properly track individual ACKs.
|
||||
targetReceiptId = inserted?.receiptId;
|
||||
} catch (e) {
|
||||
Log.warn('[$receiptId] Error inserting receipt: $e');
|
||||
}
|
||||
await tryToSendCompleteMessage(receiptId: receiptId, blocking: false);
|
||||
if (targetReceiptId != null) {
|
||||
await tryToSendCompleteMessage(
|
||||
receiptId: targetReceiptId,
|
||||
blocking: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
case Message_Type.TEST_NOTIFICATION:
|
||||
break;
|
||||
|
|
@ -350,6 +361,7 @@ Future<(EncryptedContent?, PlaintextContent?)> handleEncryptedMessage(
|
|||
fromUserId,
|
||||
content.errorMessages,
|
||||
receiptId,
|
||||
groupId: content.hasGroupId() ? content.groupId : null,
|
||||
);
|
||||
return (null, null);
|
||||
}
|
||||
|
|
@ -430,6 +442,7 @@ Future<(EncryptedContent?, PlaintextContent?)> handleEncryptedMessage(
|
|||
|
||||
/// Verify that the user is (still) in that group...
|
||||
if (!await twonlyDB.groupsDao.isContactInGroup(fromUserId, content.groupId)) {
|
||||
// Check if this is a direct chat...
|
||||
if (getUUIDforDirectChat(userService.currentUser.userId, fromUserId) ==
|
||||
content.groupId) {
|
||||
final contact = await twonlyDB.contactsDao
|
||||
|
|
@ -477,9 +490,19 @@ Future<(EncryptedContent?, PlaintextContent?)> handleEncryptedMessage(
|
|||
}
|
||||
|
||||
Log.error(
|
||||
'[$receiptId] User $fromUserId tried to access group ${content.groupId}.',
|
||||
'[$receiptId] User $fromUserId tried to access group ${content.groupId}. Sending GROUP_NOT_FOUND_OR_NOT_A_MEMBER error.',
|
||||
);
|
||||
return (
|
||||
EncryptedContent(
|
||||
groupId: content.groupId,
|
||||
errorMessages: EncryptedContent_ErrorMessages(
|
||||
type: EncryptedContent_ErrorMessages_Type
|
||||
.GROUP_NOT_FOUND_OR_NOT_A_MEMBER,
|
||||
relatedReceiptId: receiptId,
|
||||
),
|
||||
),
|
||||
null,
|
||||
);
|
||||
return (null, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -139,6 +139,7 @@ Future<bool> createNewGroup(String groupName, List<Contact> members) async {
|
|||
groupCreate: EncryptedContent_GroupCreate(
|
||||
stateKey: stateEncryptionKey,
|
||||
groupPublicKey: myGroupKey.getPublicKey().serialize(),
|
||||
groupName: group.groupName,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
@ -770,6 +771,7 @@ Future<bool> addNewGroupMembers(
|
|||
groupCreate: EncryptedContent_GroupCreate(
|
||||
stateKey: group.stateEncryptionKey,
|
||||
groupPublicKey: keyPair.getPublicKey().serialize(),
|
||||
groupName: group.groupName,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ Future<CiphertextMessage?> _signalEncryptMessage(
|
|||
final session = SessionCipher.fromStore(signalStore, address);
|
||||
return await session.encrypt(plaintextContent);
|
||||
} catch (e) {
|
||||
Log.error(e.toString());
|
||||
Log.error('Could not encrypt message for target $target: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,12 +78,13 @@ class GroupContextMenu extends StatelessWidget {
|
|||
if (group.isDirectChat) {
|
||||
await twonlyDB.groupsDao.deleteGroup(group.groupId);
|
||||
} else {
|
||||
await twonlyDB.groupsDao.updateGroup(
|
||||
group.groupId,
|
||||
const GroupsCompanion(
|
||||
deletedContent: Value(true),
|
||||
),
|
||||
);
|
||||
await twonlyDB.groupsDao.deleteGroup(group.groupId);
|
||||
// await twonlyDB.groupsDao.updateGroup(
|
||||
// group.groupId,
|
||||
// const GroupsCompanion(
|
||||
// deletedContent: Value(true),
|
||||
// ),
|
||||
// );
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -141,13 +141,13 @@ class _ContactRowState extends State<_ContactRow> {
|
|||
),
|
||||
);
|
||||
|
||||
if (added > 0) await importSignalContactAndCreateRequest(userdata);
|
||||
|
||||
await KeyVerificationService.verifySharedContact(
|
||||
contactId: userdata.userId.toInt(),
|
||||
sharedPublicIdentityKey: widget.contact.publicIdentityKey,
|
||||
senderId: widget.message.senderId!,
|
||||
);
|
||||
|
||||
if (added > 0) await importSignalContactAndCreateRequest(userdata);
|
||||
} catch (e) {
|
||||
Log.error(e);
|
||||
} finally {
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ class _TypingIndicatorState extends State<TypingIndicator> {
|
|||
|
||||
StreamSubscription<List<(Contact, GroupMember)>>? membersSub;
|
||||
Timer? _periodicUpdate;
|
||||
bool _wasShownOnce = false;
|
||||
double _wasShownOnce = 0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
|
@ -81,19 +81,22 @@ class _TypingIndicatorState extends State<TypingIndicator> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (_groupMembers.isEmpty) {
|
||||
return SizedBox(height: _wasShownOnce ? 19 : 0);
|
||||
} else {
|
||||
_wasShownOnce = true;
|
||||
return SizedBox(height: _wasShownOnce);
|
||||
}
|
||||
|
||||
final height =
|
||||
(widget.group.isDirectChat ? 20 : 24) * _groupMembers.length.toDouble();
|
||||
_wasShownOnce = height;
|
||||
|
||||
return SizedBox(
|
||||
height: 19,
|
||||
height: height,
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 12),
|
||||
child: Row(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: _groupMembers
|
||||
.map(
|
||||
(member) => Padding(
|
||||
|
|
|
|||
66
pubspec.lock
66
pubspec.lock
|
|
@ -65,7 +65,7 @@ packages:
|
|||
source: hosted
|
||||
version: "1.0.4"
|
||||
archive:
|
||||
dependency: "direct main"
|
||||
dependency: transitive
|
||||
description:
|
||||
name: archive
|
||||
sha256: a96e8b390886ee8abb49b7bd3ac8df6f451c621619f52a26e815fdcf568959ff
|
||||
|
|
@ -389,18 +389,18 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: device_info_plus
|
||||
sha256: b4fed1b2835da9d670d7bed7db79ae2a94b0f5ad6312268158a9b5479abbacdd
|
||||
sha256: "6a642e1daa10190af89ba6cb6386c0df7d071a3592080bfe1e44faa63ae1df65"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "12.4.0"
|
||||
version: "13.1.0"
|
||||
device_info_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: device_info_plus_platform_interface
|
||||
sha256: e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f
|
||||
sha256: "04b173a92e2d9161dfead145667037c8d834db725ce2e7b942bfe18fd2f45a46"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.3"
|
||||
version: "8.1.0"
|
||||
dots_indicator:
|
||||
dependency: "direct overridden"
|
||||
description:
|
||||
|
|
@ -471,6 +471,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
ffi_leak_tracker:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: ffi_leak_tracker
|
||||
sha256: "4093d4ef9ca06ffe2786e73bfb25e22aa92112b9bb4ec941f11e3e6b61489a97"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.2"
|
||||
file:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -479,14 +487,6 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.1"
|
||||
file_picker:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: file_picker
|
||||
sha256: "57d9a1dd5063f85fa3107fb42d1faffda52fdc948cefd5fe5ea85267a5fc7343"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.3.10"
|
||||
file_selector_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -834,10 +834,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_windows
|
||||
sha256: "3b7c8e068875dfd46719ff57c90d8c459c87f2302ed6b00ff006b3c9fcad1613"
|
||||
sha256: "471951813a97006d899db4948acc654a4f28c440083ea08178935ce20b173ec1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.0"
|
||||
version: "4.2.2"
|
||||
flutter_sharing_intent:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
@ -892,14 +892,6 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
get:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: get
|
||||
sha256: "5ed34a7925b85336e15d472cc4cfe7d9ebf4ab8e8b9f688585bf6b50f4c3d79a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.7.3"
|
||||
get_it:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
@ -1037,10 +1029,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: image_picker
|
||||
sha256: "784210112be18ea55f69d7076e2c656a4e24949fa9e76429fe53af0c0f4fa320"
|
||||
sha256: "91c025426c2881c551100bce834e201c835a170151545f58d17da5180ca7d9ac"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
version: "1.2.2"
|
||||
image_picker_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -1381,18 +1373,18 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: package_info_plus
|
||||
sha256: "468c26b4254ab01979fa5e4a98cb343ea3631b9acee6f21028997419a80e1a20"
|
||||
sha256: "4bf625947f6c7713ee242296a682e23e44823c09cf9d79e4f1238923c92db852"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.0.1"
|
||||
version: "10.1.0"
|
||||
package_info_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: package_info_plus_platform_interface
|
||||
sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086"
|
||||
sha256: db762cb2f4f25ee60fb6359773861b0f199e00b90d237bd85a76a1e806b46ef4
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.1"
|
||||
version: "4.1.0"
|
||||
path:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
@ -1694,18 +1686,18 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: share_plus
|
||||
sha256: "223873d106614442ea6f20db5a038685cc5b32a2fba81cdecaefbbae0523f7fa"
|
||||
sha256: a857d8b1479250aff6b57a51b2c02d31ca05848d441817c43f1640c885c286c0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "12.0.2"
|
||||
version: "13.1.0"
|
||||
share_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: share_plus_platform_interface
|
||||
sha256: "88023e53a13429bd65d8e85e11a9b484f49d4c190abbd96c7932b74d6927cc9a"
|
||||
sha256: "7f7ae28cf400d13f811e297ff37742dba83b79e0a6f5dce14eec0248274e6ce9"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.0"
|
||||
version: "7.1.0"
|
||||
shared_preferences:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -2170,18 +2162,18 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: win32
|
||||
sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e
|
||||
sha256: ba6f4bba816c8d7e3c1580e170f3786d216951cc6b94babc3b814c08d2cb2738
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.15.0"
|
||||
version: "6.3.0"
|
||||
win32_registry:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: win32_registry
|
||||
sha256: "6f1b564492d0147b330dd794fee8f512cec4977957f310f9951b5f9d83618dae"
|
||||
sha256: "73b1d78920a9d6e03f8b4e43e612b87bf3152a0e5c5e5150267762b7c4116904"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
version: "3.0.3"
|
||||
workmanager:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
|
|||
17
pubspec.yaml
17
pubspec.yaml
|
|
@ -17,8 +17,8 @@ dependencies:
|
|||
# Trusted published dart.dev or tools.dart.dev
|
||||
collection: ^1.18.0
|
||||
fixnum: ^1.1.1
|
||||
meta: ^1.17.0
|
||||
http: ^1.3.0
|
||||
meta: ^1.17.0 # used by overwritten dependencies...
|
||||
http: ^1.6.0
|
||||
intl: ^0.20.2
|
||||
path: ^1.9.0
|
||||
logging: ^1.3.0
|
||||
|
|
@ -32,7 +32,7 @@ dependencies:
|
|||
# Trusted publisher flutter.dev
|
||||
camera: ^0.12.0+1
|
||||
flutter_svg: ^2.0.17
|
||||
image_picker: ^1.1.2
|
||||
image_picker: ^1.2.2
|
||||
local_auth: ^3.0.0
|
||||
path_provider: ^2.1.5
|
||||
url_launcher: ^6.3.2
|
||||
|
|
@ -44,10 +44,10 @@ dependencies:
|
|||
|
||||
# Trusted publisher fluttercommunity.dev
|
||||
connectivity_plus: ^7.0.0
|
||||
device_info_plus: ^12.1.0
|
||||
device_info_plus: ^13.1.0
|
||||
font_awesome_flutter: ^11.0.0
|
||||
share_plus: ^12.0.0
|
||||
package_info_plus: ^9.0.0
|
||||
share_plus: ^13.1.0
|
||||
package_info_plus: ^10.1.0
|
||||
workmanager: ^0.9.0+3
|
||||
|
||||
|
||||
|
|
@ -91,14 +91,11 @@ dependencies:
|
|||
# With high download. (But should be checked nonetheless.)
|
||||
app_links: ^7.0.0 # 1.6 mio
|
||||
image: ^4.3.0 # 3.3 mio
|
||||
archive: ^4.0.7 # 6.5 mio
|
||||
file_picker: ^10.3.6 # 2 mio
|
||||
get: ^4.7.2 # 740 k
|
||||
flutter_secure_storage: ^10.3.1 # 1.85 mio
|
||||
permission_handler: ^12.0.0+1 # 2 mio
|
||||
|
||||
# Not yet checked
|
||||
audio_waveforms: ^2.0.0
|
||||
audio_waveforms: ^2.0.2
|
||||
avatar_maker: ^0.4.0
|
||||
background_downloader: ^9.4.0
|
||||
cached_network_image: ^3.4.1
|
||||
|
|
|
|||
102
scripts/check_dependencies.py
Executable file
102
scripts/check_dependencies.py
Executable file
|
|
@ -0,0 +1,102 @@
|
|||
#!/usr/bin/env python3
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
def parse_dependencies(pubspec_path):
|
||||
deps = []
|
||||
in_deps = False
|
||||
|
||||
with open(pubspec_path, 'r', encoding='utf-8') as f:
|
||||
for line in f:
|
||||
stripped = line.strip()
|
||||
if not stripped or stripped.startswith('#'):
|
||||
continue
|
||||
|
||||
# Detect starting of dependencies or ending
|
||||
if line[0].isalpha() or line.startswith('dev_dependencies') or line.startswith('dependency_overrides'):
|
||||
if stripped.startswith('dependencies:'):
|
||||
in_deps = True
|
||||
else:
|
||||
in_deps = False
|
||||
continue
|
||||
|
||||
if in_deps:
|
||||
# Matches exactly 2 spaces indentation, followed by package name and colon
|
||||
match = re.match(r'^ ([a-zA-Z0-9_-]+):', line)
|
||||
if match:
|
||||
dep = match.group(1)
|
||||
# Ignore Flutter SDK built-ins and custom local rust bridge wrapper
|
||||
if dep not in ['flutter', 'flutter_localizations', 'rust_lib_twonly']:
|
||||
deps.append(dep)
|
||||
return deps
|
||||
|
||||
def find_used_packages(root_dir):
|
||||
used = set()
|
||||
# Matches: import 'package:package_name/...'; or export 'package:package_name/...';
|
||||
pattern = re.compile(r'(?:import|export)\s+[\'"]package:([a-zA-Z0-9_-]+)/')
|
||||
|
||||
for dirpath, _, filenames in os.walk(root_dir):
|
||||
# Skip hidden directories (.git, .dart_tool, etc.)
|
||||
if any(part.startswith('.') for part in dirpath.split(os.sep)):
|
||||
continue
|
||||
for filename in filenames:
|
||||
if filename.endswith('.dart'):
|
||||
filepath = os.path.join(dirpath, filename)
|
||||
try:
|
||||
with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
|
||||
for line in f:
|
||||
match = pattern.search(line)
|
||||
if match:
|
||||
used.add(match.group(1))
|
||||
except Exception:
|
||||
pass
|
||||
return used
|
||||
|
||||
def main():
|
||||
# Locate project root (assuming script is in scripts/ or root/)
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
project_root = os.path.abspath(os.path.join(script_dir, '..'))
|
||||
|
||||
pubspec_path = os.path.join(project_root, 'pubspec.yaml')
|
||||
if not os.path.exists(pubspec_path):
|
||||
print(f"Error: pubspec.yaml not found at {pubspec_path}")
|
||||
sys.exit(1)
|
||||
|
||||
print("Parsing dependencies from pubspec.yaml...")
|
||||
declared_deps = parse_dependencies(pubspec_path)
|
||||
print(f"Found {len(declared_deps)} runtime dependencies.")
|
||||
|
||||
print("\nScanning codebase for imports/exports in lib/, test/, integration_test/...")
|
||||
used_in_code = set()
|
||||
for folder in ['lib', 'test', 'integration_test']:
|
||||
folder_path = os.path.join(project_root, folder)
|
||||
if os.path.exists(folder_path):
|
||||
used_in_code.update(find_used_packages(folder_path))
|
||||
|
||||
unused_deps = []
|
||||
used_deps = []
|
||||
|
||||
for dep in declared_deps:
|
||||
if dep in used_in_code:
|
||||
used_deps.append(dep)
|
||||
else:
|
||||
unused_deps.append(dep)
|
||||
|
||||
print("\n" + "=" * 50)
|
||||
print(" RESULTS")
|
||||
print("=" * 50)
|
||||
|
||||
if unused_deps:
|
||||
print(f"\n❌ UNUSED DEPENDENCIES ({len(unused_deps)}):")
|
||||
for dep in sorted(unused_deps):
|
||||
print(f" - {dep}")
|
||||
else:
|
||||
print("\n✅ All dependencies listed in pubspec.yaml are used in the codebase!")
|
||||
|
||||
print(f"\n✨ USED DEPENDENCIES ({len(used_deps)}):")
|
||||
for dep in sorted(used_deps):
|
||||
print(f" - {dep}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Loading…
Reference in a new issue