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/BKUHelper.java105
-rw-r--r--pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/LocalBKUConnector.java122
-rw-r--r--pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/MobileBKUConnector.java439
-rw-r--r--pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/ATrustParser.java379
-rw-r--r--pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/MobileBKUValidator.java93
5 files changed, 0 insertions, 1138 deletions
diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/BKUHelper.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/BKUHelper.java
deleted file mode 100644
index 382a3d24..00000000
--- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/BKUHelper.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright 2012 by A-SIT, Secure Information Technology Center Austria
- *
- * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
- * the European Commission - subsequent versions of the EUPL (the "Licence");
- * You may not use this work except in compliance with the Licence.
- * You may obtain a copy of the Licence at:
- * http://joinup.ec.europa.eu/software/page/eupl
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the Licence is distributed on an "AS IS" basis,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Licence for the specific language governing permissions and
- * limitations under the Licence.
- */
-package at.asit.pdfover.gui.bku;
-
-import org.apache.commons.httpclient.HttpClient;
-import org.apache.commons.httpclient.UsernamePasswordCredentials;
-// Imports
-import org.apache.commons.httpclient.auth.AuthScope;
-import org.apache.http.client.config.CookieSpecs;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import at.asit.pdfover.commons.Constants;
-
-/**
- *
- */
-public class BKUHelper {
- /**
- * SLF4J Logger instance
- **/
- @SuppressWarnings("unused")
- private static final Logger log = LoggerFactory.getLogger(BKUHelper.class);
-
- /* public static HttpClient getHttpClient(boolean useProxy) {
- HttpClient client = new HttpClient();
- client.getParams().setParameter("http.useragent",
- Constants.APP_NAME_VERSION);
-
- if (useProxy) {
- String host = System.getProperty("http.proxyHost");
- String port = System.getProperty("http.proxyPort");
- if (host != null && !host.isEmpty() &&
- port != null && !port.isEmpty()) {
- int p = Integer.parseInt(port);
- client.getHostConfiguration().setProxy(host, p);
- String user = System.getProperty("http.proxyUser");
- String pass = System.getProperty("http.proxyPassword");
- if (user != null && !user.isEmpty() && pass != null) {
- client.getState().setProxyCredentials(new AuthScope(host, p),
- new UsernamePasswordCredentials(user, pass));
- }
- }
- }
-
- return client;
- }*/
-
- /**
- * Get a HTTP Client instance
- *
- * @param useProxy
- * whether to use a potentially set proxy
- * @return the HttpClient
- */
- @SuppressWarnings("deprecation")
- public static HttpClient getHttpClient(boolean useProxy) {
- HttpClient client = new HttpClient();
- client.getParams().setParameter("http.useragent",
- Constants.APP_NAME_VERSION);
-
-
- client.getParams().setParameter("http.protocol.cookie-policy", CookieSpecs.BROWSER_COMPATIBILITY);
-
- if (useProxy) {
- String host = System.getProperty("http.proxyHost");//
- String port = System.getProperty("http.proxyPort");//
- if (host != null && !host.isEmpty() && port != null && !port.isEmpty()) {
- int p = Integer.parseInt(port);
- client.getHostConfiguration().setProxy(host, p);
- String user = System.getProperty("http.proxyUser");//
- String pass = System.getProperty("http.proxyPassword");//
- if (user != null && !user.isEmpty() && pass != null) {
- client.getState().setProxyCredentials(new AuthScope(host, p),
- new UsernamePasswordCredentials(user, pass));
- }
- }
- }
-
- return client;
-
- }
-
- /**
- * Get a HTTP Client instance
- *
- * @return the HttpClient
- */
- public static HttpClient getHttpClient() {
- return getHttpClient(false);
- }
-}
diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/LocalBKUConnector.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/LocalBKUConnector.java
deleted file mode 100644
index 1f68a020..00000000
--- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/LocalBKUConnector.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2012 by A-SIT, Secure Information Technology Center Austria
- *
- * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
- * the European Commission - subsequent versions of the EUPL (the "Licence");
- * You may not use this work except in compliance with the Licence.
- * You may obtain a copy of the Licence at:
- * http://joinup.ec.europa.eu/software/page/eupl
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the Licence is distributed on an "AS IS" basis,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Licence for the specific language governing permissions and
- * limitations under the Licence.
- */
-package at.asit.pdfover.gui.bku;
-
-// Imports
-import java.io.IOException;
-import java.net.Socket;
-
-import org.apache.commons.httpclient.HttpClient;
-import org.apache.commons.httpclient.HttpException;
-import org.apache.commons.httpclient.HttpStatus;
-import org.apache.commons.httpclient.methods.PostMethod;
-import org.apache.commons.httpclient.methods.multipart.FilePart;
-import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
-import org.apache.commons.httpclient.methods.multipart.Part;
-import org.apache.commons.httpclient.methods.multipart.StringPart;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import at.asit.pdfover.commons.Constants;
-import at.asit.pdfover.gui.utils.FileUploadSource;
-import at.asit.pdfover.signer.BkuSlConnector;
-import at.asit.pdfover.signer.SignatureException;
-import at.asit.pdfover.signer.pdfas.PdfAs4SLRequest;
-
-/**
- *
- */
-public class LocalBKUConnector implements BkuSlConnector {
- /**
- * SLF4J Logger instance
- **/
- private static final Logger log = LoggerFactory.getLogger(LocalBKUConnector.class);
-
- private static boolean isAvailable = false;
- public static boolean IsAvailable() { return isAvailable; }
- private static Thread pollingThread = new Thread(() -> {
- while (true) {
- try { Thread.sleep(isAvailable ? 30000 : 5000); } catch (InterruptedException e) {}
- try (Socket socket = new Socket("127.0.0.1", 3495)) {
- isAvailable = true;
- } catch (IOException e) {
- isAvailable = false;
- }
- }
- }, "LocalBKUProbeThread");
- static {
- pollingThread.setDaemon(true);
- pollingThread.start();
- }
-
-
- /**
- * HTTP Response server HEADER
- */
- public final static String BKU_RESPONSE_HEADER_SERVER = "server";
-
- /**
- * HTTP Response user-agent HEADER
- */
- public final static String BKU_RESPONSE_HEADER_USERAGENT = "user-agent";
-
- /**
- * HTTP Response SignatureLayout HEADER
- */
- public final static String BKU_RESPONSE_HEADER_SIGNATURE_LAYOUT = "SignatureLayout";
-
- /* (non-Javadoc)
- * @see at.asit.pdfover.signator.BkuSlConnector#handleSLRequest(java.lang.String)
- */
- @Override
- public String handleSLRequest(PdfAs4SLRequest request) throws SignatureException {
- try {
- HttpClient client = BKUHelper.getHttpClient();
- PostMethod method = new PostMethod(Constants.LOCAL_BKU_URL);
-
- String sl_request = request.xmlRequest;
- if (request.signatureData == null) {
- method.addParameter("XMLRequest", sl_request);
- } else {
- StringPart xmlpart = new StringPart(
- "XMLRequest", sl_request, "UTF-8");
-
- FilePart filepart = new FilePart("fileupload", new FileUploadSource(request.signatureData));
-
- Part[] parts = { xmlpart, filepart };
-
- method.setRequestEntity(new MultipartRequestEntity(parts, method
- .getParams()));
- }
- log.trace("SL REQUEST: " + sl_request);
-
- int returnCode = client.executeMethod(method);
-
- if (returnCode != HttpStatus.SC_OK) {
- throw new HttpException(
- method.getResponseBodyAsString());
- }
-
- return method.getResponseBodyAsString();
- } catch (HttpException e) {
- log.error("LocalBKUConnector: ", e);
- throw new SignatureException(e);
- } catch (IOException e) {
- log.error("LocalBKUConnector: ", e);
- throw new SignatureException(e);
- }
- }
-}
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
deleted file mode 100644
index 779e24c6..00000000
--- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/MobileBKUConnector.java
+++ /dev/null
@@ -1,439 +0,0 @@
-package at.asit.pdfover.gui.bku;
-
-import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.Base64;
-import java.util.List;
-import java.util.Optional;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nonnull;
-
-import org.apache.hc.client5.http.classic.methods.HttpGet;
-import org.apache.hc.client5.http.classic.methods.HttpPost;
-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.core5.http.ClassicHttpRequest;
-import org.apache.hc.core5.http.ContentType;
-import org.apache.hc.core5.http.Header;
-import org.apache.hc.core5.http.HttpEntity;
-import org.apache.hc.core5.http.HttpStatus;
-import org.apache.hc.core5.http.NameValuePair;
-import org.apache.hc.core5.http.NoHttpResponseException;
-import org.apache.hc.core5.http.ParseException;
-import org.apache.hc.core5.http.ProtocolException;
-import org.apache.hc.core5.http.io.entity.EntityUtils;
-import org.apache.hc.core5.http.message.BasicNameValuePair;
-import org.json.JSONObject;
-import org.jsoup.Jsoup;
-import org.jsoup.nodes.Document;
-import org.jsoup.nodes.Element;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import at.asit.pdfover.commons.Constants;
-import at.asit.pdfover.commons.Messages;
-import at.asit.pdfover.gui.bku.mobile.ATrustParser;
-import at.asit.pdfover.gui.workflow.states.MobileBKUState;
-import at.asit.pdfover.gui.workflow.states.MobileBKUState.UsernameAndPassword;
-import at.asit.pdfover.signer.BkuSlConnector;
-import at.asit.pdfover.signer.SignatureException;
-import at.asit.pdfover.signer.UserCancelledException;
-import at.asit.pdfover.signer.pdfas.PdfAs4SLRequest;
-import at.asit.webauthn.WebAuthN;
-
-import static at.asit.pdfover.commons.Constants.ISNOTNULL;
-
-public class MobileBKUConnector implements BkuSlConnector {
- private static final Logger log = LoggerFactory.getLogger(MobileBKUConnector.class);
-
- private final @Nonnull MobileBKUState state;
- public MobileBKUConnector(@Nonnull MobileBKUState state) {
- this.state = state;
- this.wantsFido2Default = WebAuthN.isAvailable() && state.getConfig().getFido2ByDefault();
- state.storeRememberedCredentialsTo(this.credentials);
- }
-
- private class UserDisplayedError extends Exception {
- private final @Nonnull String msg;
- @Override public @Nonnull String getMessage() { return this.msg; }
- private UserDisplayedError(@Nonnull String s) { this.msg = s; }
- }
-
- public @Nonnull UsernameAndPassword credentials = new UsernameAndPassword();
-
- /**
- * This method takes the SLRequest from PDF-AS, and blocks until it has obtained a response
- */
- @Override
- public String handleSLRequest(PdfAs4SLRequest slRequest) throws SignatureException, UserCancelledException {
- log.debug("Got security layer request: (has file part: {})\n{}", (slRequest.signatureData != null), slRequest.xmlRequest);
- try (final CloseableHttpClient httpClient = HttpClients.custom().disableRedirectHandling().build()) {
- ClassicHttpRequest currentRequest = buildInitialRequest(slRequest);
- ATrustParser.Result response;
- while ((response = sendHTTPRequest(httpClient, currentRequest)).slResponse == null)
- currentRequest = presentResponseToUserAndReturnNextRequest(ISNOTNULL(response.html));
- log.debug("Returning security layer response:\n{}", response.slResponse);
- return response.slResponse;
- } catch (UserDisplayedError e) {
- state.showUnrecoverableError(e.getMessage());
- throw new IllegalStateException("unreachable", e); /* showUnrecoverableError always throws */
- } catch (UserCancelledException e) {
- throw e;
- } catch (Exception e) {
- throw new SignatureException(e);
- }
- }
-
- /* some anti-infinite-loop safeguards so we don't murder the atrust servers by accident */
- private int loopHTTPRequestCounter = 0;
- private Long lastHTTPRequestTime = null;
- /**
- * Sends the specified request, following redirects (including meta-tag redirects) recursively
- * @return The JSOUP document retrieved
- * @throws IOException on HTTP error codes
- * @throws ProtocolException
- * @throws URISyntaxException
- * @throws InterruptedException
- */
- private @Nonnull ATrustParser.Result sendHTTPRequest(CloseableHttpClient httpClient, ClassicHttpRequest request) throws IOException, ProtocolException, URISyntaxException, UserDisplayedError {
- long now = System.nanoTime();
- if ((lastHTTPRequestTime != null) && ((now - lastHTTPRequestTime) < 2e+9)) { /* less than 2s since last request */
- ++loopHTTPRequestCounter;
- if (loopHTTPRequestCounter > 250)
- throw new IOException("Infinite loop protection triggered");
- } else {
- loopHTTPRequestCounter = 0;
- }
- lastHTTPRequestTime = now;
-
- log.debug("Sending {} request to '{}'...", request.getMethod(), request.getUri().toString());
- try (final CloseableHttpResponse response = httpClient.execute(request)) {
- int httpStatus = response.getCode();
- if ((httpStatus == HttpStatus.SC_MOVED_PERMANENTLY) || (httpStatus == HttpStatus.SC_MOVED_TEMPORARILY)) {
- Header redirectPath = response.getHeader("location");
- if (redirectPath == null)
- throw new IOException("Received HTTP redirect, but no Location header.");
- return sendHTTPRequest(httpClient, buildRedirectedRequest(request.getUri(), redirectPath.getValue()));
- }
-
- if (httpStatus != HttpStatus.SC_OK) {
- switch (httpStatus) {
- case HttpStatus.SC_REQUEST_TOO_LONG: throw new UserDisplayedError(Messages.getString("atrusterror.http_413"));
- default: throw new UserDisplayedError(Messages.formatString("atrusterror.http_generic", httpStatus, Optional.ofNullable(response.getReasonPhrase()).orElse("(null)")));
- }
- }
-
- Header refreshHeader = response.getHeader("refresh");
- if (refreshHeader != null)
- return sendHTTPRequest(httpClient, buildRefreshHeaderRequest(request.getUri(), refreshHeader.getValue()));
-
- HttpEntity responseEntity = response.getEntity();
- if (responseEntity == null)
- throw new IOException("Did not get a HTTP body (entity == null)");
-
- ContentType contentType = ContentType.parse(responseEntity.getContentType());
- String entityBody = EntityUtils.toString(response.getEntity(),contentType.getCharset());
- if (entityBody == null)
- throw new IOException("Did not get a HTTP body (entity content == null)");
-
- if ("text/html".equals(contentType.getMimeType())) {
- Document resultDocument = Jsoup.parse(entityBody, request.getUri().toASCIIString());
- if (resultDocument == null)
- {
- log.error("Failed to parse A-Trust server response as HTML:\n{}", entityBody);
- throw new IOException("Failed to parse HTML");
- }
-
- Element metaRefresh = resultDocument.selectFirst("meta[http-equiv=\"refresh\"i]");
- if (metaRefresh != null) {
- String refreshContent = metaRefresh.attr("content");
- if (!refreshContent.isEmpty())
- return sendHTTPRequest(httpClient, buildRefreshHeaderRequest(request.getUri(), refreshContent));
- }
- return ATrustParser.Parse(resultDocument);
- } else {
- return ATrustParser.Parse(request.getUri(), contentType.getMimeType(), entityBody);
- }
- }
- }
-
- /**
- * Builds a HttpRequest for the given base URI and (potentially relative) redirect path
- */
- private static @Nonnull ClassicHttpRequest buildRedirectedRequest(URI baseURI, String redirectLocation) {
- log.debug("following redirect: {}", redirectLocation);
- return new HttpGet(baseURI.resolve(redirectLocation));
- }
-
- /**
- * Builds a HttpRequest for redirection to a given Refresh header value
- */
- private static @Nonnull ClassicHttpRequest buildRefreshHeaderRequest(URI baseURI, String refreshHeader) throws IOException {
- // refresh value is delay in seconds, semicolon, URL=, url
- Pattern pattern = Pattern.compile("^\\s*[0-9\\.]+\\s*;\\s*(?:[uU][rR][lL]\s*=\s*)(.+)$");
- Matcher matcher = pattern.matcher(refreshHeader);
- if (!matcher.matches())
- throw new IOException("Got invalid Refresh header with value \"" + refreshHeader + "\".");
- String redirectURL = matcher.group(1);
- return buildRedirectedRequest(baseURI, redirectURL);
- }
-
- /**
- * Builds the initial request to A-Trust based on the specified SL request
- */
- private static @Nonnull ClassicHttpRequest buildInitialRequest(PdfAs4SLRequest slRequest) {
- HttpPost post = new HttpPost(Constants.MOBILE_BKU_URL);
- if (slRequest.signatureData != null) {
- post.setEntity(MultipartEntityBuilder.create()
- .addBinaryBody("fileupload", slRequest.signatureData.getByteArray(), ContentType.APPLICATION_PDF, "sign.pdf")
- .addTextBody("XMLRequest", slRequest.xmlRequest)
- .build());
- } else {
- post.setEntity(UrlEncodedFormEntityBuilder.create()
- .add("XMLRequest", slRequest.xmlRequest)
- .build());
- }
- return post;
- }
-
- private static @Nonnull ClassicHttpRequest buildFormSubmit(@Nonnull ATrustParser.HTMLResult html, @CheckForNull String submitButton) {
- HttpPost post = new HttpPost(html.formTarget);
-
- var builder = MultipartEntityBuilder.create();
- for (var pair : html.iterateFormOptions())
- builder.addTextBody(pair.getKey(), pair.getValue());
-
- if (submitButton != null) {
- var submitButtonElm = html.htmlDocument.selectFirst(submitButton);
- if (submitButtonElm != null) {
- if ("input".equalsIgnoreCase(submitButtonElm.tagName())) {
- if ("submit".equalsIgnoreCase(submitButtonElm.attr("type"))) {
- String name = submitButtonElm.attr("name");
- if (!name.isEmpty())
- builder.addTextBody(name, submitButtonElm.attr("value"));
- } else {
- log.warn("Skipped specified submitButton {}, type is {} (not submit)", submitButton, submitButtonElm.attr("type"));
- }
- } else {
- log.warn("Skipped specified submitButton {}, tag name is {} (not input)", submitButton, submitButtonElm.tagName());
- }
- } else {
- log.warn("Skipped specified submitButton {}, element not found", submitButton);
- }
- }
-
- post.setEntity(builder.build());
- 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); }
- }
-
- }
-
- private boolean wantsFido2Default;
- /**
- * Main lifting function for MobileBKU UX
- * @return the next request to make
- */
- private @Nonnull ClassicHttpRequest presentResponseToUserAndReturnNextRequest(@Nonnull ATrustParser.HTMLResult html) throws UserCancelledException {
- if ((html.errorBlock == null) && (html.usernamePasswordBlock == null)) { /* successful username/password auth */
- if ((this.credentials.username != null) && (this.credentials.password != null))
- state.rememberCredentialsIfNecessary(this.credentials);
- }
-
- if (wantsFido2Default && (html.fido2Link != null)) {
- wantsFido2Default = false;
- return new HttpGet(html.fido2Link);
- }
-
- if (html.autoSkipBlock != null) {
- return buildFormSubmit(html, html.autoSkipBlock.submitButton);
- }
- 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;
- this.state.clearRememberedPassword();
-
- if (html.errorBlock.isRecoverable)
- this.state.showRecoverableError(html.errorBlock.errorText);
- else
- this.state.showUnrecoverableError(html.errorBlock.errorText);
- return buildFormSubmit(html, "#Button_Back");
- } catch (UserCancelledException e) {
- return buildFormSubmit(html, "#Button_Cancel");
- }
- }
- if (html.usernamePasswordBlock != null) {
- try {
- while ((this.credentials.username == null) || (this.credentials.password == null)) {
- this.state.getCredentialsFromUserTo(this.credentials, html.usernamePasswordBlock.errorMessage);
- }
- html.usernamePasswordBlock.setUsernamePassword(this.credentials.username, this.credentials.password);
- return buildFormSubmit(html, "#Button_Identification");
- } catch (UserCancelledException e) {
- return buildFormSubmit(html, "#Button_Cancel");
- }
- }
- if (html.smsTanBlock != null) {
- MobileBKUState.SMSTanResult result = this.state.getSMSTanFromUser(
- html.smsTanBlock.referenceValue, html.signatureDataLink,
- html.fido2Link != null, html.smsTanBlock.errorMessage);
-
- switch (result.type) {
- case TO_FIDO2: if (html.fido2Link != null) return new HttpGet(html.fido2Link);
- case SMSTAN: html.smsTanBlock.setTAN(result.smsTan); return buildFormSubmit(html, "#SignButton");
- }
- return new HttpGet(html.htmlDocument.baseUri());
- }
- if (html.qrCodeBlock != null) {
- 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.showWaitingForAppOpen(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;
- }
- 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);
-
- switch (fido2Result.type) {
- case TO_SMS: return new HttpGet(html.smsTanLink);
- case CREDENTIAL: break;
- }
-
- var fido2Assertion = ISNOTNULL(fido2Result.credential);
-
- Base64.Encoder base64 = Base64.getEncoder();
-
- JSONObject aTrustAssertion = new JSONObject();
- aTrustAssertion.put("id", fido2Assertion.id);
- aTrustAssertion.put("rawId", base64.encodeToString(fido2Assertion.rawId));
- aTrustAssertion.put("type", fido2Assertion.type);
- aTrustAssertion.put("extensions", new JSONObject()); // TODO fix extensions in library
-
- JSONObject aTrustAssertionResponse = new JSONObject();
- aTrustAssertion.put("response", aTrustAssertionResponse);
- aTrustAssertionResponse.put("authenticatorData", base64.encodeToString(fido2Assertion.response.authenticatorData));
- aTrustAssertionResponse.put("clientDataJson", base64.encodeToString(fido2Assertion.response.clientDataJSON));
- aTrustAssertionResponse.put("signature", base64.encodeToString(fido2Assertion.response.signature));
- if (fido2Assertion.response.userHandle != null)
- aTrustAssertionResponse.put("userHandle", base64.encodeToString(fido2Assertion.response.userHandle));
- else
- aTrustAssertionResponse.put("userHandle", JSONObject.NULL);
-
- html.fido2Block.setFIDOResult(aTrustAssertion.toString());
- return buildFormSubmit(html, "#FidoContinue");
- }
- throw new IllegalStateException("No top-level block is set? Something has gone terribly wrong.");
- }
-
- private static class UrlEncodedFormEntityBuilder {
- private UrlEncodedFormEntityBuilder() {}
- private List<NameValuePair> values = new ArrayList<>();
- public static @Nonnull UrlEncodedFormEntityBuilder create() { return new UrlEncodedFormEntityBuilder(); }
- public @Nonnull UrlEncodedFormEntityBuilder add(String key, String value) { values.add(new BasicNameValuePair(key, value)); return this; }
- public @Nonnull UrlEncodedFormEntity build() { return new UrlEncodedFormEntity(values, Charset.forName("utf-8")); }
- }
-}
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
deleted file mode 100644
index 89f53629..00000000
--- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/ATrustParser.java
+++ /dev/null
@@ -1,379 +0,0 @@
-package at.asit.pdfover.gui.bku.mobile;
-
-import java.lang.reflect.InvocationTargetException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import org.jsoup.Jsoup;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import static at.asit.pdfover.commons.Constants.ISNOTNULL;
-
-public class ATrustParser {
- private static final Logger log = LoggerFactory.getLogger(ATrustParser.class);
-
- private static class ComponentParseFailed extends Exception {}
-
- private static class TopLevelFormBlock {
- protected final @Nonnull org.jsoup.nodes.Document htmlDocument;
- protected final @Nonnull Map<String, String> formOptions;
- protected TopLevelFormBlock(@Nonnull org.jsoup.nodes.Document d, @Nonnull Map<String,String> fO) { this.htmlDocument = d; this.formOptions = fO; }
-
- protected void abortIfElementMissing(@Nonnull String selector) throws ComponentParseFailed {
- if (this.htmlDocument.selectFirst(selector) != null) return;
- log.debug("Tested for element {} -- not found.", selector);
- throw new ComponentParseFailed();
- }
- protected @Nonnull org.jsoup.nodes.Element getElementEnsureNotNull(@Nonnull String selector) throws ComponentParseFailed {
- var elm = this.htmlDocument.selectFirst(selector);
- if (elm == null) { log.warn("Expected element not found in response: {}", selector); throw new ComponentParseFailed(); }
- return elm;
- }
- protected @Nonnull String getAttributeEnsureNotNull(@Nonnull String selector, @Nonnull String attribute) throws ComponentParseFailed {
- var elm = getElementEnsureNotNull(selector);
- if (!elm.hasAttr(attribute)) { log.warn("Element {} is missing expected attribute '{}'.", selector, attribute); throw new ComponentParseFailed(); }
- return ISNOTNULL(elm.attr(attribute));
- }
- protected @Nonnull URI getURIAttributeEnsureNotNull(@Nonnull String selector, @Nonnull String attribute) throws ComponentParseFailed {
- String value = getAttributeEnsureNotNull(selector, attribute);
- try {
- return new URI(value);
- } catch (URISyntaxException e) {
- if (attribute.startsWith("abs:"))
- attribute = ISNOTNULL(attribute.substring(4));
- log.warn("Element {} attribute {} is '{}', could not be parsed as URI", selector, attribute, getAttributeEnsureNotNull(selector, attribute));
- 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 AutoSkipBlock extends TopLevelFormBlock {
- public final @Nonnull String submitButton;
-
- private AutoSkipBlock(@Nonnull org.jsoup.nodes.Document htmlDocument, @Nonnull Map<String, String> formOptions) throws ComponentParseFailed {
- super(htmlDocument, formOptions);
- if (htmlDocument.baseUri().contains("/tanAppInfo.aspx")) {
- this.submitButton = "#NextBtn";
- } else { throw new ComponentParseFailed(); }
- }
- }
-
- 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;
-
- private ErrorBlock(@Nonnull org.jsoup.nodes.Document htmlDocument, @Nonnull Map<String, String> formOptions) throws ComponentParseFailed {
- super(htmlDocument, formOptions);
-
- try {
- String documentPath = new URI(htmlDocument.baseUri()).getPath();
- String aspxFile = documentPath.substring(documentPath.lastIndexOf('/'));
-
- // gods this is such a hack, why can't they have a proper error element or something
- if (!(aspxFile.startsWith("/error") && aspxFile.endsWith(".aspx")))
- throw new ComponentParseFailed();
- } catch (URISyntaxException ex) {
- log.warn("Failed to parse document base URI as URI? ({})", htmlDocument.baseUri());
- throw new ComponentParseFailed();
- }
-
- this.isRecoverable = (htmlDocument.selectFirst("#Button_Back") != null);
-
- StringBuilder errorText = new StringBuilder(getElementEnsureNotNull("#Label1").ownText().trim());
- var detailLabel = this.htmlDocument.selectFirst("#LabelDetail");
- if (detailLabel != null)
- errorText.append("\n").append(detailLabel.ownText().trim());
- this.errorText = ISNOTNULL(errorText.toString());
- }
- }
-
- public static class UsernamePasswordBlock extends TopLevelFormBlock {
- private final @Nonnull String usernameKey;
- private final @Nonnull String passwordKey;
- public final @CheckForNull String errorMessage;
-
- public void setUsernamePassword(String username, String password) {
- formOptions.put(usernameKey, username); formOptions.put(passwordKey, password);
- }
-
- private UsernamePasswordBlock(@Nonnull org.jsoup.nodes.Document htmlDocument, @Nonnull Map<String, String> formOptions) throws ComponentParseFailed {
- super(htmlDocument, formOptions);
- abortIfElementMissing("#handynummer");
- this.usernameKey = getAttributeEnsureNotNull("#handynummer", "name");
- this.passwordKey = getAttributeEnsureNotNull("#signaturpasswort", "name");
- this.errorMessage = null;
- }
- }
-
- public static class SMSTanBlock extends TopLevelFormBlock {
- private final @Nonnull String tanKey;
- public final @Nonnull String referenceValue;
- public final @CheckForNull String errorMessage;
-
- public void setTAN(String tan) {
- formOptions.put(tanKey, tan);
- }
-
- private SMSTanBlock(@Nonnull org.jsoup.nodes.Document htmlDocument, @Nonnull Map<String, String> formOptions) throws ComponentParseFailed {
- super(htmlDocument, formOptions);
- abortIfElementMissing("#input_tan");
- this.tanKey = getAttributeEnsureNotNull("#input_tan", "name");
- this.referenceValue = ISNOTNULL(getElementEnsureNotNull("#vergleichswert").ownText());
- this.errorMessage = null;
- }
- }
-
- public static class QRCodeBlock extends TopLevelFormBlock {
- public final @Nonnull String referenceValue;
- public final @Nonnull URI qrCodeURI;
- public final @Nonnull URI pollingURI;
- public final @Nullable String errorMessage;
-
- private QRCodeBlock(@Nonnull org.jsoup.nodes.Document htmlDocument, @Nonnull Map<String, String> formOptions) throws ComponentParseFailed {
- super(htmlDocument, formOptions);
- abortIfElementMissing("#qrimage");
-
- this.referenceValue = ISNOTNULL(getElementEnsureNotNull("#vergleichswert").ownText());
- this.qrCodeURI = getURIAttributeEnsureNotNull("#qrimage", "abs:src");
- this.pollingURI = getLongPollURI();
-
- this.errorMessage = null;
- }
- }
-
- public static class WaitingForAppBlock extends TopLevelFormBlock {
- public final @Nonnull String referenceValue;
- public final @Nonnull URI pollingURI;
-
- private WaitingForAppBlock(@Nonnull org.jsoup.nodes.Document htmlDocument, @Nonnull Map<String, String> formOptions) throws ComponentParseFailed {
- super(htmlDocument, formOptions);
- abortIfElementMissing("#smartphoneAnimation");
-
- this.referenceValue = ISNOTNULL(getElementEnsureNotNull("#vergleichswert").ownText());
- this.pollingURI = getLongPollURI();
- }
- }
-
- 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;
-
- public void setFIDOResult(String result) { formOptions.put(credentialResultKey, result); }
-
- private Fido2Block(@Nonnull org.jsoup.nodes.Document htmlDocument, @Nonnull Map<String, String> formOptions) throws ComponentParseFailed {
- super(htmlDocument, formOptions);
- abortIfElementMissing("#fidoBlock");
- this.fidoOptions = getAttributeEnsureNotNull("#credentialOptions", "value");
- this.credentialResultKey = getAttributeEnsureNotNull("#credentialResult", "name");
- }
- }
-
- public static class HTMLResult {
- public final @Nonnull org.jsoup.nodes.Document htmlDocument;
- public final @Nonnull URI formTarget;
- public final @Nonnull Map<String, String> formOptions = new HashMap<>();
-
- public @Nonnull Iterable<Map.Entry<String, String>> iterateFormOptions() { return ISNOTNULL(formOptions.entrySet()); }
-
- /* optional links (any number may or may not be null) */
- public final @CheckForNull URI signatureDataLink;
- public final @CheckForNull URI smsTanLink;
- public final @CheckForNull URI fido2Link;
-
- /* top-level blocks (exactly one is not null) */
- public final @CheckForNull AutoSkipBlock autoSkipBlock;
- 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 (autoSkipBlock != null) populated.add("autoSkipBlock");
- 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()) {
- case 0: log.error("Did not find any top-level blocks.\n{}", this.htmlDocument.toString()); break;
- case 1: /* passed */ return;
- default: log.error("Found too many top-level blocks: {}\n", String.join(", ", populated), this.htmlDocument.toString()); break;
- }
- throw new IllegalArgumentException("Unknown A-Trust page reached?");
- }
-
- private @Nullable URI getHrefIfExists(String selector) {
- var elm = htmlDocument.selectFirst(selector);
- if (elm == null) return null;
-
- String url = elm.absUrl("href");
- try {
- return new URI(url);
- } catch (Exception e) {
- log.warn("Invalid {} href attribute: {} ({})", selector, elm.attr("href"), url);
- return null;
- }
- }
-
- /**
- * tries to parse T using its constructor; if ComponentParseFailed is thrown, swallows it
- */
- private <T extends TopLevelFormBlock> @Nullable T TryParseMainBlock(Class<T> clazz) {
- try {
- return clazz.getDeclaredConstructor(org.jsoup.nodes.Document.class, Map.class).newInstance(this.htmlDocument, this.formOptions);
- } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | IllegalArgumentException | SecurityException e) {
- log.error("Internal parser error; check your method signatures?", e);
- return null;
- } catch (InvocationTargetException wrappedE) {
- Throwable e = wrappedE.getCause();
- if (!(e instanceof ComponentParseFailed)) {
- if (e instanceof RuntimeException)
- throw (RuntimeException)e;
- log.warn("Unexpected parser failure.", e);
- }
- return null;
- }
- }
-
- private HTMLResult(@Nonnull org.jsoup.nodes.Document htmlDocument) {
- log.trace("Now parsing:\n{}", htmlDocument.toString());
- this.htmlDocument = htmlDocument;
-
- var forms = htmlDocument.getElementsByTag("form");
- if (forms.size() != 1) {
- log.error("Found {} forms in A-Trust response document, expected 1. Document:\n{}", forms.size(), htmlDocument.toString());
- throw new IllegalArgumentException("Failed to parse A-Trust response page");
- }
-
- var mainForm = ISNOTNULL(forms.first()); /* size check above */
- String formAction = mainForm.absUrl("action");
- try {
- this.formTarget = new URI(formAction);
- } catch (URISyntaxException e) {
- log.error("Invalid form target in page: {} ({})", mainForm.attr("action"), formAction, e);
- throw new IllegalArgumentException("Failed to parse A-Trust response page");
- }
-
- for (var input : mainForm.select("input")) {
- String name = input.attr("name");
-
- if (name.isEmpty())
- continue;
-
- /* submit inputs omitted here, they only get sent if they are "clicked", cf. MobileBKUConnector::buildFormSubmit */
- if ("submit".equalsIgnoreCase(input.attr("type")))
- continue;
-
- this.formOptions.put(name, input.attr("value"));
- }
-
- this.signatureDataLink = getHrefIfExists("#LinkList a[href*=\"ShowSigobj.aspx\"]"); /* grr, they didn't give it an ID */
- this.smsTanLink = getHrefIfExists("#SmsButton");
- this.fido2Link = getHrefIfExists("#FidoButton"); // TODO hide the button if unsupported?
-
- this.autoSkipBlock = TryParseMainBlock(AutoSkipBlock.class);
- 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();
- }
- }
-
- public static class Result {
- public final @CheckForNull String slResponse;
- public final @CheckForNull HTMLResult html;
-
- private Result(@Nonnull String slResponse) { this.slResponse = slResponse; this.html = null; }
- private Result(@Nonnull org.jsoup.nodes.Document htmlDocument) { this.slResponse = null; this.html = new HTMLResult(htmlDocument); }
- }
-
- public static @Nonnull Result Parse(@Nonnull org.jsoup.nodes.Document htmlDocument) { return new Result(htmlDocument); }
-
- public static @Nonnull Result Parse(URI baseURI, String contentType, @Nonnull String content) {
- if (contentType.equals("text/html"))
- {
- var document = Jsoup.parse(content, baseURI.toASCIIString());
- if (document == null)
- {
- log.error("Failed to parse HTML (document == null):\n{}", content);
- throw new IllegalArgumentException("A-Trust parsing failed");
- }
- return Parse(document);
- }
-
- if (contentType.endsWith("/xml"))
- return new Result(content);
-
- log.error("Unknown content-type \"{}\" from URI {}", contentType, baseURI.toString());
- throw new IllegalArgumentException("Unknown A-Trust page reached?");
- }
-}
diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/MobileBKUValidator.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/MobileBKUValidator.java
deleted file mode 100644
index 89dbdf4f..00000000
--- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/bku/mobile/MobileBKUValidator.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2012 by A-SIT, Secure Information Technology Center Austria
- *
- * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
- * the European Commission - subsequent versions of the EUPL (the "Licence");
- * You may not use this work except in compliance with the Licence.
- * You may obtain a copy of the Licence at:
- * http://joinup.ec.europa.eu/software/page/eupl
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the Licence is distributed on an "AS IS" basis,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Licence for the specific language governing permissions and
- * limitations under the Licence.
- */
-package at.asit.pdfover.gui.bku.mobile;
-
-// Imports
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import at.asit.pdfover.gui.exceptions.InvalidPasswordException;
-import at.asit.pdfover.gui.exceptions.PasswordTooLongException;
-import at.asit.pdfover.gui.exceptions.PasswordTooShortException;
-
-/**
- *
- */
-public class MobileBKUValidator {
-
- /**
- * Regular expression for mobile phone numbers: this allows the entry of
- * mobile numbers in the following formats:
- *
- * +(countryCode)99999999999 00(countryCode)99999999999 099999999999
- * 1030199999999999 (A-Trust Test bku)
- */
- private static final String NUMBER_REGEX = "^((\\+[\\d]{2})|(00[\\d]{2})|(0)|(10301))([1-9][\\d]+)$";
-
- /**
- * Validates the Mobile phone number
- *
- * @param number
- * @return the normalized Phone number
- */
- public static String normalizeMobileNumber(String number) {
- // Verify number and normalize
-
- number = number.trim();
-
- String numberWithoutWhitespace = number.replaceAll("\\s","");
- // Compile and use regular expression
- Pattern pattern = Pattern.compile(NUMBER_REGEX);
- Matcher matcher = pattern.matcher(numberWithoutWhitespace);
-
- if (!matcher.find())
- return number; /* might be an idA username, return unchanged */
-
- if (matcher.groupCount() != 6) {
- return number;
- }
-
- String countryCode = matcher.group(1);
-
- String normalNumber = matcher.group(6);
-
- if (countryCode.equals("10301")) {
- // A-Trust Testnumber! Don't change
- return numberWithoutWhitespace;
- }
-
- countryCode = countryCode.replace("00", "+");
-
- if (countryCode.equals("0")) {
- countryCode = "+43";
- }
-
- return countryCode + normalNumber;
- }
-
- /**
- * Validate given Password for Mobile BKU
- *
- * @param password
- * @throws InvalidPasswordException
- */
- public static void validatePassword(String password)
- throws InvalidPasswordException {
- if (password.length() < 5)
- throw new PasswordTooShortException();
- if (password.length() > 200)
- throw new PasswordTooLongException();
- }
-}