From 07be3aee47b0280396ec33181f2ab58c0679fe9f Mon Sep 17 00:00:00 2001 From: Gregoire Pailler Date: Sun, 26 Apr 2015 16:54:26 +0200 Subject: [PATCH] Updated copyright year to 2015 --- LICENSE | 2 +- MegaApiClient/Crypto.cs | 344 +++++------ MegaApiClient/Exceptions.cs | 2 +- MegaApiClient/Extensions.cs | 2 +- MegaApiClient/IWebClient.cs | 2 +- MegaApiClient/JsonSerialization.cs | 942 ++++++++++++++--------------- MegaApiClient/MegaAesCtrStream.cs | 2 +- MegaApiClient/MegaApiClient.cs | 2 +- MegaApiClient/WebClient.cs | 2 +- 9 files changed, 650 insertions(+), 650 deletions(-) diff --git a/LICENSE b/LICENSE index 78e7dc4..f19f93b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013 gpailler +Copyright (c) 2015 gpailler Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/MegaApiClient/Crypto.cs b/MegaApiClient/Crypto.cs index 4e53f5c..a2f093e 100644 --- a/MegaApiClient/Crypto.cs +++ b/MegaApiClient/Crypto.cs @@ -1,79 +1,79 @@ -#region License - -/* -The MIT License (MIT) - -Copyright (c) 2014 Gregoire Pailler - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#endregion - -using System; -using System.Security.Cryptography; -using Newtonsoft.Json; - -namespace CG.Web.MegaApiClient -{ - internal class Crypto - { - private static readonly Rijndael Rijndael; - private static readonly byte[] DefaultIv = new byte[16]; - - static Crypto() - { - Rijndael = Rijndael.Create(); - Rijndael.Padding = PaddingMode.None; - Rijndael.Mode = CipherMode.CBC; - } - - #region Key - - public static byte[] DecryptKey(byte[] data, byte[] key) - { - byte[] result = new byte[data.Length]; - - for (int idx = 0; idx < data.Length; idx += 16) - { - byte[] block = data.CopySubArray(16, idx); - byte[] decryptedBlock = DecryptAes(block, key); - Array.Copy(decryptedBlock, 0, result, idx, 16); - } - - return result; - } - - public static byte[] EncryptKey(byte[] data, byte[] key) - { - byte[] result = new byte[data.Length]; - - for (int idx = 0; idx < data.Length; idx += 16) - { - byte[] block = data.CopySubArray(16, idx); - byte[] encryptedBlock = EncryptAes(block, key); - Array.Copy(encryptedBlock, 0, result, idx, 16); - } - - return result; - } - - public static void GetPartsFromDecryptedKey(byte[] decryptedKey, out byte[] iv, out byte[] metaMac, out byte[] fileKey) +#region License + +/* +The MIT License (MIT) + +Copyright (c) 2015 Gregoire Pailler + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#endregion + +using System; +using System.Security.Cryptography; +using Newtonsoft.Json; + +namespace CG.Web.MegaApiClient +{ + internal class Crypto + { + private static readonly Rijndael Rijndael; + private static readonly byte[] DefaultIv = new byte[16]; + + static Crypto() + { + Rijndael = Rijndael.Create(); + Rijndael.Padding = PaddingMode.None; + Rijndael.Mode = CipherMode.CBC; + } + + #region Key + + public static byte[] DecryptKey(byte[] data, byte[] key) + { + byte[] result = new byte[data.Length]; + + for (int idx = 0; idx < data.Length; idx += 16) + { + byte[] block = data.CopySubArray(16, idx); + byte[] decryptedBlock = DecryptAes(block, key); + Array.Copy(decryptedBlock, 0, result, idx, 16); + } + + return result; + } + + public static byte[] EncryptKey(byte[] data, byte[] key) + { + byte[] result = new byte[data.Length]; + + for (int idx = 0; idx < data.Length; idx += 16) + { + byte[] block = data.CopySubArray(16, idx); + byte[] encryptedBlock = EncryptAes(block, key); + Array.Copy(encryptedBlock, 0, result, idx, 16); + } + + return result; + } + + public static void GetPartsFromDecryptedKey(byte[] decryptedKey, out byte[] iv, out byte[] metaMac, out byte[] fileKey) { // Extract Iv and MetaMac iv = new byte[8]; @@ -86,99 +86,99 @@ public static void GetPartsFromDecryptedKey(byte[] decryptedKey, out byte[] iv, for (int idx = 0; idx < 16; idx++) { fileKey[idx] = (byte)(decryptedKey[idx] ^ decryptedKey[idx + 16]); - } - } - #endregion - - #region Aes - - public static byte[] DecryptAes(byte[] data, byte[] key) - { - using (ICryptoTransform decryptor = Rijndael.CreateDecryptor(key, DefaultIv)) - { - return decryptor.TransformFinalBlock(data, 0, data.Length); - } - } - - public static byte[] EncryptAes(byte[] data, byte[] key) - { - using (ICryptoTransform encryptor = Rijndael.CreateEncryptor(key, DefaultIv)) - { - return encryptor.TransformFinalBlock(data, 0, data.Length); - } - } - - public static byte[] CreateAesKey() - { - using (Rijndael rijndael = Rijndael.Create()) - { - rijndael.Mode = CipherMode.CBC; - rijndael.KeySize = 128; - rijndael.Padding = PaddingMode.None; - rijndael.GenerateKey(); - return rijndael.Key; - } - } - - #endregion - - #region Attributes - - public static byte[] EncryptAttributes(Attributes attributes, byte[] nodeKey) - { - string data = "MEGA" + JsonConvert.SerializeObject(attributes, Formatting.None); - byte[] dataBytes = data.ToBytes(); - dataBytes = dataBytes.CopySubArray(dataBytes.Length + 16 - (dataBytes.Length % 16)); - - return EncryptAes(dataBytes, nodeKey); - } - - public static Attributes DecryptAttributes(byte[] attributes, byte[] nodeKey) - { - byte[] decryptedAttributes = DecryptAes(attributes, nodeKey); - - // Remove MEGA prefix - try - { - return JsonConvert.DeserializeObject(decryptedAttributes.ToUTF8String().Substring(4)); - } - catch (Exception ex) - { - return new Attributes(string.Format("Attribute deserialization failed: {0}", ex.Message)); - } - } - - #endregion - - #region Rsa - - public static BigInteger[] GetRsaPrivateKeyComponents(byte[] encodedRsaPrivateKey, byte[] masterKey) - { - // We need to add padding to obtain multiple of 16 - encodedRsaPrivateKey = encodedRsaPrivateKey.CopySubArray(encodedRsaPrivateKey.Length + (16 - encodedRsaPrivateKey.Length % 16)); - byte[] rsaPrivateKey = DecryptKey(encodedRsaPrivateKey, masterKey); - - // rsaPrivateKeyComponents[0] => First factor p - // rsaPrivateKeyComponents[1] => Second factor q - // rsaPrivateKeyComponents[2] => Private exponent d - BigInteger[] rsaPrivateKeyComponents = new BigInteger[4]; - for (int i = 0; i < 4; i++) - { - rsaPrivateKeyComponents[i] = rsaPrivateKey.FromMPINumber(); - - // Remove already retrieved part - int dataLength = ((rsaPrivateKey[0] * 256 + rsaPrivateKey[1] + 7) / 8); - rsaPrivateKey = rsaPrivateKey.CopySubArray(rsaPrivateKey.Length - dataLength - 2, dataLength + 2); - } - - return rsaPrivateKeyComponents; - } - - public static byte[] RsaDecrypt(BigInteger data, BigInteger p, BigInteger q, BigInteger d) - { - return data.modPow(d, p * q).getBytes(); - } - - #endregion - } -} + } + } + #endregion + + #region Aes + + public static byte[] DecryptAes(byte[] data, byte[] key) + { + using (ICryptoTransform decryptor = Rijndael.CreateDecryptor(key, DefaultIv)) + { + return decryptor.TransformFinalBlock(data, 0, data.Length); + } + } + + public static byte[] EncryptAes(byte[] data, byte[] key) + { + using (ICryptoTransform encryptor = Rijndael.CreateEncryptor(key, DefaultIv)) + { + return encryptor.TransformFinalBlock(data, 0, data.Length); + } + } + + public static byte[] CreateAesKey() + { + using (Rijndael rijndael = Rijndael.Create()) + { + rijndael.Mode = CipherMode.CBC; + rijndael.KeySize = 128; + rijndael.Padding = PaddingMode.None; + rijndael.GenerateKey(); + return rijndael.Key; + } + } + + #endregion + + #region Attributes + + public static byte[] EncryptAttributes(Attributes attributes, byte[] nodeKey) + { + string data = "MEGA" + JsonConvert.SerializeObject(attributes, Formatting.None); + byte[] dataBytes = data.ToBytes(); + dataBytes = dataBytes.CopySubArray(dataBytes.Length + 16 - (dataBytes.Length % 16)); + + return EncryptAes(dataBytes, nodeKey); + } + + public static Attributes DecryptAttributes(byte[] attributes, byte[] nodeKey) + { + byte[] decryptedAttributes = DecryptAes(attributes, nodeKey); + + // Remove MEGA prefix + try + { + return JsonConvert.DeserializeObject(decryptedAttributes.ToUTF8String().Substring(4)); + } + catch (Exception ex) + { + return new Attributes(string.Format("Attribute deserialization failed: {0}", ex.Message)); + } + } + + #endregion + + #region Rsa + + public static BigInteger[] GetRsaPrivateKeyComponents(byte[] encodedRsaPrivateKey, byte[] masterKey) + { + // We need to add padding to obtain multiple of 16 + encodedRsaPrivateKey = encodedRsaPrivateKey.CopySubArray(encodedRsaPrivateKey.Length + (16 - encodedRsaPrivateKey.Length % 16)); + byte[] rsaPrivateKey = DecryptKey(encodedRsaPrivateKey, masterKey); + + // rsaPrivateKeyComponents[0] => First factor p + // rsaPrivateKeyComponents[1] => Second factor q + // rsaPrivateKeyComponents[2] => Private exponent d + BigInteger[] rsaPrivateKeyComponents = new BigInteger[4]; + for (int i = 0; i < 4; i++) + { + rsaPrivateKeyComponents[i] = rsaPrivateKey.FromMPINumber(); + + // Remove already retrieved part + int dataLength = ((rsaPrivateKey[0] * 256 + rsaPrivateKey[1] + 7) / 8); + rsaPrivateKey = rsaPrivateKey.CopySubArray(rsaPrivateKey.Length - dataLength - 2, dataLength + 2); + } + + return rsaPrivateKeyComponents; + } + + public static byte[] RsaDecrypt(BigInteger data, BigInteger p, BigInteger q, BigInteger d) + { + return data.modPow(d, p * q).getBytes(); + } + + #endregion + } +} diff --git a/MegaApiClient/Exceptions.cs b/MegaApiClient/Exceptions.cs index 5aab6e7..52e4d81 100644 --- a/MegaApiClient/Exceptions.cs +++ b/MegaApiClient/Exceptions.cs @@ -3,7 +3,7 @@ /* The MIT License (MIT) -Copyright (c) 2014 Gregoire Pailler +Copyright (c) 2015 Gregoire Pailler Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/MegaApiClient/Extensions.cs b/MegaApiClient/Extensions.cs index 382137a..29bacd6 100644 --- a/MegaApiClient/Extensions.cs +++ b/MegaApiClient/Extensions.cs @@ -3,7 +3,7 @@ /* The MIT License (MIT) -Copyright (c) 2014 Gregoire Pailler +Copyright (c) 2015 Gregoire Pailler Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/MegaApiClient/IWebClient.cs b/MegaApiClient/IWebClient.cs index f0c32ca..471a8c0 100644 --- a/MegaApiClient/IWebClient.cs +++ b/MegaApiClient/IWebClient.cs @@ -3,7 +3,7 @@ /* The MIT License (MIT) -Copyright (c) 2014 Gregoire Pailler +Copyright (c) 2015 Gregoire Pailler Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/MegaApiClient/JsonSerialization.cs b/MegaApiClient/JsonSerialization.cs index 243b874..819477d 100644 --- a/MegaApiClient/JsonSerialization.cs +++ b/MegaApiClient/JsonSerialization.cs @@ -1,473 +1,473 @@ -#region License - -/* -The MIT License (MIT) - -Copyright (c) 2014 Gregoire Pailler - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#endregion - -using System; -using System.Diagnostics; -using System.Linq; -using System.Runtime.Serialization; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace CG.Web.MegaApiClient -{ - - #region Base - - internal abstract class RequestBase - { - protected RequestBase(string action) - { - this.Action = action; - } - - [JsonProperty("a")] - public string Action { get; private set; } - } - - #endregion - - - #region Login - - internal class LoginRequest : RequestBase - { - public LoginRequest(string userHandle, string passwordHash) - : base("us") - { - this.UserHandle = userHandle; - this.PasswordHash = passwordHash; - } - - [JsonProperty("user")] - public string UserHandle { get; private set; } - - [JsonProperty("uh")] - public string PasswordHash { get; private set; } - } - - internal class LoginResponse - { - [JsonProperty("csid")] - public string SessionId { get; private set; } - - [JsonProperty("tsid")] - public string TemporarySessionId { get; private set; } - - [JsonProperty("privk")] - public string PrivateKey { get; private set; } - - [JsonProperty("k")] - public string MasterKey { get; private set; } - } - - internal class AnonymousLoginRequest : RequestBase - { - public AnonymousLoginRequest(string masterKey, string temporarySession) - : base("up") - { - this.MasterKey = masterKey; - this.TemporarySession = temporarySession; - } - - [JsonProperty("k")] - public string MasterKey { get; set; } - - [JsonProperty("ts")] - public string TemporarySession { get; set; } - } - - #endregion - - - #region Nodes - - internal class GetNodesRequest : RequestBase - { - public GetNodesRequest() - : base("f") - { - this.c = 1; - } - - public int c { get; private set; } - } - - internal class GetNodesResponse - { - public Node[] Nodes { get; private set; } - - [JsonProperty("f")] - public JRaw NodesSerialized { get; private set; } - - [JsonProperty("ok")] - public SharedKey[] SharedKeys { get; private set; } - - internal class SharedKey - { - [JsonProperty("h")] - public string Id { get; private set; } - - [JsonProperty("k")] - public string Key { get; private set; } - } - - [OnDeserialized] - public void OnDeserialized(StreamingContext ctx) - { - JsonSerializerSettings settings = new JsonSerializerSettings(); - settings.Context = new StreamingContext(StreamingContextStates.All, new [] { ctx.Context, this }); - - // For shared files/folders nodes, we need to retrieve SharedKeys. - // So we deserialize nodes in 2 steps - this.Nodes = JsonConvert.DeserializeObject(this.NodesSerialized.ToString(), settings); - } - } - - #endregion - - - #region Delete - - internal class DeleteRequest : RequestBase - { - public DeleteRequest(Node node) - : base("d") - { - this.Node = node.Id; - } - - [JsonProperty("n")] - public string Node { get; private set; } - } - - #endregion - - - #region Link - - internal class GetDownloadLinkRequest : RequestBase - { - public GetDownloadLinkRequest(Node node) - : base("l") - { - this.Id = node.Id; - } - - [JsonProperty("n")] - public string Id { get; private set; } - } - - #endregion - - - #region Create node - - internal class CreateNodeRequest : RequestBase - { - private CreateNodeRequest(Node parentNode, NodeType type, string attributes, string key, string completionHandle) - : base("p") - { - this.ParentId = parentNode.Id; - this.Nodes = new [] - { - new CreateNodeRequestData - { - Attributes = attributes, - Key = key, - Type = type, - CompletionHandle = completionHandle - } - }; - } - - public static CreateNodeRequest CreateFileNodeRequest(Node parentNode, string attributes, string key, string completionHandle) - { - return new CreateNodeRequest(parentNode, NodeType.File, attributes, key, completionHandle); - } - - public static CreateNodeRequest CreateFolderNodeRequest(Node parentNode, string attributes, string key) - { - return new CreateNodeRequest(parentNode, NodeType.Directory, attributes, key, "xxxxxxxx"); - } - - [JsonProperty("t")] - public string ParentId { get; private set; } - - [JsonProperty("n")] - public CreateNodeRequestData[] Nodes { get; private set; } - - internal class CreateNodeRequestData - { - [JsonProperty("h")] - public string CompletionHandle { get; set; } - - [JsonProperty("t")] - public NodeType Type { get; set; } - - [JsonProperty("a")] - public string Attributes { get; set; } - - [JsonProperty("k")] - public string Key { get; set; } - } - } - - #endregion - - - #region UploadRequest - - internal class UploadUrlRequest : RequestBase - { - public UploadUrlRequest(long fileSize) - : base("u") - { - this.Size = fileSize; - } - - [JsonProperty("s")] - public long Size { get; private set; } - } - - internal class UploadUrlResponse - { - [JsonProperty("p")] - public string Url { get; private set; } - } - - #endregion - - - #region DownloadRequest - - internal class DownloadUrlRequest : RequestBase - { - public DownloadUrlRequest(Node node) - : base("g") - { - this.Id = node.Id; - } - - public int g { get { return 1; } } - - [JsonProperty("n")] - public string Id { get; private set; } +#region License + +/* +The MIT License (MIT) + +Copyright (c) 2015 Gregoire Pailler + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#endregion + +using System; +using System.Diagnostics; +using System.Linq; +using System.Runtime.Serialization; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace CG.Web.MegaApiClient +{ + + #region Base + + internal abstract class RequestBase + { + protected RequestBase(string action) + { + this.Action = action; + } + + [JsonProperty("a")] + public string Action { get; private set; } + } + + #endregion + + + #region Login + + internal class LoginRequest : RequestBase + { + public LoginRequest(string userHandle, string passwordHash) + : base("us") + { + this.UserHandle = userHandle; + this.PasswordHash = passwordHash; + } + + [JsonProperty("user")] + public string UserHandle { get; private set; } + + [JsonProperty("uh")] + public string PasswordHash { get; private set; } + } + + internal class LoginResponse + { + [JsonProperty("csid")] + public string SessionId { get; private set; } + + [JsonProperty("tsid")] + public string TemporarySessionId { get; private set; } + + [JsonProperty("privk")] + public string PrivateKey { get; private set; } + + [JsonProperty("k")] + public string MasterKey { get; private set; } + } + + internal class AnonymousLoginRequest : RequestBase + { + public AnonymousLoginRequest(string masterKey, string temporarySession) + : base("up") + { + this.MasterKey = masterKey; + this.TemporarySession = temporarySession; + } + + [JsonProperty("k")] + public string MasterKey { get; set; } + + [JsonProperty("ts")] + public string TemporarySession { get; set; } + } + + #endregion + + + #region Nodes + + internal class GetNodesRequest : RequestBase + { + public GetNodesRequest() + : base("f") + { + this.c = 1; + } + + public int c { get; private set; } + } + + internal class GetNodesResponse + { + public Node[] Nodes { get; private set; } + + [JsonProperty("f")] + public JRaw NodesSerialized { get; private set; } + + [JsonProperty("ok")] + public SharedKey[] SharedKeys { get; private set; } + + internal class SharedKey + { + [JsonProperty("h")] + public string Id { get; private set; } + + [JsonProperty("k")] + public string Key { get; private set; } + } + + [OnDeserialized] + public void OnDeserialized(StreamingContext ctx) + { + JsonSerializerSettings settings = new JsonSerializerSettings(); + settings.Context = new StreamingContext(StreamingContextStates.All, new [] { ctx.Context, this }); + + // For shared files/folders nodes, we need to retrieve SharedKeys. + // So we deserialize nodes in 2 steps + this.Nodes = JsonConvert.DeserializeObject(this.NodesSerialized.ToString(), settings); + } + } + + #endregion + + + #region Delete + + internal class DeleteRequest : RequestBase + { + public DeleteRequest(Node node) + : base("d") + { + this.Node = node.Id; + } + + [JsonProperty("n")] + public string Node { get; private set; } + } + + #endregion + + + #region Link + + internal class GetDownloadLinkRequest : RequestBase + { + public GetDownloadLinkRequest(Node node) + : base("l") + { + this.Id = node.Id; + } + + [JsonProperty("n")] + public string Id { get; private set; } + } + + #endregion + + + #region Create node + + internal class CreateNodeRequest : RequestBase + { + private CreateNodeRequest(Node parentNode, NodeType type, string attributes, string key, string completionHandle) + : base("p") + { + this.ParentId = parentNode.Id; + this.Nodes = new [] + { + new CreateNodeRequestData + { + Attributes = attributes, + Key = key, + Type = type, + CompletionHandle = completionHandle + } + }; + } + + public static CreateNodeRequest CreateFileNodeRequest(Node parentNode, string attributes, string key, string completionHandle) + { + return new CreateNodeRequest(parentNode, NodeType.File, attributes, key, completionHandle); + } + + public static CreateNodeRequest CreateFolderNodeRequest(Node parentNode, string attributes, string key) + { + return new CreateNodeRequest(parentNode, NodeType.Directory, attributes, key, "xxxxxxxx"); + } + + [JsonProperty("t")] + public string ParentId { get; private set; } + + [JsonProperty("n")] + public CreateNodeRequestData[] Nodes { get; private set; } + + internal class CreateNodeRequestData + { + [JsonProperty("h")] + public string CompletionHandle { get; set; } + + [JsonProperty("t")] + public NodeType Type { get; set; } + + [JsonProperty("a")] + public string Attributes { get; set; } + + [JsonProperty("k")] + public string Key { get; set; } + } + } + + #endregion + + + #region UploadRequest + + internal class UploadUrlRequest : RequestBase + { + public UploadUrlRequest(long fileSize) + : base("u") + { + this.Size = fileSize; + } + + [JsonProperty("s")] + public long Size { get; private set; } + } + + internal class UploadUrlResponse + { + [JsonProperty("p")] + public string Url { get; private set; } + } + + #endregion + + + #region DownloadRequest + + internal class DownloadUrlRequest : RequestBase + { + public DownloadUrlRequest(Node node) + : base("g") + { + this.Id = node.Id; + } + + public int g { get { return 1; } } + + [JsonProperty("n")] + public string Id { get; private set; } + } + + internal class DownloadUrlRequestFromId : RequestBase + { + public DownloadUrlRequestFromId(string id) + : base("g") + { + this.Id = id; + } + + public int g { get { return 1; } } + + [JsonProperty("p")] + public string Id { get; private set; } + } + + internal class DownloadUrlResponse + { + [JsonProperty("g")] + public string Url { get; private set; } + + [JsonProperty("s")] + public long Size { get; private set; } + + [JsonProperty("at")] + private string SerializedAttributes { get; set; } + } + + #endregion + + + #region Move + + internal class MoveRequest : RequestBase + { + public MoveRequest(Node node, Node destinationParentNode) + : base("m") + { + this.Id = node.Id; + this.DestinationParentId = destinationParentNode.Id; + } + + [JsonProperty("n")] + public string Id { get; private set; } + + [JsonProperty("t")] + public string DestinationParentId { get; private set; } + } + + #endregion + + + #region Attributes + + internal class Attributes + { + public Attributes(string name) + { + this.Name = name; + } + + [JsonProperty("n")] + public string Name { get; set; } + } + + #endregion + + + #region Node + + [DebuggerDisplay("Type: {Type} - Name: {Name} - Id: {Id}")] + public class Node : IEquatable + { + private static readonly DateTime OriginalDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0); + + #region Public properties + + [JsonProperty("h")] + public string Id { get; private set; } + + [JsonProperty("p")] + public string ParentId { get; private set; } + + [JsonProperty("u")] + public string Owner { get; private set; } + + [JsonProperty("t")] + public NodeType Type { get; private set; } + + [JsonProperty("s")] + public long Size { get; private set; } + + [JsonIgnore] + public string Name { get; private set; } + + [JsonIgnore] + public DateTime LastModificationDate { get; private set; } + + [JsonIgnore] + internal byte[] DecryptedKey { get; private set; } + + [JsonIgnore] + internal byte[] Key { get; private set; } + + [JsonIgnore] + internal byte[] Iv { get; private set; } + + [JsonIgnore] + internal byte[] MetaMac { get; private set; } + + #endregion + + #region Deserialization + + [JsonProperty("ts")] + private long SerializedLastModificationDate { get; set; } + + [JsonProperty("a")] + private string SerializedAttributes { get; set; } + + [JsonProperty("k")] + private string SerializedKey { get; set; } + + [OnDeserialized] + public void OnDeserialized(StreamingContext ctx) + { + byte[] masterKey = (byte[])((object[])ctx.Context)[0]; + GetNodesResponse nodesResponse = (GetNodesResponse)((object[])ctx.Context)[1]; + + this.LastModificationDate = OriginalDateTime.AddSeconds(this.SerializedLastModificationDate).ToLocalTime(); + + if (this.Type == NodeType.File || this.Type == NodeType.Directory) + { + int splitPosition = this.SerializedKey.IndexOf(":", StringComparison.InvariantCulture); + byte[] encryptedKey = this.SerializedKey.Substring(splitPosition + 1).FromBase64(); + + this.DecryptedKey = Crypto.DecryptKey(encryptedKey, masterKey); + this.Key = this.DecryptedKey; + + // If node is shared, we need to retrieve shared masterkey + if (nodesResponse.SharedKeys != null) + { + string owner = this.SerializedKey.Substring(0, splitPosition); + GetNodesResponse.SharedKey sharedKey = nodesResponse.SharedKeys.FirstOrDefault(x => x.Id == owner); + if (sharedKey != null) + { + masterKey = Crypto.DecryptKey(sharedKey.Key.FromBase64(), masterKey); + + if (this.Type == NodeType.Directory) + { + this.DecryptedKey = masterKey; + } + + this.Key = Crypto.DecryptKey(encryptedKey, masterKey); + } + } + + if (this.Type == NodeType.File) + { + byte[] iv, metaMac, fileKey; + Crypto.GetPartsFromDecryptedKey(this.DecryptedKey, out iv, out metaMac, out fileKey); + + this.Iv = iv; + this.MetaMac = metaMac; + this.Key = fileKey; + } + + Attributes attributes = Crypto.DecryptAttributes(this.SerializedAttributes.FromBase64(), this.Key); + this.Name = attributes.Name; + } + } + + #endregion + + #region Equality + + public bool Equals(Node other) + { + return other != null && this.Id == other.Id; + } + + #endregion + } + + public enum NodeType + { + File = 0, + Directory, + Root, + Inbox, + Trash } - internal class DownloadUrlRequestFromId : RequestBase - { - public DownloadUrlRequestFromId(string id) - : base("g") - { - this.Id = id; - } - - public int g { get { return 1; } } - - [JsonProperty("p")] - public string Id { get; private set; } - } - - internal class DownloadUrlResponse - { - [JsonProperty("g")] - public string Url { get; private set; } - - [JsonProperty("s")] - public long Size { get; private set; } - - [JsonProperty("at")] - private string SerializedAttributes { get; set; } - } - - #endregion - - - #region Move - - internal class MoveRequest : RequestBase - { - public MoveRequest(Node node, Node destinationParentNode) - : base("m") - { - this.Id = node.Id; - this.DestinationParentId = destinationParentNode.Id; - } - - [JsonProperty("n")] - public string Id { get; private set; } - - [JsonProperty("t")] - public string DestinationParentId { get; private set; } - } - - #endregion - - - #region Attributes - - internal class Attributes - { - public Attributes(string name) - { - this.Name = name; - } - - [JsonProperty("n")] - public string Name { get; set; } - } - - #endregion - - - #region Node - - [DebuggerDisplay("Type: {Type} - Name: {Name} - Id: {Id}")] - public class Node : IEquatable - { - private static readonly DateTime OriginalDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0); - - #region Public properties - - [JsonProperty("h")] - public string Id { get; private set; } - - [JsonProperty("p")] - public string ParentId { get; private set; } - - [JsonProperty("u")] - public string Owner { get; private set; } - - [JsonProperty("t")] - public NodeType Type { get; private set; } - - [JsonProperty("s")] - public long Size { get; private set; } - - [JsonIgnore] - public string Name { get; private set; } - - [JsonIgnore] - public DateTime LastModificationDate { get; private set; } - - [JsonIgnore] - internal byte[] DecryptedKey { get; private set; } - - [JsonIgnore] - internal byte[] Key { get; private set; } - - [JsonIgnore] - internal byte[] Iv { get; private set; } - - [JsonIgnore] - internal byte[] MetaMac { get; private set; } - - #endregion - - #region Deserialization - - [JsonProperty("ts")] - private long SerializedLastModificationDate { get; set; } - - [JsonProperty("a")] - private string SerializedAttributes { get; set; } - - [JsonProperty("k")] - private string SerializedKey { get; set; } - - [OnDeserialized] - public void OnDeserialized(StreamingContext ctx) - { - byte[] masterKey = (byte[])((object[])ctx.Context)[0]; - GetNodesResponse nodesResponse = (GetNodesResponse)((object[])ctx.Context)[1]; - - this.LastModificationDate = OriginalDateTime.AddSeconds(this.SerializedLastModificationDate).ToLocalTime(); - - if (this.Type == NodeType.File || this.Type == NodeType.Directory) - { - int splitPosition = this.SerializedKey.IndexOf(":", StringComparison.InvariantCulture); - byte[] encryptedKey = this.SerializedKey.Substring(splitPosition + 1).FromBase64(); - - this.DecryptedKey = Crypto.DecryptKey(encryptedKey, masterKey); - this.Key = this.DecryptedKey; - - // If node is shared, we need to retrieve shared masterkey - if (nodesResponse.SharedKeys != null) - { - string owner = this.SerializedKey.Substring(0, splitPosition); - GetNodesResponse.SharedKey sharedKey = nodesResponse.SharedKeys.FirstOrDefault(x => x.Id == owner); - if (sharedKey != null) - { - masterKey = Crypto.DecryptKey(sharedKey.Key.FromBase64(), masterKey); - - if (this.Type == NodeType.Directory) - { - this.DecryptedKey = masterKey; - } - - this.Key = Crypto.DecryptKey(encryptedKey, masterKey); - } - } - - if (this.Type == NodeType.File) - { - byte[] iv, metaMac, fileKey; - Crypto.GetPartsFromDecryptedKey(this.DecryptedKey, out iv, out metaMac, out fileKey); - - this.Iv = iv; - this.MetaMac = metaMac; - this.Key = fileKey; - } - - Attributes attributes = Crypto.DecryptAttributes(this.SerializedAttributes.FromBase64(), this.Key); - this.Name = attributes.Name; - } - } - - #endregion - - #region Equality - - public bool Equals(Node other) - { - return other != null && this.Id == other.Id; - } - - #endregion - } - - public enum NodeType - { - File = 0, - Directory, - Root, - Inbox, - Trash - } - - #endregion -} + #endregion +} diff --git a/MegaApiClient/MegaAesCtrStream.cs b/MegaApiClient/MegaAesCtrStream.cs index 4b9ad91..fe8470a 100644 --- a/MegaApiClient/MegaAesCtrStream.cs +++ b/MegaApiClient/MegaAesCtrStream.cs @@ -3,7 +3,7 @@ /* The MIT License (MIT) -Copyright (c) 2014 Gregoire Pailler +Copyright (c) 2015 Gregoire Pailler Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/MegaApiClient/MegaApiClient.cs b/MegaApiClient/MegaApiClient.cs index 28a8452..49a8f31 100644 --- a/MegaApiClient/MegaApiClient.cs +++ b/MegaApiClient/MegaApiClient.cs @@ -3,7 +3,7 @@ /* The MIT License (MIT) -Copyright (c) 2014 Gregoire Pailler +Copyright (c) 2015 Gregoire Pailler Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/MegaApiClient/WebClient.cs b/MegaApiClient/WebClient.cs index f72e9f1..3d0ae14 100644 --- a/MegaApiClient/WebClient.cs +++ b/MegaApiClient/WebClient.cs @@ -3,7 +3,7 @@ /* The MIT License (MIT) -Copyright (c) 2014 Gregoire Pailler +Copyright (c) 2015 Gregoire Pailler Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in