From 092ac81f4695c718ff544824f98dca21a5f038f1 Mon Sep 17 00:00:00 2001 From: SendSafely Date: Tue, 10 Mar 2020 22:37:49 -0400 Subject: [PATCH] v3.0.5 updates - add allowReplyAll for Outlook integration - add parentPackageId property to identify reply packages --- SendsafelyAPI/ClientAPI.cs | 26 ++ .../Objects/FinalizePackageRequest.cs | 6 +- SendsafelyAPI/Objects/PackageDTO.cs | 7 + .../Objects/PackageInformationResponse.cs | 319 +++++++++--------- SendsafelyAPI/PackageInformation.cs | 248 +++++++------- SendsafelyAPI/Properties/AssemblyInfo.cs | 6 +- SendsafelyAPI/Utilities/PackageUtility.cs | 19 ++ 7 files changed, 361 insertions(+), 270 deletions(-) diff --git a/SendsafelyAPI/ClientAPI.cs b/SendsafelyAPI/ClientAPI.cs index bb634c3..7afe7c6 100644 --- a/SendsafelyAPI/ClientAPI.cs +++ b/SendsafelyAPI/ClientAPI.cs @@ -695,6 +695,32 @@ public String FinalizePackage(String packageId, String keycode) return pu.FinalizePackage(packageId, keycode); } + /// + /// Finalizes the package so it can be delivered to the recipients. + /// createPackage(). Additionally, the package must contain at least one file. + /// + /// The unique package id of the package to be finalized. + /// The keycode belonging to the package. + /// Determines whether package recipients permitted to reply to all recipients or just sender. + /// Thrown when the API has not been initialized. + /// Thrown when the API credentials are incorrect. + /// Thrown when the API failed to connect to the server. + /// Thrown when a non-existent or invalid package ID is used. + /// Thrown when the package limits has been exceeded. + /// Thrown when the package couldn't be finalized. The message will contain detailed information + /// Thrown when the keycode is null, empty or to short. + /// Will be thrown if the server returns an error message + /// + /// A link to access the package. This link can be sent to the recipients. + /// + public String FinalizePackage(String packageId, String keycode, bool allowReplyAll) + { + EnforceInitialized(); + + PackageUtility pu = new PackageUtility(connection); + return pu.FinalizePackage(packageId, keycode, allowReplyAll); + } + /// /// Finalizes an undisclosed package, which is a package without recipients. Anyone with access to the link can access the package. /// diff --git a/SendsafelyAPI/Objects/FinalizePackageRequest.cs b/SendsafelyAPI/Objects/FinalizePackageRequest.cs index f74c9f6..4c6cb19 100644 --- a/SendsafelyAPI/Objects/FinalizePackageRequest.cs +++ b/SendsafelyAPI/Objects/FinalizePackageRequest.cs @@ -10,7 +10,8 @@ class FinalizePackageRequest { private String _password; private String _checksum; - private bool undisclosedRecipients; + private bool undisclosedRecipients; + private bool allowReplyAll = false; [JsonProperty(PropertyName = "password")] public String Password { get; set; } @@ -20,5 +21,8 @@ class FinalizePackageRequest [JsonProperty(PropertyName = "undisclosedRecipients")] public bool UndisclosedRecipients { get; set; } + + [JsonProperty(PropertyName = "allowReplyAll")] + public bool AllowReplyAll { get; set; } } } diff --git a/SendsafelyAPI/Objects/PackageDTO.cs b/SendsafelyAPI/Objects/PackageDTO.cs index 9433b41..958e416 100644 --- a/SendsafelyAPI/Objects/PackageDTO.cs +++ b/SendsafelyAPI/Objects/PackageDTO.cs @@ -23,6 +23,7 @@ class PackageDTO private String packageUserName; private String packageState; private List contactGroups; + private String _packageParentId; [JsonProperty(PropertyName = "response")] internal APIResponse Response @@ -125,5 +126,11 @@ public List ContactGroups get { return contactGroups; } set { contactGroups = value; } } + [JsonProperty(PropertyName = "packageParentId")] + public String PackageParentId + { + get { return _packageParentId; } + set { _packageParentId = value; } + } } } diff --git a/SendsafelyAPI/Objects/PackageInformationResponse.cs b/SendsafelyAPI/Objects/PackageInformationResponse.cs index 0c8b3f4..236aaa7 100644 --- a/SendsafelyAPI/Objects/PackageInformationResponse.cs +++ b/SendsafelyAPI/Objects/PackageInformationResponse.cs @@ -1,155 +1,170 @@ -using System; -using System.Collections.Generic; -using System.Text; -using Newtonsoft.Json; - -namespace SendSafely.Objects -{ - [JsonObject(MemberSerialization.OptIn)] - class PackageInformationResponse - { - private String _packageId; - private String _packageCode; - private String _serverSecret; - private APIResponse _response; - private String _message; - private bool _needsApprover; - private String state; - private List _recipients; - private List _files; - private List _approvers; +using System; +using System.Collections.Generic; +using System.Text; +using Newtonsoft.Json; + +namespace SendSafely.Objects +{ + [JsonObject(MemberSerialization.OptIn)] + class PackageInformationResponse + { + private String _packageId; + private String _packageCode; + private String _serverSecret; + private APIResponse _response; + private String _message; + private bool _needsApprover; + private String state; + private List _recipients; + private List _files; + private List _approvers; private int _life; - private DateTime _packageTimestamp; - private String _packageSender; - private String _rootDirectoryId; - private String _label; - private bool _isVDR; - private List contactGroups; - - [JsonProperty(PropertyName = "response")] - internal APIResponse Response - { - get { return _response; } - set { _response = value; } - } - - [JsonProperty(PropertyName = "packageId")] - internal String PackageID - { - get { return _packageId; } - set { _packageId = value; } - } - - [JsonProperty(PropertyName = "packageCode")] - internal String PackageCode - { - get { return _packageCode; } - set { _packageCode = value; } - } - - [JsonProperty(PropertyName = "serverSecret")] - internal String ServerSecret - { - get { return _serverSecret; } - set { _serverSecret = value; } - } - - [JsonProperty(PropertyName = "message")] - public String Message - { - get { return _message; } - set { _message = value; } - } - - [JsonProperty(PropertyName = "needsApproval")] - public bool NeedsApprover - { - get { return _needsApprover; } - set { _needsApprover = value; } - } - - [JsonProperty(PropertyName = "recipients")] - internal List Recipients - { - get { return _recipients; } - set { _recipients = value; } - } - - [JsonProperty(PropertyName = "files")] - public List Files - { - get { return _files; } - set { _files = value; } - } - - [JsonProperty(PropertyName = "approverList")] - public List Approvers - { - get { return _approvers; } - set { _approvers = value; } - } - - [JsonProperty(PropertyName = "life")] - public int Life - { - get { return _life; } - set { _life = value; } - } - - [JsonProperty(PropertyName = "packageTimestamp")] - public DateTime PackageTimestamp - { - get { return _packageTimestamp; } - set { _packageTimestamp = value; } - } - - [JsonProperty(PropertyName = "packageSender")] - public String PackageSender - { - get { return _packageSender; } - set { _packageSender = value; } - } - - [JsonProperty(PropertyName = "rootDirectoryId")] - public String RootDirectoryId - { - get { return _rootDirectoryId; } - set { _rootDirectoryId = value; } - } - - [JsonProperty(PropertyName = "label")] - public String Label - { - get { return _label; } - set { _label = value; } - } - - [JsonProperty(PropertyName = "isVDR")] - public Boolean IsVDR - { - get { return _isVDR; } - set { _isVDR = value; } - } - - /// - /// A list of contact groups - /// - [JsonProperty(PropertyName = "contactGroups")] - public List ContactGroups - { - get { return contactGroups; } - set { contactGroups = value; } - } - + private DateTime _packageTimestamp; + private String _packageSender; + private String _rootDirectoryId; + private String _label; + private bool _isVDR; + private List contactGroups; + private bool _allowReplyAll; + private String _packageParentId; + + [JsonProperty(PropertyName = "response")] + internal APIResponse Response + { + get { return _response; } + set { _response = value; } + } + + [JsonProperty(PropertyName = "packageId")] + internal String PackageID + { + get { return _packageId; } + set { _packageId = value; } + } + + [JsonProperty(PropertyName = "packageCode")] + internal String PackageCode + { + get { return _packageCode; } + set { _packageCode = value; } + } + + [JsonProperty(PropertyName = "serverSecret")] + internal String ServerSecret + { + get { return _serverSecret; } + set { _serverSecret = value; } + } + + [JsonProperty(PropertyName = "message")] + public String Message + { + get { return _message; } + set { _message = value; } + } + + [JsonProperty(PropertyName = "needsApproval")] + public bool NeedsApprover + { + get { return _needsApprover; } + set { _needsApprover = value; } + } + + [JsonProperty(PropertyName = "recipients")] + internal List Recipients + { + get { return _recipients; } + set { _recipients = value; } + } + + [JsonProperty(PropertyName = "files")] + public List Files + { + get { return _files; } + set { _files = value; } + } + + [JsonProperty(PropertyName = "approverList")] + public List Approvers + { + get { return _approvers; } + set { _approvers = value; } + } + + [JsonProperty(PropertyName = "life")] + public int Life + { + get { return _life; } + set { _life = value; } + } + + [JsonProperty(PropertyName = "packageTimestamp")] + public DateTime PackageTimestamp + { + get { return _packageTimestamp; } + set { _packageTimestamp = value; } + } + + [JsonProperty(PropertyName = "packageSender")] + public String PackageSender + { + get { return _packageSender; } + set { _packageSender = value; } + } + + [JsonProperty(PropertyName = "rootDirectoryId")] + public String RootDirectoryId + { + get { return _rootDirectoryId; } + set { _rootDirectoryId = value; } + } + + [JsonProperty(PropertyName = "label")] + public String Label + { + get { return _label; } + set { _label = value; } + } + + [JsonProperty(PropertyName = "isVDR")] + public Boolean IsVDR + { + get { return _isVDR; } + set { _isVDR = value; } + } + + /// + /// A list of contact groups + /// + [JsonProperty(PropertyName = "contactGroups")] + public List ContactGroups + { + get { return contactGroups; } + set { contactGroups = value; } + } + /// /// a string of state - /// - [JsonProperty(PropertyName = "state")] - public String State - { - get { return state; } - set { state = value; } - } - - } -} + /// + [JsonProperty(PropertyName = "state")] + public String State + { + get { return state; } + set { state = value; } + } + + [JsonProperty(PropertyName = "allowReplyAll")] + public Boolean AllowReplyAll + { + get { return _allowReplyAll; } + set { _allowReplyAll = value; } + } + + [JsonProperty(PropertyName = "packageParentId")] + public String PackageParentId + { + get { return _packageParentId; } + set { _packageParentId = value; } + } + } +} diff --git a/SendsafelyAPI/PackageInformation.cs b/SendsafelyAPI/PackageInformation.cs index 2376b30..2f1d64e 100644 --- a/SendsafelyAPI/PackageInformation.cs +++ b/SendsafelyAPI/PackageInformation.cs @@ -26,91 +26,93 @@ public class PackageInformation private bool isWorkspace; private DateTime packageTimestamp; private String packageOwner; - private List recipients; - private List contactGroups; - - /// - /// The package ID for the given package. - /// - public String PackageId - { - get { return packageId; } - set { packageId = value; } - } - - /// - /// The package code for the given package. The package code is a part of the URL that must be sent to the recipients. - /// - public String PackageCode - { - get { return packageCode; } - set { packageCode = value; } - } - - /// - /// The keycode for the package. This key should always be kept client side and never be sent to the server. - /// The keycode makes up one part of the encryption key. - /// - public String KeyCode - { - get { return keyCode; } - set { keyCode = value; } - } - - /// - /// The server secret makes together with the keycode up the encryption key. The server secret is specific - /// to a package and passed from the server. - /// - public String ServerSecret - { - get { return serverSecret; } - set { serverSecret = value; } - } - - /// - /// NeedsApprover will be true when a package needs to add at least one approver before the package can be finalized. - /// If the package is finalized without the approver, an exception will be thrown. - /// - public bool NeedsApprover - { - get { return needsApprover; } - set { needsApprover = value; } - } - - /// - /// A list of recipients that are currently attached to the package. - /// - public List Recipients - { - get { return recipients; } - set { recipients = value; } - } - - /// - /// A list of files that are currently attached to the package. - /// - public List Files - { - get { return files; } - set { files = value; } - } - - /// - /// A list of approvers that are currently attached to the package. - /// - public List Approvers - { - get { return approvers; } - set { approvers = value; } - } - - /// - /// The current package life. The package life determines for how long the package - /// should be available to the recipients. It's measured in days. - /// - public int Life - { - get { return life; } + private List recipients; + private List contactGroups; + private bool allowReplyAll; + private String packageParentId; + + /// + /// The package ID for the given package. + /// + public String PackageId + { + get { return packageId; } + set { packageId = value; } + } + + /// + /// The package code for the given package. The package code is a part of the URL that must be sent to the recipients. + /// + public String PackageCode + { + get { return packageCode; } + set { packageCode = value; } + } + + /// + /// The keycode for the package. This key should always be kept client side and never be sent to the server. + /// The keycode makes up one part of the encryption key. + /// + public String KeyCode + { + get { return keyCode; } + set { keyCode = value; } + } + + /// + /// The server secret makes together with the keycode up the encryption key. The server secret is specific + /// to a package and passed from the server. + /// + public String ServerSecret + { + get { return serverSecret; } + set { serverSecret = value; } + } + + /// + /// NeedsApprover will be true when a package needs to add at least one approver before the package can be finalized. + /// If the package is finalized without the approver, an exception will be thrown. + /// + public bool NeedsApprover + { + get { return needsApprover; } + set { needsApprover = value; } + } + + /// + /// A list of recipients that are currently attached to the package. + /// + public List Recipients + { + get { return recipients; } + set { recipients = value; } + } + + /// + /// A list of files that are currently attached to the package. + /// + public List Files + { + get { return files; } + set { files = value; } + } + + /// + /// A list of approvers that are currently attached to the package. + /// + public List Approvers + { + get { return approvers; } + set { approvers = value; } + } + + /// + /// The current package life. The package life determines for how long the package + /// should be available to the recipients. It's measured in days. + /// + public int Life + { + get { return life; } set { life = value; } } @@ -121,7 +123,7 @@ public int Life public DateTime PackageTimestamp { get { return packageTimestamp; } - set { packageTimestamp = value; } + set { packageTimestamp = value; } } /// @@ -149,42 +151,60 @@ public PackageStatus Status { get { return status; } set { status = value; } - } - + } + /// /// The root directory of a workspace package. - /// - public String RootDirectoryId - { - get { return rootDirectoryId; } - set { rootDirectoryId = value; } - } - + /// + public String RootDirectoryId + { + get { return rootDirectoryId; } + set { rootDirectoryId = value; } + } + /// /// The package descriptor. - /// - public String PackageDescriptor - { - get { return packageDescriptor; } - set { packageDescriptor = value; } - } - + /// + public String PackageDescriptor + { + get { return packageDescriptor; } + set { packageDescriptor = value; } + } + /// /// The flag specifying the package is a workspace. - /// + /// public Boolean IsWorkspace { - get { return isWorkspace; } + get { return isWorkspace; } set { isWorkspace = value; } } - /// - /// A list of contact groups - /// - public List ContactGroups - { - get { return contactGroups; } - set { contactGroups = value; } - } - } -} + /// + /// A list of contact groups + /// + public List ContactGroups + { + get { return contactGroups; } + set { contactGroups = value; } + } + + /// + /// Allow reply all, false if BCC recipients + /// + public Boolean AllowReplyAll + { + get { return allowReplyAll; } + set { allowReplyAll = value; } + } + + /// + /// Package parent id + /// + public String PackageParentId + { + get { return packageParentId; } + set { packageParentId = value; } + } + } +} diff --git a/SendsafelyAPI/Properties/AssemblyInfo.cs b/SendsafelyAPI/Properties/AssemblyInfo.cs index b214cc3..d7fe2b5 100644 --- a/SendsafelyAPI/Properties/AssemblyInfo.cs +++ b/SendsafelyAPI/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("SendSafely Windows Client API")] -[assembly: AssemblyCopyright("Copyright © 2019")] +[assembly: AssemblyCopyright("Copyright © 2020")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -32,7 +32,7 @@ // 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("3.0.4")] -[assembly: AssemblyFileVersion("3.0.4")] +[assembly: AssemblyVersion("3.0.5")] +[assembly: AssemblyFileVersion("3.0.5")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("APITests")] \ No newline at end of file diff --git a/SendsafelyAPI/Utilities/PackageUtility.cs b/SendsafelyAPI/Utilities/PackageUtility.cs index 39a2b1a..54e0c3a 100644 --- a/SendsafelyAPI/Utilities/PackageUtility.cs +++ b/SendsafelyAPI/Utilities/PackageUtility.cs @@ -576,6 +576,23 @@ public String FinalizePackage(String packageId, String keycode) return FinalizePackage(packageInfo); } + public String FinalizePackage(String packageId, String keycode, bool allowReplyAll) + { + if (packageId == null) + { + throw new InvalidPackageException("PackageId can not be null"); + } + FinalizePackageRequest request = new FinalizePackageRequest(); + + request.AllowReplyAll = allowReplyAll; + // Add the keycode in case we don't have it + connection.AddKeycode(packageId, keycode); + + // Get the updated package information. + PackageInformation packageInfo = GetPackageInformation(packageId); + return FinalizePackage(packageInfo, request); + } + public String FinalizePackage(PackageInformation packageInfo) { FinalizePackageRequest request = new FinalizePackageRequest(); @@ -1325,6 +1342,7 @@ private PackageInformation Convert(PackageDTO raw) packageInfo.ServerSecret = raw.ServerSecret; packageInfo.Approvers = raw.Approvers; packageInfo.PackageTimestamp = raw.PackageUpdateTimestamp; + packageInfo.PackageParentId = raw.PackageParentId; packageInfo.PackageOwner = raw.PackageUserName; @@ -1385,6 +1403,7 @@ private PackageInformation Convert(PackageInformationResponse raw) packageInfo.ContactGroups = raw.ContactGroups; int stateValue = (int) Enum.Parse(typeof(PackageState), raw.State, true); packageInfo.Status = ConvertStateToStatus(stateValue); + packageInfo.PackageParentId = raw.PackageParentId; try {