All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ch.dissem.bitmessage.repository.JdbcAddressRepository Maven / Gradle / Ivy

Go to download

A Java implementation of the Bitmessage protocol. This contains JDBC implementations of the repositories.

There is a newer version: 2.0.4
Show newest version
/*
 * Copyright 2015 Christian Basler
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package ch.dissem.bitmessage.repository;

import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.payload.Pubkey;
import ch.dissem.bitmessage.entity.payload.V3Pubkey;
import ch.dissem.bitmessage.entity.payload.V4Pubkey;
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
import ch.dissem.bitmessage.factory.Factory;
import ch.dissem.bitmessage.ports.AddressRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

public class JdbcAddressRepository extends JdbcHelper implements AddressRepository {
    private static final Logger LOG = LoggerFactory.getLogger(JdbcAddressRepository.class);

    public JdbcAddressRepository(JdbcConfig config) {
        super(config);
    }

    @Override
    public BitmessageAddress findContact(byte[] ripeOrTag) {
        for (BitmessageAddress address : find("public_key is null")) {
            if (address.getVersion() > 3) {
                if (Arrays.equals(ripeOrTag, address.getTag())) return address;
            } else {
                if (Arrays.equals(ripeOrTag, address.getRipe())) return address;
            }
        }
        return null;
    }

    @Override
    public BitmessageAddress findIdentity(byte[] ripeOrTag) {
        for (BitmessageAddress address : find("private_key is not null")) {
            if (address.getVersion() > 3) {
                if (Arrays.equals(ripeOrTag, address.getTag())) return address;
            } else {
                if (Arrays.equals(ripeOrTag, address.getRipe())) return address;
            }
        }
        return null;
    }

    @Override
    public List getIdentities() {
        return find("private_key IS NOT NULL");
    }

    @Override
    public List getChans() {
        return find("chan = '1'");
    }

    @Override
    public List getSubscriptions() {
        return find("subscribed = '1'");
    }

    @Override
    public List getSubscriptions(long broadcastVersion) {
        if (broadcastVersion > 4) {
            return find("subscribed = '1' AND version > 3");
        } else {
            return find("subscribed = '1' AND version <= 3");
        }
    }

    @Override
    public List getContacts() {
        return find("private_key IS NULL OR chan = '1'");
    }

    private List find(String where) {
        List result = new LinkedList<>();
        try (
                Connection connection = config.getConnection();
                Statement stmt = connection.createStatement();
                ResultSet rs = stmt.executeQuery("SELECT address, alias, public_key, private_key, subscribed, chan " +
                        "FROM Address WHERE " + where)
        ) {
            while (rs.next()) {
                BitmessageAddress address;

                InputStream privateKeyStream = rs.getBinaryStream("private_key");
                if (privateKeyStream == null) {
                    address = new BitmessageAddress(rs.getString("address"));
                    Blob publicKeyBlob = rs.getBlob("public_key");
                    if (publicKeyBlob != null) {
                        Pubkey pubkey = Factory.readPubkey(address.getVersion(), address.getStream(),
                                publicKeyBlob.getBinaryStream(), (int) publicKeyBlob.length(), false);
                        if (address.getVersion() == 4 && pubkey instanceof V3Pubkey) {
                            pubkey = new V4Pubkey((V3Pubkey) pubkey);
                        }
                        address.setPubkey(pubkey);
                    }
                } else {
                    PrivateKey privateKey = PrivateKey.read(privateKeyStream);
                    address = new BitmessageAddress(privateKey);
                }
                address.setAlias(rs.getString("alias"));
                address.setSubscribed(rs.getBoolean("subscribed"));
                address.setChan(rs.getBoolean("chan"));

                result.add(address);
            }
        } catch (IOException | SQLException e) {
            LOG.error(e.getMessage(), e);
        }
        return result;
    }

    private boolean exists(BitmessageAddress address) {
        try (
                Connection connection = config.getConnection();
                Statement stmt = connection.createStatement();
                ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM Address " +
                        "WHERE address='" + address.getAddress() + "'")
        ) {
            if (rs.next()) {
                return rs.getInt(1) > 0;
            }
        } catch (SQLException e) {
            LOG.error(e.getMessage(), e);
        }
        return false;
    }

    @Override
    public void save(BitmessageAddress address) {
        try {
            if (exists(address)) {
                update(address);
            } else {
                insert(address);
            }
        } catch (IOException | SQLException e) {
            LOG.error(e.getMessage(), e);
        }
    }

    private void update(BitmessageAddress address) throws IOException, SQLException {
        StringBuilder statement = new StringBuilder("UPDATE Address SET alias=?");
        if (address.getPubkey() != null) {
            statement.append(", public_key=?");
        }
        if (address.getPrivateKey() != null) {
            statement.append(", private_key=?");
        }
        statement.append(", subscribed=?, chan=? WHERE address=?");
        try (
                Connection connection = config.getConnection();
                PreparedStatement ps = connection.prepareStatement(statement.toString())
        ) {
            int i = 0;
            ps.setString(++i, address.getAlias());
            if (address.getPubkey() != null) {
                writePubkey(ps, ++i, address.getPubkey());
            }
            if (address.getPrivateKey() != null) {
                writeBlob(ps, ++i, address.getPrivateKey());
            }
            ps.setBoolean(++i, address.isSubscribed());
            ps.setBoolean(++i, address.isChan());
            ps.setString(++i, address.getAddress());
            ps.executeUpdate();
        }
    }

    private void insert(BitmessageAddress address) throws IOException, SQLException {
        try (
                Connection connection = config.getConnection();
                PreparedStatement ps = connection.prepareStatement(
                        "INSERT INTO Address (address, version, alias, public_key, private_key, subscribed, chan) " +
                                "VALUES (?, ?, ?, ?, ?, ?, ?)")
        ) {
            ps.setString(1, address.getAddress());
            ps.setLong(2, address.getVersion());
            ps.setString(3, address.getAlias());
            writePubkey(ps, 4, address.getPubkey());
            writeBlob(ps, 5, address.getPrivateKey());
            ps.setBoolean(6, address.isSubscribed());
            ps.setBoolean(7, address.isChan());
            ps.executeUpdate();
        }
    }

    protected void writePubkey(PreparedStatement ps, int parameterIndex, Pubkey data) throws SQLException, IOException {
        if (data != null) {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            data.writeUnencrypted(out);
            ps.setBytes(parameterIndex, out.toByteArray());
        } else {
            ps.setBytes(parameterIndex, null);
        }
    }

    @Override
    public void remove(BitmessageAddress address) {
        try (
                Connection connection = config.getConnection();
                Statement stmt = connection.createStatement()
        ) {
            stmt.executeUpdate("DELETE FROM Address WHERE address = '" + address.getAddress() + "'");
        } catch (SQLException e) {
            LOG.error(e.getMessage(), e);
        }
    }

    @Override
    public BitmessageAddress getAddress(String address) {
        List result = find("address = '" + address + "'");
        if (result.size() > 0) return result.get(0);
        return null;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy