Skip to content
139 changes: 127 additions & 12 deletions LearnositySDK/Request/Init.cs
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LearnositySDK.Utils;
using System.Web;
using System.Runtime.InteropServices;

namespace LearnositySDK.Request
{
Expand Down Expand Up @@ -77,6 +77,11 @@ public class Init
/// </summary>
private string algorithm;

/// <summary>
/// Determines if telemetry is enabled; default is true
/// </summary>
private static bool telemetryEnabled = true;

/// <summary>
/// Instantiate this class with all security and request data. It will be used to create a signature.
/// </summary>
Expand Down Expand Up @@ -153,6 +158,7 @@ private void Initialize(string service, JsonObject securityPacket, string secret
//try
//{
this.validate(this.service, ref this.securityPacket, this.secret, this.requestPacket, this.action);
this.addTelemetryData();
this.requestString = this.generateRequestString();
this.setServiceOptions();
this.securityPacket.set("signature", this.generateSignature());
Expand Down Expand Up @@ -180,7 +186,7 @@ private string generateRequestString()
{
throw new Exception("Invalid data, please check you request packet.");
}

return request;
}

Expand All @@ -191,7 +197,7 @@ private string generateRequestString()
/// - the `action` value if passed
/// </summary>
/// <returns>A signature hash for the request authentication</returns>
private string generateSignature()
public string generateSignature()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Turned to public so we can use it in the tests. In Java SDK this is also a public method.

{
List<string> signatureList = new List<string>();
string temp = null;
Expand Down Expand Up @@ -256,7 +262,7 @@ public string generate()
{
return this.generateData(output);
}
else if(this.service == "assess")
else if (this.service == "assess")
{
output = this.generateAssess(output);
}
Expand All @@ -277,7 +283,7 @@ public string generate()
// do nothing
break;
}

return output.toJson();
}

Expand All @@ -291,7 +297,7 @@ private string generateData(JsonObject output)
StringBuilder sb = new StringBuilder();
JsonObject obj = null;
string str = "";

obj = output.getJsonObject("security");
if (!Tools.empty(obj))
{
Expand Down Expand Up @@ -380,7 +386,7 @@ private void setServiceOptions()
case "assess":
// fall-through
case "questions":

this.signRequestData = false;

if (this.service == "assess" && Tools.array_key_exists("questionsApiActivity", this.requestPacket))
Expand Down Expand Up @@ -456,18 +462,21 @@ private void setServiceOptions()
this.signRequestData = false;

JsonObject requestPackageUsers = this.requestPacket.getJsonObject("users");
if (requestPackageUsers != null) {
string[] users = requestPackageUsers.getValuesArray();
if (users != null && users.Length > 0) {
if (requestPackageUsers != null)
{
string[] users = requestPackageUsers.getValuesArray();
if (users != null && users.Length > 0)
{
hashedUsers = new JsonObject();
for (int i = 0; i < users.Length; i++) {
for (int i = 0; i < users.Length; i++)
{
string user_id = users[i];
hashedUsers.set(user_id, Tools.hash(this.algorithm, user_id + this.secret));
}
this.requestPacket.set("users", hashedUsers);
}
}

break;
default:
// do nothing
Expand Down Expand Up @@ -518,5 +527,111 @@ public void validate(string service, ref JsonObject securityPacket, string secre
throw new Exception("The `secret` argument must be a valid string");
}
}

/// <summary>
/// Adds a meta field with SDK information in it to the requestPacket
/// </summary>
public void addTelemetryData()
{
if (this.isTelemetryEnabled())
{
JsonObject meta;
if (this.requestPacket.getJsonObject("meta") != null)
{
meta = this.requestPacket.getJsonObject("meta");
}
else
{
meta = new JsonObject();
}

meta.set("sdk", this.getSdkMeta());
this.requestPacket.set("meta", meta);
}
}

public bool isTelemetryEnabled()
{
return telemetryEnabled;
}

public JsonObject getSdkMeta()
{
JsonObject sdkMeta = new JsonObject();
sdkMeta.set("version", this.getSdkVersion());
sdkMeta.set("lang", "asp.net");
sdkMeta.set("lang_version", this.getLanguageVersion());
sdkMeta.set("platform", this.getPlatform());
sdkMeta.set("platform_version", this.getPlatformVersion());

return sdkMeta;
}

/// <summary>
/// Returns the version number of ASP.NET
/// </summary>
/// <returns></returns>
public string getLanguageVersion()
{
return Environment.Version.ToString();
}

/// <summary>
/// Returns the name of the platform the code is running on
/// </summary>
/// <returns></returns>
public string getPlatform()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
return "darwin";
}

if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return "win";
}

if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
return "linux";
}

return Environment.OSVersion.Platform.ToString();
}

/// <summary>
/// Returns the version number of the platform the code is running on
/// </summary>
/// <returns></returns>
public string getPlatformVersion()
{
var os = Environment.OSVersion;
return string.Concat(os.Version.Major, '.', os.Version.Minor);
}

/// <summary>
/// Extracts the version number of this SDK from the project meta data
/// </summary>
/// <returns>The version number</returns>
public string getSdkVersion()
{
return GetType().Assembly.GetName().Version.ToString();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will return a string with four sections separated by periods. i.e. 0.0.8.0

}

/// <summary>
/// We use telemetry to enable better support and feature planning.
/// It will not interfere with any usage.
/// However, it is not advised to disable it.
/// </summary>
public static void disableTelemetry()
{
telemetryEnabled = false;
}

public static void enableTelemetry()
{
telemetryEnabled = true;
}
}
}
143 changes: 143 additions & 0 deletions LearnositySDKIntegrationTests/LearnositySDKIntegrationTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using Xunit;
using System.IO;
using LearnositySDK.Utils;
using LearnositySDK.Request;

Expand Down Expand Up @@ -69,5 +70,147 @@ private static string BuildDataAPIBaseUrl(string env, string region, string vers

return "https://data" + regionDomain + envDomain + ".learnosity.com/" + versionPath;
}

[Fact]
public void InitGeneratesExactSameSignature()
{
string action = "get";

JsonObject security = this.generateSecurityObject();

JsonObject request = new JsonObject();
request.set("limit", 100);

Init.disableTelemetry();
Init init = new Init("data", security, this.consumerSecret, request, action);

// Assert signature is still the same
Assert.Equal(
init.generateSignature(),
"e1eae0b86148df69173cb3b824275ea73c9c93967f7d17d6957fcdd299c8a4fe"
);

// Assert telemetry is turned off
Assert.False(init.isTelemetryEnabled());
Init.enableTelemetry();
}

[Fact]
public void InitGenerateBuildsNonEmptyRequest()
{
string action = "get";

JsonObject security = this.generateSecurityObject();

JsonObject request = new JsonObject();
request.set("page", 1);

Init init = new Init("data", security, this.consumerSecret, request, action);
string generatedString = init.generate();

// Assert generated string is not empty
Assert.NotEmpty(generatedString);

// Assert telemetry is turned on
Assert.True(init.isTelemetryEnabled());
}

[Fact]
public void EnabledTelemetryAddsSdkField()
{
string action = "get";
JsonObject security = this.generateSecurityObject();

JsonObject request = new JsonObject();
request.set("page", 1);

Init init = new Init("data", security, this.consumerSecret, request, action);
string generatedString = init.generate();

Assert.Contains("meta", generatedString);
Assert.Contains("sdk", generatedString);
}

[Fact]
public void EnabledTelemetryPreservesOtherMetaProps()
{
string action = "get";
JsonObject security = this.generateSecurityObject();

JsonObject metaField = new JsonObject();
metaField.set("test_key_string", "test-string");
metaField.set("test_key_integer", 12345);

JsonObject request = new JsonObject();
request.set("page", 1);
request.set("meta", metaField);

Init init = new Init("data", security, this.consumerSecret, request, action);
string generatedString = init.generate();

Assert.Contains("meta", generatedString);
Assert.Contains("sdk", generatedString);
Assert.Contains("test_key_string", generatedString);
Assert.Contains("test_key_integer", generatedString);
}

[Fact]
public void DisabledTelemetryPreservesEmptyProps()
{
string action = "get";
JsonObject security = this.generateSecurityObject();

Init.disableTelemetry();

JsonObject request = new JsonObject();
request.set("page", 1);

Init init = new Init("data", security, this.consumerSecret, request, action);
string generatedString = init.generate();

Assert.DoesNotContain("meta", generatedString);
Assert.DoesNotContain("sdk", generatedString);

Init.enableTelemetry();
}

[Fact]
public void DisabledTelemetryPreservesFilledProps()
{
string action = "get";
JsonObject security = this.generateSecurityObject();

Init.disableTelemetry();

JsonObject metaField = new JsonObject();
metaField.set("test_key_string", "test-string");
metaField.set("test_key_integer", 12345);

JsonObject request = new JsonObject();
request.set("page", 1);
request.set("meta", metaField);

Init init = new Init("data", security, this.consumerSecret, request, action);
string generatedString = init.generate();

Assert.Contains("meta", generatedString);
Assert.DoesNotContain("sdk", generatedString);
Assert.Contains("test_key_string", generatedString);
Assert.Contains("test_key_integer", generatedString);

Init.enableTelemetry();
}

private JsonObject generateSecurityObject()
{
string timestamp = "20140626-0528";

JsonObject security = new JsonObject();
security.set("consumer_key", this.consumerKey);
security.set("domain", this.domain);
security.set("timestamp", timestamp);

return security;
}
}
}