/// <summary> /// Creates CAN IPNS record object to point to a CAN object of the given hash with the given sequence number. /// </summary> /// <param name="Hash">Hash of the CAN object to point IPNS record to.</param> /// <param name="SequenceNumber">Sequence number of the IPNS record.</param> /// <param name="ExpirationTimeSeconds">Expiration time of the newly created record in seconds.</param> /// <returns>Valid signed CAN IPNS record object, ready to be sent to CAN server.</returns> public static CanIpnsEntry CreateIpnsRecord(byte[] Hash, UInt64 SequenceNumber, int ExpirationTimeSeconds) { log.Trace("(Hash:'{0}',SequenceNumber:{1},ExpirationTimeSeconds:{2})", Hash.ToBase58(), SequenceNumber, ExpirationTimeSeconds); string validityString = DateTime.UtcNow.AddMonths(1).ToString(Rfc3339DateTimeFormat, DateTimeFormatInfo.InvariantInfo); byte[] validityBytes = Encoding.UTF8.GetBytes(validityString); UInt64 ttlNanoSec = (UInt64)(TimeSpan.FromSeconds(ExpirationTimeSeconds).TotalMilliseconds) * (UInt64)1000000; string valueString = CanApi.CreateIpfsPathFromHash(Hash); byte[] valueBytes = Encoding.UTF8.GetBytes(valueString); CanIpnsEntry res = new CanIpnsEntry() { Sequence = SequenceNumber, ValidityType = CanIpnsEntry.Types.ValidityType.Eol, Ttl = ttlNanoSec, Validity = ProtocolHelper.ByteArrayToByteString(validityBytes), Value = ProtocolHelper.ByteArrayToByteString(valueBytes) }; res.Signature = ProtocolHelper.ByteArrayToByteString(CreateIpnsRecordSignature(res)); log.Trace("(-):{0}", res); return(res); }
/// <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); }
/// <summary> /// Deletes CAN object from CAN server. /// </summary> /// <param name="ObjectHash">CAN object hash.</param> /// <returns>Structure describing whether the function succeeded and response provided by CAN server.</returns> public async Task <CanDeleteResult> CanDeleteObjectByHash(byte[] ObjectHash) { string objectPath = CanApi.CreateIpfsPathFromHash(ObjectHash); return(await CanDeleteObject(objectPath)); }