mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-16 12:49:55 +01:00
briar-headless: Add command line arguments
This commit is contained in:
@@ -1,56 +0,0 @@
|
|||||||
package org.briarproject.bramble.system;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.ConfigurationManager;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.attribute.PosixFilePermission;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import static java.nio.file.Files.setPosixFilePermissions;
|
|
||||||
import static java.nio.file.attribute.PosixFilePermission.OWNER_EXECUTE;
|
|
||||||
import static java.nio.file.attribute.PosixFilePermission.OWNER_READ;
|
|
||||||
import static java.nio.file.attribute.PosixFilePermission.OWNER_WRITE;
|
|
||||||
import static java.util.logging.Level.WARNING;
|
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
|
||||||
class JavaConfigurationManager implements ConfigurationManager {
|
|
||||||
|
|
||||||
private static final Logger LOG =
|
|
||||||
Logger.getLogger(JavaConfigurationManager.class.getName());
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public JavaConfigurationManager() {
|
|
||||||
try {
|
|
||||||
ensurePermissions(getAppDir());
|
|
||||||
} catch (IOException e) {
|
|
||||||
logException(LOG, WARNING, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public File getAppDir() {
|
|
||||||
String home = System.getProperty("user.home");
|
|
||||||
return new File(home + File.separator + ".briar");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ensurePermissions(File file)throws IOException {
|
|
||||||
if (!file.exists()) {
|
|
||||||
if (!file.mkdirs()) {
|
|
||||||
throw new IOException("Could not create directory");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Set<PosixFilePermission> perms = new HashSet<>();
|
|
||||||
perms.add(OWNER_READ);
|
|
||||||
perms.add(OWNER_WRITE);
|
|
||||||
perms.add(OWNER_EXECUTE);
|
|
||||||
setPosixFilePermissions(file.toPath(), perms);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.briarproject.bramble.system;
|
package org.briarproject.bramble.system;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.ConfigurationManager;
|
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
import org.briarproject.bramble.api.system.LocationUtils;
|
||||||
import org.briarproject.bramble.api.system.ResourceProvider;
|
import org.briarproject.bramble.api.system.ResourceProvider;
|
||||||
|
|
||||||
@@ -12,13 +11,6 @@ import dagger.Provides;
|
|||||||
@Module
|
@Module
|
||||||
public class JavaSystemModule {
|
public class JavaSystemModule {
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
ConfigurationManager provideConfigurationManager(
|
|
||||||
JavaConfigurationManager configurationManager) {
|
|
||||||
return configurationManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
LocationUtils provideLocationUtils(JavaLocationUtils locationUtils) {
|
LocationUtils provideLocationUtils(JavaLocationUtils locationUtils) {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id 'java'
|
id 'java'
|
||||||
id 'net.ltgt.apt'
|
|
||||||
id 'idea'
|
id 'idea'
|
||||||
id "org.jetbrains.kotlin.jvm" version "1.2.61"
|
id 'org.jetbrains.kotlin.jvm' version '1.2.61'
|
||||||
|
id "org.jetbrains.kotlin.kapt" version "1.2.61"
|
||||||
id 'witness'
|
id 'witness'
|
||||||
}
|
}
|
||||||
apply from: 'witness.gradle'
|
apply from: 'witness.gradle'
|
||||||
@@ -17,8 +17,8 @@ dependencies {
|
|||||||
implementation 'io.javalin:javalin:2.1.0'
|
implementation 'io.javalin:javalin:2.1.0'
|
||||||
implementation 'org.slf4j:slf4j-simple:1.7.25'
|
implementation 'org.slf4j:slf4j-simple:1.7.25'
|
||||||
implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.6'
|
implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.6'
|
||||||
|
implementation 'com.github.ajalt:clikt:1.5.0'
|
||||||
|
|
||||||
apt 'com.google.dagger:dagger-compiler:2.0.2'
|
|
||||||
kapt 'com.google.dagger:dagger-compiler:2.0.2'
|
kapt 'com.google.dagger:dagger-compiler:2.0.2'
|
||||||
|
|
||||||
testImplementation project(path: ':bramble-api', configuration: 'testOutput')
|
testImplementation project(path: ':bramble-api', configuration: 'testOutput')
|
||||||
@@ -34,7 +34,7 @@ dependencies {
|
|||||||
jar {
|
jar {
|
||||||
manifest {
|
manifest {
|
||||||
attributes(
|
attributes(
|
||||||
'Main-Class': 'org.briarproject.briar.headless.Main'
|
'Main-Class': 'org.briarproject.briar.headless.MainKt'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
from {
|
from {
|
||||||
@@ -42,6 +42,15 @@ jar {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// At the moment for non-Android projects we need to explicitly mark the code generated by kapt
|
||||||
|
// as 'generated source code' for correct highlighting and resolve in IDE.
|
||||||
|
idea {
|
||||||
|
module {
|
||||||
|
sourceDirs += file('build/generated/source/kapt/main')
|
||||||
|
generatedSourceDirs += file('build/generated/source/kapt/main')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
test {
|
test {
|
||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
testLogging {
|
testLogging {
|
||||||
|
|||||||
@@ -1,113 +0,0 @@
|
|||||||
package org.briarproject.briar.headless;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.account.AccountManager;
|
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
|
||||||
|
|
||||||
import java.io.Console;
|
|
||||||
import java.util.Scanner;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import javax.annotation.ParametersAreNonnullByDefault;
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Singleton;
|
|
||||||
|
|
||||||
import static java.lang.System.console;
|
|
||||||
import static java.lang.System.err;
|
|
||||||
import static java.lang.System.exit;
|
|
||||||
import static java.lang.System.out;
|
|
||||||
import static java.util.logging.Logger.getLogger;
|
|
||||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
|
||||||
|
|
||||||
@Immutable
|
|
||||||
@Singleton
|
|
||||||
@MethodsNotNullByDefault
|
|
||||||
@ParametersAreNonnullByDefault
|
|
||||||
public class BriarService {
|
|
||||||
|
|
||||||
private final static Logger LOG = getLogger(BriarService.class.getName());
|
|
||||||
|
|
||||||
private final AccountManager accountManager;
|
|
||||||
private final LifecycleManager lifecycleManager;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public BriarService(AccountManager accountManager,
|
|
||||||
LifecycleManager lifecycleManager) {
|
|
||||||
this.accountManager = accountManager;
|
|
||||||
this.lifecycleManager = lifecycleManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start() {
|
|
||||||
Console console = console();
|
|
||||||
out.println("Welcome to Briar!\n");
|
|
||||||
|
|
||||||
if (!accountManager.accountExists()) {
|
|
||||||
if (console == null) {
|
|
||||||
LOG.warning("No account found.");
|
|
||||||
LOG.warning("Please start in terminal to set one up.");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
console.printf("No account found. Let's create one!\n\n");
|
|
||||||
String nickname = createNickname(console);
|
|
||||||
String password = createPassword(console);
|
|
||||||
accountManager.createAccount(nickname, password);
|
|
||||||
} else {
|
|
||||||
out.print("Password: ");
|
|
||||||
String password;
|
|
||||||
if (console == null) {
|
|
||||||
Scanner scanner = new Scanner(System.in);
|
|
||||||
password = scanner.nextLine();
|
|
||||||
} else {
|
|
||||||
password = new String(console.readPassword());
|
|
||||||
}
|
|
||||||
if (!accountManager.signIn(password)) {
|
|
||||||
err.println("Error: Password invalid");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert accountManager.getDatabaseKey() != null;
|
|
||||||
|
|
||||||
lifecycleManager.startServices(accountManager.getDatabaseKey());
|
|
||||||
}
|
|
||||||
|
|
||||||
private String createNickname(Console console) {
|
|
||||||
String nickname;
|
|
||||||
boolean error;
|
|
||||||
do {
|
|
||||||
nickname = console.readLine("Nickname: ");
|
|
||||||
if (nickname.length() == 0) {
|
|
||||||
console.printf("Please enter a nickname!\n");
|
|
||||||
error = true;
|
|
||||||
} else if (nickname.length() > MAX_AUTHOR_NAME_LENGTH) {
|
|
||||||
console.printf("Please choose a shorter nickname!\n");
|
|
||||||
error = true;
|
|
||||||
} else {
|
|
||||||
error = false;
|
|
||||||
}
|
|
||||||
} while (error);
|
|
||||||
return nickname;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String createPassword(Console console) {
|
|
||||||
String password;
|
|
||||||
boolean error;
|
|
||||||
do {
|
|
||||||
password = new String(console.readPassword("Password: "));
|
|
||||||
if (password.length() < 4) {
|
|
||||||
console.printf(
|
|
||||||
"Please enter a password with at least 4 characters!\n");
|
|
||||||
error = true;
|
|
||||||
// TODO enforce stronger password
|
|
||||||
} else {
|
|
||||||
error = false;
|
|
||||||
}
|
|
||||||
} while (error);
|
|
||||||
return password;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stop() {
|
|
||||||
lifecycleManager.stopServices();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package org.briarproject.briar.headless
|
||||||
|
|
||||||
|
import com.github.ajalt.clikt.core.UsageError
|
||||||
|
import com.github.ajalt.clikt.output.TermUi.echo
|
||||||
|
import com.github.ajalt.clikt.output.TermUi.prompt
|
||||||
|
import org.briarproject.bramble.api.account.AccountManager
|
||||||
|
import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator
|
||||||
|
import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_WEAK
|
||||||
|
import org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH
|
||||||
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager
|
||||||
|
import java.lang.System.exit
|
||||||
|
import javax.annotation.concurrent.Immutable
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
@Singleton
|
||||||
|
class BriarService @Inject
|
||||||
|
constructor(
|
||||||
|
private val accountManager: AccountManager,
|
||||||
|
private val lifecycleManager: LifecycleManager,
|
||||||
|
private val passwordStrengthEstimator: PasswordStrengthEstimator
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun start() {
|
||||||
|
if (!accountManager.accountExists()) {
|
||||||
|
createAccount()
|
||||||
|
} else {
|
||||||
|
val password = prompt("Password")
|
||||||
|
?: throw UsageError("Could not get password. Is STDIN connected?")
|
||||||
|
if (!accountManager.signIn(password)) {
|
||||||
|
echo("Error: Password invalid")
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val dbKey = accountManager.databaseKey ?: throw AssertionError()
|
||||||
|
lifecycleManager.startServices(dbKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stop() {
|
||||||
|
lifecycleManager.stopServices()
|
||||||
|
lifecycleManager.waitForShutdown()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createAccount() {
|
||||||
|
echo("No account found. Let's create one!\n\n")
|
||||||
|
val nickname = prompt("Nickname") { nickname ->
|
||||||
|
if (nickname.length > MAX_AUTHOR_NAME_LENGTH)
|
||||||
|
throw UsageError("Please choose a shorter nickname!")
|
||||||
|
nickname
|
||||||
|
}
|
||||||
|
val password = prompt("Password") { password ->
|
||||||
|
if (passwordStrengthEstimator.estimateStrength(password) < QUITE_WEAK)
|
||||||
|
throw UsageError("Please enter a stronger password!")
|
||||||
|
password
|
||||||
|
}
|
||||||
|
if (nickname == null || password == null)
|
||||||
|
throw UsageError("Could not get account information. Is STDIN connected?")
|
||||||
|
accountManager.createAccount(nickname, password)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,137 +0,0 @@
|
|||||||
package org.briarproject.briar.headless;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.ConfigurationManager;
|
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
|
||||||
import org.briarproject.bramble.api.crypto.PublicKey;
|
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
|
||||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
|
||||||
import org.briarproject.bramble.api.network.NetworkManager;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
import org.briarproject.bramble.api.plugin.BackoffFactory;
|
|
||||||
import org.briarproject.bramble.api.plugin.PluginConfig;
|
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
|
||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
|
||||||
import org.briarproject.bramble.api.reporting.DevConfig;
|
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
|
||||||
import org.briarproject.bramble.api.system.ResourceProvider;
|
|
||||||
import org.briarproject.bramble.network.JavaNetworkModule;
|
|
||||||
import org.briarproject.bramble.plugin.tor.CircumventionModule;
|
|
||||||
import org.briarproject.bramble.plugin.tor.CircumventionProvider;
|
|
||||||
import org.briarproject.bramble.plugin.tor.LinuxTorPluginFactory;
|
|
||||||
import org.briarproject.bramble.system.JavaSystemModule;
|
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
|
||||||
import org.briarproject.briar.headless.messaging.MessagingModule;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.security.GeneralSecurityException;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
|
||||||
import javax.net.SocketFactory;
|
|
||||||
|
|
||||||
import dagger.Module;
|
|
||||||
import dagger.Provides;
|
|
||||||
|
|
||||||
import static java.util.Collections.emptyList;
|
|
||||||
import static java.util.Collections.singletonList;
|
|
||||||
import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_ONION_ADDRESS;
|
|
||||||
import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_PUBLIC_KEY_HEX;
|
|
||||||
|
|
||||||
@Module(includes = {
|
|
||||||
JavaNetworkModule.class,
|
|
||||||
JavaSystemModule.class,
|
|
||||||
CircumventionModule.class,
|
|
||||||
MessagingModule.class
|
|
||||||
})
|
|
||||||
public class HeadlessModule {
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
DatabaseConfig provideDatabaseConfig(
|
|
||||||
ConfigurationManager configurationManager) {
|
|
||||||
File dbDir = appDir(configurationManager, "db");
|
|
||||||
File keyDir = appDir(configurationManager, "key");
|
|
||||||
return new HeadlessDatabaseConfig(dbDir, keyDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
PluginConfig providePluginConfig(@IoExecutor Executor ioExecutor,
|
|
||||||
SocketFactory torSocketFactory, BackoffFactory backoffFactory,
|
|
||||||
NetworkManager networkManager, LocationUtils locationUtils,
|
|
||||||
EventBus eventBus, ResourceProvider resourceProvider,
|
|
||||||
CircumventionProvider circumventionProvider, Clock clock,
|
|
||||||
ConfigurationManager configurationManager) {
|
|
||||||
File torDirectory = appDir(configurationManager, "tor");
|
|
||||||
DuplexPluginFactory tor = new LinuxTorPluginFactory(ioExecutor,
|
|
||||||
networkManager, locationUtils, eventBus, torSocketFactory,
|
|
||||||
backoffFactory, resourceProvider, circumventionProvider, clock,
|
|
||||||
torDirectory);
|
|
||||||
Collection<DuplexPluginFactory> duplex = singletonList(tor);
|
|
||||||
@NotNullByDefault
|
|
||||||
PluginConfig pluginConfig = new PluginConfig() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<DuplexPluginFactory> getDuplexFactories() {
|
|
||||||
return duplex;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<SimplexPluginFactory> getSimplexFactories() {
|
|
||||||
return emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldPoll() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return pluginConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
DevConfig provideDevConfig(CryptoComponent crypto,
|
|
||||||
ConfigurationManager configurationManager) {
|
|
||||||
@NotNullByDefault
|
|
||||||
DevConfig devConfig = new DevConfig() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PublicKey getDevPublicKey() {
|
|
||||||
try {
|
|
||||||
return crypto.getMessageKeyParser().parsePublicKey(
|
|
||||||
StringUtils.fromHexString(DEV_PUBLIC_KEY_HEX));
|
|
||||||
} catch (GeneralSecurityException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDevOnionAddress() {
|
|
||||||
return DEV_ONION_ADDRESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public File getReportDir() {
|
|
||||||
return appDir(configurationManager, "reportDir");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return devConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
WebSocketController provideWebSocketHandler(
|
|
||||||
WebSocketControllerImpl webSocketController) {
|
|
||||||
return webSocketController;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private File appDir(ConfigurationManager configurationManager,
|
|
||||||
String file) {
|
|
||||||
return new File(configurationManager.getAppDir(), file);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
package org.briarproject.briar.headless
|
||||||
|
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.Provides
|
||||||
|
import org.briarproject.bramble.api.crypto.CryptoComponent
|
||||||
|
import org.briarproject.bramble.api.crypto.PublicKey
|
||||||
|
import org.briarproject.bramble.api.db.DatabaseConfig
|
||||||
|
import org.briarproject.bramble.api.event.EventBus
|
||||||
|
import org.briarproject.bramble.api.lifecycle.IoExecutor
|
||||||
|
import org.briarproject.bramble.api.network.NetworkManager
|
||||||
|
import org.briarproject.bramble.api.plugin.BackoffFactory
|
||||||
|
import org.briarproject.bramble.api.plugin.PluginConfig
|
||||||
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory
|
||||||
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory
|
||||||
|
import org.briarproject.bramble.api.reporting.DevConfig
|
||||||
|
import org.briarproject.bramble.api.reporting.ReportingConstants.DEV_ONION_ADDRESS
|
||||||
|
import org.briarproject.bramble.api.reporting.ReportingConstants.DEV_PUBLIC_KEY_HEX
|
||||||
|
import org.briarproject.bramble.api.system.Clock
|
||||||
|
import org.briarproject.bramble.api.system.LocationUtils
|
||||||
|
import org.briarproject.bramble.api.system.ResourceProvider
|
||||||
|
import org.briarproject.bramble.network.JavaNetworkModule
|
||||||
|
import org.briarproject.bramble.plugin.tor.CircumventionModule
|
||||||
|
import org.briarproject.bramble.plugin.tor.CircumventionProvider
|
||||||
|
import org.briarproject.bramble.plugin.tor.LinuxTorPluginFactory
|
||||||
|
import org.briarproject.bramble.system.JavaSystemModule
|
||||||
|
import org.briarproject.bramble.util.StringUtils.fromHexString
|
||||||
|
import org.briarproject.briar.headless.messaging.MessagingModule
|
||||||
|
import java.io.File
|
||||||
|
import java.security.GeneralSecurityException
|
||||||
|
import java.util.Collections.emptyList
|
||||||
|
import java.util.concurrent.Executor
|
||||||
|
import javax.inject.Singleton
|
||||||
|
import javax.net.SocketFactory
|
||||||
|
|
||||||
|
@Module(
|
||||||
|
includes = [
|
||||||
|
JavaNetworkModule::class,
|
||||||
|
JavaSystemModule::class,
|
||||||
|
CircumventionModule::class,
|
||||||
|
MessagingModule::class
|
||||||
|
]
|
||||||
|
)
|
||||||
|
class HeadlessModule(private val appDir: File) {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
internal fun provideDatabaseConfig(): DatabaseConfig {
|
||||||
|
val dbDir = File(appDir, "db")
|
||||||
|
val keyDir = File(appDir, "key")
|
||||||
|
return HeadlessDatabaseConfig(dbDir, keyDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
internal fun providePluginConfig(
|
||||||
|
@IoExecutor ioExecutor: Executor, torSocketFactory: SocketFactory,
|
||||||
|
backoffFactory: BackoffFactory, networkManager: NetworkManager,
|
||||||
|
locationUtils: LocationUtils, eventBus: EventBus,
|
||||||
|
resourceProvider: ResourceProvider,
|
||||||
|
circumventionProvider: CircumventionProvider, clock: Clock
|
||||||
|
): PluginConfig {
|
||||||
|
val torDirectory = File(appDir, "tor")
|
||||||
|
val tor = LinuxTorPluginFactory(
|
||||||
|
ioExecutor,
|
||||||
|
networkManager, locationUtils, eventBus, torSocketFactory,
|
||||||
|
backoffFactory, resourceProvider, circumventionProvider, clock,
|
||||||
|
torDirectory
|
||||||
|
)
|
||||||
|
val duplex = listOf<DuplexPluginFactory>(tor)
|
||||||
|
return object : PluginConfig {
|
||||||
|
override fun getDuplexFactories(): Collection<DuplexPluginFactory> {
|
||||||
|
return duplex
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSimplexFactories(): Collection<SimplexPluginFactory> {
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun shouldPoll(): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
internal fun provideDevConfig(crypto: CryptoComponent): DevConfig {
|
||||||
|
return object : DevConfig {
|
||||||
|
override fun getDevPublicKey(): PublicKey {
|
||||||
|
try {
|
||||||
|
return crypto.messageKeyParser
|
||||||
|
.parsePublicKey(fromHexString(DEV_PUBLIC_KEY_HEX))
|
||||||
|
} catch (e: GeneralSecurityException) {
|
||||||
|
throw RuntimeException(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getDevOnionAddress(): String {
|
||||||
|
return DEV_ONION_ADDRESS
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getReportDir(): File {
|
||||||
|
return File(appDir, "reportDir")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
internal fun provideWebSocketHandler(
|
||||||
|
webSocketController: WebSocketControllerImpl): WebSocketController {
|
||||||
|
return webSocketController
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package org.briarproject.briar.headless;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.BrambleCoreModule;
|
|
||||||
import org.briarproject.briar.BriarCoreModule;
|
|
||||||
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.LogManager;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
public class Main {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
Logger rootLogger = LogManager.getLogManager().getLogger("");
|
|
||||||
rootLogger.setLevel(Level.WARNING);
|
|
||||||
|
|
||||||
for (String arg : args) {
|
|
||||||
if (arg.equals("-v")) {
|
|
||||||
rootLogger.setLevel(Level.INFO);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BriarHeadlessApp app = DaggerBriarHeadlessApp.builder()
|
|
||||||
.headlessModule(new HeadlessModule()).build();
|
|
||||||
// We need to load the eager singletons directly after making the
|
|
||||||
// dependency graphs
|
|
||||||
BrambleCoreModule.initEagerSingletons(app);
|
|
||||||
BriarCoreModule.initEagerSingletons(app);
|
|
||||||
|
|
||||||
app.router().start();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
package org.briarproject.briar.headless
|
||||||
|
|
||||||
|
import com.github.ajalt.clikt.core.CliktCommand
|
||||||
|
import com.github.ajalt.clikt.parameters.options.counted
|
||||||
|
import com.github.ajalt.clikt.parameters.options.default
|
||||||
|
import com.github.ajalt.clikt.parameters.options.flag
|
||||||
|
import com.github.ajalt.clikt.parameters.options.option
|
||||||
|
import com.github.ajalt.clikt.parameters.types.int
|
||||||
|
import org.briarproject.bramble.BrambleCoreModule
|
||||||
|
import org.briarproject.briar.BriarCoreModule
|
||||||
|
import org.slf4j.impl.SimpleLogger.DEFAULT_LOG_LEVEL_KEY
|
||||||
|
import java.io.File
|
||||||
|
import java.io.File.separator
|
||||||
|
import java.io.IOException
|
||||||
|
import java.lang.System.getProperty
|
||||||
|
import java.lang.System.setProperty
|
||||||
|
import java.nio.file.Files.setPosixFilePermissions
|
||||||
|
import java.nio.file.attribute.PosixFilePermission
|
||||||
|
import java.nio.file.attribute.PosixFilePermission.*
|
||||||
|
import java.util.logging.Level.*
|
||||||
|
import java.util.logging.LogManager
|
||||||
|
|
||||||
|
private const val DEFAULT_PORT = 7000
|
||||||
|
private val DEFAULT_DATA_DIR = getProperty("user.home") + separator + ".briar"
|
||||||
|
|
||||||
|
class Main : CliktCommand(
|
||||||
|
name = "briar-headless",
|
||||||
|
help = "A Briar client without GUI that exposes a REST and Websocket API"
|
||||||
|
) {
|
||||||
|
private val debug by option("--debug", "-d", help = "Enable printing of debug messages").flag(
|
||||||
|
default = false
|
||||||
|
)
|
||||||
|
private val verbosity by option(
|
||||||
|
"--verbose",
|
||||||
|
"-v",
|
||||||
|
help = "Print verbose log messages"
|
||||||
|
).counted()
|
||||||
|
private val port by option(
|
||||||
|
"--port",
|
||||||
|
help = "Bind the server to this port. Default: $DEFAULT_PORT",
|
||||||
|
metavar = "PORT",
|
||||||
|
envvar = "BRIAR_PORT"
|
||||||
|
).int().default(DEFAULT_PORT)
|
||||||
|
private val dataDir by option(
|
||||||
|
"--data-dir",
|
||||||
|
help = "The directory where Briar will store its files. Default: $DEFAULT_DATA_DIR",
|
||||||
|
metavar = "PATH",
|
||||||
|
envvar = "BRIAR_DATA_DIR"
|
||||||
|
).default(DEFAULT_DATA_DIR)
|
||||||
|
|
||||||
|
override fun run() {
|
||||||
|
// logging
|
||||||
|
val levelSlf4j = if (debug) "DEBUG" else when (verbosity) {
|
||||||
|
0 -> "WARN"
|
||||||
|
1 -> "INFO"
|
||||||
|
else -> "DEBUG"
|
||||||
|
}
|
||||||
|
val level = if (debug) ALL else when (verbosity) {
|
||||||
|
0 -> WARNING
|
||||||
|
1 -> INFO
|
||||||
|
else -> ALL
|
||||||
|
}
|
||||||
|
setProperty(DEFAULT_LOG_LEVEL_KEY, levelSlf4j);
|
||||||
|
LogManager.getLogManager().getLogger("").level = level
|
||||||
|
|
||||||
|
val app =
|
||||||
|
DaggerBriarHeadlessApp.builder().headlessModule(HeadlessModule(getDataDir())).build()
|
||||||
|
// We need to load the eager singletons directly after making the
|
||||||
|
// dependency graphs
|
||||||
|
BrambleCoreModule.initEagerSingletons(app)
|
||||||
|
BriarCoreModule.initEagerSingletons(app)
|
||||||
|
|
||||||
|
app.router().start(port, debug)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getDataDir(): File {
|
||||||
|
val file = File(dataDir)
|
||||||
|
if (!file.exists() && !file.mkdirs()) {
|
||||||
|
throw IOException("Could not create directory: ${file.absolutePath}")
|
||||||
|
} else if (!file.isDirectory) {
|
||||||
|
throw IOException("Data dir is not a directory: ${file.absolutePath}")
|
||||||
|
}
|
||||||
|
val perms = HashSet<PosixFilePermission>();
|
||||||
|
perms.add(OWNER_READ);
|
||||||
|
perms.add(OWNER_WRITE);
|
||||||
|
perms.add(OWNER_EXECUTE);
|
||||||
|
setPosixFilePermissions(file.toPath(), perms);
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main(args: Array<String>) = Main().main(args)
|
||||||
@@ -25,19 +25,19 @@ constructor(
|
|||||||
private val blogController: BlogController
|
private val blogController: BlogController
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun start() {
|
fun start(port: Int, debug: Boolean) {
|
||||||
briarService.start()
|
briarService.start()
|
||||||
getRuntime().addShutdownHook(Thread(Runnable { briarService.stop() }))
|
getRuntime().addShutdownHook(Thread(Runnable { briarService.stop() }))
|
||||||
|
|
||||||
val app = Javalin.create()
|
val app = Javalin.create()
|
||||||
.port(7000)
|
.port(port)
|
||||||
.disableStartupBanner()
|
.disableStartupBanner()
|
||||||
.enableDebugLogging()
|
|
||||||
.enableCaseSensitiveUrls()
|
.enableCaseSensitiveUrls()
|
||||||
.enableRouteOverview("/")
|
.enableRouteOverview("/")
|
||||||
.event(SERVER_START_FAILED) { stop() }
|
.event(SERVER_START_FAILED) { stop() }
|
||||||
.event(SERVER_STOPPED) { stop() }
|
.event(SERVER_STOPPED) { stop() }
|
||||||
.start()
|
if (debug) app.enableDebugLogging()
|
||||||
|
app.start()
|
||||||
|
|
||||||
app.routes {
|
app.routes {
|
||||||
path("/v1") {
|
path("/v1") {
|
||||||
@@ -68,7 +68,7 @@ constructor(
|
|||||||
|
|
||||||
private fun stop() {
|
private fun stop() {
|
||||||
briarService.stop()
|
briarService.stop()
|
||||||
exitProcess(1)
|
exitProcess(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ dependencyVerification {
|
|||||||
'com.fasterxml.jackson.core:jackson-annotations:2.9.0:jackson-annotations-2.9.0.jar:45d32ac61ef8a744b464c54c2b3414be571016dd46bfc2bec226761cf7ae457a',
|
'com.fasterxml.jackson.core:jackson-annotations:2.9.0:jackson-annotations-2.9.0.jar:45d32ac61ef8a744b464c54c2b3414be571016dd46bfc2bec226761cf7ae457a',
|
||||||
'com.fasterxml.jackson.core:jackson-core:2.9.6:jackson-core-2.9.6.jar:fab8746aedd6427788ee390ea04d438ec141bff7eb3476f8bdd5d9110fb2718a',
|
'com.fasterxml.jackson.core:jackson-core:2.9.6:jackson-core-2.9.6.jar:fab8746aedd6427788ee390ea04d438ec141bff7eb3476f8bdd5d9110fb2718a',
|
||||||
'com.fasterxml.jackson.core:jackson-databind:2.9.6:jackson-databind-2.9.6.jar:657e3e979446d61f88432b9c50f0ccd9c1fe4f1c822d533f5572e4c0d172a125',
|
'com.fasterxml.jackson.core:jackson-databind:2.9.6:jackson-databind-2.9.6.jar:657e3e979446d61f88432b9c50f0ccd9c1fe4f1c822d533f5572e4c0d172a125',
|
||||||
|
'com.github.ajalt:clikt:1.5.0:clikt-1.5.0.jar:f13ab614cb0372229f6bb1e19aa98ee6f4ac96f253d0e72d482ee4f5fd2a13a9',
|
||||||
'com.google.dagger:dagger-compiler:2.0.2:dagger-compiler-2.0.2.jar:b74bc9de063dd4c6400b232231f2ef5056145b8fbecbf5382012007dd1c071b3',
|
'com.google.dagger:dagger-compiler:2.0.2:dagger-compiler-2.0.2.jar:b74bc9de063dd4c6400b232231f2ef5056145b8fbecbf5382012007dd1c071b3',
|
||||||
'com.google.dagger:dagger-producers:2.0-beta:dagger-producers-2.0-beta.jar:99ec15e8a0507ba569e7655bc1165ee5e5ca5aa914b3c8f7e2c2458f724edd6b',
|
'com.google.dagger:dagger-producers:2.0-beta:dagger-producers-2.0-beta.jar:99ec15e8a0507ba569e7655bc1165ee5e5ca5aa914b3c8f7e2c2458f724edd6b',
|
||||||
'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
|
'com.google.dagger:dagger:2.0.2:dagger-2.0.2.jar:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
|
||||||
@@ -34,6 +35,7 @@ dependencyVerification {
|
|||||||
'org.eclipse.jetty:jetty-util:9.4.11.v20180605:jetty-util-9.4.11.v20180605.jar:936e5ed74275c16164cc1eccaeae55900eb00edd9f1b1d3b83d70782dd25f505',
|
'org.eclipse.jetty:jetty-util:9.4.11.v20180605:jetty-util-9.4.11.v20180605.jar:936e5ed74275c16164cc1eccaeae55900eb00edd9f1b1d3b83d70782dd25f505',
|
||||||
'org.eclipse.jetty:jetty-webapp:9.4.11.v20180605:jetty-webapp-9.4.11.v20180605.jar:858f3f16cecb0891f07a4e8d82554201c513bf058c0f65969b366936155b6a36',
|
'org.eclipse.jetty:jetty-webapp:9.4.11.v20180605:jetty-webapp-9.4.11.v20180605.jar:858f3f16cecb0891f07a4e8d82554201c513bf058c0f65969b366936155b6a36',
|
||||||
'org.eclipse.jetty:jetty-xml:9.4.11.v20180605:jetty-xml-9.4.11.v20180605.jar:1780bdaee2b1908e032fbc286bb856d730c4d0c9de39d5e14a1b9c48028c295e',
|
'org.eclipse.jetty:jetty-xml:9.4.11.v20180605:jetty-xml-9.4.11.v20180605.jar:1780bdaee2b1908e032fbc286bb856d730c4d0c9de39d5e14a1b9c48028c295e',
|
||||||
|
'org.jetbrains.kotlin:kotlin-annotation-processing-gradle:1.2.61:kotlin-annotation-processing-gradle-1.2.61.jar:52ce75c26c94c54490e217b1ed4a6b2d689a7d5b0482c1032624e45ed5e259a7',
|
||||||
'org.jetbrains.kotlin:kotlin-compiler-embeddable:1.2.61:kotlin-compiler-embeddable-1.2.61.jar:f8165810c61f440a2de6003ed9857d28a1dfc990bacbecee1436610c8ebe565b',
|
'org.jetbrains.kotlin:kotlin-compiler-embeddable:1.2.61:kotlin-compiler-embeddable-1.2.61.jar:f8165810c61f440a2de6003ed9857d28a1dfc990bacbecee1436610c8ebe565b',
|
||||||
'org.jetbrains.kotlin:kotlin-reflect:1.2.41:kotlin-reflect-1.2.41.jar:1bab75771dfa2bb5949cd383ceaedf6f8d354fa0d677804fc5a39e320bab70d3',
|
'org.jetbrains.kotlin:kotlin-reflect:1.2.41:kotlin-reflect-1.2.41.jar:1bab75771dfa2bb5949cd383ceaedf6f8d354fa0d677804fc5a39e320bab70d3',
|
||||||
'org.jetbrains.kotlin:kotlin-reflect:1.2.61:kotlin-reflect-1.2.61.jar:a4f1ed542390f9bf967fb9aff2c232b90988f7ce138a4b7bcc70b754821a8943',
|
'org.jetbrains.kotlin:kotlin-reflect:1.2.61:kotlin-reflect-1.2.61.jar:a4f1ed542390f9bf967fb9aff2c232b90988f7ce138a4b7bcc70b754821a8943',
|
||||||
|
|||||||
Reference in New Issue
Block a user