From d5cf8e739f865f0f568872724aa370f162ad2922 Mon Sep 17 00:00:00 2001 From: 0x330a <92654767+0x330a@users.noreply.github.com> Date: Wed, 26 Oct 2022 12:12:11 +1100 Subject: [PATCH 001/269] feat: add new protobuf changes for closed group config messages --- libsignal/protobuf/SignalService.proto | 17 +- .../libsignal/protos/SignalServiceProtos.java | 357 +++++++++++++++--- 2 files changed, 319 insertions(+), 55 deletions(-) diff --git a/libsignal/protobuf/SignalService.proto b/libsignal/protobuf/SignalService.proto index e1c1c856d98..905b355d139 100644 --- a/libsignal/protobuf/SignalService.proto +++ b/libsignal/protobuf/SignalService.proto @@ -122,12 +122,17 @@ message DataMessage { message ClosedGroupControlMessage { enum Type { - NEW = 1; // publicKey, name, encryptionKeyPair, members, admins, expireTimer - ENCRYPTION_KEY_PAIR = 3; // publicKey, wrappers - NAME_CHANGE = 4; // name - MEMBERS_ADDED = 5; // members - MEMBERS_REMOVED = 6; // members + NEW = 1; // publicKey, name, encryptionKeyPair, members, admins, expireTimer + ENCRYPTION_KEY_PAIR = 3; // publicKey, wrappers + NAME_CHANGE = 4; // name + MEMBERS_ADDED = 5; // members + MEMBERS_REMOVED = 6; // members MEMBER_LEFT = 7; + INVITE = 9; // publicKey, name, memberPrivateKey + PROMOTE = 10; // publicKey, privateKey + DELETE_GROUP = 11; // publicKey, members + DELETE_MESSAGES = 12; // publicKey + DELETE_ATTACHMENTS = 13; // publicKey } message KeyPairWrapper { @@ -146,6 +151,8 @@ message DataMessage { repeated bytes admins = 6; repeated KeyPairWrapper wrappers = 7; optional uint32 expirationTimer = 8; + optional bytes memberPrivateKey = 9; + optional bytes privateKey = 10; } message Reaction { diff --git a/libsignal/src/main/java/org/session/libsignal/protos/SignalServiceProtos.java b/libsignal/src/main/java/org/session/libsignal/protos/SignalServiceProtos.java index ead1b6255ec..9121458aaac 100644 --- a/libsignal/src/main/java/org/session/libsignal/protos/SignalServiceProtos.java +++ b/libsignal/src/main/java/org/session/libsignal/protos/SignalServiceProtos.java @@ -10518,6 +10518,26 @@ org.session.libsignal.protos.SignalServiceProtos.DataMessage.ClosedGroupControlM * optional uint32 expirationTimer = 8; */ int getExpirationTimer(); + + // optional bytes memberPrivateKey = 9; + /** + * optional bytes memberPrivateKey = 9; + */ + boolean hasMemberPrivateKey(); + /** + * optional bytes memberPrivateKey = 9; + */ + com.google.protobuf.ByteString getMemberPrivateKey(); + + // optional bytes privateKey = 10; + /** + * optional bytes privateKey = 10; + */ + boolean hasPrivateKey(); + /** + * optional bytes privateKey = 10; + */ + com.google.protobuf.ByteString getPrivateKey(); } /** * Protobuf type {@code signalservice.DataMessage.ClosedGroupControlMessage} @@ -10633,6 +10653,16 @@ private ClosedGroupControlMessage( expirationTimer_ = input.readUInt32(); break; } + case 74: { + bitField0_ |= 0x00000020; + memberPrivateKey_ = input.readBytes(); + break; + } + case 82: { + bitField0_ |= 0x00000040; + privateKey_ = input.readBytes(); + break; + } } } } catch (com.google.protobuf.InvalidProtocolBufferException e) { @@ -10730,6 +10760,46 @@ public enum Type * MEMBER_LEFT = 7; */ MEMBER_LEFT(5, 7), + /** + * INVITE = 9; + * + *
+         * publicKey, name, memberPrivateKey
+         * 
+ */ + INVITE(6, 9), + /** + * PROMOTE = 10; + * + *
+         * publicKey, privateKey
+         * 
+ */ + PROMOTE(7, 10), + /** + * DELETE_GROUP = 11; + * + *
+         * publicKey, members
+         * 
+ */ + DELETE_GROUP(8, 11), + /** + * DELETE_MESSAGES = 12; + * + *
+         * publicKey
+         * 
+ */ + DELETE_MESSAGES(9, 12), + /** + * DELETE_ATTACHMENTS = 13; + * + *
+         * publicKey
+         * 
+ */ + DELETE_ATTACHMENTS(10, 13), ; /** @@ -10776,6 +10846,46 @@ public enum Type * MEMBER_LEFT = 7; */ public static final int MEMBER_LEFT_VALUE = 7; + /** + * INVITE = 9; + * + *
+         * publicKey, name, memberPrivateKey
+         * 
+ */ + public static final int INVITE_VALUE = 9; + /** + * PROMOTE = 10; + * + *
+         * publicKey, privateKey
+         * 
+ */ + public static final int PROMOTE_VALUE = 10; + /** + * DELETE_GROUP = 11; + * + *
+         * publicKey, members
+         * 
+ */ + public static final int DELETE_GROUP_VALUE = 11; + /** + * DELETE_MESSAGES = 12; + * + *
+         * publicKey
+         * 
+ */ + public static final int DELETE_MESSAGES_VALUE = 12; + /** + * DELETE_ATTACHMENTS = 13; + * + *
+         * publicKey
+         * 
+ */ + public static final int DELETE_ATTACHMENTS_VALUE = 13; public final int getNumber() { return value; } @@ -10788,6 +10898,11 @@ public static Type valueOf(int value) { case 5: return MEMBERS_ADDED; case 6: return MEMBERS_REMOVED; case 7: return MEMBER_LEFT; + case 9: return INVITE; + case 10: return PROMOTE; + case 11: return DELETE_GROUP; + case 12: return DELETE_MESSAGES; + case 13: return DELETE_ATTACHMENTS; default: return null; } } @@ -11606,6 +11721,38 @@ public int getExpirationTimer() { return expirationTimer_; } + // optional bytes memberPrivateKey = 9; + public static final int MEMBERPRIVATEKEY_FIELD_NUMBER = 9; + private com.google.protobuf.ByteString memberPrivateKey_; + /** + * optional bytes memberPrivateKey = 9; + */ + public boolean hasMemberPrivateKey() { + return ((bitField0_ & 0x00000020) == 0x00000020); + } + /** + * optional bytes memberPrivateKey = 9; + */ + public com.google.protobuf.ByteString getMemberPrivateKey() { + return memberPrivateKey_; + } + + // optional bytes privateKey = 10; + public static final int PRIVATEKEY_FIELD_NUMBER = 10; + private com.google.protobuf.ByteString privateKey_; + /** + * optional bytes privateKey = 10; + */ + public boolean hasPrivateKey() { + return ((bitField0_ & 0x00000040) == 0x00000040); + } + /** + * optional bytes privateKey = 10; + */ + public com.google.protobuf.ByteString getPrivateKey() { + return privateKey_; + } + private void initFields() { type_ = org.session.libsignal.protos.SignalServiceProtos.DataMessage.ClosedGroupControlMessage.Type.NEW; publicKey_ = com.google.protobuf.ByteString.EMPTY; @@ -11615,6 +11762,8 @@ private void initFields() { admins_ = java.util.Collections.emptyList(); wrappers_ = java.util.Collections.emptyList(); expirationTimer_ = 0; + memberPrivateKey_ = com.google.protobuf.ByteString.EMPTY; + privateKey_ = com.google.protobuf.ByteString.EMPTY; } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { @@ -11668,6 +11817,12 @@ public void writeTo(com.google.protobuf.CodedOutputStream output) if (((bitField0_ & 0x00000010) == 0x00000010)) { output.writeUInt32(8, expirationTimer_); } + if (((bitField0_ & 0x00000020) == 0x00000020)) { + output.writeBytes(9, memberPrivateKey_); + } + if (((bitField0_ & 0x00000040) == 0x00000040)) { + output.writeBytes(10, privateKey_); + } getUnknownFields().writeTo(output); } @@ -11719,6 +11874,14 @@ public int getSerializedSize() { size += com.google.protobuf.CodedOutputStream .computeUInt32Size(8, expirationTimer_); } + if (((bitField0_ & 0x00000020) == 0x00000020)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(9, memberPrivateKey_); + } + if (((bitField0_ & 0x00000040) == 0x00000040)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(10, privateKey_); + } size += getUnknownFields().getSerializedSize(); memoizedSerializedSize = size; return size; @@ -11861,6 +12024,10 @@ public Builder clear() { } expirationTimer_ = 0; bitField0_ = (bitField0_ & ~0x00000080); + memberPrivateKey_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000100); + privateKey_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000200); return this; } @@ -11932,6 +12099,14 @@ public org.session.libsignal.protos.SignalServiceProtos.DataMessage.ClosedGroupC to_bitField0_ |= 0x00000010; } result.expirationTimer_ = expirationTimer_; + if (((from_bitField0_ & 0x00000100) == 0x00000100)) { + to_bitField0_ |= 0x00000020; + } + result.memberPrivateKey_ = memberPrivateKey_; + if (((from_bitField0_ & 0x00000200) == 0x00000200)) { + to_bitField0_ |= 0x00000040; + } + result.privateKey_ = privateKey_; result.bitField0_ = to_bitField0_; onBuilt(); return result; @@ -12011,6 +12186,12 @@ public Builder mergeFrom(org.session.libsignal.protos.SignalServiceProtos.DataMe if (other.hasExpirationTimer()) { setExpirationTimer(other.getExpirationTimer()); } + if (other.hasMemberPrivateKey()) { + setMemberPrivateKey(other.getMemberPrivateKey()); + } + if (other.hasPrivateKey()) { + setPrivateKey(other.getPrivateKey()); + } this.mergeUnknownFields(other.getUnknownFields()); return this; } @@ -12750,6 +12931,78 @@ public Builder clearExpirationTimer() { return this; } + // optional bytes memberPrivateKey = 9; + private com.google.protobuf.ByteString memberPrivateKey_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes memberPrivateKey = 9; + */ + public boolean hasMemberPrivateKey() { + return ((bitField0_ & 0x00000100) == 0x00000100); + } + /** + * optional bytes memberPrivateKey = 9; + */ + public com.google.protobuf.ByteString getMemberPrivateKey() { + return memberPrivateKey_; + } + /** + * optional bytes memberPrivateKey = 9; + */ + public Builder setMemberPrivateKey(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000100; + memberPrivateKey_ = value; + onChanged(); + return this; + } + /** + * optional bytes memberPrivateKey = 9; + */ + public Builder clearMemberPrivateKey() { + bitField0_ = (bitField0_ & ~0x00000100); + memberPrivateKey_ = getDefaultInstance().getMemberPrivateKey(); + onChanged(); + return this; + } + + // optional bytes privateKey = 10; + private com.google.protobuf.ByteString privateKey_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes privateKey = 10; + */ + public boolean hasPrivateKey() { + return ((bitField0_ & 0x00000200) == 0x00000200); + } + /** + * optional bytes privateKey = 10; + */ + public com.google.protobuf.ByteString getPrivateKey() { + return privateKey_; + } + /** + * optional bytes privateKey = 10; + */ + public Builder setPrivateKey(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000200; + privateKey_ = value; + onChanged(); + return this; + } + /** + * optional bytes privateKey = 10; + */ + public Builder clearPrivateKey() { + bitField0_ = (bitField0_ & ~0x00000200); + privateKey_ = getDefaultInstance().getPrivateKey(); + onChanged(); + return this; + } + // @@protoc_insertion_point(builder_scope:signalservice.DataMessage.ClosedGroupControlMessage) } @@ -25856,7 +26109,7 @@ public Builder addAdminsBytes( "(\014\"\226\001\n\032DataExtractionNotification\022<\n\004typ" + "e\030\001 \002(\0162..signalservice.DataExtractionNo" + "tification.Type\022\021\n\ttimestamp\030\002 \001(\004\"\'\n\004Ty" + - "pe\022\016\n\nSCREENSHOT\020\001\022\017\n\013MEDIA_SAVED\020\002\"\361\r\n\013" + + "pe\022\016\n\nSCREENSHOT\020\001\022\017\n\013MEDIA_SAVED\020\002\"\370\016\n\013" + "DataMessage\022\014\n\004body\030\001 \001(\t\0225\n\013attachments" + "\030\002 \003(\0132 .signalservice.AttachmentPointer", "\022*\n\005group\030\003 \001(\0132\033.signalservice.GroupCon" + @@ -25883,7 +26136,7 @@ public Builder addAdminsBytes( "\n\005image\030\003 \001(\0132 .signalservice.Attachment" + "Pointer\032:\n\013LokiProfile\022\023\n\013displayName\030\001 " + "\001(\t\022\026\n\016profilePicture\030\002 \001(\t\0320\n\023OpenGroup" + - "Invitation\022\013\n\003url\030\001 \002(\t\022\014\n\004name\030\003 \002(\t\032\374\003" + + "Invitation\022\013\n\003url\030\001 \002(\t\022\014\n\004name\030\003 \002(\t\032\203\005" + "\n\031ClosedGroupControlMessage\022G\n\004type\030\001 \002(" + "\01629.signalservice.DataMessage.ClosedGrou" + "pControlMessage.Type\022\021\n\tpublicKey\030\002 \001(\014\022" + @@ -25892,53 +26145,57 @@ public Builder addAdminsBytes( "\014\022\016\n\006admins\030\006 \003(\014\022U\n\010wrappers\030\007 \003(\0132C.si" + "gnalservice.DataMessage.ClosedGroupContr" + "olMessage.KeyPairWrapper\022\027\n\017expirationTi" + - "mer\030\010 \001(\r\032=\n\016KeyPairWrapper\022\021\n\tpublicKey" + - "\030\001 \002(\014\022\030\n\020encryptedKeyPair\030\002 \002(\014\"r\n\004Type" + - "\022\007\n\003NEW\020\001\022\027\n\023ENCRYPTION_KEY_PAIR\020\003\022\017\n\013NA" + - "ME_CHANGE\020\004\022\021\n\rMEMBERS_ADDED\020\005\022\023\n\017MEMBER" + - "S_REMOVED\020\006\022\017\n\013MEMBER_LEFT\020\007\032\222\001\n\010Reactio" + - "n\022\n\n\002id\030\001 \002(\004\022\016\n\006author\030\002 \002(\t\022\r\n\005emoji\030\003" + - " \001(\t\022:\n\006action\030\004 \002(\0162*.signalservice.Dat", - "aMessage.Reaction.Action\"\037\n\006Action\022\t\n\005RE" + - "ACT\020\000\022\n\n\006REMOVE\020\001\"$\n\005Flags\022\033\n\027EXPIRATION" + - "_TIMER_UPDATE\020\002\"\352\001\n\013CallMessage\022-\n\004type\030" + - "\001 \002(\0162\037.signalservice.CallMessage.Type\022\014" + - "\n\004sdps\030\002 \003(\t\022\027\n\017sdpMLineIndexes\030\003 \003(\r\022\017\n" + - "\007sdpMids\030\004 \003(\t\022\014\n\004uuid\030\005 \002(\t\"f\n\004Type\022\r\n\t" + - "PRE_OFFER\020\006\022\t\n\005OFFER\020\001\022\n\n\006ANSWER\020\002\022\026\n\022PR" + - "OVISIONAL_ANSWER\020\003\022\022\n\016ICE_CANDIDATES\020\004\022\014" + - "\n\010END_CALL\020\005\"\245\004\n\024ConfigurationMessage\022E\n" + - "\014closedGroups\030\001 \003(\0132/.signalservice.Conf", - "igurationMessage.ClosedGroup\022\022\n\nopenGrou" + - "ps\030\002 \003(\t\022\023\n\013displayName\030\003 \001(\t\022\026\n\016profile" + - "Picture\030\004 \001(\t\022\022\n\nprofileKey\030\005 \001(\014\022=\n\010con" + - "tacts\030\006 \003(\0132+.signalservice.Configuratio" + - "nMessage.Contact\032\233\001\n\013ClosedGroup\022\021\n\tpubl" + - "icKey\030\001 \001(\014\022\014\n\004name\030\002 \001(\t\0221\n\021encryptionK" + - "eyPair\030\003 \001(\0132\026.signalservice.KeyPair\022\017\n\007" + - "members\030\004 \003(\014\022\016\n\006admins\030\005 \003(\014\022\027\n\017expirat" + - "ionTimer\030\006 \001(\r\032\223\001\n\007Contact\022\021\n\tpublicKey\030" + - "\001 \002(\014\022\014\n\004name\030\002 \002(\t\022\026\n\016profilePicture\030\003 ", - "\001(\t\022\022\n\nprofileKey\030\004 \001(\014\022\022\n\nisApproved\030\005 " + - "\001(\010\022\021\n\tisBlocked\030\006 \001(\010\022\024\n\014didApproveMe\030\007" + - " \001(\010\",\n\026MessageRequestResponse\022\022\n\nisAppr" + - "oved\030\001 \002(\010\"u\n\016ReceiptMessage\0220\n\004type\030\001 \002" + - "(\0162\".signalservice.ReceiptMessage.Type\022\021" + - "\n\ttimestamp\030\002 \003(\004\"\036\n\004Type\022\014\n\010DELIVERY\020\000\022" + - "\010\n\004READ\020\001\"\354\001\n\021AttachmentPointer\022\n\n\002id\030\001 " + - "\002(\006\022\023\n\013contentType\030\002 \001(\t\022\013\n\003key\030\003 \001(\014\022\014\n" + - "\004size\030\004 \001(\r\022\021\n\tthumbnail\030\005 \001(\014\022\016\n\006digest" + - "\030\006 \001(\014\022\020\n\010fileName\030\007 \001(\t\022\r\n\005flags\030\010 \001(\r\022", - "\r\n\005width\030\t \001(\r\022\016\n\006height\030\n \001(\r\022\017\n\007captio" + - "n\030\013 \001(\t\022\013\n\003url\030e \001(\t\"\032\n\005Flags\022\021\n\rVOICE_M" + - "ESSAGE\020\001\"\365\001\n\014GroupContext\022\n\n\002id\030\001 \001(\014\022.\n" + - "\004type\030\002 \001(\0162 .signalservice.GroupContext" + - ".Type\022\014\n\004name\030\003 \001(\t\022\017\n\007members\030\004 \003(\t\0220\n\006" + - "avatar\030\005 \001(\0132 .signalservice.AttachmentP" + - "ointer\022\016\n\006admins\030\006 \003(\t\"H\n\004Type\022\013\n\007UNKNOW" + - "N\020\000\022\n\n\006UPDATE\020\001\022\013\n\007DELIVER\020\002\022\010\n\004QUIT\020\003\022\020" + - "\n\014REQUEST_INFO\020\004B3\n\034org.session.libsigna" + - "l.protosB\023SignalServiceProtos" + "mer\030\010 \001(\r\022\030\n\020memberPrivateKey\030\t \001(\014\022\022\n\np" + + "rivateKey\030\n \001(\014\032=\n\016KeyPairWrapper\022\021\n\tpub" + + "licKey\030\001 \002(\014\022\030\n\020encryptedKeyPair\030\002 \002(\014\"\312" + + "\001\n\004Type\022\007\n\003NEW\020\001\022\027\n\023ENCRYPTION_KEY_PAIR\020" + + "\003\022\017\n\013NAME_CHANGE\020\004\022\021\n\rMEMBERS_ADDED\020\005\022\023\n" + + "\017MEMBERS_REMOVED\020\006\022\017\n\013MEMBER_LEFT\020\007\022\n\n\006I" + + "NVITE\020\t\022\013\n\007PROMOTE\020\n\022\020\n\014DELETE_GROUP\020\013\022\023", + "\n\017DELETE_MESSAGES\020\014\022\026\n\022DELETE_ATTACHMENT" + + "S\020\r\032\222\001\n\010Reaction\022\n\n\002id\030\001 \002(\004\022\016\n\006author\030\002" + + " \002(\t\022\r\n\005emoji\030\003 \001(\t\022:\n\006action\030\004 \002(\0162*.si" + + "gnalservice.DataMessage.Reaction.Action\"" + + "\037\n\006Action\022\t\n\005REACT\020\000\022\n\n\006REMOVE\020\001\"$\n\005Flag" + + "s\022\033\n\027EXPIRATION_TIMER_UPDATE\020\002\"\352\001\n\013CallM" + + "essage\022-\n\004type\030\001 \002(\0162\037.signalservice.Cal" + + "lMessage.Type\022\014\n\004sdps\030\002 \003(\t\022\027\n\017sdpMLineI" + + "ndexes\030\003 \003(\r\022\017\n\007sdpMids\030\004 \003(\t\022\014\n\004uuid\030\005 " + + "\002(\t\"f\n\004Type\022\r\n\tPRE_OFFER\020\006\022\t\n\005OFFER\020\001\022\n\n", + "\006ANSWER\020\002\022\026\n\022PROVISIONAL_ANSWER\020\003\022\022\n\016ICE" + + "_CANDIDATES\020\004\022\014\n\010END_CALL\020\005\"\245\004\n\024Configur" + + "ationMessage\022E\n\014closedGroups\030\001 \003(\0132/.sig" + + "nalservice.ConfigurationMessage.ClosedGr" + + "oup\022\022\n\nopenGroups\030\002 \003(\t\022\023\n\013displayName\030\003" + + " \001(\t\022\026\n\016profilePicture\030\004 \001(\t\022\022\n\nprofileK" + + "ey\030\005 \001(\014\022=\n\010contacts\030\006 \003(\0132+.signalservi" + + "ce.ConfigurationMessage.Contact\032\233\001\n\013Clos" + + "edGroup\022\021\n\tpublicKey\030\001 \001(\014\022\014\n\004name\030\002 \001(\t" + + "\0221\n\021encryptionKeyPair\030\003 \001(\0132\026.signalserv", + "ice.KeyPair\022\017\n\007members\030\004 \003(\014\022\016\n\006admins\030\005" + + " \003(\014\022\027\n\017expirationTimer\030\006 \001(\r\032\223\001\n\007Contac" + + "t\022\021\n\tpublicKey\030\001 \002(\014\022\014\n\004name\030\002 \002(\t\022\026\n\016pr" + + "ofilePicture\030\003 \001(\t\022\022\n\nprofileKey\030\004 \001(\014\022\022" + + "\n\nisApproved\030\005 \001(\010\022\021\n\tisBlocked\030\006 \001(\010\022\024\n" + + "\014didApproveMe\030\007 \001(\010\",\n\026MessageRequestRes" + + "ponse\022\022\n\nisApproved\030\001 \002(\010\"u\n\016ReceiptMess" + + "age\0220\n\004type\030\001 \002(\0162\".signalservice.Receip" + + "tMessage.Type\022\021\n\ttimestamp\030\002 \003(\004\"\036\n\004Type" + + "\022\014\n\010DELIVERY\020\000\022\010\n\004READ\020\001\"\354\001\n\021AttachmentP", + "ointer\022\n\n\002id\030\001 \002(\006\022\023\n\013contentType\030\002 \001(\t\022" + + "\013\n\003key\030\003 \001(\014\022\014\n\004size\030\004 \001(\r\022\021\n\tthumbnail\030" + + "\005 \001(\014\022\016\n\006digest\030\006 \001(\014\022\020\n\010fileName\030\007 \001(\t\022" + + "\r\n\005flags\030\010 \001(\r\022\r\n\005width\030\t \001(\r\022\016\n\006height\030" + + "\n \001(\r\022\017\n\007caption\030\013 \001(\t\022\013\n\003url\030e \001(\t\"\032\n\005F" + + "lags\022\021\n\rVOICE_MESSAGE\020\001\"\365\001\n\014GroupContext" + + "\022\n\n\002id\030\001 \001(\014\022.\n\004type\030\002 \001(\0162 .signalservi" + + "ce.GroupContext.Type\022\014\n\004name\030\003 \001(\t\022\017\n\007me" + + "mbers\030\004 \003(\t\0220\n\006avatar\030\005 \001(\0132 .signalserv" + + "ice.AttachmentPointer\022\016\n\006admins\030\006 \003(\t\"H\n", + "\004Type\022\013\n\007UNKNOWN\020\000\022\n\n\006UPDATE\020\001\022\013\n\007DELIVE" + + "R\020\002\022\010\n\004QUIT\020\003\022\020\n\014REQUEST_INFO\020\004B3\n\034org.s" + + "ession.libsignal.protosB\023SignalServicePr" + + "otos" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { @@ -26022,7 +26279,7 @@ public com.google.protobuf.ExtensionRegistry assignDescriptors( internal_static_signalservice_DataMessage_ClosedGroupControlMessage_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_signalservice_DataMessage_ClosedGroupControlMessage_descriptor, - new java.lang.String[] { "Type", "PublicKey", "Name", "EncryptionKeyPair", "Members", "Admins", "Wrappers", "ExpirationTimer", }); + new java.lang.String[] { "Type", "PublicKey", "Name", "EncryptionKeyPair", "Members", "Admins", "Wrappers", "ExpirationTimer", "MemberPrivateKey", "PrivateKey", }); internal_static_signalservice_DataMessage_ClosedGroupControlMessage_KeyPairWrapper_descriptor = internal_static_signalservice_DataMessage_ClosedGroupControlMessage_descriptor.getNestedTypes().get(0); internal_static_signalservice_DataMessage_ClosedGroupControlMessage_KeyPairWrapper_fieldAccessorTable = new From 220c76cfee437c44617ab2309ed7a740a085b692 Mon Sep 17 00:00:00 2001 From: 0x330a <92654767+0x330a@users.noreply.github.com> Date: Wed, 26 Oct 2022 14:49:46 +1100 Subject: [PATCH 002/269] fix: broken tests and unnecessary ConversationUiState value for hosted open group --- .../securesms/conversation/v2/ConversationViewModel.kt | 1 - .../conversation/v2/ConversationViewModelTest.kt | 7 ------- .../securesms/util/OpenGroupMigrationTests.kt | 2 ++ .../messages/control/ClosedGroupControlMessage.kt | 9 +++++++-- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModel.kt index 4d78653abcf..8db66e0801b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModel.kt @@ -182,7 +182,6 @@ class ConversationViewModel( data class UiMessage(val id: Long, val message: String) data class ConversationUiState( - val isOxenHostedOpenGroup: Boolean = false, val uiMessages: List = emptyList(), val isMessageRequestAccepted: Boolean? = null ) diff --git a/app/src/test/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModelTest.kt b/app/src/test/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModelTest.kt index fa02721558c..0ac7d29df2f 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModelTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/conversation/v2/ConversationViewModelTest.kt @@ -5,7 +5,6 @@ import kotlinx.coroutines.flow.first import org.hamcrest.CoreMatchers.endsWith import org.hamcrest.CoreMatchers.equalTo import org.hamcrest.MatcherAssert.assertThat -import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.mockito.Mockito.anyLong @@ -37,15 +36,9 @@ class ConversationViewModelTest: BaseViewModelTest() { @Before fun setUp() { recipient = mock(Recipient::class.java) - whenever(repository.isOxenHostedOpenGroup(anyLong())).thenReturn(true) whenever(repository.maybeGetRecipientForThreadId(anyLong())).thenReturn(recipient) } - @Test - fun `should emit group type on init`() = runBlockingTest { - assertTrue(viewModel.uiState.first().isOxenHostedOpenGroup) - } - @Test fun `should save draft message`() { val draft = "Hi there" diff --git a/app/src/test/java/org/thoughtcrime/securesms/util/OpenGroupMigrationTests.kt b/app/src/test/java/org/thoughtcrime/securesms/util/OpenGroupMigrationTests.kt index dcf8ca231b8..b58992701c3 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/util/OpenGroupMigrationTests.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/util/OpenGroupMigrationTests.kt @@ -117,6 +117,7 @@ class OpenGroupMigrationTests { fun `test migration thread DB calls legacy and returns if no legacy official groups`() { val mockedThreadDb = mock { on { legacyOxenOpenGroups } doReturn emptyList() + on { httpOxenOpenGroups } doReturn emptyList() } val mockedDbComponent = mock { on { threadDatabase() } doReturn mockedThreadDb @@ -126,6 +127,7 @@ class OpenGroupMigrationTests { verify(mockedDbComponent).threadDatabase() verify(mockedThreadDb).legacyOxenOpenGroups + verify(mockedThreadDb).httpOxenOpenGroups verifyNoMoreInteractions(mockedThreadDb) } diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupControlMessage.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupControlMessage.kt index c7aa03a7b29..2782b8408f1 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupControlMessage.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupControlMessage.kt @@ -6,10 +6,10 @@ import org.session.libsignal.crypto.ecc.DjbECPublicKey import org.session.libsignal.crypto.ecc.ECKeyPair import org.session.libsignal.protos.SignalServiceProtos import org.session.libsignal.protos.SignalServiceProtos.DataMessage -import org.session.libsignal.utilities.removingIdPrefixIfNeeded -import org.session.libsignal.utilities.toHexString import org.session.libsignal.utilities.Hex import org.session.libsignal.utilities.Log +import org.session.libsignal.utilities.removingIdPrefixIfNeeded +import org.session.libsignal.utilities.toHexString class ClosedGroupControlMessage() : ControlMessage() { var kind: Kind? = null @@ -113,6 +113,11 @@ class ClosedGroupControlMessage() : ControlMessage() { DataMessage.ClosedGroupControlMessage.Type.MEMBER_LEFT -> { kind = Kind.MemberLeft() } + DataMessage.ClosedGroupControlMessage.Type.INVITE -> TODO() + DataMessage.ClosedGroupControlMessage.Type.PROMOTE -> TODO() + DataMessage.ClosedGroupControlMessage.Type.DELETE_GROUP -> TODO() + DataMessage.ClosedGroupControlMessage.Type.DELETE_MESSAGES -> TODO() + DataMessage.ClosedGroupControlMessage.Type.DELETE_ATTACHMENTS -> TODO() } return ClosedGroupControlMessage(kind) } From 129f92ec69c79f3bb970964fa40b5bf0d866d3ab Mon Sep 17 00:00:00 2001 From: 0x330a <92654767+0x330a@users.noreply.github.com> Date: Wed, 26 Oct 2022 16:55:52 +1100 Subject: [PATCH 003/269] refactor: add new shared config message, generate protos and start ID prefix for group types --- libsignal/protobuf/SignalService.proto | 13 + .../libsignal/protos/SignalServiceProtos.java | 728 +++++++++++++++++- .../session/libsignal/utilities/IdPrefix.kt | 3 +- 3 files changed, 705 insertions(+), 39 deletions(-) diff --git a/libsignal/protobuf/SignalService.proto b/libsignal/protobuf/SignalService.proto index 905b355d139..1257dd43778 100644 --- a/libsignal/protobuf/SignalService.proto +++ b/libsignal/protobuf/SignalService.proto @@ -207,6 +207,19 @@ message CallMessage { required string uuid = 5; } +message SharedConfigMessage { + enum Type { + USER = 1; + CLOSED_GROUP_INFO = 2; + ENCRYPTION_KEYS = 3; + CONVERSATION_READ_STATE = 4; + } + + // @required + required Type type = 1; + required bytes data = 2; +} + message ConfigurationMessage { message ClosedGroup { diff --git a/libsignal/src/main/java/org/session/libsignal/protos/SignalServiceProtos.java b/libsignal/src/main/java/org/session/libsignal/protos/SignalServiceProtos.java index 9121458aaac..11fb98778b7 100644 --- a/libsignal/src/main/java/org/session/libsignal/protos/SignalServiceProtos.java +++ b/libsignal/src/main/java/org/session/libsignal/protos/SignalServiceProtos.java @@ -17819,6 +17819,643 @@ public Builder setUuidBytes( // @@protoc_insertion_point(class_scope:signalservice.CallMessage) } + public interface SharedConfigMessageOrBuilder + extends com.google.protobuf.MessageOrBuilder { + + // required .signalservice.SharedConfigMessage.Type type = 1; + /** + * required .signalservice.SharedConfigMessage.Type type = 1; + * + *
+     * @required
+     * 
+ */ + boolean hasType(); + /** + * required .signalservice.SharedConfigMessage.Type type = 1; + * + *
+     * @required
+     * 
+ */ + org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage.Type getType(); + + // required bytes data = 2; + /** + * required bytes data = 2; + */ + boolean hasData(); + /** + * required bytes data = 2; + */ + com.google.protobuf.ByteString getData(); + } + /** + * Protobuf type {@code signalservice.SharedConfigMessage} + */ + public static final class SharedConfigMessage extends + com.google.protobuf.GeneratedMessage + implements SharedConfigMessageOrBuilder { + // Use SharedConfigMessage.newBuilder() to construct. + private SharedConfigMessage(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private SharedConfigMessage(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } + + private static final SharedConfigMessage defaultInstance; + public static SharedConfigMessage getDefaultInstance() { + return defaultInstance; + } + + public SharedConfigMessage getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.UnknownFieldSet unknownFields; + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private SharedConfigMessage( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + int rawValue = input.readEnum(); + org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage.Type value = org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage.Type.valueOf(rawValue); + if (value == null) { + unknownFields.mergeVarintField(1, rawValue); + } else { + bitField0_ |= 0x00000001; + type_ = value; + } + break; + } + case 18: { + bitField0_ |= 0x00000002; + data_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.session.libsignal.protos.SignalServiceProtos.internal_static_signalservice_SharedConfigMessage_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.session.libsignal.protos.SignalServiceProtos.internal_static_signalservice_SharedConfigMessage_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage.class, org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage.Builder.class); + } + + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public SharedConfigMessage parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new SharedConfigMessage(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + /** + * Protobuf enum {@code signalservice.SharedConfigMessage.Type} + */ + public enum Type + implements com.google.protobuf.ProtocolMessageEnum { + /** + * USER = 1; + */ + USER(0, 1), + /** + * CLOSED_GROUP_INFO = 2; + */ + CLOSED_GROUP_INFO(1, 2), + /** + * ENCRYPTION_KEYS = 3; + */ + ENCRYPTION_KEYS(2, 3), + /** + * CONVERSATION_READ_STATE = 4; + */ + CONVERSATION_READ_STATE(3, 4), + ; + + /** + * USER = 1; + */ + public static final int USER_VALUE = 1; + /** + * CLOSED_GROUP_INFO = 2; + */ + public static final int CLOSED_GROUP_INFO_VALUE = 2; + /** + * ENCRYPTION_KEYS = 3; + */ + public static final int ENCRYPTION_KEYS_VALUE = 3; + /** + * CONVERSATION_READ_STATE = 4; + */ + public static final int CONVERSATION_READ_STATE_VALUE = 4; + + + public final int getNumber() { return value; } + + public static Type valueOf(int value) { + switch (value) { + case 1: return USER; + case 2: return CLOSED_GROUP_INFO; + case 3: return ENCRYPTION_KEYS; + case 4: return CONVERSATION_READ_STATE; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public Type findValueByNumber(int number) { + return Type.valueOf(number); + } + }; + + public final com.google.protobuf.Descriptors.EnumValueDescriptor + getValueDescriptor() { + return getDescriptor().getValues().get(index); + } + public final com.google.protobuf.Descriptors.EnumDescriptor + getDescriptorForType() { + return getDescriptor(); + } + public static final com.google.protobuf.Descriptors.EnumDescriptor + getDescriptor() { + return org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage.getDescriptor().getEnumTypes().get(0); + } + + private static final Type[] VALUES = values(); + + public static Type valueOf( + com.google.protobuf.Descriptors.EnumValueDescriptor desc) { + if (desc.getType() != getDescriptor()) { + throw new java.lang.IllegalArgumentException( + "EnumValueDescriptor is not for this type."); + } + return VALUES[desc.getIndex()]; + } + + private final int index; + private final int value; + + private Type(int index, int value) { + this.index = index; + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:signalservice.SharedConfigMessage.Type) + } + + private int bitField0_; + // required .signalservice.SharedConfigMessage.Type type = 1; + public static final int TYPE_FIELD_NUMBER = 1; + private org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage.Type type_; + /** + * required .signalservice.SharedConfigMessage.Type type = 1; + * + *
+     * @required
+     * 
+ */ + public boolean hasType() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required .signalservice.SharedConfigMessage.Type type = 1; + * + *
+     * @required
+     * 
+ */ + public org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage.Type getType() { + return type_; + } + + // required bytes data = 2; + public static final int DATA_FIELD_NUMBER = 2; + private com.google.protobuf.ByteString data_; + /** + * required bytes data = 2; + */ + public boolean hasData() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required bytes data = 2; + */ + public com.google.protobuf.ByteString getData() { + return data_; + } + + private void initFields() { + type_ = org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage.Type.USER; + data_ = com.google.protobuf.ByteString.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized != -1) return isInitialized == 1; + + if (!hasType()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasData()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeEnum(1, type_.getNumber()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(2, data_); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(1, type_.getNumber()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(2, data_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code signalservice.SharedConfigMessage} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder + implements org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessageOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.session.libsignal.protos.SignalServiceProtos.internal_static_signalservice_SharedConfigMessage_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.session.libsignal.protos.SignalServiceProtos.internal_static_signalservice_SharedConfigMessage_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage.class, org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage.Builder.class); + } + + // Construct using org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + } + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + type_ = org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage.Type.USER; + bitField0_ = (bitField0_ & ~0x00000001); + data_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.session.libsignal.protos.SignalServiceProtos.internal_static_signalservice_SharedConfigMessage_descriptor; + } + + public org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage getDefaultInstanceForType() { + return org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage.getDefaultInstance(); + } + + public org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage build() { + org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage buildPartial() { + org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage result = new org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.type_ = type_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.data_ = data_; + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage) { + return mergeFrom((org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage other) { + if (other == org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage.getDefaultInstance()) return this; + if (other.hasType()) { + setType(other.getType()); + } + if (other.hasData()) { + setData(other.getData()); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public final boolean isInitialized() { + if (!hasType()) { + + return false; + } + if (!hasData()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + // required .signalservice.SharedConfigMessage.Type type = 1; + private org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage.Type type_ = org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage.Type.USER; + /** + * required .signalservice.SharedConfigMessage.Type type = 1; + * + *
+       * @required
+       * 
+ */ + public boolean hasType() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required .signalservice.SharedConfigMessage.Type type = 1; + * + *
+       * @required
+       * 
+ */ + public org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage.Type getType() { + return type_; + } + /** + * required .signalservice.SharedConfigMessage.Type type = 1; + * + *
+       * @required
+       * 
+ */ + public Builder setType(org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage.Type value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + type_ = value; + onChanged(); + return this; + } + /** + * required .signalservice.SharedConfigMessage.Type type = 1; + * + *
+       * @required
+       * 
+ */ + public Builder clearType() { + bitField0_ = (bitField0_ & ~0x00000001); + type_ = org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage.Type.USER; + onChanged(); + return this; + } + + // required bytes data = 2; + private com.google.protobuf.ByteString data_ = com.google.protobuf.ByteString.EMPTY; + /** + * required bytes data = 2; + */ + public boolean hasData() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required bytes data = 2; + */ + public com.google.protobuf.ByteString getData() { + return data_; + } + /** + * required bytes data = 2; + */ + public Builder setData(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + data_ = value; + onChanged(); + return this; + } + /** + * required bytes data = 2; + */ + public Builder clearData() { + bitField0_ = (bitField0_ & ~0x00000002); + data_ = getDefaultInstance().getData(); + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:signalservice.SharedConfigMessage) + } + + static { + defaultInstance = new SharedConfigMessage(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:signalservice.SharedConfigMessage) + } + public interface ConfigurationMessageOrBuilder extends com.google.protobuf.MessageOrBuilder { @@ -26038,6 +26675,11 @@ public Builder addAdminsBytes( private static com.google.protobuf.GeneratedMessage.FieldAccessorTable internal_static_signalservice_CallMessage_fieldAccessorTable; + private static com.google.protobuf.Descriptors.Descriptor + internal_static_signalservice_SharedConfigMessage_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_signalservice_SharedConfigMessage_fieldAccessorTable; private static com.google.protobuf.Descriptors.Descriptor internal_static_signalservice_ConfigurationMessage_descriptor; private static @@ -26163,39 +26805,43 @@ public Builder addAdminsBytes( "ndexes\030\003 \003(\r\022\017\n\007sdpMids\030\004 \003(\t\022\014\n\004uuid\030\005 " + "\002(\t\"f\n\004Type\022\r\n\tPRE_OFFER\020\006\022\t\n\005OFFER\020\001\022\n\n", "\006ANSWER\020\002\022\026\n\022PROVISIONAL_ANSWER\020\003\022\022\n\016ICE" + - "_CANDIDATES\020\004\022\014\n\010END_CALL\020\005\"\245\004\n\024Configur" + - "ationMessage\022E\n\014closedGroups\030\001 \003(\0132/.sig" + - "nalservice.ConfigurationMessage.ClosedGr" + - "oup\022\022\n\nopenGroups\030\002 \003(\t\022\023\n\013displayName\030\003" + - " \001(\t\022\026\n\016profilePicture\030\004 \001(\t\022\022\n\nprofileK" + - "ey\030\005 \001(\014\022=\n\010contacts\030\006 \003(\0132+.signalservi" + - "ce.ConfigurationMessage.Contact\032\233\001\n\013Clos" + - "edGroup\022\021\n\tpublicKey\030\001 \001(\014\022\014\n\004name\030\002 \001(\t" + - "\0221\n\021encryptionKeyPair\030\003 \001(\0132\026.signalserv", - "ice.KeyPair\022\017\n\007members\030\004 \003(\014\022\016\n\006admins\030\005" + - " \003(\014\022\027\n\017expirationTimer\030\006 \001(\r\032\223\001\n\007Contac" + - "t\022\021\n\tpublicKey\030\001 \002(\014\022\014\n\004name\030\002 \002(\t\022\026\n\016pr" + - "ofilePicture\030\003 \001(\t\022\022\n\nprofileKey\030\004 \001(\014\022\022" + - "\n\nisApproved\030\005 \001(\010\022\021\n\tisBlocked\030\006 \001(\010\022\024\n" + - "\014didApproveMe\030\007 \001(\010\",\n\026MessageRequestRes" + - "ponse\022\022\n\nisApproved\030\001 \002(\010\"u\n\016ReceiptMess" + - "age\0220\n\004type\030\001 \002(\0162\".signalservice.Receip" + - "tMessage.Type\022\021\n\ttimestamp\030\002 \003(\004\"\036\n\004Type" + - "\022\014\n\010DELIVERY\020\000\022\010\n\004READ\020\001\"\354\001\n\021AttachmentP", - "ointer\022\n\n\002id\030\001 \002(\006\022\023\n\013contentType\030\002 \001(\t\022" + - "\013\n\003key\030\003 \001(\014\022\014\n\004size\030\004 \001(\r\022\021\n\tthumbnail\030" + - "\005 \001(\014\022\016\n\006digest\030\006 \001(\014\022\020\n\010fileName\030\007 \001(\t\022" + - "\r\n\005flags\030\010 \001(\r\022\r\n\005width\030\t \001(\r\022\016\n\006height\030" + - "\n \001(\r\022\017\n\007caption\030\013 \001(\t\022\013\n\003url\030e \001(\t\"\032\n\005F" + - "lags\022\021\n\rVOICE_MESSAGE\020\001\"\365\001\n\014GroupContext" + - "\022\n\n\002id\030\001 \001(\014\022.\n\004type\030\002 \001(\0162 .signalservi" + - "ce.GroupContext.Type\022\014\n\004name\030\003 \001(\t\022\017\n\007me" + - "mbers\030\004 \003(\t\0220\n\006avatar\030\005 \001(\0132 .signalserv" + - "ice.AttachmentPointer\022\016\n\006admins\030\006 \003(\t\"H\n", - "\004Type\022\013\n\007UNKNOWN\020\000\022\n\n\006UPDATE\020\001\022\013\n\007DELIVE" + - "R\020\002\022\010\n\004QUIT\020\003\022\020\n\014REQUEST_INFO\020\004B3\n\034org.s" + - "ession.libsignal.protosB\023SignalServicePr" + - "otos" + "_CANDIDATES\020\004\022\014\n\010END_CALL\020\005\"\265\001\n\023SharedCo" + + "nfigMessage\0225\n\004type\030\001 \002(\0162\'.signalservic" + + "e.SharedConfigMessage.Type\022\014\n\004data\030\002 \002(\014" + + "\"Y\n\004Type\022\010\n\004USER\020\001\022\025\n\021CLOSED_GROUP_INFO\020" + + "\002\022\023\n\017ENCRYPTION_KEYS\020\003\022\033\n\027CONVERSATION_R" + + "EAD_STATE\020\004\"\245\004\n\024ConfigurationMessage\022E\n\014" + + "closedGroups\030\001 \003(\0132/.signalservice.Confi" + + "gurationMessage.ClosedGroup\022\022\n\nopenGroup" + + "s\030\002 \003(\t\022\023\n\013displayName\030\003 \001(\t\022\026\n\016profileP", + "icture\030\004 \001(\t\022\022\n\nprofileKey\030\005 \001(\014\022=\n\010cont" + + "acts\030\006 \003(\0132+.signalservice.Configuration" + + "Message.Contact\032\233\001\n\013ClosedGroup\022\021\n\tpubli" + + "cKey\030\001 \001(\014\022\014\n\004name\030\002 \001(\t\0221\n\021encryptionKe" + + "yPair\030\003 \001(\0132\026.signalservice.KeyPair\022\017\n\007m" + + "embers\030\004 \003(\014\022\016\n\006admins\030\005 \003(\014\022\027\n\017expirati" + + "onTimer\030\006 \001(\r\032\223\001\n\007Contact\022\021\n\tpublicKey\030\001" + + " \002(\014\022\014\n\004name\030\002 \002(\t\022\026\n\016profilePicture\030\003 \001" + + "(\t\022\022\n\nprofileKey\030\004 \001(\014\022\022\n\nisApproved\030\005 \001" + + "(\010\022\021\n\tisBlocked\030\006 \001(\010\022\024\n\014didApproveMe\030\007 ", + "\001(\010\",\n\026MessageRequestResponse\022\022\n\nisAppro" + + "ved\030\001 \002(\010\"u\n\016ReceiptMessage\0220\n\004type\030\001 \002(" + + "\0162\".signalservice.ReceiptMessage.Type\022\021\n" + + "\ttimestamp\030\002 \003(\004\"\036\n\004Type\022\014\n\010DELIVERY\020\000\022\010" + + "\n\004READ\020\001\"\354\001\n\021AttachmentPointer\022\n\n\002id\030\001 \002" + + "(\006\022\023\n\013contentType\030\002 \001(\t\022\013\n\003key\030\003 \001(\014\022\014\n\004" + + "size\030\004 \001(\r\022\021\n\tthumbnail\030\005 \001(\014\022\016\n\006digest\030" + + "\006 \001(\014\022\020\n\010fileName\030\007 \001(\t\022\r\n\005flags\030\010 \001(\r\022\r" + + "\n\005width\030\t \001(\r\022\016\n\006height\030\n \001(\r\022\017\n\007caption" + + "\030\013 \001(\t\022\013\n\003url\030e \001(\t\"\032\n\005Flags\022\021\n\rVOICE_ME", + "SSAGE\020\001\"\365\001\n\014GroupContext\022\n\n\002id\030\001 \001(\014\022.\n\004" + + "type\030\002 \001(\0162 .signalservice.GroupContext." + + "Type\022\014\n\004name\030\003 \001(\t\022\017\n\007members\030\004 \003(\t\0220\n\006a" + + "vatar\030\005 \001(\0132 .signalservice.AttachmentPo" + + "inter\022\016\n\006admins\030\006 \003(\t\"H\n\004Type\022\013\n\007UNKNOWN" + + "\020\000\022\n\n\006UPDATE\020\001\022\013\n\007DELIVER\020\002\022\010\n\004QUIT\020\003\022\020\n" + + "\014REQUEST_INFO\020\004B3\n\034org.session.libsignal" + + ".protosB\023SignalServiceProtos" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { @@ -26298,8 +26944,14 @@ public com.google.protobuf.ExtensionRegistry assignDescriptors( com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_signalservice_CallMessage_descriptor, new java.lang.String[] { "Type", "Sdps", "SdpMLineIndexes", "SdpMids", "Uuid", }); - internal_static_signalservice_ConfigurationMessage_descriptor = + internal_static_signalservice_SharedConfigMessage_descriptor = getDescriptor().getMessageTypes().get(8); + internal_static_signalservice_SharedConfigMessage_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_signalservice_SharedConfigMessage_descriptor, + new java.lang.String[] { "Type", "Data", }); + internal_static_signalservice_ConfigurationMessage_descriptor = + getDescriptor().getMessageTypes().get(9); internal_static_signalservice_ConfigurationMessage_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_signalservice_ConfigurationMessage_descriptor, @@ -26317,25 +26969,25 @@ public com.google.protobuf.ExtensionRegistry assignDescriptors( internal_static_signalservice_ConfigurationMessage_Contact_descriptor, new java.lang.String[] { "PublicKey", "Name", "ProfilePicture", "ProfileKey", "IsApproved", "IsBlocked", "DidApproveMe", }); internal_static_signalservice_MessageRequestResponse_descriptor = - getDescriptor().getMessageTypes().get(9); + getDescriptor().getMessageTypes().get(10); internal_static_signalservice_MessageRequestResponse_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_signalservice_MessageRequestResponse_descriptor, new java.lang.String[] { "IsApproved", }); internal_static_signalservice_ReceiptMessage_descriptor = - getDescriptor().getMessageTypes().get(10); + getDescriptor().getMessageTypes().get(11); internal_static_signalservice_ReceiptMessage_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_signalservice_ReceiptMessage_descriptor, new java.lang.String[] { "Type", "Timestamp", }); internal_static_signalservice_AttachmentPointer_descriptor = - getDescriptor().getMessageTypes().get(11); + getDescriptor().getMessageTypes().get(12); internal_static_signalservice_AttachmentPointer_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_signalservice_AttachmentPointer_descriptor, new java.lang.String[] { "Id", "ContentType", "Key", "Size", "Thumbnail", "Digest", "FileName", "Flags", "Width", "Height", "Caption", "Url", }); internal_static_signalservice_GroupContext_descriptor = - getDescriptor().getMessageTypes().get(12); + getDescriptor().getMessageTypes().get(13); internal_static_signalservice_GroupContext_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_signalservice_GroupContext_descriptor, diff --git a/libsignal/src/main/java/org/session/libsignal/utilities/IdPrefix.kt b/libsignal/src/main/java/org/session/libsignal/utilities/IdPrefix.kt index 154b91ee208..bfae48d7769 100644 --- a/libsignal/src/main/java/org/session/libsignal/utilities/IdPrefix.kt +++ b/libsignal/src/main/java/org/session/libsignal/utilities/IdPrefix.kt @@ -1,13 +1,14 @@ package org.session.libsignal.utilities enum class IdPrefix(val value: String) { - STANDARD("05"), BLINDED("15"), UN_BLINDED("00"); + STANDARD("05"), BLINDED("15"), UN_BLINDED("00"), GROUP("03"); companion object { fun fromValue(rawValue: String): IdPrefix? = when(rawValue.take(2)) { STANDARD.value -> STANDARD BLINDED.value -> BLINDED UN_BLINDED.value -> UN_BLINDED + GROUP.value -> GROUP else -> null } } From 3078d18ebd890b85623cfd6d4a7508aa6306f2c6 Mon Sep 17 00:00:00 2001 From: 0x330a <92654767+0x330a@users.noreply.github.com> Date: Fri, 28 Oct 2022 11:57:47 +1100 Subject: [PATCH 004/269] feat: add encoding and decoding utilities --- .../libsession/utilities/bencode/Bencoder.kt | 136 ++++++++++++++++++ .../libsession/utilities/BencoderTest.kt | 108 ++++++++++++++ 2 files changed, 244 insertions(+) create mode 100644 libsession/src/main/java/org/session/libsession/utilities/bencode/Bencoder.kt create mode 100644 libsession/src/test/java/org/session/libsession/utilities/BencoderTest.kt diff --git a/libsession/src/main/java/org/session/libsession/utilities/bencode/Bencoder.kt b/libsession/src/main/java/org/session/libsession/utilities/bencode/Bencoder.kt new file mode 100644 index 00000000000..2674e5194c6 --- /dev/null +++ b/libsession/src/main/java/org/session/libsession/utilities/bencode/Bencoder.kt @@ -0,0 +1,136 @@ +package org.session.libsession.utilities.bencode + +import java.util.LinkedList + +object Bencoder { + class Decoder(source: CharArray) { + + private val iterator = LinkedList().apply { + addAll(source.asIterable()) + } + + /** + * Decode an element based on next marker assumed to be string/int/list/dict or return null + */ + fun decode(): BencodeElement? { + val result = when (iterator.peek()) { + in NUMBERS -> decodeString() + INT_INDICATOR -> decodeInt() + LIST_INDICATOR -> decodeList() + DICT_INDICATOR -> decodeDict() + else -> { + null + } + } + return result + } + + /** + * Decode a string element from iterator assumed to have structure `{length}:{data}` + */ + private fun decodeString(): BencodeString? { + val lengthStrings = buildString { + while (iterator.isNotEmpty() && iterator.peek() != SEPARATOR) { + append(iterator.pop()) + } + }.toCharArray() + iterator.pop() // drop `:` + val length = String(lengthStrings).toIntOrNull(10) ?: return null + val remaining = (0 until length).map { iterator.pop() }.toCharArray() + return BencodeString(String(remaining)) + } + + /** + * Decode an int element from iterator assumed to have structure `i{int}e` + */ + private fun decodeInt(): BencodeElement? { + iterator.pop() // drop `i` + val intString = buildString { + while (iterator.isNotEmpty() && iterator.peek() != END_INDICATOR) { + append(iterator.pop()) + } + } + val asInt = intString.toIntOrNull(10) ?: return null + iterator.pop() // drop `e` + return BencodeInteger(asInt) + } + + /** + * Decode a list element from iterator assumed to have structure `l{data}e` + */ + private fun decodeList(): BencodeElement { + iterator.pop() // drop `l` + val listElements = mutableListOf() + while (iterator.isNotEmpty() && iterator.peek() != END_INDICATOR) { + decode()?.let { nextElement -> + listElements += nextElement + } + } + iterator.pop() // drop `e` + return BencodeList(listElements) + } + + /** + * Decode a dict element from iterator assumed to have structure `d{data}e` + */ + private fun decodeDict(): BencodeElement? { + iterator.pop() // drop `d` + val dictElements = mutableMapOf() + while (iterator.isNotEmpty() && iterator.peek() != END_INDICATOR) { + val key = decodeString() ?: return null + val value = decode() ?: return null + dictElements += key.value to value + } + iterator.pop() // drop `e` + return BencodeDict(dictElements) + } + + companion object { + private val NUMBERS = arrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9') + private const val INT_INDICATOR = 'i' + private const val LIST_INDICATOR = 'l' + private const val DICT_INDICATOR = 'd' + private const val END_INDICATOR = 'e' + private const val SEPARATOR = ':' + } + + } + +} + +sealed class BencodeElement { + abstract fun encode(): CharArray +} +data class BencodeString(val value: String): BencodeElement() { + override fun encode(): CharArray = buildString { + append(value.length.toString()) + append(':') + append(value) + }.toCharArray() +} +data class BencodeInteger(val value: Int): BencodeElement() { + override fun encode(): CharArray = buildString { + append('i') + append(value) + append('e') + }.toCharArray() +} +data class BencodeList(val values: List): BencodeElement() { + override fun encode(): CharArray = buildString { + append('l') + for (value in values) { + append(value.encode()) + } + append('e') + }.toCharArray() +} +data class BencodeDict(val values: Map): BencodeElement() { + override fun encode(): CharArray = buildString { + append('d') + for ((key, value) in values) { + append(BencodeString(key).encode()) + append(value.encode()) + } + append('e') + }.toCharArray() +} \ No newline at end of file diff --git a/libsession/src/test/java/org/session/libsession/utilities/BencoderTest.kt b/libsession/src/test/java/org/session/libsession/utilities/BencoderTest.kt new file mode 100644 index 00000000000..127d708f8b3 --- /dev/null +++ b/libsession/src/test/java/org/session/libsession/utilities/BencoderTest.kt @@ -0,0 +1,108 @@ +package org.session.libsession.utilities + +import org.junit.Assert.assertArrayEquals +import org.junit.Assert.assertEquals +import org.junit.Test +import org.session.libsession.utilities.bencode.BencodeDict +import org.session.libsession.utilities.bencode.BencodeInteger +import org.session.libsession.utilities.bencode.BencodeList +import org.session.libsession.utilities.bencode.BencodeString +import org.session.libsession.utilities.bencode.Bencoder + +class BencoderTest { + + @Test + fun `it should decode a basic string`() { + val basicString = "5:howdy".toCharArray() + val bencoder = Bencoder.Decoder(basicString) + val result = bencoder.decode() + assertEquals(BencodeString("howdy"), result) + } + + @Test + fun `it should decode a basic integer`() { + val basicInteger = "i3e".toCharArray() + val bencoder = Bencoder.Decoder(basicInteger) + val result = bencoder.decode() + assertEquals(BencodeInteger(3), result) + } + + @Test + fun `it should decode a list of integers`() { + val basicIntList = "li1ei2ee".toCharArray() + val bencoder = Bencoder.Decoder(basicIntList) + val result = bencoder.decode() + assertEquals( + BencodeList( + listOf( + BencodeInteger(1), + BencodeInteger(2) + ) + ), + result + ) + } + + @Test + fun `it should decode a basic dict`() { + val basicDict = "d4:spaml1:a1:bee".toCharArray() + val bencoder = Bencoder.Decoder(basicDict) + val result = bencoder.decode() + assertEquals( + BencodeDict( + mapOf( + "spam" to BencodeList( + listOf( + BencodeString("a"), + BencodeString("b") + ) + ) + ) + ), + result + ) + } + + @Test + fun `it should encode a basic string`() { + val basicString = "5:howdy".toCharArray() + val element = BencodeString("howdy") + assertArrayEquals(basicString, element.encode()) + } + + @Test + fun `it should encode a basic int`() { + val basicInt = "i3e".toCharArray() + val element = BencodeInteger(3) + assertArrayEquals(basicInt, element.encode()) + } + + @Test + fun `it should encode a basic list`() { + val basicList = "li1ei2ee".toCharArray() + val element = BencodeList( + listOf( + BencodeInteger(1), + BencodeInteger(2) + ) + ) + assertArrayEquals(basicList, element.encode()) + } + + @Test + fun `it should encode a basic dict`() { + val basicDict = "d4:spaml1:a1:bee".toCharArray() + val element = BencodeDict( + mapOf( + "spam" to BencodeList( + listOf( + BencodeString("a"), + BencodeString("b") + ) + ) + ) + ) + assertArrayEquals(basicDict, element.encode()) + } + +} \ No newline at end of file From 35902e5047628c24a06de70d10be9c1d4a1d1541 Mon Sep 17 00:00:00 2001 From: 0x330a <92654767+0x330a@users.noreply.github.com> Date: Fri, 28 Oct 2022 15:17:18 +1100 Subject: [PATCH 005/269] feat: add convenient constructors for dict and list types, add int and string extension bencode functions --- .../bencode/{Bencoder.kt => Bencode.kt} | 12 +++- .../libsession/utilities/BencoderTest.kt | 65 +++++++++---------- 2 files changed, 43 insertions(+), 34 deletions(-) rename libsession/src/main/java/org/session/libsession/utilities/bencode/{Bencoder.kt => Bencode.kt} (94%) diff --git a/libsession/src/main/java/org/session/libsession/utilities/bencode/Bencoder.kt b/libsession/src/main/java/org/session/libsession/utilities/bencode/Bencode.kt similarity index 94% rename from libsession/src/main/java/org/session/libsession/utilities/bencode/Bencoder.kt rename to libsession/src/main/java/org/session/libsession/utilities/bencode/Bencode.kt index 2674e5194c6..53b535d1d85 100644 --- a/libsession/src/main/java/org/session/libsession/utilities/bencode/Bencoder.kt +++ b/libsession/src/main/java/org/session/libsession/utilities/bencode/Bencode.kt @@ -2,7 +2,7 @@ package org.session.libsession.utilities.bencode import java.util.LinkedList -object Bencoder { +object Bencode { class Decoder(source: CharArray) { private val iterator = LinkedList().apply { @@ -101,6 +101,10 @@ object Bencoder { sealed class BencodeElement { abstract fun encode(): CharArray } + +fun String.bencode() = BencodeString(this) +fun Int.bencode() = BencodeInteger(this) + data class BencodeString(val value: String): BencodeElement() { override fun encode(): CharArray = buildString { append(value.length.toString()) @@ -116,6 +120,9 @@ data class BencodeInteger(val value: Int): BencodeElement() { }.toCharArray() } data class BencodeList(val values: List): BencodeElement() { + + constructor(vararg values: BencodeElement) : this(values.toList()) + override fun encode(): CharArray = buildString { append('l') for (value in values) { @@ -125,6 +132,9 @@ data class BencodeList(val values: List): BencodeElement() { }.toCharArray() } data class BencodeDict(val values: Map): BencodeElement() { + + constructor(vararg values: Pair) : this(values.toMap()) + override fun encode(): CharArray = buildString { append('d') for ((key, value) in values) { diff --git a/libsession/src/test/java/org/session/libsession/utilities/BencoderTest.kt b/libsession/src/test/java/org/session/libsession/utilities/BencoderTest.kt index 127d708f8b3..2286424a867 100644 --- a/libsession/src/test/java/org/session/libsession/utilities/BencoderTest.kt +++ b/libsession/src/test/java/org/session/libsession/utilities/BencoderTest.kt @@ -3,26 +3,26 @@ package org.session.libsession.utilities import org.junit.Assert.assertArrayEquals import org.junit.Assert.assertEquals import org.junit.Test +import org.session.libsession.utilities.bencode.Bencode import org.session.libsession.utilities.bencode.BencodeDict import org.session.libsession.utilities.bencode.BencodeInteger import org.session.libsession.utilities.bencode.BencodeList -import org.session.libsession.utilities.bencode.BencodeString -import org.session.libsession.utilities.bencode.Bencoder +import org.session.libsession.utilities.bencode.bencode class BencoderTest { @Test fun `it should decode a basic string`() { val basicString = "5:howdy".toCharArray() - val bencoder = Bencoder.Decoder(basicString) + val bencoder = Bencode.Decoder(basicString) val result = bencoder.decode() - assertEquals(BencodeString("howdy"), result) + assertEquals("howdy".bencode(), result) } @Test fun `it should decode a basic integer`() { val basicInteger = "i3e".toCharArray() - val bencoder = Bencoder.Decoder(basicInteger) + val bencoder = Bencode.Decoder(basicInteger) val result = bencoder.decode() assertEquals(BencodeInteger(3), result) } @@ -30,14 +30,12 @@ class BencoderTest { @Test fun `it should decode a list of integers`() { val basicIntList = "li1ei2ee".toCharArray() - val bencoder = Bencoder.Decoder(basicIntList) + val bencoder = Bencode.Decoder(basicIntList) val result = bencoder.decode() assertEquals( BencodeList( - listOf( - BencodeInteger(1), - BencodeInteger(2) - ) + 1.bencode(), + 2.bencode() ), result ) @@ -46,17 +44,13 @@ class BencoderTest { @Test fun `it should decode a basic dict`() { val basicDict = "d4:spaml1:a1:bee".toCharArray() - val bencoder = Bencoder.Decoder(basicDict) + val bencoder = Bencode.Decoder(basicDict) val result = bencoder.decode() assertEquals( BencodeDict( - mapOf( - "spam" to BencodeList( - listOf( - BencodeString("a"), - BencodeString("b") - ) - ) + "spam" to BencodeList( + "a".bencode(), + "b".bencode() ) ), result @@ -66,26 +60,21 @@ class BencoderTest { @Test fun `it should encode a basic string`() { val basicString = "5:howdy".toCharArray() - val element = BencodeString("howdy") + val element = "howdy".bencode() assertArrayEquals(basicString, element.encode()) } @Test fun `it should encode a basic int`() { val basicInt = "i3e".toCharArray() - val element = BencodeInteger(3) + val element = 3.bencode() assertArrayEquals(basicInt, element.encode()) } @Test fun `it should encode a basic list`() { val basicList = "li1ei2ee".toCharArray() - val element = BencodeList( - listOf( - BencodeInteger(1), - BencodeInteger(2) - ) - ) + val element = BencodeList(1.bencode(),2.bencode()) assertArrayEquals(basicList, element.encode()) } @@ -93,16 +82,26 @@ class BencoderTest { fun `it should encode a basic dict`() { val basicDict = "d4:spaml1:a1:bee".toCharArray() val element = BencodeDict( - mapOf( - "spam" to BencodeList( - listOf( - BencodeString("a"), - BencodeString("b") - ) - ) + "spam" to BencodeList( + "a".bencode(), + "b".bencode() ) ) assertArrayEquals(basicDict, element.encode()) } + @Test + fun `it should encode a more complex real world case`() { + val source = "d15:lastReadMessaged66:031122334455667788990011223344556677889900112233445566778899001122i1234568790e66:051122334455667788990011223344556677889900112233445566778899001122i1234568790ee5:seqNoi1ee".toCharArray() + val result = Bencode.Decoder(source).decode() + val expected = BencodeDict( + "lastReadMessage" to BencodeDict( + "051122334455667788990011223344556677889900112233445566778899001122" to 1234568790.bencode(), + "031122334455667788990011223344556677889900112233445566778899001122" to 1234568790.bencode() + ), + "seqNo" to BencodeInteger(1) + ) + assertEquals(expected, result) + } + } \ No newline at end of file From 00ed94a930b25344dead239e6f7dcf66d299358c Mon Sep 17 00:00:00 2001 From: 0x330a <92654767+0x330a@users.noreply.github.com> Date: Fri, 28 Oct 2022 16:55:29 +1100 Subject: [PATCH 006/269] feat: add conversation settings activity --- .../settings/ConversationSettingsActivity.kt | 32 +++++++++ .../settings/ConversationSettingsViewModel.kt | 9 +++ .../layout/activity_conversation_settings.xml | 21 ++++++ .../libsession/utilities/bencode/Bencode.kt | 71 ++++++++++--------- .../libsession/utilities/BencoderTest.kt | 18 ++--- 5 files changed, 109 insertions(+), 42 deletions(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsActivity.kt create mode 100644 app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsViewModel.kt create mode 100644 app/src/main/res/layout/activity_conversation_settings.xml diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsActivity.kt new file mode 100644 index 00000000000..13ee040148b --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsActivity.kt @@ -0,0 +1,32 @@ +package org.thoughtcrime.securesms.conversation.settings + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import androidx.activity.viewModels +import dagger.hilt.android.AndroidEntryPoint +import network.loki.messenger.databinding.ActivityConversationSettingsBinding +import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity +import org.thoughtcrime.securesms.conversation.v2.utilities.BaseDialog +import org.thoughtcrime.securesms.util.ActivityDispatcher + +@AndroidEntryPoint +class ConversationSettingsActivity: PassphraseRequiredActionBarActivity(), ActivityDispatcher { + + lateinit var binding: ActivityConversationSettingsBinding + val viewModel: ConversationSettingsViewModel by viewModels() + + override fun dispatchIntent(body: (Context) -> Intent?) { + TODO() + } + + override fun showDialog(baseDialog: BaseDialog, tag: String?) { + TODO() + } + + + override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) { + super.onCreate(savedInstanceState, ready) + binding = ActivityConversationSettingsBinding.inflate(layoutInflater) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsViewModel.kt new file mode 100644 index 00000000000..71d8b5352a5 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/settings/ConversationSettingsViewModel.kt @@ -0,0 +1,9 @@ +package org.thoughtcrime.securesms.conversation.settings + +import androidx.lifecycle.ViewModel + +class ConversationSettingsViewModel: ViewModel() { + + + +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_conversation_settings.xml b/app/src/main/res/layout/activity_conversation_settings.xml new file mode 100644 index 00000000000..8c01e5be5ba --- /dev/null +++ b/app/src/main/res/layout/activity_conversation_settings.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/utilities/bencode/Bencode.kt b/libsession/src/main/java/org/session/libsession/utilities/bencode/Bencode.kt index 53b535d1d85..9d08b2873d2 100644 --- a/libsession/src/main/java/org/session/libsession/utilities/bencode/Bencode.kt +++ b/libsession/src/main/java/org/session/libsession/utilities/bencode/Bencode.kt @@ -1,11 +1,14 @@ package org.session.libsession.utilities.bencode +import org.session.libsession.utilities.bencode.Bencode.Decoder.Companion.DICT_INDICATOR +import org.session.libsession.utilities.bencode.Bencode.Decoder.Companion.END_INDICATOR +import org.session.libsession.utilities.bencode.Bencode.Decoder.Companion.LIST_INDICATOR import java.util.LinkedList object Bencode { - class Decoder(source: CharArray) { + class Decoder(source: ByteArray) { - private val iterator = LinkedList().apply { + private val iterator = LinkedList().apply { addAll(source.asIterable()) } @@ -29,14 +32,14 @@ object Bencode { * Decode a string element from iterator assumed to have structure `{length}:{data}` */ private fun decodeString(): BencodeString? { - val lengthStrings = buildString { + val lengthStrings = buildList { while (iterator.isNotEmpty() && iterator.peek() != SEPARATOR) { - append(iterator.pop()) + add(iterator.pop()) } - }.toCharArray() + }.toByteArray() iterator.pop() // drop `:` - val length = String(lengthStrings).toIntOrNull(10) ?: return null - val remaining = (0 until length).map { iterator.pop() }.toCharArray() + val length = lengthStrings.decodeToString().toIntOrNull(10) ?: return null + val remaining = (0 until length).map { iterator.pop() }.toByteArray() return BencodeString(String(remaining)) } @@ -45,12 +48,12 @@ object Bencode { */ private fun decodeInt(): BencodeElement? { iterator.pop() // drop `i` - val intString = buildString { + val intString = buildList { while (iterator.isNotEmpty() && iterator.peek() != END_INDICATOR) { - append(iterator.pop()) + add(iterator.pop()) } - } - val asInt = intString.toIntOrNull(10) ?: return null + }.toByteArray() + val asInt = intString.decodeToString().toIntOrNull(10) ?: return null iterator.pop() // drop `e` return BencodeInteger(asInt) } @@ -86,12 +89,12 @@ object Bencode { } companion object { - private val NUMBERS = arrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9') - private const val INT_INDICATOR = 'i' - private const val LIST_INDICATOR = 'l' - private const val DICT_INDICATOR = 'd' - private const val END_INDICATOR = 'e' - private const val SEPARATOR = ':' + val NUMBERS = arrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9').map { it.code.toByte() } + const val INT_INDICATOR = 'i'.code.toByte() + const val LIST_INDICATOR = 'l'.code.toByte() + const val DICT_INDICATOR = 'd'.code.toByte() + const val END_INDICATOR = 'e'.code.toByte() + const val SEPARATOR = ':'.code.toByte() } } @@ -99,48 +102,50 @@ object Bencode { } sealed class BencodeElement { - abstract fun encode(): CharArray + abstract fun encode(): ByteArray } fun String.bencode() = BencodeString(this) fun Int.bencode() = BencodeInteger(this) data class BencodeString(val value: String): BencodeElement() { - override fun encode(): CharArray = buildString { + override fun encode(): ByteArray = buildString { append(value.length.toString()) append(':') append(value) - }.toCharArray() + }.toByteArray() } data class BencodeInteger(val value: Int): BencodeElement() { - override fun encode(): CharArray = buildString { + override fun encode(): ByteArray = buildString { append('i') append(value) append('e') - }.toCharArray() + }.toByteArray() } + data class BencodeList(val values: List): BencodeElement() { constructor(vararg values: BencodeElement) : this(values.toList()) - override fun encode(): CharArray = buildString { - append('l') + override fun encode(): ByteArray = buildList { + add(LIST_INDICATOR) for (value in values) { - append(value.encode()) + addAll(value.encode().toTypedArray()) } - append('e') - }.toCharArray() + add(END_INDICATOR) + }.toByteArray() } + data class BencodeDict(val values: Map): BencodeElement() { constructor(vararg values: Pair) : this(values.toMap()) - override fun encode(): CharArray = buildString { - append('d') + override fun encode(): ByteArray = buildList { + add(DICT_INDICATOR) for ((key, value) in values) { - append(BencodeString(key).encode()) - append(value.encode()) + addAll(BencodeString(key).encode().toTypedArray()) + addAll(value.encode().toTypedArray()) } - append('e') - }.toCharArray() + add(END_INDICATOR) + }.toByteArray() } \ No newline at end of file diff --git a/libsession/src/test/java/org/session/libsession/utilities/BencoderTest.kt b/libsession/src/test/java/org/session/libsession/utilities/BencoderTest.kt index 2286424a867..d96fa6658fe 100644 --- a/libsession/src/test/java/org/session/libsession/utilities/BencoderTest.kt +++ b/libsession/src/test/java/org/session/libsession/utilities/BencoderTest.kt @@ -13,7 +13,7 @@ class BencoderTest { @Test fun `it should decode a basic string`() { - val basicString = "5:howdy".toCharArray() + val basicString = "5:howdy".toByteArray() val bencoder = Bencode.Decoder(basicString) val result = bencoder.decode() assertEquals("howdy".bencode(), result) @@ -21,7 +21,7 @@ class BencoderTest { @Test fun `it should decode a basic integer`() { - val basicInteger = "i3e".toCharArray() + val basicInteger = "i3e".toByteArray() val bencoder = Bencode.Decoder(basicInteger) val result = bencoder.decode() assertEquals(BencodeInteger(3), result) @@ -29,7 +29,7 @@ class BencoderTest { @Test fun `it should decode a list of integers`() { - val basicIntList = "li1ei2ee".toCharArray() + val basicIntList = "li1ei2ee".toByteArray() val bencoder = Bencode.Decoder(basicIntList) val result = bencoder.decode() assertEquals( @@ -43,7 +43,7 @@ class BencoderTest { @Test fun `it should decode a basic dict`() { - val basicDict = "d4:spaml1:a1:bee".toCharArray() + val basicDict = "d4:spaml1:a1:bee".toByteArray() val bencoder = Bencode.Decoder(basicDict) val result = bencoder.decode() assertEquals( @@ -59,28 +59,28 @@ class BencoderTest { @Test fun `it should encode a basic string`() { - val basicString = "5:howdy".toCharArray() + val basicString = "5:howdy".toByteArray() val element = "howdy".bencode() assertArrayEquals(basicString, element.encode()) } @Test fun `it should encode a basic int`() { - val basicInt = "i3e".toCharArray() + val basicInt = "i3e".toByteArray() val element = 3.bencode() assertArrayEquals(basicInt, element.encode()) } @Test fun `it should encode a basic list`() { - val basicList = "li1ei2ee".toCharArray() + val basicList = "li1ei2ee".toByteArray() val element = BencodeList(1.bencode(),2.bencode()) assertArrayEquals(basicList, element.encode()) } @Test fun `it should encode a basic dict`() { - val basicDict = "d4:spaml1:a1:bee".toCharArray() + val basicDict = "d4:spaml1:a1:bee".toByteArray() val element = BencodeDict( "spam" to BencodeList( "a".bencode(), @@ -92,7 +92,7 @@ class BencoderTest { @Test fun `it should encode a more complex real world case`() { - val source = "d15:lastReadMessaged66:031122334455667788990011223344556677889900112233445566778899001122i1234568790e66:051122334455667788990011223344556677889900112233445566778899001122i1234568790ee5:seqNoi1ee".toCharArray() + val source = "d15:lastReadMessaged66:031122334455667788990011223344556677889900112233445566778899001122i1234568790e66:051122334455667788990011223344556677889900112233445566778899001122i1234568790ee5:seqNoi1ee".toByteArray() val result = Bencode.Decoder(source).decode() val expected = BencodeDict( "lastReadMessage" to BencodeDict( From f5801a57dedc00ac7fab8788c1d7ae69363c3328 Mon Sep 17 00:00:00 2001 From: 0x330a <92654767+0x330a@users.noreply.github.com> Date: Mon, 31 Oct 2022 17:21:36 +1100 Subject: [PATCH 007/269] feat: add layouts for the conversation settings activity and some basic view groups to control admin views and group specific views --- app/src/main/AndroidManifest.xml | 3 + .../settings/ConversationSettingsActivity.kt | 5 + .../conversation/v2/ConversationActivityV2.kt | 16 +- app/src/main/res/drawable/debug_border.xml | 4 + app/src/main/res/drawable/ic_add_admins.xml | 16 + app/src/main/res/drawable/ic_all_media.xml | 13 + .../main/res/drawable/ic_clear_messages.xml | 20 + app/src/main/res/drawable/ic_delete.xml | 16 + .../res/drawable/ic_disappearing_messages.xml | 16 + app/src/main/res/drawable/ic_edit_group.xml | 22 ++ app/src/main/res/drawable/ic_leave_group.xml | 13 + .../res/drawable/ic_notification_settings.xml | 9 + .../main/res/drawable/ic_pin_conversation.xml | 13 + .../res/drawable/ic_search_conversation.xml | 9 + .../profile_picture_view_large_background.xml | 5 +- .../layout/activity_conversation_settings.xml | 341 +++++++++++++++++- .../res/layout/view_large_profile_picture.xml | 45 +++ .../main/res/menu/menu_message_request.xml | 2 +- app/src/main/res/values/dimens.xml | 1 + app/src/main/res/values/strings.xml | 12 + app/src/main/res/values/styles.xml | 48 +++ 21 files changed, 618 insertions(+), 11 deletions(-) create mode 100644 app/src/main/res/drawable/debug_border.xml create mode 100644 app/src/main/res/drawable/ic_add_admins.xml create mode 100644 app/src/main/res/drawable/ic_all_media.xml create mode 100644 app/src/main/res/drawable/ic_clear_messages.xml create mode 100644 app/src/main/res/drawable/ic_delete.xml create mode 100644 app/src/main/res/drawable/ic_disappearing_messages.xml create mode 100644 app/src/main/res/drawable/ic_edit_group.xml create mode 100644 app/src/main/res/drawable/ic_leave_group.xml create mode 100644 app/src/main/res/drawable/ic_notification_settings.xml create mode 100644 app/src/main/res/drawable/ic_pin_conversation.xml create mode 100644 app/src/main/res/drawable/ic_search_conversation.xml create mode 100644 app/src/main/res/layout/view_large_profile_picture.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 681fc00c17a..00a45ba4353 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -225,6 +225,9 @@ android:name="android.support.PARENT_ACTIVITY" android:value="org.thoughtcrime.securesms.home.HomeActivity" /> + , OnReactionSelectedListener, ReactWithAnyEmojiDialogFragment.Callback, ReactionsDialogFragment.Callback, - ConversationMenuHelper.ConversationMenuListener { + ConversationMenuHelper.ConversationMenuListener, View.OnClickListener { private var binding: ActivityConversationV2Binding? = null @@ -474,9 +475,8 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe binding!!.toolbarContent.profilePictureView.root.glide = glide MentionManagerUtilities.populateUserPublicKeyCacheIfNeeded(viewModel.threadId, this) val profilePictureView = binding!!.toolbarContent.profilePictureView.root - viewModel.recipient?.let { recipient -> - profilePictureView.update(recipient) - } + profilePictureView.update(recipient) + profilePictureView.setOnClickListener(this) } // called from onCreate @@ -960,6 +960,14 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe } ?: false } + override fun onClick(v: View?) { + if (v === binding?.toolbarContent?.profilePictureView?.root) { + // open conversation settings + val intent = Intent(this, ConversationSettingsActivity::class.java) + startActivity(intent) + } + } + override fun block(deleteThread: Boolean) { val title = R.string.RecipientPreferenceActivity_block_this_contact_question val message = R.string.RecipientPreferenceActivity_you_will_no_longer_receive_messages_and_calls_from_this_contact diff --git a/app/src/main/res/drawable/debug_border.xml b/app/src/main/res/drawable/debug_border.xml new file mode 100644 index 00000000000..e0a28b77e4c --- /dev/null +++ b/app/src/main/res/drawable/debug_border.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_add_admins.xml b/app/src/main/res/drawable/ic_add_admins.xml new file mode 100644 index 00000000000..b0b326ca3d3 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_admins.xml @@ -0,0 +1,16 @@ + + + + + + + diff --git a/app/src/main/res/drawable/ic_all_media.xml b/app/src/main/res/drawable/ic_all_media.xml new file mode 100644 index 00000000000..a9b3bdfdd1e --- /dev/null +++ b/app/src/main/res/drawable/ic_all_media.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_clear_messages.xml b/app/src/main/res/drawable/ic_clear_messages.xml new file mode 100644 index 00000000000..e79703910d7 --- /dev/null +++ b/app/src/main/res/drawable/ic_clear_messages.xml @@ -0,0 +1,20 @@ + + + + + + + diff --git a/app/src/main/res/drawable/ic_delete.xml b/app/src/main/res/drawable/ic_delete.xml new file mode 100644 index 00000000000..f3db9cc27ff --- /dev/null +++ b/app/src/main/res/drawable/ic_delete.xml @@ -0,0 +1,16 @@ + + + + + + + diff --git a/app/src/main/res/drawable/ic_disappearing_messages.xml b/app/src/main/res/drawable/ic_disappearing_messages.xml new file mode 100644 index 00000000000..1e2de4e757c --- /dev/null +++ b/app/src/main/res/drawable/ic_disappearing_messages.xml @@ -0,0 +1,16 @@ + + + + + + + diff --git a/app/src/main/res/drawable/ic_edit_group.xml b/app/src/main/res/drawable/ic_edit_group.xml new file mode 100644 index 00000000000..f647fea3ea2 --- /dev/null +++ b/app/src/main/res/drawable/ic_edit_group.xml @@ -0,0 +1,22 @@ + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_leave_group.xml b/app/src/main/res/drawable/ic_leave_group.xml new file mode 100644 index 00000000000..a6a235aeb7f --- /dev/null +++ b/app/src/main/res/drawable/ic_leave_group.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_notification_settings.xml b/app/src/main/res/drawable/ic_notification_settings.xml new file mode 100644 index 00000000000..e3dea6f2a2d --- /dev/null +++ b/app/src/main/res/drawable/ic_notification_settings.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_pin_conversation.xml b/app/src/main/res/drawable/ic_pin_conversation.xml new file mode 100644 index 00000000000..b2ff304b359 --- /dev/null +++ b/app/src/main/res/drawable/ic_pin_conversation.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_search_conversation.xml b/app/src/main/res/drawable/ic_search_conversation.xml new file mode 100644 index 00000000000..bd9eaad36cc --- /dev/null +++ b/app/src/main/res/drawable/ic_search_conversation.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/profile_picture_view_large_background.xml b/app/src/main/res/drawable/profile_picture_view_large_background.xml index 278d70901f0..90325c3fbfc 100644 --- a/app/src/main/res/drawable/profile_picture_view_large_background.xml +++ b/app/src/main/res/drawable/profile_picture_view_large_background.xml @@ -1,9 +1,6 @@ - + android:shape="oval"> - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_conversation_settings.xml b/app/src/main/res/layout/activity_conversation_settings.xml index 8c01e5be5ba..98450498d2f 100644 --- a/app/src/main/res/layout/activity_conversation_settings.xml +++ b/app/src/main/res/layout/activity_conversation_settings.xml @@ -2,14 +2,26 @@ + tools:context="org.thoughtcrime.securesms.conversation.settings.ConversationSettingsActivity" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_large_profile_picture.xml b/app/src/main/res/layout/view_large_profile_picture.xml new file mode 100644 index 00000000000..559f6c5a1bb --- /dev/null +++ b/app/src/main/res/layout/view_large_profile_picture.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_message_request.xml b/app/src/main/res/menu/menu_message_request.xml index d9ff7376477..fcaa8acb082 100644 --- a/app/src/main/res/menu/menu_message_request.xml +++ b/app/src/main/res/menu/menu_message_request.xml @@ -3,7 +3,7 @@ 34dp 24dp + 26dp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8bde853c736..6e7635eefd8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -864,4 +864,16 @@ Join Navigate Back Close Dialog + Search Conversation + All Media + Pin Conversation + Notifications + Auto-download Media + Automatically download media and files from this chat. + Admin Settings + Disappearing Messages + Edit Group + Add Admins + Clear Messages + Leave Group diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index c97cb9e7402..ffdea822811 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -13,6 +13,54 @@ 0dp + + + + + + + + + + + +