Exemple #1
0
        /// <summary>
        /// Creates a new object based on a result from CAN API including validation checks.
        /// </summary>
        /// <param name="ApiResult">CAN API result object to copy values from.</param>
        /// <returns>Structure describing result of CAN IPNS refresh operation.</returns>
        public static CanRefreshIpnsResult FromApiResult(CanApiResult ApiResult)
        {
            log.Trace("()");

            CanRefreshIpnsResult res = new CanRefreshIpnsResult(ApiResult);

            if (res.Success)
            {
                bool error = false;
                try
                {
                    CanRefreshIpnsResponse response = JsonConvert.DeserializeObject <CanRefreshIpnsResponse>(res.DataStr);
                    res.Details = response;
                }
                catch (Exception e)
                {
                    log.Error("Exception occurred: {0}", e.ToString());
                    error = true;
                }

                if (error)
                {
                    res.Success    = false;
                    res.Message    = "Invalid CAN response.";
                    res.IsCanError = false;
                }
            }

            log.Trace("(-)");
            return(res);
        }
Exemple #2
0
 /// <summary>
 /// Creates an instance of the object as a copy of another existing instance.
 /// </summary>
 /// <param name="ApiResult">Existing instance to copy.</param>
 public CanApiResult(CanApiResult ApiResult)
 {
     Success    = ApiResult.Success;
     Data       = ApiResult.Data;
     DataStr    = ApiResult.DataStr;
     Message    = ApiResult.Message;
     IsCanError = ApiResult.IsCanError;
 }
Exemple #3
0
        /// <summary>
        /// Deletes CAN object from CAN server.
        /// </summary>
        /// <param name="ObjectPath">CAN path to the object.</param>
        /// <returns>Structure describing whether the function succeeded and response provided by CAN server.</returns>
        public async Task <CanDeleteResult> CanDeleteObject(string ObjectPath)
        {
            log.Trace("(ObjectPath:'{0}')", ObjectPath);

            NameValueCollection args = new NameValueCollection();

            args.Add("arg", ObjectPath);
            CanApiResult apiResult = await SendRequest("pin/rm", args);

            CanDeleteResult res = CanDeleteResult.FromApiResult(apiResult);

            log.Trace("(-):{0}", res);
            return(res);
        }
Exemple #4
0
        /// <summary>
        /// Uploads CAN object to CAN server.
        /// </summary>
        /// <param name="ObjectData">CAN object to upload.</param>
        /// <returns>Structure describing whether the function succeeded and response provided by CAN server.</returns>
        public async Task <CanUploadResult> CanUploadObject(byte[] ObjectData)
        {
            log.Trace("(ObjectData.Length:{0})", ObjectData.Length);

            CanApiResult apiResult = await SendRequest("add", new NameValueCollection(), "file", "object", ObjectData);

            CanUploadResult res = CanUploadResult.FromApiResult(apiResult);

            if (res.Success)
            {
                log.Trace("(-):*.Success={0},*.Hash='{1}'", res.Success, res.Hash.ToBase58());
            }
            else
            {
                log.Trace("(-):*.Success={0},*.Message='{1}'", res.Success, res.Message);
            }
            return(res);
        }
Exemple #5
0
        /// <summary>
        /// Creates a new object based on a result from CAN API including validation checks.
        /// </summary>
        /// <param name="ApiResult">CAN API result object to copy values from.</param>
        /// <returns>Structure describing result of CAN upload operation.</returns>
        public static CanUploadResult FromApiResult(CanApiResult ApiResult)
        {
            log.Trace("()");

            CanUploadResult res = new CanUploadResult(ApiResult);

            if (res.Success)
            {
                bool error = false;
                try
                {
                    CanUploadObjectResponse response = JsonConvert.DeserializeObject <CanUploadObjectResponse>(res.DataStr);
                    if (!string.IsNullOrEmpty(response.Hash))
                    {
                        res.Hash = Base58Encoding.Encoder.DecodeRaw(response.Hash);
                        if (res.Hash == null)
                        {
                            log.Error("Unable to decode hash '{0}'.", response.Hash);
                            error = true;
                        }
                    }
                    else
                    {
                        log.Error("Empty hash in CAN response.");
                        error = true;
                    }
                }
                catch (Exception e)
                {
                    log.Error("Exception occurred: {0}", e.ToString());
                    error = true;
                }

                if (error)
                {
                    res.Success    = false;
                    res.Message    = "Invalid CAN response.";
                    res.IsCanError = false;
                }
            }

            log.Trace("(-)");
            return(res);
        }
Exemple #6
0
        /// <summary>
        /// Creates a new object based on a result from CAN API including validation checks.
        /// </summary>
        /// <param name="ApiResult">CAN API result object to copy values from.</param>
        /// <returns>Structure describing result of CAN upload operation.</returns>
        public static CanDeleteResult FromApiResult(CanApiResult ApiResult)
        {
            log.Trace("()");

            CanDeleteResult res = new CanDeleteResult(ApiResult);

            if (res.Success)
            {
                bool error = false;
                try
                {
                    CanDeleteObjectResponse response = JsonConvert.DeserializeObject <CanDeleteObjectResponse>(res.DataStr);
                    res.Pins = response.Pins;

                    // If the object was deleted previously, we might have empty Pins in response.
                    // We are thus OK if we receive success response and no more validation is done.
                }
                catch (Exception e)
                {
                    log.Error("Exception occurred: {0}", e.ToString());
                    error = true;
                }

                if (error)
                {
                    res.Success    = false;
                    res.Message    = "Invalid CAN response.";
                    res.IsCanError = false;
                }
            }
            else if (res.Message.ToLowerInvariant() == "not pinned")
            {
                res.Success = true;
                res.Pins    = null;
            }

            log.Trace("(-)");
            return(res);
        }
Exemple #7
0
 /// <summary>
 /// Creates delete result from generic API result.
 /// </summary>
 /// <param name="ApiResult">Existing instance to copy.</param>
 public CanRefreshIpnsResult(CanApiResult ApiResult) :
     base(ApiResult)
 {
 }
Exemple #8
0
        /// <summary>
        /// Sends HTTP POST request to CAN server.
        /// </summary>
        /// <param name="Action">Specifies the API function to call.</param>
        /// <param name="Params">List of parameters and their values.</param>
        /// <param name="FileToUploadParamName">Name of the file parameter, or null if no file is being uploaded.</param>
        /// <param name="FileToUploadName">Name of the file being uploaded, or null if no file is being uploaded.</param>
        /// <param name="FileToUploadData">Binary data of the file being uploaded, or null if no file is being uploaded.</param>
        /// <returns>Structure describing whether the function succeeded and response provided by CAN server.</returns>
        private async Task <CanApiResult> SendRequest(string Action, NameValueCollection Params, string FileToUploadParamName = null, string FileToUploadName = null, byte[] FileToUploadData = null)
        {
            log.Trace("(Action:'{0}',FileToUploadParamName:'{1}')", Action, FileToUploadParamName);

            CanApiResult res = new CanApiResult();

            string query = "";

            foreach (string key in Params)
            {
                query += string.Format("{0}{1}={2}", query.Length > 0 ? "&" : "", WebUtility.HtmlEncode(key), WebUtility.HtmlEncode(Params[key]));
            }

            string url = string.Format("{0}{1}{2}{3}", apiUrl, Action, query.Length > 0 ? "?" : "", query);

            log.Debug("CAN API URL is '{0}'.", url);

            try
            {
                using (HttpClient client = new HttpClient())
                {
                    client.Timeout = TimeSpan.FromSeconds(20);

                    byte[] boundaryBytes = new byte[16];
                    Crypto.Rng.GetBytes(boundaryBytes);
                    string boundary = string.Format("------------------------{0}", boundaryBytes.ToHex().ToLowerInvariant());

                    using (MultipartFormDataContent content = new MultipartFormDataContent(boundary))
                    {
                        if (FileToUploadParamName != null)
                        {
                            ByteArrayContent fileContent = new ByteArrayContent(FileToUploadData);
                            fileContent.Headers.Add("Content-Type", "application/octet-stream");
                            fileContent.Headers.Add("Content-Disposition", string.Format("form-data; name=\"{0}\"; filename = \"{1}\"", FileToUploadParamName, FileToUploadName));
                            content.Add(fileContent, FileToUploadParamName, FileToUploadName);
                        }

                        using (HttpResponseMessage message = await client.PostAsync(url, content, shutdownSignaling.ShutdownCancellationTokenSource.Token))
                        {
                            res.Success = message.IsSuccessStatusCode;
                            byte[] data = await message.Content.ReadAsByteArrayAsync();

                            string dataStr = null;
                            try
                            {
                                dataStr = Encoding.UTF8.GetString(data);
                            }
                            catch
                            {
                            }

                            if (res.Success)
                            {
                                res.Data    = data;
                                res.DataStr = dataStr;
                            }
                            else
                            {
                                try
                                {
                                    dataStr = Encoding.UTF8.GetString(data);
                                    CanErrorResponse cer = JsonConvert.DeserializeObject <CanErrorResponse>(dataStr);
                                    res.Message = cer.Message;
                                }
                                catch
                                {
                                    res.Message = dataStr != null ? dataStr : "Invalid response.";
                                }
                                res.IsCanError = true;
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                if (e is OperationCanceledException)
                {
                    log.Debug("Shutdown detected.");
                    res.IsCanError = false;
                    res.Message    = "Shutdown";
                }
                else
                {
                    log.Warn("Exception occurred: {0}", e.Message);
                }
            }

            if (res.Success)
            {
                log.Trace("(-):*.Success={0},*.Data:\n{1}", res.Success, res.DataStr != null ? res.DataStr.SubstrMax() : "n/a");
            }
            else
            {
                log.Trace("(-):*.Success={0},*.IsCanError={1},*.Message:\n{2}", res.Success, res.IsCanError, res.Message != null ? res.Message.SubstrMax(512) : "");
            }
            return(res);
        }
Exemple #9
0
 /// <summary>
 /// Creates delete result from generic API result.
 /// </summary>
 /// <param name="ApiResult">Existing instance to copy.</param>
 public CanDeleteResult(CanApiResult ApiResult) :
     base(ApiResult)
 {
 }
Exemple #10
0
 /// <summary>
 /// Creates upload result from generic API result.
 /// </summary>
 /// <param name="ApiResult">Existing instance to copy.</param>
 public CanUploadResult(CanApiResult ApiResult) :
     base(ApiResult)
 {
 }
Exemple #11
0
        /// <summary>
        /// Refreshes server's IPNS record in CAN.
        /// </summary>
        /// <param name="IpnsRecord">IPNS record to refresh.</param>
        /// <param name="PublicKey">Public key of the IPNS record owner.</param>
        /// <returns>Structure describing whether the function succeeded and response provided by CAN server.</returns>
        public async Task <CanRefreshIpnsResult> RefreshIpnsRecord(CanIpnsEntry IpnsRecord, byte[] PublicKey)
        {
            log.Trace("(PublicKey:'{0}')", PublicKey.ToHex());

            string ipnsRecordEncoded = IpnsRecord.ToByteArray().ToBase64UrlPad(true);

            CanCryptoKey cryptoKey = new CanCryptoKey()
            {
                Type = CanCryptoKey.Types.KeyType.Ed25519,
                Data = ProtocolHelper.ByteArrayToByteString(PublicKey)
            };
            string keyEncoded = Base58Encoding.Encoder.Encode(cryptoKey.ToByteArray());

            log.Debug("Encoding public key: {0}", keyEncoded);

            NameValueCollection args = new NameValueCollection();

            args.Add("arg", ipnsRecordEncoded);
            args.Add("key", keyEncoded);

            CanApiResult apiResult = await SendRequest("name/upload", args);

            CanRefreshIpnsResult res = CanRefreshIpnsResult.FromApiResult(apiResult);

            if (res.Success)
            {
                res.IsCanError = false;

                // Check that the ID, path and sequence number match what we expect.
                string canId = CanApi.PublicKeyToId(PublicKey).ToBase58();
                if (res.Details.Peer == canId)
                {
                    string path = Encoding.UTF8.GetString(IpnsRecord.Value.ToByteArray());
                    if (res.Details.NewPath == path)
                    {
                        if (res.Details.NewSeq == IpnsRecord.Sequence)
                        {
                            // All OK.
                        }
                        else
                        {
                            log.Warn("CAN sequence is {0}, received {1}.", IpnsRecord.Sequence, res.Details.NewSeq);
                            res.Success = false;
                            res.Message = "CAN path in response does not match expected value.";
                        }
                    }
                    else
                    {
                        log.Warn("CAN path is '{0}', received '{1}'.", path, res.Details.NewPath);
                        res.Success = false;
                        res.Message = "CAN path in response does not match expected value.";
                    }
                }
                else
                {
                    log.Warn("CAN ID is '{0}', received '{1}'.", canId, res.Details.Peer);
                    res.Success = false;
                    res.Message = "CAN ID in response does not match expected value.";
                }
            }

            if (res.Success)
            {
                log.Trace("(-):*.Success={0}", res.Success);
            }
            else
            {
                log.Trace("(-):*.Success={0},*.IsCanError={1},*.Message='{2}'", res.Success, res.IsCanError, res.Message);
            }
            return(res);
        }