initial UI work to allow setting up accounts from certifcates
This commit is contained in:
parent
ef605e4cbd
commit
b23cb5a9e4
|
@ -29,6 +29,7 @@ dependencies {
|
|||
compile project(':libs:MemorizingTrustManager')
|
||||
compile 'com.android.support:support-v13:23.0.1'
|
||||
compile 'org.bouncycastle:bcprov-jdk15on:1.52'
|
||||
compile 'org.bouncycastle:bcmail-jdk15on:1.52'
|
||||
compile 'org.jitsi:org.otr4j:0.22'
|
||||
compile 'org.gnu.inet:libidn:1.15'
|
||||
compile 'com.google.zxing:core:3.2.1'
|
||||
|
|
|
@ -194,18 +194,14 @@ public class Account extends AbstractEntity {
|
|||
return jid.getLocalpart();
|
||||
}
|
||||
|
||||
public void setUsername(final String username) throws InvalidJidException {
|
||||
jid = Jid.fromParts(username, jid.getDomainpart(), jid.getResourcepart());
|
||||
public void setJid(final Jid jid) {
|
||||
this.jid = jid;
|
||||
}
|
||||
|
||||
public Jid getServer() {
|
||||
return jid.toDomainJid();
|
||||
}
|
||||
|
||||
public void setServer(final String server) throws InvalidJidException {
|
||||
jid = Jid.fromParts(jid.getLocalpart(), server, jid.getResourcepart());
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
@ -272,6 +268,14 @@ public class Account extends AbstractEntity {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean setPrivateKeyAlias(String alias) {
|
||||
return setKey("private_key_alias", alias);
|
||||
}
|
||||
|
||||
public String getPrivateKeyAlias() {
|
||||
return getKey("private_key_alias");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentValues getContentValues() {
|
||||
final ContentValues values = new ContentValues();
|
||||
|
|
|
@ -25,6 +25,8 @@ import android.os.PowerManager.WakeLock;
|
|||
import android.os.SystemClock;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.provider.ContactsContract;
|
||||
import android.security.KeyChain;
|
||||
import android.security.KeyChainException;
|
||||
import android.util.Log;
|
||||
import android.util.LruCache;
|
||||
|
||||
|
@ -34,11 +36,22 @@ import net.java.otr4j.session.SessionID;
|
|||
import net.java.otr4j.session.SessionImpl;
|
||||
import net.java.otr4j.session.SessionStatus;
|
||||
|
||||
import org.bouncycastle.asn1.x500.RDN;
|
||||
import org.bouncycastle.asn1.x500.X500Name;
|
||||
import org.bouncycastle.asn1.x500.style.BCStyle;
|
||||
import org.bouncycastle.asn1.x500.style.IETFUtils;
|
||||
import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
|
||||
import org.bouncycastle.jce.PrincipalUtil;
|
||||
import org.bouncycastle.jce.X509Principal;
|
||||
import org.openintents.openpgp.util.OpenPgpApi;
|
||||
import org.openintents.openpgp.util.OpenPgpServiceConnection;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.CertificateParsingException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
@ -1285,6 +1298,43 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
|||
updateAccountUi();
|
||||
}
|
||||
|
||||
public void createAccountFromKey(final String alias, final OnAccountCreated callback) {
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
X509Certificate[] chain = KeyChain.getCertificateChain(XmppConnectionService.this, alias);
|
||||
PrivateKey key = KeyChain.getPrivateKey(XmppConnectionService.this, alias);
|
||||
X500Name x500name = new JcaX509CertificateHolder(chain[0]).getSubject();
|
||||
String email = IETFUtils.valueToString(x500name.getRDNs(BCStyle.EmailAddress)[0].getFirst().getValue());
|
||||
String name = IETFUtils.valueToString(x500name.getRDNs(BCStyle.CN)[0].getFirst().getValue());
|
||||
Jid jid = Jid.fromString(email);
|
||||
if (findAccountByJid(jid) == null) {
|
||||
Account account = new Account(jid, "");
|
||||
account.setPrivateKeyAlias(alias);
|
||||
account.setOption(Account.OPTION_DISABLED, true);
|
||||
createAccount(account);
|
||||
callback.onAccountCreated(account);
|
||||
} else {
|
||||
callback.informUser(R.string.account_already_exists);
|
||||
}
|
||||
} catch (KeyChainException e) {
|
||||
callback.informUser(R.string.unable_to_parse_certificate);
|
||||
} catch (InterruptedException e) {
|
||||
callback.informUser(R.string.unable_to_parse_certificate);
|
||||
e.printStackTrace();
|
||||
} catch (CertificateEncodingException e) {
|
||||
callback.informUser(R.string.unable_to_parse_certificate);
|
||||
e.printStackTrace();
|
||||
} catch (InvalidJidException e) {
|
||||
callback.informUser(R.string.unable_to_parse_certificate);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
|
||||
}
|
||||
|
||||
public void updateAccount(final Account account) {
|
||||
this.statusListener.onStatusChanged(account);
|
||||
databaseBackend.updateAccount(account);
|
||||
|
@ -2699,54 +2749,59 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
|||
}
|
||||
}
|
||||
|
||||
public interface OnMoreMessagesLoaded {
|
||||
public void onMoreMessagesLoaded(int count, Conversation conversation);
|
||||
public interface OnAccountCreated {
|
||||
void onAccountCreated(Account account);
|
||||
void informUser(int r);
|
||||
}
|
||||
|
||||
public void informUser(int r);
|
||||
public interface OnMoreMessagesLoaded {
|
||||
void onMoreMessagesLoaded(int count, Conversation conversation);
|
||||
|
||||
void informUser(int r);
|
||||
}
|
||||
|
||||
public interface OnAccountPasswordChanged {
|
||||
public void onPasswordChangeSucceeded();
|
||||
void onPasswordChangeSucceeded();
|
||||
|
||||
public void onPasswordChangeFailed();
|
||||
void onPasswordChangeFailed();
|
||||
}
|
||||
|
||||
public interface OnAffiliationChanged {
|
||||
public void onAffiliationChangedSuccessful(Jid jid);
|
||||
void onAffiliationChangedSuccessful(Jid jid);
|
||||
|
||||
public void onAffiliationChangeFailed(Jid jid, int resId);
|
||||
void onAffiliationChangeFailed(Jid jid, int resId);
|
||||
}
|
||||
|
||||
public interface OnRoleChanged {
|
||||
public void onRoleChangedSuccessful(String nick);
|
||||
void onRoleChangedSuccessful(String nick);
|
||||
|
||||
public void onRoleChangeFailed(String nick, int resid);
|
||||
void onRoleChangeFailed(String nick, int resid);
|
||||
}
|
||||
|
||||
public interface OnConversationUpdate {
|
||||
public void onConversationUpdate();
|
||||
void onConversationUpdate();
|
||||
}
|
||||
|
||||
public interface OnAccountUpdate {
|
||||
public void onAccountUpdate();
|
||||
void onAccountUpdate();
|
||||
}
|
||||
|
||||
public interface OnRosterUpdate {
|
||||
public void onRosterUpdate();
|
||||
void onRosterUpdate();
|
||||
}
|
||||
|
||||
public interface OnMucRosterUpdate {
|
||||
public void onMucRosterUpdate();
|
||||
void onMucRosterUpdate();
|
||||
}
|
||||
|
||||
public interface OnConferenceConfigurationFetched {
|
||||
public void onConferenceConfigurationFetched(Conversation conversation);
|
||||
void onConferenceConfigurationFetched(Conversation conversation);
|
||||
}
|
||||
|
||||
public interface OnConferenceOptionsPushed {
|
||||
public void onPushSucceeded();
|
||||
void onPushSucceeded();
|
||||
|
||||
public void onPushFailed();
|
||||
void onPushFailed();
|
||||
}
|
||||
|
||||
public interface OnShowErrorToast {
|
||||
|
|
|
@ -74,6 +74,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
|
|||
private LinearLayout keysCard;
|
||||
|
||||
private Jid jidToEdit;
|
||||
private boolean mInitMode = false;
|
||||
private Account mAccount;
|
||||
private String messageFingerprint;
|
||||
|
||||
|
@ -83,6 +84,9 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
|
|||
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
if (mInitMode && mAccount != null) {
|
||||
mAccount.setOption(Account.OPTION_DISABLED, false);
|
||||
}
|
||||
if (mAccount != null && mAccount.getStatus() == Account.State.DISABLED && !accountInfoEdited()) {
|
||||
mAccount.setOption(Account.OPTION_DISABLED, false);
|
||||
xmppConnectionService.updateAccount(mAccount);
|
||||
|
@ -129,12 +133,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
|
|||
}
|
||||
}
|
||||
if (mAccount != null) {
|
||||
try {
|
||||
mAccount.setUsername(jid.hasLocalpart() ? jid.getLocalpart() : "");
|
||||
mAccount.setServer(jid.getDomainpart());
|
||||
} catch (final InvalidJidException ignored) {
|
||||
return;
|
||||
}
|
||||
mAccount.setJid(jid);
|
||||
mAccountJid.setError(null);
|
||||
mPasswordConfirm.setError(null);
|
||||
mAccount.setPassword(password);
|
||||
|
@ -152,9 +151,9 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
|
|||
mAccount.setOption(Account.OPTION_REGISTER, registerNewAccount);
|
||||
xmppConnectionService.createAccount(mAccount);
|
||||
}
|
||||
if (jidToEdit != null
|
||||
&& !mAccount.isOptionSet(Account.OPTION_DISABLED)
|
||||
&& !registerNewAccount) {
|
||||
if (!mAccount.isOptionSet(Account.OPTION_DISABLED)
|
||||
&& !registerNewAccount
|
||||
&& !mInitMode) {
|
||||
finish();
|
||||
} else {
|
||||
updateSaveButton();
|
||||
|
@ -179,12 +178,10 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
|
|||
startActivity(new Intent(getApplicationContext(),
|
||||
ManageAccountActivity.class));
|
||||
finish();
|
||||
} else if (jidToEdit == null && mAccount != null
|
||||
&& mAccount.getStatus() == Account.State.ONLINE) {
|
||||
} else if (mInitMode && mAccount != null && mAccount.getStatus() == Account.State.ONLINE) {
|
||||
if (!mFetchingAvatar) {
|
||||
mFetchingAvatar = true;
|
||||
xmppConnectionService.checkForAvatar(mAccount,
|
||||
mAvatarFetchCallback);
|
||||
xmppConnectionService.checkForAvatar(mAccount, mAvatarFetchCallback);
|
||||
}
|
||||
} else {
|
||||
updateSaveButton();
|
||||
|
@ -236,8 +233,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
|
|||
@Override
|
||||
public void onClick(final View view) {
|
||||
if (mAccount != null) {
|
||||
final Intent intent = new Intent(getApplicationContext(),
|
||||
PublishProfilePictureActivity.class);
|
||||
final Intent intent = new Intent(getApplicationContext(), PublishProfilePictureActivity.class);
|
||||
intent.putExtra("account", mAccount.getJid().toBareJid().toString());
|
||||
startActivity(intent);
|
||||
}
|
||||
|
@ -269,7 +265,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
|
|||
}
|
||||
|
||||
protected void updateSaveButton() {
|
||||
if (accountInfoEdited() && jidToEdit != null) {
|
||||
if (accountInfoEdited() && !mInitMode) {
|
||||
this.mSaveButton.setText(R.string.save);
|
||||
this.mSaveButton.setEnabled(true);
|
||||
this.mSaveButton.setTextColor(getPrimaryTextColor());
|
||||
|
@ -277,14 +273,14 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
|
|||
this.mSaveButton.setEnabled(false);
|
||||
this.mSaveButton.setTextColor(getSecondaryTextColor());
|
||||
this.mSaveButton.setText(R.string.account_status_connecting);
|
||||
} else if (mAccount != null && mAccount.getStatus() == Account.State.DISABLED) {
|
||||
} else if (mAccount != null && mAccount.getStatus() == Account.State.DISABLED && !mInitMode) {
|
||||
this.mSaveButton.setEnabled(true);
|
||||
this.mSaveButton.setTextColor(getPrimaryTextColor());
|
||||
this.mSaveButton.setText(R.string.enable);
|
||||
} else {
|
||||
this.mSaveButton.setEnabled(true);
|
||||
this.mSaveButton.setTextColor(getPrimaryTextColor());
|
||||
if (jidToEdit != null) {
|
||||
if (!mInitMode) {
|
||||
if (mAccount != null && mAccount.isOnlineAndConnected()) {
|
||||
this.mSaveButton.setText(R.string.save);
|
||||
if (!accountInfoEdited()) {
|
||||
|
@ -421,8 +417,9 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
|
|||
} catch (final InvalidJidException | NullPointerException ignored) {
|
||||
this.jidToEdit = null;
|
||||
}
|
||||
this.mInitMode = getIntent().getBooleanExtra("init", false) || this.jidToEdit == null;
|
||||
this.messageFingerprint = getIntent().getStringExtra("fingerprint");
|
||||
if (this.jidToEdit != null) {
|
||||
if (!mInitMode) {
|
||||
this.mRegisterNew.setVisibility(View.GONE);
|
||||
if (getActionBar() != null) {
|
||||
getActionBar().setTitle(getString(R.string.account_details));
|
||||
|
@ -440,7 +437,14 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
|
|||
protected void onBackendConnected() {
|
||||
if (this.jidToEdit != null) {
|
||||
this.mAccount = xmppConnectionService.findAccountByJid(jidToEdit);
|
||||
updateAccountInformation(true);
|
||||
if (this.mAccount != null) {
|
||||
if (this.mAccount.getPrivateKeyAlias() != null) {
|
||||
this.mPassword.setHint(R.string.authenticate_with_certificate);
|
||||
if (this.mInitMode) {
|
||||
this.mPassword.requestFocus();
|
||||
}
|
||||
} updateAccountInformation(true);
|
||||
}
|
||||
} else if (this.xmppConnectionService.getAccounts().size() == 0) {
|
||||
if (getActionBar() != null) {
|
||||
getActionBar().setDisplayHomeAsUpEnabled(false);
|
||||
|
@ -492,7 +496,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
|
|||
}
|
||||
this.mPassword.setText(this.mAccount.getPassword());
|
||||
}
|
||||
if (this.jidToEdit != null) {
|
||||
if (!mInitMode) {
|
||||
this.mAvatar.setVisibility(View.VISIBLE);
|
||||
this.mAvatar.setImageBitmap(avatarService().get(this.mAccount, getPixel(72)));
|
||||
}
|
||||
|
|
|
@ -5,6 +5,9 @@ import android.content.DialogInterface;
|
|||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.security.KeyChain;
|
||||
import android.security.KeyChainAliasCallback;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.Menu;
|
||||
|
@ -14,6 +17,7 @@ import android.widget.AdapterView;
|
|||
import android.widget.AdapterView.AdapterContextMenuInfo;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.ListView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -21,10 +25,11 @@ import java.util.List;
|
|||
import eu.siacs.conversations.Config;
|
||||
import eu.siacs.conversations.R;
|
||||
import eu.siacs.conversations.entities.Account;
|
||||
import eu.siacs.conversations.services.XmppConnectionService;
|
||||
import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
|
||||
import eu.siacs.conversations.ui.adapter.AccountAdapter;
|
||||
|
||||
public class ManageAccountActivity extends XmppActivity implements OnAccountUpdate {
|
||||
public class ManageAccountActivity extends XmppActivity implements OnAccountUpdate, KeyChainAliasCallback, XmppConnectionService.OnAccountCreated {
|
||||
|
||||
protected Account selectedAccount = null;
|
||||
|
||||
|
@ -144,6 +149,9 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
|
|||
case R.id.action_enable_all:
|
||||
enableAllAccounts();
|
||||
break;
|
||||
case R.id.action_add_account_from_key:
|
||||
addAccountFromKey();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -179,6 +187,10 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
|
|||
}
|
||||
}
|
||||
|
||||
private void addAccountFromKey() {
|
||||
KeyChain.choosePrivateKeyAlias(this, this, null, null, null, -1, null);
|
||||
}
|
||||
|
||||
private void publishAvatar(Account account) {
|
||||
Intent intent = new Intent(getApplicationContext(),
|
||||
PublishProfilePictureActivity.class);
|
||||
|
@ -281,4 +293,26 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void alias(String alias) {
|
||||
if (alias != null) {
|
||||
xmppConnectionService.createAccountFromKey(alias, this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccountCreated(Account account) {
|
||||
switchToAccount(account, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void informUser(final int r) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(ManageAccountActivity.this,r,Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -435,8 +435,13 @@ public abstract class XmppActivity extends Activity {
|
|||
}
|
||||
|
||||
public void switchToAccount(Account account) {
|
||||
switchToAccount(account,false);
|
||||
}
|
||||
|
||||
public void switchToAccount(Account account, boolean init) {
|
||||
Intent intent = new Intent(this, EditAccountActivity.class);
|
||||
intent.putExtra("jid", account.getJid().toBareJid().toString());
|
||||
intent.putExtra("init", init);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,12 @@
|
|||
android:icon="?attr/icon_add_person"
|
||||
android:showAsAction="always"
|
||||
android:title="@string/action_add_account"/>
|
||||
<item
|
||||
android:id="@+id/action_add_account_from_key"
|
||||
android:showAsAction="never"
|
||||
android:icon="?attr/icon_add_person"
|
||||
android:title="@string/action_add_account_from_key"
|
||||
android:visible="false"/>
|
||||
<item
|
||||
android:id="@+id/action_enable_all"
|
||||
android:title="@string/enable_all_accounts"/>
|
||||
|
|
|
@ -524,4 +524,7 @@
|
|||
<string name="pref_away_when_screen_off_summary">Marks your resource as away when the screen is turned off</string>
|
||||
<string name="pref_xa_on_silent_mode">Not available in silent mode</string>
|
||||
<string name="pref_xa_on_silent_mode_summary">Marks your resource as not available when phone is in silent mode</string>
|
||||
<string name="action_add_account_from_key">Add account from key</string>
|
||||
<string name="unable_to_parse_certificate">Unable to parse certificate</string>
|
||||
<string name="authenticate_with_certificate">Leave empty to authenticate w/ certificate</string>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue