mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-19 14:19:53 +01:00
Store private keys for pseudonyms and restricted groups in the DB.
This commit is contained in:
@@ -9,7 +9,10 @@ import static java.util.logging.Level.WARNING;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@@ -53,7 +56,6 @@ implements OnClickListener, OnItemSelectedListener {
|
|||||||
new BriarServiceConnection();
|
new BriarServiceConnection();
|
||||||
|
|
||||||
@Inject private BundleEncrypter bundleEncrypter;
|
@Inject private BundleEncrypter bundleEncrypter;
|
||||||
private boolean restricted = false;
|
|
||||||
private GroupNameSpinnerAdapter adapter = null;
|
private GroupNameSpinnerAdapter adapter = null;
|
||||||
private Spinner spinner = null;
|
private Spinner spinner = null;
|
||||||
private ImageButton sendButton = null;
|
private ImageButton sendButton = null;
|
||||||
@@ -63,6 +65,7 @@ implements OnClickListener, OnItemSelectedListener {
|
|||||||
@Inject private volatile DatabaseComponent db;
|
@Inject private volatile DatabaseComponent db;
|
||||||
@Inject @DatabaseExecutor private volatile Executor dbExecutor;
|
@Inject @DatabaseExecutor private volatile Executor dbExecutor;
|
||||||
@Inject private volatile MessageFactory messageFactory;
|
@Inject private volatile MessageFactory messageFactory;
|
||||||
|
private volatile boolean restricted = false;
|
||||||
private volatile Group group = null;
|
private volatile Group group = null;
|
||||||
private volatile GroupId groupId = null;
|
private volatile GroupId groupId = null;
|
||||||
private volatile MessageId parentId = null;
|
private volatile MessageId parentId = null;
|
||||||
@@ -131,7 +134,14 @@ implements OnClickListener, OnItemSelectedListener {
|
|||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
serviceConnection.waitForStartup();
|
serviceConnection.waitForStartup();
|
||||||
updateGroupList(db.getSubscriptions());
|
List<Group> postable = new ArrayList<Group>();
|
||||||
|
if(restricted) {
|
||||||
|
postable.addAll(db.getLocalGroups());
|
||||||
|
} else {
|
||||||
|
for(Group g : db.getSubscriptions())
|
||||||
|
if(!g.isRestricted()) postable.add(g);
|
||||||
|
}
|
||||||
|
updateGroupList(Collections.unmodifiableList(postable));
|
||||||
} catch(DbException e) {
|
} catch(DbException e) {
|
||||||
if(LOG.isLoggable(WARNING))
|
if(LOG.isLoggable(WARNING))
|
||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
@@ -147,7 +157,6 @@ implements OnClickListener, OnItemSelectedListener {
|
|||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
for(Group g : groups) {
|
for(Group g : groups) {
|
||||||
if(g.isRestricted() != restricted) continue;
|
|
||||||
if(g.getId().equals(groupId)) {
|
if(g.getId().equals(groupId)) {
|
||||||
group = g;
|
group = g;
|
||||||
spinner.setSelection(adapter.getCount());
|
spinner.setSelection(adapter.getCount());
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ import net.sf.briar.api.messaging.Ack;
|
|||||||
import net.sf.briar.api.messaging.AuthorId;
|
import net.sf.briar.api.messaging.AuthorId;
|
||||||
import net.sf.briar.api.messaging.Group;
|
import net.sf.briar.api.messaging.Group;
|
||||||
import net.sf.briar.api.messaging.GroupId;
|
import net.sf.briar.api.messaging.GroupId;
|
||||||
|
import net.sf.briar.api.messaging.LocalAuthor;
|
||||||
|
import net.sf.briar.api.messaging.LocalGroup;
|
||||||
import net.sf.briar.api.messaging.Message;
|
import net.sf.briar.api.messaging.Message;
|
||||||
import net.sf.briar.api.messaging.MessageId;
|
import net.sf.briar.api.messaging.MessageId;
|
||||||
import net.sf.briar.api.messaging.Offer;
|
import net.sf.briar.api.messaging.Offer;
|
||||||
@@ -51,18 +53,26 @@ public interface DatabaseComponent {
|
|||||||
void removeListener(DatabaseListener d);
|
void removeListener(DatabaseListener d);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a contact with the given name to the database and returns an ID for
|
* Stores a contact with the given name and returns an ID for the contact.
|
||||||
* the contact.
|
|
||||||
*/
|
*/
|
||||||
ContactId addContact(String name) throws DbException;
|
ContactId addContact(String name) throws DbException;
|
||||||
|
|
||||||
/** Adds an endpoint to the database. */
|
/** Stores an endpoint. */
|
||||||
void addEndpoint(Endpoint ep) throws DbException;
|
void addEndpoint(Endpoint ep) throws DbException;
|
||||||
|
|
||||||
/** Adds a locally generated group message to the database. */
|
/** Stores a pseudonym that the user can use to sign messages. */
|
||||||
|
void addLocalAuthor(LocalAuthor a) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores a restricted group to which the user can post messages. Storing
|
||||||
|
* a group does not create a subscription to it.
|
||||||
|
*/
|
||||||
|
void addLocalGroup(LocalGroup g) throws DbException;
|
||||||
|
|
||||||
|
/** Stores a locally generated group message. */
|
||||||
void addLocalGroupMessage(Message m) throws DbException;
|
void addLocalGroupMessage(Message m) throws DbException;
|
||||||
|
|
||||||
/** Adds a locally generated private message to the database. */
|
/** Stores a locally generated private message. */
|
||||||
void addLocalPrivateMessage(Message m, ContactId c) throws DbException;
|
void addLocalPrivateMessage(Message m, ContactId c) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -72,13 +82,13 @@ public interface DatabaseComponent {
|
|||||||
void addSecrets(Collection<TemporarySecret> secrets) throws DbException;
|
void addSecrets(Collection<TemporarySecret> secrets) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a transport to the database and returns true if the transport was
|
* Stores a transport and returns true if the transport was not previously
|
||||||
* not previously in the database.
|
* in the database.
|
||||||
*/
|
*/
|
||||||
boolean addTransport(TransportId t) throws DbException;
|
boolean addTransport(TransportId t) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates an acknowledgement for the given contact. Returns null if
|
* Generates an acknowledgement for the given contact, or returns null if
|
||||||
* there are no messages to acknowledge.
|
* there are no messages to acknowledge.
|
||||||
*/
|
*/
|
||||||
Ack generateAck(ContactId c, int maxMessages) throws DbException;
|
Ack generateAck(ContactId c, int maxMessages) throws DbException;
|
||||||
@@ -106,14 +116,14 @@ public interface DatabaseComponent {
|
|||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates an offer for the given contact. Returns null if there are no
|
* Generates an offer for the given contact, or returns null if there are
|
||||||
* messages to offer.
|
* no messages to offer.
|
||||||
*/
|
*/
|
||||||
Offer generateOffer(ContactId c, int maxMessages) throws DbException;
|
Offer generateOffer(ContactId c, int maxMessages) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a retention ack for the given contact. Returns null if no ack
|
* Generates a retention ack for the given contact, or returns null if no
|
||||||
* is due.
|
* ack is due.
|
||||||
*/
|
*/
|
||||||
RetentionAck generateRetentionAck(ContactId c) throws DbException;
|
RetentionAck generateRetentionAck(ContactId c) throws DbException;
|
||||||
|
|
||||||
@@ -126,8 +136,8 @@ public interface DatabaseComponent {
|
|||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a subscription ack for the given contact. Returns null if no
|
* Generates a subscription ack for the given contact, or returns null if
|
||||||
* ack is due.
|
* no ack is due.
|
||||||
*/
|
*/
|
||||||
SubscriptionAck generateSubscriptionAck(ContactId c) throws DbException;
|
SubscriptionAck generateSubscriptionAck(ContactId c) throws DbException;
|
||||||
|
|
||||||
@@ -140,8 +150,8 @@ public interface DatabaseComponent {
|
|||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a batch of transport acks for the given contact. Returns null
|
* Generates a batch of transport acks for the given contact, or returns
|
||||||
* if no acks are due.
|
* null if no acks are due.
|
||||||
*/
|
*/
|
||||||
Collection<TransportAck> generateTransportAcks(ContactId c)
|
Collection<TransportAck> generateTransportAcks(ContactId c)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
@@ -166,6 +176,12 @@ public interface DatabaseComponent {
|
|||||||
/** Returns the group with the given ID, if the user subscribes to it. */
|
/** Returns the group with the given ID, if the user subscribes to it. */
|
||||||
Group getGroup(GroupId g) throws DbException;
|
Group getGroup(GroupId g) throws DbException;
|
||||||
|
|
||||||
|
/** Returns all pseudonyms that the user can use to sign messages. */
|
||||||
|
Collection<LocalAuthor> getLocalAuthors() throws DbException;
|
||||||
|
|
||||||
|
/** Returns all restricted groups to which the user can post messages. */
|
||||||
|
Collection<LocalGroup> getLocalGroups() throws DbException;
|
||||||
|
|
||||||
/** Returns the local transport properties for the given transport. */
|
/** Returns the local transport properties for the given transport. */
|
||||||
TransportProperties getLocalProperties(TransportId t) throws DbException;
|
TransportProperties getLocalProperties(TransportId t) throws DbException;
|
||||||
|
|
||||||
@@ -219,8 +235,8 @@ public interface DatabaseComponent {
|
|||||||
boolean hasSendableMessages(ContactId c) throws DbException;
|
boolean hasSendableMessages(ContactId c) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increments the outgoing connection counter for the given contact
|
* Increments the outgoing connection counter for the given endpoint
|
||||||
* transport in the given rotation period and returns the old value.
|
* in the given rotation period and returns the old value of the counter.
|
||||||
*/
|
*/
|
||||||
long incrementConnectionCounter(ContactId c, TransportId t, long period)
|
long incrementConnectionCounter(ContactId c, TransportId t, long period)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|||||||
18
briar-api/src/net/sf/briar/api/messaging/LocalAuthor.java
Normal file
18
briar-api/src/net/sf/briar/api/messaging/LocalAuthor.java
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package net.sf.briar.api.messaging;
|
||||||
|
|
||||||
|
/** A pseudonym that the user can use to sign {@link Message}s. */
|
||||||
|
public class LocalAuthor extends Author {
|
||||||
|
|
||||||
|
private final byte[] privateKey;
|
||||||
|
|
||||||
|
public LocalAuthor(AuthorId id, String name, byte[] publicKey,
|
||||||
|
byte[] privateKey) {
|
||||||
|
super(id, name, publicKey);
|
||||||
|
this.privateKey = privateKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the private key that is used to sign messages. */
|
||||||
|
public byte[] getPrivateKey() {
|
||||||
|
return privateKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
18
briar-api/src/net/sf/briar/api/messaging/LocalGroup.java
Normal file
18
briar-api/src/net/sf/briar/api/messaging/LocalGroup.java
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package net.sf.briar.api.messaging;
|
||||||
|
|
||||||
|
/** A restricted group to which the user can post messages. */
|
||||||
|
public class LocalGroup extends Group {
|
||||||
|
|
||||||
|
private final byte[] privateKey;
|
||||||
|
|
||||||
|
public LocalGroup(GroupId id, String name, byte[] publicKey,
|
||||||
|
byte[] privateKey) {
|
||||||
|
super(id, name, publicKey);
|
||||||
|
this.privateKey = privateKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the private key that is used to sign messages. */
|
||||||
|
public byte[] getPrivateKey() {
|
||||||
|
return privateKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,6 +15,8 @@ import net.sf.briar.api.db.PrivateMessageHeader;
|
|||||||
import net.sf.briar.api.messaging.AuthorId;
|
import net.sf.briar.api.messaging.AuthorId;
|
||||||
import net.sf.briar.api.messaging.Group;
|
import net.sf.briar.api.messaging.Group;
|
||||||
import net.sf.briar.api.messaging.GroupId;
|
import net.sf.briar.api.messaging.GroupId;
|
||||||
|
import net.sf.briar.api.messaging.LocalAuthor;
|
||||||
|
import net.sf.briar.api.messaging.LocalGroup;
|
||||||
import net.sf.briar.api.messaging.Message;
|
import net.sf.briar.api.messaging.Message;
|
||||||
import net.sf.briar.api.messaging.MessageId;
|
import net.sf.briar.api.messaging.MessageId;
|
||||||
import net.sf.briar.api.messaging.RetentionAck;
|
import net.sf.briar.api.messaging.RetentionAck;
|
||||||
@@ -40,6 +42,7 @@ import net.sf.briar.api.transport.TemporarySecret;
|
|||||||
* deadlock, locks must be acquired in the following (alphabetical) order:
|
* deadlock, locks must be acquired in the following (alphabetical) order:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li> contact
|
* <li> contact
|
||||||
|
* <li> identity
|
||||||
* <li> message
|
* <li> message
|
||||||
* <li> rating
|
* <li> rating
|
||||||
* <li> retention
|
* <li> retention
|
||||||
@@ -102,6 +105,21 @@ interface Database<T> {
|
|||||||
*/
|
*/
|
||||||
boolean addGroupMessage(T txn, Message m) throws DbException;
|
boolean addGroupMessage(T txn, Message m) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores a pseudonym that the user can use to sign messages.
|
||||||
|
* <p>
|
||||||
|
* Locking: identity write.
|
||||||
|
*/
|
||||||
|
void addLocalAuthor(T txn, LocalAuthor a) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores a restricted group to which the user can post messages. Storing
|
||||||
|
* a group does not create a subscription to it.
|
||||||
|
* <p>
|
||||||
|
* Locking: identity write.
|
||||||
|
*/
|
||||||
|
void addLocalGroup(T txn, LocalGroup g) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Records a received message as needing to be acknowledged.
|
* Records a received message as needing to be acknowledged.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -259,6 +277,20 @@ interface Database<T> {
|
|||||||
*/
|
*/
|
||||||
long getLastConnected(T txn, ContactId c) throws DbException;
|
long getLastConnected(T txn, ContactId c) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all pseudonyms that the user can use to sign messages.
|
||||||
|
* <p>
|
||||||
|
* Locking: identity read.
|
||||||
|
*/
|
||||||
|
Collection<LocalAuthor> getLocalAuthors(T txn) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all restricted groups to which the user can post messages.
|
||||||
|
* <p>
|
||||||
|
* Locking: identity read.
|
||||||
|
*/
|
||||||
|
Collection<LocalGroup> getLocalGroups(T txn) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the local transport properties for the given transport.
|
* Returns the local transport properties for the given transport.
|
||||||
* <p>
|
* <p>
|
||||||
|
|||||||
@@ -61,6 +61,8 @@ import net.sf.briar.api.messaging.Author;
|
|||||||
import net.sf.briar.api.messaging.AuthorId;
|
import net.sf.briar.api.messaging.AuthorId;
|
||||||
import net.sf.briar.api.messaging.Group;
|
import net.sf.briar.api.messaging.Group;
|
||||||
import net.sf.briar.api.messaging.GroupId;
|
import net.sf.briar.api.messaging.GroupId;
|
||||||
|
import net.sf.briar.api.messaging.LocalAuthor;
|
||||||
|
import net.sf.briar.api.messaging.LocalGroup;
|
||||||
import net.sf.briar.api.messaging.Message;
|
import net.sf.briar.api.messaging.Message;
|
||||||
import net.sf.briar.api.messaging.MessageId;
|
import net.sf.briar.api.messaging.MessageId;
|
||||||
import net.sf.briar.api.messaging.Offer;
|
import net.sf.briar.api.messaging.Offer;
|
||||||
@@ -97,6 +99,8 @@ DatabaseCleaner.Callback {
|
|||||||
|
|
||||||
private final ReentrantReadWriteLock contactLock =
|
private final ReentrantReadWriteLock contactLock =
|
||||||
new ReentrantReadWriteLock(true);
|
new ReentrantReadWriteLock(true);
|
||||||
|
private final ReentrantReadWriteLock identityLock =
|
||||||
|
new ReentrantReadWriteLock(true);
|
||||||
private final ReentrantReadWriteLock messageLock =
|
private final ReentrantReadWriteLock messageLock =
|
||||||
new ReentrantReadWriteLock(true);
|
new ReentrantReadWriteLock(true);
|
||||||
private final ReentrantReadWriteLock ratingLock =
|
private final ReentrantReadWriteLock ratingLock =
|
||||||
@@ -426,6 +430,38 @@ DatabaseCleaner.Callback {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addLocalAuthor(LocalAuthor a) throws DbException {
|
||||||
|
identityLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
T txn = db.startTransaction();
|
||||||
|
try {
|
||||||
|
db.addLocalAuthor(txn, a);
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
identityLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addLocalGroup(LocalGroup g) throws DbException {
|
||||||
|
identityLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
T txn = db.startTransaction();
|
||||||
|
try {
|
||||||
|
db.addLocalGroup(txn, g);
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
identityLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void addSecrets(Collection<TemporarySecret> secrets)
|
public void addSecrets(Collection<TemporarySecret> secrets)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
contactLock.readLock().lock();
|
contactLock.readLock().lock();
|
||||||
@@ -911,6 +947,40 @@ DatabaseCleaner.Callback {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Collection<LocalAuthor> getLocalAuthors() throws DbException {
|
||||||
|
identityLock.readLock().lock();
|
||||||
|
try {
|
||||||
|
T txn = db.startTransaction();
|
||||||
|
try {
|
||||||
|
Collection<LocalAuthor> authors = db.getLocalAuthors(txn);
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
return authors;
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
identityLock.readLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<LocalGroup> getLocalGroups() throws DbException {
|
||||||
|
identityLock.readLock().lock();
|
||||||
|
try {
|
||||||
|
T txn = db.startTransaction();
|
||||||
|
try {
|
||||||
|
Collection<LocalGroup> groups = db.getLocalGroups(txn);
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
return groups;
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
identityLock.readLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public TransportProperties getLocalProperties(TransportId t)
|
public TransportProperties getLocalProperties(TransportId t)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
transportLock.readLock().lock();
|
transportLock.readLock().lock();
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ import net.sf.briar.api.messaging.Author;
|
|||||||
import net.sf.briar.api.messaging.AuthorId;
|
import net.sf.briar.api.messaging.AuthorId;
|
||||||
import net.sf.briar.api.messaging.Group;
|
import net.sf.briar.api.messaging.Group;
|
||||||
import net.sf.briar.api.messaging.GroupId;
|
import net.sf.briar.api.messaging.GroupId;
|
||||||
|
import net.sf.briar.api.messaging.LocalAuthor;
|
||||||
|
import net.sf.briar.api.messaging.LocalGroup;
|
||||||
import net.sf.briar.api.messaging.Message;
|
import net.sf.briar.api.messaging.Message;
|
||||||
import net.sf.briar.api.messaging.MessageId;
|
import net.sf.briar.api.messaging.MessageId;
|
||||||
import net.sf.briar.api.messaging.RetentionAck;
|
import net.sf.briar.api.messaging.RetentionAck;
|
||||||
@@ -60,10 +62,28 @@ import net.sf.briar.util.FileUtils;
|
|||||||
*/
|
*/
|
||||||
abstract class JdbcDatabase implements Database<Connection> {
|
abstract class JdbcDatabase implements Database<Connection> {
|
||||||
|
|
||||||
|
// Locking: identity
|
||||||
|
private static final String CREATE_LOCAL_AUTHORS =
|
||||||
|
"CREATE TABLE localAuthors"
|
||||||
|
+ " (authorId HASH NOT NULL,"
|
||||||
|
+ " name VARCHAR NOT NULL,"
|
||||||
|
+ " publicKey BINARY NOT NULL,"
|
||||||
|
+ " privateKey BINARY NOT NULL,"
|
||||||
|
+ " PRIMARY KEY (authorId))";
|
||||||
|
|
||||||
|
// Locking: identity
|
||||||
|
private static final String CREATE_LOCAL_GROUPS =
|
||||||
|
"CREATE TABLE localGroups"
|
||||||
|
+ " (groupId HASH NOT NULL,"
|
||||||
|
+ " name VARCHAR NOT NULL,"
|
||||||
|
+ " publicKey BINARY NOT NULL,"
|
||||||
|
+ " privateKey BINARY NOT NULL,"
|
||||||
|
+ " PRIMARY KEY (groupId))";
|
||||||
|
|
||||||
// Locking: contact
|
// Locking: contact
|
||||||
// Dependents: message, retention, subscription, transport, window
|
// Dependents: message, retention, subscription, transport, window
|
||||||
private static final String CREATE_CONTACTS =
|
private static final String CREATE_CONTACTS =
|
||||||
"CREATE TABLE contacts "
|
"CREATE TABLE contacts"
|
||||||
+ " (contactId COUNTER,"
|
+ " (contactId COUNTER,"
|
||||||
+ " name VARCHAR NOT NULL,"
|
+ " name VARCHAR NOT NULL,"
|
||||||
+ " PRIMARY KEY (contactId))";
|
+ " PRIMARY KEY (contactId))";
|
||||||
@@ -74,7 +94,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
"CREATE TABLE groups"
|
"CREATE TABLE groups"
|
||||||
+ " (groupId HASH NOT NULL,"
|
+ " (groupId HASH NOT NULL,"
|
||||||
+ " name VARCHAR NOT NULL,"
|
+ " name VARCHAR NOT NULL,"
|
||||||
+ " key BINARY," // Null for unrestricted groups
|
+ " publicKey BINARY," // Null for unrestricted groups
|
||||||
+ " PRIMARY KEY (groupId))";
|
+ " PRIMARY KEY (groupId))";
|
||||||
|
|
||||||
// Locking: subscription
|
// Locking: subscription
|
||||||
@@ -95,7 +115,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " (contactId INT NOT NULL,"
|
+ " (contactId INT NOT NULL,"
|
||||||
+ " groupId HASH NOT NULL," // Not a foreign key
|
+ " groupId HASH NOT NULL," // Not a foreign key
|
||||||
+ " name VARCHAR NOT NULL,"
|
+ " name VARCHAR NOT NULL,"
|
||||||
+ " key BINARY," // Null for unrestricted groups
|
+ " publicKey BINARY," // Null for unrestricted groups
|
||||||
+ " PRIMARY KEY (contactId, groupId),"
|
+ " PRIMARY KEY (contactId, groupId),"
|
||||||
+ " FOREIGN KEY (contactId)"
|
+ " FOREIGN KEY (contactId)"
|
||||||
+ " REFERENCES contacts (contactId)"
|
+ " REFERENCES contacts (contactId)"
|
||||||
@@ -378,6 +398,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
Statement s = null;
|
Statement s = null;
|
||||||
try {
|
try {
|
||||||
s = txn.createStatement();
|
s = txn.createStatement();
|
||||||
|
s.executeUpdate(insertTypeNames(CREATE_LOCAL_AUTHORS));
|
||||||
|
s.executeUpdate(insertTypeNames(CREATE_LOCAL_GROUPS));
|
||||||
s.executeUpdate(insertTypeNames(CREATE_CONTACTS));
|
s.executeUpdate(insertTypeNames(CREATE_CONTACTS));
|
||||||
s.executeUpdate(insertTypeNames(CREATE_GROUPS));
|
s.executeUpdate(insertTypeNames(CREATE_GROUPS));
|
||||||
s.executeUpdate(insertTypeNames(CREATE_GROUP_VISIBILITIES));
|
s.executeUpdate(insertTypeNames(CREATE_GROUP_VISIBILITIES));
|
||||||
@@ -672,6 +694,48 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addLocalAuthor(Connection txn, LocalAuthor a)
|
||||||
|
throws DbException {
|
||||||
|
PreparedStatement ps = null;
|
||||||
|
try {
|
||||||
|
String sql = "INSERT INTO localAuthors"
|
||||||
|
+ " (authorId, name, publicKey, privateKey)"
|
||||||
|
+ " VALUES (?, ?, ?, ?)";
|
||||||
|
ps = txn.prepareStatement(sql);
|
||||||
|
ps.setBytes(1, a.getId().getBytes());
|
||||||
|
ps.setString(2, a.getName());
|
||||||
|
ps.setBytes(3, a.getPublicKey());
|
||||||
|
ps.setBytes(4, a.getPrivateKey());
|
||||||
|
int affected = ps.executeUpdate();
|
||||||
|
if(affected != 1) throw new DbStateException();
|
||||||
|
ps.close();
|
||||||
|
} catch(SQLException e) {
|
||||||
|
tryToClose(ps);
|
||||||
|
throw new DbException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addLocalGroup(Connection txn, LocalGroup g)
|
||||||
|
throws DbException {
|
||||||
|
PreparedStatement ps = null;
|
||||||
|
try {
|
||||||
|
String sql = "INSERT INTO localGroups"
|
||||||
|
+ " (groupId, name, publicKey, privateKey)"
|
||||||
|
+ " VALUES (?, ?, ?, ?)";
|
||||||
|
ps = txn.prepareStatement(sql);
|
||||||
|
ps.setBytes(1, g.getId().getBytes());
|
||||||
|
ps.setString(2, g.getName());
|
||||||
|
ps.setBytes(3, g.getPublicKey());
|
||||||
|
ps.setBytes(4, g.getPrivateKey());
|
||||||
|
int affected = ps.executeUpdate();
|
||||||
|
if(affected != 1) throw new DbStateException();
|
||||||
|
ps.close();
|
||||||
|
} catch(SQLException e) {
|
||||||
|
tryToClose(ps);
|
||||||
|
throw new DbException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void addMessageToAck(Connection txn, ContactId c, MessageId m)
|
public void addMessageToAck(Connection txn, ContactId c, MessageId m)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
@@ -819,7 +883,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
ps.close();
|
ps.close();
|
||||||
if(count > MAX_SUBSCRIPTIONS) throw new DbStateException();
|
if(count > MAX_SUBSCRIPTIONS) throw new DbStateException();
|
||||||
if(count == MAX_SUBSCRIPTIONS) return false;
|
if(count == MAX_SUBSCRIPTIONS) return false;
|
||||||
sql = "INSERT INTO groups (groupId, name, key) VALUES (?, ?, ?)";
|
sql = "INSERT INTO groups (groupId, name, publicKey)"
|
||||||
|
+ " VALUES (?, ?, ?)";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setBytes(1, g.getId().getBytes());
|
ps.setBytes(1, g.getId().getBytes());
|
||||||
ps.setString(2, g.getName());
|
ps.setString(2, g.getName());
|
||||||
@@ -1154,7 +1219,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
try {
|
try {
|
||||||
String sql = "SELECT name, key FROM groups WHERE groupId = ?";
|
String sql = "SELECT name, publicKey FROM groups WHERE groupId = ?";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setBytes(1, g.getBytes());
|
ps.setBytes(1, g.getBytes());
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
@@ -1222,6 +1287,56 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Collection<LocalAuthor> getLocalAuthors(Connection txn)
|
||||||
|
throws DbException {
|
||||||
|
PreparedStatement ps = null;
|
||||||
|
ResultSet rs = null;
|
||||||
|
try {
|
||||||
|
String sql = "SELECT authorId, name, publicKey, privateKey"
|
||||||
|
+ " FROM localAuthors";
|
||||||
|
ps = txn.prepareStatement(sql);
|
||||||
|
rs = ps.executeQuery();
|
||||||
|
List<LocalAuthor> authors = new ArrayList<LocalAuthor>();
|
||||||
|
while(rs.next()) {
|
||||||
|
AuthorId id = new AuthorId(rs.getBytes(1));
|
||||||
|
authors.add(new LocalAuthor(id, rs.getString(2), rs.getBytes(3),
|
||||||
|
rs.getBytes(4)));
|
||||||
|
}
|
||||||
|
rs.close();
|
||||||
|
ps.close();
|
||||||
|
return Collections.unmodifiableList(authors);
|
||||||
|
} catch(SQLException e) {
|
||||||
|
tryToClose(rs);
|
||||||
|
tryToClose(ps);
|
||||||
|
throw new DbException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<LocalGroup> getLocalGroups(Connection txn)
|
||||||
|
throws DbException {
|
||||||
|
PreparedStatement ps = null;
|
||||||
|
ResultSet rs = null;
|
||||||
|
try {
|
||||||
|
String sql = "SELECT groupId, name, publicKey, privateKey"
|
||||||
|
+ " FROM localGroups";
|
||||||
|
ps = txn.prepareStatement(sql);
|
||||||
|
rs = ps.executeQuery();
|
||||||
|
List<LocalGroup> groups = new ArrayList<LocalGroup>();
|
||||||
|
while(rs.next()) {
|
||||||
|
GroupId id = new GroupId(rs.getBytes(1));
|
||||||
|
groups.add(new LocalGroup(id, rs.getString(2), rs.getBytes(3),
|
||||||
|
rs.getBytes(4)));
|
||||||
|
}
|
||||||
|
rs.close();
|
||||||
|
ps.close();
|
||||||
|
return Collections.unmodifiableList(groups);
|
||||||
|
} catch(SQLException e) {
|
||||||
|
tryToClose(rs);
|
||||||
|
tryToClose(ps);
|
||||||
|
throw new DbException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public TransportProperties getLocalProperties(Connection txn, TransportId t)
|
public TransportProperties getLocalProperties(Connection txn, TransportId t)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
@@ -1965,7 +2080,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
try {
|
try {
|
||||||
String sql = "SELECT groupId, name, key FROM groups";
|
String sql = "SELECT groupId, name, publicKey FROM groups";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
List<Group> subs = new ArrayList<Group>();
|
List<Group> subs = new ArrayList<Group>();
|
||||||
@@ -1990,7 +2105,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
try {
|
try {
|
||||||
String sql = "SELECT groupId, name, key FROM contactGroups"
|
String sql = "SELECT groupId, name, publicKey FROM contactGroups"
|
||||||
+ " WHERE contactId = ?";
|
+ " WHERE contactId = ?";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setInt(1, c.getInt());
|
ps.setInt(1, c.getInt());
|
||||||
@@ -2052,7 +2167,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
try {
|
try {
|
||||||
String sql = "SELECT g.groupId, name, key, localVersion, txCount"
|
String sql = "SELECT g.groupId, name, publicKey,"
|
||||||
|
+ " localVersion, txCount"
|
||||||
+ " FROM groups AS g"
|
+ " FROM groups AS g"
|
||||||
+ " JOIN groupVisibilities AS vis"
|
+ " JOIN groupVisibilities AS vis"
|
||||||
+ " ON g.groupId = vis.groupId"
|
+ " ON g.groupId = vis.groupId"
|
||||||
@@ -3023,7 +3139,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
ps.executeUpdate();
|
ps.executeUpdate();
|
||||||
// Store the new subscriptions, if any
|
// Store the new subscriptions, if any
|
||||||
if(subs.isEmpty()) return;
|
if(subs.isEmpty()) return;
|
||||||
sql = "INSERT INTO contactGroups (contactId, groupId, name, key)"
|
sql = "INSERT INTO contactGroups"
|
||||||
|
+ " (contactId, groupId, name, publicKey)"
|
||||||
+ " VALUES (?, ?, ?, ?)";
|
+ " VALUES (?, ?, ?, ?)";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setInt(1, c.getInt());
|
ps.setInt(1, c.getInt());
|
||||||
|
|||||||
Reference in New Issue
Block a user