From 4493c68c66162790afc9c42a0f2811a47b9c8191 Mon Sep 17 00:00:00 2001 From: Kee Jefferys Date: Fri, 13 Mar 2020 14:44:12 +1100 Subject: [PATCH 01/25] Update issue templates Update issues templates and remove old Signal related files --- .github/ISSUE_TEMPLATE.md | 12 ++--- .github/PULL_REQUEST_TEMPLATE.md | 4 -- BUILDING.md | 74 -------------------------- CONTRIBUTING.md | 89 -------------------------------- 4 files changed, 3 insertions(+), 176 deletions(-) delete mode 100644 BUILDING.md delete mode 100644 CONTRIBUTING.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 5a116b751a..b772403787 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -3,18 +3,14 @@ You can also preview your report before submitting it. You may remove sections t Before we begin, please note that this tracker is only for issues. It is not for questions, comments, or feature requests. -If you would like to discuss a new feature or submit suggestions, please visit the community forum: -https://community.signalusers.org -If you are looking for support, please visit our support center: -https://support.signal.org/ -or email support@signal.org +If you are looking for support, please file an issue or: +or email team@loki.network Let's begin with a checklist: Replace the empty checkboxes [ ] below with checked ones [x] accordingly. --> - [ ] I have searched open and closed issues for duplicates - [ ] I am submitting a bug report for existing functionality that does not work as intended -- [ ] I have read https://github.com/signalapp/Signal-Android/wiki/Submitting-useful-bug-reports - [ ] This isn't a feature request or a discussion topic ---------------------------------------- @@ -38,8 +34,6 @@ Describe here the issue that you are experiencing. **Device:** Manufacturer Model XVI **Android version:** 0.0.0 -**Signal version:** 0.0.0 +**Session version:** 0.0.0 -### Link to debug log - diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 543e006459..4e2e4b5310 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,12 +1,8 @@ ### First time contributor checklist -- [ ] I have read [how to contribute](https://github.com/signalapp/Signal-Android/blob/master/CONTRIBUTING.md) to this project -- [ ] I have signed the [Contributor License Agreement](https://whispersystems.org/cla/) - ### Contributor checklist -- [ ] I am following the [Code Style Guidelines](https://github.com/signalapp/Signal-Android/wiki/Code-Style-Guidelines) - [ ] I have tested my contribution on these devices: * Device A, Android X.Y.Z * Device B, Android Z.Y diff --git a/BUILDING.md b/BUILDING.md deleted file mode 100644 index 4f97d9a014..0000000000 --- a/BUILDING.md +++ /dev/null @@ -1,74 +0,0 @@ -Building Signal -=============== - -Basics ------- - -Signal uses [Gradle](http://gradle.org) to build the project and to maintain -dependencies. However, you needn't install it yourself; the -"gradle wrapper" `gradlew`, mentioned below, will do that for you. - -Building Signal ---------------- - -The following steps should help you (re)build Signal from the command line. - -1. Checkout the Signal-Android project source with the command: - - git clone https://github.com/signalapp/Signal-Android.git - -2. Make sure you have the [Android SDK](https://developer.android.com/sdk/index.html) installed. -3. Ensure that the following packages are installed from the Android SDK manager: - * Android SDK Build Tools (see buildToolsVersion in build.gradle) - * SDK Platform (All API levels) - * Android Support Repository - * Google Repository -4. Create a local.properties file at the root of your source checkout and add an sdk.dir entry to it. For example: - - sdk.dir=/Application/android-sdk-macosx - -5. Using Java 8 - -6. Execute Gradle: - - ./gradlew build - -Visual assets ----------------------- - -Source assets tend to be large binary blobs, which are best stored outside of git repositories. Some source files are SVGs that can be auto-colored and sized using a tool like [android-res-utils](https://github.com/sebkur/android-res-utils). - -Sample command for generating our audio placeholder image: - -```bash -pngs_from_svg.py ic_audio.svg /path/to/Signal/res/ 150 --color #000 --opacity 0.54 --suffix _light -pngs_from_svg.py ic_audio.svg /path/to/Signal/res/ 150 --color #fff --opacity 1.00 --suffix _light -``` - -Setting up a development environment ------------------------------------- - -[Android Studio](https://developer.android.com/sdk/installing/studio.html) is the recommended development environment. - -1. Install Android Studio. -2. Open Android Studio. On a new installation, the Quickstart panel will appear. If you have open projects, close them using "File > Close Project" to see the Quickstart panel. -3. From the Quickstart panel, choose "Configure" then "SDK Manager". -4. In the SDK Tools tab of the SDK Manager, make sure that the "Android Support Repository" is installed, and that the latest "Android SDK build-tools" are installed. Click "OK" to return to the Quickstart panel. -5. From the Quickstart panel, choose "Checkout from Version Control" then "git". -6. Paste the URL for the Signal-Android project when prompted (https://github.com/signalapp/Signal-Android.git). -7. Android studio should detect the presence of a project file and ask you whether to open it. Click "yes". -9. Default config options should be good enough. -9. Project initialisation and build should proceed. - -Contributing code ------------------ - -Code contributions should be sent via github as pull requests, from feature branches [as explained here](https://help.github.com/articles/using-pull-requests). - -Mailing list ------------- - -Development discussion happens on the whispersystems mailing list. -[To join](https://lists.riseup.net/www/info/whispersystems) -Send emails to whispersystems@lists.riseup.net - diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index b48217186e..0000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,89 +0,0 @@ -# Contributing to Signal Android - -Thank you for supporting Signal and looking for ways to help. Please note that some conventions here might be a bit different than what you are used to, even if you have contributed to other open source projects before. Reading this document will help you save time and work effectively with the developers and other contributors. - - -## Development Ideology - -Truths which we believe to be self-evident: - -1. **The answer is not more options.** If you feel compelled to add a preference that's exposed to the user, it's very possible you've made a wrong turn somewhere. -1. **The user doesn't know what a key is.** We need to minimize the points at which a user is exposed to this sort of terminology as extremely as possible. -1. **There are no power users.** The idea that some users "understand" concepts better than others has proven to be, for the most part, false. If anything, "power users" are more dangerous than the rest, and we should avoid exposing dangerous functionality to them. -1. **If it's "like PGP," it's wrong.** PGP is our guide for what not to do. -1. **It's an asynchronous world.** Be wary of anything that is anti-asynchronous: ACKs, protocol confirmations, or any protocol-level "advisory" message. -1. **There is no such thing as time.** Protocol ideas that require synchronized clocks are doomed to failure. - - -## Translations - -Thanks to a dedicated community of volunteer translators, Signal is now available in more than one hundred languages. We use Transifex to manage our translation efforts, not GitHub. Any suggestions, corrections, or new translations should be submitted to the [Signal localization project for Android](https://www.transifex.com/signalapp/signal-android/). - - -## Issues - -### Useful bug reports -1. Please search both open and closed issues to make sure your bug report is not a duplicate. -1. Read the [guide to submitting useful bug reports](https://github.com/signalapp/Signal-Android/wiki/Submitting-useful-bug-reports) before posting a bug. - -### The issue tracker is for bugs, not feature requests -The GitHub issue tracker is not used for feature requests, but new ideas can be submitted and discussed on the [community forum](https://community.signalusers.org/c/feature-requests). The purpose of this issue tracker is to track bugs in the Android client. Bug reports should only be submitted for existing functionality that does not work as intended. Comments that are relevant and concise will help the developers solve issues more quickly. - -### Send support questions to support -You can reach support by sending an email to support@signal.org or by visiting the [Signal Support Center](https://support.signal.org/) where you can also search for existing troubleshooting articles and find answers to frequently asked questions. Please do not post support questions on the GitHub issue tracker. - -### GitHub is not a generic discussion forum -Conversations about open bug reports belong here. However, all other discussions should take place on the [community forum](https://community.signalusers.org). You can use the community forum to discuss anything that is related to Signal or to hang out with your fellow users in the "Off Topic" category. - -### Don't bump issues -Every time someone comments on an issue, GitHub sends an email to [hundreds of people](https://github.com/signalapp/Signal-Android/watchers). Bumping issues with a "+1" (or asking for updates) generates a lot of unnecessary email notifications and does not help anyone solve the issue any faster. Please be respectful of everyone's time and only comment when you have new information to add. - -### Open issues - -#### If it's open, it's tracked -The developers read every issue, but high-priority bugs or features can take precedence over others. Signal is an open source project, and everyone is encouraged to play an active role in diagnosing and fixing open issues. - -### Closed issues - -#### "My issue was closed without giving a reason!" -Although we do our best, writing detailed explanations for every issue can be time consuming, and the topic also might have been covered previously in other related issues. - - -## Pull requests - -### Smaller is better -Big changes are significantly less likely to be accepted. Large features often require protocol modifications and necessitate a staged rollout process that is coordinated across millions of users on multiple platforms (Android, iOS, and Desktop). - -Try not to take on too much at once. As a first-time contributor, we recommend starting with small and simple PRs in order to become familiar with the codebase. Most of the work should go into discovering which three lines need to change rather than writing the code. - -### Sign the Contributor License Agreement (CLA) -You will need to [sign our CLA](https://signal.org/cla/) before your pull request can be merged. - -### Follow the Code Style Guidelines -Ensure that your code adheres to the [Code Style Guidelines](https://github.com/signalapp/Signal-Android/wiki/Code-Style-Guidelines) before submitting a pull request. - -### Submit finished and well-tested pull requests -Please do not submit pull requests that are still a work in progress. Pull requests should be thoroughly tested and ready to merge before they are submitted. - -### Merging can sometimes take a while -If your pull request follows all of the advice above but still has not been merged, this usually means that the developers haven't had time to review it yet. We understand that this might feel frustrating, and we apologize. The Signal team is still small, but [we are hiring](https://signal.org/workworkwork/). - - -## How can I contribute? -There are several other ways to get involved: -* Help new users learn about Signal. - * Redirect support questions to support@signal.org and the [Signal Support Center](https://support.signal.org/). - * Redirect non-bug discussions to the [community forum](https://community.signalusers.org). -* Improve documentation in the [wiki](https://github.com/signalapp/Signal-Android/wiki). -* Join the community of volunteer translators on Transifex: - * [Android](https://www.transifex.com/signalapp/signal-android/) - * [iOS](https://www.transifex.com/signalapp/signal-ios/) - * [Desktop](https://www.transifex.com/signalapp/signal-desktop/) -* Find and mark duplicate issues. -* Try to reproduce issues and help with troubleshooting. -* Discover solutions to open issues and post any relevant findings. -* Test other people's pull requests. -* Contribute to Signal via the [Freedom of the Press Foundation's donation page](https://freedom.press/crowdfunding/signal/). -* Share Signal with your friends and family. - -Signal is made for you. Thank you for your feedback and support. From 592456d59d42640e8d8bebfaf942cddf4bf85987 Mon Sep 17 00:00:00 2001 From: Niels Andriesse <9340958+nielsandriesse@users.noreply.github.com> Date: Mon, 6 Apr 2020 14:27:39 +1000 Subject: [PATCH 02/25] Update ISSUE_TEMPLATE.md --- .github/ISSUE_TEMPLATE.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index b772403787..928dfd6269 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -24,6 +24,7 @@ Describe here the issue that you are experiencing. - that reproduce the bug **Actual result:** Describe here what happens after you run the steps above (i.e. the buggy behaviour) + **Expected result:** Describe here what should happen after you run the steps above (i.e. what would be the correct behaviour) ### Screenshots @@ -33,7 +34,9 @@ Describe here the issue that you are experiencing. ### Device info **Device:** Manufacturer Model XVI + **Android version:** 0.0.0 + **Session version:** 0.0.0 From b5e10c79d8c7d42a98f323cf3f942cec65cd25f4 Mon Sep 17 00:00:00 2001 From: Niels Andriesse <9340958+nielsandriesse@users.noreply.github.com> Date: Mon, 6 Apr 2020 14:29:10 +1000 Subject: [PATCH 03/25] Update bug_report.md --- .github/ISSUE_TEMPLATE/bug_report.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 00542bd888..b7c55daee6 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -8,18 +8,23 @@ assignees: '' --- **Describe the bug** + A clear and concise description of what the bug is. **To reproduce** + Steps to reproduce the behavior: **Screenshots or logs** + If applicable, add screenshots or logs to help explain your problem. **Smartphone (please complete the following information):** + - Device: [e.g. Samsung Galaxy S8] - OS: [e.g. Android Pie] - Version of Loki Messenger or latest commit hash **Additional context** + Add any other context about the problem here. From 3ec5974210e6441105e10eb892b32acbfe3c3700 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Thu, 9 Apr 2020 09:41:01 +1000 Subject: [PATCH 04/25] Correctly display when user was kicked or added --- .../groups/GroupMessageProcessor.java | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java b/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java index c9145e77e1..a0dff036ac 100644 --- a/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java +++ b/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java @@ -146,40 +146,40 @@ public class GroupMessageProcessor { } } - Set
recordMembers = new HashSet<>(groupRecord.getMembers()); - Set
messageMembers = new HashSet<>(); + Set
currentMembers = new HashSet<>(groupRecord.getMembers()); + Set
newMembers = new HashSet<>(); for (String messageMember : group.getMembers().get()) { - messageMembers.add(Address.fromExternal(context, messageMember)); + newMembers.add(Address.fromExternal(context, messageMember)); } - Set
addedMembers = new HashSet<>(messageMembers); - addedMembers.removeAll(recordMembers); + // Added members are the members who are present in newMembers but not in currentMembers + Set
addedMembers = new HashSet<>(newMembers); + addedMembers.removeAll(currentMembers); - Set
missingMembers = new HashSet<>(recordMembers); - missingMembers.removeAll(messageMembers); + // Kicked members are members who are present in currentMembers but not in newMembers + Set
removedMembers = new HashSet<>(currentMembers); + removedMembers.removeAll(newMembers); GroupContext.Builder builder = createGroupContext(group); builder.setType(GroupContext.Type.UPDATE); - if (addedMembers.size() > 0) { - Set
unionMembers = new HashSet<>(recordMembers); - unionMembers.addAll(messageMembers); - database.updateMembers(id, new LinkedList<>(unionMembers)); - - builder.clearMembers(); - - for (Address addedMember : addedMembers) { - builder.addMembers(addedMember.serialize()); - } - } else { - builder.clearMembers(); + // Update our group members if they're different + if (!currentMembers.equals(newMembers)) { + database.updateMembers(id, new LinkedList<>(newMembers)); } - if (missingMembers.size() > 0) { - for (Address removedMember : missingMembers) { - builder.addMembers(removedMember.serialize()); - } + builder.clearMembers(); + + // We add any new or removed members to the group context + // This will allow us later to iterate over them to check if they left or were added for UI display + + for (Address addedMember : addedMembers) { + builder.addMembers(addedMember.serialize()); + } + + for (Address removedMember : removedMembers) { + builder.addMembers(removedMember.serialize()); } if (group.getName().isPresent() || group.getAvatar().isPresent()) { From 4a36ed333db138a8ae2e067451d9443efd9f55ce Mon Sep 17 00:00:00 2001 From: Mikunj Date: Thu, 9 Apr 2020 10:47:18 +1000 Subject: [PATCH 05/25] Disable chat if we were removed from the group. --- .../securesms/groups/GroupMessageProcessor.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java b/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java index a0dff036ac..4e53e6273b 100644 --- a/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java +++ b/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java @@ -173,7 +173,6 @@ public class GroupMessageProcessor { // We add any new or removed members to the group context // This will allow us later to iterate over them to check if they left or were added for UI display - for (Address addedMember : addedMembers) { builder.addMembers(addedMember.serialize()); } @@ -182,6 +181,13 @@ public class GroupMessageProcessor { builder.addMembers(removedMember.serialize()); } + // If we were removed then we need to disable the chat + String masterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(context); + String ourHexEncodedPublicKey = masterHexEncodedPublicKey != null ? masterHexEncodedPublicKey : TextSecurePreferences.getLocalNumber(context); + if (removedMembers.contains(Address.fromSerialized(ourHexEncodedPublicKey))) { + database.setActive(id, false); + } + if (group.getName().isPresent() || group.getAvatar().isPresent()) { SignalServiceAttachment avatar = group.getAvatar().orNull(); database.update(id, group.getName().orNull(), avatar != null ? avatar.asPointer() : null); From f149065a30c8221d05e9df8a44d27ce54a6006b5 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Thu, 9 Apr 2020 13:17:00 +1000 Subject: [PATCH 06/25] Fix GroupDescriptions updating dynamically. This shouldn't happen, rather it should have the snapshot of the group state per message. --- .../groups/GroupMessageProcessor.java | 38 ++++++----- .../securesms/util/GroupUtil.java | 63 +++++++------------ 2 files changed, 45 insertions(+), 56 deletions(-) diff --git a/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java b/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java index 4e53e6273b..719a7dd7d8 100644 --- a/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java +++ b/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java @@ -137,13 +137,25 @@ public class GroupMessageProcessor { GroupDatabase database = DatabaseFactory.getGroupDatabase(context); String id = GroupUtil.getEncodedId(group); - // Only update group if admin sent the message + String masterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(context); + String ourHexEncodedPublicKey = masterHexEncodedPublicKey != null ? masterHexEncodedPublicKey : TextSecurePreferences.getLocalNumber(context); + if (group.getGroupType() == SignalServiceGroup.GroupType.SIGNAL) { + // Only update group if admin sent the message String hexEncodedPublicKey = getMasterHexEncodedPublicKey(context, content.getSender()); if (!groupRecord.getAdmins().contains(Address.fromSerialized(hexEncodedPublicKey))) { Log.d("Loki - Group Message", "Received a group update message from a non-admin user for " + id +". Ignoring."); return null; } + + // We should only process update message if we were in the group + Address ourAddress = Address.fromSerialized(ourHexEncodedPublicKey); + if (!groupRecord.getMembers().contains(ourAddress) && + !group.getMembers().or(Collections.emptyList()).contains(ourHexEncodedPublicKey)) { + Log.d("Loki - Group Message", "Received a group update message from a group we are not members in: " + id + " . Ignoring."); + database.setActive(id, false); + return null; + } } Set
currentMembers = new HashSet<>(groupRecord.getMembers()); @@ -169,23 +181,14 @@ public class GroupMessageProcessor { database.updateMembers(id, new LinkedList<>(newMembers)); } - builder.clearMembers(); - // We add any new or removed members to the group context // This will allow us later to iterate over them to check if they left or were added for UI display for (Address addedMember : addedMembers) { - builder.addMembers(addedMember.serialize()); + builder.addNewMembers(addedMember.serialize()); } for (Address removedMember : removedMembers) { - builder.addMembers(removedMember.serialize()); - } - - // If we were removed then we need to disable the chat - String masterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(context); - String ourHexEncodedPublicKey = masterHexEncodedPublicKey != null ? masterHexEncodedPublicKey : TextSecurePreferences.getLocalNumber(context); - if (removedMembers.contains(Address.fromSerialized(ourHexEncodedPublicKey))) { - database.setActive(id, false); + builder.addRemovedMembers(removedMember.serialize()); } if (group.getName().isPresent() || group.getAvatar().isPresent()) { @@ -197,10 +200,15 @@ public class GroupMessageProcessor { builder.clearName(); } - if (!groupRecord.isActive()) database.setActive(id, true); + // If we were removed then we need to disable the chat + if (removedMembers.contains(Address.fromSerialized(ourHexEncodedPublicKey))) { + database.setActive(id, false); + } else { + if (!groupRecord.isActive()) database.setActive(id, true); - if (group.getMembers().isPresent()) { - establishSessionsWithMembersIfNeeded(context, group.getMembers().get()); + if (group.getMembers().isPresent()) { + establishSessionsWithMembersIfNeeded(context, group.getMembers().get()); + } } return storeMessage(context, content, group, builder.build(), outgoing); diff --git a/src/org/thoughtcrime/securesms/util/GroupUtil.java b/src/org/thoughtcrime/securesms/util/GroupUtil.java index 907a21217e..0029d5f6a4 100644 --- a/src/org/thoughtcrime/securesms/util/GroupUtil.java +++ b/src/org/thoughtcrime/securesms/util/GroupUtil.java @@ -10,7 +10,6 @@ import com.google.protobuf.ByteString; import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.GroupDatabase; -import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage; import org.thoughtcrime.securesms.recipients.Recipient; @@ -159,7 +158,7 @@ public class GroupUtil { @NonNull private final Context context; @Nullable private final GroupContext groupContext; - private final List members; + private final List newMembers; private final List removedMembers; private boolean ourDeviceWasRemoved; @@ -167,35 +166,35 @@ public class GroupUtil { this.context = context.getApplicationContext(); this.groupContext = groupContext; - this.members = new LinkedList<>(); + this.newMembers = new LinkedList<>(); this.removedMembers = new LinkedList<>(); this.ourDeviceWasRemoved = false; - if (groupContext != null && !groupContext.getMembersList().isEmpty()) { - List memberList = groupContext.getMembersList(); - List
currentMembers = getCurrentGroupMembers(); + if (groupContext != null) { + List newMembers = groupContext.getNewMembersList(); + for (String member : newMembers) { + this.newMembers.add(this.toRecipient(member)); + } - // Add them to the member or removed members lists - for (String member : memberList) { - Address address = Address.fromSerialized(member); - Recipient recipient = Recipient.from(context, address, true); - if (currentMembers == null || currentMembers.contains(address)) { - this.members.add(recipient); - } else { - this.removedMembers.add(recipient); - } + List removedMembers = groupContext.getRemovedMembersList(); + for (String member : removedMembers) { + this.removedMembers.add(this.toRecipient(member)); } // Check if our device was removed if (!removedMembers.isEmpty()) { String masterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(context); String hexEncodedPublicKey = masterHexEncodedPublicKey != null ? masterHexEncodedPublicKey : TextSecurePreferences.getLocalNumber(context); - Recipient self = Recipient.from(context, Address.fromSerialized(hexEncodedPublicKey), false); - ourDeviceWasRemoved = removedMembers.contains(self); + ourDeviceWasRemoved = removedMembers.contains(hexEncodedPublicKey); } } } + private Recipient toRecipient(String hexEncodedPublicKey) { + Address address = Address.fromSerialized(hexEncodedPublicKey); + return Recipient.from(context, address, false); + } + public String toString(Recipient sender) { // Show the local removed message if (ourDeviceWasRemoved) { @@ -211,10 +210,10 @@ public class GroupUtil { String title = groupContext.getName(); - if (!members.isEmpty()) { + if (!newMembers.isEmpty()) { description.append("\n"); description.append(context.getResources().getQuantityString(R.plurals.GroupUtil_joined_the_group, - members.size(), toString(members))); + newMembers.size(), toString(newMembers))); } if (!removedMembers.isEmpty()) { @@ -224,8 +223,8 @@ public class GroupUtil { } if (title != null && !title.trim().isEmpty()) { - if (!members.isEmpty()) description.append(" "); - else description.append("\n"); + String separator = (!newMembers.isEmpty() || !removedMembers.isEmpty()) ? " " : "\n"; + description.append(separator); description.append(context.getString(R.string.GroupUtil_group_name_is_now, title)); } @@ -233,8 +232,8 @@ public class GroupUtil { } public void addListener(RecipientModifiedListener listener) { - if (!this.members.isEmpty()) { - for (Recipient member : this.members) { + if (!this.newMembers.isEmpty()) { + for (Recipient member : this.newMembers) { member.addListener(listener); } } @@ -252,23 +251,5 @@ public class GroupUtil { return result; } - - private List
getCurrentGroupMembers() { - if (groupContext == null) { return null; } - GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context); - byte[] decodedGroupId = groupContext.getId().toByteArray(); - String signalGroupId = getEncodedId(decodedGroupId, false); - String publicChatId = getEncodedPublicChatId(decodedGroupId); - String rssFeedId = getEncodedRSSFeedId(decodedGroupId); - GroupRecord groupRecord = null; - if (!groupDatabase.isUnknownGroup(signalGroupId)) { - groupRecord = groupDatabase.getGroup(signalGroupId).orNull(); - } else if (!groupDatabase.isUnknownGroup(publicChatId)) { - groupRecord = groupDatabase.getGroup(publicChatId).orNull(); - } else if (!groupDatabase.isUnknownGroup(rssFeedId)) { - groupRecord = groupDatabase.getGroup(rssFeedId).orNull(); - } - return (groupRecord != null) ? groupRecord.getMembers() : null; - } } } From 45220bfa701af4d040bc72df2c6e6032ad91a0c5 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Thu, 9 Apr 2020 13:23:51 +1000 Subject: [PATCH 07/25] Hide input when group is marked as not active. Fix bug where input panel gets shown when you long press a message. --- .../conversation/ConversationActivity.java | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java index d1b9136ddd..93819bc5f4 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -317,7 +317,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity private Button makeDefaultSmsButton; private Button registerButton; private InputAwareLayout container; - private View composePanel; protected Stub reminderView; private Stub unverifiedBannerView; private Stub groupShareProfileView; @@ -552,7 +551,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity updateTitleTextView(recipient); updateSubtitleTextView(); setActionBarColor(recipient.getColor()); - setBlockedUserState(recipient, isSecureText, isDefaultSms); + updateInputUI(recipient, isSecureText, isDefaultSms); setGroupShareProfileReminder(recipient); calculateCharactersRemaining(); @@ -645,7 +644,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity updateTitleTextView(recipient); updateSubtitleTextView(); NotificationChannels.updateContactChannelName(this, recipient); - setBlockedUserState(recipient, isSecureText, isDefaultSms); + updateInputUI(recipient, isSecureText, isDefaultSms); supportInvalidateOptionsMenu(); break; case TAKE_PHOTO: @@ -858,6 +857,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity searchViewModel.onSearchClosed(); searchNav.setVisibility(View.GONE); inputPanel.setVisibility(View.VISIBLE); + updateInputUI(recipient, isSecureText, isDefaultSms); fragment.onSearchQueryUpdated(null); invalidateOptionsMenu(); return true; @@ -1343,7 +1343,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity calculateCharactersRemaining(); supportInvalidateOptionsMenu(); - setBlockedUserState(recipient, isSecureText, isDefaultSms); + updateInputUI(recipient, isSecureText, isDefaultSms); } ///// Initializers @@ -1627,7 +1627,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity unblockButton = ViewUtil.findById(this, R.id.unblock_button); makeDefaultSmsButton = ViewUtil.findById(this, R.id.make_default_sms_button); registerButton = ViewUtil.findById(this, R.id.register_button); - composePanel = ViewUtil.findById(this, R.id.bottom_panel); container = ViewUtil.findById(this, R.id.layout_container); reminderView = ViewUtil.findStubById(this, R.id.reminder_stub); unverifiedBannerView = ViewUtil.findStubById(this, R.id.unverified_banner_stub); @@ -1835,7 +1834,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity updateTitleTextView(recipient); updateSubtitleTextView(); // titleView.setVerified(identityRecords.isVerified()); - setBlockedUserState(recipient, isSecureText, isDefaultSms); + updateInputUI(recipient, isSecureText, isDefaultSms); setActionBarColor(recipient.getColor()); setGroupShareProfileReminder(recipient); updateReminders(recipient.hasSeenInviteReminder()); @@ -2043,29 +2042,29 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity setStatusBarColor(getResources().getColor(R.color.action_bar_background)); } - private void setBlockedUserState(Recipient recipient, boolean isSecureText, boolean isDefaultSms) { - if (recipient.isGroupRecipient() && recipient.getAddress().isRSSFeed()) { + private void updateInputUI(Recipient recipient, boolean isSecureText, boolean isDefaultSms) { + if (recipient.isGroupRecipient() && !isActiveGroup()) { unblockButton.setVisibility(View.GONE); - composePanel.setVisibility(View.GONE); + inputPanel.setVisibility(View.GONE); makeDefaultSmsButton.setVisibility(View.GONE); registerButton.setVisibility(View.GONE); } else if (recipient.isBlocked()) { unblockButton.setVisibility(View.VISIBLE); - composePanel.setVisibility(View.GONE); + inputPanel.setVisibility(View.GONE); makeDefaultSmsButton.setVisibility(View.GONE); registerButton.setVisibility(View.GONE); } else if (!isSecureText && isPushGroupConversation()) { unblockButton.setVisibility(View.GONE); - composePanel.setVisibility(View.GONE); + inputPanel.setVisibility(View.GONE); makeDefaultSmsButton.setVisibility(View.GONE); registerButton.setVisibility(View.VISIBLE); } else if (!isSecureText && !isDefaultSms) { unblockButton.setVisibility(View.GONE); - composePanel.setVisibility(View.GONE); + inputPanel.setVisibility(View.GONE); makeDefaultSmsButton.setVisibility(View.VISIBLE); registerButton.setVisibility(View.GONE); } else { - composePanel.setVisibility(View.VISIBLE); + inputPanel.setVisibility(View.VISIBLE); unblockButton.setVisibility(View.GONE); makeDefaultSmsButton.setVisibility(View.GONE); registerButton.setVisibility(View.GONE); @@ -2125,7 +2124,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity } private boolean isActiveGroup() { - if (!isGroupConversation()) return false; + if (!isGroupConversation() || recipient.getAddress().isRSSFeed()) return false; Optional record = DatabaseFactory.getGroupDatabase(this).getGroup(getRecipient().getAddress().toGroupString()); return record.isPresent() && record.get().isActive(); @@ -2314,7 +2313,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity String hint = enabled ? "Message" : "Pending session request"; inputPanel.setHint(hint); inputPanel.setEnabled(enabled); - if (enabled) { + if (enabled && inputPanel.getVisibility() == View.VISIBLE) { inputPanel.composeText.requestFocus(); InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); inputMethodManager.showSoftInput(inputPanel.composeText, 0); @@ -2939,6 +2938,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity @Override public void handleReplyMessage(MessageRecord messageRecord) { + if (recipient.isGroupRecipient() && !isActiveGroup()) { return; } + Recipient author; if (messageRecord.isOutgoing()) { From 7d9eafe8fb67ac08f75d0fced6123f833be5465c Mon Sep 17 00:00:00 2001 From: Mikunj Date: Thu, 9 Apr 2020 15:30:29 +1000 Subject: [PATCH 08/25] Ignore closed group messages from users who are not members. --- .../groups/GroupMessageProcessor.java | 3 +-- .../securesms/jobs/PushDecryptJob.java | 23 ++++++++++++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java b/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java index 719a7dd7d8..29e591ffb2 100644 --- a/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java +++ b/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java @@ -137,8 +137,7 @@ public class GroupMessageProcessor { GroupDatabase database = DatabaseFactory.getGroupDatabase(context); String id = GroupUtil.getEncodedId(group); - String masterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(context); - String ourHexEncodedPublicKey = masterHexEncodedPublicKey != null ? masterHexEncodedPublicKey : TextSecurePreferences.getLocalNumber(context); + String ourHexEncodedPublicKey = getMasterHexEncodedPublicKey(context, TextSecurePreferences.getLocalNumber(context)); if (group.getGroupType() == SignalServiceGroup.GroupType.SIGNAL) { // Only update group if admin sent the message diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index 29d3a12172..c421e3ba8b 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -1895,7 +1895,28 @@ public class PushDecryptJob extends BaseJob implements InjectableType { boolean isGroupActive = groupId.isPresent() && groupDatabase.isActive(groupId.get()); boolean isLeaveMessage = message.getGroupInfo().isPresent() && message.getGroupInfo().get().getType() == SignalServiceGroup.Type.QUIT; - return (isContentMessage && !isGroupActive) || (sender.isBlocked() && !isLeaveMessage); + boolean isClosedGroup = conversation.getAddress().isSignalGroup(); + boolean isGroupMember = true; + + // Only allow messages from members of a group + if (isClosedGroup) { + String senderHexEncodedPublicKey = content.getSender(); + + try { + String masterHexEncodedPublicKey = PromiseUtil.timeout(LokiDeviceLinkUtilities.INSTANCE.getMasterHexEncodedPublicKey(content.getSender()), 5000).get(); + if (masterHexEncodedPublicKey != null) { + senderHexEncodedPublicKey = masterHexEncodedPublicKey; + } + } catch (Exception e) { + e.printStackTrace(); + } + + Recipient senderMaster = Recipient.from(context, Address.fromSerialized(senderHexEncodedPublicKey), false); + + isGroupMember = groupId.isPresent() && groupDatabase.getGroupMembers(groupId.get(), true).contains(senderMaster); + } + + return (isContentMessage && !isGroupActive) || (sender.isBlocked() && !isLeaveMessage) || (isContentMessage && !isGroupMember); } else { return sender.isBlocked(); } From b72048d9a4c8ec394619ea031a6fb6463944a6f6 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 15 Apr 2020 10:24:30 +1000 Subject: [PATCH 09/25] add FCM to app for remote push notification --- AndroidManifest.xml | 9 ++ build.gradle | 4 + .../securesms/ApplicationContext.java | 25 +++++ .../loki/LokiPushNotificationManager.kt | 98 +++++++++++++++++++ .../messaging/BackgroundPollWorker.kt | 2 +- .../service/PushNotificationService.kt | 39 ++++++++ .../securesms/util/TextSecurePreferences.java | 10 ++ 7 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 src/org/thoughtcrime/securesms/loki/LokiPushNotificationManager.kt create mode 100644 src/org/thoughtcrime/securesms/service/PushNotificationService.kt diff --git a/AndroidManifest.xml b/AndroidManifest.xml index bfa2c456dc..654d3bc721 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -47,6 +47,7 @@ + @@ -509,6 +510,14 @@ android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize" android:exported="true" android:theme="@style/TextSecure.LightNoActionBar" /> + + + + + diff --git a/build.gradle b/build.gradle index 41e2ac5d37..fef89e3a44 100644 --- a/build.gradle +++ b/build.gradle @@ -16,6 +16,7 @@ buildscript { classpath "com.android.tools.build:gradle:$gradle_version" classpath files('libs/gradle-witness.jar') classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath 'com.google.gms:google-services:4.3.3' } } @@ -24,6 +25,7 @@ apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-android' apply plugin: 'witness' apply plugin: 'kotlin-kapt' +apply plugin: 'com.google.gms.google-services' repositories { mavenLocal() @@ -87,6 +89,8 @@ dependencies { implementation 'android.arch.lifecycle:extensions:1.1.1' implementation 'android.arch.lifecycle:common-java8:1.1.1' + implementation 'com.google.firebase:firebase-messaging:18.0.0' + implementation 'com.google.android.exoplayer:exoplayer-core:2.9.1' implementation 'com.google.android.exoplayer:exoplayer-ui:2.9.1' diff --git a/src/org/thoughtcrime/securesms/ApplicationContext.java b/src/org/thoughtcrime/securesms/ApplicationContext.java index 0687981f55..7e6215f2a7 100644 --- a/src/org/thoughtcrime/securesms/ApplicationContext.java +++ b/src/org/thoughtcrime/securesms/ApplicationContext.java @@ -30,6 +30,11 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.multidex.MultiDexApplication; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.iid.FirebaseInstanceId; +import com.google.firebase.iid.InstanceIdResult; + import org.conscrypt.Conscrypt; import org.jetbrains.annotations.NotNull; import org.signal.aesgcmprovider.AesGcmProvider; @@ -61,6 +66,7 @@ import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.logging.PersistentLogger; import org.thoughtcrime.securesms.logging.UncaughtExceptionLogger; import org.thoughtcrime.securesms.loki.LokiPublicChatManager; +import org.thoughtcrime.securesms.loki.LokiPushNotificationManager; import org.thoughtcrime.securesms.loki.MultiDeviceUtilities; import org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity; import org.thoughtcrime.securesms.loki.redesign.messaging.BackgroundOpenGroupPollWorker; @@ -197,6 +203,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc // Loki - Set up public chat manager lokiPublicChatManager = new LokiPublicChatManager(this); updatePublicChatProfilePictureIfNeeded(); + setUpFirebaseDeviceToken(); } @Override @@ -453,6 +460,24 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc }, this); } + public void setUpFirebaseDeviceToken() { + Context context = this; + FirebaseInstanceId.getInstance().getInstanceId() + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (!task.isSuccessful()) { + Log.w(TAG, "getInstanceId failed", task.getException()); + return; + } + // Get new Instance ID token + String token = task.getResult().getToken(); + String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context); + LokiPushNotificationManager.register(token, userHexEncodedPublicKey, context); + } + }); + } + @Override public void ping(@NotNull String s) { // TODO: Implement diff --git a/src/org/thoughtcrime/securesms/loki/LokiPushNotificationManager.kt b/src/org/thoughtcrime/securesms/loki/LokiPushNotificationManager.kt new file mode 100644 index 0000000000..8378519412 --- /dev/null +++ b/src/org/thoughtcrime/securesms/loki/LokiPushNotificationManager.kt @@ -0,0 +1,98 @@ +package org.thoughtcrime.securesms.loki + +import android.content.Context +import okhttp3.* +import org.thoughtcrime.securesms.util.TextSecurePreferences +import org.whispersystems.libsignal.logging.Log +import org.whispersystems.signalservice.internal.util.JsonUtil +import java.io.IOException + +object LokiPushNotificationManager { + //const val server = "https://live.apns.getsession.org/" + const val server = "https://dev.apns.getsession.org/" + const val tokenExpirationInterval = 2 * 24 * 60 * 60 + private val connection = OkHttpClient() + + fun disableRemoteNotification(token: String, context: Context?) { + val parameters = mapOf("token" to token) + val url = "${server}register" + val body = RequestBody.create(MediaType.get("application/json"), JsonUtil.toJson(parameters)) + val request = Request.Builder().url(url).post(body).build() + connection.newCall(request).enqueue(object : Callback { + + override fun onResponse(call: Call, response: Response) { + when (response.code()) { + 200 -> { + val bodyAsString = response.body()!!.string() + val json = JsonUtil.fromJson(bodyAsString, Map::class.java) + val code = json?.get("code") as? Int + if (code != null && code != 0) { + TextSecurePreferences.setIsUsingRemoteNotification(context, false) + } else { + Log.d("Loki", "Couldn't disable remote notification due to error: ${json?.get("message") as? String}.") + } + } + } + } + + override fun onFailure(call: Call, exception: IOException) { + Log.d("Loki", "Couldn't disable remote notification.") + } + }) + } + + @JvmStatic + fun register(token: String, hexEncodedPublicKey: String, context: Context?) { + val parameters = mapOf("token" to token, "pubKey" to hexEncodedPublicKey) + val url = "${server}register" + val body = RequestBody.create(MediaType.get("application/json"), JsonUtil.toJson(parameters)) + val request = Request.Builder().url(url).post(body).build() + connection.newCall(request).enqueue(object : Callback { + + override fun onResponse(call: Call, response: Response) { + when (response.code()) { + 200 -> { + val bodyAsString = response.body()!!.string() + val json = JsonUtil.fromJson(bodyAsString, Map::class.java) + val code = json?.get("code") as? Int + if (code != null && code != 0) { + TextSecurePreferences.setIsUsingRemoteNotification(context, true) + } else { + Log.d("Loki", "Couldn't register device token due to error: ${json?.get("message") as? String}.") + } + } + } + } + + override fun onFailure(call: Call, exception: IOException) { + Log.d("Loki", "Couldn't register device token.") + } + }) + } + + fun acknowledgeDeliveryForMessageWith(hash: String, expiration: Int, hexEncodedPublicKey: String, context: Context?) { + val parameters = mapOf("hash" to hash, "pubKey" to hexEncodedPublicKey, "expiration" to expiration) + val url = "${server}acknowledge_message_delivery" + val body = RequestBody.create(MediaType.get("application/json"), JsonUtil.toJson(parameters)) + val request = Request.Builder().url(url).post(body).build() + connection.newCall(request).enqueue(object : Callback { + + override fun onResponse(call: Call, response: Response) { + when (response.code()) { + 200 -> { + val bodyAsString = response.body()!!.string() + val json = JsonUtil.fromJson(bodyAsString, Map::class.java) + val code = json?.get("code") as? Int + if (code == null || code == 0) { + Log.d("Loki", "Couldn't acknowledge the delivery for message due to error: ${json?.get("message") as? String}.") + } + } + } + } + + override fun onFailure(call: Call, exception: IOException) { + Log.d("Loki", "Couldn't acknowledge the delivery for message with last hash: ${hash}") + } + }) + } +} diff --git a/src/org/thoughtcrime/securesms/loki/redesign/messaging/BackgroundPollWorker.kt b/src/org/thoughtcrime/securesms/loki/redesign/messaging/BackgroundPollWorker.kt index 4b8fdc9037..19c335f41a 100644 --- a/src/org/thoughtcrime/securesms/loki/redesign/messaging/BackgroundPollWorker.kt +++ b/src/org/thoughtcrime/securesms/loki/redesign/messaging/BackgroundPollWorker.kt @@ -15,7 +15,7 @@ import java.util.concurrent.TimeUnit class BackgroundPollWorker : PersistentAlarmManagerListener() { companion object { - private val pollInterval = TimeUnit.MINUTES.toMillis(2) + private val pollInterval = TimeUnit.MINUTES.toMillis(20) @JvmStatic fun schedule(context: Context) { diff --git a/src/org/thoughtcrime/securesms/service/PushNotificationService.kt b/src/org/thoughtcrime/securesms/service/PushNotificationService.kt new file mode 100644 index 0000000000..c877510f59 --- /dev/null +++ b/src/org/thoughtcrime/securesms/service/PushNotificationService.kt @@ -0,0 +1,39 @@ +package org.thoughtcrime.securesms.service + +import com.google.firebase.messaging.FirebaseMessagingService +import com.google.firebase.messaging.RemoteMessage +import org.thoughtcrime.securesms.ApplicationContext +import org.thoughtcrime.securesms.jobs.PushContentReceiveJob +import org.thoughtcrime.securesms.loki.LokiPushNotificationManager +import org.thoughtcrime.securesms.util.TextSecurePreferences +import org.whispersystems.libsignal.logging.Log +import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope +import org.whispersystems.signalservice.internal.util.Base64 +import org.whispersystems.signalservice.loki.messaging.LokiMessageWrapper + +class PushNotificationService: FirebaseMessagingService() { + + override fun onNewToken(token: String) { + super.onNewToken(token) + Log.d("Loki", "new token ${token}") + val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this) + LokiPushNotificationManager.register(token, userHexEncodedPublicKey, this) + } + + override fun onMessageReceived(message: RemoteMessage) { + val base64EncodedData = message.data["ENCRYPTED_DATA"] + val data = base64EncodedData?.let { Base64.decode(it) } + if (data != null) { + try { + val envelope = LokiMessageWrapper.unwrap(data) + PushContentReceiveJob(this).processEnvelope(SignalServiceEnvelope(envelope)) + } catch (e: Exception) { + Log.d("Loki", "Failed to unwrap data for message.") + } + } else { + Log.d("Loki", "Failed to decode data for message.") + } + } + + +} \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java index 42c204dfbb..62fc6c258e 100644 --- a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java +++ b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java @@ -185,6 +185,16 @@ public class TextSecurePreferences { private static final String MEDIA_KEYBOARD_MODE = "pref_media_keyboard_mode"; + private static final String IS_USING_REMOTE_NOTIFICATION = "pref_is_using_remote_notification"; + + public static boolean isUsingRemoteNotification(Context context) { + return getBooleanPreference(context, IS_USING_REMOTE_NOTIFICATION, false); + } + + public static void setIsUsingRemoteNotification(Context context, boolean value) { + setBooleanPreference(context, IS_USING_REMOTE_NOTIFICATION, value); + } + public static boolean isScreenLockEnabled(@NonNull Context context) { return getBooleanPreference(context, SCREEN_LOCK, false); } From 6ed3a4c3726ead174f073930c3199067d2d9c56d Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 15 Apr 2020 15:01:02 +1000 Subject: [PATCH 10/25] Add FIXME --- .../securesms/conversation/ConversationActivity.java | 1 + .../securesms/groups/GroupMessageProcessor.java | 8 ++++---- src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java | 6 +++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java index 93819bc5f4..7721233336 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -2042,6 +2042,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity setStatusBarColor(getResources().getColor(R.color.action_bar_background)); } + // FIXME: This name is confusing because we also have updateInputPanel and setInputPanelEnabled private void updateInputUI(Recipient recipient, boolean isSecureText, boolean isDefaultSms) { if (recipient.isGroupRecipient() && !isActiveGroup()) { unblockButton.setVisibility(View.GONE); diff --git a/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java b/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java index 29e591ffb2..52ffa66183 100644 --- a/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java +++ b/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java @@ -140,18 +140,18 @@ public class GroupMessageProcessor { String ourHexEncodedPublicKey = getMasterHexEncodedPublicKey(context, TextSecurePreferences.getLocalNumber(context)); if (group.getGroupType() == SignalServiceGroup.GroupType.SIGNAL) { - // Only update group if admin sent the message + // Only update group if the group admin sent the message String hexEncodedPublicKey = getMasterHexEncodedPublicKey(context, content.getSender()); if (!groupRecord.getAdmins().contains(Address.fromSerialized(hexEncodedPublicKey))) { Log.d("Loki - Group Message", "Received a group update message from a non-admin user for " + id +". Ignoring."); return null; } - // We should only process update message if we were in the group + // We should only process update messages if we're in the group Address ourAddress = Address.fromSerialized(ourHexEncodedPublicKey); if (!groupRecord.getMembers().contains(ourAddress) && !group.getMembers().or(Collections.emptyList()).contains(ourHexEncodedPublicKey)) { - Log.d("Loki - Group Message", "Received a group update message from a group we are not members in: " + id + " . Ignoring."); + Log.d("Loki - Group Message", "Received a group update message from a group we are not a member of: " + id + "; ignoring."); database.setActive(id, false); return null; } @@ -181,7 +181,7 @@ public class GroupMessageProcessor { } // We add any new or removed members to the group context - // This will allow us later to iterate over them to check if they left or were added for UI display + // This will allow us later to iterate over them to check if they left or were added for UI purposes for (Address addedMember : addedMembers) { builder.addNewMembers(addedMember.serialize()); } diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index c421e3ba8b..96d76d818c 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -1898,7 +1898,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { boolean isClosedGroup = conversation.getAddress().isSignalGroup(); boolean isGroupMember = true; - // Only allow messages from members of a group + // Only allow messages from group members if (isClosedGroup) { String senderHexEncodedPublicKey = content.getSender(); @@ -1911,9 +1911,9 @@ public class PushDecryptJob extends BaseJob implements InjectableType { e.printStackTrace(); } - Recipient senderMaster = Recipient.from(context, Address.fromSerialized(senderHexEncodedPublicKey), false); + Recipient senderMasterAddress = Recipient.from(context, Address.fromSerialized(senderHexEncodedPublicKey), false); - isGroupMember = groupId.isPresent() && groupDatabase.getGroupMembers(groupId.get(), true).contains(senderMaster); + isGroupMember = groupId.isPresent() && groupDatabase.getGroupMembers(groupId.get(), true).contains(senderMasterAddress); } return (isContentMessage && !isGroupActive) || (sender.isBlocked() && !isLeaveMessage) || (isContentMessage && !isGroupMember); From 8ea2fe0294627ef196282121271cce29f58c0631 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 15 Apr 2020 15:03:57 +1000 Subject: [PATCH 11/25] add update token guard and move acknowledgement to signal service --- .../loki/LokiPushNotificationManager.kt | 32 ++++--------------- .../messaging/BackgroundPollWorker.kt | 3 +- .../securesms/util/TextSecurePreferences.java | 19 +++++++++++ 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/src/org/thoughtcrime/securesms/loki/LokiPushNotificationManager.kt b/src/org/thoughtcrime/securesms/loki/LokiPushNotificationManager.kt index 8378519412..4858e2c818 100644 --- a/src/org/thoughtcrime/securesms/loki/LokiPushNotificationManager.kt +++ b/src/org/thoughtcrime/securesms/loki/LokiPushNotificationManager.kt @@ -10,7 +10,7 @@ import java.io.IOException object LokiPushNotificationManager { //const val server = "https://live.apns.getsession.org/" const val server = "https://dev.apns.getsession.org/" - const val tokenExpirationInterval = 2 * 24 * 60 * 60 + const val tokenExpirationInterval = 2 * 24 * 60 * 60 * 1000 private val connection = OkHttpClient() fun disableRemoteNotification(token: String, context: Context?) { @@ -43,6 +43,10 @@ object LokiPushNotificationManager { @JvmStatic fun register(token: String, hexEncodedPublicKey: String, context: Context?) { + if (token == TextSecurePreferences.getTokenForRemoteNotification(context) && System.currentTimeMillis() - TextSecurePreferences.getLastTimeForTokenUploading(context) < tokenExpirationInterval) { + return + } + val parameters = mapOf("token" to token, "pubKey" to hexEncodedPublicKey) val url = "${server}register" val body = RequestBody.create(MediaType.get("application/json"), JsonUtil.toJson(parameters)) @@ -57,6 +61,8 @@ object LokiPushNotificationManager { val code = json?.get("code") as? Int if (code != null && code != 0) { TextSecurePreferences.setIsUsingRemoteNotification(context, true) + TextSecurePreferences.setTokenForRemoteNotification(context, token) + TextSecurePreferences.setLastTimeForTokenUploading(context, System.currentTimeMillis()) } else { Log.d("Loki", "Couldn't register device token due to error: ${json?.get("message") as? String}.") } @@ -70,29 +76,5 @@ object LokiPushNotificationManager { }) } - fun acknowledgeDeliveryForMessageWith(hash: String, expiration: Int, hexEncodedPublicKey: String, context: Context?) { - val parameters = mapOf("hash" to hash, "pubKey" to hexEncodedPublicKey, "expiration" to expiration) - val url = "${server}acknowledge_message_delivery" - val body = RequestBody.create(MediaType.get("application/json"), JsonUtil.toJson(parameters)) - val request = Request.Builder().url(url).post(body).build() - connection.newCall(request).enqueue(object : Callback { - override fun onResponse(call: Call, response: Response) { - when (response.code()) { - 200 -> { - val bodyAsString = response.body()!!.string() - val json = JsonUtil.fromJson(bodyAsString, Map::class.java) - val code = json?.get("code") as? Int - if (code == null || code == 0) { - Log.d("Loki", "Couldn't acknowledge the delivery for message due to error: ${json?.get("message") as? String}.") - } - } - } - } - - override fun onFailure(call: Call, exception: IOException) { - Log.d("Loki", "Couldn't acknowledge the delivery for message with last hash: ${hash}") - } - }) - } } diff --git a/src/org/thoughtcrime/securesms/loki/redesign/messaging/BackgroundPollWorker.kt b/src/org/thoughtcrime/securesms/loki/redesign/messaging/BackgroundPollWorker.kt index 53cd42c29e..7205e624de 100644 --- a/src/org/thoughtcrime/securesms/loki/redesign/messaging/BackgroundPollWorker.kt +++ b/src/org/thoughtcrime/securesms/loki/redesign/messaging/BackgroundPollWorker.kt @@ -6,6 +6,7 @@ import nl.komponents.kovenant.functional.map import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.jobs.PushContentReceiveJob +import org.thoughtcrime.securesms.loki.LokiPushNotificationManager import org.thoughtcrime.securesms.service.PersistentAlarmManagerListener import org.thoughtcrime.securesms.util.TextSecurePreferences import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope @@ -15,7 +16,7 @@ import java.util.concurrent.TimeUnit class BackgroundPollWorker : PersistentAlarmManagerListener() { companion object { - private val pollInterval = TimeUnit.MINUTES.toMillis(20) + private val pollInterval = TimeUnit.MINUTES.toMillis(2) @JvmStatic fun schedule(context: Context) { diff --git a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java index 62fc6c258e..c1fbd89b25 100644 --- a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java +++ b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java @@ -185,7 +185,10 @@ public class TextSecurePreferences { private static final String MEDIA_KEYBOARD_MODE = "pref_media_keyboard_mode"; + //Session for Push Notification private static final String IS_USING_REMOTE_NOTIFICATION = "pref_is_using_remote_notification"; + private static final String TOKEN_FOR_REMOTE_NOTIFICATION = "pref_token_for_remote_notification"; + private static final String LAST_TIME_FOR_TOKEN_UPLOADING = "pref_last_time_for_token_uploading"; public static boolean isUsingRemoteNotification(Context context) { return getBooleanPreference(context, IS_USING_REMOTE_NOTIFICATION, false); @@ -195,6 +198,22 @@ public class TextSecurePreferences { setBooleanPreference(context, IS_USING_REMOTE_NOTIFICATION, value); } + public static String getTokenForRemoteNotification(Context context) { + return getStringPreference(context, TOKEN_FOR_REMOTE_NOTIFICATION, ""); + } + + public static void setTokenForRemoteNotification(Context context, String value) { + setStringPreference(context, TOKEN_FOR_REMOTE_NOTIFICATION, value); + } + + public static long getLastTimeForTokenUploading(Context context) { + return getLongPreference(context, LAST_TIME_FOR_TOKEN_UPLOADING, 0); + } + + public static void setLastTimeForTokenUploading(Context context, long value) { + setLongPreference(context, LAST_TIME_FOR_TOKEN_UPLOADING, value); + } + public static boolean isScreenLockEnabled(@NonNull Context context) { return getBooleanPreference(context, SCREEN_LOCK, false); } From c09032900feccb40719cdd90348c942148697c7b Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Thu, 16 Apr 2020 14:49:23 +1000 Subject: [PATCH 12/25] Implement PN mode screen UI --- AndroidManifest.xml | 3 + res/drawable/pn_option_background.xml | 15 +++ ..._option_background_deselect_transition.xml | 5 + ...pn_option_background_select_transition.xml | 5 + .../pn_option_background_selected.xml | 15 +++ res/layout-sw400dp/activity_pn_mode.xml | 116 ++++++++++++++++++ res/layout/activity_pn_mode.xml | 116 ++++++++++++++++++ res/values/colors.xml | 2 + res/values/dimens.xml | 1 + res/values/strings.xml | 8 ++ .../redesign/activities/PNModeActivity.kt | 77 ++++++++++++ 11 files changed, 363 insertions(+) create mode 100644 res/drawable/pn_option_background.xml create mode 100644 res/drawable/pn_option_background_deselect_transition.xml create mode 100644 res/drawable/pn_option_background_select_transition.xml create mode 100644 res/drawable/pn_option_background_selected.xml create mode 100644 res/layout-sw400dp/activity_pn_mode.xml create mode 100644 res/layout/activity_pn_mode.xml create mode 100644 src/org/thoughtcrime/securesms/loki/redesign/activities/PNModeActivity.kt diff --git a/AndroidManifest.xml b/AndroidManifest.xml index bfa2c456dc..ea4e449167 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -112,6 +112,9 @@ android:name="org.thoughtcrime.securesms.loki.redesign.activities.DisplayNameActivity" android:screenOrientation="portrait" android:windowSoftInputMode="adjustResize" /> + + + + + + + + + + \ No newline at end of file diff --git a/res/drawable/pn_option_background_deselect_transition.xml b/res/drawable/pn_option_background_deselect_transition.xml new file mode 100644 index 0000000000..7fcb8e1160 --- /dev/null +++ b/res/drawable/pn_option_background_deselect_transition.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/pn_option_background_select_transition.xml b/res/drawable/pn_option_background_select_transition.xml new file mode 100644 index 0000000000..21c58cf71d --- /dev/null +++ b/res/drawable/pn_option_background_select_transition.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/pn_option_background_selected.xml b/res/drawable/pn_option_background_selected.xml new file mode 100644 index 0000000000..56d1ed983a --- /dev/null +++ b/res/drawable/pn_option_background_selected.xml @@ -0,0 +1,15 @@ + + + + + + + + + + \ No newline at end of file diff --git a/res/layout-sw400dp/activity_pn_mode.xml b/res/layout-sw400dp/activity_pn_mode.xml new file mode 100644 index 0000000000..8edc9267df --- /dev/null +++ b/res/layout-sw400dp/activity_pn_mode.xml @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +