Some code for supporting chans
This commit is contained in:
parent
3e5e431d6f
commit
ead5341b2e
@ -17,10 +17,7 @@
|
||||
package ch.dissem.bitmessage;
|
||||
|
||||
import ch.dissem.bitmessage.entity.*;
|
||||
import ch.dissem.bitmessage.entity.payload.Broadcast;
|
||||
import ch.dissem.bitmessage.entity.payload.Msg;
|
||||
import ch.dissem.bitmessage.entity.payload.ObjectPayload;
|
||||
import ch.dissem.bitmessage.entity.payload.ObjectType;
|
||||
import ch.dissem.bitmessage.entity.payload.*;
|
||||
import ch.dissem.bitmessage.entity.payload.Pubkey.Feature;
|
||||
import ch.dissem.bitmessage.entity.valueobject.Label;
|
||||
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
|
||||
@ -117,9 +114,17 @@ public class BitmessageContext {
|
||||
return identity;
|
||||
}
|
||||
|
||||
public void addDistributedMailingList(String address, String alias) {
|
||||
// TODO
|
||||
throw new ApplicationException("not implemented");
|
||||
public BitmessageAddress joinChan(String passphrase, String address) {
|
||||
BitmessageAddress chan = BitmessageAddress.chan(address, passphrase);
|
||||
ctx.getAddressRepository().save(chan);
|
||||
return chan;
|
||||
}
|
||||
|
||||
public BitmessageAddress createChan(String passphrase) {
|
||||
// FIXME: hardcoded stream number
|
||||
BitmessageAddress chan = BitmessageAddress.chan(1, passphrase);
|
||||
ctx.getAddressRepository().save(chan);
|
||||
return chan;
|
||||
}
|
||||
|
||||
public void broadcast(final BitmessageAddress from, final String subject, final String message) {
|
||||
|
@ -57,6 +57,7 @@ public class BitmessageAddress implements Serializable {
|
||||
|
||||
private String alias;
|
||||
private boolean subscribed;
|
||||
private boolean chan;
|
||||
|
||||
BitmessageAddress(long version, long stream, byte[] ripe) {
|
||||
try {
|
||||
@ -93,6 +94,27 @@ public class BitmessageAddress implements Serializable {
|
||||
this.pubkey = publicKey;
|
||||
}
|
||||
|
||||
public BitmessageAddress(String address, String passphrase) {
|
||||
this(address);
|
||||
this.privateKey = new PrivateKey(this, passphrase);
|
||||
if (!Arrays.equals(ripe, privateKey.getPubkey().getRipe())) {
|
||||
throw new IllegalArgumentException("Wrong address or passphrase");
|
||||
}
|
||||
}
|
||||
|
||||
public static BitmessageAddress chan(String address, String passphrase) {
|
||||
BitmessageAddress result = new BitmessageAddress(address, passphrase);
|
||||
result.chan = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
public static BitmessageAddress chan(long stream, String passphrase) {
|
||||
PrivateKey privateKey = new PrivateKey(Pubkey.LATEST_VERSION, stream, passphrase);
|
||||
BitmessageAddress result = new BitmessageAddress(privateKey);
|
||||
result.chan = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
public BitmessageAddress(PrivateKey privateKey) {
|
||||
this(privateKey.getPubkey());
|
||||
this.privateKey = privateKey;
|
||||
@ -221,4 +243,8 @@ public class BitmessageAddress implements Serializable {
|
||||
public void setSubscribed(boolean subscribed) {
|
||||
this.subscribed = subscribed;
|
||||
}
|
||||
|
||||
public boolean isChan() {
|
||||
return chan;
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package ch.dissem.bitmessage.entity.valueobject;
|
||||
|
||||
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
||||
import ch.dissem.bitmessage.entity.Streamable;
|
||||
import ch.dissem.bitmessage.entity.payload.Pubkey;
|
||||
import ch.dissem.bitmessage.exception.ApplicationException;
|
||||
@ -64,14 +65,32 @@ public class PrivateKey implements Streamable {
|
||||
this.pubkey = pubkey;
|
||||
}
|
||||
|
||||
public PrivateKey(long version, long stream, String passphrase, long nonceTrialsPerByte, long extraBytes, Pubkey.Feature... features) {
|
||||
public PrivateKey(BitmessageAddress address, String passphrase) {
|
||||
this(address.getVersion(), address.getStream(), passphrase);
|
||||
}
|
||||
|
||||
public PrivateKey(long version, long stream, String passphrase) {
|
||||
try {
|
||||
// FIXME: this is most definitely wrong
|
||||
this.privateSigningKey = Bytes.truncate(security().sha512(passphrase.getBytes("UTF-8"), new byte[]{0}), 32);
|
||||
this.privateEncryptionKey = Bytes.truncate(security().sha512(passphrase.getBytes("UTF-8"), new byte[]{1}), 32);
|
||||
this.pubkey = security().createPubkey(version, stream, privateSigningKey, privateEncryptionKey,
|
||||
nonceTrialsPerByte, extraBytes, features);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
byte[] signingKey;
|
||||
int signingKeyNonce = 0;
|
||||
byte[] encryptionKey;
|
||||
int encryptionKeyNonce = 1;
|
||||
byte[] passPhraseBytes = passphrase.getBytes("UTF-8");
|
||||
byte[] ripe;
|
||||
do {
|
||||
signingKey = Bytes.truncate(security().sha512(passPhraseBytes, Encode.varInt(signingKeyNonce)), 32);
|
||||
encryptionKey = Bytes.truncate(security().sha512(passPhraseBytes, Encode.varInt(encryptionKeyNonce)), 32);
|
||||
byte[] publicSigningKey = security().createPublicKey(signingKey);
|
||||
byte[] publicEncryptionKey = security().createPublicKey(encryptionKey);
|
||||
ripe = security().ripemd160(security().sha512(publicSigningKey, publicEncryptionKey));
|
||||
|
||||
signingKeyNonce += 2;
|
||||
encryptionKeyNonce += 2;
|
||||
} while (ripe[0] != 0);
|
||||
this.privateSigningKey = signingKey;
|
||||
this.privateEncryptionKey = encryptionKey;
|
||||
this.pubkey = security().createPubkey(version, stream, privateSigningKey, privateEncryptionKey, 0, 0);
|
||||
} catch (IOException e) {
|
||||
throw new ApplicationException(e);
|
||||
}
|
||||
}
|
||||
|
@ -41,6 +41,34 @@ public class Encode {
|
||||
varInt(value, stream, null);
|
||||
}
|
||||
|
||||
public static byte[] varInt(long value) throws IOException {
|
||||
final byte[] result;
|
||||
if (value < 0) {
|
||||
// This is due to the fact that Java doesn't really support unsigned values.
|
||||
// Please be aware that this might be an error due to a smaller negative value being cast to long.
|
||||
// Normally, negative values shouldn't occur within the protocol, and I large enough longs
|
||||
// to being recognized as negatives aren't realistic.
|
||||
ByteBuffer buffer = ByteBuffer.allocate(9);
|
||||
buffer.put((byte) 0xff);
|
||||
result = buffer.putLong(value).array();
|
||||
} else if (value < 0xfd) {
|
||||
result = new byte[]{(byte) value};
|
||||
} else if (value <= 0xffffL) {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(3);
|
||||
buffer.put((byte) 0xfd);
|
||||
result = buffer.putShort((short) value).array();
|
||||
} else if (value <= 0xffffffffL) {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(5);
|
||||
buffer.put((byte) 0xfe);
|
||||
result = buffer.putInt((int) value).array();
|
||||
} else {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(9);
|
||||
buffer.put((byte) 0xff);
|
||||
result = buffer.putLong(value).array();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void varInt(long value, OutputStream stream, AccessCounter counter) throws IOException {
|
||||
if (value < 0) {
|
||||
// This is due to the fact that Java doesn't really support unsigned values.
|
||||
@ -81,7 +109,7 @@ public class Encode {
|
||||
}
|
||||
|
||||
public static void int16(long value, OutputStream stream, AccessCounter counter) throws IOException {
|
||||
stream.write(ByteBuffer.allocate(4).putInt((int) value).array(), 2, 2);
|
||||
stream.write(ByteBuffer.allocate(2).putShort((short) value).array());
|
||||
inc(counter, 2);
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ import static ch.dissem.bitmessage.entity.payload.ObjectType.*;
|
||||
import static ch.dissem.bitmessage.utils.MessageMatchers.object;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ -206,4 +206,21 @@ public class BitmessageContextTest {
|
||||
.build();
|
||||
ctx.send(msg);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ensureChanIsJoined() {
|
||||
String chanAddress = "BM-2cW67GEKkHGonXKZLCzouLLxnLym3azS8r";
|
||||
BitmessageAddress chan = ctx.joinChan("general", chanAddress);
|
||||
assertNotNull(chan);
|
||||
assertEquals(chan.getAddress(), chanAddress);
|
||||
assertTrue(chan.isChan());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ensureChanIsCreated() {
|
||||
BitmessageAddress chan = ctx.createChan("test");
|
||||
assertNotNull(chan);
|
||||
assertEquals(chan.getVersion(), Pubkey.LATEST_VERSION);
|
||||
assertTrue(chan.isChan());
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,10 @@ import ch.dissem.bitmessage.entity.payload.Pubkey;
|
||||
import ch.dissem.bitmessage.entity.payload.V4Pubkey;
|
||||
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
|
||||
import ch.dissem.bitmessage.exception.DecryptionFailedException;
|
||||
import ch.dissem.bitmessage.utils.*;
|
||||
import ch.dissem.bitmessage.utils.Base58;
|
||||
import ch.dissem.bitmessage.utils.Bytes;
|
||||
import ch.dissem.bitmessage.utils.Strings;
|
||||
import ch.dissem.bitmessage.utils.TestUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
|
Loading…
Reference in New Issue
Block a user