mirror of
https://github.com/bisq-network/bisq.git
synced 2025-03-26 20:30:55 +01:00
Merge relay repository at 5c730b0
This commit is contained in:
parent
9a7b761549
commit
a55673fe52
8 changed files with 337 additions and 0 deletions
1
relay/Procfile
Normal file
1
relay/Procfile
Normal file
|
@ -0,0 +1 @@
|
|||
web: if [ "$HIDDEN" == true ]; then ./tor/bin/run_tor java -jar -Dserver.port=$PORT build/libs/bisq-relay.jar; else java -jar -Dserver.port=$PORT build/libs/bisq-relay.jar; fi
|
36
relay/build.gradle
Normal file
36
relay/build.gradle
Normal file
|
@ -0,0 +1,36 @@
|
|||
plugins {
|
||||
id "java"
|
||||
id "org.springframework.boot" version "1.5.10.RELEASE"
|
||||
}
|
||||
|
||||
sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
|
||||
version = file("src/main/resources/version.txt").text
|
||||
|
||||
jar.manifest.attributes(
|
||||
"Implementation-Title": rootProject.name,
|
||||
"Implementation-Version": version)
|
||||
|
||||
jar.archiveName "${rootProject.name}.jar"
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
jcenter()
|
||||
maven { url "https://jitpack.io" }
|
||||
maven { url "https://raw.githubusercontent.com/JesusMcCloud/tor-binary/master/release/" }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(":common")
|
||||
compile("com.sparkjava:spark-core:2.5.2")
|
||||
compile("com.turo:pushy:0.13.2")
|
||||
compile("com.google.firebase:firebase-admin:6.2.0")
|
||||
|
||||
compileOnly 'org.projectlombok:lombok:1.16.16'
|
||||
//annotationProcessor 'org.projectlombok:lombok:1.16.16'
|
||||
}
|
||||
|
||||
task stage {
|
||||
dependsOn assemble
|
||||
}
|
127
relay/src/main/java/bisq/relay/RelayMain.java
Normal file
127
relay/src/main/java/bisq/relay/RelayMain.java
Normal file
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* This file is part of Bisq.
|
||||
*
|
||||
* Bisq is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bisq is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package bisq.relay;
|
||||
|
||||
import bisq.common.app.Log;
|
||||
import bisq.common.util.Utilities;
|
||||
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
|
||||
import static spark.Spark.get;
|
||||
import static spark.Spark.port;
|
||||
|
||||
public class RelayMain {
|
||||
private static final Logger log = LoggerFactory.getLogger(RelayMain.class);
|
||||
private static final String VERSION = "0.1.0";
|
||||
private static RelayService relayService;
|
||||
|
||||
static {
|
||||
// Need to set default locale initially otherwise we get problems at non-english OS
|
||||
Locale.setDefault(new Locale("en", Locale.getDefault().getCountry()));
|
||||
|
||||
Utilities.removeCryptographyRestrictions();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param args Pass port as program argument if other port than default port 8080 is wanted.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
final String logPath = System.getProperty("user.home") + File.separator + "provider";
|
||||
Log.setup(logPath);
|
||||
Log.setLevel(Level.INFO);
|
||||
log.info("Log files under: " + logPath);
|
||||
log.info("RelayVersion.VERSION: " + VERSION);
|
||||
Utilities.printSysInfo();
|
||||
|
||||
|
||||
String appleCertPwPath;
|
||||
if (args.length > 0)
|
||||
appleCertPwPath = args[0];
|
||||
else
|
||||
throw new RuntimeException("You need to set the path to the password text file for the Apple push certificate as first argument.");
|
||||
|
||||
String appleCertPath;
|
||||
if (args.length > 1)
|
||||
appleCertPath = args[1];
|
||||
else
|
||||
throw new RuntimeException("You need to set the path to the Apple push certificate as second argument.");
|
||||
|
||||
String appleBundleId;
|
||||
if (args.length > 2)
|
||||
appleBundleId = args[2];
|
||||
else
|
||||
throw new RuntimeException("You need to set the Apple bundle ID as third argument.");
|
||||
|
||||
String androidCertPath;
|
||||
if (args.length > 3)
|
||||
androidCertPath = args[3];
|
||||
else
|
||||
throw new RuntimeException("You need to set the Android certificate path as 4th argument.");
|
||||
|
||||
|
||||
int port = 8080;
|
||||
if (args.length > 4)
|
||||
port = Integer.parseInt(args[4]);
|
||||
|
||||
port(port);
|
||||
|
||||
relayService = new RelayService(appleCertPwPath, appleCertPath, appleBundleId, androidCertPath);
|
||||
|
||||
handleRelay();
|
||||
|
||||
keepRunning();
|
||||
}
|
||||
|
||||
private static void handleRelay() {
|
||||
get("/relay", (request, response) -> {
|
||||
log.info("Incoming relay request from: " + request.userAgent());
|
||||
boolean isAndroid = request.queryParams("isAndroid").equalsIgnoreCase("true");
|
||||
boolean useSound = request.queryParams("snd").equalsIgnoreCase("true");
|
||||
String token = new String(Hex.decodeHex(request.queryParams("token").toCharArray()), "UTF-8");
|
||||
String encryptedMessage = new String(Hex.decodeHex(request.queryParams("msg").toCharArray()), "UTF-8");
|
||||
log.info("isAndroid={}\nuseSound={}\napsTokenHex={}\nencryptedMessage={}", isAndroid, useSound, token,
|
||||
encryptedMessage);
|
||||
if (isAndroid) {
|
||||
return relayService.sendAndroidMessage(token, encryptedMessage, useSound);
|
||||
} else {
|
||||
boolean isProduction = request.queryParams("isProduction").equalsIgnoreCase("true");
|
||||
boolean isContentAvailable = request.queryParams("isContentAvailable").equalsIgnoreCase("true");
|
||||
return relayService.sendAppleMessage(isProduction, isContentAvailable, token, encryptedMessage, useSound);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void keepRunning() {
|
||||
//noinspection InfiniteLoopStatement
|
||||
while (true) {
|
||||
try {
|
||||
Thread.sleep(Long.MAX_VALUE);
|
||||
} catch (InterruptedException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
154
relay/src/main/java/bisq/relay/RelayService.java
Normal file
154
relay/src/main/java/bisq/relay/RelayService.java
Normal file
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* This file is part of Bisq.
|
||||
*
|
||||
* Bisq is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bisq is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package bisq.relay;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import java.util.Scanner;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
|
||||
|
||||
import com.google.auth.oauth2.GoogleCredentials;
|
||||
import com.google.firebase.FirebaseApp;
|
||||
import com.google.firebase.FirebaseOptions;
|
||||
import com.google.firebase.messaging.FirebaseMessaging;
|
||||
import com.google.firebase.messaging.FirebaseMessagingException;
|
||||
import com.google.firebase.messaging.Message;
|
||||
import com.google.firebase.messaging.Notification;
|
||||
import com.turo.pushy.apns.ApnsClient;
|
||||
import com.turo.pushy.apns.ApnsClientBuilder;
|
||||
import com.turo.pushy.apns.PushNotificationResponse;
|
||||
import com.turo.pushy.apns.util.ApnsPayloadBuilder;
|
||||
import com.turo.pushy.apns.util.SimpleApnsPushNotification;
|
||||
import com.turo.pushy.apns.util.concurrent.PushNotificationFuture;
|
||||
|
||||
@Slf4j
|
||||
class RelayService {
|
||||
private static final String ANDROID_DATABASE_URL = "https://bisqnotifications.firebaseio.com";
|
||||
// Used in Bisq app to check for success state. We won't want a code dependency just for that string so we keep it
|
||||
// duplicated in core and here. Must not be changed.
|
||||
private static final String SUCCESS = "success";
|
||||
|
||||
private final String appleBundleId;
|
||||
|
||||
private ApnsClient productionApnsClient;
|
||||
private ApnsClient devApnsClient; // used for iOS development in XCode
|
||||
|
||||
RelayService(String appleCertPwPath, String appleCertPath, String appleBundleId, String androidCertPath) {
|
||||
this.appleBundleId = appleBundleId;
|
||||
|
||||
setupForAndroid(androidCertPath);
|
||||
setupForApple(appleCertPwPath, appleCertPath);
|
||||
}
|
||||
|
||||
private void setupForAndroid(String androidCertPath) {
|
||||
try {
|
||||
InputStream androidCertStream = new FileInputStream(androidCertPath);
|
||||
FirebaseOptions options = new FirebaseOptions.Builder()
|
||||
.setCredentials(GoogleCredentials.fromStream(androidCertStream))
|
||||
.setDatabaseUrl(ANDROID_DATABASE_URL)
|
||||
.build();
|
||||
FirebaseApp.initializeApp(options);
|
||||
} catch (IOException e) {
|
||||
log.error(e.toString());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void setupForApple(String appleCertPwPath, String appleCertPath) {
|
||||
try {
|
||||
InputStream certInputStream = new FileInputStream(appleCertPwPath);
|
||||
Scanner scanner = new Scanner(certInputStream);
|
||||
String password = scanner.next();
|
||||
productionApnsClient = new ApnsClientBuilder()
|
||||
.setApnsServer(ApnsClientBuilder.PRODUCTION_APNS_HOST)
|
||||
.setClientCredentials(new File(appleCertPath), password)
|
||||
.build();
|
||||
devApnsClient = new ApnsClientBuilder()
|
||||
.setApnsServer(ApnsClientBuilder.DEVELOPMENT_APNS_HOST)
|
||||
.setClientCredentials(new File(appleCertPath), password)
|
||||
.build();
|
||||
} catch (IOException e) {
|
||||
log.error(e.toString());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
String sendAppleMessage(boolean isProduction, boolean isContentAvailable, String apsTokenHex, String encryptedMessage, boolean useSound) {
|
||||
ApnsPayloadBuilder payloadBuilder = new ApnsPayloadBuilder();
|
||||
if (useSound)
|
||||
payloadBuilder.setSoundFileName("default");
|
||||
payloadBuilder.setAlertBody("Bisq notification");
|
||||
payloadBuilder.setContentAvailable(isContentAvailable);
|
||||
payloadBuilder.addCustomProperty("encrypted", encryptedMessage);
|
||||
final String payload = payloadBuilder.buildWithDefaultMaximumLength();
|
||||
log.info("payload " + payload);
|
||||
SimpleApnsPushNotification simpleApnsPushNotification = new SimpleApnsPushNotification(apsTokenHex, appleBundleId, payload);
|
||||
|
||||
ApnsClient apnsClient = isProduction ? productionApnsClient : devApnsClient;
|
||||
PushNotificationFuture<SimpleApnsPushNotification, PushNotificationResponse<SimpleApnsPushNotification>>
|
||||
notificationFuture = apnsClient.sendNotification(simpleApnsPushNotification);
|
||||
try {
|
||||
PushNotificationResponse<SimpleApnsPushNotification> pushNotificationResponse = notificationFuture.get();
|
||||
if (pushNotificationResponse.isAccepted()) {
|
||||
log.info("Push notification accepted by APNs gateway.");
|
||||
return SUCCESS;
|
||||
} else {
|
||||
String msg1 = "Notification rejected by the APNs gateway: " +
|
||||
pushNotificationResponse.getRejectionReason();
|
||||
String msg2 = "";
|
||||
if (pushNotificationResponse.getTokenInvalidationTimestamp() != null)
|
||||
msg2 = " and the token is invalid as of " +
|
||||
pushNotificationResponse.getTokenInvalidationTimestamp();
|
||||
|
||||
log.info(msg1 + msg2);
|
||||
return "Error: " + msg1 + msg2;
|
||||
}
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
log.error(e.toString());
|
||||
e.printStackTrace();
|
||||
return "Error: " + e.toString();
|
||||
}
|
||||
}
|
||||
|
||||
String sendAndroidMessage(String apsTokenHex, String encryptedMessage, boolean useSound) {
|
||||
Message.Builder messageBuilder = Message.builder();
|
||||
Notification notification = new Notification("Bisq", "Notification");
|
||||
messageBuilder.setNotification(notification);
|
||||
messageBuilder.putData("encrypted", encryptedMessage);
|
||||
messageBuilder.setToken(apsTokenHex);
|
||||
if (useSound)
|
||||
messageBuilder.putData("sound", "default");
|
||||
Message message = messageBuilder.build();
|
||||
try {
|
||||
FirebaseMessaging firebaseMessaging = FirebaseMessaging.getInstance();
|
||||
firebaseMessaging.send(message);
|
||||
return SUCCESS;
|
||||
} catch (FirebaseMessagingException e) {
|
||||
log.error(e.toString());
|
||||
e.printStackTrace();
|
||||
return "Error: " + e.toString();
|
||||
}
|
||||
}
|
||||
}
|
15
relay/src/main/resources/logback.xml
Normal file
15
relay/src/main/resources/logback.xml
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appender name="CONSOLE_APPENDER" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%highlight(%d{MMM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{15}: %msg %xEx%n)</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="WARN">
|
||||
<appender-ref ref="CONSOLE_APPENDER"/>
|
||||
</root>
|
||||
|
||||
<logger name="bisq" level="INFO"/>
|
||||
|
||||
</configuration>
|
1
relay/src/main/resources/version.txt
Normal file
1
relay/src/main/resources/version.txt
Normal file
|
@ -0,0 +1 @@
|
|||
0.8.0
|
2
relay/torrc
Normal file
2
relay/torrc
Normal file
|
@ -0,0 +1,2 @@
|
|||
HiddenServiceDir build/tor-hidden-service
|
||||
HiddenServicePort 80 127.0.0.1:8080
|
|
@ -5,5 +5,6 @@ include 'core'
|
|||
include 'desktop'
|
||||
include 'monitor'
|
||||
include 'pricenode'
|
||||
include 'relay'
|
||||
|
||||
rootProject.name = 'bisq'
|
||||
|
|
Loading…
Add table
Reference in a new issue