diff --git a/TinkerSrc/CreateOauthClient.cs b/TinkerSrc/CreateOauthClient.cs new file mode 100644 index 0000000..f9db12f --- /dev/null +++ b/TinkerSrc/CreateOauthClient.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Bunq.Sdk.Context; +using Bunq.Sdk.Exception; +using Bunq.Sdk.Json; +using Bunq.Sdk.Model.Core; +using Bunq.Sdk.Model.Generated.Endpoint; +using Mono.Options; +using Tinker.Utils; + +namespace TinkerSrc +{ + public class CreateOauthClient : ITinker + { + /// + /// API constants. + /// + protected const string OPTION_CONTEXT = "context="; + protected const string OPTION_REDIRECT_URI = "redirect="; + + /** + * File constants. + */ + protected const string FILE_OAUTH_CONFIGURATION = "oauth.conf"; + + /** + * Error constants. + */ + protected const string ERROR_MISSING_MANDATORY_OPTION = "Missing mandatory option."; + + public void Run(string[] args) + { + Dictionary allOption = AssertMandatoryOptions(args); + + BunqContext.LoadApiContext( + ApiContext.Restore(allOption[OPTION_CONTEXT]) + ); + + OauthClient oauthClient; + if (File.Exists(FILE_OAUTH_CONFIGURATION)) + { + oauthClient = OauthClient.CreateFromJsonString(File.ReadAllText(FILE_OAUTH_CONFIGURATION)); + } + else + { + int oauthClientId = OauthClient.Create().Value; + + OauthCallbackUrl.Create(oauthClientId, allOption[OPTION_REDIRECT_URI]); + oauthClient = OauthClient.Get(oauthClientId).Value; + + String serializedClient = BunqJsonConvert.SerializeObject(oauthClient); + File.WriteAllText(FILE_OAUTH_CONFIGURATION, serializedClient); + } + + OauthAuthorizationUri authorizationUri = OauthAuthorizationUri.Create( + OauthResponseType.CODE, + allOption[OPTION_REDIRECT_URI], + oauthClient + ); + + Console.WriteLine(" | Created oauth client. Stored in {0}.", FILE_OAUTH_CONFIGURATION); + Console.WriteLine(" | Point your user to {0} to obtain an Authorization code.", authorizationUri.AuthorizationUri); + } + + private Dictionary AssertMandatoryOptions(string[] allArgument) + { + Dictionary allOption = new Dictionary(); + + new OptionSet + { + {OPTION_CONTEXT, value => allOption.Add(OPTION_CONTEXT, value)}, + {OPTION_REDIRECT_URI, value => allOption.Add(OPTION_REDIRECT_URI, value)} + }.Parse(allArgument); + + if (allOption[OPTION_CONTEXT] != null && + allOption[OPTION_REDIRECT_URI] != null) { + return allOption; + } + + throw new BunqException(ERROR_MISSING_MANDATORY_OPTION); + } + } +} \ No newline at end of file diff --git a/TinkerSrc/CreatePsd2Configuration.cs b/TinkerSrc/CreatePsd2Configuration.cs new file mode 100644 index 0000000..a46022d --- /dev/null +++ b/TinkerSrc/CreatePsd2Configuration.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Security.Cryptography.X509Certificates; +using Bunq.Sdk.Context; +using Bunq.Sdk.Exception; +using Bunq.Sdk.Model.Generated.Object; +using Bunq.Sdk.Security; +using Mono.Options; +using Tinker.Utils; +using TinkerSrc.Lib; + +namespace TinkerSrc +{ + public class CreatePsd2Configuration : ITinker + { + /// + /// API constants. + /// + protected const string API_DEVICE_DESCRIPTION = "##### YOUR DEVICE DESCRIPTION #####"; + + /// + /// Option constants. + /// + protected const string OPTION_CREDENTIALS = "credentials="; + protected const string OPTION_CERTIFICATE_CHAIN = "chain="; + protected const string OPTION_PASSPHRASE = "pass="; + + /// + /// Error constants. + /// + protected const string ERROR_MISSING_MANDATORY_OPTION = "Missing mandatory option."; + + /// + /// File constants. + /// + protected const string FILE_CONTEXT = "bunq-psd2.conf"; + + public void Run(string[] args) + { + Dictionary allOption = AssertMandatoryOptions(args); + + ApiContext apiContext = ApiContext.CreateForPsd2( + ShareLib.DetermineEnvironmentType(args), + SecurityUtils.GetCertificateFromFile(allOption[OPTION_CREDENTIALS], allOption[OPTION_PASSPHRASE]), + new X509CertificateCollection () { + SecurityUtils.GetCertificateFromFile(allOption[OPTION_CERTIFICATE_CHAIN]) + }, + API_DEVICE_DESCRIPTION, + new List() + ); + + apiContext.Save(FILE_CONTEXT); + } + + private Dictionary AssertMandatoryOptions(string[] allArgument) + { + Dictionary allOption = new Dictionary(); + + new OptionSet + { + {OPTION_CREDENTIALS, value => allOption.Add(OPTION_CREDENTIALS, value)}, + {OPTION_CERTIFICATE_CHAIN, value => allOption.Add(OPTION_CERTIFICATE_CHAIN, value)}, + {OPTION_PASSPHRASE, value => allOption.Add(OPTION_PASSPHRASE, value)} + }.Parse(allArgument); + + if (allOption[OPTION_CERTIFICATE_CHAIN] != null && + allOption[OPTION_CREDENTIALS] != null && + allOption[OPTION_PASSPHRASE] != null) { + return allOption; + } + + throw new BunqException(ERROR_MISSING_MANDATORY_OPTION); + } + } +} \ No newline at end of file diff --git a/TinkerSrc/TestOauth.cs b/TinkerSrc/TestOauth.cs new file mode 100644 index 0000000..414cd66 --- /dev/null +++ b/TinkerSrc/TestOauth.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using Bunq.Sdk.Context; +using Bunq.Sdk.Exception; +using Bunq.Sdk.Model.Core; +using Bunq.Sdk.Model.Generated.Endpoint; +using Mono.Options; +using Tinker.Utils; +using TinkerSrc.Lib; + +namespace TinkerSrc +{ + public class TestOauth : ITinker + { + /// + /// Option constants. + /// + protected const string OPTION_AUTH_CODE = "code="; + protected const string OPTION_CLIENT_CONFIGURATION = "configuration="; + protected const string OPTION_REDIRECT = "redirect="; + protected const string OPTION_CONTEXT = "context="; + + /// + /// API constants. + /// + protected const string API_DEVICE_DESCRIPTION = "##### YOUR DEVICE DESCRIPTION #####"; + + /// + /// Error constants. + /// + protected const string ERROR_MISSING_MANDATORY_OPTION = "Missing mandatory option."; + + public void Run(string[] args) + { + Dictionary allOption = AssertMandatoryOptions(args); + + ApiContext apiContext = ApiContext.Restore(allOption[OPTION_CONTEXT]); + BunqContext.LoadApiContext(apiContext); + + OauthAccessToken accessToken = OauthAccessToken.Create( + OauthGrantType.AUTHORIZATION_CODE, + allOption[OPTION_AUTH_CODE], + allOption[OPTION_REDIRECT], + CreateOauthClientFromFile(allOption[OPTION_CLIENT_CONFIGURATION]) + ); + + apiContext = CreateApiContextByOauthToken( + accessToken, + ShareLib.DetermineEnvironmentType(args) + ); + BunqContext.LoadApiContext(apiContext); + + (new UserOverview()).Run(new String[]{}); + } + + + private Dictionary AssertMandatoryOptions(string[] allArgument) + { + Dictionary allOption = new Dictionary(); + + new OptionSet + { + {OPTION_AUTH_CODE, value => allOption.Add(OPTION_AUTH_CODE, value)}, + {OPTION_REDIRECT, value => allOption.Add(OPTION_REDIRECT, value)}, + {OPTION_CONTEXT, value => allOption.Add(OPTION_CONTEXT, value)}, + {OPTION_CLIENT_CONFIGURATION, value => allOption.Add(OPTION_CLIENT_CONFIGURATION, value)} + }.Parse(allArgument); + + if (allOption[OPTION_AUTH_CODE] != null && + allOption[OPTION_REDIRECT] != null && + allOption[OPTION_CONTEXT] != null && + allOption[OPTION_CLIENT_CONFIGURATION] != null) { + return allOption; + } + + throw new BunqException(ERROR_MISSING_MANDATORY_OPTION); + } + + private OauthClient CreateOauthClientFromFile(String path) + { + return OauthClient.CreateFromJsonString( + File.ReadAllText(path) + ); + } + + private static ApiContext CreateApiContextByOauthToken(OauthAccessToken token, ApiEnvironmentType environmentType) + { + return ApiContext.Create( + environmentType, + token.Token, + API_DEVICE_DESCRIPTION + ); + } + } +} \ No newline at end of file diff --git a/TinkerSrc/TinkerSrc.csproj b/TinkerSrc/TinkerSrc.csproj index 449b4ad..4717a59 100755 --- a/TinkerSrc/TinkerSrc.csproj +++ b/TinkerSrc/TinkerSrc.csproj @@ -1,10 +1,10 @@  Exe - netcoreapp1.1 + netcoreapp2.2 - + \ No newline at end of file diff --git a/go-pro b/go-pro index 215811a..0fc4d9e 100755 --- a/go-pro +++ b/go-pro @@ -22,6 +22,28 @@ USAGE="\ ┌───────────────────────┬────────────────────────────────────────────────────────────┐ │ │ Run │ ├───────────────────────┼────────────────────────────────────────────────────────────┤ + │ 🔐 Create PSD2 Provider! │ ${ANSI_FORMAT_VERBOSE}dotnet Tinker/TinkerSrc.dll CreatePsd2Configuration${ANSI_FORMAT_CLEAR} │ + │ │ │ + │ │ ${ANSI_FORMAT_DIM}Required parameters:${ANSI_FORMAT_CLEAR} │ + │ │ ${ANSI_FORMAT_DIM}--env [SANDBOX/PRODUCTION]${ANSI_FORMAT_CLEAR} │ + │ │ ${ANSI_FORMAT_DIM}--certificate [path]${ANSI_FORMAT_CLEAR} │ + │ │ ${ANSI_FORMAT_DIM}--chain [path]${ANSI_FORMAT_CLEAR} │ + │ │ ${ANSI_FORMAT_DIM}--key [path]${ANSI_FORMAT_CLEAR} │ + ├───────────────────────┼────────────────────────────────────────────────────────────┤ + │ 🔒 Create PSD2 OAuth Client │ ${ANSI_FORMAT_VERBOSE}dotnet Tinker/TinkerSrc.dll CreateOauthClient${ANSI_FORMAT_CLEAR} │ + │ │ │ + │ │ ${ANSI_FORMAT_DIM}Required parameters:${ANSI_FORMAT_CLEAR} │ + │ │ ${ANSI_FORMAT_DIM}--context [path]${ANSI_FORMAT_CLEAR} │ + │ │ ${ANSI_FORMAT_DIM}--redirect [uri]${ANSI_FORMAT_CLEAR} │ + ├───────────────────────┼────────────────────────────────────────────────────────────┤ + │ 🔓 Test PSD2 OAuth │ ${ANSI_FORMAT_VERBOSE}dotnet Tinker/TinkerSrc.dll TestOauth${ANSI_FORMAT_CLEAR} │ + │ │ │ + │ │ ${ANSI_FORMAT_DIM}Required parameters:${ANSI_FORMAT_CLEAR} │ + │ │ ${ANSI_FORMAT_DIM}--env [SANDBOX/PRODUCTION]${ANSI_FORMAT_CLEAR} │ + │ │ ${ANSI_FORMAT_DIM}--code [authcode]${ANSI_FORMAT_CLEAR} │ + │ │ ${ANSI_FORMAT_DIM}--configuration [path]${ANSI_FORMAT_CLEAR} │ + │ │ ${ANSI_FORMAT_DIM}--redirect [uri]${ANSI_FORMAT_CLEAR} │ + |───────────────────────┼────────────────────────────────────────────────────────────┤ │ ✅ Show Overview │ ${ANSI_FORMAT_VERBOSE}dotnet Tinker/TinkerSrc.dll UserOverview --production${ANSI_FORMAT_CLEAR} │ ├───────────────────────┼────────────────────────────────────────────────────────────┤ │ 🔼 Make a payment │ ${ANSI_FORMAT_VERBOSE}dotnet Tinker/TinkerSrc.dll MakePayment --production${ANSI_FORMAT_CLEAR} │ diff --git a/go-tinker b/go-tinker index 4c28189..6804b87 100755 --- a/go-tinker +++ b/go-tinker @@ -19,6 +19,28 @@ USAGE="\ ┌───────────────────────┬──────────────────────────────────────────────┐ │ │ Run │ ├───────────────────────┼──────────────────────────────────────────────┤ + │ 🔐 Create PSD2 Provider! │ ${ANSI_FORMAT_VERBOSE}dotnet Tinker/TinkerSrc.dll CreatePsd2Configuration${ANSI_FORMAT_CLEAR} │ + │ │ │ + │ │ ${ANSI_FORMAT_DIM}Required parameters:${ANSI_FORMAT_CLEAR} │ + │ │ ${ANSI_FORMAT_DIM}--env [SANDBOX/PRODUCTION]${ANSI_FORMAT_CLEAR} │ + │ │ ${ANSI_FORMAT_DIM}--certificate [path]${ANSI_FORMAT_CLEAR} │ + │ │ ${ANSI_FORMAT_DIM}--chain [path]${ANSI_FORMAT_CLEAR} │ + │ │ ${ANSI_FORMAT_DIM}--key [path]${ANSI_FORMAT_CLEAR} │ + ├───────────────────────┼──────────────────────────────────────────────┤ + │ 🔒 Create PSD2 OAuth Client │ ${ANSI_FORMAT_VERBOSE}dotnet Tinker/TinkerSrc.dll CreateOauthClient${ANSI_FORMAT_CLEAR} │ + │ │ │ + │ │ ${ANSI_FORMAT_DIM}Required parameters:${ANSI_FORMAT_CLEAR} │ + │ │ ${ANSI_FORMAT_DIM}--context [path]${ANSI_FORMAT_CLEAR} │ + │ │ ${ANSI_FORMAT_DIM}--redirect [uri]${ANSI_FORMAT_CLEAR} │ + ├───────────────────────┼──────────────────────────────────────────────┤ + │ 🔓 Test PSD2 OAuth │ ${ANSI_FORMAT_VERBOSE}dotnet Tinker/TinkerSrc.dll TestOauth${ANSI_FORMAT_CLEAR} │ + │ │ │ + │ │ ${ANSI_FORMAT_DIM}Required parameters:${ANSI_FORMAT_CLEAR} │ + │ │ ${ANSI_FORMAT_DIM}--env [SANDBOX/PRODUCTION]${ANSI_FORMAT_CLEAR} │ + │ │ ${ANSI_FORMAT_DIM}--code [authcode]${ANSI_FORMAT_CLEAR} │ + │ │ ${ANSI_FORMAT_DIM}--configuration [path]${ANSI_FORMAT_CLEAR} │ + │ │ ${ANSI_FORMAT_DIM}--redirect [uri]${ANSI_FORMAT_CLEAR} │ + ├───────────────────────┼──────────────────────────────────────────────┤ │ ✅ Show Overview │ ${ANSI_FORMAT_VERBOSE}dotnet Tinker/TinkerSrc.dll UserOverview${ANSI_FORMAT_CLEAR} │ ├───────────────────────┼──────────────────────────────────────────────┤ │ 🔼 Make a payment │ ${ANSI_FORMAT_VERBOSE}dotnet Tinker/TinkerSrc.dll MakePayment${ANSI_FORMAT_CLEAR} │