-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into feat/oneclick-fullTransaction
- Loading branch information
Showing
11 changed files
with
351 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -337,3 +337,4 @@ coverage/ | |
opencover.xml | ||
|
||
.[Dd][Ss]_[Ss][Tt][Oo][Rr][Ee] | ||
.leu |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
using System; | ||
|
||
|
||
namespace Transbank.Onepay.Exceptions | ||
{ | ||
public class HttpHelperException : TransbankException | ||
{ | ||
public HttpHelperException() : base() | ||
{ | ||
} | ||
|
||
public HttpHelperException(string message) | ||
: base(-1, message) | ||
{ | ||
} | ||
|
||
public HttpHelperException(string message, Exception innerException) | ||
: base(-1, message, innerException) | ||
{ | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
using System; | ||
|
||
|
||
namespace Transbank.Onepay.Exceptions | ||
{ | ||
public class Sigv4UtilException : TransbankException | ||
{ | ||
public Sigv4UtilException() : base() | ||
{ | ||
} | ||
|
||
public Sigv4UtilException(string message) | ||
: base(-1, message) | ||
{ | ||
} | ||
|
||
public Sigv4UtilException(string message, Exception innerException) | ||
: base(-1, message, innerException) | ||
{ | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using MQTTnet; | ||
using MQTTnet.Client; | ||
|
||
|
||
namespace Transbank.Onepay | ||
{ | ||
public interface IOnepayPayment | ||
{ | ||
int Ticket { get; } | ||
int Total { get; } | ||
string ExternalUniqueNumber { get; } | ||
string Occ { get; } | ||
string Ott { get; } | ||
|
||
void Connected(); | ||
void NewMessage(string payload); | ||
void Disconnected(); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
namespace Transbank.Onepay.Model | ||
{ | ||
public class WebsocketMessage | ||
{ | ||
public string status; | ||
public string description; | ||
|
||
public override string ToString() | ||
{ | ||
return "Status: " + status + "\n" + | ||
"Description: " + description; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
namespace Transbank.Onepay.Model | ||
{ | ||
public class WebsocketCredentials | ||
{ | ||
public string iotEndpoint; | ||
public string region; | ||
public string accessKey; | ||
public string secretKey; | ||
public string sessionToken; | ||
|
||
public override string ToString() | ||
{ | ||
return "Endpoint: " + iotEndpoint + "\n" + | ||
"Region: " + region + "\n" + | ||
"Acces Key: " + accessKey + "\n" + | ||
"SecretKey: " + secretKey + "\n" + | ||
"SessionToken: " + sessionToken; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
using System; | ||
using System.Text; | ||
using Transbank.Onepay.Exceptions; | ||
|
||
namespace Transbank.Onepay.Utils | ||
{ | ||
public static class HttpHelper | ||
{ | ||
// The Set of accepted and valid Url characters per RFC3986. Characters outside of this set will be encoded. | ||
const string ValidUrlCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~"; | ||
|
||
public static string UrlEncode(string data, bool isPath = false) | ||
{ | ||
|
||
var encoded = new StringBuilder(data.Length * 2); | ||
|
||
try | ||
{ | ||
string unreservedChars = String.Concat(ValidUrlCharacters, (isPath ? "/:" : "")); | ||
|
||
foreach (char symbol in Encoding.UTF8.GetBytes(data)) | ||
{ | ||
if (unreservedChars.IndexOf(symbol) != -1) | ||
encoded.Append(symbol); | ||
else | ||
encoded.Append("%").Append(String.Format("{0:X2}", (int)symbol)); | ||
} | ||
} | ||
catch (Exception e) | ||
{ | ||
throw new HttpHelperException("Unable to encode URL", e); | ||
} | ||
return encoded.ToString(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
using System; | ||
using System.Security.Cryptography; | ||
using System.Text; | ||
using System.Globalization; | ||
using Transbank.Onepay.Exceptions; | ||
using Transbank.Onepay.Model; | ||
|
||
namespace Transbank.Onepay.Utils | ||
{ | ||
public static class Sigv4util | ||
{ | ||
public const string ISO8601BasicFormat = "yyyyMMddTHHmmssZ"; | ||
public const string DateStringFormat = "yyyyMMdd"; | ||
public const string EmptyBodySha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; | ||
public static HashAlgorithm CanonicalRequestHashAlgorithm = HashAlgorithm.Create("SHA-256"); | ||
public const string HmacSha256 = "HMACSHA256"; | ||
public const string XAmzSignature = "X-Amz-Signature"; | ||
|
||
private static byte[] HmacSHA256(String data, byte[] key) | ||
{ | ||
var algorithm = "HmacSHA256"; | ||
var keyHashAlgorithm = KeyedHashAlgorithm.Create(algorithm); | ||
keyHashAlgorithm.Key = key; | ||
|
||
return keyHashAlgorithm.ComputeHash(Encoding.UTF8.GetBytes(data)); | ||
} | ||
|
||
private static byte[] ComputeKeyedHash(string algorithm, byte[] key, byte[] data) | ||
{ | ||
var kha = KeyedHashAlgorithm.Create(algorithm); | ||
kha.Key = key; | ||
return kha.ComputeHash(data); | ||
} | ||
|
||
public static string ToHexString(byte[] data, bool lowerCase) | ||
{ | ||
var stringBuilder = new StringBuilder(); | ||
|
||
try | ||
{ | ||
for (var i = 0; i < data.Length; i++) | ||
{ | ||
stringBuilder.Append(data[i].ToString(lowerCase ? "x2" : "X2")); | ||
} | ||
|
||
} | ||
catch (Exception e) | ||
{ | ||
throw new Sigv4UtilException("Unable to convert data to hex string", e); | ||
} | ||
return stringBuilder.ToString(); | ||
} | ||
|
||
private static byte[] getSignatureKey(String key, String dateStamp, String regionName, String serviceName) | ||
{ | ||
byte[] kSecret = Encoding.UTF8.GetBytes(("AWS4" + key).ToCharArray()); | ||
byte[] kDate = HmacSHA256(dateStamp, kSecret); | ||
byte[] kRegion = HmacSHA256(regionName, kDate); | ||
byte[] kService = HmacSHA256(serviceName, kRegion); | ||
byte[] kSigning = HmacSHA256("aws4_request", kService); | ||
|
||
return kSigning; | ||
} | ||
|
||
public static string getSignedurl(WebsocketCredentials credentials) | ||
{ | ||
string requestUrl; | ||
try | ||
{ | ||
|
||
var requestDateTime = DateTime.UtcNow; | ||
string datetime = requestDateTime.ToString(ISO8601BasicFormat, CultureInfo.InvariantCulture); | ||
var date = requestDateTime.ToString(DateStringFormat, CultureInfo.InvariantCulture); | ||
|
||
string method = "GET"; | ||
string protocol = "wss"; | ||
string uri = "/mqtt"; | ||
string service = "iotdevicegateway"; | ||
string algorithm = "AWS4-HMAC-SHA256"; | ||
|
||
string credentialScope = date + "/" + credentials.region + "/" + service + "/" + "aws4_request"; | ||
string canonicalQuerystring = "X-Amz-Algorithm=" + algorithm; | ||
canonicalQuerystring += "&X-Amz-Credential=" + HttpHelper.UrlEncode(credentials.accessKey + '/' + credentialScope); | ||
|
||
canonicalQuerystring += "&X-Amz-Date=" + datetime; | ||
canonicalQuerystring += "&X-Amz-Expires=86400"; | ||
canonicalQuerystring += "&X-Amz-SignedHeaders=host"; | ||
|
||
string canonicalHeaders = "host:" + credentials.iotEndpoint + "\n"; | ||
|
||
var canonicalRequest = method + "\n" + uri + "\n" + canonicalQuerystring + "\n" + canonicalHeaders + "\n" + "host" + "\n" + EmptyBodySha256; | ||
|
||
byte[] hashValueCanonicalRequest = CanonicalRequestHashAlgorithm.ComputeHash(Encoding.UTF8.GetBytes(canonicalRequest)); | ||
|
||
var builder = new StringBuilder(); | ||
|
||
for (int i = 0; i < hashValueCanonicalRequest.Length; i++) | ||
{ | ||
builder.Append(hashValueCanonicalRequest[i].ToString("x2")); | ||
} | ||
|
||
string byteString = builder.ToString(); | ||
|
||
var stringToSign = algorithm + "\n" + datetime + "\n" + credentialScope + "\n" + byteString; | ||
|
||
// compute the signing key | ||
var keyedHashAlgorithm = KeyedHashAlgorithm.Create(HmacSha256); | ||
|
||
keyedHashAlgorithm.Key = getSignatureKey(credentials.secretKey, date, credentials.region, service); | ||
|
||
var signingKey = keyedHashAlgorithm.Key; | ||
|
||
var signature = ComputeKeyedHash(HmacSha256, signingKey, Encoding.UTF8.GetBytes(stringToSign)); | ||
var signatureString = ToHexString(signature, true); | ||
|
||
canonicalQuerystring += "&X-Amz-Signature=" + signatureString; | ||
canonicalQuerystring += "&X-Amz-Security-Token=" + HttpHelper.UrlEncode(credentials.sessionToken); | ||
|
||
requestUrl = protocol + "://" + credentials.iotEndpoint + uri + "?" + canonicalQuerystring; | ||
} | ||
|
||
catch (Exception e) | ||
{ | ||
throw new Sigv4UtilException("Unable to get signed url", e); | ||
} | ||
|
||
|
||
return requestUrl; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
using System; | ||
using System.IO; | ||
using System.Net; | ||
using System.Text; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using MQTTnet; | ||
using MQTTnet.Client; | ||
using MQTTnet.Client.Options; | ||
using Newtonsoft.Json; | ||
using Transbank.Onepay.Model; | ||
using Transbank.Onepay.Utils; | ||
|
||
namespace Transbank.Onepay | ||
{ | ||
public class Websocket | ||
{ | ||
private static readonly string OnepayIotEndpoint = "https://qml1wjqokl.execute-api.us-east-1.amazonaws.com/prod/onepayjs/auth/keys"; | ||
internal WebsocketCredentials Credentials; | ||
|
||
public IMqttClient mqttClient; | ||
public IMqttClientOptions mqttClientOptions; | ||
|
||
public Websocket() | ||
{ | ||
Credentials = FetchCredentials(); | ||
|
||
string requestUrl = Sigv4util.getSignedurl(Credentials); | ||
|
||
var factory = new MqttFactory(); | ||
mqttClient = factory.CreateMqttClient(); | ||
|
||
mqttClientOptions = new MqttClientOptionsBuilder(). | ||
WithWebSocketServer(requestUrl). | ||
WithKeepAlivePeriod(TimeSpan.FromMinutes(10)).Build(); | ||
|
||
} | ||
|
||
public async Task ConnectAsync(IOnepayPayment obj) | ||
{ | ||
mqttClient.UseConnectedHandler(e => { | ||
obj.Connected(); | ||
}); | ||
|
||
mqttClient.UseApplicationMessageReceivedHandler(e => { | ||
obj.NewMessage(Encoding.UTF8.GetString(e.ApplicationMessage.Payload)); | ||
}); | ||
|
||
mqttClient.UseDisconnectedHandler(e => { | ||
obj.Disconnected(); | ||
}); | ||
|
||
_ = await mqttClient.ConnectAsync(mqttClientOptions, CancellationToken.None); | ||
_ = await mqttClient.SubscribeAsync(new TopicFilterBuilder().WithTopic(obj.Ott).Build()); | ||
} | ||
|
||
private WebsocketCredentials FetchCredentials() | ||
{ | ||
var request = (HttpWebRequest)WebRequest.Create(OnepayIotEndpoint); | ||
|
||
var responseStream = request.GetResponse().GetResponseStream(); | ||
var streamReader = new StreamReader(responseStream); | ||
var credentialsAsJson = streamReader.ReadToEnd(); | ||
return JsonConvert.DeserializeObject<WebsocketCredentials>(credentialsAsJson); | ||
} | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters