Skip to content

Commit

Permalink
Mergeing with master
Browse files Browse the repository at this point in the history
  • Loading branch information
slorello89 committed Oct 14, 2019
2 parents c8a517f + 629e5e7 commit dce8d83
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 15 deletions.
57 changes: 57 additions & 0 deletions Nexmo.Api/Cryptography/SmsSignatureGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using Nexmo.Api.Request;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Nexmo.Api.Cryptography
{
public class SmsSignatureGenerator
{
public enum Method
{
md5hash,
md5,
sha1,
sha256,
sha512
}
public static string GenerateSignature(string query, string securitySecret, Method method)
{
// security secret provided, sort and sign request
if (method == Method.md5hash)
{
query += securitySecret;
var hashgen = MD5.Create();
var hash = hashgen.ComputeHash(Encoding.UTF8.GetBytes(query));
return ByteArrayToHexHelper.ByteArrayToHex(hash).ToLower();
}
else
{
var securityBytes = Encoding.UTF8.GetBytes(securitySecret);
var input = Encoding.UTF8.GetBytes(query);
HMAC hmacGen = new HMACMD5(securityBytes);
switch (method)
{
case Method.md5:
hmacGen = new HMACMD5(securityBytes);
break;
case Method.sha1:
hmacGen = new HMACSHA1(securityBytes);
break;
case Method.sha256:
hmacGen = new HMACSHA256(securityBytes);
break;
case Method.sha512:
hmacGen = new HMACSHA512(securityBytes);
break;
}
var hmac = hmacGen.ComputeHash(input);
var sig = ByteArrayToHexHelper.ByteArrayToHex(hmac).ToUpper();
return sig;
}
}
}
}
2 changes: 1 addition & 1 deletion Nexmo.Api/Nexmo.Api.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Official C#/.NET wrapper for the Nexmo API</description>
<releaseNotes>
* Harmonizing dependencies
* Adding type safety for NCCOs and webhook events
</releaseNotes>
<copyright>© Nexmo 2018</copyright>
<tags>SMS voice telephony phone nexmo</tags>
Expand Down
4 changes: 2 additions & 2 deletions Nexmo.Api/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("4.1.1.0")]
[assembly: AssemblyFileVersion("4.1.1.0")]
[assembly: AssemblyVersion("4.1.2.0")]
[assembly: AssemblyFileVersion("4.1.2.0")]
40 changes: 30 additions & 10 deletions Nexmo.Api/Request/ApiRequest.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
using Newtonsoft.Json;
using Nexmo.Api.Cryptography;
using Nexmo.Api.Logging;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Text;
using Newtonsoft.Json;
using System.Net.Http;
using System.Security.Cryptography;
using Nexmo.Api.Logging;

namespace Nexmo.Api.Request
{
Expand All @@ -26,15 +26,36 @@ private static StringBuilder BuildQueryString(IDictionary<string, string> parame
var apiKey = (creds?.ApiKey ?? Configuration.Instance.Settings["appSettings:Nexmo.api_key"]).ToLower();
var apiSecret = creds?.ApiSecret ?? Configuration.Instance.Settings["appSettings:Nexmo.api_secret"];
var securitySecret = creds?.SecuritySecret ?? Configuration.Instance.Settings["appSettings:Nexmo.security_secret"];
SmsSignatureGenerator.Method method;
if (creds?.Method != null)
{
method = creds.Method;
}
else if(Enum.TryParse(Configuration.Instance.Settings["appSettings:Nexmo.signing_method"], out method))
{
//left blank intentionally
}
else
{
method = SmsSignatureGenerator.Method.md5hash;
}

var sb = new StringBuilder();
var signature_sb = new StringBuilder();
Action<IDictionary<string, string>, StringBuilder> buildStringFromParams = (param, strings) =>
{
foreach (var kvp in param)
{
strings.AppendFormat("{0}={1}&", WebUtility.UrlEncode(kvp.Key), WebUtility.UrlEncode(kvp.Value));
}
};
Action<IDictionary<string, string>, StringBuilder> buildSignatureStringFromParams = (param, strings) =>
{
foreach (var kvp in param)
{
strings.AppendFormat("{0}={1}&", kvp.Key.Replace('=','_').Replace('&','_'), kvp.Value.Replace('=', '_').Replace('&', '_'));
}
};
parameters.Add("api_key", apiKey);
if (string.IsNullOrEmpty(securitySecret))
{
Expand All @@ -43,15 +64,14 @@ private static StringBuilder BuildQueryString(IDictionary<string, string> parame
buildStringFromParams(parameters, sb);
return sb;
}
// security secret provided, sort and sign request
parameters.Add("timestamp", ((int)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds).ToString(CultureInfo.InvariantCulture));
var sortedParams = new SortedDictionary<string, string>(parameters);
buildStringFromParams(sortedParams, sb);
var queryToSign = "&" + sb;
queryToSign = queryToSign.Remove(queryToSign.Length - 1) + securitySecret.ToUpper();
var hashgen = MD5.Create();
var hash = hashgen.ComputeHash(Encoding.UTF8.GetBytes(queryToSign));
sb.AppendFormat("sig={0}", ByteArrayToHexHelper.ByteArrayToHex(hash).ToLower());
buildSignatureStringFromParams(sortedParams, signature_sb);
var queryToSign = "&" + signature_sb.ToString();
queryToSign = queryToSign.Remove(queryToSign.Length - 1);
var signature = SmsSignatureGenerator.GenerateSignature(queryToSign, securitySecret, method);
sb.AppendFormat("sig={0}", signature);
return sb;
}

Expand Down
9 changes: 8 additions & 1 deletion Nexmo.Api/Request/Credentials.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
namespace Nexmo.Api.Request
using Nexmo.Api.Cryptography;

namespace Nexmo.Api.Request
{
public class Credentials
{

/// <summary>
/// Method to be used for signing SMS Messages
/// </summary>
public SmsSignatureGenerator.Method Method { get; set; }
/// <summary>
/// Nexmo API Key (from your account dashboard)
/// </summary>
Expand Down
43 changes: 42 additions & 1 deletion Nexmo.Api/SMS.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using Nexmo.Api.Request;

Expand Down Expand Up @@ -301,7 +306,7 @@ public class SMSInbound
/// The time at UTC±00:00 that Nexmo started to push this inbound message to your webhook endpoint. The message-timestamp is in the following format YYYY-MM-DD HH:MM:SS. For example, 2020-01-01 12:00:00.
/// </summary>
[JsonProperty("message-timestamp")]
public DateTime message_timestamp { get; set; }
public string message_timestamp { get; set; }
/// <summary>
/// A unix timestamp representation of message-timestamp.
/// </summary>
Expand Down Expand Up @@ -354,6 +359,42 @@ public class SMSInbound
/// The hex encoded User Data Header
/// </summary>
public string udh { get; set; }

/// <summary>
/// Signature if Applicable
/// </summary>
public string sig { get; set; }

/// <summary>
/// converts dictionary into properly formatted signature string
/// </summary>
/// <param name="query"></param>
/// <returns></returns>
public static string ConstructSignatureStringFromDictionary(IDictionary<string,string> query)
{
try
{
var sig_sb = new StringBuilder();
var sorted_dict = new SortedDictionary<string, string>(StringComparer.Ordinal);
foreach (var key in query.Keys)
{
sorted_dict.Add(key, query[key].ToString());
}
foreach (var key in sorted_dict.Keys)
{
if (key == "sig")
{
continue;
}
sig_sb.AppendFormat("&{0}={1}", key.Replace('=', '_').Replace('&', '_'), sorted_dict[key].ToString().Replace('=', '_').Replace('&', '_'));
}
return sig_sb.ToString();
}
catch
{
return "";
}
}
}

/// <summary>
Expand Down

0 comments on commit dce8d83

Please # to comment.