Skip to content

Commit 0bfe327

Browse files
authored
Merge pull request #17 from bunq/feature/psd2_example
Added PSD2 examples
2 parents f618989 + b70ac54 commit 0bfe327

File tree

8 files changed

+305
-5
lines changed

8 files changed

+305
-5
lines changed

build.gradle

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ dependencies {
1414
testCompile group: 'junit', name: 'junit', version: '4.12'
1515
// https://mvnrepository.com/artifact/commons-cli/commons-cli
1616
compile group: 'commons-cli', name: 'commons-cli', version: '1.2'
17-
compile 'com.github.bunq:sdk_java:1.10.+'
17+
compile 'com.github.bunq:sdk_java:1.12.+'
18+
}
19+
20+
compileJava {
21+
options.compilerArgs << '-Xlint:unchecked'
1822
}
1923

2024
jar {

go-tinker

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,28 @@ USAGE="\
1919
┌───────────────────────┬─────────────────────────────────────────────────┐
2020
│ │ Run │
2121
├───────────────────────┼─────────────────────────────────────────────────┤
22+
│ 🔐 Create PSD2 Provider! │ ${ANSI_FORMAT_VERBOSE}java -jar tinker/tinker.jar CreatePsd2Configuration${ANSI_FORMAT_CLEAR}
23+
│ │ │
24+
│ │ ${ANSI_FORMAT_DIM}Required parameters:${ANSI_FORMAT_CLEAR}
25+
│ │ ${ANSI_FORMAT_DIM}--env [SANDBOX/PRODUCTION]${ANSI_FORMAT_CLEAR}
26+
│ │ ${ANSI_FORMAT_DIM}--certificate [path]${ANSI_FORMAT_CLEAR}
27+
│ │ ${ANSI_FORMAT_DIM}--chain [path]${ANSI_FORMAT_CLEAR}
28+
│ │ ${ANSI_FORMAT_DIM}--key [path]${ANSI_FORMAT_CLEAR}
29+
├───────────────────────┼─────────────────────────────────────────────────┤
30+
│ 🔒 Create PSD2 OAuth Client │ ${ANSI_FORMAT_VERBOSE}java -jar tinker/tinker.jar CreateOauthClient${ANSI_FORMAT_CLEAR}
31+
│ │ │
32+
│ │ ${ANSI_FORMAT_DIM}Required parameters:${ANSI_FORMAT_CLEAR}
33+
│ │ ${ANSI_FORMAT_DIM}--context [path]${ANSI_FORMAT_CLEAR}
34+
│ │ ${ANSI_FORMAT_DIM}--redirect [uri]${ANSI_FORMAT_CLEAR}
35+
├───────────────────────┼─────────────────────────────────────────────────┤
36+
│ 🔓 Test PSD2 OAuth │ ${ANSI_FORMAT_VERBOSE}java -jar tinker/tinker.jar TestOauth${ANSI_FORMAT_CLEAR}
37+
│ │ │
38+
│ │ ${ANSI_FORMAT_DIM}Required parameters:${ANSI_FORMAT_CLEAR}
39+
│ │ ${ANSI_FORMAT_DIM}--env [SANDBOX/PRODUCTION]${ANSI_FORMAT_CLEAR}
40+
│ │ ${ANSI_FORMAT_DIM}--code [authcode]${ANSI_FORMAT_CLEAR}
41+
│ │ ${ANSI_FORMAT_DIM}--configuration [path]${ANSI_FORMAT_CLEAR}
42+
│ │ ${ANSI_FORMAT_DIM}--redirect [uri]${ANSI_FORMAT_CLEAR}
43+
├───────────────────────┼─────────────────────────────────────────────────┤
2244
│ ✅ Show Overview │ ${ANSI_FORMAT_VERBOSE}java -jar tinker/tinker.jar UserOverview${ANSI_FORMAT_CLEAR}
2345
├───────────────────────┼─────────────────────────────────────────────────┤
2446
│ 🔼 Make a payment │ ${ANSI_FORMAT_VERBOSE}java -jar tinker/tinker.jar MakePayment${ANSI_FORMAT_CLEAR}

gradlew

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ APP_NAME="Gradle"
2828
APP_BASE_NAME=`basename "$0"`
2929

3030
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31-
DEFAULT_JVM_OPTS=""
31+
DEFAULT_JVM_OPTS='"-Xmx64m"'
3232

3333
# Use the maximum available, or set MAX_FD != -1 to use that value.
3434
MAX_FD="maximum"

gradlew.bat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ set APP_BASE_NAME=%~n0
1414
set APP_HOME=%DIRNAME%
1515

1616
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17-
set DEFAULT_JVM_OPTS=
17+
set DEFAULT_JVM_OPTS="-Xmx64m"
1818

1919
@rem Find java.exe
2020
if defined JAVA_HOME goto findJavaFromJavaHome
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package com.bunq.tinker;
2+
3+
import com.bunq.sdk.context.ApiContext;
4+
import com.bunq.sdk.context.ApiEnvironmentType;
5+
import com.bunq.sdk.context.BunqContext;
6+
import com.bunq.sdk.exception.BunqException;
7+
import com.bunq.sdk.json.BunqGsonBuilder;
8+
import com.bunq.sdk.model.core.OauthAuthorizationUri;
9+
import com.bunq.sdk.model.core.OauthResponseType;
10+
import com.bunq.sdk.model.generated.endpoint.OauthCallbackUrl;
11+
import com.bunq.sdk.model.generated.endpoint.OauthClient;
12+
import com.bunq.sdk.model.generated.object.Certificate;
13+
import com.bunq.sdk.security.SecurityUtils;
14+
import com.bunq.tinker.utils.ITinker;
15+
import com.google.gson.stream.JsonReader;
16+
import org.apache.commons.cli.*;
17+
18+
import java.io.*;
19+
import java.nio.file.Files;
20+
import java.util.ArrayList;
21+
22+
public class CreateOauthClient implements ITinker {
23+
/**
24+
* API constants.
25+
*/
26+
protected static final String OPTION_CONTEXT = "context";
27+
protected static final String OPTION_REDIRECT_URI = "redirect";
28+
29+
/**
30+
* File constants.
31+
*/
32+
protected static final String FILE_OAUTH_CONFIGURATION = "oauth.conf";
33+
34+
/**
35+
* Error constants.
36+
*/
37+
protected static final String ERROR_MISSING_MANDATORY_OPTION = "Missing mandatory option.";
38+
39+
@Override
40+
public void run(String[] args) throws Exception {
41+
Options options = new Options();
42+
options.addOption(new Option("", OPTION_CONTEXT, true, ""));
43+
options.addOption(new Option("", OPTION_REDIRECT_URI, true, ""));
44+
45+
CommandLineParser parser = new BasicParser();
46+
CommandLine allOption = parser.parse(options, args);
47+
48+
assertMandatoryOptions(allOption);
49+
50+
BunqContext.loadApiContext(
51+
ApiContext.restore(allOption.getOptionValue(OPTION_CONTEXT))
52+
);
53+
54+
OauthClient oauthClient;
55+
File oauthFile = new File(FILE_OAUTH_CONFIGURATION);
56+
if (oauthFile.exists()) {
57+
oauthClient = createOauthClientFromFile(oauthFile.getPath());
58+
} else {
59+
Integer oauthClientId = OauthClient.create().getValue();
60+
61+
OauthCallbackUrl.create(oauthClientId, allOption.getOptionValue(OPTION_REDIRECT_URI));
62+
oauthClient = OauthClient.get(oauthClientId).getValue();
63+
64+
String serializedClient = BunqGsonBuilder.buildDefault().create().toJson(oauthClient);
65+
FileWriter fileWriter = new FileWriter(FILE_OAUTH_CONFIGURATION);
66+
67+
fileWriter.write(serializedClient);
68+
fileWriter.close();
69+
}
70+
71+
OauthAuthorizationUri authorizationUri = OauthAuthorizationUri.create(
72+
OauthResponseType.CODE,
73+
allOption.getOptionValue(OPTION_REDIRECT_URI),
74+
oauthClient
75+
);
76+
77+
System.out.println(" | Created OAuth client!");
78+
System.out.println(" | Point your user to the following URL to obtain an auth code:");
79+
System.out.println(" | " + authorizationUri.getAuthorizationUri());
80+
}
81+
82+
/**
83+
*/
84+
private void assertMandatoryOptions(CommandLine allOption)
85+
{
86+
if (allOption.hasOption(OPTION_CONTEXT) &&
87+
allOption.hasOption(OPTION_REDIRECT_URI)) {
88+
return;
89+
}
90+
throw new BunqException(ERROR_MISSING_MANDATORY_OPTION);
91+
}
92+
93+
94+
private OauthClient createOauthClientFromFile(String path) throws IOException
95+
{
96+
return OauthClient.fromJsonReader(
97+
new JsonReader(new InputStreamReader(new FileInputStream(path)))
98+
);
99+
}
100+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package com.bunq.tinker;
2+
3+
import com.bunq.sdk.context.ApiContext;
4+
import com.bunq.sdk.context.ApiEnvironmentType;
5+
import com.bunq.sdk.exception.BunqException;
6+
import com.bunq.sdk.model.generated.object.Certificate;
7+
import com.bunq.sdk.security.SecurityUtils;
8+
import com.bunq.tinker.libs.SharedLib;
9+
import com.bunq.tinker.utils.ITinker;
10+
import org.apache.commons.cli.*;
11+
12+
import java.util.ArrayList;
13+
14+
public class CreatePsd2Configuration implements ITinker {
15+
/**
16+
* API constants.
17+
*/
18+
protected static final String API_DEVICE_DESCRIPTION = "##### YOUR DEVICE DESCRIPTION #####";
19+
20+
/**
21+
* Option constants.
22+
*/
23+
protected static final String OPTION_ENVIRONMENT = "env";
24+
protected static final String OPTION_CERTIFICATE = "certificate";
25+
protected static final String OPTION_CERTIFICATE_CHAIN = "chain";
26+
protected static final String OPTION_PRIVATE_KEY = "key";
27+
28+
/**
29+
* File constants.
30+
*/
31+
protected static final String FILE_CONTEXT = "bunq-psd2.conf";
32+
33+
/**
34+
* Error constants.
35+
*/
36+
protected static final String ERROR_MISSING_MANDATORY_OPTION = "Missing mandatory option.";
37+
38+
@Override
39+
public void run(String[] args) throws Exception {
40+
41+
Options options = new Options();
42+
options.addOption(new Option("", OPTION_CERTIFICATE, true, ""));
43+
options.addOption(new Option("", OPTION_CERTIFICATE_CHAIN, true, ""));
44+
options.addOption(new Option("", OPTION_PRIVATE_KEY, true, ""));
45+
46+
CommandLineParser parser = new BasicParser();
47+
CommandLine allOption = parser.parse(options, args);
48+
49+
assertMandatoryOptions(allOption);
50+
51+
ApiContext apiContext = ApiContext.createForPsd2(
52+
SharedLib.determineEnvironmentType(allOption),
53+
SecurityUtils.getCertificateFromFile(allOption.getOptionValue(OPTION_CERTIFICATE)),
54+
SecurityUtils.getPrivateKeyFromFile(allOption.getOptionValue(OPTION_PRIVATE_KEY)),
55+
new Certificate[]{
56+
SecurityUtils.getCertificateFromFile(allOption.getOptionValue(OPTION_CERTIFICATE_CHAIN))
57+
},
58+
API_DEVICE_DESCRIPTION,
59+
new ArrayList<String>()
60+
);
61+
62+
apiContext.save(FILE_CONTEXT);
63+
64+
System.out.println(" | PSD2 configuration created. Saved as bunq-psd.conf!");
65+
}
66+
67+
/**
68+
*/
69+
private void assertMandatoryOptions(CommandLine allOption)
70+
{
71+
if (allOption.hasOption(OPTION_CERTIFICATE) &&
72+
allOption.hasOption(OPTION_CERTIFICATE_CHAIN) &&
73+
allOption.hasOption(OPTION_PRIVATE_KEY)) {
74+
return;
75+
}
76+
throw new BunqException(ERROR_MISSING_MANDATORY_OPTION);
77+
}
78+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package com.bunq.tinker;
2+
3+
import com.bunq.sdk.context.ApiContext;
4+
import com.bunq.sdk.context.ApiEnvironmentType;
5+
import com.bunq.sdk.context.BunqContext;
6+
import com.bunq.sdk.exception.BunqException;
7+
import com.bunq.sdk.model.core.OauthAccessToken;
8+
import com.bunq.sdk.model.core.OauthGrantType;
9+
import com.bunq.sdk.model.generated.endpoint.OauthClient;
10+
import com.bunq.tinker.libs.SharedLib;
11+
import com.bunq.tinker.utils.ITinker;
12+
import com.google.gson.stream.JsonReader;
13+
import org.apache.commons.cli.*;
14+
15+
import java.io.FileInputStream;
16+
import java.io.IOException;
17+
import java.io.InputStreamReader;
18+
19+
public class TestOauth implements ITinker {
20+
/**
21+
* Option constants.
22+
*/
23+
private static final String OPTION_AUTH_CODE = "code";
24+
private static final String OPTION_CLIENT_CONFIGURATION = "configuration";
25+
private static final String OPTION_REDIRECT = "redirect";
26+
27+
/**
28+
* API constants.
29+
*/
30+
protected static final String API_DEVICE_DESCRIPTION = "##### YOUR DEVICE DESCRIPTION #####";
31+
32+
/**
33+
* Error constants.
34+
*/
35+
protected static final String ERROR_MISSING_MANDATORY_OPTION = "Missing mandatory option.";
36+
37+
@Override
38+
public void run(String[] args) throws Exception {
39+
Options options = new Options();
40+
options.addOption(new Option("", OPTION_AUTH_CODE, true, ""));
41+
options.addOption(new Option("", OPTION_CLIENT_CONFIGURATION, true, ""));
42+
options.addOption(new Option("", OPTION_REDIRECT, true, ""));
43+
44+
CommandLineParser parser = new BasicParser();
45+
CommandLine allOption = parser.parse(options, args);
46+
47+
assertMandatoryOptions(allOption);
48+
49+
OauthAccessToken accessToken = OauthAccessToken.create(
50+
OauthGrantType.AUTHORIZATION_CODE,
51+
allOption.getOptionValue(OPTION_AUTH_CODE),
52+
allOption.getOptionValue(OPTION_REDIRECT),
53+
createOauthClientFromFile(allOption.getOptionValue(OPTION_CLIENT_CONFIGURATION))
54+
);
55+
56+
ApiContext apiContext = createApiContextByOauthToken(
57+
accessToken,
58+
SharedLib.determineEnvironmentType(allOption)
59+
);
60+
BunqContext.loadApiContext(apiContext);
61+
62+
(new UserOverview()).run(new String[]{});
63+
}
64+
65+
/**
66+
*/
67+
private void assertMandatoryOptions(CommandLine allOption)
68+
{
69+
if (allOption.hasOption(OPTION_CLIENT_CONFIGURATION) &&
70+
allOption.hasOption(OPTION_REDIRECT) &&
71+
allOption.hasOption(OPTION_AUTH_CODE)) {
72+
return;
73+
}
74+
throw new BunqException(ERROR_MISSING_MANDATORY_OPTION);
75+
}
76+
77+
private OauthClient createOauthClientFromFile(String path) throws IOException
78+
{
79+
return OauthClient.fromJsonReader(
80+
new JsonReader(new InputStreamReader(new FileInputStream(path)))
81+
);
82+
}
83+
84+
private static ApiContext createApiContextByOauthToken(OauthAccessToken token, ApiEnvironmentType environmentType)
85+
{
86+
return ApiContext.create(
87+
environmentType,
88+
token.getToken(),
89+
API_DEVICE_DESCRIPTION
90+
);
91+
}
92+
}

src/main/java/com/bunq/tinker/utils/TinkerRunner.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@ public static void main(String[] args) throws Exception {
1616

1717
String className = args[0];
1818
Class classObject = Class.forName(PACKAGE_TINKER_PREFIX + className);
19-
ITinker tinker = (ITinker) classObject.newInstance();
2019

21-
tinker.run(args);
20+
try {
21+
ITinker tinker = (ITinker) classObject.getConstructor().newInstance();
22+
tinker.run(args);
23+
} catch (NoSuchMethodException exception) {
24+
System.out.println("Couldn\'t start " + className + ". Class is missing or invalid.");
25+
}
2226
}
2327
}

0 commit comments

Comments
 (0)