summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/MobileBKUConnector.java19
-rw-r--r--pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/ATrustParser.java32
-rw-r--r--pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/MobileBKUFingerprintComposite.java143
-rw-r--r--pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/WaitingForAppComposite.java7
-rw-r--r--pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/states/MobileBKUState.java116
5 files changed, 130 insertions, 187 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 2e301a2e..3efecb4c 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
@@ -291,6 +291,10 @@ public class MobileBKUConnector implements BkuSlConnector {
state.rememberCredentialsIfNecessary(this.credentials);
}
+ if (html.interstitialBlock != null) {
+ this.state.showInformationMessage(html.interstitialBlock.interstitialMessage);
+ return buildFormSubmit(html, html.interstitialBlock.submitButton);
+ }
if (html.errorBlock != null) {
try {
this.credentials.password = null;
@@ -342,7 +346,7 @@ public class MobileBKUConnector implements BkuSlConnector {
}
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);
+ this.state.showWaitingForAppOpen(html.waitingForAppBlock.referenceValue, html.signatureDataLink, html.smsTanLink != null, html.fido2Link != null);
longPollThread.start();
var result = this.state.waitForAppOpen();
switch (result) {
@@ -353,6 +357,19 @@ public class MobileBKUConnector implements BkuSlConnector {
return new HttpGet(html.htmlDocument.baseUri());
}
}
+ if (html.waitingForBiometryBlock != null) {
+ try (LongPollThread longPollThread = new LongPollThread(html.waitingForBiometryBlock.pollingURI, () -> { this.state.signalAppBiometryDone(); })) {
+ this.state.showWaitingForAppBiometry(html.waitingForBiometryBlock.referenceValue, html.signatureDataLink, html.smsTanLink != null, html.fido2Link != null);
+ longPollThread.start();
+ var result = this.state.waitForAppBiometry();
+ 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.fido2Block != null) {
var fido2Result = this.state.promptUserForFIDO2Auth(html.fido2Block.fidoOptions, html.signatureDataLink, html.smsTanLink != null);
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 f7bd45bf..1d0b6406 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
@@ -74,6 +74,19 @@ public class ATrustParser {
}
}
+ public static class InterstitialBlock extends TopLevelFormBlock {
+ public final @Nonnull String submitButton;
+ public final @Nonnull String interstitialMessage;
+
+ private InterstitialBlock(@Nonnull org.jsoup.nodes.Document htmlDocument, @Nonnull Map<String, String> formOptions) throws ComponentParseFailed {
+ super(htmlDocument, formOptions);
+ if (htmlDocument.baseUri().contains("/ExpiresInfo.aspx")) {
+ this.interstitialMessage = ISNOTNULL(getElementEnsureNotNull("#Label2").ownText());
+ this.submitButton = "#Button_Next";
+ } else { throw new ComponentParseFailed(); }
+ }
+ }
+
public static class ErrorBlock extends TopLevelFormBlock {
public final boolean isRecoverable;
public final @Nonnull String errorText;
@@ -159,6 +172,19 @@ public class ATrustParser {
}
}
+ public static class WaitingForBiometryBlock extends TopLevelFormBlock {
+ public final @Nonnull String referenceValue;
+ public final @Nonnull URI pollingURI;
+
+ private WaitingForBiometryBlock(@Nonnull org.jsoup.nodes.Document htmlDocument, @Nonnull Map<String, String> formOptions) throws ComponentParseFailed {
+ super(htmlDocument, formOptions);
+ abortIfElementMissing("#biometricimage");
+
+ this.referenceValue = ISNOTNULL(getElementEnsureNotNull("#vergleichswert").ownText());
+ this.pollingURI = getLongPollURI();
+ }
+ }
+
public static class Fido2Block extends TopLevelFormBlock {
public final @Nonnull String fidoOptions;
private final @Nonnull String credentialResultKey;
@@ -186,21 +212,25 @@ public class ATrustParser {
public final @CheckForNull URI fido2Link;
/* top-level blocks (exactly one is not null) */
+ public final @CheckForNull InterstitialBlock interstitialBlock;
public final @CheckForNull ErrorBlock errorBlock;
public final @CheckForNull UsernamePasswordBlock usernamePasswordBlock;
public final @CheckForNull SMSTanBlock smsTanBlock;
public final @CheckForNull QRCodeBlock qrCodeBlock;
public final @CheckForNull WaitingForAppBlock waitingForAppBlock;
+ public final @CheckForNull WaitingForBiometryBlock waitingForBiometryBlock;
public final @CheckForNull Fido2Block fido2Block;
private void validate() {
Set<String> populated = new HashSet<>();
+ if (interstitialBlock != null) populated.add("interstitialBlock");
if (errorBlock != null) populated.add("errorBlock");
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 (waitingForBiometryBlock != null) populated.add("waitingForBiometryBlock");
if (fido2Block != null) populated.add("fido2Block");
switch (populated.size()) {
@@ -280,11 +310,13 @@ public class ATrustParser {
this.smsTanLink = getHrefIfExists("#SmsButton");
this.fido2Link = getHrefIfExists("#FidoButton");
+ this.interstitialBlock = TryParseMainBlock(InterstitialBlock.class);
this.errorBlock = TryParseMainBlock(ErrorBlock.class);
this.usernamePasswordBlock = TryParseMainBlock(UsernamePasswordBlock.class);
this.smsTanBlock = TryParseMainBlock(SMSTanBlock.class);
this.qrCodeBlock = TryParseMainBlock(QRCodeBlock.class);
this.waitingForAppBlock = TryParseMainBlock(WaitingForAppBlock.class);
+ this.waitingForBiometryBlock = TryParseMainBlock(WaitingForBiometryBlock.class);
this.fido2Block = TryParseMainBlock(Fido2Block.class);
validate();
diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/MobileBKUFingerprintComposite.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/MobileBKUFingerprintComposite.java
index 14ca1dc7..dfde1d1e 100644
--- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/MobileBKUFingerprintComposite.java
+++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/MobileBKUFingerprintComposite.java
@@ -15,12 +15,12 @@
*/
package at.asit.pdfover.gui.composites.mobilebku;
+import java.net.URI;
+
// Imports
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.Rectangle;
@@ -29,8 +29,6 @@ import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Link;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import at.asit.pdfover.commons.Constants;
import at.asit.pdfover.commons.Messages;
@@ -42,102 +40,33 @@ import at.asit.pdfover.gui.workflow.states.State;
* Composite for displaying the QR code for the mobile BKU
*/
public class MobileBKUFingerprintComposite extends StateComposite {
-
- /**
- *
- */
- private final class SMSSelectionListener extends SelectionAdapter {
- /**
- * Empty constructor
- */
- public SMSSelectionListener() {
- }
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- if(!MobileBKUFingerprintComposite.this.btn_sms.getEnabled()) {
- return;
- }
-
- MobileBKUFingerprintComposite.this.setUserSMS(true);
- MobileBKUFingerprintComposite.this.btn_sms.setEnabled(false);
- }
- }
-
- /**
- *
- */
- private final class CancelSelectionListener extends SelectionAdapter {
- /**
- * Empty constructor
- */
- public CancelSelectionListener() {
- }
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- MobileBKUFingerprintComposite.this.setUserCancel(true);
- }
- }
-
- /**
- * SLF4J Logger instance
- **/
- static final Logger log = LoggerFactory.getLogger(MobileBKUFingerprintComposite.class);
-
- boolean userCancel = false;
- boolean userSMS = false;
- boolean done = false;
-
- private Label lblRefVal;
-
- String refVal;
-
- String signatureData;
-
- /**
- * @return the signatureData
- */
- public String getSignatureData() {
- return this.signatureData;
- }
-
- /**
- * @param signatureData
- * the signatureData to set
- */
- public void setSignatureData(String signatureData) {
- this.signatureData = signatureData;
- }
-
private Label lblError;
private Label lblRefValLabel;
private Label lblFPLabel;
+ private Label lblRefVal;
+ private Button btn_sms;
+ private Button btn_cancel;
+ private Link lnk_sig_data;
+ public URI signatureDataURI;
+ private String refVal;
- Button btn_sms;
- Button btn_cancel;
+ private boolean userCancelClicked = false;
+ private boolean userSMSClicked = false;
+ private boolean pollingDone = false;
- Link lnk_sig_data;
+ public void signalPollingDone() { this.pollingDone = true; getDisplay().wake(); }
+ public boolean isDone() { return (this.userCancelClicked || this.userSMSClicked || this.pollingDone); }
+ public boolean wasCancelClicked() { return this.userCancelClicked; }
+ public boolean wasSMSClicked() { return this.userSMSClicked; }
+ public boolean wasFIDO2Clicked() { return false; } // TODO
+ public void reset() { this.userCancelClicked = this.userSMSClicked = this.pollingDone = false; }
- /**
- * @return the userCancel
- */
- public boolean isUserCancel() {
- return this.userCancel;
- }
-
- /**
- * @return the userSMS
- */
- public boolean isUserSMS() {
- return this.userSMS;
+ public void setSMSEnabled(boolean state) {
+ this.btn_sms.setEnabled(state);
}
- /**
- * @return the done
- */
- public boolean isDone() {
- return this.done;
+ public void setFIDO2Enabled(boolean state) {
+ // TODO
}
/**
@@ -153,30 +82,6 @@ public class MobileBKUFingerprintComposite extends StateComposite {
}
/**
- * @param userCancel
- * the userCancel to set
- */
- public void setUserCancel(boolean userCancel) {
- this.userCancel = userCancel;
- }
-
- /**
- * @param userSMS
- * the userSMS to set
- */
- public void setUserSMS(boolean userSMS) {
- this.userSMS = userSMS;
- }
-
- /**
- * @param done
- * the done to set
- */
- public void setDone(boolean done) {
- this.done = done;
- }
-
- /**
* @return the reference value
*/
public String getRefVal() {
@@ -245,15 +150,15 @@ public class MobileBKUFingerprintComposite extends StateComposite {
this.lnk_sig_data = new Link(containerComposite, SWT.NATIVE | SWT.RESIZE);
SWTUtils.anchor(lnk_sig_data).right(100, -20).top(0, 20);
this.lnk_sig_data.setEnabled(true);
- SWTUtils.addSelectionListener(lnk_sig_data, (e) -> { SWTUtils.openURL(getSignatureData()); });
+ SWTUtils.addSelectionListener(lnk_sig_data, (e) -> { SWTUtils.openURL(this.signatureDataURI); });
this.btn_cancel = new Button(containerComposite, SWT.NATIVE);
SWTUtils.anchor(btn_cancel).right(100, -20).bottom(100, -20);
- this.btn_cancel.addSelectionListener(new CancelSelectionListener());
+ SWTUtils.addSelectionListener(btn_cancel, () -> { userCancelClicked = true; });
this.btn_sms = new Button(containerComposite, SWT.NATIVE);
SWTUtils.anchor(btn_sms).right(btn_cancel, -20).bottom(100, -20);
- this.btn_sms.addSelectionListener(new SMSSelectionListener());
+ SWTUtils.addSelectionListener(btn_sms, () -> { userSMSClicked = true; });
this.lblError = new Label(containerComposite, SWT.WRAP | SWT.NATIVE);
SWTUtils.anchor(lblError).right(btn_sms, -10).bottom(100, -20);
diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/WaitingForAppComposite.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/WaitingForAppComposite.java
index ed311957..b1e676f0 100644
--- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/WaitingForAppComposite.java
+++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/mobilebku/WaitingForAppComposite.java
@@ -41,13 +41,6 @@ public class WaitingForAppComposite extends StateComposite {
private boolean userFIDO2Clicked = false;
private boolean pollingDone = false;
- /**
- * @return the isDone
- */
- public Boolean getIsDone() {
- return this.pollingDone;
- }
-
public void signalPollingDone() { this.pollingDone = true; getDisplay().wake(); }
public boolean isDone() { return (this.userCancelClicked || this.userSMSClicked || this.userFIDO2Clicked || this.pollingDone); }
public boolean wasCancelClicked() { return this.userCancelClicked; }
diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/states/MobileBKUState.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/states/MobileBKUState.java
index 15348218..4ddededf 100644
--- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/states/MobileBKUState.java
+++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/states/MobileBKUState.java
@@ -51,6 +51,8 @@ import at.asit.pdfover.gui.composites.mobilebku.MobileBKUFingerprintComposite;
import at.asit.pdfover.gui.composites.mobilebku.MobileBKUQRComposite;
import at.asit.pdfover.gui.composites.mobilebku.WaitingForAppComposite;
import at.asit.pdfover.gui.controls.Dialog.BUTTONS;
+import at.asit.pdfover.gui.controls.Dialog.ICON;
+import at.asit.pdfover.gui.controls.Dialog;
import at.asit.pdfover.gui.controls.ErrorDialog;
import at.asit.pdfover.commons.Messages;
import at.asit.pdfover.gui.workflow.StateMachine;
@@ -188,6 +190,16 @@ public class MobileBKUState extends State {
});
}
+ public void showInformationMessage(final @Nonnull String message) throws UserCancelledException {
+ Display.getDefault().syncCall(() -> {
+ Dialog dialog = new Dialog(getStateMachine().getMainShell(), Messages.getString("common.info"), message, BUTTONS.OK, ICON.INFORMATION);
+ int result = dialog.open();
+ if (result == SWT.CANCEL)
+ throw new UserCancelledException();
+ return true; /* dummy return to keep java happy */
+ });
+ }
+
/**
* Show an error message to the user with "retry" or "cancel" as options
* returns normally on "retry", throws UserCancelledException on "cancel"
@@ -417,7 +429,7 @@ public class MobileBKUState extends State {
/**
* start showing the "waiting for app" screen
* this method will return immediately */
- public void showWaitingForApp(final @Nonnull String referenceValue, @Nullable URI signatureDataURI, final boolean showSmsTan, final boolean showFido2) {
+ public void showWaitingForAppOpen(final @Nonnull String referenceValue, @Nullable URI signatureDataURI, final boolean showSmsTan, final boolean showFido2) {
Display.getDefault().syncExec(() -> {
WaitingForAppComposite wfa = getWaitingForAppComposite();
wfa.reset();
@@ -473,76 +485,60 @@ public class MobileBKUState extends State {
getWaitingForAppComposite().signalPollingDone();
}
- /**
- * when fingerprint or faceid is selected in the app
- * this information is shown
- */
- /*public void showFingerPrintInformation() {
- final ATrustStatus status = this.status;
- final ATrustHandler handler = this.handler;
-
- Timer checkDone = new Timer();
- checkDone.scheduleAtFixedRate(new TimerTask() {
-
- @Override
- public void run() {
- // ping signature page to see if code has been scanned
- try {
- String resp = handler.getSignaturePage();
- if (handler.handleQRResponse(resp)) {
- log.debug("Signature page response: " + resp);
- getMobileBKUFingerprintComposite().setDone(true);
- Display display = getStateMachine().getMainShell().getDisplay();
- display.wake();
- checkDone.cancel();
- }
- Display.getDefault().wake();
- } catch (Exception e) {
- log.error("Error getting signature page", e);
- }
- }
- }, 0, 5000);
+ public void showWaitingForAppBiometry(final @Nonnull String referenceValue, @Nullable URI signatureDataURI, final boolean showSmsTan, final boolean showFido2) {
Display.getDefault().syncExec(() -> {
- MobileBKUFingerprintComposite fingerprintComposite = getMobileBKUFingerprintComposite();
+ MobileBKUFingerprintComposite bio = getMobileBKUFingerprintComposite();
+ bio.reset();
+
+ bio.setRefVal(referenceValue);
+ bio.signatureDataURI = signatureDataURI;
+ bio.setErrorMessage(null); // TODO
+ bio.setSMSEnabled(showSmsTan);
+ bio.setFIDO2Enabled(showFido2);
+ getStateMachine().display(bio);
+ });
+ }
- fingerprintComposite.setRefVal(status.refVal);
- fingerprintComposite.setSignatureData(status.signatureDataURL);
- fingerprintComposite.setErrorMessage(status.errorMessage);
- getStateMachine().display(fingerprintComposite);
+ // TODO can we maybe deduplicate the various waiting screens' logic?
- Display display = getStateMachine().getMainShell().getDisplay();
- while (!fingerprintComposite.isUserCancel() && !fingerprintComposite.isUserSMS() && !fingerprintComposite.isDone()) {
- if (!display.readAndDispatch()) {
+ public enum AppBiometryResult {
+ /* the user has pressed the FIDO2 button */
+ TO_FIDO2,
+ /* the user has pressed the SMS button */
+ TO_SMS,
+ /* signalAppBiometryDone has been called; this indicates that we should refresh the page */
+ UPDATE
+ };
+
+ public @Nonnull AppBiometryResult waitForAppBiometry() throws UserCancelledException {
+ return ISNOTNULL(Display.getDefault().syncCall(() -> {
+ MobileBKUFingerprintComposite bio = getMobileBKUFingerprintComposite();
+
+ Display display = bio.getDisplay();
+ while (!bio.isDone()) {
+ if (!display.readAndDispatch())
display.sleep();
- }
}
- checkDone.cancel();
- if (fingerprintComposite.isUserCancel()) {
- fingerprintComposite.setUserCancel(false);
- clearRememberedPassword();
- status.errorMessage = "cancel";
- return;
- }
+ getStateMachine().display(this.getWaitingComposite());
- if (fingerprintComposite.isUserSMS()) {
-// fingerprintComposite.setUserSMS(false);
- status.qrCodeURL = null;
+ if (bio.wasCancelClicked()) {
+ clearRememberedPassword();
+ throw new UserCancelledException();
}
- if (fingerprintComposite.isDone())
- fingerprintComposite.setDone(false);
+ if (bio.wasSMSClicked())
+ return AppBiometryResult.TO_SMS;
+
+ if (bio.wasFIDO2Clicked())
+ return AppBiometryResult.TO_FIDO2;
- // show waiting composite
- getStateMachine().display(this.getWaitingComposite());
- });
- }*/
+ return AppBiometryResult.UPDATE;
+ }));
+ }
- /**
- * @return a boolean true if the user has pressed the sms tan button
- */
- public boolean getSMSStatus() {
- return this.getMobileBKUFingerprintComposite().isUserSMS();
+ public void signalAppBiometryDone() {
+ getMobileBKUFingerprintComposite().signalPollingDone();
}
public static class FIDO2Result {