Skip to content

Commit 94d2f83

Browse files
authored
Merge pull request #124 from FlowCrypt/0.2.0
0.2.0
2 parents db99ea3 + 0a7580e commit 94d2f83

File tree

54 files changed

+2492
-1407
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+2492
-1407
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ captures/
3030
*.iml
3131
.idea/workspace.xml
3232
.idea/libraries
33+
.idea/misc.xml
3334

3435
# Keystore files
3536
*.jks

FlowCrypt/src/main/AndroidManifest.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@
106106
android:label="@string/app_name"
107107
android:screenOrientation="portrait" />
108108

109+
<activity
110+
android:name=".ui.activity.AddNewAccountManuallyActivity"
111+
android:label="@string/adding_new_account"
112+
android:screenOrientation="portrait" />
113+
109114
<activity
110115
android:name=".ui.activity.AddNewAccountActivity"
111116
android:label="@string/adding_new_account"

FlowCrypt/src/main/assets/js/tool.js

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2032,16 +2032,22 @@
20322032
}
20332033

20342034
function crypto_message_decrypt(db, account_email, encrypted_data, one_time_message_password, callback, force_output_format) {
2035-
var armored_encrypted = tool.value(crypto_armor_headers('message').begin).in(encrypted_data);
2036-
var armored_signed_only = tool.value(crypto_armor_headers('signed_message').begin).in(encrypted_data);
2035+
var armored_encrypted = false;
2036+
var armored_signed_only = false;
20372037
var other_errors = [];
20382038
try {
2039-
if(armored_encrypted) {
2040-
var message = openpgp.message.readArmored(encrypted_data);
2041-
} else if(armored_signed_only) {
2042-
var message = openpgp.cleartext.readArmored(encrypted_data);
2039+
if (encrypted_data instanceof Uint8Array) {
2040+
var message = openpgp.message.read(encrypted_data);
20432041
} else {
2044-
var message = openpgp.message.read(tool.str.to_uint8(encrypted_data));
2042+
armored_encrypted = tool.value(crypto_armor_headers('message').begin).in(encrypted_data);
2043+
armored_signed_only = !armored_encrypted && tool.value(crypto_armor_headers('signed_message').begin).in(encrypted_data);
2044+
if(armored_encrypted) {
2045+
var message = openpgp.message.readArmored(encrypted_data);
2046+
} else if(armored_signed_only) {
2047+
var message = openpgp.cleartext.readArmored(encrypted_data);
2048+
} else {
2049+
var message = openpgp.message.read(tool.str.to_uint8(encrypted_data));
2050+
}
20452051
}
20462052
} catch(format_error) {
20472053
callback({success: false, counts: zeroed_decrypt_error_counts(), format_error: format_error.message, errors: other_errors, encrypted: null, signature: null});
@@ -3899,7 +3905,7 @@
38993905
(function ( /* EXTENSIONS AND CONFIG */ ) {
39003906

39013907
if(typeof window.openpgp !== 'undefined' && typeof window.openpgp.config !== 'undefined' && typeof window.openpgp.config.versionstring !== 'undefined' && typeof window.openpgp.config.commentstring !== 'undefined') {
3902-
window.openpgp.config.versionstring = 'CryptUp ' + (catcher.version() || '') + ' Gmail Encryption https://cryptup.org';
3908+
window.openpgp.config.versionstring = 'FlowCrypt ' + (catcher.version() || '') + ' Email Encryption: flowcrypt.com';
39033909
window.openpgp.config.commentstring = 'Seamlessly send, receive and search encrypted email';
39043910
}
39053911

FlowCrypt/src/main/java/com/flowcrypt/email/Constants.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,14 @@ public class Constants {
4444

4545
public static final String PREFERENCES_KEY_TEMP_LAST_AUTH_CREDENTIALS =
4646
"preferences_key_temp_last_auth_credentials";
47+
48+
/**
49+
* The max total size off all attachment which can be send via the app.
50+
*/
51+
public static final int MAX_TOTAL_ATTACHMENT_SIZE_IN_BYTES = 1024 * 1024 * 3;
52+
53+
/**
54+
* The max size off an attachment which can be decrypted via the app.
55+
*/
56+
public static final int MAX_ATTACHMENT_SIZE_WHICH_CAN_BE_DECRYPTED = 1024 * 1024 * 3;
4757
}

FlowCrypt/src/main/java/com/flowcrypt/email/FlowCryptApplication.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111
import android.support.v4.app.FragmentManager;
1212
import android.support.v7.preference.PreferenceManager;
1313

14+
import com.flowcrypt.email.ui.NotificationChannelManager;
1415
import com.flowcrypt.email.util.SharedPreferencesHelper;
1516
import com.squareup.leakcanary.LeakCanary;
1617

1718
import org.acra.ACRA;
19+
import org.acra.ReportField;
1820
import org.acra.annotation.ReportsCrashes;
1921
import org.acra.sender.HttpSender;
2022

@@ -28,13 +30,44 @@
2830
*/
2931
@ReportsCrashes(
3032
formUri = "https://api.cryptup.io/help/acra",
33+
customReportContent = {
34+
ReportField.ANDROID_VERSION,
35+
ReportField.APP_VERSION_CODE,
36+
ReportField.APP_VERSION_NAME,
37+
ReportField.AVAILABLE_MEM_SIZE,
38+
ReportField.BRAND,
39+
ReportField.BUILD,
40+
ReportField.BUILD_CONFIG,
41+
ReportField.CRASH_CONFIGURATION,
42+
ReportField.CUSTOM_DATA,
43+
ReportField.DEVICE_FEATURES,
44+
ReportField.DISPLAY,
45+
ReportField.DUMPSYS_MEMINFO,
46+
ReportField.ENVIRONMENT,
47+
ReportField.FILE_PATH,
48+
ReportField.INITIAL_CONFIGURATION,
49+
ReportField.INSTALLATION_ID,
50+
ReportField.IS_SILENT,
51+
ReportField.LOGCAT,
52+
ReportField.PACKAGE_NAME,
53+
ReportField.PHONE_MODEL,
54+
ReportField.PRODUCT,
55+
ReportField.REPORT_ID,
56+
ReportField.STACK_TRACE,
57+
ReportField.TOTAL_MEM_SIZE,
58+
ReportField.USER_APP_START_DATE,
59+
ReportField.USER_CRASH_DATE,
60+
ReportField.USER_EMAIL
61+
},
3162
httpMethod = HttpSender.Method.POST,
3263
reportType = HttpSender.Type.JSON)
3364
public class FlowCryptApplication extends Application {
3465

3566
@Override
3667
public void onCreate() {
3768
super.onCreate();
69+
NotificationChannelManager.registerNotificationChannels(this);
70+
3871
intiLeakCanary();
3972
FragmentManager.enableDebugLogging(BuildConfig.DEBUG);
4073
}

FlowCrypt/src/main/java/com/flowcrypt/email/api/email/sync/EmailSyncManager.java

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import com.flowcrypt.email.api.email.sync.tasks.UpdateLabelsSyncTask;
2323
import com.flowcrypt.email.database.dao.source.AccountDao;
2424
import com.google.android.gms.auth.GoogleAuthException;
25-
import com.sun.mail.gimap.GmailSSLStore;
2625

2726
import java.io.IOException;
2827
import java.util.Iterator;
@@ -38,9 +37,9 @@
3837
import javax.mail.Store;
3938

4039
/**
41-
* This class describes a logic of work with {@link GmailSSLStore} for the single account. Via
40+
* This class describes a logic of work with {@link Store} for the single account. Via
4241
* this class we can retrieve a new information from the server and send a data to the server.
43-
* Here we open a new connection to the {@link GmailSSLStore} and keep it alive. This class does
42+
* Here we open a new connection to the {@link Store} and keep it alive. This class does
4443
* all job to communicate with IMAP server.
4544
*
4645
* @author DenBond7
@@ -63,6 +62,7 @@ public class EmailSyncManager {
6362
private volatile Session session;
6463
private volatile Store store;
6564
private volatile AccountDao accountDao;
65+
private boolean isNeedToResetConnection;
6666

6767
public EmailSyncManager(AccountDao accountDao) {
6868
this.accountDao = accountDao;
@@ -79,7 +79,7 @@ public EmailSyncManager(AccountDao accountDao) {
7979
public void beginSync(boolean isNeedReset) {
8080
Log.d(TAG, "beginSync | isNeedReset = " + isNeedReset);
8181
if (isNeedReset) {
82-
stopSync();
82+
resetSync();
8383
}
8484

8585
if (!isSyncThreadAlreadyWork()) {
@@ -101,11 +101,7 @@ public boolean isSyncThreadAlreadyWork() {
101101
* Stop a synchronization.
102102
*/
103103
public void stopSync() {
104-
cancelAllSyncTask();
105-
106-
if (syncTaskRunnableFuture != null) {
107-
syncTaskRunnableFuture.cancel(true);
108-
}
104+
resetSync();
109105

110106
if (executorService != null) {
111107
executorService.shutdown();
@@ -298,6 +294,23 @@ public AccountDao getAccountDao() {
298294
return accountDao;
299295
}
300296

297+
public void setAccount(AccountDao accountDao) {
298+
this.accountDao = accountDao;
299+
}
300+
301+
/**
302+
* Reset a synchronization.
303+
*/
304+
private void resetSync() {
305+
cancelAllSyncTask();
306+
307+
if (syncTaskRunnableFuture != null) {
308+
syncTaskRunnableFuture.cancel(true);
309+
}
310+
311+
isNeedToResetConnection = true;
312+
}
313+
301314
/**
302315
* Remove the old tasks from the queue of synchronization.
303316
*
@@ -326,6 +339,14 @@ public void run() {
326339

327340
if (syncTask != null) {
328341
try {
342+
if (isNeedToResetConnection) {
343+
isNeedToResetConnection = false;
344+
if (store != null) {
345+
store.close();
346+
}
347+
session = null;
348+
}
349+
329350
if (!isConnected()) {
330351
Log.d(TAG, "Not connected. Start a reconnection ...");
331352
openConnectionToStore();
@@ -366,24 +387,13 @@ private void openConnectionToStore() throws IOException,
366387
}
367388

368389
/**
369-
* Check available connection to the gmail store.
390+
* Check available connection to the store.
370391
* Must be called from non-main thread.
371392
*
372393
* @return trus if connected, false otherwise.
373394
*/
374395
private boolean isConnected() {
375396
return store != null && store.isConnected();
376397
}
377-
378-
/**
379-
* Check available connection to the gmail store. If connection does not exists try to
380-
* reconnect.
381-
* Must be called from non-main thread.
382-
*/
383-
private void checkConnection() throws GoogleAuthException, IOException, MessagingException {
384-
if (!isConnected()) {
385-
openConnectionToStore();
386-
}
387-
}
388398
}
389399
}

FlowCrypt/src/main/java/com/flowcrypt/email/api/email/sync/tasks/SendMessageSyncTask.java

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ public void runSMTPAction(AccountDao accountDao, Session session, Store store, S
103103

104104
updateContactsLastUseDateTime(context);
105105

106-
MimeMessage mimeMessage = createMimeMessage(session, context, pgpCacheDirectory);
106+
MimeMessage mimeMessage = createMimeMessage(session, context, accountDao, pgpCacheDirectory);
107107

108108
Transport transport = prepareTransportForSmtp(syncListener.getContext(), session, accountDao);
109109
transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
@@ -155,16 +155,16 @@ private void saveCopyOfSentMessage(AccountDao accountDao, Store store, Context c
155155
*
156156
* @param session Will be used to create {@link MimeMessage}
157157
* @param context Interface to global information about an application environment.
158-
* @param pgpCacheDirectory The cache directory which contains temp files.
159-
* @return {@link MimeMessage}
158+
* @param accountDao The {@link AccountDao} which contains information about account.
159+
* @param pgpCacheDirectory The cache directory which contains temp files. @return {@link MimeMessage}
160160
* @throws IOException
161161
* @throws MessagingException
162162
*/
163163
@NonNull
164-
private MimeMessage createMimeMessage(Session session, Context context, File pgpCacheDirectory)
165-
throws IOException, MessagingException {
164+
private MimeMessage createMimeMessage(Session session, Context context, AccountDao accountDao,
165+
File pgpCacheDirectory) throws IOException, MessagingException {
166166
Js js = new Js(context, new SecurityStorageConnector(context));
167-
String[] pubKeys = getPubKeys(js, context);
167+
String[] pubKeys = getPubKeys(context, js, accountDao);
168168

169169
String rawMessage = generateRawMessageWithoutAttachments(js, pubKeys);
170170

@@ -288,42 +288,59 @@ private void updateContactsLastUseDateTime(Context context) {
288288
/**
289289
* Get public keys for recipients + keys of the sender;
290290
*
291-
* @param js - {@link Js} util class.
292-
* @param context - Interface to global information about an application environment.
291+
* @param context Interface to global information about an application environment.
292+
* @param accountDao The {@link AccountDao} which contains information about account.
293+
* @param js - {@link Js} util class.
293294
* @return <tt>String[]</tt> An array of public keys.
294295
*/
295-
private String[] getPubKeys(Js js, Context context) {
296+
private String[] getPubKeys(Context context, Js js, AccountDao accountDao) {
296297
ArrayList<String> publicKeys = new ArrayList<>();
297298
for (PgpContact pgpContact : outgoingMessageInfo.getToPgpContacts()) {
298299
if (!TextUtils.isEmpty(pgpContact.getPubkey())) {
299300
publicKeys.add(pgpContact.getPubkey());
300301
}
301302
}
302303

303-
publicKeys.addAll(generateOwnPublicKeys(js, context));
304+
publicKeys.add(getAccountPublicKey(context, js, accountDao));
304305

305306
return publicKeys.toArray(new String[0]);
306307
}
307308

308309
/**
309-
* Get public keys of the sender;
310+
* Get a public key of the sender;
310311
*
311-
* @param js - {@link Js} util class.
312-
* @param context - Interface to global information about an application environment.
313-
* @return <tt>String[]</tt> An array of the sender public keys.
312+
* @param context Interface to global information about an application environment.
313+
* @param js {@link Js} util class.
314+
* @param accountDao The {@link AccountDao} which contains information about account.
315+
* @return <tt>String</tt> The sender public key.
314316
*/
315-
private ArrayList<String> generateOwnPublicKeys(Js js, Context context) {
316-
ArrayList<String> publicKeys = new ArrayList<>();
317+
private String getAccountPublicKey(Context context, Js js, AccountDao accountDao) {
318+
PgpContact pgpContact = new ContactsDaoSource().getPgpContact(context, accountDao.getEmail());
317319

318-
SecurityStorageConnector securityStorageConnector = new SecurityStorageConnector(context);
319-
PgpKeyInfo[] pgpKeyInfoArray = securityStorageConnector.getAllPgpPrivateKeys();
320+
if (pgpContact != null && !TextUtils.isEmpty(pgpContact.getPubkey())) {
321+
return pgpContact.getPubkey();
322+
}
320323

324+
PgpKeyInfo[] pgpKeyInfoArray = new SecurityStorageConnector(context).getAllPgpPrivateKeys();
321325
for (PgpKeyInfo pgpKeyInfo : pgpKeyInfoArray) {
322326
PgpKey pgpKey = js.crypto_key_read(pgpKeyInfo.getArmored());
323-
publicKeys.add(pgpKey.toPublic().armor());
327+
if (pgpKey != null) {
328+
PgpKey publicKey = pgpKey.toPublic();
329+
if (publicKey != null) {
330+
PgpContact primaryUserId = pgpKey.getPrimaryUserId();
331+
if (primaryUserId != null) {
332+
if (!TextUtils.isEmpty(publicKey.armor())) {
333+
primaryUserId.setPubkey(publicKey.armor());
334+
new ContactsDaoSource().addRow(context, primaryUserId);
335+
return primaryUserId.getPubkey();
336+
}
337+
break;
338+
}
339+
}
340+
}
324341
}
325342

326-
return publicKeys;
343+
throw new IllegalArgumentException("The sender doesn't have a public key");
327344
}
328345

329346
/**

FlowCrypt/src/main/java/com/flowcrypt/email/database/dao/source/AccountDao.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import android.os.Parcel;
1111
import android.os.Parcelable;
1212
import android.support.annotation.Nullable;
13+
import android.text.TextUtils;
1314

1415
import com.flowcrypt.email.api.email.model.AuthCredentials;
1516

@@ -47,7 +48,13 @@ public AccountDao[] newArray(int size) {
4748
public AccountDao(String email, String accountType, String displayName, String givenName,
4849
String familyName, String photoUrl, AuthCredentials authCredentials) {
4950
this.email = email;
50-
this.accountType = accountType;
51+
if (TextUtils.isEmpty(accountType)) {
52+
if (!TextUtils.isEmpty(email)) {
53+
this.accountType = email.substring(email.indexOf('@') + 1, email.length());
54+
}
55+
} else {
56+
this.accountType = accountType;
57+
}
5158
this.displayName = displayName;
5259
this.givenName = givenName;
5360
this.familyName = familyName;

0 commit comments

Comments
 (0)