Some code for supporting chans
This commit is contained in:
		@@ -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;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user