summaryrefslogtreecommitdiff
path: root/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku
diff options
context:
space:
mode:
Diffstat (limited to 'pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku')
-rw-r--r--pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/MobileBKUConnector.java138
-rw-r--r--pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDMobileBKUConnector.java11
-rw-r--r--pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/ATrustHandler.java6
-rw-r--r--pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/ATrustParser.java48
4 files changed, 120 insertions, 83 deletions
diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/MobileBKUConnector.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/MobileBKUConnector.java
index dc2258a1..1748f631 100644
--- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/MobileBKUConnector.java
+++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/MobileBKUConnector.java
@@ -13,18 +13,14 @@ import java.util.regex.Pattern;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.swing.text.html.HTML.Tag;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.classic.methods.HttpPost;
-import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.entity.UrlEncodedFormEntity;
import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
-import org.apache.hc.client5.http.impl.classic.RequestFailedException;
import org.apache.hc.core5.http.ClassicHttpRequest;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.Header;
@@ -228,6 +224,67 @@ public class MobileBKUConnector implements BkuSlConnector {
return post;
}
+ private static class LongPollThread extends Thread implements AutoCloseable {
+
+ private final CloseableHttpClient httpClient = HttpClients.createDefault();
+ private final HttpGet request;
+ private final Runnable signal;
+ private boolean done = false;
+
+ @Override
+ public void run() {
+ long timeout = System.nanoTime() + (300l * 1000l * 1000l * 1000l); /* a-trust timeout is 5 minutes */
+ log.debug("longPollThread hello");
+ while (!done) {
+ try (final CloseableHttpResponse response = httpClient.execute(request)) {
+ JSONObject jsonResponse = new JSONObject(EntityUtils.toString(response.getEntity()));
+ if (jsonResponse.getBoolean("Fin"))
+ signal.run();
+ else if (jsonResponse.getBoolean("Wait"))
+ {
+ log.debug("longPollThread continue...");
+ continue;
+ }
+ else if (jsonResponse.getBoolean("Error"))
+ signal.run(); /* will trigger reload and find error; this is the same thing a-trust does */
+ else {
+ log.warn("Unknown long poll response:\n{}", jsonResponse.toString(2));
+ break;
+ }
+ } catch (NoHttpResponseException e) {
+ if (timeout <= System.nanoTime())
+ signal.run(); /* reload to find the timeout error */
+ continue; /* httpclient timeout */
+ } catch (IOException | ParseException | IllegalStateException e) {
+ if (done) break;
+ log.warn("QR code long polling exception", e);
+ /* sleep so we don't hammer a-trust too hard in case this goes wrong */
+ try { Thread.sleep(5000); } catch (InterruptedException e2) {}
+ }
+ }
+ log.debug("longPollThread goodbye");
+ }
+
+ public LongPollThread(URI uri, Runnable signal) {
+ this.request = new HttpGet(uri);
+ this.signal = signal;
+ }
+
+ @Override
+ public void close() {
+ done = true;
+ if (this.request != null)
+ this.request.abort();
+
+ if (this.isAlive())
+ try { this.join(1000); } catch (InterruptedException e) {}
+
+ if (this.httpClient != null)
+ try { this.httpClient.close(); } catch (IOException e) { log.warn("Auto-close of long-poll HTTP client threw exception", e); }
+ }
+
+ }
+
/**
* Main lifting function for MobileBKU UX
* @return the next request to make, or null if the current response should be returned
@@ -270,58 +327,29 @@ public class MobileBKUConnector implements BkuSlConnector {
return new HttpGet(html.htmlDocument.baseUri());
}
if (html.qrCodeBlock != null) {
- try (final CloseableHttpClient httpClient = HttpClients.custom().disableRedirectHandling().build()) {
- final HttpGet request = new HttpGet(html.qrCodeBlock.pollingURI);
- boolean[] done = new boolean[1];
- done[0] = false;
- Thread longPollThread = new Thread(() -> {
- long timeout = System.nanoTime() + (300l * 1000l * 1000l * 1000l); /* a-trust timeout is 5 minutes */
- log.debug("longPollThread hello");
- while (!done[0]) {
- try (final CloseableHttpResponse response = httpClient.execute(request)) {
- JSONObject jsonResponse = new JSONObject(EntityUtils.toString(response.getEntity()));
- if (jsonResponse.getBoolean("Fin"))
- state.signalQRScanned();
- else if (jsonResponse.getBoolean("Wait"))
- {
- log.debug("longPollThread continue...");
- continue;
- }
- else if (jsonResponse.getBoolean("Error"))
- state.signalQRScanned(); /* will trigger reload and find error; this is the same thing a-trust does */
- else {
- log.warn("Unknown long poll response:\n{}", jsonResponse.toString(2));
- break;
- }
- } catch (NoHttpResponseException e) {
- if (timeout <= System.nanoTime())
- state.signalQRScanned(); /* reload to find the timeout error */
- continue; /* httpclient timeout */
- } catch (IOException | ParseException | IllegalStateException e) {
- if (done[0]) break;
- log.warn("QR code long polling exception", e);
- /* sleep so we don't hammer a-trust too hard in case this goes wrong */
- try { Thread.sleep(5000); } catch (InterruptedException e2) {}
- }
- }
- log.debug("longPollThread goodbye");
- });
- try {
- longPollThread.start();
- MobileBKUState.QRResult result = this.state.showQRCode(html.qrCodeBlock.referenceValue, html.qrCodeBlock.qrCodeURI, html.signatureDataLink, html.smsTanLink != null, html.fido2Link != null, html.qrCodeBlock.errorMessage);
- switch (result) {
- case UPDATE: break;
- case TO_FIDO2: if (html.fido2Link != null) return new HttpGet(html.fido2Link); break;
- case TO_SMS: if (html.smsTanLink != null) return new HttpGet(html.smsTanLink); break;
- }
- return new HttpGet(html.htmlDocument.baseUri());
- } finally {
- done[0] = true;
- request.abort();
- try { longPollThread.join(1000); } catch (InterruptedException e) {}
+ try (LongPollThread longPollThread = new LongPollThread(html.qrCodeBlock.pollingURI, () -> { this.state.signalQRScanned(); })) {
+ this.state.showQRCode(html.qrCodeBlock.referenceValue, html.qrCodeBlock.qrCodeURI, html.signatureDataLink, html.smsTanLink != null, html.fido2Link != null, html.qrCodeBlock.errorMessage);
+ longPollThread.start();
+ var result = this.state.waitForQRCodeResult();
+ switch (result) {
+ case UPDATE: break;
+ case TO_FIDO2: if (html.fido2Link != null) return new HttpGet(html.fido2Link); break;
+ case TO_SMS: if (html.smsTanLink != null) return new HttpGet(html.smsTanLink); break;
+ }
+ return new HttpGet(html.htmlDocument.baseUri());
+ }
+ }
+ if (html.waitingForAppBlock != null) {
+ try (LongPollThread longPollThread = new LongPollThread(html.waitingForAppBlock.pollingURI, () -> { this.state.signalAppOpened(); })) {
+ this.state.showWaitingForApp(html.waitingForAppBlock.referenceValue, html.signatureDataLink, html.smsTanLink != null, html.fido2Link != null);
+ longPollThread.start();
+ var result = this.state.waitForAppOpen();
+ switch (result) {
+ case UPDATE: break;
+ case TO_FIDO2: if (html.fido2Link != null) return new HttpGet(html.fido2Link); break;
+ case TO_SMS: if (html.smsTanLink != null) return new HttpGet(html.smsTanLink); break;
}
- } catch (IOException e) {
- log.warn("closing long-polling HttpClient threw exception", e);
+ return new HttpGet(html.htmlDocument.baseUri());
}
}
if (html.fido2Block != null) {
diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDMobileBKUConnector.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDMobileBKUConnector.java
index 8c054e95..c9ab164b 100644
--- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDMobileBKUConnector.java
+++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDMobileBKUConnector.java
@@ -15,9 +15,6 @@
*/
package at.asit.pdfover.gui.bku;
-import java.io.IOException;
-import java.net.URISyntaxException;
-
// Imports
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -90,7 +87,7 @@ public class OLDMobileBKUConnector implements BkuSlConnector {
if (responseData.contains("undecided.aspx?sid=")) {
// handle polling
- this.state.showOpenAppMessageWithSMSandCancel();
+ //this.state.showOpenAppMessageWithSMSandCancel();
if (this.state.status.isSMSTan) {
String response = handler.postSMSRequest();
@@ -124,11 +121,11 @@ public class OLDMobileBKUConnector implements BkuSlConnector {
boolean enterTAN = true;
String responseData = null;
if (status.qrCodeURL != null) {
- try {
+ /*try {
this.state.OLDshowQR();
} catch (IOException | URISyntaxException e) {
throw new SignatureException(e);
- }
+ }*/
if ("cancel".equals(this.state.status.errorMessage))
throw new SignatureException(new IllegalStateException());
if (status.qrCodeURL == null) {
@@ -178,7 +175,7 @@ public class OLDMobileBKUConnector implements BkuSlConnector {
if (enterTAN) {
try {
// Get TAN
- this.state.OLDcheckTAN();
+ //this.state.OLDcheckTAN();
if ("cancel".equals(this.state.status.errorMessage))
throw new SignatureException(new IllegalStateException());
diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/ATrustHandler.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/ATrustHandler.java
index ab85645b..e22db900 100644
--- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/ATrustHandler.java
+++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/OLDmobile/ATrustHandler.java
@@ -16,12 +16,10 @@
package at.asit.pdfover.gui.bku.OLDmobile;
// Imports
-import java.awt.Desktop;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.net.URI;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -38,12 +36,8 @@ import org.apache.commons.httpclient.methods.multipart.Part;
import org.apache.commons.httpclient.methods.multipart.StringPart;
import org.apache.commons.io.IOUtils;
import org.eclipse.swt.SWT;
-import org.eclipse.swt.program.Program;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
-import org.jsoup.Jsoup;
-import org.jsoup.nodes.Document;
-import org.jsoup.nodes.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/ATrustParser.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/ATrustParser.java
index 90afc834..1fb3b8d6 100644
--- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/ATrustParser.java
+++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/ATrustParser.java
@@ -56,6 +56,24 @@ public class ATrustParser {
throw new ComponentParseFailed();
}
}
+ protected @Nonnull URI getLongPollURI() throws ComponentParseFailed {
+ var pollingScriptElm = getElementEnsureNotNull("#jsLongPoll script");
+ String pollingScript = pollingScriptElm.data();
+ int startIdx = pollingScript.indexOf("qrpoll(\"");
+ if (startIdx < 0) { log.warn("Failed to find 'qrpoll(\"' in jsLongPoll script:\n{}", pollingScript); throw new ComponentParseFailed(); }
+ startIdx += 8;
+
+ int endIdx = pollingScript.indexOf("\");", startIdx);
+ if (endIdx < 0) { log.warn("Failed to find qrpoll terminator '\");' in jsLongPoll script:\n{}", pollingScript); throw new ComponentParseFailed(); }
+
+ String pollingUriString = pollingScript.substring(startIdx, endIdx);
+ try {
+ return ISNOTNULL(new URI(pollingScriptElm.baseUri()).resolve(pollingUriString));
+ } catch (URISyntaxException e) {
+ log.warn("Long-poll URI '{}' could not be parsed", pollingUriString);
+ throw new ComponentParseFailed();
+ }
+ }
}
public static class ErrorBlock extends TopLevelFormBlock {
@@ -126,25 +144,22 @@ public class ATrustParser {
this.referenceValue = ISNOTNULL(getElementEnsureNotNull("#vergleichswert").ownText());
this.qrCodeURI = getURIAttributeEnsureNotNull("#qrimage", "abs:src");
+ this.pollingURI = getLongPollURI();
- var pollingScriptElm = getElementEnsureNotNull("#jsLongPoll script");
- String pollingScript = pollingScriptElm.data();
- int startIdx = pollingScript.indexOf("qrpoll(\"");
- if (startIdx < 0) { log.warn("Failed to find 'qrpoll(\"' in jsLongPoll script:\n{}", pollingScript); throw new ComponentParseFailed(); }
- startIdx += 8;
+ this.errorMessage = null;
+ }
+ }
- int endIdx = pollingScript.indexOf("\");", startIdx);
- if (endIdx < 0) { log.warn("Failed to find qrpoll terminator '\");' in jsLongPoll script:\n{}", pollingScript); throw new ComponentParseFailed(); }
+ public static class WaitingForAppBlock extends TopLevelFormBlock {
+ public final @Nonnull String referenceValue;
+ public final @Nonnull URI pollingURI;
- String pollingUriString = pollingScript.substring(startIdx, endIdx);
- try {
- this.pollingURI = ISNOTNULL(new URI(pollingScriptElm.baseUri()).resolve(pollingUriString));
- } catch (URISyntaxException e) {
- log.warn("URI '{}' could not be parsed", pollingUriString);
- throw new ComponentParseFailed();
- }
+ private WaitingForAppBlock(@Nonnull org.jsoup.nodes.Document htmlDocument, @Nonnull Map<String, String> formOptions) throws ComponentParseFailed {
+ super(htmlDocument, formOptions);
+ abortIfElementMissing("#smartphoneAnimation");
- this.errorMessage = null;
+ this.referenceValue = ISNOTNULL(getElementEnsureNotNull("#vergleichswert").ownText());
+ this.pollingURI = getLongPollURI();
}
}
@@ -179,6 +194,7 @@ public class ATrustParser {
public final @CheckForNull UsernamePasswordBlock usernamePasswordBlock;
public final @CheckForNull SMSTanBlock smsTanBlock;
public final @CheckForNull QRCodeBlock qrCodeBlock;
+ public final @CheckForNull WaitingForAppBlock waitingForAppBlock;
public final @CheckForNull Fido2Block fido2Block;
private void validate() {
@@ -188,6 +204,7 @@ public class ATrustParser {
if (usernamePasswordBlock != null) populated.add("usernamePasswordBlock");
if (smsTanBlock != null) populated.add("smsTanBlock");
if (qrCodeBlock != null) populated.add("qrCodeBlock");
+ if (waitingForAppBlock != null) populated.add("waitingForAppBlock");
if (fido2Block != null) populated.add("fido2Block");
switch (populated.size()) {
@@ -271,6 +288,7 @@ public class ATrustParser {
this.usernamePasswordBlock = TryParseMainBlock(UsernamePasswordBlock.class);
this.smsTanBlock = TryParseMainBlock(SMSTanBlock.class);
this.qrCodeBlock = TryParseMainBlock(QRCodeBlock.class);
+ this.waitingForAppBlock = TryParseMainBlock(WaitingForAppBlock.class);
this.fido2Block = TryParseMainBlock(Fido2Block.class);
validate();