Rename account to identity.

This commit is contained in:
akwizgran
2019-05-03 13:46:02 +01:00
parent 5553b7d0e4
commit 9c08073e49
17 changed files with 459 additions and 453 deletions

View File

@@ -4,7 +4,7 @@ import org.briarproject.bramble.api.account.AccountManager;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.identity.Account;
import org.briarproject.bramble.api.identity.Identity;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
@@ -161,8 +161,8 @@ class AccountManagerImpl implements AccountManager {
synchronized (stateChangeLock) {
if (hasDatabaseKey())
throw new AssertionError("Already have a database key");
Account account = identityManager.createAccount(name);
identityManager.registerAccount(account);
Identity identity = identityManager.createIdentity(name);
identityManager.registerIdentity(identity);
SecretKey key = crypto.generateSecretKey();
if (!encryptAndStoreDatabaseKey(key, password)) return false;
databaseKey = key;

View File

@@ -13,9 +13,9 @@ import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.MessageDeletedException;
import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.MigrationListener;
import org.briarproject.bramble.api.identity.Account;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.Identity;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.settings.Settings;
@@ -86,11 +86,6 @@ interface Database<T> {
*/
void commitTransaction(T txn) throws DbException;
/**
* Stores an account.
*/
void addAccount(T txn, Account a) throws DbException;
/**
* Stores a contact associated with the given local and remote pseudonyms,
* and returns an ID for the contact.
@@ -124,6 +119,11 @@ interface Database<T> {
HandshakeKeySetId addHandshakeKeys(T txn, PendingContactId p,
HandshakeKeys k) throws DbException;
/**
* Stores an identity.
*/
void addIdentity(T txn, Identity i) throws DbException;
/**
* Stores a message.
*
@@ -163,13 +163,6 @@ interface Database<T> {
TransportKeySetId addTransportKeys(T txn, ContactId c, TransportKeys k)
throws DbException;
/**
* Returns true if the database contains an account for the given pseudonym.
* <p/>
* Read-only.
*/
boolean containsAccount(T txn, AuthorId a) throws DbException;
/**
* Returns true if the database contains the given contact for the given
* local pseudonym.
@@ -193,6 +186,14 @@ interface Database<T> {
*/
boolean containsGroup(T txn, GroupId g) throws DbException;
/**
* Returns true if the database contains an identity for the given
* pseudonym.
* <p/>
* Read-only.
*/
boolean containsIdentity(T txn, AuthorId a) throws DbException;
/**
* Returns true if the database contains the given message.
* <p/>
@@ -245,20 +246,6 @@ interface Database<T> {
*/
void deleteMessageMetadata(T txn, MessageId m) throws DbException;
/**
* Returns the account for local pseudonym with the given ID.
* <p/>
* Read-only.
*/
Account getAccount(T txn, AuthorId a) throws DbException;
/**
* Returns the accounts for all local pseudonyms.
* <p/>
* Read-only.
*/
Collection<Account> getAccounts(T txn) throws DbException;
/**
* Returns the contact with the given ID.
* <p/>
@@ -336,6 +323,20 @@ interface Database<T> {
Collection<HandshakeKeySet> getHandshakeKeys(T txn, TransportId t)
throws DbException;
/**
* Returns the identity for local pseudonym with the given ID.
* <p/>
* Read-only.
*/
Identity getIdentity(T txn, AuthorId a) throws DbException;
/**
* Returns the identities for all local pseudonyms.
* <p/>
* Read-only.
*/
Collection<Identity> getIdentities(T txn) throws DbException;
/**
* Returns the message with the given ID.
* <p/>
@@ -605,11 +606,6 @@ interface Database<T> {
*/
void raiseSeenFlag(T txn, ContactId c, MessageId m) throws DbException;
/**
* Removes an account (and all associated state) from the database.
*/
void removeAccount(T txn, AuthorId a) throws DbException;
/**
* Removes a contact from the database.
*/
@@ -633,6 +629,11 @@ interface Database<T> {
void removeHandshakeKeys(T txn, TransportId t, HandshakeKeySetId k)
throws DbException;
/**
* Removes an identity (and all associated state) from the database.
*/
void removeIdentity(T txn, AuthorId a) throws DbException;
/**
* Removes a message (and all associated state) from the database.
*/
@@ -686,7 +687,7 @@ interface Database<T> {
throws DbException;
/**
* Sets the handshake key pair for the account with the given ID.
* Sets the handshake key pair for the identity with the given ID.
*/
void setHandshakeKeyPair(T txn, AuthorId local, byte[] publicKey,
byte[] privateKey) throws DbException;

View File

@@ -30,9 +30,9 @@ import org.briarproject.bramble.api.db.TaskAction;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventExecutor;
import org.briarproject.bramble.api.identity.Account;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.Identity;
import org.briarproject.bramble.api.identity.event.LocalAuthorAddedEvent;
import org.briarproject.bramble.api.identity.event.LocalAuthorRemovedEvent;
import org.briarproject.bramble.api.lifecycle.ShutdownManager;
@@ -231,26 +231,15 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
return txnClass.cast(transaction.unbox());
}
@Override
public void addAccount(Transaction transaction, Account a)
throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction);
if (!db.containsAccount(txn, a.getId())) {
db.addAccount(txn, a);
transaction.attach(new LocalAuthorAddedEvent(a.getId()));
}
}
@Override
public ContactId addContact(Transaction transaction, Author remote,
AuthorId local, boolean verified)
throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction);
if (!db.containsAccount(txn, local))
if (!db.containsIdentity(txn, local))
throw new NoSuchLocalAuthorException();
if (db.containsAccount(txn, remote.getId()))
if (db.containsIdentity(txn, remote.getId()))
throw new ContactExistsException();
if (db.containsContact(txn, remote.getId(), local))
throw new ContactExistsException();
@@ -293,6 +282,17 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
return db.addHandshakeKeys(txn, p, k);
}
@Override
public void addIdentity(Transaction transaction, Identity i)
throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction);
if (!db.containsIdentity(txn, i.getId())) {
db.addIdentity(txn, i);
transaction.attach(new LocalAuthorAddedEvent(i.getId()));
}
}
@Override
public void addLocalMessage(Transaction transaction, Message m,
Metadata meta, boolean shared) throws DbException {
@@ -341,18 +341,11 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
return db.addTransportKeys(txn, c, k);
}
@Override
public boolean containsAccount(Transaction transaction, AuthorId local)
throws DbException {
T txn = unbox(transaction);
return db.containsAccount(txn, local);
}
@Override
public boolean containsContact(Transaction transaction, AuthorId remote,
AuthorId local) throws DbException {
T txn = unbox(transaction);
if (!db.containsAccount(txn, local))
if (!db.containsIdentity(txn, local))
throw new NoSuchLocalAuthorException();
return db.containsContact(txn, remote, local);
}
@@ -364,6 +357,13 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
return db.containsGroup(txn, g);
}
@Override
public boolean containsIdentity(Transaction transaction, AuthorId a)
throws DbException {
T txn = unbox(transaction);
return db.containsIdentity(txn, a);
}
@Override
public boolean containsPendingContact(Transaction transaction,
PendingContactId p) throws DbException {
@@ -478,22 +478,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
return messages;
}
@Override
public Account getAccount(Transaction transaction, AuthorId a)
throws DbException {
T txn = unbox(transaction);
if (!db.containsAccount(txn, a))
throw new NoSuchLocalAuthorException();
return db.getAccount(txn, a);
}
@Override
public Collection<Account> getAccounts(Transaction transaction)
throws DbException {
T txn = unbox(transaction);
return db.getAccounts(txn);
}
@Override
public Contact getContact(Transaction transaction, ContactId c)
throws DbException {
@@ -521,7 +505,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
public Collection<ContactId> getContacts(Transaction transaction,
AuthorId a) throws DbException {
T txn = unbox(transaction);
if (!db.containsAccount(txn, a))
if (!db.containsIdentity(txn, a))
throw new NoSuchLocalAuthorException();
return db.getContacts(txn, a);
}
@@ -569,6 +553,22 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
return db.getHandshakeKeys(txn, t);
}
@Override
public Identity getIdentity(Transaction transaction, AuthorId a)
throws DbException {
T txn = unbox(transaction);
if (!db.containsIdentity(txn, a))
throw new NoSuchLocalAuthorException();
return db.getIdentity(txn, a);
}
@Override
public Collection<Identity> getIdentities(Transaction transaction)
throws DbException {
T txn = unbox(transaction);
return db.getIdentities(txn);
}
@Override
public Message getMessage(Transaction transaction, MessageId m)
throws DbException {
@@ -868,17 +868,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
if (requested) transaction.attach(new MessageRequestedEvent(c));
}
@Override
public void removeAccount(Transaction transaction, AuthorId a)
throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction);
if (!db.containsAccount(txn, a))
throw new NoSuchLocalAuthorException();
db.removeAccount(txn, a);
transaction.attach(new LocalAuthorRemovedEvent(a));
}
@Override
public void removeContact(Transaction transaction, ContactId c)
throws DbException {
@@ -915,6 +904,17 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
db.removeHandshakeKeys(txn, t, k);
}
@Override
public void removeIdentity(Transaction transaction, AuthorId a)
throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction);
if (!db.containsIdentity(txn, a))
throw new NoSuchLocalAuthorException();
db.removeIdentity(txn, a);
transaction.attach(new LocalAuthorRemovedEvent(a));
}
@Override
public void removeMessage(Transaction transaction, MessageId m)
throws DbException {
@@ -1040,7 +1040,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
byte[] publicKey, byte[] privateKey) throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction);
if (!db.containsAccount(txn, local))
if (!db.containsIdentity(txn, local))
throw new NoSuchLocalAuthorException();
db.setHandshakeKeyPair(txn, local, publicKey, privateKey);
}

View File

@@ -13,9 +13,9 @@ import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.MessageDeletedException;
import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.MigrationListener;
import org.briarproject.bramble.api.identity.Account;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.Identity;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId;
@@ -662,35 +662,6 @@ abstract class JdbcDatabase implements Database<Connection> {
if (interrupted) Thread.currentThread().interrupt();
}
@Override
public void addAccount(Connection txn, Account a) throws DbException {
PreparedStatement ps = null;
try {
String sql = "INSERT INTO localAuthors"
+ " (authorId, formatVersion, name, publicKey, privateKey,"
+ " handshakePublicKey, handshakePrivateKey, created)"
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
ps = txn.prepareStatement(sql);
LocalAuthor local = a.getLocalAuthor();
ps.setBytes(1, local.getId().getBytes());
ps.setInt(2, local.getFormatVersion());
ps.setString(3, local.getName());
ps.setBytes(4, local.getPublicKey());
ps.setBytes(5, local.getPrivateKey());
if (a.getHandshakePublicKey() == null) ps.setNull(6, BINARY);
else ps.setBytes(6, a.getHandshakePublicKey());
if (a.getHandshakePrivateKey() == null) ps.setNull(7, BINARY);
else ps.setBytes(7, a.getHandshakePrivateKey());
ps.setLong(8, a.getTimeCreated());
int affected = ps.executeUpdate();
if (affected != 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override
public ContactId addContact(Connection txn, Author remote, AuthorId local,
boolean verified) throws DbException {
@@ -903,6 +874,35 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
@Override
public void addIdentity(Connection txn, Identity i) throws DbException {
PreparedStatement ps = null;
try {
String sql = "INSERT INTO localAuthors"
+ " (authorId, formatVersion, name, publicKey, privateKey,"
+ " handshakePublicKey, handshakePrivateKey, created)"
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
ps = txn.prepareStatement(sql);
LocalAuthor local = i.getLocalAuthor();
ps.setBytes(1, local.getId().getBytes());
ps.setInt(2, local.getFormatVersion());
ps.setString(3, local.getName());
ps.setBytes(4, local.getPublicKey());
ps.setBytes(5, local.getPrivateKey());
if (i.getHandshakePublicKey() == null) ps.setNull(6, BINARY);
else ps.setBytes(6, i.getHandshakePublicKey());
if (i.getHandshakePrivateKey() == null) ps.setNull(7, BINARY);
else ps.setBytes(7, i.getHandshakePrivateKey());
ps.setLong(8, i.getTimeCreated());
int affected = ps.executeUpdate();
if (affected != 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override
public void addMessage(Connection txn, Message m, MessageState state,
boolean messageShared, @Nullable ContactId sender)
@@ -1180,28 +1180,6 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
@Override
public boolean containsAccount(Connection txn, AuthorId a)
throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT NULL FROM localAuthors WHERE authorId = ?";
ps = txn.prepareStatement(sql);
ps.setBytes(1, a.getBytes());
rs = ps.executeQuery();
boolean found = rs.next();
if (rs.next()) throw new DbStateException();
rs.close();
ps.close();
return found;
} catch (SQLException e) {
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override
public boolean containsContact(Connection txn, AuthorId remote,
AuthorId local) throws DbException {
@@ -1270,6 +1248,28 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
@Override
public boolean containsIdentity(Connection txn, AuthorId a)
throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT NULL FROM localAuthors WHERE authorId = ?";
ps = txn.prepareStatement(sql);
ps.setBytes(1, a.getBytes());
rs = ps.executeQuery();
boolean found = rs.next();
if (rs.next()) throw new DbStateException();
rs.close();
ps.close();
return found;
} catch (SQLException e) {
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override
public boolean containsMessage(Connection txn, MessageId m)
throws DbException {
@@ -1427,76 +1427,6 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
@Override
public Account getAccount(Connection txn, AuthorId a) throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT formatVersion, name, publicKey, privateKey,"
+ " handshakePublicKey, handshakePrivateKey, created"
+ " FROM localAuthors"
+ " WHERE authorId = ?";
ps = txn.prepareStatement(sql);
ps.setBytes(1, a.getBytes());
rs = ps.executeQuery();
if (!rs.next()) throw new DbStateException();
int formatVersion = rs.getInt(1);
String name = rs.getString(2);
byte[] publicKey = rs.getBytes(3);
byte[] privateKey = rs.getBytes(4);
byte[] handshakePublicKey = rs.getBytes(5);
byte[] handshakePrivateKey = rs.getBytes(6);
long created = rs.getLong(7);
if (rs.next()) throw new DbStateException();
rs.close();
ps.close();
LocalAuthor local = new LocalAuthor(a, formatVersion, name,
publicKey, privateKey);
return new Account(local, handshakePublicKey, handshakePrivateKey,
created);
} catch (SQLException e) {
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override
public Collection<Account> getAccounts(Connection txn) throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT authorId, formatVersion, name, publicKey,"
+ " privateKey, handshakePublicKey, handshakePrivateKey,"
+ " created"
+ " FROM localAuthors";
ps = txn.prepareStatement(sql);
rs = ps.executeQuery();
List<Account> accounts = new ArrayList<>();
while (rs.next()) {
AuthorId authorId = new AuthorId(rs.getBytes(1));
int formatVersion = rs.getInt(2);
String name = rs.getString(3);
byte[] publicKey = rs.getBytes(4);
byte[] privateKey = rs.getBytes(5);
byte[] handshakePublicKey = rs.getBytes(6);
byte[] handshakePrivateKey = rs.getBytes(7);
long created = rs.getLong(8);
LocalAuthor local = new LocalAuthor(authorId, formatVersion,
name, publicKey, privateKey);
accounts.add(new Account(local, handshakePublicKey,
handshakePrivateKey, created));
}
rs.close();
ps.close();
return accounts;
} catch (SQLException e) {
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override
public Contact getContact(Connection txn, ContactId c) throws DbException {
PreparedStatement ps = null;
@@ -1811,6 +1741,77 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
@Override
public Identity getIdentity(Connection txn, AuthorId a) throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT formatVersion, name, publicKey, privateKey,"
+ " handshakePublicKey, handshakePrivateKey, created"
+ " FROM localAuthors"
+ " WHERE authorId = ?";
ps = txn.prepareStatement(sql);
ps.setBytes(1, a.getBytes());
rs = ps.executeQuery();
if (!rs.next()) throw new DbStateException();
int formatVersion = rs.getInt(1);
String name = rs.getString(2);
byte[] publicKey = rs.getBytes(3);
byte[] privateKey = rs.getBytes(4);
byte[] handshakePublicKey = rs.getBytes(5);
byte[] handshakePrivateKey = rs.getBytes(6);
long created = rs.getLong(7);
if (rs.next()) throw new DbStateException();
rs.close();
ps.close();
LocalAuthor local = new LocalAuthor(a, formatVersion, name,
publicKey, privateKey);
return new Identity(local, handshakePublicKey, handshakePrivateKey,
created);
} catch (SQLException e) {
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override
public Collection<Identity> getIdentities(Connection txn)
throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT authorId, formatVersion, name, publicKey,"
+ " privateKey, handshakePublicKey, handshakePrivateKey,"
+ " created"
+ " FROM localAuthors";
ps = txn.prepareStatement(sql);
rs = ps.executeQuery();
List<Identity> identities = new ArrayList<>();
while (rs.next()) {
AuthorId authorId = new AuthorId(rs.getBytes(1));
int formatVersion = rs.getInt(2);
String name = rs.getString(3);
byte[] publicKey = rs.getBytes(4);
byte[] privateKey = rs.getBytes(5);
byte[] handshakePublicKey = rs.getBytes(6);
byte[] handshakePrivateKey = rs.getBytes(7);
long created = rs.getLong(8);
LocalAuthor local = new LocalAuthor(authorId, formatVersion,
name, publicKey, privateKey);
identities.add(new Identity(local, handshakePublicKey,
handshakePrivateKey, created));
}
rs.close();
ps.close();
return identities;
} catch (SQLException e) {
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override
public Message getMessage(Connection txn, MessageId m) throws DbException {
PreparedStatement ps = null;
@@ -2879,22 +2880,6 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
@Override
public void removeAccount(Connection txn, AuthorId a) throws DbException {
PreparedStatement ps = null;
try {
String sql = "DELETE FROM localAuthors WHERE authorId = ?";
ps = txn.prepareStatement(sql);
ps.setBytes(1, a.getBytes());
int affected = ps.executeUpdate();
if (affected != 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override
public void removeContact(Connection txn, ContactId c)
throws DbException {
@@ -2977,6 +2962,22 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
@Override
public void removeIdentity(Connection txn, AuthorId a) throws DbException {
PreparedStatement ps = null;
try {
String sql = "DELETE FROM localAuthors WHERE authorId = ?";
ps = txn.prepareStatement(sql);
ps.setBytes(1, a.getBytes());
int affected = ps.executeUpdate();
if (affected != 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override
public void removeMessage(Connection txn, MessageId m) throws DbException {
PreparedStatement ps = null;

View File

@@ -5,8 +5,8 @@ import org.briarproject.bramble.api.crypto.KeyPair;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.identity.Account;
import org.briarproject.bramble.api.identity.AuthorFactory;
import org.briarproject.bramble.api.identity.Identity;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.lifecycle.LifecycleManager.OpenDatabaseHook;
@@ -38,23 +38,23 @@ class IdentityManagerImpl implements IdentityManager, OpenDatabaseHook {
private final Clock clock;
/**
* The user's account, or null if no account has been registered or loaded.
* If non-null, this account always has handshake keys.
* The user's identity, or null if no identity has been registered or
* loaded. If non-null, this identity always has handshake keys.
*/
@Nullable
private volatile Account cachedAccount = null;
private volatile Identity cachedIdentity = null;
/**
* True if {@code cachedAccount} was registered via
* {@link #registerAccount(Account)} and should be stored when
* True if {@code cachedIdentity} was registered via
* {@link #registerIdentity(Identity)} and should be stored when
* {@link #onDatabaseOpened(Transaction)} is called.
*/
private volatile boolean shouldStoreAccount = false;
private volatile boolean shouldStoreIdentity = false;
/**
* True if the handshake keys in {@code cachedAccount} were generated when
* the account was loaded and should be stored when
* True if the handshake keys in {@code cachedIdentity} were generated
* when the identity was loaded and should be stored when
* {@link #onDatabaseOpened(Transaction)} is called.
*/
private volatile boolean shouldStoreKeys = false;
@@ -69,31 +69,31 @@ class IdentityManagerImpl implements IdentityManager, OpenDatabaseHook {
}
@Override
public Account createAccount(String name) {
public Identity createIdentity(String name) {
long start = now();
LocalAuthor localAuthor = authorFactory.createLocalAuthor(name);
KeyPair handshakeKeyPair = crypto.generateAgreementKeyPair();
byte[] handshakePub = handshakeKeyPair.getPublic().getEncoded();
byte[] handshakePriv = handshakeKeyPair.getPrivate().getEncoded();
logDuration(LOG, "Creating account", start);
return new Account(localAuthor, handshakePub, handshakePriv,
logDuration(LOG, "Creating identity", start);
return new Identity(localAuthor, handshakePub, handshakePriv,
clock.currentTimeMillis());
}
@Override
public void registerAccount(Account a) {
if (!a.hasHandshakeKeyPair()) throw new IllegalArgumentException();
cachedAccount = a;
shouldStoreAccount = true;
LOG.info("Account registered");
public void registerIdentity(Identity i) {
if (!i.hasHandshakeKeyPair()) throw new IllegalArgumentException();
cachedIdentity = i;
shouldStoreIdentity = true;
LOG.info("Identity registered");
}
@Override
public void onDatabaseOpened(Transaction txn) throws DbException {
Account cached = getCachedAccount(txn);
if (shouldStoreAccount) {
db.addAccount(txn, cached);
LOG.info("Account stored");
Identity cached = getCachedIdentity(txn);
if (shouldStoreIdentity) {
db.addIdentity(txn, cached);
LOG.info("Identity stored");
} else if (shouldStoreKeys) {
byte[] publicKey = requireNonNull(cached.getHandshakePublicKey());
byte[] privateKey = requireNonNull(cached.getHandshakePrivateKey());
@@ -104,49 +104,50 @@ class IdentityManagerImpl implements IdentityManager, OpenDatabaseHook {
@Override
public LocalAuthor getLocalAuthor() throws DbException {
Account cached = cachedAccount;
Identity cached = cachedIdentity;
if (cached == null)
cached = db.transactionWithResult(true, this::getCachedAccount);
cached = db.transactionWithResult(true, this::getCachedIdentity);
return cached.getLocalAuthor();
}
@Override
public LocalAuthor getLocalAuthor(Transaction txn) throws DbException {
return getCachedAccount(txn).getLocalAuthor();
return getCachedIdentity(txn).getLocalAuthor();
}
@Override
public byte[][] getHandshakeKeys(Transaction txn) throws DbException {
Account cached = getCachedAccount(txn);
Identity cached = getCachedIdentity(txn);
return new byte[][] {
cached.getHandshakePublicKey(),
cached.getHandshakePrivateKey()
};
}
private Account getCachedAccount(Transaction txn) throws DbException {
Account cached = cachedAccount;
private Identity getCachedIdentity(Transaction txn) throws DbException {
Identity cached = cachedIdentity;
if (cached == null)
cachedAccount = cached = loadAccountWithKeyPair(txn);
cachedIdentity = cached = loadIdentityWithKeyPair(txn);
return cached;
}
private Account loadAccountWithKeyPair(Transaction txn) throws DbException {
Account a = loadAccount(txn);
LOG.info("Account loaded");
if (a.hasHandshakeKeyPair()) return a;
private Identity loadIdentityWithKeyPair(Transaction txn)
throws DbException {
Identity i = loadIdentity(txn);
LOG.info("Identity loaded");
if (i.hasHandshakeKeyPair()) return i;
KeyPair keyPair = crypto.generateAgreementKeyPair();
byte[] publicKey = keyPair.getPublic().getEncoded();
byte[] privateKey = keyPair.getPrivate().getEncoded();
LOG.info("Handshake key pair generated");
shouldStoreKeys = true;
return new Account(a.getLocalAuthor(), publicKey, privateKey,
a.getTimeCreated());
return new Identity(i.getLocalAuthor(), publicKey, privateKey,
i.getTimeCreated());
}
private Account loadAccount(Transaction txn) throws DbException {
Collection<Account> accounts = db.getAccounts(txn);
if (accounts.size() != 1) throw new DbException();
return accounts.iterator().next();
private Identity loadIdentity(Transaction txn) throws DbException {
Collection<Identity> identities = db.getIdentities(txn);
if (identities.size() != 1) throw new DbException();
return identities.iterator().next();
}
}