Skip to content
Merged

0.2.0 #124

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
adf3d73
Modified a layout of the navigation header. | #76.
DenBond7 Oct 3, 2017
8a2a6ae
Renamed AddNewAccountActivity to AddNewAccountManuallyActivity. | #76.
DenBond7 Oct 5, 2017
56587ed
Added AddNewAccountActivity. Added switching between accounts (as a t…
DenBond7 Oct 5, 2017
e2800f4
Added BaseSignInActivity. Added the Google Sign-in option on the add …
DenBond7 Oct 9, 2017
d919184
Added sign out function for all accounts. Removed "Revoke Access" in …
DenBond7 Oct 9, 2017
ec05cf1
Fixed NPE in EmailSyncManager.
DenBond7 Oct 9, 2017
1806f28
Fixed handle "Use another account".Refactored code. | #76.
DenBond7 Oct 9, 2017
2daacc2
Modified the app startup logic. | #76.
DenBond7 Oct 9, 2017
1f9bc18
Fixed a bug when return back from the check private keys screen. | #76.
DenBond7 Oct 9, 2017
53d2e8d
Fixed a bug when try to search Gmail backups.
DenBond7 Oct 10, 2017
57037f3
Merge branch '0.0.9' into switch_beetwen_accounts
DenBond7 Oct 10, 2017
9089366
Merge branch 'master' into switch_beetwen_accounts
DenBond7 Oct 11, 2017
907ef1d
Fixed a bug after merge.
DenBond7 Oct 11, 2017
5c8aa1e
Added a search private keys backups for other email providers. | #76.
DenBond7 Oct 12, 2017
128a7a0
Renamed content_add_new_account.xml
DenBond7 Oct 12, 2017
478c6c4
Added a search private keys backups for Gmail accounts when add a new…
DenBond7 Oct 12, 2017
9d096f5
Fixed a bug with receive a reply from the EmailSyncService | #76.
DenBond7 Oct 12, 2017
b147085
Fixed show an error hint when try to add an exist private key. | #76.
DenBond7 Oct 12, 2017
8b0fb74
Excluded ReportField.SHARED_PREFERENCES from the crash reports. | Clo…
DenBond7 Oct 12, 2017
128018e
Fixed login into Gmail accounts from the main screen. | #76, #114.
DenBond7 Oct 13, 2017
253e50a
decrypting non-armored files | #118
Oct 16, 2017
a72957c
pgpDecrypted.getString instead of getContent | #118
Oct 16, 2017
ad688a7
added pgpDecrypted.countAttempts() | #104
Oct 16, 2017
919c857
add flowcrypt version to pgp armor | close #116
Oct 16, 2017
b8ea2cb
Fixed an option when we trying to add a new account with existing key…
DenBond7 Oct 16, 2017
4a4643f
Fixed NPE in EmailSyncService.
DenBond7 Oct 16, 2017
262e9e4
Added decryption of attachments. | #118.
DenBond7 Oct 16, 2017
889caf9
Added NotificationChannelManager to support notifications on Android …
DenBond7 Oct 17, 2017
babbc7d
Added limitation for decryption files. | #118.
DenBond7 Oct 17, 2017
0a7580e
Changed the encryption logic. | Close #106.
DenBond7 Oct 19, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ captures/
*.iml
.idea/workspace.xml
.idea/libraries
.idea/misc.xml

# Keystore files
*.jks
5 changes: 5 additions & 0 deletions FlowCrypt/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@
android:label="@string/app_name"
android:screenOrientation="portrait" />

<activity
android:name=".ui.activity.AddNewAccountManuallyActivity"
android:label="@string/adding_new_account"
android:screenOrientation="portrait" />

<activity
android:name=".ui.activity.AddNewAccountActivity"
android:label="@string/adding_new_account"
Expand Down
22 changes: 14 additions & 8 deletions FlowCrypt/src/main/assets/js/tool.js
Original file line number Diff line number Diff line change
Expand Up @@ -2032,16 +2032,22 @@
}

function crypto_message_decrypt(db, account_email, encrypted_data, one_time_message_password, callback, force_output_format) {
var armored_encrypted = tool.value(crypto_armor_headers('message').begin).in(encrypted_data);
var armored_signed_only = tool.value(crypto_armor_headers('signed_message').begin).in(encrypted_data);
var armored_encrypted = false;
var armored_signed_only = false;
var other_errors = [];
try {
if(armored_encrypted) {
var message = openpgp.message.readArmored(encrypted_data);
} else if(armored_signed_only) {
var message = openpgp.cleartext.readArmored(encrypted_data);
if (encrypted_data instanceof Uint8Array) {
var message = openpgp.message.read(encrypted_data);
} else {
var message = openpgp.message.read(tool.str.to_uint8(encrypted_data));
armored_encrypted = tool.value(crypto_armor_headers('message').begin).in(encrypted_data);
armored_signed_only = !armored_encrypted && tool.value(crypto_armor_headers('signed_message').begin).in(encrypted_data);
if(armored_encrypted) {
var message = openpgp.message.readArmored(encrypted_data);
} else if(armored_signed_only) {
var message = openpgp.cleartext.readArmored(encrypted_data);
} else {
var message = openpgp.message.read(tool.str.to_uint8(encrypted_data));
}
}
} catch(format_error) {
callback({success: false, counts: zeroed_decrypt_error_counts(), format_error: format_error.message, errors: other_errors, encrypted: null, signature: null});
Expand Down Expand Up @@ -3899,7 +3905,7 @@
(function ( /* EXTENSIONS AND CONFIG */ ) {

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

Expand Down
10 changes: 10 additions & 0 deletions FlowCrypt/src/main/java/com/flowcrypt/email/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,14 @@ public class Constants {

public static final String PREFERENCES_KEY_TEMP_LAST_AUTH_CREDENTIALS =
"preferences_key_temp_last_auth_credentials";

/**
* The max total size off all attachment which can be send via the app.
*/
public static final int MAX_TOTAL_ATTACHMENT_SIZE_IN_BYTES = 1024 * 1024 * 3;

/**
* The max size off an attachment which can be decrypted via the app.
*/
public static final int MAX_ATTACHMENT_SIZE_WHICH_CAN_BE_DECRYPTED = 1024 * 1024 * 3;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@
import android.support.v4.app.FragmentManager;
import android.support.v7.preference.PreferenceManager;

import com.flowcrypt.email.ui.NotificationChannelManager;
import com.flowcrypt.email.util.SharedPreferencesHelper;
import com.squareup.leakcanary.LeakCanary;

import org.acra.ACRA;
import org.acra.ReportField;
import org.acra.annotation.ReportsCrashes;
import org.acra.sender.HttpSender;

Expand All @@ -28,13 +30,44 @@
*/
@ReportsCrashes(
formUri = "https://api.cryptup.io/help/acra",
customReportContent = {
ReportField.ANDROID_VERSION,
ReportField.APP_VERSION_CODE,
ReportField.APP_VERSION_NAME,
ReportField.AVAILABLE_MEM_SIZE,
ReportField.BRAND,
ReportField.BUILD,
ReportField.BUILD_CONFIG,
ReportField.CRASH_CONFIGURATION,
ReportField.CUSTOM_DATA,
ReportField.DEVICE_FEATURES,
ReportField.DISPLAY,
ReportField.DUMPSYS_MEMINFO,
ReportField.ENVIRONMENT,
ReportField.FILE_PATH,
ReportField.INITIAL_CONFIGURATION,
ReportField.INSTALLATION_ID,
ReportField.IS_SILENT,
ReportField.LOGCAT,
ReportField.PACKAGE_NAME,
ReportField.PHONE_MODEL,
ReportField.PRODUCT,
ReportField.REPORT_ID,
ReportField.STACK_TRACE,
ReportField.TOTAL_MEM_SIZE,
ReportField.USER_APP_START_DATE,
ReportField.USER_CRASH_DATE,
ReportField.USER_EMAIL
},
httpMethod = HttpSender.Method.POST,
reportType = HttpSender.Type.JSON)
public class FlowCryptApplication extends Application {

@Override
public void onCreate() {
super.onCreate();
NotificationChannelManager.registerNotificationChannels(this);

intiLeakCanary();
FragmentManager.enableDebugLogging(BuildConfig.DEBUG);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import com.flowcrypt.email.api.email.sync.tasks.UpdateLabelsSyncTask;
import com.flowcrypt.email.database.dao.source.AccountDao;
import com.google.android.gms.auth.GoogleAuthException;
import com.sun.mail.gimap.GmailSSLStore;

import java.io.IOException;
import java.util.Iterator;
Expand All @@ -38,9 +37,9 @@
import javax.mail.Store;

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

public EmailSyncManager(AccountDao accountDao) {
this.accountDao = accountDao;
Expand All @@ -79,7 +79,7 @@ public EmailSyncManager(AccountDao accountDao) {
public void beginSync(boolean isNeedReset) {
Log.d(TAG, "beginSync | isNeedReset = " + isNeedReset);
if (isNeedReset) {
stopSync();
resetSync();
}

if (!isSyncThreadAlreadyWork()) {
Expand All @@ -101,11 +101,7 @@ public boolean isSyncThreadAlreadyWork() {
* Stop a synchronization.
*/
public void stopSync() {
cancelAllSyncTask();

if (syncTaskRunnableFuture != null) {
syncTaskRunnableFuture.cancel(true);
}
resetSync();

if (executorService != null) {
executorService.shutdown();
Expand Down Expand Up @@ -298,6 +294,23 @@ public AccountDao getAccountDao() {
return accountDao;
}

public void setAccount(AccountDao accountDao) {
this.accountDao = accountDao;
}

/**
* Reset a synchronization.
*/
private void resetSync() {
cancelAllSyncTask();

if (syncTaskRunnableFuture != null) {
syncTaskRunnableFuture.cancel(true);
}

isNeedToResetConnection = true;
}

/**
* Remove the old tasks from the queue of synchronization.
*
Expand Down Expand Up @@ -326,6 +339,14 @@ public void run() {

if (syncTask != null) {
try {
if (isNeedToResetConnection) {
isNeedToResetConnection = false;
if (store != null) {
store.close();
}
session = null;
}

if (!isConnected()) {
Log.d(TAG, "Not connected. Start a reconnection ...");
openConnectionToStore();
Expand Down Expand Up @@ -366,24 +387,13 @@ private void openConnectionToStore() throws IOException,
}

/**
* Check available connection to the gmail store.
* Check available connection to the store.
* Must be called from non-main thread.
*
* @return trus if connected, false otherwise.
*/
private boolean isConnected() {
return store != null && store.isConnected();
}

/**
* Check available connection to the gmail store. If connection does not exists try to
* reconnect.
* Must be called from non-main thread.
*/
private void checkConnection() throws GoogleAuthException, IOException, MessagingException {
if (!isConnected()) {
openConnectionToStore();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public void runSMTPAction(AccountDao accountDao, Session session, Store store, S

updateContactsLastUseDateTime(context);

MimeMessage mimeMessage = createMimeMessage(session, context, pgpCacheDirectory);
MimeMessage mimeMessage = createMimeMessage(session, context, accountDao, pgpCacheDirectory);

Transport transport = prepareTransportForSmtp(syncListener.getContext(), session, accountDao);
transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
Expand Down Expand Up @@ -155,16 +155,16 @@ private void saveCopyOfSentMessage(AccountDao accountDao, Store store, Context c
*
* @param session Will be used to create {@link MimeMessage}
* @param context Interface to global information about an application environment.
* @param pgpCacheDirectory The cache directory which contains temp files.
* @return {@link MimeMessage}
* @param accountDao The {@link AccountDao} which contains information about account.
* @param pgpCacheDirectory The cache directory which contains temp files. @return {@link MimeMessage}
* @throws IOException
* @throws MessagingException
*/
@NonNull
private MimeMessage createMimeMessage(Session session, Context context, File pgpCacheDirectory)
throws IOException, MessagingException {
private MimeMessage createMimeMessage(Session session, Context context, AccountDao accountDao,
File pgpCacheDirectory) throws IOException, MessagingException {
Js js = new Js(context, new SecurityStorageConnector(context));
String[] pubKeys = getPubKeys(js, context);
String[] pubKeys = getPubKeys(context, js, accountDao);

String rawMessage = generateRawMessageWithoutAttachments(js, pubKeys);

Expand Down Expand Up @@ -288,42 +288,59 @@ private void updateContactsLastUseDateTime(Context context) {
/**
* Get public keys for recipients + keys of the sender;
*
* @param js - {@link Js} util class.
* @param context - Interface to global information about an application environment.
* @param context Interface to global information about an application environment.
* @param accountDao The {@link AccountDao} which contains information about account.
* @param js - {@link Js} util class.
* @return <tt>String[]</tt> An array of public keys.
*/
private String[] getPubKeys(Js js, Context context) {
private String[] getPubKeys(Context context, Js js, AccountDao accountDao) {
ArrayList<String> publicKeys = new ArrayList<>();
for (PgpContact pgpContact : outgoingMessageInfo.getToPgpContacts()) {
if (!TextUtils.isEmpty(pgpContact.getPubkey())) {
publicKeys.add(pgpContact.getPubkey());
}
}

publicKeys.addAll(generateOwnPublicKeys(js, context));
publicKeys.add(getAccountPublicKey(context, js, accountDao));

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

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

SecurityStorageConnector securityStorageConnector = new SecurityStorageConnector(context);
PgpKeyInfo[] pgpKeyInfoArray = securityStorageConnector.getAllPgpPrivateKeys();
if (pgpContact != null && !TextUtils.isEmpty(pgpContact.getPubkey())) {
return pgpContact.getPubkey();
}

PgpKeyInfo[] pgpKeyInfoArray = new SecurityStorageConnector(context).getAllPgpPrivateKeys();
for (PgpKeyInfo pgpKeyInfo : pgpKeyInfoArray) {
PgpKey pgpKey = js.crypto_key_read(pgpKeyInfo.getArmored());
publicKeys.add(pgpKey.toPublic().armor());
if (pgpKey != null) {
PgpKey publicKey = pgpKey.toPublic();
if (publicKey != null) {
PgpContact primaryUserId = pgpKey.getPrimaryUserId();
if (primaryUserId != null) {
if (!TextUtils.isEmpty(publicKey.armor())) {
primaryUserId.setPubkey(publicKey.armor());
new ContactsDaoSource().addRow(context, primaryUserId);
return primaryUserId.getPubkey();
}
break;
}
}
}
}

return publicKeys;
throw new IllegalArgumentException("The sender doesn't have a public key");
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.Nullable;
import android.text.TextUtils;

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

Expand Down Expand Up @@ -47,7 +48,13 @@ public AccountDao[] newArray(int size) {
public AccountDao(String email, String accountType, String displayName, String givenName,
String familyName, String photoUrl, AuthCredentials authCredentials) {
this.email = email;
this.accountType = accountType;
if (TextUtils.isEmpty(accountType)) {
if (!TextUtils.isEmpty(email)) {
this.accountType = email.substring(email.indexOf('@') + 1, email.length());
}
} else {
this.accountType = accountType;
}
this.displayName = displayName;
this.givenName = givenName;
this.familyName = familyName;
Expand Down
Loading