Server POW and some admin functions
(needs some testing)
This commit is contained in:
parent
7a5dc1af4d
commit
5c4b976417
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip
|
||||
|
13
src/main/java/ch/dissem/bitmessage/server/Constants.java
Normal file
13
src/main/java/ch/dissem/bitmessage/server/Constants.java
Normal file
@ -0,0 +1,13 @@
|
||||
package ch.dissem.bitmessage.server;
|
||||
|
||||
/**
|
||||
* Created by chrigu on 22.11.15.
|
||||
*/
|
||||
public interface Constants {
|
||||
String ADMIN_LIST = "admins.conf";
|
||||
String CLIENT_LIST = "clients.conf";
|
||||
|
||||
String WHITELIST = "whitelist.conf";
|
||||
String SHORTLIST = "shortlist.conf";
|
||||
String BLACKLIST = "blacklist.conf";
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package ch.dissem.bitmessage.server;
|
||||
|
||||
import ch.dissem.bitmessage.BitmessageContext;
|
||||
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
||||
import ch.dissem.bitmessage.networking.DefaultNetworkHandler;
|
||||
import ch.dissem.bitmessage.ports.MemoryNodeRegistry;
|
||||
import ch.dissem.bitmessage.repository.JdbcAddressRepository;
|
||||
@ -16,6 +17,9 @@ import springfox.documentation.spring.web.plugins.Docket;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static ch.dissem.bitmessage.server.Constants.*;
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
|
||||
@Configuration
|
||||
public class JabitServerConfig {
|
||||
public static final int SHORTLIST_SIZE = 5;
|
||||
@ -36,19 +40,34 @@ public class JabitServerConfig {
|
||||
.messageRepo(new JdbcMessageRepository(config))
|
||||
.nodeRegistry(new MemoryNodeRegistry())
|
||||
.networkHandler(new DefaultNetworkHandler())
|
||||
.objectListener(new ServerObjectListener(admins(), clients(), whitelist(), shortlist(), blacklist()))
|
||||
.security(new BouncySecurity())
|
||||
.port(port)
|
||||
.connectionLimit(connectionLimit)
|
||||
.connectionTTL(connectionTTL)
|
||||
.listener(plaintext -> {
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Set<BitmessageAddress> admins() {
|
||||
return Utils.readOrCreateList(
|
||||
ADMIN_LIST,
|
||||
"# Admins can send commands to the server.\n"
|
||||
).stream().map(BitmessageAddress::new).collect(toSet());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Set<BitmessageAddress> clients() {
|
||||
return Utils.readOrCreateList(
|
||||
CLIENT_LIST,
|
||||
"# Clients may send incomplete objects for proof of work.\n"
|
||||
).stream().map(BitmessageAddress::new).collect(toSet());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Set<String> whitelist() {
|
||||
return Utils.readOrCreateList(
|
||||
"whitelist.conf",
|
||||
WHITELIST,
|
||||
"# If there are any Bitmessage addresses in the whitelist, only those will be shown.\n" +
|
||||
"# blacklist.conf will be ignored, but shortlist.conf will be applied to whitelisted addresses.\n"
|
||||
);
|
||||
@ -57,7 +76,7 @@ public class JabitServerConfig {
|
||||
@Bean
|
||||
public Set<String> shortlist() {
|
||||
return Utils.readOrCreateList(
|
||||
"shortlist.conf",
|
||||
SHORTLIST,
|
||||
"# Broadcasts of these addresses will be restricted to the last " + SHORTLIST_SIZE + " entries.\n\n" +
|
||||
"# Time Service:\n" +
|
||||
"BM-BcbRqcFFSQUUmXFKsPJgVQPSiFA3Xash\n\n" +
|
||||
@ -69,7 +88,7 @@ public class JabitServerConfig {
|
||||
@Bean
|
||||
public Set<String> blacklist() {
|
||||
return Utils.readOrCreateList(
|
||||
"blacklist.conf",
|
||||
BLACKLIST,
|
||||
"# Bitmessage addresses in this file are being ignored and their broadcasts won't be returned.\n"
|
||||
);
|
||||
}
|
||||
|
@ -0,0 +1,160 @@
|
||||
package ch.dissem.bitmessage.server;
|
||||
|
||||
import ch.dissem.bitmessage.DefaultObjectListener;
|
||||
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
||||
import ch.dissem.bitmessage.entity.ObjectMessage;
|
||||
import ch.dissem.bitmessage.entity.Plaintext;
|
||||
import ch.dissem.bitmessage.entity.payload.Broadcast;
|
||||
import ch.dissem.bitmessage.exception.DecryptionFailedException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Scanner;
|
||||
|
||||
import static ch.dissem.bitmessage.factory.Factory.getObjectMessage;
|
||||
import static ch.dissem.bitmessage.server.Constants.*;
|
||||
import static ch.dissem.bitmessage.server.Utils.zero;
|
||||
import static ch.dissem.bitmessage.utils.Singleton.security;
|
||||
|
||||
/**
|
||||
* @author Christian Basler
|
||||
*/
|
||||
public class ServerObjectListener extends DefaultObjectListener {
|
||||
private final static Logger LOG = LoggerFactory.getLogger(ServerObjectListener.class);
|
||||
|
||||
private final Collection<BitmessageAddress> admins;
|
||||
private final Collection<BitmessageAddress> clients;
|
||||
|
||||
private final Collection<String> whitelist;
|
||||
private final Collection<String> shortlist;
|
||||
private final Collection<String> blacklist;
|
||||
|
||||
public ServerObjectListener(Collection<BitmessageAddress> admins, Collection<BitmessageAddress> clients, Collection<String> whitelist, Collection<String> shortlist, Collection<String> blacklist) {
|
||||
super(p -> {
|
||||
});
|
||||
this.admins = admins;
|
||||
this.clients = clients;
|
||||
this.whitelist = whitelist;
|
||||
this.shortlist = shortlist;
|
||||
this.blacklist = blacklist;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void receive(ObjectMessage object, Broadcast broadcast) throws IOException {
|
||||
processCommands(broadcast);
|
||||
if (zero(object.getNonce())) {
|
||||
calculateNonceForClient(object, broadcast);
|
||||
} else {
|
||||
super.receive(object, broadcast);
|
||||
}
|
||||
}
|
||||
|
||||
private void processCommands(Broadcast broadcast) throws IOException {
|
||||
for (BitmessageAddress admin : admins) {
|
||||
try {
|
||||
broadcast.decrypt(admin);
|
||||
Plaintext message = broadcast.getPlaintext();
|
||||
String[] command = message.getSubject().trim().toLowerCase().split("\\s+");
|
||||
String data = message.getText();
|
||||
if (command.length == 2) {
|
||||
switch (command[1]) {
|
||||
case "client":
|
||||
case "clients":
|
||||
updateUserList(CLIENT_LIST, clients, command[0], data);
|
||||
break;
|
||||
case "admin":
|
||||
case "admins":
|
||||
case "administrator":
|
||||
case "administrators":
|
||||
updateUserList(ADMIN_LIST, admins, command[0], data);
|
||||
break;
|
||||
case "whitelist":
|
||||
updateList(WHITELIST, whitelist, command[0], data);
|
||||
break;
|
||||
case "shortlist":
|
||||
updateList(WHITELIST, shortlist, command[0], data);
|
||||
break;
|
||||
case "blacklist":
|
||||
updateList(WHITELIST, blacklist, command[0], data);
|
||||
break;
|
||||
default:
|
||||
LOG.trace("ignoring unknown command " + message.getSubject());
|
||||
}
|
||||
}
|
||||
} catch (DecryptionFailedException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateNonceForClient(ObjectMessage object, Broadcast broadcast) throws IOException {
|
||||
for (BitmessageAddress client : clients) {
|
||||
try {
|
||||
broadcast.decrypt(client);
|
||||
byte[] message = broadcast.getPlaintext().getMessage();
|
||||
final ObjectMessage toRelay = getObjectMessage(3, new ByteArrayInputStream(message), message.length);
|
||||
security().doProofOfWork(toRelay,
|
||||
ctx.getNetworkNonceTrialsPerByte(), ctx.getNetworkExtraBytes(),
|
||||
(nonce) -> {
|
||||
toRelay.setNonce(nonce);
|
||||
ctx.getInventory().storeObject(object);
|
||||
ctx.getNetworkHandler().offer(object.getInventoryVector());
|
||||
}
|
||||
);
|
||||
} catch (DecryptionFailedException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateUserList(String file, Collection<BitmessageAddress> list, String command, String data) {
|
||||
switch (command) {
|
||||
case "set":
|
||||
list.clear();
|
||||
case "add":
|
||||
Scanner scanner = new Scanner(data);
|
||||
while (scanner.hasNextLine()) {
|
||||
String line = scanner.nextLine();
|
||||
try {
|
||||
list.add(new BitmessageAddress(line));
|
||||
} catch (Exception e) {
|
||||
LOG.info(command + " " + file + ": ignoring line: " + line);
|
||||
}
|
||||
}
|
||||
Utils.saveList(file, list.stream().map(BitmessageAddress::getAddress));
|
||||
break;
|
||||
case "remove":
|
||||
list.removeIf(address -> data.contains(address.getAddress()));
|
||||
Utils.saveList(file, list.stream().map(BitmessageAddress::getAddress));
|
||||
break;
|
||||
default:
|
||||
LOG.info("unknown command " + command + " on list " + file);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateList(String file, Collection<String> list, String command, String data) {
|
||||
switch (command) {
|
||||
case "set":
|
||||
list.clear();
|
||||
case "add":
|
||||
Scanner scanner = new Scanner(data);
|
||||
while (scanner.hasNextLine()) {
|
||||
String line = scanner.nextLine();
|
||||
try {
|
||||
list.add(new BitmessageAddress(line).getAddress());
|
||||
} catch (Exception e) {
|
||||
LOG.info(command + " " + file + ": ignoring line: " + line);
|
||||
}
|
||||
}
|
||||
Utils.saveList(file, list.stream());
|
||||
break;
|
||||
case "remove":
|
||||
list.removeIf(data::contains);
|
||||
Utils.saveList(file, list.stream());
|
||||
break;
|
||||
default:
|
||||
LOG.info("unknown command " + command + " on list " + file);
|
||||
}
|
||||
}
|
||||
}
|
@ -4,7 +4,10 @@ import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.HashSet;
|
||||
import java.util.Scanner;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Utils {
|
||||
public static Set<String> readOrCreateList(String filename, String content) {
|
||||
@ -23,6 +26,24 @@ public class Utils {
|
||||
}
|
||||
}
|
||||
|
||||
public static void saveList(String filename, Stream<String> content) {
|
||||
try {
|
||||
File file = new File(filename);
|
||||
try (FileWriter fw = new FileWriter(file)) {
|
||||
content.forEach(l -> {
|
||||
try {
|
||||
fw.write(l);
|
||||
fw.write(System.lineSeparator());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Set<String> readList(File file) {
|
||||
Set<String> result = new HashSet<>();
|
||||
try {
|
||||
@ -38,4 +59,11 @@ public class Utils {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static boolean zero(byte[] nonce) {
|
||||
for (byte b : nonce) {
|
||||
if (b != 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user