├── GitVersionConfig.yaml
├── src
├── ipfs.dev.snk
├── ipfs.ci.snk.enc
├── IFileSystemLink.cs
├── ILinkedNode.cs
├── IFileSystemNode.cs
├── CoreApi
│ ├── TransferProgress.cs
│ ├── IDhtApi.cs
│ ├── PingResult.cs
│ ├── BandwidthData.cs
│ ├── ObjectStat.cs
│ ├── IPeerRouting.cs
│ ├── RepositoryData.cs
│ ├── BitswapData.cs
│ ├── IDnsApi.cs
│ ├── IStatsApi.cs
│ ├── BitswapLedger.cs
│ ├── IContentRouting.cs
│ ├── IValueStore.cs
│ ├── IBlockRepository.cs
│ ├── IPinApi.cs
│ ├── IConfigApi.cs
│ ├── AddFileOptions.cs
│ ├── IBootstrapApi.cs
│ ├── IBitswapApi.cs
│ ├── INameApi.cs
│ ├── ICoreApi.cs
│ ├── IPubSubApi.cs
│ ├── IKeyApi.cs
│ └── ISwarmApi.cs
├── NamedContent.cs
├── Base32z.cs
├── IKey.cs
├── Cryptography
│ ├── DoubleSha256.cs
│ ├── IdentityHash.cs
│ ├── BouncyDigest.cs
│ └── Keccak.cs
├── IMerkleLink.cs
├── ProtobufHelper.cs
├── IPublishedMessage.cs
├── IDataBlock.cs
├── IMerkleNode.cs
├── Base58.cs
├── Base64NoPad.cs
├── Base32.cs
├── IpfsCore.csproj
├── Base64Url.cs
├── MultiCodec.cs
├── MultiBase.cs
├── DagLink.cs
├── HexString.cs
└── Registry
│ └── Codec.cs
├── doc
├── api
│ └── .gitignore
├── images
│ ├── ipfs-favicon.ico
│ ├── ipfs-cs-logo-48x48.png
│ ├── ipfs-cs-logo-64x64.png
│ ├── docs-latest-green.svg
│ └── ipfs-logo.svg
├── toc.yml
├── Documentation.csproj
├── .gitignore
├── articles
│ ├── toc.yml
│ ├── multiaddress.md
│ ├── cid.md
│ ├── intro.md
│ ├── varint.md
│ ├── dag.md
│ ├── core-api.md
│ └── multihash.md
├── index.md
├── Properties
│ └── AssemblyInfo.cs
└── docfx.json
├── .codacy.yml
├── test
├── packages.config
├── NamedContentTest.cs
├── CoreApi
│ ├── PingResultTest.cs
│ ├── ObjectStatTest.cs
│ ├── BitswapLedgerTest.cs
│ └── AddFileOptionsTest.cs
├── App.config
├── IpfsCoreTests.csproj
├── ExceptionAssert.cs
├── Registry
│ ├── CodecTest.cs
│ ├── MultibaseAlgorithmTest.cs
│ └── HashingAlgorithmTest.cs
├── NetworkProtocolTest.cs
├── Base58Test.cs
├── HexStringTest.cs
├── Base32Test.cs
├── DagLinkTest.cs
├── DurationTest.cs
├── VarintTest.cs
└── PeerTest.cs
├── .travis.yml
├── Local.testsettings
├── IpfsCore.vsmdi
├── LICENSE
├── TraceAndTestImpact.testsettings
├── IpfsCore.sln
├── appveyor.yml
├── .gitignore
└── README.md
/GitVersionConfig.yaml:
--------------------------------------------------------------------------------
1 | mode: ContinuousDeployment
2 | next-version: 0.2.1
3 | branches: {}
4 |
--------------------------------------------------------------------------------
/src/ipfs.dev.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardschneider/net-ipfs-core/HEAD/src/ipfs.dev.snk
--------------------------------------------------------------------------------
/doc/api/.gitignore:
--------------------------------------------------------------------------------
1 | ###############
2 | # temp file #
3 | ###############
4 | *.yml
5 | .manifest
6 |
--------------------------------------------------------------------------------
/src/ipfs.ci.snk.enc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardschneider/net-ipfs-core/HEAD/src/ipfs.ci.snk.enc
--------------------------------------------------------------------------------
/.codacy.yml:
--------------------------------------------------------------------------------
1 | ---
2 | exclude_paths:
3 | - 'test/*'
4 | - 'test/**/*'
5 | - 'doc/*'
6 | - 'doc/**/*'
7 |
--------------------------------------------------------------------------------
/doc/images/ipfs-favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardschneider/net-ipfs-core/HEAD/doc/images/ipfs-favicon.ico
--------------------------------------------------------------------------------
/doc/images/ipfs-cs-logo-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardschneider/net-ipfs-core/HEAD/doc/images/ipfs-cs-logo-48x48.png
--------------------------------------------------------------------------------
/doc/images/ipfs-cs-logo-64x64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardschneider/net-ipfs-core/HEAD/doc/images/ipfs-cs-logo-64x64.png
--------------------------------------------------------------------------------
/test/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/doc/toc.yml:
--------------------------------------------------------------------------------
1 | - name: Articles
2 | href: articles/
3 | - name: Api Documentation
4 | href: api/
5 | - name: Github
6 | href: https://github.com/richardschneider/net-ipfs-core
7 |
--------------------------------------------------------------------------------
/doc/Documentation.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2
5 |
6 |
7 |
--------------------------------------------------------------------------------
/doc/.gitignore:
--------------------------------------------------------------------------------
1 | ###############
2 | # folder #
3 | ###############
4 | /**/DROP/
5 | /**/TEMP/
6 | /**/packages/
7 | /**/bin/
8 | /**/obj/
9 | _site
10 | log.txt
11 | msdn.4.5.2.zip
12 | namespaces.4.5.2.zip
13 |
14 |
--------------------------------------------------------------------------------
/src/IFileSystemLink.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Ipfs
6 | {
7 | ///
8 | /// A link to another file system node in IPFS.
9 | ///
10 | public interface IFileSystemLink : IMerkleLink
11 | {
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: csharp
2 | sudo: required
3 | mono: none
4 | dist: xenial
5 | dotnet: 3.0.100
6 | os:
7 | - linux
8 | - osx
9 |
10 | script:
11 | - dotnet restore
12 | - dotnet build -c Release --no-restore --framework netcoreapp3.0 ./src
13 | - dotnet test -c Release --no-restore --framework netcoreapp3.0 ./test
--------------------------------------------------------------------------------
/doc/articles/toc.yml:
--------------------------------------------------------------------------------
1 | - name: Introduction
2 | href: intro.md
3 | - name: Core API
4 | href: core-api.md
5 | - name: CID
6 | href: cid.md
7 | - name: Merkle DAG
8 | href: dag.md
9 | - name: MultiAddress
10 | href: multiaddress.md
11 | - name: MultiHash
12 | href: multihash.md
13 | - name: Varint
14 | href: varint.md
15 | - name: Class Reference
16 | href: ../api/Ipfs.yml
17 |
--------------------------------------------------------------------------------
/doc/articles/multiaddress.md:
--------------------------------------------------------------------------------
1 | # MultiAddress
2 |
3 | A standard way to represent a networks address that supports [multiple network protocols](xref:Ipfs.MultiAddress). It is represented as
4 | a series of tuples, a protocol code and an optional value. For example, an IPFS node at a sepcific address over ipv4 and tcp is
5 |
6 | /ip4/10.1.10.10/tcp/80/p2p/QmVcSqVEsvm5RR9mBLjwpb2XjFVn5bPdPL69mL8PH45pPC
7 |
8 |
--------------------------------------------------------------------------------
/Local.testsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 | These are default test settings for a local test run.
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/ILinkedNode.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Ipfs
6 | {
7 | ///
8 | /// InterPlanetary Linked Data.
9 | ///
10 | ///
11 | /// Not yet ready for prime time.
12 | ///
13 | ///
14 | public interface ILinkedNode : IMerkleNode
15 | {
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/IpfsCore.vsmdi:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/doc/articles/cid.md:
--------------------------------------------------------------------------------
1 | # Content ID
2 |
3 | A [Cid](xref:Ipfs.Cid) is a self-describing content-addressed identifier for distributed systems. It doesn't indicate *where*
4 | the content is stored, but it forms a kind of address based on the content itself.
5 |
6 | For background information, see [cid concept](https://docs.ipfs.io/guides/concepts/cid/).
7 |
8 | # Encoding
9 |
10 | In June 2019 the IPFS ecosystem switched from **base58btc** encoding
11 | to the case-insensitive **base32** encoding. This plays much
12 | better with DNS and URL based systems.
13 |
--------------------------------------------------------------------------------
/doc/articles/intro.md:
--------------------------------------------------------------------------------
1 | # IPFS Core
2 |
3 | The core objects and interfaces of the [IPFS](https://ipfs.io) (Inter Planetary File System) for .Net (C#, VB, F# etc.)
4 |
5 | The interplanetary file system is the permanent web. It is a new hypermedia distribution protocol, addressed by content and identities.
6 | IPFS enables the creation of completely distributed applications. It aims to make the web faster, safer, and more open.
7 |
8 | The source code is on [GitHub](https://github.com/richardschneider/net-ipfs-core) and the
9 | package is published on [NuGet](https://www.nuget.org/packages/Ipfs.Core).
10 |
--------------------------------------------------------------------------------
/doc/articles/varint.md:
--------------------------------------------------------------------------------
1 | # Variable Integer
2 |
3 | A [varint](xref:Ipfs.Varint) is used to encode a non-negative integer of up to 64 bits.
4 | It is encoded in network byte order (Big Endian). Each byte (except the last) contains 7 bits
5 | of information with the most significant bit set to 1. The last byte has the MSB set to 0.
6 |
7 | | Value | Varint encoding |
8 | | ----- | --------------- |
9 | | 1 (0x1) | 01 |
10 | | 16 (0x10) | 10 |
11 | | 256 (0x100) | 80 02 |
12 | | 4096 (0x1000) | 80 20 |
13 | | 65536 (0x10000) | 80 80 04 |
14 | | 1048576 (0x100000) | 80 80 40 |
15 | | 16777216 (0x1000000) | 80 80 80 08 |
16 |
--------------------------------------------------------------------------------
/src/IFileSystemNode.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Ipfs
6 | {
7 | ///
8 | /// A Directed Acyclic Graph (DAG) for IPFS file system node.
9 | ///
10 | public interface IFileSystemNode : IMerkleNode
11 | {
12 | ///
13 | /// Determines if the node is a directory (folder).
14 | ///
15 | ///
16 | /// true if the node is a directory; Otherwise false,
17 | /// it is some type of a file.
18 | ///
19 | bool IsDirectory { get; }
20 |
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/doc/index.md:
--------------------------------------------------------------------------------
1 | # IPFS Core
2 |
3 | The [core objects](api/Ipfs.yml) of the [Inter Planetary File System](https://ipfs.io/) (IPFS) for .Net (C#, VB, F# etc.)
4 | The source code is on [GitHub](https://github.com/richardschneider/net-ipfs-core) and the
5 | package on [NuGet](https://www.nuget.org/packages/Ipfs.Core).
6 |
7 | The interplanetary file system is the permanent web. It is a new hypermedia distribution protocol, addressed by content and identities. IPFS enables the creation of completely distributed applications. It aims to make the web faster, safer, and more open.
8 |
9 | - [Articles](articles/intro.md) on using the core objects
10 | - [API Documentation](api/Ipfs.yml) describes the core objects in detail
--------------------------------------------------------------------------------
/test/NamedContentTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using Microsoft.VisualStudio.TestTools.UnitTesting;
6 | using System.IO;
7 | using Google.Protobuf;
8 |
9 | namespace Ipfs
10 | {
11 | [TestClass]
12 | public class NamedContentTest
13 | {
14 | [TestMethod]
15 | public void Properties()
16 | {
17 | var nc = new NamedContent
18 | {
19 | ContentPath = "/ipfs/...",
20 | NamePath = "/ipns/..."
21 | };
22 | Assert.AreEqual("/ipfs/...", nc.ContentPath);
23 | Assert.AreEqual("/ipns/...", nc.NamePath);
24 | }
25 |
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/doc/images/docs-latest-green.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/CoreApi/PingResultTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Text;
4 | using Microsoft.VisualStudio.TestTools.UnitTesting;
5 |
6 | namespace Ipfs.CoreApi
7 | {
8 | [TestClass]
9 | public class PingResultTest
10 | {
11 | [TestMethod]
12 | public void Properties()
13 | {
14 | var time = TimeSpan.FromSeconds(3);
15 | var r = new PingResult
16 | {
17 | Success = true,
18 | Text = "ping",
19 | Time = time
20 | };
21 | Assert.AreEqual(true, r.Success);
22 | Assert.AreEqual("ping", r.Text);
23 | Assert.AreEqual(time, r.Time);
24 | }
25 |
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/test/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/CoreApi/TransferProgress.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Ipfs.CoreApi
6 | {
7 | ///
8 | /// Reports the progress of
9 | /// a transfer operation.
10 | ///
11 | public class TransferProgress
12 | {
13 | ///
14 | /// The name of the item being trasfered.
15 | ///
16 | ///
17 | /// Typically, a relative file path.
18 | ///
19 | public string Name;
20 |
21 | ///
22 | /// The cumuative number of bytes transfered for
23 | /// the .
24 | ///
25 | public ulong Bytes;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/NamedContent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Ipfs
6 | {
7 | ///
8 | /// Content that has an associated name.
9 | ///
10 | ///
11 | public class NamedContent
12 | {
13 | ///
14 | /// Path to the name.
15 | ///
16 | ///
17 | /// Typically /ipns/....
18 | ///
19 | public string NamePath { get; set; }
20 |
21 | ///
22 | /// Path to the content.
23 | ///
24 | ///
25 | /// Typically /ipfs/....
26 | ///
27 | public string ContentPath { get; set; }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/CoreApi/IDhtApi.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace Ipfs.CoreApi
8 | {
9 | ///
10 | /// Manages the Distributed Hash Table.
11 | ///
12 | ///
13 | /// The DHT is a place to store, not the value, but pointers to peers who have
14 | /// the actual value.
15 | ///
16 | /// See the ongoing DHT specification at
17 | ///
18 | ///
19 | /// DHT API spec
20 | public interface IDhtApi : IPeerRouting, IContentRouting, IValueStore
21 | {
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/CoreApi/PingResult.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Ipfs.CoreApi
6 | {
7 | ///
8 | /// The result from sending a .
9 | ///
10 | public class PingResult
11 | {
12 | ///
13 | /// Indicates success or failure.
14 | ///
15 | public bool Success { get; set; }
16 |
17 | ///
18 | /// The round trip time; nano second resolution.
19 | ///
20 | public TimeSpan Time { get; set; }
21 |
22 | ///
23 | /// The text to echo.
24 | ///
25 | public string Text { get; set; }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Base32z.cs:
--------------------------------------------------------------------------------
1 | using SimpleBase;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace Ipfs
7 | {
8 | ///
9 | /// Base32 encoding designed to be easier for human use and more compact.
10 | ///
11 | ///
12 | /// Commonly referred to as 'z-base-32'.
13 | ///
14 | ///
15 | public static class Base32z
16 | {
17 | static readonly Base32Alphabet alphabet =
18 | new Base32Alphabet("ybndrfg8ejkmcpqxot1uwisza345h769");
19 |
20 | ///
21 | /// The encoder/decoder for z-base-32.
22 | ///
23 | public static readonly SimpleBase.Base32 Codec = new SimpleBase.Base32(alphabet);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/CoreApi/BandwidthData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Ipfs.CoreApi
6 | {
7 | ///
8 | /// The statistics for .
9 | ///
10 | public class BandwidthData
11 | {
12 | ///
13 | /// The number of bytes received.
14 | ///
15 | public ulong TotalIn;
16 |
17 | ///
18 | /// The number of bytes sent.
19 | ///
20 | public ulong TotalOut;
21 |
22 | ///
23 | /// TODO
24 | ///
25 | public double RateIn;
26 |
27 | ///
28 | /// TODO
29 | ///
30 | public double RateOut;
31 |
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/IKey.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Ipfs
6 | {
7 | ///
8 | /// Information about a cryptographic key.
9 | ///
10 | public interface IKey
11 | {
12 | ///
13 | /// Unique identifier.
14 | ///
15 | ///
16 | /// The of the key's public key.
17 | ///
18 | MultiHash Id { get; }
19 |
20 | ///
21 | /// The locally assigned name to the key.
22 | ///
23 | ///
24 | /// The name is only unique within the local peer node. The
25 | /// is universally unique.
26 | ///
27 | string Name { get; }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/test/CoreApi/ObjectStatTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Text;
4 | using Microsoft.VisualStudio.TestTools.UnitTesting;
5 |
6 | namespace Ipfs.CoreApi
7 | {
8 | [TestClass]
9 | public class ObjectStatTest
10 | {
11 | [TestMethod]
12 | public void Properties()
13 | {
14 | var stat = new ObjectStat
15 | {
16 | BlockSize = 1,
17 | CumulativeSize = 2,
18 | DataSize = 3,
19 | LinkCount = 4,
20 | LinkSize = 5
21 | };
22 | Assert.AreEqual(1, stat.BlockSize);
23 | Assert.AreEqual(2, stat.CumulativeSize);
24 | Assert.AreEqual(3, stat.DataSize);
25 | Assert.AreEqual(4, stat.LinkCount);
26 | Assert.AreEqual(5, stat.LinkSize);
27 | }
28 |
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Cryptography/DoubleSha256.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Security.Cryptography;
4 | using System.Text;
5 |
6 | namespace Ipfs.Cryptography
7 | {
8 | class DoubleSha256 : HashAlgorithm
9 | {
10 | HashAlgorithm digest = SHA256.Create();
11 | byte[] round1;
12 |
13 | public override void Initialize()
14 | {
15 | digest.Initialize();
16 | round1 = null;
17 | }
18 |
19 | public override int HashSize => digest.HashSize;
20 |
21 | protected override void HashCore(byte[] array, int ibStart, int cbSize)
22 | {
23 | if (round1 != null)
24 | throw new NotSupportedException("Already called.");
25 |
26 | round1 = digest.ComputeHash(array, ibStart, cbSize);
27 | }
28 |
29 | protected override byte[] HashFinal()
30 | {
31 | digest.Initialize();
32 | return digest.ComputeHash(round1);
33 | }
34 |
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/IMerkleLink.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace Ipfs
3 | {
4 |
5 | ///
6 | /// A link to another node in IPFS.
7 | ///
8 | public interface IMerkleLink
9 | {
10 |
11 | ///
12 | /// A name associated with the linked node.
13 | ///
14 | /// A or null.
15 | ///
16 | ///
17 | /// IPFS considers a null name different from a
18 | /// name;
19 | ///
20 | ///
21 | string Name { get; }
22 |
23 | ///
24 | /// The unique ID of the link.
25 | ///
26 | ///
27 | /// A of the content.
28 | ///
29 | Cid Id { get; }
30 |
31 | ///
32 | /// The serialised size (in bytes) of the linked node.
33 | ///
34 | /// Number of bytes.
35 | long Size { get; }
36 |
37 | }
38 | }
--------------------------------------------------------------------------------
/src/CoreApi/ObjectStat.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Ipfs.CoreApi
6 | {
7 | ///
8 | /// Information on a DAG node.
9 | ///
10 | ///
11 | public class ObjectStat
12 | {
13 | ///
14 | /// Number of links.
15 | ///
16 | public int LinkCount { get; set; }
17 |
18 | ///
19 | /// Size of the links segment.
20 | ///
21 | public long LinkSize { get; set; }
22 |
23 | ///
24 | /// Size of the raw, encoded data.
25 | ///
26 | public long BlockSize { get; set; }
27 |
28 | ///
29 | /// Siz of the data segment.
30 | ///
31 | public long DataSize { get; set; }
32 |
33 | ///
34 | /// Size of object and its references
35 | ///
36 | public long CumulativeSize { get; set; }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Cryptography/IdentityHash.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Security.Cryptography;
4 | using System.Text;
5 |
6 | namespace Ipfs.Cryptography
7 | {
8 | class IdentityHash : HashAlgorithm
9 | {
10 | byte[] digest;
11 |
12 | public override void Initialize()
13 | {
14 | }
15 |
16 | protected override void HashCore(byte[] array, int ibStart, int cbSize)
17 | {
18 | if (digest == null)
19 | {
20 | digest = new byte[cbSize];
21 | Buffer.BlockCopy(array, ibStart, digest, 0, cbSize);
22 | return;
23 | }
24 |
25 | var buffer = new byte[digest.Length + cbSize];
26 | Buffer.BlockCopy(digest, 0, buffer, digest.Length, digest.Length);
27 | Buffer.BlockCopy(array, ibStart, digest, digest.Length, cbSize);
28 | digest = buffer;
29 | }
30 |
31 | protected override byte[] HashFinal()
32 | {
33 | return digest;
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Richard Schneider
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/test/IpfsCoreTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net45;netcoreapp1.1;netcoreapp2.1;netcoreapp3.0
5 |
6 | false
7 | portable
8 | Ipfs
9 |
10 |
11 |
12 |
13 |
14 | false
15 | opencover
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/ProtobufHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using Google.Protobuf;
8 |
9 | namespace Ipfs
10 | {
11 | static class ProtobufHelper
12 | {
13 | static MethodInfo writeRawBytes = typeof(CodedOutputStream)
14 | .GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
15 | .Single(m =>
16 | m.Name == "WriteRawBytes" && m.GetParameters().Count() == 1
17 | );
18 | static MethodInfo readRawBytes = typeof(CodedInputStream)
19 | .GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
20 | .Single(m =>
21 | m.Name == "ReadRawBytes"
22 | );
23 |
24 | public static void WriteSomeBytes(this CodedOutputStream stream, byte[] bytes)
25 | {
26 | writeRawBytes.Invoke(stream, new object[] { bytes });
27 | }
28 |
29 | public static byte[] ReadSomeBytes(this CodedInputStream stream, int length)
30 | {
31 | return (byte[])readRawBytes.Invoke(stream, new object[] { length });
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/CoreApi/IPeerRouting.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 |
5 | namespace Ipfs.CoreApi
6 | {
7 | ///
8 | /// Find information about a peer.
9 | ///
10 | ///
11 | /// No IPFS documentation is currently available. See the
12 | /// code.
13 | ///
14 | public interface IPeerRouting
15 | {
16 | ///
17 | /// Information about an IPFS peer.
18 | ///
19 | ///
20 | /// The ID of the IPFS peer.
21 | ///
22 | ///
23 | /// Is used to stop the task. When cancelled, the is NOT raised.
24 | ///
25 | ///
26 | /// A task that represents the asynchronous operation that returns
27 | /// the information or a closer peer.
28 | ///
29 | Task FindPeerAsync(MultiHash id, CancellationToken cancel = default(CancellationToken));
30 |
31 | }
32 | }
33 |
34 |
--------------------------------------------------------------------------------
/src/IPublishedMessage.cs:
--------------------------------------------------------------------------------
1 | using Ipfs.CoreApi;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace Ipfs
7 | {
8 | ///
9 | /// A published message.
10 | ///
11 | ///
12 | /// The is used to publish and subsribe to a message.
13 | ///
14 | public interface IPublishedMessage : IDataBlock
15 | {
16 | ///
17 | /// The sender of the message.
18 | ///
19 | ///
20 | /// The peer that sent the message.
21 | ///
22 | Peer Sender { get; }
23 |
24 | ///
25 | /// The topics of the message.
26 | ///
27 | ///
28 | /// All topics related to this message.
29 | ///
30 | IEnumerable Topics { get; }
31 |
32 | ///
33 | /// The sequence number of the message.
34 | ///
35 | ///
36 | /// A sender unique id for the message.
37 | ///
38 | byte[] SequenceNumber { get; }
39 |
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/doc/articles/dag.md:
--------------------------------------------------------------------------------
1 | # Merkle DAG
2 |
3 | The [DagNode](xref:Ipfs.DagNode) is a directed acyclic graph whose edges are a
4 | [DagLink](xref:Ipfs.DagLink). This means that links to objects can authenticate
5 | the objects themselves, and that every object contains a secure
6 | representation of its children.
7 |
8 | Every Merkle node is a directed acyclic graph (DAG) because each child node is accessed via its [CID](cid.md),
9 | basically the [hash](multihash.md) of the child's dag node. It's [ID](xref:Ipfs.DagNode.Id)
10 | is the hash of its local content ([data](xref:Ipfs.DagNode.DataBytes) and [links](xref:Ipfs.DagNode.Links)).
11 | So after creation there is no way to edit a DagNode. This prevents cycles (assuming there are no hash collisions)
12 | since one can not link the first created node to the last node to create the last reference.
13 |
14 | ```csharp
15 | var a = Encoding.UTF8.GetBytes("a");
16 | var anode = new DagNode(a);
17 | var alink = anode.ToLink("a");
18 |
19 | var b = Encoding.UTF8.GetBytes("b");
20 | var bnode = new DagNode(b);
21 | var blink = bnode.ToLink("b");
22 |
23 | var node = new DagNode(null, new[] { alink, blink });
24 | Assert.AreEqual(2, node.Links.Count());
25 | Assert.AreEqual("QmbNgNPPykP4YTuAeSa3DsnBJWLVxccrqLUZDPNQfizGKs", (string)node.Id);
26 | ```
27 |
--------------------------------------------------------------------------------
/test/CoreApi/BitswapLedgerTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Text;
4 | using Microsoft.VisualStudio.TestTools.UnitTesting;
5 |
6 | namespace Ipfs.CoreApi
7 | {
8 | [TestClass]
9 | public class BitswapLedgerTest
10 | {
11 | [TestMethod]
12 | public void Defaults()
13 | {
14 | var ledger = new BitswapLedger();
15 | Assert.IsNull(ledger.Peer);
16 | Assert.AreEqual(0ul, ledger.BlocksExchanged);
17 | Assert.AreEqual(0ul, ledger.DataReceived);
18 | Assert.AreEqual(0ul, ledger.DataSent);
19 | Assert.AreEqual(0f, ledger.DebtRatio);
20 | Assert.IsTrue(ledger.IsInDebt);
21 | }
22 |
23 | [TestMethod]
24 | public void DebtRatio_Positive()
25 | {
26 | var ledger = new BitswapLedger { DataSent = 1024 * 1024 };
27 | Assert.IsTrue(ledger.DebtRatio >= 1);
28 | Assert.IsFalse(ledger.IsInDebt);
29 | }
30 |
31 | [TestMethod]
32 | public void DebtRatio_Negative()
33 | {
34 | var ledger = new BitswapLedger { DataReceived = 1024 * 1024 };
35 | Assert.IsTrue(ledger.DebtRatio < 1);
36 | Assert.IsTrue(ledger.IsInDebt);
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Cryptography/BouncyDigest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Ipfs.Cryptography
6 | {
7 | ///
8 | /// Thin wrapper around bouncy castle digests.
9 | ///
10 | ///
11 | /// Makes a Bouncy Caslte IDigest speak .Net HashAlgorithm.
12 | ///
13 | internal class BouncyDigest : System.Security.Cryptography.HashAlgorithm
14 | {
15 | Org.BouncyCastle.Crypto.IDigest digest;
16 |
17 | ///
18 | /// Wrap the bouncy castle digest.
19 | ///
20 | public BouncyDigest(Org.BouncyCastle.Crypto.IDigest digest)
21 | {
22 | this.digest = digest;
23 | }
24 |
25 | ///
26 | public override void Initialize()
27 | {
28 | digest.Reset();
29 | }
30 |
31 | ///
32 | protected override void HashCore(byte[] array, int ibStart, int cbSize)
33 | {
34 | digest.BlockUpdate(array, ibStart, cbSize);
35 | }
36 |
37 | ///
38 | protected override byte[] HashFinal()
39 | {
40 | var output = new byte[digest.GetDigestSize()];
41 | digest.DoFinal(output, 0);
42 | return output;
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/doc/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("WebApplication1")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("WebApplication1")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("f3a32ea9-0b2f-46a3-b47a-33b4c04bd423")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Revision and Build Numbers
33 | // by using the '*' as shown below:
34 | [assembly: AssemblyVersion("1.0.0.0")]
35 | [assembly: AssemblyFileVersion("1.0.0.0")]
36 |
--------------------------------------------------------------------------------
/doc/articles/core-api.md:
--------------------------------------------------------------------------------
1 | # Core API
2 |
3 | [ICoreApi](xref:Ipfs.CoreApi.ICoreApi) is a set of interfaces to IPFS features.
4 |
5 |
6 | | Feature | Purpose |
7 | | ------- | ------- |
8 | | [Bitswap](xref:Ipfs.CoreApi.IBitswapApi) | Block trading between peers |
9 | | [Block](xref:Ipfs.CoreApi.IBlockApi) | Manages the blocks |
10 | | [BlockRepository](xref:Ipfs.CoreApi.IBlockRepositoryApi) | Manages the repository for [blocks](xref:Ipfs.CoreApi.IBlockApi) |
11 | | [Bootstrap](xref:Ipfs.CoreApi.IBootstrapApi) | Trusted peers |
12 | | [Config](xref:Ipfs.CoreApi.IConfigApi) | Manages the configuration of the local peer |
13 | | [Dag](xref:Ipfs.CoreApi.IDagApi) | Manages the IPLD (linked data) Directed Acrylic Graph |
14 | | [Dht](xref:Ipfs.CoreApi.IDhtApi) | Manages the Distributed Hash Table |
15 | | [Dns](xref:Ipfs.CoreApi.IDnsApi) | DNS mapping to IPFS |
16 | | [FileSystem](xref:Ipfs.CoreApi.IFileSystemApi) | Manages the files/directories in IPFS |
17 | | [Key](xref:Ipfs.CoreApi.IKeyApi) | Manages the cryptographic keys |
18 | | [Misc](xref:Ipfs.CoreApi.IGenericApi) | Some miscellaneous methods |
19 | | [Name](xref:Ipfs.CoreApi.INameApi) | Manages the Interplanetary Name Space (IPNS) |
20 | | [Object](xref:Ipfs.CoreApi.IObjectApi) | Manages the IPFS Directed Acrylic Graph |
21 | | [Pin](xref:Ipfs.CoreApi.IPinApi) | Manage objects that are locally stored and permanent |
22 | | [PubSub](xref:Ipfs.CoreApi.IPubSubApi) | Publish and subscribe topic messages |
23 | | [Swarm](xref:Ipfs.CoreApi.ISwarmApi) | Manages the swarm of peers |
24 | | [Stats](xref:Ipfs.CoreApi.IStatsApi) | Statistics on IPFS components |
25 |
26 |
--------------------------------------------------------------------------------
/test/ExceptionAssert.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using Microsoft.VisualStudio.TestTools.UnitTesting;
4 |
5 | namespace Ipfs
6 | {
7 | ///
8 | /// Asserting an .
9 | ///
10 | public static class ExceptionAssert
11 | {
12 |
13 | public static T Throws(Action action, string expectedMessage = null) where T : Exception
14 | {
15 | try
16 | {
17 | action();
18 | }
19 | catch (AggregateException e)
20 | {
21 | var match = e.InnerExceptions.OfType().FirstOrDefault();
22 | if (match != null)
23 | {
24 | if (expectedMessage != null)
25 | Assert.AreEqual(expectedMessage, match.Message, "Wrong exception message.");
26 | return match;
27 | }
28 |
29 | throw;
30 | }
31 | catch (T e)
32 | {
33 | if (expectedMessage != null)
34 | Assert.AreEqual(expectedMessage, e.Message);
35 | return e;
36 | }
37 | Assert.Fail("Exception of type {0} should be thrown.", typeof(T));
38 |
39 | // The compiler doesn't know that Assert.Fail will always throw an exception
40 | return null;
41 | }
42 |
43 | public static Exception Throws(Action action, string expectedMessage = null)
44 | {
45 | return Throws(action, expectedMessage);
46 | }
47 |
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/test/Registry/CodecTest.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.IO;
7 | using Google.Protobuf;
8 |
9 | namespace Ipfs.Registry
10 | {
11 | [TestClass]
12 | public class CodecTest
13 | {
14 | [TestMethod]
15 | public void Bad_Name()
16 | {
17 | ExceptionAssert.Throws(() => Codec.Register(null, 1));
18 | ExceptionAssert.Throws(() => Codec.Register("", 1));
19 | ExceptionAssert.Throws(() => Codec.Register(" ", 1));
20 | }
21 |
22 | [TestMethod]
23 | public void Name_Already_Exists()
24 | {
25 | ExceptionAssert.Throws(() => Codec.Register("raw", 1));
26 | }
27 |
28 | [TestMethod]
29 | public void Code_Already_Exists()
30 | {
31 | ExceptionAssert.Throws(() => Codec.Register("raw-x", 0x55));
32 | }
33 |
34 | [TestMethod]
35 | public void Algorithms_Are_Enumerable()
36 | {
37 | Assert.AreNotEqual(0, Codec.All.Count());
38 | }
39 |
40 | [TestMethod]
41 | public void Register()
42 | {
43 | var codec = Codec.Register("something-new", 0x0bad);
44 | try
45 | {
46 | Assert.AreEqual("something-new", codec.Name);
47 | Assert.AreEqual("something-new", codec.ToString());
48 | Assert.AreEqual(0x0bad, codec.Code);
49 | }
50 | finally
51 | {
52 | Codec.Deregister(codec);
53 | }
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/CoreApi/RepositoryData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Ipfs.CoreApi
6 | {
7 | ///
8 | /// The statistics for .
9 | ///
10 | public class RepositoryData
11 | {
12 | ///
13 | /// The number of blocks in the repository.
14 | ///
15 | ///
16 | /// The number of blocks in the repository.
17 | ///
18 | public ulong NumObjects;
19 |
20 | ///
21 | /// The total number bytes in the repository.
22 | ///
23 | ///
24 | /// The total number bytes in the repository.
25 | ///
26 | public ulong RepoSize;
27 |
28 | ///
29 | /// The fully qualified path to the repository.
30 | ///
31 | ///
32 | /// The directory of the repository.
33 | ///
34 | public string RepoPath;
35 |
36 | ///
37 | /// The version number of the repository.
38 | ///
39 | ///
40 | /// The version number of the repository.
41 | ///
42 | public string Version;
43 |
44 | ///
45 | /// The maximum number of bytes allowed in the repository.
46 | ///
47 | ///
48 | /// Max bytes allowed in the repository.
49 | ///
50 | public ulong StorageMax;
51 |
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/IDataBlock.cs:
--------------------------------------------------------------------------------
1 | using Google.Protobuf;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace Ipfs
10 | {
11 | ///
12 | /// Some data that is stored in IPFS.
13 | ///
14 | ///
15 | /// A DataBlock has an unique ID
16 | /// and some data (
17 | /// or ).
18 | ///
19 | /// It is useful to talk about them as "blocks" in Bitswap
20 | /// and other things that do not care about what is being stored.
21 | ///
22 | ///
23 | ///
24 | public interface IDataBlock
25 | {
26 |
27 | ///
28 | /// Contents as a byte array.
29 | ///
30 | ///
31 | /// It is never null.
32 | ///
33 | ///
34 | /// The contents as a sequence of bytes.
35 | ///
36 | byte[] DataBytes { get; }
37 |
38 | ///
39 | /// Contents as a stream of bytes.
40 | ///
41 | ///
42 | /// The contents as a stream of bytes.
43 | ///
44 | Stream DataStream { get; }
45 |
46 | ///
47 | /// The unique ID of the data.
48 | ///
49 | ///
50 | /// A of the content.
51 | ///
52 | Cid Id { get; }
53 |
54 | ///
55 | /// The size (in bytes) of the data.
56 | ///
57 | /// Number of bytes.
58 | long Size { get; }
59 |
60 |
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/doc/docfx.json:
--------------------------------------------------------------------------------
1 | {
2 | "metadata": [
3 | {
4 | "src": [
5 | {
6 | "files": [
7 | "src/**.csproj"
8 | ],
9 | "exclude": [
10 | "**/obj/**",
11 | "**/bin/**",
12 | "_site/**"
13 | ],
14 | "src": ".."
15 | }
16 | ],
17 | "properties": {
18 | "TargetFramework": "netcoreapp3.0"
19 | },
20 |
21 | "dest": "api"
22 | }
23 | ],
24 | "build": {
25 | "content": [
26 | {
27 | "files": [
28 | "api/**.yml",
29 | "api/index.md"
30 | ]
31 | },
32 | {
33 | "files": [
34 | "articles/**.md",
35 | "articles/**/toc.yml",
36 | "toc.yml",
37 | "*.md"
38 | ],
39 | "exclude": [
40 | "obj/**",
41 | "_site/**"
42 | ]
43 | }
44 | ],
45 | "resource": [
46 | {
47 | "files": [
48 | "images/**"
49 | ],
50 | "exclude": [
51 | "obj/**",
52 | "_site/**"
53 | ]
54 | }
55 | ],
56 | "overwrite": [
57 | {
58 | "files": [
59 | "apidoc/**.md"
60 | ],
61 | "exclude": [
62 | "obj/**",
63 | "_site/**"
64 | ]
65 | }
66 | ],
67 | "xrefService": [
68 | "https://xref.docs.microsoft.com/query?uid={uid}"
69 | ],
70 | "globalMetadata": {
71 | "_appTitle": "IPFS Core documentation",
72 | "_appFooter": "Generated by DocFX",
73 | "_appFaviconPath": "images/ipfs-favicon.ico",
74 | "_appLogoPath": "images/ipfs-cs-logo-48x48.png"
75 | },
76 | "dest": "_site",
77 | "globalMetadataFiles": [],
78 | "fileMetadataFiles": [],
79 | "template": [
80 | "default"
81 | ],
82 | "postProcessors": [],
83 | "noLangKeyword": false
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/test/NetworkProtocolTest.cs:
--------------------------------------------------------------------------------
1 | using Ipfs;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.IO;
8 | using Google.Protobuf;
9 |
10 | namespace Ipfs
11 | {
12 | [TestClass]
13 | public class NetworkProtocolTest
14 | {
15 | [TestMethod]
16 | public void Stringing()
17 | {
18 | Assert.AreEqual("/tcp/8080", new MultiAddress("/tcp/8080").Protocols[0].ToString());
19 | }
20 |
21 | [TestMethod]
22 | public void Register_Name_Already_Exists()
23 | {
24 | ExceptionAssert.Throws(() => NetworkProtocol.Register());
25 | }
26 |
27 | [TestMethod]
28 | public void Register_Code_Already_Exists()
29 | {
30 | ExceptionAssert.Throws(() => NetworkProtocol.Register());
31 | }
32 |
33 | class NameExists : NetworkProtocol
34 | {
35 | public override string Name { get { return "tcp"; } }
36 | public override uint Code { get { return 0x7FFF; } }
37 | public override void ReadValue(CodedInputStream stream) { }
38 | public override void ReadValue(TextReader stream) { }
39 | public override void WriteValue(CodedOutputStream stream) { }
40 | }
41 |
42 | class CodeExists : NetworkProtocol
43 | {
44 | public override string Name { get { return "x-tcp"; } }
45 | public override uint Code { get { return 6; } }
46 | public override void ReadValue(CodedInputStream stream) { }
47 | public override void ReadValue(TextReader stream) { }
48 | public override void WriteValue(CodedOutputStream stream) { }
49 | }
50 |
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/IMerkleNode.cs:
--------------------------------------------------------------------------------
1 | using Google.Protobuf;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace Ipfs
10 | {
11 | ///
12 | /// A Directed Acyclic Graph (DAG) in IPFS.
13 | ///
14 | ///
15 | /// A MerkleNode has a sequence of navigable
16 | /// and some data (
17 | /// or ).
18 | ///
19 | ///
20 | /// The type of used by this node.
21 | ///
22 | ///
23 | ///
24 | public interface IMerkleNode : IDataBlock
25 | where Link : IMerkleLink
26 | {
27 |
28 | ///
29 | /// Links to other nodes.
30 | ///
31 | ///
32 | /// A sequence of .
33 | ///
34 | ///
35 | /// It is never null.
36 | ///
37 | /// The links are sorted ascending by . A null
38 | /// name is compared as "".
39 | ///
40 | ///
41 | IEnumerable Links { get; }
42 |
43 | ///
44 | /// Returns a link to the node.
45 | ///
46 | ///
47 | /// A for the link; defaults to "".
48 | ///
49 | ///
50 | /// A new to the node.
51 | ///
52 | Link ToLink(string name = "");
53 |
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/test/Base58Test.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using Microsoft.VisualStudio.TestTools.UnitTesting;
6 |
7 | namespace Ipfs
8 | {
9 | [TestClass]
10 | public class Base58Test
11 | {
12 | [TestMethod]
13 | public void Encode()
14 | {
15 | Assert.AreEqual("jo91waLQA1NNeBmZKUF", Base58.Encode(Encoding.UTF8.GetBytes("this is a test")));
16 | Assert.AreEqual("jo91waLQA1NNeBmZKUF", Encoding.UTF8.GetBytes("this is a test").ToBase58());
17 | }
18 |
19 | [TestMethod]
20 | public void Decode()
21 | {
22 | Assert.AreEqual("this is a test", Encoding.UTF8.GetString(Base58.Decode("jo91waLQA1NNeBmZKUF")));
23 | Assert.AreEqual("this is a test", Encoding.UTF8.GetString("jo91waLQA1NNeBmZKUF".FromBase58()));
24 | }
25 |
26 | ///
27 | /// C# version of base58Test in
28 | ///
29 | [TestMethod]
30 | public void Java()
31 | {
32 | String input = "QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB";
33 | byte[] output = Base58.Decode(input);
34 | String encoded = Base58.Encode(output);
35 | Assert.AreEqual(input, encoded);
36 | }
37 |
38 | [TestMethod]
39 | public void Decode_Bad()
40 | {
41 | ExceptionAssert.Throws(() => Base58.Decode("jo91waLQA1NNeBmZKUF=="));
42 | }
43 |
44 | [TestMethod]
45 | public void Zero()
46 | {
47 | Assert.AreEqual("1111111", Base58.Encode(new byte[7]));
48 | Assert.AreEqual(7, Base58.Decode("1111111").Length);
49 | Assert.IsTrue(Base58.Decode("1111111").All(b => b == 0));
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/doc/images/ipfs-logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/test/CoreApi/AddFileOptionsTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Text;
4 | using Microsoft.VisualStudio.TestTools.UnitTesting;
5 |
6 | namespace Ipfs.CoreApi
7 | {
8 | [TestClass]
9 | public class AddFileOptionsTests
10 | {
11 | [TestMethod]
12 | public void Defaults()
13 | {
14 | var options = new AddFileOptions();
15 |
16 | Assert.AreEqual(true, options.Pin);
17 | Assert.AreEqual(256 * 1024, options.ChunkSize);
18 | Assert.AreEqual(MultiHash.DefaultAlgorithmName, options.Hash);
19 | Assert.AreEqual(false, options.OnlyHash);
20 | Assert.AreEqual(false, options.RawLeaves);
21 | Assert.AreEqual(false, options.Trickle);
22 | Assert.AreEqual(false, options.Wrap);
23 | Assert.IsNull(options.Progress);
24 | Assert.IsNull(options.ProtectionKey);
25 | }
26 |
27 | [TestMethod]
28 | public void Setting()
29 | {
30 | var options = new AddFileOptions
31 | {
32 | Pin = false,
33 | ChunkSize = 2 * 1024,
34 | Hash = "sha2-512",
35 | OnlyHash = true,
36 | RawLeaves = true,
37 | Progress = new Progress(),
38 | Trickle = true,
39 | Wrap = true,
40 | ProtectionKey = "secret"
41 | };
42 |
43 | Assert.AreEqual(false, options.Pin);
44 | Assert.AreEqual(2 * 1024, options.ChunkSize);
45 | Assert.AreEqual("sha2-512", options.Hash);
46 | Assert.AreEqual(true, options.OnlyHash);
47 | Assert.AreEqual(true, options.RawLeaves);
48 | Assert.AreEqual(true, options.Trickle);
49 | Assert.AreEqual(true, options.Wrap);
50 | Assert.IsNotNull(options.Progress);
51 | Assert.AreEqual("secret", options.ProtectionKey);
52 | }
53 |
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/CoreApi/BitswapData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Ipfs.CoreApi
6 | {
7 | ///
8 | /// The statistics for .
9 | ///
10 | public class BitswapData
11 | {
12 | ///
13 | /// TODO: Unknown.
14 | ///
15 | public int ProvideBufLen;
16 |
17 | ///
18 | /// The content that is wanted.
19 | ///
20 | public IEnumerable Wantlist;
21 |
22 | ///
23 | /// The known peers.
24 | ///
25 | public IEnumerable Peers;
26 |
27 | ///
28 | /// The number of blocks sent by other peers.
29 | ///
30 | public ulong BlocksReceived;
31 |
32 | ///
33 | /// The number of bytes sent by other peers.
34 | ///
35 | public ulong DataReceived;
36 |
37 | ///
38 | /// The number of blocks sent to other peers.
39 | ///
40 | public ulong BlocksSent;
41 |
42 | ///
43 | /// The number of bytes sent to other peers.
44 | ///
45 | public ulong DataSent;
46 |
47 | ///
48 | /// The number of duplicate blocks sent by other peers.
49 | ///
50 | ///
51 | /// A duplicate block is a block that is already stored in the
52 | /// local repository.
53 | ///
54 | public ulong DupBlksReceived;
55 |
56 | ///
57 | /// The number of duplicate bytes sent by other peers.
58 | ///
59 | ///
60 | /// A duplicate block is a block that is already stored in the
61 | /// local repository.
62 | ///
63 | public ulong DupDataReceived;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/test/HexStringTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using Microsoft.VisualStudio.TestTools.UnitTesting;
6 | using System.IO;
7 |
8 | namespace Ipfs
9 | {
10 | [TestClass]
11 | public class HexStringTest
12 | {
13 | [TestMethod]
14 | public void Encode()
15 | {
16 | var buffer = Enumerable.Range(byte.MinValue, byte.MaxValue).Select(b => (byte) b).ToArray();
17 | var lowerHex = string.Concat(buffer.Select(b => b.ToString("x2")).ToArray());
18 | var upperHex = string.Concat(buffer.Select(b => b.ToString("X2")).ToArray());
19 |
20 | Assert.AreEqual(lowerHex, buffer.ToHexString(), "encode default");
21 | Assert.AreEqual(lowerHex, buffer.ToHexString("G"), "encode general");
22 | Assert.AreEqual(lowerHex, buffer.ToHexString("x"), "encode lower");
23 | Assert.AreEqual(upperHex, buffer.ToHexString("X"), "encode upper");
24 | }
25 |
26 | [TestMethod]
27 | public void Decode()
28 | {
29 | var buffer = Enumerable.Range(byte.MinValue, byte.MaxValue).Select(b => (byte)b).ToArray();
30 | var lowerHex = string.Concat(buffer.Select(b => b.ToString("x2")).ToArray());
31 | var upperHex = string.Concat(buffer.Select(b => b.ToString("X2")).ToArray());
32 |
33 | CollectionAssert.AreEqual(buffer, lowerHex.ToHexBuffer(), "decode lower");
34 | CollectionAssert.AreEqual(buffer, upperHex.ToHexBuffer(), "decode upper");
35 | }
36 |
37 | [TestMethod]
38 | public void InvalidFormatSpecifier()
39 | {
40 | ExceptionAssert.Throws(() => HexString.Encode(new byte[0], "..."));
41 | }
42 |
43 | [TestMethod]
44 | public void InvalidHexStrings()
45 | {
46 | ExceptionAssert.Throws(() => HexString.Decode("0"));
47 | ExceptionAssert.Throws(() => HexString.Decode("0Z"));
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/TraceAndTestImpact.testsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 | These are test settings for Trace and Test Impact.
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/CoreApi/IDnsApi.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace Ipfs.CoreApi
8 | {
9 | ///
10 | /// DNS mapping to IPFS.
11 | ///
12 | ///
13 | /// Multihashes are hard to remember, but domain names are usually easy to
14 | /// remember. To create memorable aliases for multihashes, DNS TXT
15 | /// records can point to other DNS links, IPFS objects, IPNS keys, etc.
16 | ///
17 | public interface IDnsApi
18 | {
19 |
20 | ///
21 | /// Resolve a domain name to an IPFS path.
22 | ///
23 | ///
24 | /// An domain name, such as "ipfs.io".
25 | ///
26 | ///
27 | /// Resolve until the result is not a DNS link. Defaults to false.
28 | ///
29 | ///
30 | /// Is used to stop the task. When cancelled, the is raised.
31 | ///
32 | ///
33 | /// A task that represents the asynchronous operation. The task's value is
34 | /// the resolved IPFS path as a , such as
35 | /// /ipfs/QmYNQJoKGNHTpPxCBPh9KkDpaExgd2duMa3aF6ytMpHdao.
36 | ///
37 | ///
38 | /// A DNS TXT record with a "dnslink=..." entry is expected to exist. The
39 | /// value of the "dnslink" is an IPFS path to another IPFS object.
40 | ///
41 | /// A DNS query is generated for both and
42 | /// _dnslink..
43 | ///
44 | ///
45 | ///
46 | /// ResolveAsync("ipfs.io", recursive: false) produces "/ipns/website.ipfs.io". Whereas,
47 | /// ResolveAsync("ipfs.io", recursive: true) produces "/ipfs/QmXZz6vQTMiu6UyGxVgpLB6xJdHvvUbhdWagJQNnxXAjpn".
48 | ///
49 | Task ResolveAsync(
50 | string name,
51 | bool recursive = false,
52 | CancellationToken cancel = default(CancellationToken)
53 | );
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/CoreApi/IStatsApi.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace Ipfs.CoreApi
8 | {
9 | ///
10 | /// Get statistics/diagnostics for the various core components.
11 | ///
12 | public interface IStatsApi
13 | {
14 | ///
15 | /// Get statistics on network bandwidth.
16 | ///
17 | ///
18 | /// Is used to stop the task. When cancelled, the is raised.
19 | ///
20 | ///
21 | /// A task that represents the asynchronous operation. The task's result is
22 | /// the current .
23 | ///
24 | ///
25 | Task BandwidthAsync(CancellationToken cancel = default(CancellationToken));
26 |
27 | ///
28 | /// Get statistics on the blocks exchanged with other peers.
29 | ///
30 | ///
31 | /// Is used to stop the task. When cancelled, the is raised.
32 | ///
33 | ///
34 | /// A task that represents the asynchronous operation. The task's result is
35 | /// the current .
36 | ///
37 | ///
38 | Task BitswapAsync(CancellationToken cancel = default(CancellationToken));
39 |
40 | ///
41 | /// Get statistics on the repository.
42 | ///
43 | ///
44 | /// Is used to stop the task. When cancelled, the is raised.
45 | ///
46 | ///
47 | /// A task that represents the asynchronous operation. The task's result is
48 | /// the current .
49 | ///
50 | ///
51 | /// Same as .
52 | ///
53 | ///
54 | Task RepositoryAsync(CancellationToken cancel = default(CancellationToken));
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/CoreApi/BitswapLedger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Ipfs.CoreApi
6 | {
7 | ///
8 | /// Statistics on the bitswap blocks exchanged with another .
9 | ///
10 | ///
11 | public class BitswapLedger
12 | {
13 | ///
14 | /// The that pertains to this ledger.
15 | ///
16 | ///
17 | /// The peer that is being monitored.
18 | ///
19 | public Peer Peer { get; set; }
20 |
21 | ///
22 | /// The number of blocks exchanged with the .
23 | ///
24 | ///
25 | /// The number of blocks sent by the peer or sent by us to the peer.
26 | ///
27 | public ulong BlocksExchanged { get; set; }
28 |
29 | ///
30 | /// The number of bytes sent by the to us.
31 | ///
32 | ///
33 | /// The number of bytes.
34 | ///
35 | public ulong DataReceived { get; set; }
36 |
37 | ///
38 | /// The number of bytes sent by us to the
39 | ///
40 | ///
41 | /// The number of bytes.
42 | ///
43 | public ulong DataSent { get; set; }
44 |
45 | ///
46 | /// The calculated debt to the peer.
47 | ///
48 | ///
49 | /// divided by .
50 | /// A value less than 1 indicates that we are in debt to the
51 | /// .
52 | ///
53 | public float DebtRatio
54 | {
55 | get
56 | {
57 | return (float)DataSent / (float)(DataReceived + 1); // +1 is to prevent division by zero
58 | }
59 | }
60 |
61 | ///
62 | /// Determines if we owe the some blocks.
63 | ///
64 | ///
65 | /// true if we owe data to the peer; otherwise, false.
66 | ///
67 | public bool IsInDebt => DebtRatio < 1;
68 |
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/CoreApi/IContentRouting.cs:
--------------------------------------------------------------------------------
1 | using Ipfs;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 |
9 | namespace Ipfs.CoreApi
10 | {
11 | ///
12 | /// Find information about who has what content.
13 | ///
14 | ///
15 | /// No IPFS documentation is currently available. See the
16 | /// code.
17 | ///
18 | public interface IContentRouting
19 | {
20 | ///
21 | /// Adds the to the content routing system.
22 | ///
23 | ///
24 | /// The ID of some content that the peer contains.
25 | ///
26 | ///
27 | /// Advertise the to other peers.
28 | ///
29 | ///
30 | /// Is used to stop the task. When cancelled, the is raised.
31 | ///
32 | ///
33 | /// A task that represents the asynchronous operation.
34 | ///
35 | Task ProvideAsync(Cid cid, bool advertise = true, CancellationToken cancel = default(CancellationToken));
36 |
37 | ///
38 | /// Find the providers for the specified content.
39 | ///
40 | ///
41 | /// The of the content.
42 | ///
43 | ///
44 | /// The maximum number of peers to return. Defaults to 20.
45 | ///
46 | ///
47 | /// An action to perform when a provider is found.
48 | ///
49 | ///
50 | /// Is used to stop the task. When cancelled, the is raised.
51 | ///
52 | ///
53 | /// A task that represents the asynchronous operation that returns
54 | /// a sequence of IPFS .
55 | ///
56 | Task> FindProvidersAsync(
57 | Cid id,
58 | int limit = 20,
59 | Action providerFound = null,
60 | CancellationToken cancel = default(CancellationToken));
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/test/Registry/MultibaseAlgorithmTest.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.IO;
7 | using Google.Protobuf;
8 |
9 | namespace Ipfs.Registry
10 | {
11 | [TestClass]
12 | public class MultiBaseAlgorithmTest
13 | {
14 | [TestMethod]
15 | public void Bad_Name()
16 | {
17 | ExceptionAssert.Throws(() => MultiBaseAlgorithm.Register(null, '?'));
18 | ExceptionAssert.Throws(() => MultiBaseAlgorithm.Register("", '?'));
19 | ExceptionAssert.Throws(() => MultiBaseAlgorithm.Register(" ", '?'));
20 | }
21 |
22 | [TestMethod]
23 | public void Name_Already_Exists()
24 | {
25 | ExceptionAssert.Throws(() => MultiBaseAlgorithm.Register("base58btc", 'z'));
26 | }
27 |
28 | [TestMethod]
29 | public void Code_Already_Exists()
30 | {
31 | ExceptionAssert.Throws(() => MultiBaseAlgorithm.Register("base58btc-x", 'z'));
32 | }
33 |
34 | [TestMethod]
35 | public void Algorithms_Are_Enumerable()
36 | {
37 | Assert.AreNotEqual(0, MultiBaseAlgorithm.All.Count());
38 | }
39 |
40 | [TestMethod]
41 | public void Roundtrip_All_Algorithms()
42 | {
43 | var bytes = new byte[] { 1, 2, 3, 4, 5 };
44 |
45 | foreach (var alg in MultiBaseAlgorithm.All)
46 | {
47 | var s = alg.Encode(bytes);
48 | CollectionAssert.AreEqual(bytes, alg.Decode(s), alg.Name);
49 | }
50 | }
51 |
52 | [TestMethod]
53 | public void Name_Is_Also_ToString()
54 | {
55 | foreach (var alg in MultiBaseAlgorithm.All)
56 | {
57 | Assert.AreEqual(alg.Name, alg.ToString());
58 | }
59 | }
60 |
61 | [TestMethod]
62 | public void Known_But_NYI()
63 | {
64 | var alg = MultiBaseAlgorithm.Register("nyi", 'n');
65 | try
66 | {
67 | ExceptionAssert.Throws(() => alg.Encode(null));
68 | ExceptionAssert.Throws(() => alg.Decode(null));
69 | }
70 | finally
71 | {
72 | MultiBaseAlgorithm.Deregister(alg);
73 | }
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/CoreApi/IValueStore.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace Ipfs.CoreApi
8 | {
9 | ///
10 | /// A basic Put/Get interface.
11 | ///
12 | public interface IValueStore
13 | {
14 | ///
15 | /// Gets th value of a key.
16 | ///
17 | ///
18 | /// A byte array representing the name of a key.
19 | ///
20 | ///
21 | /// Is used to stop the task. When cancelled, the is raised.
22 | ///
23 | ///
24 | /// A task that represents the asynchronous operation that returns
25 | /// the value of the key as a byte array.
26 | ///
27 | Task GetAsync(byte[] key, CancellationToken cancel = default(CancellationToken));
28 |
29 | ///
30 | /// Tries to get the value of a key.
31 | ///
32 | ///
33 | /// A byte array representing the name of a key.
34 | ///
35 | ///
36 | /// A byte array containing the value of the
37 | ///
38 | ///
39 | /// Is used to stop the task. When cancelled, the is raised.
40 | ///
41 | ///
42 | /// A task that represents the asynchronous operation that returns
43 | /// true if the key exists; otherwise, false.
44 | ///
45 | Task TryGetAsync(byte[] key, out byte[] value, CancellationToken cancel = default(CancellationToken));
46 |
47 | ///
48 | /// Put the value of a key.
49 | ///
50 | ///
51 | /// A byte array representing the name of a key.
52 | ///
53 | ///
54 | /// A byte array containing the value of the
55 | ///
56 | ///
57 | /// Is used to stop the task. When cancelled, the is raised.
58 | ///
59 | ///
60 | /// A task that represents the asynchronous operation.
61 | ///
62 | Task PutAsync(byte[] key, out byte[] value, CancellationToken cancel = default(CancellationToken));
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/IpfsCore.sln:
--------------------------------------------------------------------------------
1 | Microsoft Visual Studio Solution File, Format Version 12.00
2 | # Visual Studio 15
3 | VisualStudioVersion = 15.0.27004.2005
4 | MinimumVisualStudioVersion = 10.0.40219.1
5 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IpfsCore", "src\IpfsCore.csproj", "{6401AF07-B7F2-4664-86AA-FAD99F82DFAD}"
6 | EndProject
7 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IpfsCoreTests", "test\IpfsCoreTests.csproj", "{FE639401-D4C7-4528-A07C-4290A7710889}"
8 | EndProject
9 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DA715302-8746-4884-95F9-B56F069A0451}"
10 | ProjectSection(SolutionItems) = preProject
11 | .codacy.yml = .codacy.yml
12 | .travis.yml = .travis.yml
13 | appveyor.yml = appveyor.yml
14 | builddocs.cmd = builddocs.cmd
15 | IpfsCore.vsmdi = IpfsCore.vsmdi
16 | LICENSE = LICENSE
17 | Local.testsettings = Local.testsettings
18 | README.md = README.md
19 | TraceAndTestImpact.testsettings = TraceAndTestImpact.testsettings
20 | EndProjectSection
21 | EndProject
22 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Documentation", "doc\Documentation.csproj", "{F3A32EA9-0B2F-46A3-B47A-33B4C04BD423}"
23 | EndProject
24 | Global
25 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
26 | Debug|Any CPU = Debug|Any CPU
27 | Release|Any CPU = Release|Any CPU
28 | EndGlobalSection
29 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
30 | {6401AF07-B7F2-4664-86AA-FAD99F82DFAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31 | {6401AF07-B7F2-4664-86AA-FAD99F82DFAD}.Debug|Any CPU.Build.0 = Debug|Any CPU
32 | {6401AF07-B7F2-4664-86AA-FAD99F82DFAD}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 | {6401AF07-B7F2-4664-86AA-FAD99F82DFAD}.Release|Any CPU.Build.0 = Release|Any CPU
34 | {FE639401-D4C7-4528-A07C-4290A7710889}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35 | {FE639401-D4C7-4528-A07C-4290A7710889}.Debug|Any CPU.Build.0 = Debug|Any CPU
36 | {FE639401-D4C7-4528-A07C-4290A7710889}.Release|Any CPU.ActiveCfg = Release|Any CPU
37 | {FE639401-D4C7-4528-A07C-4290A7710889}.Release|Any CPU.Build.0 = Release|Any CPU
38 | {F3A32EA9-0B2F-46A3-B47A-33B4C04BD423}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39 | {F3A32EA9-0B2F-46A3-B47A-33B4C04BD423}.Release|Any CPU.ActiveCfg = Release|Any CPU
40 | EndGlobalSection
41 | GlobalSection(SolutionProperties) = preSolution
42 | HideSolutionNode = FALSE
43 | EndGlobalSection
44 | GlobalSection(ExtensibilityGlobals) = postSolution
45 | SolutionGuid = {36ED5AA7-8F41-4F7D-A665-230635EF64A1}
46 | EndGlobalSection
47 | GlobalSection(TestCaseManagementSettings) = postSolution
48 | CategoryFile = IpfsCore.vsmdi
49 | EndGlobalSection
50 | EndGlobal
51 |
--------------------------------------------------------------------------------
/src/CoreApi/IBlockRepository.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace Ipfs.CoreApi
8 | {
9 | ///
10 | /// Manages all the blocks stored locally.
11 | ///
12 | ///
13 | public interface IBlockRepositoryApi
14 | {
15 | ///
16 | /// Perform a garbage collection sweep on the repo.
17 | ///
18 | ///
19 | /// Is used to stop the task. When cancelled, the is raised.
20 | ///
21 | ///
22 | /// TODO: not sure what this should return.
23 | ///
24 | Task RemoveGarbageAsync(CancellationToken cancel = default(CancellationToken));
25 |
26 | ///
27 | /// Get statistics on the repository.
28 | ///
29 | ///
30 | /// Is used to stop the task. When cancelled, the is raised.
31 | ///
32 | ///
33 | /// A task that represents the asynchronous operation. The task's result is
34 | /// the current .
35 | ///
36 | ///
37 | /// Same as .
38 | ///
39 | Task StatisticsAsync(CancellationToken cancel = default(CancellationToken));
40 |
41 | ///
42 | /// Verify all blocks in repo are not corrupted.
43 | ///
44 | ///
45 | /// Is used to stop the task. When cancelled, the is raised.
46 | ///
47 | ///
48 | /// TODO: not sure what this should return.
49 | ///
50 | Task VerifyAsync(CancellationToken cancel = default(CancellationToken));
51 |
52 | ///
53 | /// Gets the version number of the repo.
54 | ///
55 | ///
56 | /// Is used to stop the task. When cancelled, the is raised.
57 | ///
58 | ///
59 | /// A task that represents the asynchronous operation. The task's result is
60 | /// the version number of the data block repository.
61 | ///
62 | Task VersionAsync(CancellationToken cancel = default(CancellationToken));
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/test/Base32Test.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using System.Text;
3 | using Microsoft.VisualStudio.TestTools.UnitTesting;
4 |
5 | namespace Ipfs
6 | {
7 | [TestClass]
8 | public class Base32EncodeTests
9 | {
10 | byte[] GetStringBytes(string x)
11 | {
12 | return Encoding.ASCII.GetBytes(x);
13 | }
14 |
15 | [TestMethod]
16 | public void Vector1()
17 | {
18 | Assert.AreEqual(string.Empty, Base32.Encode(GetStringBytes(string.Empty)));
19 | }
20 |
21 | [TestMethod]
22 | public void Vector2()
23 | {
24 | Assert.AreEqual("my", Base32.Encode(GetStringBytes("f")));
25 | }
26 |
27 | [TestMethod]
28 | public void Vector3()
29 | {
30 | Assert.AreEqual("mzxq", Base32.Encode(GetStringBytes("fo")));
31 | }
32 |
33 | [TestMethod]
34 | public void Vector4()
35 | {
36 | Assert.AreEqual("mzxw6", Base32.Encode(GetStringBytes("foo")));
37 | }
38 |
39 | [TestMethod]
40 | public void Vector5()
41 | {
42 | Assert.AreEqual("mzxw6yq", Base32.Encode(GetStringBytes("foob")));
43 | }
44 |
45 | [TestMethod]
46 | public void Vector6()
47 | {
48 | Assert.AreEqual("mzxw6ytb", Base32.Encode(GetStringBytes("fooba")));
49 | }
50 |
51 | [TestMethod]
52 | public void Vector7()
53 | {
54 | Assert.AreEqual("mzxw6ytboi", Base32.Encode(GetStringBytes("foobar")));
55 | }
56 | }
57 |
58 | [TestClass]
59 | public class Base32DecodeTests
60 | {
61 | byte[] GetStringBytes(string x)
62 | {
63 | return Encoding.ASCII.GetBytes(x);
64 | }
65 |
66 | [TestMethod]
67 | public void Vector1()
68 | {
69 | CollectionAssert.AreEqual(GetStringBytes(string.Empty), Base32.Decode(string.Empty));
70 | }
71 |
72 | [TestMethod]
73 | public void Vector2()
74 | {
75 | CollectionAssert.AreEqual(GetStringBytes("f"), Base32.Decode("MY======"));
76 | }
77 |
78 | [TestMethod]
79 | public void Vector3()
80 | {
81 | CollectionAssert.AreEqual(GetStringBytes("fo"), Base32.Decode("MZXQ===="));
82 | }
83 |
84 | [TestMethod]
85 | public void Vector4()
86 | {
87 | CollectionAssert.AreEqual(GetStringBytes("foo"), Base32.Decode("MZXW6==="));
88 | }
89 |
90 | [TestMethod]
91 | public void Vector5()
92 | {
93 | CollectionAssert.AreEqual(GetStringBytes("foob"), Base32.Decode("MZXW6YQ="));
94 | }
95 |
96 | [TestMethod]
97 | public void Vector6()
98 | {
99 | CollectionAssert.AreEqual(GetStringBytes("fooba"), Base32.Decode("MZXW6YTB"));
100 | }
101 |
102 | [TestMethod]
103 | public void Vector7()
104 | {
105 | CollectionAssert.AreEqual(GetStringBytes("foobar"), Base32.Decode("MZXW6YTBOI======"));
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/src/CoreApi/IPinApi.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace Ipfs.CoreApi
8 | {
9 | ///
10 | /// Manage pinned objects (locally stored and permanent).
11 | ///
12 | /// Pin API spec
13 | public interface IPinApi
14 | {
15 | ///
16 | /// Adds an IPFS object to the pinset and also stores it to the IPFS repo. pinset is the set of hashes currently pinned (not gc'able).
17 | ///
18 | ///
19 | /// A CID or path to an existing object, such as "QmXarR6rgkQ2fDSHjSY5nM2kuCXKYGViky5nohtwgF65Ec/about"
20 | /// or "QmZTR5bcpQD7cFgTorqxZDYaew1Wqgfbd2ud9QqGPAkK2V"
21 | ///
22 | ///
23 | /// true to recursively pin links of the object; otherwise, false to only pin
24 | /// the specified object. Default is true.
25 | ///
26 | ///
27 | /// Is used to stop the task. When cancelled, the is raised.
28 | ///
29 | ///
30 | /// A task that represents the asynchronous operation. The task's value
31 | /// is a sequence of that were pinned.
32 | ///
33 | Task> AddAsync(string path, bool recursive = true, CancellationToken cancel = default(CancellationToken));
34 |
35 | ///
36 | /// List all the objects pinned to local storage.
37 | ///
38 | ///
39 | /// Is used to stop the task. When cancelled, the is raised.
40 | ///
41 | ///
42 | /// A task that represents the asynchronous operation. The task's value
43 | /// is a sequence of .
44 | ///
45 | Task> ListAsync(CancellationToken cancel = default(CancellationToken));
46 |
47 | ///
48 | /// Unpin an object.
49 | ///
50 | ///
51 | /// The CID of the object.
52 | ///
53 | ///
54 | /// true to recursively unpin links of object; otherwise, false to only unpin
55 | /// the specified object. Default is true.
56 | ///
57 | ///
58 | /// Is used to stop the task. When cancelled, the is raised.
59 | ///
60 | ///
61 | /// A task that represents the asynchronous operation. The task's value
62 | /// is a sequence of that were unpinned.
63 | ///
64 | Task> RemoveAsync(Cid id, bool recursive = true, CancellationToken cancel = default(CancellationToken));
65 |
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/doc/articles/multihash.md:
--------------------------------------------------------------------------------
1 | # MultiHash
2 |
3 | All hashes in IPFS are encoded as a [MultiHash](xref:Ipfs.MultiHash), a self-describing hash format.
4 | The actual [hash function](#algorithms) used depends on security requirements; "sha2-256" is todays default.
5 |
6 | A multihash is used to identify a [peer](xref:Ipfs.Peer), [key](xref:Ipfs.IKey) and [content](cid.md).
7 | For background information, see [hash concept](https://docs.ipfs.io/guides/concepts/hashes/).
8 |
9 | ```csharp
10 | var hello = Encoding.UTF8.GetBytes("Hello world");
11 | var mh = MultiHash.ComputeHash(hello, "sha2-256");
12 | ```
13 |
14 | ## Format
15 |
16 | The binary representation consists of the [hash code](xref:Ipfs.MultiHash.Algorithm), the [digest's](xref:Ipfs.MultiHash.Digest)
17 | length and value. The code and length are encoded as [varints](varint.md).
18 |
19 | The textual representation is usually the [Base58](xref:Ipfs.MultiHash.ToBase58*) encoding of the
20 | binary format. [Base32](xref:Ipfs.MultiHash.ToBase32*) encoding is used when case insensity is required.
21 |
22 | From the above example, the following is produced
23 |
24 | | Name | Value |
25 | | ---- | ----- |
26 | | hash code | 0x12 |
27 | | digest length | 0x20 |
28 | | digest value | 64ec88ca00b268e5ba1a35678a1b5316d212f4f366b2477232534a8aeca37f3c |
29 | | binary | 12 20 64ec88ca00b268e5ba1a35678a1b5316d212f4f366b2477232534a8aeca37f3c |
30 | | base 58 | QmV8cfu6n4NT5xRr2AHdKxFMTZEJrA44qgrBCr739BN9Wb |
31 | | base 32 | ciqgj3eiziale2hfxindkz4kdnjrnuqs6tzwnmshoizfgsuk5srx6pa |
32 |
33 | ## Algorithms
34 |
35 | IPFS assigns a unique [Name](xref:Ipfs.Registry.HashingAlgorithm.Name) and [Code](xref:Ipfs.Registry.HashingAlgorithm.Code)
36 | to a hashing algorithm. See [hashtable.csv](https://github.com/multiformats/multicodec/blob/master/table.csv")
37 | for the currently defined hashing algorithms.
38 |
39 | These algorithms are implemented:
40 |
41 | - blake2b-160, blake2b-256 blake2b-384 and blake2b-512
42 | - blake2s-128, blake2s-160, blake2s-224 a nd blake2s-256
43 | - keccak-224, keccak-256, keccak-384 and keccak-512
44 | - md4 and md5
45 | - sha1
46 | - sha2-256, sha2-512 and dbl-sha2-256
47 | - sha3-224, sha3-256, sha3-384 and sha3-512
48 | - shake-128 and shake-256
49 |
50 | The identity hash is also implemented; which just returns the input bytes. This is used to inline a small amount of
51 | data into a [CID](cid.md).
52 |
53 | ## Registry
54 |
55 | The [hashing registry](xref:Ipfs.Registry.HashingAlgorithm) contains the metadata on hashing algorithms. You can use
56 | [Register](xref:Ipfs.Registry.HashingAlgorithm.Register*) to add a new hashing algorithm.
57 |
58 | ### Example
59 |
60 | Using an hashing algorithm. Note that `ComputeHash` can take a byte array or a `Stream`.
61 |
62 | ```csharp
63 | public void GetHasher()
64 | {
65 | using (var hasher = HashingAlgorithm.GetAlgorithm("sha3-256"))
66 | {
67 | Assert.IsNotNull(hasher);
68 | var input = new byte[] { 0xe9 };
69 | var expected = "f0d04dd1e6cfc29a4460d521796852f25d9ef8d28b44ee91ff5b759d72c1e6d6".ToHexBuffer();
70 |
71 | var actual = hasher.ComputeHash(input);
72 | CollectionAssert.AreEqual(expected, actual);
73 | }
74 | }
75 | ```
76 |
--------------------------------------------------------------------------------
/test/DagLinkTest.cs:
--------------------------------------------------------------------------------
1 | using Ipfs;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.IO;
8 | using Google.Protobuf;
9 |
10 | namespace Ipfs
11 | {
12 | [TestClass]
13 | public class DagLinkTest
14 | {
15 | [TestMethod]
16 | public void Creating()
17 | {
18 | var link = new DagLink("abc", "QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39V", 5);
19 | Assert.AreEqual("abc", link.Name);
20 | Assert.AreEqual("QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39V", (string)link.Id);
21 | Assert.AreEqual(5, link.Size);
22 | }
23 |
24 | [TestMethod]
25 | public void Cloning()
26 | {
27 | var link = new DagLink("abc", "QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39V", 5);
28 | var clone = new DagLink(link);
29 |
30 | Assert.AreEqual("abc", clone.Name);
31 | Assert.AreEqual("QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39V", (string)clone.Id);
32 | Assert.AreEqual(5, clone.Size);
33 | }
34 |
35 | [TestMethod]
36 | public void Encoding()
37 | {
38 | var encoded = "0a22122023dca2a7429612378554b0bb5b85012dec00a17cc2c673f17d2b76a50b839cd51201611803";
39 | var link = new DagLink("a", "QmQke7LGtfu3GjFP3AnrP8vpEepQ6C5aJSALKAq653bkRi", 3);
40 | var x = link.ToArray();
41 | Assert.AreEqual(encoded, link.ToArray().ToHexString());
42 | }
43 |
44 | [TestMethod]
45 | public void Encoding_EmptyName()
46 | {
47 | var encoded = "0a22122023dca2a7429612378554b0bb5b85012dec00a17cc2c673f17d2b76a50b839cd512001803";
48 | var link = new DagLink("", "QmQke7LGtfu3GjFP3AnrP8vpEepQ6C5aJSALKAq653bkRi", 3);
49 | var x = link.ToArray();
50 | Assert.AreEqual(encoded, link.ToArray().ToHexString());
51 | }
52 |
53 | [TestMethod]
54 | public void Encoding_NullName()
55 | {
56 | var encoded = "0a22122023dca2a7429612378554b0bb5b85012dec00a17cc2c673f17d2b76a50b839cd51803";
57 | var link = new DagLink(null, "QmQke7LGtfu3GjFP3AnrP8vpEepQ6C5aJSALKAq653bkRi", 3);
58 | var x = link.ToArray();
59 | Assert.AreEqual(encoded, link.ToArray().ToHexString());
60 | }
61 |
62 | [TestMethod]
63 | public void Null_Stream()
64 | {
65 | ExceptionAssert.Throws(() => new DagLink((CodedInputStream)null));
66 | ExceptionAssert.Throws(() => new DagLink((Stream)null));
67 | }
68 |
69 | [TestMethod]
70 | public void Cid_V1()
71 | {
72 | var link = new DagLink("hello", "zB7NCdng5WffuNCgHu4PhDj7nbtuVrhPc2pMhanNxYKRsECdjX9nd44g6CRu2xNrj2bG2NNaTsveL5zDGWhbfiug3VekW", 11);
73 | Assert.AreEqual("hello", link.Name);
74 | Assert.AreEqual(1, link.Id.Version);
75 | Assert.AreEqual("raw", link.Id.ContentType);
76 | Assert.AreEqual("sha2-512", link.Id.Hash.Algorithm.Name);
77 | Assert.AreEqual(11, link.Size);
78 | }
79 |
80 |
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | # gitversion will change the version number
2 | version: x-{build}
3 |
4 | for:
5 | -
6 | branches:
7 | only:
8 | - master
9 |
10 | environment:
11 | snk_secret:
12 | secure: 5QzEIgiDqTIrZruPaIQIvTlNMl5BZ7TGEps7ALyBfHE=
13 | git_token:
14 | secure: NeX5NCOUXsCLc1UjTJjqB9F02FZ8Wq0VsxqTXC8kBdyK6zjxjebrf/9Da2sY1Kql
15 |
16 | configuration: Release
17 | os: Visual Studio 2019
18 |
19 | init:
20 | - git config --global core.autocrlf input
21 | - git config --global credential.helper store
22 | - ps: Add-Content "$env:USERPROFILE\.git-credentials" "https://$($env:git_token):x-oauth-basic@github.com`n"
23 | - git config --global user.email "noreply@emanon.org"
24 | - git config --global user.name "Appveyor CI"
25 |
26 | environment:
27 | COVERALLS_REPO_TOKEN:
28 | secure: j4sELCwhVRRjNXFVhjPZjdG4y2itz8jrExhlyDU/lTiLlRQ/P4brB69MGQRFBQae
29 | DOTNET_CLI_TELEMETRY_OPTOUT: 1
30 |
31 | # tools we need for bulding/testing/deploying
32 | install:
33 | # see https://help.appveyor.com/discussions/problems/24758-gitversion-5-not-working-on-visual-studio-2019-build
34 | - choco install gitversion.portable -y --version 4.0.0
35 | - npm install gh-pages@2.0 -g
36 | # No longer signing the assembly
37 | #- nuget install secure-file -ExcludeVersion
38 | #- if defined snk_secret secure-file\tools\secure-file -decrypt src\ipfs.ci.snk.enc -secret %snk_secret% -out src\ipfs.dev.snk
39 |
40 | pull_requests:
41 | do_not_increment_build_number: true
42 |
43 | nuget:
44 | disable_publish_on_pr: true
45 |
46 | before_build:
47 | # - ps: gitversion /output buildserver /updateAssemblyInfo >gitversion.log
48 | - gitversion /output buildserver /updateAssemblyInfo >gitversion
49 |
50 | - echo %GitVersion_MajorMinorPatch%
51 | - echo %GitVersion_NuGetVersion%
52 |
53 | build_script:
54 | - dotnet build -c %CONFIGURATION% -p:Version=%GitVersion_MajorMinorPatch% -p:AssemblyVersion=%GitVersion_MajorMinorPatch%
55 |
56 | after_build:
57 | # Build documentation in doc\_site
58 | - cmd: choco install docfx -y
59 | - cmd: builddocs.cmd
60 | - cmd: 7z a -tzip docs.zip doc\_site
61 | - cmd: appveyor PushArtifact docs.zip
62 | - if defined git_token gh-pages -d doc\_site -m "new docs %GitVersion_FullSemVer%"
63 |
64 | test_script:
65 | - dotnet test -c %CONFIGURATION% --no-build --no-restore test
66 |
67 | after_test:
68 | # Generate coverage report
69 | - dotnet test -c %CONFIGURATION% -f netcoreapp3.0 --no-build --no-restore test /p:CollectCoverage=true /p:Include="[Ipfs.Core]*"
70 | - choco install codecov -y
71 | - codecov -f "test/coverage.opencover.xml"
72 | - dotnet tool install --global coveralls.net --version 1.0.0
73 | - if defined COVERALLS_REPO_TOKEN
74 | csmacnz.coveralls.exe
75 | --opencover -i test/coverage.opencover.xml --useRelativePaths --serviceName appveyor --jobId %APPVEYOR_BUILD_NUMBER%
76 |
77 | artifacts:
78 | - path: 'src/**/*.nupkg'
79 | name: nupkg
80 | - path: 'src/**/*.snupkg'
81 | name: snupkg
82 |
83 | # publish NuGet package on tag build
84 | deploy:
85 | - provider: NuGet
86 | api_key:
87 | secure: OdmGEj/l0K0ZPDmXAYx+fryCzV012eTrM29ALBuL0waxvwLvrufdDXiI+1iNhWEG
88 | on:
89 | appveyor_repo_tag: true
90 |
--------------------------------------------------------------------------------
/src/Base58.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace Ipfs
7 | {
8 | ///
9 | /// A codec for IPFS Base-58.
10 | ///
11 | ///
12 | ///
13 | /// A codec for Base-58, and . Adds the extension method
14 | /// to encode a byte array and to decode a Base-58 string.
15 | ///
16 | ///
17 | /// This is just thin wrapper of .
18 | ///
19 | ///
20 | /// This codec uses the BitCoin alphabet not Flickr's.
21 | ///
22 | ///
23 | public static class Base58
24 | {
25 | ///
26 | /// Converts an array of 8-bit unsigned integers to its equivalent string representation that is
27 | /// encoded with base-58 characters.
28 | /// s
29 | ///
30 | /// An array of 8-bit unsigned integers.
31 | ///
32 | ///
33 | /// The string representation, in base 58, of the contents of .
34 | ///
35 | public static string Encode(byte[] bytes)
36 | {
37 | return SimpleBase.Base58.Bitcoin.Encode(bytes);
38 | }
39 |
40 | ///
41 | /// Converts an array of 8-bit unsigned integers to its equivalent string representation that is
42 | /// encoded with base-58 digits.
43 | ///
44 | ///
45 | /// An array of 8-bit unsigned integers.
46 | ///
47 | ///
48 | /// The string representation, in base 58, of the contents of .
49 | ///
50 | public static string ToBase58(this byte[] bytes)
51 | {
52 | return Encode(bytes);
53 | }
54 |
55 | ///
56 | /// Converts the specified , which encodes binary data as base 58 digits,
57 | /// to an equivalent 8-bit unsigned integer array.
58 | ///
59 | ///
60 | /// The base 58 string to convert.
61 | ///
62 | ///
63 | /// An array of 8-bit unsigned integers that is equivalent to .
64 | ///
65 | public static byte[] Decode(string s)
66 | {
67 | return SimpleBase.Base58.Bitcoin.Decode(s);
68 | }
69 |
70 | ///
71 | /// Converts the specified , which encodes binary data as base 58 digits,
72 | /// to an equivalent 8-bit unsigned integer array.
73 | ///
74 | ///
75 | /// The base 58 string to convert.
76 | ///
77 | ///
78 | /// An array of 8-bit unsigned integers that is equivalent to .
79 | ///
80 | public static byte[] FromBase58(this string s)
81 | {
82 | return Decode(s);
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/CoreApi/IConfigApi.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json.Linq;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 |
8 | namespace Ipfs.CoreApi
9 | {
10 | ///
11 | /// Manages the IPFS Configuration.
12 | ///
13 | ///
14 | ///
15 | /// Configuration values are JSON. Json.NET
16 | /// is used to represent JSON.
17 | ///
18 | ///
19 | /// Config API spec
20 | public interface IConfigApi
21 | {
22 | ///
23 | /// Gets the entire configuration.
24 | ///
25 | ///
26 | /// A containing the configuration.
27 | ///
28 | Task GetAsync(CancellationToken cancel = default(CancellationToken));
29 |
30 | ///
31 | /// Gets the value of a configuration key.
32 | ///
33 | ///
34 | /// The key name, such as "Addresses.API".
35 | ///
36 | ///
37 | /// Is used to stop the task. When cancelled, the is raised.
38 | ///
39 | ///
40 | /// The value of the as .
41 | ///
42 | ///
43 | /// When the does not exist.
44 | ///
45 | ///
46 | /// Keys are case sensistive.
47 | ///
48 | Task GetAsync(string key, CancellationToken cancel = default(CancellationToken));
49 |
50 | ///
51 | /// Adds or replaces a configuration value.
52 | ///
53 | ///
54 | /// The key name, such as "Addresses.API".
55 | ///
56 | ///
57 | /// The new value of the .
58 | ///
59 | ///
60 | /// Is used to stop the task. When cancelled, the is raised.
61 | ///
62 | Task SetAsync(string key, string value, CancellationToken cancel = default(CancellationToken));
63 |
64 | ///
65 | /// Adds or replaces a configuration value.
66 | ///
67 | ///
68 | /// The key name, such as "Addresses.API".
69 | ///
70 | ///
71 | /// The new JSON value of the .
72 | ///
73 | ///
74 | /// Is used to stop the task. When cancelled, the is raised.
75 | ///
76 | Task SetAsync(string key, JToken value, CancellationToken cancel = default(CancellationToken));
77 |
78 | ///
79 | /// Replaces the entire configuration.
80 | ///
81 | ///
82 | Task ReplaceAsync(JObject config);
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/Base64NoPad.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace Ipfs
7 | {
8 | ///
9 | /// A codec for Base-64 (RFC 4648) with no padding.
10 | ///
11 | ///
12 | ///
13 | /// A codec for Base-64, and . Adds the extension method
14 | /// to encode a byte array and to decode a Base-64 string.
15 | ///
16 | ///
17 | public static class Base64NoPad
18 | {
19 | ///
20 | /// Converts an array of 8-bit unsigned integers to its equivalent string representation that is
21 | /// encoded with base-64 characters.
22 | /// s
23 | ///
24 | /// An array of 8-bit unsigned integers.
25 | ///
26 | ///
27 | /// The string representation, in base 64, of the contents of .
28 | ///
29 | public static string Encode(byte[] bytes)
30 | {
31 | return Convert.ToBase64String(bytes)
32 | .TrimEnd('=');
33 | }
34 |
35 | ///
36 | /// Converts an array of 8-bit unsigned integers to its equivalent string representation that is
37 | /// encoded with base-64 digits.
38 | ///
39 | ///
40 | /// An array of 8-bit unsigned integers.
41 | /// s
42 | ///
43 | /// The string representation, in base 64, of the contents of .
44 | ///
45 | public static string ToBase64NoPad(this byte[] bytes)
46 | {
47 | return Encode(bytes);
48 | }
49 |
50 | ///
51 | /// Converts the specified , which encodes binary data as base 64 digits,
52 | /// to an equivalent 8-bit unsigned integer array.
53 | ///
54 | ///
55 | /// The base 64 string to convert.
56 | ///
57 | ///
58 | /// An array of 8-bit unsigned integers that is equivalent to .
59 | ///
60 | public static byte[] Decode(string s)
61 | {
62 | switch (s.Length % 4) // Pad with trailing '='s
63 | {
64 | case 0: break; // No pad chars in this case
65 | case 2: s += "=="; break; // Two pad chars
66 | case 3: s += "="; break; // One pad char
67 | default: throw new Exception("Illegal base64 string!");
68 | }
69 |
70 | return Convert.FromBase64String(s); // Standard base64 decoder
71 | }
72 |
73 | ///
74 | /// Converts the specified , which encodes binary data as base 64 digits,
75 | /// to an equivalent 8-bit unsigned integer array.
76 | ///
77 | ///
78 | /// The base 64 string to convert.
79 | ///
80 | ///
81 | /// An array of 8-bit unsigned integers that is equivalent to .
82 | ///
83 | public static byte[] FromBase64NoPad(this string s)
84 | {
85 | return Decode(s);
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/Base32.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace Ipfs
7 | {
8 | ///
9 | /// A codec for Base-32.
10 | ///
11 | ///
12 | ///
13 | /// A codec for Base-32, and . Adds the extension method
14 | /// to encode a byte array and to decode a Base-32 string.
15 | ///
16 | ///
17 | /// and produce the lower case form of
18 | /// with no padding.
19 | /// and are case-insensitive and
20 | /// allow optional padding.
21 | ///
22 | ///
23 | /// A thin wrapper around .
24 | ///
25 | ///
26 | public static class Base32
27 | {
28 | ///
29 | /// Converts an array of 8-bit unsigned integers to its equivalent string representation that is
30 | /// encoded with base-32 characters.
31 | /// s
32 | ///
33 | /// An array of 8-bit unsigned integers.
34 | ///
35 | ///
36 | /// The string representation, in base 32, of the contents of .
37 | ///
38 | public static string Encode(byte[] input)
39 | {
40 | return SimpleBase.Base32.Rfc4648.Encode(input, false).ToLowerInvariant();
41 | }
42 |
43 | ///
44 | /// Converts an array of 8-bit unsigned integers to its equivalent string representation that is
45 | /// encoded with base-32 digits.
46 | ///
47 | ///
48 | /// An array of 8-bit unsigned integers.
49 | ///
50 | ///
51 | /// The string representation, in base 32, of the contents of .
52 | ///
53 | public static string ToBase32(this byte[] bytes)
54 | {
55 | return Encode(bytes);
56 | }
57 |
58 | ///
59 | /// Converts the specified , which encodes binary data as base 32 digits,
60 | /// to an equivalent 8-bit unsigned integer array.
61 | ///
62 | ///
63 | /// The base 32 string to convert.
64 | ///
65 | ///
66 | /// An array of 8-bit unsigned integers that is equivalent to .
67 | ///
68 | ///
69 | /// is case-insensitive and allows padding.
70 | ///
71 | public static byte[] Decode(string input)
72 | {
73 | return SimpleBase.Base32.Rfc4648.Decode(input);
74 | }
75 |
76 | ///
77 | /// Converts the specified , which encodes binary data as base 32 digits,
78 | /// to an equivalent 8-bit unsigned integer array.
79 | ///
80 | ///
81 | /// The base 32 string to convert; case-insensitive and allows padding.
82 | ///
83 | ///
84 | /// An array of 8-bit unsigned integers that is equivalent to .
85 | ///
86 | public static byte[] FromBase32(this string s)
87 | {
88 | return Decode(s);
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/IpfsCore.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard14;netstandard2;net45;netcoreapp3.0
5 | Ipfs.Core
6 | Ipfs
7 | portable
8 | true
9 |
10 |
11 | 0.42
12 | 0.42
13 |
14 |
15 | Ipfs.Core
16 | Richard Schneider
17 | IPFS Core Objects
18 |
19 | Core objects and interfaces for IPFS.
20 |
21 | The InterPlanetary File System is the permanent web. It is a new hypermedia distribution protocol, addressed by content and identities. IPFS enables the creation of completely distributed applications. It aims to make the web faster, safer, and more open.
22 |
23 | false
24 | https://github.com/richardschneider/net-ipfs-core/releases
25 | © 2015-2019 Richard Schneider
26 | ipfs peer-to-peer distributed file-system
27 | True
28 | https://github.com/richardschneider/net-ipfs-core
29 | https://raw.githubusercontent.com/richardschneider/net-ipfs-core/master/doc/images/ipfs-cs-logo-64x64.png
30 |
31 | true
32 | true
33 |
34 |
35 |
36 |
37 | true
38 |
39 | false
40 |
41 | true
42 | snupkg
43 | .pdb;$(AllowedOutputExtensionsInPackageBuildOutputFolder)
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | NETSTANDARD14
65 |
66 |
67 |
68 | ASYNCSTREAM
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | build/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # Visual Studo 2015 cache/options directory
26 | .vs/
27 |
28 | # MSTest test Results
29 | [Tt]est[Rr]esult*/
30 | [Bb]uild[Ll]og.*
31 |
32 | # NUNIT
33 | *.VisualState.xml
34 | TestResult.xml
35 |
36 | # Build Results of an ATL Project
37 | [Dd]ebugPS/
38 | [Rr]eleasePS/
39 | dlldata.c
40 |
41 | *_i.c
42 | *_p.c
43 | *_i.h
44 | *.ilk
45 | *.meta
46 | *.obj
47 | *.pch
48 | *.pdb
49 | *.pgc
50 | *.pgd
51 | *.rsp
52 | *.sbr
53 | *.tlb
54 | *.tli
55 | *.tlh
56 | *.tmp
57 | *.tmp_proj
58 | *.log
59 | *.vspscc
60 | *.vssscc
61 | .builds
62 | *.pidb
63 | *.svclog
64 | *.scc
65 |
66 | # Chutzpah Test files
67 | _Chutzpah*
68 |
69 | # Visual C++ cache files
70 | ipch/
71 | *.aps
72 | *.ncb
73 | *.opensdf
74 | *.sdf
75 | *.cachefile
76 |
77 | # Visual Studio profiler
78 | *.psess
79 | *.vsp
80 | *.vspx
81 |
82 | # TFS 2012 Local Workspace
83 | $tf/
84 |
85 | # Guidance Automation Toolkit
86 | *.gpState
87 |
88 | # ReSharper is a .NET coding add-in
89 | _ReSharper*/
90 | *.[Rr]e[Ss]harper
91 | *.DotSettings.user
92 |
93 | # JustCode is a .NET coding addin-in
94 | .JustCode
95 |
96 | # TeamCity is a build add-in
97 | _TeamCity*
98 |
99 | # DotCover is a Code Coverage Tool
100 | *.dotCover
101 |
102 | # NCrunch
103 | _NCrunch_*
104 | .*crunch*.local.xml
105 |
106 | # MightyMoose
107 | *.mm.*
108 | AutoTest.Net/
109 |
110 | # Web workbench (sass)
111 | .sass-cache/
112 |
113 | # Installshield output folder
114 | [Ee]xpress/
115 |
116 | # DocProject is a documentation generator add-in
117 | DocProject/buildhelp/
118 | DocProject/Help/*.HxT
119 | DocProject/Help/*.HxC
120 | DocProject/Help/*.hhc
121 | DocProject/Help/*.hhk
122 | DocProject/Help/*.hhp
123 | DocProject/Help/Html2
124 | DocProject/Help/html
125 |
126 | # Click-Once directory
127 | publish/
128 |
129 | # Publish Web Output
130 | *.[Pp]ublish.xml
131 | *.azurePubxml
132 | # TODO: Comment the next line if you want to checkin your web deploy settings
133 | # but database connection strings (with potential passwords) will be unencrypted
134 | *.pubxml
135 | *.publishproj
136 |
137 | # NuGet Packages
138 | *.nupkg
139 | # The packages folder can be ignored because of Package Restore
140 | **/packages/*
141 | # except build/, which is used as an MSBuild target.
142 | !**/packages/build/
143 | # Uncomment if necessary however generally it will be regenerated when needed
144 | #!**/packages/repositories.config
145 |
146 | # Windows Azure Build Output
147 | csx/
148 | *.build.csdef
149 |
150 | # Windows Store app package directory
151 | AppPackages/
152 |
153 | # Others
154 | *.[Cc]ache
155 | ClientBin/
156 | [Ss]tyle[Cc]op.*
157 | ~$*
158 | *~
159 | *.dbmdl
160 | *.dbproj.schemaview
161 | *.pfx
162 | *.publishsettings
163 | node_modules/
164 | bower_components/
165 |
166 | # RIA/Silverlight projects
167 | Generated_Code/
168 |
169 | # Backup & report files from converting an old project file
170 | # to a newer Visual Studio version. Backup files are not needed,
171 | # because we have git ;-)
172 | _UpgradeReport_Files/
173 | Backup*/
174 | UpgradeLog*.XML
175 | UpgradeLog*.htm
176 |
177 | # SQL Server files
178 | *.mdf
179 | *.ldf
180 |
181 | # Business Intelligence projects
182 | *.rdl.data
183 | *.bim.layout
184 | *.bim_*.settings
185 |
186 | # Microsoft Fakes
187 | FakesAssemblies/
188 |
189 | # Node.js Tools for Visual Studio
190 | .ntvs_analysis.dat
191 |
192 | # Visual Studio 6 build log
193 | *.plg
194 |
195 | # Visual Studio 6 workspace options file
196 | *.opt
197 |
198 | # VS 2017 creates this
199 | src/Ipfs.Core.xml
200 |
--------------------------------------------------------------------------------
/src/CoreApi/AddFileOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Ipfs.CoreApi
6 | {
7 | ///
8 | /// The options when adding data to the IPFS file system.
9 | ///
10 | ///
11 | public class AddFileOptions
12 | {
13 | ///
14 | /// Determines if the data is pinned to local storage.
15 | ///
16 | ///
17 | /// If true the data is pinned to local storage and will not be
18 | /// garbage collected. The default is true.
19 | ///
20 | public bool Pin { get; set; } = true;
21 |
22 | ///
23 | /// The maximum number of data bytes in a block.
24 | ///
25 | ///
26 | /// The default is 256 * 1024 (262,144) bytes.
27 | ///
28 | public int ChunkSize { get; set; } = 256 * 1024;
29 |
30 | ///
31 | /// Determines if the trickle-dag format is used for dag generation.
32 | ///
33 | ///
34 | /// The default is false.
35 | ///
36 | public bool Trickle { get; set; } = false;
37 |
38 | ///
39 | /// Determines if added file(s) are wrapped in a directory object.
40 | ///
41 | ///
42 | /// The default is false.
43 | ///
44 | public bool Wrap { get; set; } = false;
45 |
46 | ///
47 | /// Determines if raw blocks are used for leaf data blocks.
48 | ///
49 | ///
50 | /// The default is false.
51 | ///
52 | ///
53 | /// RawLeaves and are mutually exclusive.
54 | ///
55 | public bool RawLeaves { get; set; } = false;
56 |
57 | ///
58 | /// The hashing algorithm name to use.
59 | ///
60 | ///
61 | /// The algorithm name used to produce the .
62 | /// Defaults to .
63 | ///
64 | ///
65 | public string Hash { get; set; } = MultiHash.DefaultAlgorithmName;
66 |
67 | ///
68 | /// The encoding algorithm name to use.
69 | ///
70 | ///
71 | /// The algorithm name used to produce the .
72 | /// Defaults to .
73 | ///
74 | ///
75 | public string Encoding { get; set; } = MultiBase.DefaultAlgorithmName;
76 |
77 | ///
78 | /// Determines if only file information is produced.
79 | ///
80 | ///
81 | /// If true no data is added to IPFS. The default is false.
82 | ///
83 | public bool OnlyHash { get; set; } = false;
84 |
85 | ///
86 | /// The key name used to protect (encrypt) the file contents.
87 | ///
88 | ///
89 | /// The name of an existing key.
90 | ///
91 | ///
92 | /// ProtectionKey and are mutually exclusive.
93 | ///
94 | ///
95 | public string ProtectionKey { get; set; }
96 |
97 | ///
98 | /// Used to report the progress of a file transfer.
99 | ///
100 | public IProgress Progress { get; set; }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/test/DurationTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using Microsoft.VisualStudio.TestTools.UnitTesting;
6 | using System.IO;
7 |
8 | namespace Ipfs
9 | {
10 |
11 | [TestClass]
12 | public class DurationTest
13 | {
14 | [TestMethod]
15 | public void Parsing_Examples()
16 | {
17 | Assert.AreEqual(TimeSpan.FromMilliseconds(300), Duration.Parse("300ms"));
18 | Assert.AreEqual(TimeSpan.FromHours(-1.5), Duration.Parse("-1.5h"));
19 | Assert.AreEqual(new TimeSpan(2, 45, 0), Duration.Parse("2h45m"));
20 | Assert.AreEqual(new TimeSpan(0, 1, 0) + TimeSpan.FromSeconds(4.483878032), Duration.Parse("1m4.483878032s"));
21 | }
22 |
23 | [TestMethod]
24 | public void Parsing_Zero()
25 | {
26 | Assert.AreEqual(TimeSpan.Zero, Duration.Parse("0s"));
27 | Assert.AreEqual(TimeSpan.Zero, Duration.Parse("0µs"));
28 | Assert.AreEqual(TimeSpan.Zero, Duration.Parse("0ns"));
29 | Assert.AreEqual(TimeSpan.Zero, Duration.Parse("n/a"));
30 | Assert.AreEqual(TimeSpan.Zero, Duration.Parse("unknown"));
31 | Assert.AreEqual(TimeSpan.Zero, Duration.Parse(""));
32 | }
33 |
34 | [TestMethod]
35 | public void Parsing_Negative()
36 | {
37 | Assert.AreEqual(TimeSpan.FromHours(-2), Duration.Parse("-1.5h30m"));
38 | }
39 |
40 | [TestMethod]
41 | public void Parsing_Submilliseconds()
42 | {
43 | // Note: resolution of TimeSpan is 100ns, e.g. 1 tick.
44 | Assert.AreEqual(TimeSpan.FromTicks(2), Duration.Parse("200ns"));
45 | Assert.AreEqual(TimeSpan.FromTicks(2000), Duration.Parse("200us"));
46 | Assert.AreEqual(TimeSpan.FromTicks(2000), Duration.Parse("200µs"));
47 | }
48 |
49 | [TestMethod]
50 | public void Parsing_MissingNumber()
51 | {
52 | ExceptionAssert.Throws(() =>
53 | {
54 | var _ = Duration.Parse("s");
55 | });
56 | }
57 |
58 | [TestMethod]
59 | public void Parsing_MissingUnit()
60 | {
61 | ExceptionAssert.Throws(() =>
62 | {
63 | var _ = Duration.Parse("1");
64 | }, "Missing IPFS duration unit.");
65 | }
66 |
67 | [TestMethod]
68 | public void Parsing_InvalidUnit()
69 | {
70 | ExceptionAssert.Throws(() =>
71 | {
72 | var _ = Duration.Parse("1jiffy");
73 | }, "Unknown IPFS duration unit 'jiffy'.");
74 | }
75 |
76 | [TestMethod]
77 | public void Stringify()
78 | {
79 | Assert.AreEqual("0s", Duration.Stringify(TimeSpan.Zero));
80 | Assert.AreEqual("n/a", Duration.Stringify(TimeSpan.Zero, "n/a"));
81 |
82 | Assert.AreEqual("2h", Duration.Stringify(new TimeSpan(2, 0, 0)));
83 | Assert.AreEqual("3m", Duration.Stringify(new TimeSpan(0, 3, 0)));
84 | Assert.AreEqual("4s", Duration.Stringify(new TimeSpan(0, 0, 4)));
85 | Assert.AreEqual("5ms", Duration.Stringify(new TimeSpan(0, 0, 0, 0, 5)));
86 | Assert.AreEqual("2h4s", Duration.Stringify(new TimeSpan(2, 0, 4)));
87 | Assert.AreEqual("26h3m4s5ms", Duration.Stringify(new TimeSpan(1, 2, 3, 4, 5)));
88 |
89 | Assert.AreEqual("-48h", Duration.Stringify(TimeSpan.FromDays(-2)));
90 | Assert.AreEqual("-2h", Duration.Stringify(TimeSpan.FromHours(-2)));
91 | Assert.AreEqual("-1h30m", Duration.Stringify(TimeSpan.FromHours(-1.5)));
92 |
93 | Assert.AreEqual("200ns", Duration.Stringify(TimeSpan.FromTicks(2)));
94 | Assert.AreEqual("200us", Duration.Stringify(TimeSpan.FromTicks(2000)));
95 | Assert.AreEqual("200us300ns", Duration.Stringify(TimeSpan.FromTicks(2003)));
96 | }
97 | }
98 | }
99 |
100 |
--------------------------------------------------------------------------------
/src/Base64Url.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace Ipfs
7 | {
8 | ///
9 | /// A codec for Base-64 URL (RFC 4648).
10 | ///
11 | ///
12 | ///
13 | /// A codec for Base-64 URL, and . Adds the extension method
14 | /// to encode a byte array and to decode a Base-64 URL string.
15 | ///
16 | ///
17 | /// The original code was found at .
18 | ///
19 | ///
20 | public static class Base64Url
21 | {
22 | ///
23 | /// Converts an array of 8-bit unsigned integers to its equivalent string representation that is
24 | /// encoded with base-64 URL characters.
25 | /// s
26 | ///
27 | /// An array of 8-bit unsigned integers.
28 | ///
29 | ///
30 | /// The string representation, in base 64, of the contents of .
31 | ///
32 | public static string Encode(byte[] bytes)
33 | {
34 | string s = Convert.ToBase64String(bytes); // Standard base64 encoder
35 |
36 | s = s.TrimEnd('='); // Remove any trailing '='s
37 | s = s.Replace('+', '-'); // 62nd char of encoding
38 | s = s.Replace('/', '_'); // 63rd char of encoding
39 |
40 | return s;
41 | }
42 |
43 | ///
44 | /// Converts an array of 8-bit unsigned integers to its equivalent string representation that is
45 | /// encoded with base-64 URL digits.
46 | ///
47 | ///
48 | /// An array of 8-bit unsigned integers.
49 | /// s
50 | ///
51 | /// The string representation, in base 64, of the contents of .
52 | ///
53 | public static string ToBase64Url(this byte[] bytes)
54 | {
55 | return Encode(bytes);
56 | }
57 |
58 | ///
59 | /// Converts the specified , which encodes binary data as base 64 URL digits,
60 | /// to an equivalent 8-bit unsigned integer array.
61 | ///
62 | ///
63 | /// The base 64 string to convert.
64 | ///
65 | ///
66 | /// An array of 8-bit unsigned integers that is equivalent to .
67 | ///
68 | public static byte[] Decode(string s)
69 | {
70 | s = s.Replace('-', '+'); // 62nd char of encoding
71 | s = s.Replace('_', '/'); // 63rd char of encoding
72 |
73 | switch (s.Length % 4) // Pad with trailing '='s
74 | {
75 | case 0: break; // No pad chars in this case
76 | case 2: s += "=="; break; // Two pad chars
77 | case 3: s += "="; break; // One pad char
78 | default: throw new Exception("Illegal base64url string!");
79 | }
80 |
81 | return Convert.FromBase64String(s); // Standard base64 decoder
82 | }
83 |
84 | ///
85 | /// Converts the specified , which encodes binary data as base 64 url digits,
86 | /// to an equivalent 8-bit unsigned integer array.
87 | ///
88 | ///
89 | /// The base 64 string to convert.
90 | ///
91 | ///
92 | /// An array of 8-bit unsigned integers that is equivalent to .
93 | ///
94 | public static byte[] FromBase64Url(this string s)
95 | {
96 | return Decode(s);
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/MultiCodec.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using Ipfs.Registry;
8 | using Google.Protobuf;
9 |
10 | namespace Ipfs
11 | {
12 | ///
13 | /// Wraps other formats with a tiny bit of self-description.
14 | ///
15 | ///
16 | /// MultiCodec is a self-describing multiformat, it wraps other formats with a
17 | /// tiny bit of self-description. A multicodec identifier is both a varint and the code
18 | /// identifying the following data.
19 | ///
20 | /// Adds the following extension methods to
21 | ///
22 | /// - ReadMultiCodec
23 | ///
24 | ///
25 | ///
26 | ///
27 | ///
28 | ///
29 | public static class MultiCodec
30 | {
31 |
32 | ///
33 | /// Reads a from the .
34 | ///
35 | ///
36 | /// A multicodec encoded .
37 | ///
38 | /// The codec.
39 | ///
40 | /// If the code does not exist, a new is
41 | /// registered with the "codec-x"; where
42 | /// 'x' is the code's decimal represention.
43 | ///
44 | public static Codec ReadMultiCodec(this Stream stream)
45 | {
46 | var code = stream.ReadVarint32();
47 | Codec.Codes.TryGetValue(code, out Codec codec);
48 | if (codec == null)
49 | {
50 | codec = Codec.Register($"codec-{code}", code);
51 | }
52 | return codec;
53 | }
54 |
55 | ///
56 | /// Reads a from the .
57 | ///
58 | ///
59 | /// A multicodec encoded .
60 | ///
61 | /// The codec.
62 | ///
63 | /// If the code does not exist, a new is
64 | /// registered with the "codec-x"; where
65 | /// 'x' is the code's decimal represention.
66 | ///
67 | public static Codec ReadMultiCodec(this CodedInputStream stream)
68 | {
69 | var code = stream.ReadInt32();
70 | Codec.Codes.TryGetValue(code, out Codec codec);
71 | if (codec == null)
72 | {
73 | codec = Codec.Register($"codec-{code}", code);
74 | }
75 | return codec;
76 | }
77 |
78 | ///
79 | /// Writes a to the .
80 | ///
81 | ///
82 | /// A multicodec encoded .
83 | ///
84 | ///
85 | /// The .
86 | ///
87 | ///
88 | /// Writes the of the to
89 | /// the .
90 | ///
91 | ///
92 | /// When is not registered.
93 | ///
94 | public static void WriteMultiCodec(this Stream stream, string name)
95 | {
96 | Codec.Names.TryGetValue(name, out Codec codec);
97 | if (codec == null)
98 | {
99 | throw new KeyNotFoundException($"Codec '{name}' is not registered.");
100 | }
101 | stream.WriteVarint(codec.Code);
102 | }
103 |
104 |
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/CoreApi/IBootstrapApi.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace Ipfs.CoreApi
8 | {
9 | ///
10 | /// Manages the list of initial peers.
11 | ///
12 | ///
13 | /// The API manipulates the "bootstrap list", which contains
14 | /// the addresses of the bootstrap nodes. These are the trusted peers from
15 | /// which to learn about other peers in the network.
16 | ///
17 | ///
18 | /// Bootstrap API spec
19 | public interface IBootstrapApi
20 | {
21 | ///
22 | /// Adds a new peer.
23 | ///
24 | ///
25 | /// The address must end with the ipfs protocol and the public ID
26 | /// of the peer. For example "/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ"
27 | ///
28 | ///
29 | /// Is used to stop the task. When cancelled, the is raised.
30 | ///
31 | ///
32 | /// A task that represents the asynchronous operation. The task's result is
33 | /// the address that was added or null if the address is already
34 | /// in the bootstrap list.
35 | ///
36 | Task AddAsync(MultiAddress address, CancellationToken cancel = default(CancellationToken));
37 |
38 | ///
39 | /// Adds the default peers to the list.
40 | ///
41 | ///
42 | /// Is used to stop the task. When cancelled, the is raised.
43 | ///
44 | ///
45 | /// A task that represents the asynchronous operation. The task's result is
46 | /// the sequence of addresses that were added.
47 | ///
48 | Task> AddDefaultsAsync(CancellationToken cancel = default(CancellationToken));
49 |
50 | ///
51 | /// List all the peers.
52 | ///
53 | ///
54 | /// Is used to stop the task. When cancelled, the is raised.
55 | ///
56 | ///
57 | /// A task that represents the asynchronous operation. The task's result is
58 | /// a sequence of addresses.
59 | ///
60 | Task> ListAsync(CancellationToken cancel = default(CancellationToken));
61 |
62 | ///
63 | /// Delete the specified peer.
64 | ///
65 | ///
66 | /// The address must end with the ipfs protocol and the public ID
67 | /// of the peer. For example "/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ"
68 | ///
69 | ///
70 | /// Is used to stop the task. When cancelled, the is raised.
71 | ///
72 | ///
73 | /// A task that represents the asynchronous operation. The task's result is
74 | /// the address that was removed or null if the
75 | /// is not in the bootstrap list.
76 | ///
77 | Task RemoveAsync(MultiAddress address, CancellationToken cancel = default(CancellationToken));
78 |
79 | ///
80 | /// Remove all the peers.
81 | ///
82 | ///
83 | /// Is used to stop the task. When cancelled, the is raised.
84 | ///
85 | ///
86 | /// A task that represents the asynchronous operation.
87 | ///
88 | Task RemoveAllAsync(CancellationToken cancel = default(CancellationToken));
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/CoreApi/IBitswapApi.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace Ipfs.CoreApi
8 | {
9 | ///
10 | /// Data trading module for IPFS. Its purpose is to request blocks from and
11 | /// send blocks to other peers in the network.
12 | ///
13 | ///
14 | /// Bitswap has two primary jobs
15 | ///
16 | /// -
17 | ///
18 | /// Attempt to acquire blocks from the network that have been requested by the client
19 | ///
20 | ///
21 | /// -
22 | ///
23 | /// Judiciously (though strategically) send blocks in its possession to other peers who want them
24 | ///
25 | ///
26 | ///
27 | ///
28 | /// Bitswap spec
29 | public interface IBitswapApi
30 | {
31 | ///
32 | /// Gets a block from the IPFS network.
33 | ///
34 | ///
35 | /// The of the block.
36 | ///
37 | ///
38 | /// Is used to stop the task. When cancelled, the is raised.
39 | ///
40 | ///
41 | /// A task that represents the asynchronous get operation. The task's value
42 | /// contains the block's id and data.
43 | ///
44 | ///
45 | /// Waits for another peer to supply the block with the .
46 | ///
47 | Task GetAsync(Cid id, CancellationToken cancel = default(CancellationToken));
48 |
49 | ///
50 | /// The blocks that are needed by a peer.
51 | ///
52 | ///
53 | /// The id of an IPFS peer. If not specified (e.g. null), then the local
54 | /// peer is used.
55 | ///
56 | ///
57 | /// Is used to stop the task. When cancelled, the is raised.
58 | ///
59 | ///
60 | /// A task that represents the asynchronous operation. The task's value
61 | /// contains the sequence of blocks needed by the .
62 | ///
63 | Task> WantsAsync(MultiHash peer = null, CancellationToken cancel = default(CancellationToken));
64 |
65 | ///
66 | /// Remove the CID from the want list.
67 | ///
68 | ///
69 | /// The content that is no longer needed.
70 | ///
71 | ///
72 | /// Is used to stop the task. When cancelled, the is raised.
73 | ///
74 | ///
75 | /// A task that represents the asynchronous operation.
76 | ///
77 | ///
78 | /// Any outstanding for the
79 | /// are cancelled.
80 | ///
81 | Task UnwantAsync(Cid id, CancellationToken cancel = default(CancellationToken));
82 |
83 | ///
84 | /// Gets information on the blocks exchanged with a specific .
85 | ///
86 | ///
87 | /// The peer to get information on. If the peer is unknown, then a ledger
88 | /// with zeros is returned.
89 | ///
90 | ///
91 | /// Is used to stop the task. When cancelled, the is raised.
92 | ///
93 | ///
94 | /// A task that represents the asynchronous operation. The task's value
95 | /// contains the for the .
96 | ///
97 | Task LedgerAsync(Peer peer, CancellationToken cancel = default(CancellationToken));
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/test/Registry/HashingAlgorithmTest.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.IO;
7 | using Google.Protobuf;
8 |
9 | namespace Ipfs.Registry
10 | {
11 | [TestClass]
12 | public class HashingAlgorithmTest
13 | {
14 | [TestMethod]
15 | public void GetHasher()
16 | {
17 | using (var hasher = HashingAlgorithm.GetAlgorithm("sha3-256"))
18 | {
19 | Assert.IsNotNull(hasher);
20 | var input = new byte[] { 0xe9 };
21 | var expected = "f0d04dd1e6cfc29a4460d521796852f25d9ef8d28b44ee91ff5b759d72c1e6d6".ToHexBuffer();
22 |
23 | var actual = hasher.ComputeHash(input);
24 | CollectionAssert.AreEqual(expected, actual);
25 | }
26 | }
27 |
28 | [TestMethod]
29 | public void GetHasher_Unknown()
30 | {
31 | ExceptionAssert.Throws(() => HashingAlgorithm.GetAlgorithm("unknown"));
32 | }
33 |
34 | [TestMethod]
35 | public void GetMetadata()
36 | {
37 | var info = HashingAlgorithm.GetAlgorithmMetadata("sha3-256");
38 | Assert.IsNotNull(info);
39 | Assert.AreEqual("sha3-256", info.Name);
40 | Assert.AreEqual(0x16, info.Code);
41 | Assert.AreEqual(256 /8, info.DigestSize);
42 | Assert.IsNotNull(info.Hasher);
43 | }
44 |
45 | [TestMethod]
46 | public void GetMetadata_Unknown()
47 | {
48 | ExceptionAssert.Throws(() => HashingAlgorithm.GetAlgorithmMetadata("unknown"));
49 | }
50 |
51 | [TestMethod]
52 | public void GetMetadata_Alias()
53 | {
54 | var info = HashingAlgorithm.GetAlgorithmMetadata("id");
55 | Assert.IsNotNull(info);
56 | Assert.AreEqual("identity", info.Name);
57 | Assert.AreEqual(0, info.Code);
58 | Assert.AreEqual(0, info.DigestSize);
59 | Assert.IsNotNull(info.Hasher);
60 | }
61 |
62 | [TestMethod]
63 | public void HashingAlgorithm_Bad_Name()
64 | {
65 | ExceptionAssert.Throws(() => HashingAlgorithm.Register(null, 1, 1));
66 | ExceptionAssert.Throws(() => HashingAlgorithm.Register("", 1, 1));
67 | ExceptionAssert.Throws(() => HashingAlgorithm.Register(" ", 1, 1));
68 | }
69 |
70 | [TestMethod]
71 | public void HashingAlgorithm_Name_Already_Exists()
72 | {
73 | ExceptionAssert.Throws(() => HashingAlgorithm.Register("sha1", 0x11, 1));
74 | }
75 |
76 | [TestMethod]
77 | public void HashingAlgorithm_Number_Already_Exists()
78 | {
79 | ExceptionAssert.Throws(() => HashingAlgorithm.Register("sha1-x", 0x11, 1));
80 | }
81 |
82 | [TestMethod]
83 | public void HashingAlgorithms_Are_Enumerable()
84 | {
85 | Assert.IsTrue(5 <= HashingAlgorithm.All.Count());
86 | }
87 |
88 | [TestMethod]
89 | public void HashingAlgorithm_Bad_Alias()
90 | {
91 | ExceptionAssert.Throws(() => HashingAlgorithm.RegisterAlias(null, "sha1"));
92 | ExceptionAssert.Throws(() => HashingAlgorithm.RegisterAlias("", "sha1"));
93 | ExceptionAssert.Throws(() => HashingAlgorithm.RegisterAlias(" ", "sha1"));
94 | }
95 |
96 | [TestMethod]
97 | public void HashingAlgorithm_Alias_Already_Exists()
98 | {
99 | ExceptionAssert.Throws(() => HashingAlgorithm.RegisterAlias("id", "identity"));
100 | }
101 |
102 | [TestMethod]
103 | public void HashingAlgorithm_Alias_Target_Does_Not_Exist()
104 | {
105 | ExceptionAssert.Throws(() => HashingAlgorithm.RegisterAlias("foo", "sha1-x"));
106 | }
107 |
108 | [TestMethod]
109 | public void HashingAlgorithm_Alias_Target_Is_Bad()
110 | {
111 | ExceptionAssert.Throws(() => HashingAlgorithm.RegisterAlias("foo", " "));
112 | }
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/src/CoreApi/INameApi.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace Ipfs.CoreApi
8 | {
9 | ///
10 | /// Manages the IPNS (Interplanetary Name Space).
11 | ///
12 | ///
13 | /// IPNS is a PKI namespace, where names are the hashes of public keys, and
14 | /// the private key enables publishing new(signed) values. The default name
15 | /// is the node's own ,
16 | /// which is the hash of its public key.
17 | ///
18 | /// Name API spec
19 | public interface INameApi
20 | {
21 | ///
22 | /// Publish an IPFS name.
23 | ///
24 | ///
25 | /// The CID or path to the content to publish.
26 | ///
27 | ///
28 | /// Resolve before publishing. Defaults to true.
29 | ///
30 | ///
31 | /// The local key name used to sign the content. Defaults to "self".
32 | ///
33 | ///
34 | /// Duration that the record will be valid for. Defaults to 24 hours.
35 | ///
36 | ///
37 | /// Is used to stop the task. When cancelled, the is raised.
38 | ///
39 | ///
40 | /// A task that represents the asynchronous operation. The task's value is
41 | /// the of the published content.
42 | ///
43 | Task PublishAsync(
44 | string path,
45 | bool resolve = true,
46 | string key = "self",
47 | TimeSpan? lifetime = null,
48 | CancellationToken cancel = default(CancellationToken)
49 | );
50 |
51 | ///
52 | /// Publish an IPFS name.
53 | ///
54 | ///
55 | /// The of the content to publish.
56 | ///
57 | ///
58 | /// The local key name used to sign the content. Defaults to "self".
59 | ///
60 | ///
61 | /// Duration that the record will be valid for. Defaults to 24 hours.
62 | ///
63 | ///
64 | /// Is used to stop the task. When cancelled, the is raised.
65 | ///
66 | ///
67 | /// A task that represents the asynchronous operation. The task's value is
68 | /// the of the published content.
69 | ///
70 | Task PublishAsync(
71 | Cid id,
72 | string key = "self",
73 | TimeSpan? lifetime = null,
74 | CancellationToken cancel = default(CancellationToken)
75 | );
76 |
77 | ///
78 | /// Resolve an IPNS name.
79 | ///
80 | ///
81 | /// An IPNS address, such as: /ipns/ipfs.io or a CID.
82 | ///
83 | ///
84 | /// Resolve until the result is not an IPNS name. Defaults to false.
85 | ///
86 | ///
87 | /// Do not use cached entries. Defaults to false.
88 | ///
89 | ///
90 | /// Is used to stop the task. When cancelled, the is raised.
91 | ///
92 | ///
93 | /// A task that represents the asynchronous operation. The task's value is
94 | /// the resolved path as a , such as
95 | /// /ipfs/QmYNQJoKGNHTpPxCBPh9KkDpaExgd2duMa3aF6ytMpHdao.
96 | ///
97 | Task ResolveAsync(
98 | string name,
99 | bool recursive = false,
100 | bool nocache = false,
101 | CancellationToken cancel = default(CancellationToken)
102 | );
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/src/MultiBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Ipfs.Registry;
7 |
8 | namespace Ipfs
9 | {
10 | ///
11 | /// Self identifying base encodings.
12 | ///
13 | ///
14 | /// MultiBase is a protocol for distinguishing base encodings
15 | /// and other simple string encodings.
16 | /// See the registry for supported algorithms.
17 | ///
18 | ///
19 | public static class MultiBase
20 | {
21 | ///
22 | /// The default multi-base algorithm is "base58btc".
23 | ///
24 | public const string DefaultAlgorithmName = "base58btc";
25 |
26 | ///
27 | /// Gets the with the specified IPFS multi-hash name.
28 | ///
29 | ///
30 | /// The name of an algorithm, see
31 | /// for
32 | /// for IPFS defined names.
33 | ///
34 | ///
35 | /// When is not registered.
36 | ///
37 | static MultiBaseAlgorithm GetAlgorithm(string name)
38 | {
39 | try
40 | {
41 | return MultiBaseAlgorithm.Names[name];
42 | }
43 | catch (KeyNotFoundException)
44 | {
45 | throw new KeyNotFoundException($"MutiBase algorithm '{name}' is not registered.");
46 | }
47 | }
48 |
49 | ///
50 | /// Converts an array of 8-bit unsigned integers to its equivalent string representation.
51 | ///
52 | ///
53 | /// An array of 8-bit unsigned integers.
54 | ///
55 | ///
56 | /// The name of the multi-base algorithm to use. See .
57 | ///
58 | ///
59 | /// A starting with the algorithm's and
60 | /// followed by the encoded string representation of the .
61 | ///
62 | ///
63 | /// When is not registered.
64 | ///
65 | public static string Encode(byte[] bytes, string algorithmName = DefaultAlgorithmName)
66 | {
67 | if (bytes == null)
68 | {
69 | throw new ArgumentNullException("bytes");
70 | }
71 |
72 | var alg = GetAlgorithm(algorithmName);
73 | return alg.Code + alg.Encode(bytes);
74 | }
75 |
76 | ///
77 | /// Converts the specified , which encodes binary data,
78 | /// to an equivalent 8-bit unsigned integer array.
79 | ///
80 | ///
81 | /// The multi-base string to convert.
82 | ///
83 | ///
84 | /// An array of 8-bit unsigned integers that is equivalent to .
85 | ///
86 | ///
87 | /// When the can not be decoded.
88 | ///
89 | public static byte[] Decode(string s)
90 | {
91 | if (string.IsNullOrWhiteSpace(s))
92 | {
93 | throw new ArgumentNullException("s");
94 | }
95 |
96 | MultiBaseAlgorithm.Codes.TryGetValue(s[0], out MultiBaseAlgorithm alg);
97 | if (alg == null)
98 | {
99 | throw new FormatException($"MultiBase '{s}' is invalid. The code is not registered.");
100 | }
101 |
102 | try
103 | {
104 | return alg.Decode(s.Substring(1));
105 | }
106 | catch (Exception e)
107 | {
108 | throw new FormatException($"MultiBase '{s}' is invalid; decode failed.", e);
109 | }
110 | }
111 |
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/test/VarintTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using Microsoft.VisualStudio.TestTools.UnitTesting;
6 | using System.IO;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 |
10 | namespace Ipfs
11 | {
12 | [TestClass]
13 | public class VarintTest
14 | {
15 | [TestMethod]
16 | public void Zero()
17 | {
18 | var x = new byte[] { 0 };
19 | Assert.AreEqual(1, Varint.RequiredBytes(0));
20 | CollectionAssert.AreEqual(x, Varint.Encode(0));
21 | Assert.AreEqual(0, Varint.DecodeInt32(x));
22 | }
23 |
24 | [TestMethod]
25 | public void ThreeHundred()
26 | {
27 | var x = new byte[] { 0xAC, 0x02 };
28 | Assert.AreEqual(2, Varint.RequiredBytes(300));
29 | CollectionAssert.AreEqual(x, Varint.Encode(300));
30 | Assert.AreEqual(300, Varint.DecodeInt32(x));
31 | }
32 |
33 | [TestMethod]
34 | public void Decode_From_Offset()
35 | {
36 | var x = new byte[] { 0x00, 0xAC, 0x02 };
37 | Assert.AreEqual(300, Varint.DecodeInt32(x, 1));
38 | }
39 |
40 | [TestMethod]
41 | public void MaxLong()
42 | {
43 | var x = "ffffffffffffffff7f".ToHexBuffer();
44 | Assert.AreEqual(9, Varint.RequiredBytes(long.MaxValue));
45 | CollectionAssert.AreEqual(x, Varint.Encode(long.MaxValue));
46 | Assert.AreEqual(long.MaxValue, Varint.DecodeInt64(x));
47 | }
48 |
49 | [TestMethod]
50 | public void Encode_Negative()
51 | {
52 | ExceptionAssert.Throws(() => Varint.Encode(-1));
53 | }
54 |
55 | [TestMethod]
56 | public void TooBig_Int32()
57 | {
58 | var bytes = Varint.Encode((long)Int32.MaxValue + 1);
59 | ExceptionAssert.Throws(() => Varint.DecodeInt32(bytes));
60 | }
61 |
62 | [TestMethod]
63 | public void TooBig_Int64()
64 | {
65 | var bytes = "ffffffffffffffffff7f".ToHexBuffer();
66 | ExceptionAssert.Throws(() => Varint.DecodeInt64(bytes));
67 | }
68 |
69 | [TestMethod]
70 | public void Unterminated()
71 | {
72 | var bytes = "ff".ToHexBuffer();
73 | ExceptionAssert.Throws(() => Varint.DecodeInt64(bytes));
74 | }
75 |
76 | [TestMethod]
77 | public void Empty()
78 | {
79 | var bytes = new byte[0];
80 | ExceptionAssert.Throws(() => Varint.DecodeInt64(bytes));
81 | }
82 |
83 | [TestMethod]
84 | public async Task WriteAsync()
85 | {
86 | using (var ms = new MemoryStream())
87 | {
88 | await ms.WriteVarintAsync(long.MaxValue);
89 | ms.Position = 0;
90 | Assert.AreEqual(long.MaxValue, ms.ReadVarint64());
91 | }
92 | }
93 |
94 | [TestMethod]
95 | public void WriteAsync_Negative()
96 | {
97 | var ms = new MemoryStream();
98 | ExceptionAssert.Throws(() => ms.WriteVarintAsync(-1).Wait());
99 | }
100 |
101 | [TestMethod]
102 | public void WriteAsync_Cancel()
103 | {
104 | var ms = new MemoryStream();
105 | var cs = new CancellationTokenSource();
106 | cs.Cancel();
107 | ExceptionAssert.Throws(() => ms.WriteVarintAsync(0, cs.Token).Wait());
108 | }
109 |
110 | [TestMethod]
111 | public async Task ReadAsync()
112 | {
113 | using (var ms = new MemoryStream("ffffffffffffffff7f".ToHexBuffer()))
114 | {
115 | var v = await ms.ReadVarint64Async();
116 | Assert.AreEqual(long.MaxValue, v);
117 | }
118 | }
119 |
120 | [TestMethod]
121 | public void ReadAsync_Cancel()
122 | {
123 | var ms = new MemoryStream(new byte[] { 0 });
124 | var cs = new CancellationTokenSource();
125 | cs.Cancel();
126 | ExceptionAssert.Throws(() => ms.ReadVarint32Async(cs.Token).Wait());
127 | }
128 |
129 | [TestMethod]
130 | public void Example()
131 | {
132 | for (long v = 1; v <= 0xFFFFFFFL; v = v << 4)
133 | {
134 | Console.Write($"| {v} (0x{v.ToString("x")}) ");
135 | Console.WriteLine($"| {Varint.Encode(v).ToHexString()} |");
136 | }
137 | }
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/test/PeerTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using Microsoft.VisualStudio.TestTools.UnitTesting;
6 | using System.IO;
7 |
8 | namespace Ipfs
9 | {
10 |
11 | [TestClass]
12 | public class PeerTest
13 | {
14 | const string marsId = "QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3";
15 | const string plutoId = "QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM";
16 | const string marsPublicKey = "CAASogEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKGUtbRQf+a9SBHFEruNAUatS/tsGUnHuCtifGrlbYPELD3UyyhWf/FYczBCavx3i8hIPEW2jQv4ehxQxi/cg9SHswZCQblSi0ucwTBFr8d40JEiyB9CcapiMdFQxdMgGvXEOQdLz1pz+UPUDojkdKZq8qkkeiBn7KlAoGEocnmpAgMBAAE=";
17 | static string marsAddress = "/ip4/10.1.10.10/tcp/29087/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3";
18 |
19 | [TestMethod]
20 | public new void ToString()
21 | {
22 | Assert.AreEqual("", new Peer().ToString());
23 | Assert.AreEqual(marsId, new Peer { Id = marsId }.ToString());
24 | }
25 |
26 | [TestMethod]
27 | public void DefaultValues()
28 | {
29 | var peer = new Peer();
30 | Assert.AreEqual(null, peer.Id);
31 | Assert.AreEqual(0, peer.Addresses.Count());
32 | Assert.AreEqual("unknown/0.0", peer.ProtocolVersion);
33 | Assert.AreEqual("unknown/0.0", peer.AgentVersion);
34 | Assert.AreEqual(null, peer.PublicKey);
35 | Assert.AreEqual(false, peer.IsValid()); // missing peer ID
36 | Assert.AreEqual(null, peer.ConnectedAddress);
37 | Assert.IsFalse(peer.Latency.HasValue);
38 | }
39 |
40 | [TestMethod]
41 | public void ConnectedPeer()
42 | {
43 | var peer = new Peer
44 | {
45 | ConnectedAddress = new MultiAddress(marsAddress),
46 | Latency = TimeSpan.FromHours(3.03 * 2)
47 | };
48 | Assert.AreEqual(marsAddress, peer.ConnectedAddress.ToString());
49 | Assert.AreEqual(3.03 * 2, peer.Latency.Value.TotalHours);
50 | }
51 |
52 | [TestMethod]
53 | public void Validation_No_Id()
54 | {
55 | var peer = new Peer();
56 | Assert.AreEqual(false, peer.IsValid());
57 | }
58 |
59 | [TestMethod]
60 | public void Validation_With_Id()
61 | {
62 | Peer peer = marsId;
63 | Assert.AreEqual(true, peer.IsValid());
64 | }
65 |
66 | [TestMethod]
67 | public void Validation_With_Id_Pubkey()
68 | {
69 | var peer = new Peer
70 | {
71 | Id = marsId,
72 | PublicKey = marsPublicKey
73 | };
74 | Assert.AreEqual(true, peer.IsValid());
75 | }
76 |
77 | [TestMethod]
78 | public void Validation_With_Id_Invalid_Pubkey()
79 | {
80 | var peer = new Peer
81 | {
82 | Id = plutoId,
83 | PublicKey = marsPublicKey
84 | };
85 | Assert.AreEqual(false, peer.IsValid());
86 | }
87 |
88 | [TestMethod]
89 | public void Value_Equality()
90 | {
91 | var a0 = new Peer { Id = marsId };
92 | var a1 = new Peer { Id = marsId };
93 | var b = new Peer { Id = plutoId };
94 | Peer c = null;
95 | Peer d = null;
96 |
97 | Assert.IsTrue(c == d);
98 | Assert.IsFalse(c == b);
99 | Assert.IsFalse(b == c);
100 |
101 | Assert.IsFalse(c != d);
102 | Assert.IsTrue(c != b);
103 | Assert.IsTrue(b != c);
104 |
105 | #pragma warning disable 1718
106 | Assert.IsTrue(a0 == a0);
107 | Assert.IsTrue(a0 == a1);
108 | Assert.IsFalse(a0 == b);
109 |
110 | #pragma warning disable 1718
111 | Assert.IsFalse(a0 != a0);
112 | Assert.IsFalse(a0 != a1);
113 | Assert.IsTrue(a0 != b);
114 |
115 | Assert.IsTrue(a0.Equals(a0));
116 | Assert.IsTrue(a0.Equals(a1));
117 | Assert.IsFalse(a0.Equals(b));
118 |
119 | Assert.AreEqual(a0, a0);
120 | Assert.AreEqual(a0, a1);
121 | Assert.AreNotEqual(a0, b);
122 |
123 | Assert.AreEqual(a0, a0);
124 | Assert.AreEqual(a0, a1);
125 | Assert.AreNotEqual(a0, b);
126 |
127 | Assert.AreEqual(a0.GetHashCode(), a0.GetHashCode());
128 | Assert.AreEqual(a0.GetHashCode(), a1.GetHashCode());
129 | Assert.AreNotEqual(a0.GetHashCode(), b.GetHashCode());
130 | }
131 |
132 |
133 | [TestMethod]
134 | public void Implicit_Conversion_From_String()
135 | {
136 | Peer a = marsId;
137 | Assert.IsInstanceOfType(a, typeof(Peer));
138 | }
139 |
140 | }
141 | }
142 |
143 |
--------------------------------------------------------------------------------
/src/CoreApi/ICoreApi.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Ipfs.CoreApi
6 | {
7 | ///
8 | /// The IPFS Core API.
9 | ///
10 | ///
11 | /// The Core API defines a set of interfaces to manage IPFS.
12 | ///
13 | ///
14 | public interface ICoreApi
15 | {
16 | ///
17 | /// Provides access to the Bitswap API.
18 | ///
19 | ///
20 | /// An object that implements .
21 | ///
22 | IBitswapApi Bitswap { get; }
23 |
24 | ///
25 | /// Provides access to the Block API.
26 | ///
27 | ///
28 | /// An object that implements .
29 | ///
30 | IBlockApi Block { get; }
31 |
32 | ///
33 | /// Provides access to the Block Repository API.
34 | ///
35 | ///
36 | /// An object that implements .
37 | ///
38 | IBlockRepositoryApi BlockRepository { get; }
39 |
40 | ///
41 | /// Provides access to the Bootstrap API.
42 | ///
43 | ///
44 | /// An object that implements .
45 | ///
46 | IBootstrapApi Bootstrap { get; }
47 |
48 | ///
49 | /// Provides access to the Config API.
50 | ///
51 | ///
52 | /// An object that implements .
53 | ///
54 | IConfigApi Config { get; }
55 |
56 | ///
57 | /// Provides access to the Dag API.
58 | ///
59 | ///
60 | /// An object that implements .
61 | ///
62 | IDagApi Dag { get; }
63 |
64 | ///
65 | /// Provides access to the DHT API.
66 | ///
67 | ///
68 | /// An object that implements .
69 | ///
70 | IDhtApi Dht { get; }
71 |
72 | ///
73 | /// Provides access to the DNS API.
74 | ///
75 | ///
76 | /// An object that implements .
77 | ///
78 | IDnsApi Dns { get; }
79 |
80 | ///
81 | /// Provides access to the File System API.
82 | ///
83 | ///
84 | /// An object that implements .
85 | ///
86 | IFileSystemApi FileSystem { get; }
87 |
88 | ///
89 | /// Provides access to the Generic API.
90 | ///
91 | ///
92 | /// An object that implements .
93 | ///
94 | IGenericApi Generic { get; }
95 |
96 | ///
97 | /// Provides access to the Key API.
98 | ///
99 | ///
100 | /// An object that implements .
101 | ///
102 | IKeyApi Key { get; }
103 |
104 | ///
105 | /// Provides access to the Name API.
106 | ///
107 | ///
108 | /// An object that implements .
109 | ///
110 | INameApi Name { get; }
111 |
112 | ///
113 | /// Provides access to the Object API.
114 | ///
115 | ///
116 | /// An object that implements .
117 | ///
118 | IObjectApi Object { get; }
119 |
120 | ///
121 | /// Provides access to the Pin API.
122 | ///
123 | ///
124 | /// An object that implements .
125 | ///
126 | IPinApi Pin { get; }
127 |
128 | ///
129 | /// Provides access to the PubSub API.
130 | ///
131 | ///
132 | /// An object that implements .
133 | ///
134 | IPubSubApi PubSub { get; }
135 |
136 | ///
137 | /// Provides access to the Stats (statistics) API.
138 | ///
139 | ///
140 | /// An object that implements .
141 | ///
142 | IStatsApi Stats { get; }
143 |
144 | ///
145 | /// Provides access to the Swarm API.
146 | ///
147 | ///
148 | /// An object that implements .
149 | ///
150 | ISwarmApi Swarm { get; }
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/src/CoreApi/IPubSubApi.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Text;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 |
8 | namespace Ipfs.CoreApi
9 | {
10 | ///
11 | /// Allows you to publish messages to a given topic, and also to
12 | /// subscribe to new messages on a given topic.
13 | ///
14 | ///
15 | ///
16 | /// This is an experimental feature. It is not intended in its current state
17 | /// to be used in a production environment.
18 | ///
19 | ///
20 | /// To use, the daemon must be run with '--enable-pubsub-experiment'.
21 | ///
22 | ///
23 | /// Pubsub API spec
24 | public interface IPubSubApi
25 | {
26 | ///
27 | /// Get the subscribed topics.
28 | ///
29 | ///
30 | /// Is used to stop the task. When cancelled, the is raised.
31 | ///
32 | ///
33 | /// A task that represents the asynchronous operation. The task's value is
34 | /// a sequence of for each topic.
35 | ///
36 | Task> SubscribedTopicsAsync(CancellationToken cancel = default(CancellationToken));
37 |
38 | ///
39 | /// Get the peers that are pubsubing with us.
40 | ///
41 | ///
42 | /// When specified, only peers subscribing on the topic are returned.
43 | ///
44 | ///
45 | /// Is used to stop the task. When cancelled, the is raised.
46 | ///
47 | ///
48 | /// A task that represents the asynchronous operation. The task's value is
49 | /// a sequence of .
50 | ///
51 | Task> PeersAsync(string topic = null, CancellationToken cancel = default(CancellationToken));
52 |
53 | ///
54 | /// Publish a string message to a given topic.
55 | ///
56 | ///
57 | /// The topic name.
58 | ///
59 | ///
60 | /// The message to publish.
61 | ///
62 | ///
63 | /// Is used to stop the task. When cancelled, the is raised.
64 | ///
65 | ///
66 | /// A task that represents the asynchronous operation.
67 | ///
68 | Task PublishAsync(string topic, string message, CancellationToken cancel = default(CancellationToken));
69 |
70 | ///
71 | /// Publish a binary message to a given topic.
72 | ///
73 | ///
74 | /// The topic name.
75 | ///
76 | ///
77 | /// The message to publish.
78 | ///
79 | ///
80 | /// Is used to stop the task. When cancelled, the is raised.
81 | ///
82 | ///
83 | /// A task that represents the asynchronous operation.
84 | ///
85 | Task PublishAsync(string topic, byte[] message, CancellationToken cancel = default(CancellationToken));
86 |
87 | ///
88 | /// Publish a binary message to a given topic.
89 | ///
90 | ///
91 | /// The topic name.
92 | ///
93 | ///
94 | /// The message to publish.
95 | ///
96 | ///
97 | /// Is used to stop the task. When cancelled, the is raised.
98 | ///
99 | ///
100 | /// A task that represents the asynchronous operation.
101 | ///
102 | Task PublishAsync(string topic, Stream message, CancellationToken cancel = default(CancellationToken));
103 |
104 | ///
105 | /// Subscribe to messages on a given topic.
106 | ///
107 | ///
108 | /// The topic name.
109 | ///
110 | ///
111 | /// The action to perform when a is received.
112 | ///
113 | ///
114 | /// Is used to stop the topic listener. When cancelled, the
115 | /// is NOT raised.
116 | ///
117 | ///
118 | /// A task that represents the asynchronous operation.
119 | ///
120 | ///
121 | /// The is invoked on the topic listener thread.
122 | ///
123 | Task SubscribeAsync(string topic, Action handler, CancellationToken cancellationToken);
124 |
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/src/DagLink.cs:
--------------------------------------------------------------------------------
1 | using Google.Protobuf;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace Ipfs
10 | {
11 |
12 | ///
13 | /// A link to another node in the IPFS Merkle DAG.
14 | ///
15 | public class DagLink : IMerkleLink
16 | {
17 | ///
18 | /// Create a new instance of class.
19 | ///
20 | /// The name associated with the linked node.
21 | /// The of the linked node.
22 | /// The serialised size (in bytes) of the linked node.
23 | public DagLink(string name, Cid id, long size)
24 | {
25 | this.Name = name;
26 | this.Id = id;
27 | this.Size = size;
28 | }
29 |
30 | ///
31 | /// Creates a new instance of the class from the
32 | /// specified .
33 | ///
34 | ///
35 | /// Some type of a Merkle link.
36 | ///
37 | public DagLink(IMerkleLink link)
38 | {
39 | this.Name = link.Name;
40 | this.Id = link.Id;
41 | this.Size = link.Size;
42 | }
43 |
44 | ///
45 | /// Creates a new instance of the class from the
46 | /// specified .
47 | ///
48 | ///
49 | /// A containing the binary representation of the
50 | /// DagLink.
51 | ///
52 | public DagLink(Stream stream)
53 | {
54 | Read(stream);
55 | }
56 |
57 | ///
58 | /// Creates a new instance of the class from the
59 | /// specified .
60 | ///
61 | /// (
62 | /// A containing the binary representation of the
63 | /// DagLink.
64 | ///
65 | public DagLink(CodedInputStream stream)
66 | {
67 | Read(stream);
68 | }
69 |
70 | ///
71 | public string Name { get; private set; }
72 |
73 | ///
74 | public Cid Id { get; private set; }
75 |
76 | ///
77 | public long Size { get; private set; }
78 |
79 | ///
80 | /// Writes the binary representation of the link to the specified .
81 | ///
82 | ///
83 | /// The to write to.
84 | ///
85 | public void Write(Stream stream)
86 | {
87 | using (var cos = new CodedOutputStream(stream, true))
88 | {
89 | Write(cos);
90 | }
91 | }
92 |
93 | ///
94 | /// Writes the binary representation of the link to the specified .
95 | ///
96 | ///
97 | /// The to write to.
98 | ///
99 | public void Write(CodedOutputStream stream)
100 | {
101 | if (stream == null)
102 | throw new ArgumentNullException("stream");
103 |
104 | stream.WriteTag(1, WireFormat.WireType.LengthDelimited);
105 | Id.Write(stream);
106 |
107 | if (Name != null)
108 | {
109 | stream.WriteTag(2, WireFormat.WireType.LengthDelimited);
110 | stream.WriteString(Name);
111 | }
112 |
113 | stream.WriteTag(3, WireFormat.WireType.Varint);
114 | stream.WriteInt64(Size);
115 | }
116 |
117 | void Read(Stream stream)
118 | {
119 | using (var cis = new CodedInputStream(stream, true))
120 | {
121 | Read(cis);
122 | }
123 | }
124 |
125 | void Read(CodedInputStream stream)
126 | {
127 | while (!stream.IsAtEnd)
128 | {
129 | var tag = stream.ReadTag();
130 | switch (WireFormat.GetTagFieldNumber(tag))
131 | {
132 | case 1:
133 | Id = Cid.Read(stream);
134 | break;
135 | case 2:
136 | Name = stream.ReadString();
137 | break;
138 | case 3:
139 | Size = stream.ReadInt64();
140 | break;
141 | default:
142 | throw new InvalidDataException("Unknown field number");
143 | }
144 | }
145 | }
146 |
147 | ///
148 | /// Returns the IPFS binary representation as a byte array.
149 | ///
150 | ///
151 | /// A byte array.
152 | ///
153 | public byte[] ToArray()
154 | {
155 | using (var ms = new MemoryStream())
156 | {
157 | Write(ms);
158 | return ms.ToArray();
159 | }
160 | }
161 |
162 | }
163 | }
--------------------------------------------------------------------------------
/src/CoreApi/IKeyApi.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace Ipfs.CoreApi
8 | {
9 | ///
10 | /// Manages cryptographic keys.
11 | ///
12 | ///
13 | ///
14 | /// The Key API is work in progress! There be dragons here.
15 | ///
16 | ///
17 | /// Key API spec
18 | public interface IKeyApi
19 | {
20 | ///
21 | /// Creates a new key.
22 | ///
23 | ///
24 | /// The local name of the key.
25 | ///
26 | ///
27 | /// The type of key to create; "rsa" or "ed25519".
28 | ///
29 | ///
30 | /// The size, in bits, of the key.
31 | ///
32 | ///
33 | /// Is used to stop the task. When cancelled, the is raised.
34 | ///
35 | ///
36 | /// A task that represents the asynchronous operation. The task's result is
37 | /// the key that was created.
38 | ///
39 | Task CreateAsync(
40 | string name,
41 | string keyType,
42 | int size,
43 | CancellationToken cancel = default(CancellationToken));
44 |
45 | ///
46 | /// List all the keys.
47 | ///
48 | ///
49 | /// Is used to stop the task. When cancelled, the is raised.
50 | ///
51 | ///
52 | /// A task that represents the asynchronous operation. The task's result is
53 | /// a sequence of IPFS keys.
54 | ///
55 | Task> ListAsync(CancellationToken cancel = default(CancellationToken));
56 |
57 | ///
58 | /// Delete the specified key.
59 | ///
60 | ///
61 | /// The local name of the key.
62 | ///
63 | ///
64 | /// Is used to stop the task. When cancelled, the is raised.
65 | ///
66 | ///
67 | /// A task that represents the asynchronous operation. The task's result is
68 | /// the key that was deleted.
69 | ///
70 | Task RemoveAsync(string name, CancellationToken cancel = default(CancellationToken));
71 |
72 | ///
73 | /// Rename the specified key.
74 | ///
75 | ///
76 | /// The local name of the key.
77 | ///
78 | ///
79 | /// The new local name of the key.
80 | ///
81 | ///
82 | /// Is used to stop the task. When cancelled, the is raised.
83 | ///
84 | ///
85 | /// A task that represents the asynchronous operation. The task's result is
86 | /// a sequence of IPFS keys that were renamed.
87 | ///
88 | Task RenameAsync(string oldName, string newName, CancellationToken cancel = default(CancellationToken));
89 |
90 | ///
91 | /// Export a key to a PEM encoded password protected PKCS #8 container.
92 | ///
93 | ///
94 | /// The local name of the key.
95 | ///
96 | ///
97 | /// The PEM's password.
98 | ///
99 | ///
100 | /// Is used to stop the task. When cancelled, the is raised.
101 | ///
102 | ///
103 | /// A task that represents the asynchronous operation. The task's result is
104 | /// the password protected PEM string.
105 | ///
106 | Task ExportAsync(string name, char[] password, CancellationToken cancel = default(CancellationToken));
107 |
108 | ///
109 | /// Import a key from a PEM encoded password protected PKCS #8 container.
110 | ///
111 | ///
112 | /// The local name of the key.
113 | ///
114 | ///
115 | /// The PEM encoded PKCS #8 container.
116 | ///
117 | ///
118 | /// The 's password.
119 | ///
120 | ///
121 | /// Is used to stop the task. When cancelled, the is raised.
122 | ///
123 | ///
124 | /// A task that represents the asynchronous operation. The task's result
125 | /// is the newly imported key.
126 | ///
127 | Task ImportAsync(string name, string pem, char[] password = null, CancellationToken cancel = default(CancellationToken));
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/src/HexString.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.IO;
6 |
7 | namespace Ipfs
8 | {
9 | ///
10 | /// A codec for Hexadecimal.
11 | ///
12 | ///
13 | ///
14 | /// A codec for a hexadecimal string, and . Adds the extension method
15 | /// to encode a byte array and to decode a hexadecimal .
16 | ///
17 | ///
18 | public static class HexString
19 | {
20 | static readonly string[] LowerCaseHexStrings =
21 | Enumerable.Range(byte.MinValue, byte.MaxValue + 1)
22 | .Select(v => v.ToString("x2"))
23 | .ToArray();
24 | static readonly string[] UpperCaseHexStrings =
25 | Enumerable.Range(byte.MinValue, byte.MaxValue + 1)
26 | .Select(v => v.ToString("X2"))
27 | .ToArray();
28 | static readonly Dictionary HexBytes =
29 | Enumerable.Range(byte.MinValue, byte.MaxValue + 1)
30 | .SelectMany(v => new [] {
31 | new { Value = v, String = v.ToString("x2") } ,
32 | new { Value = v, String = v.ToString("X2") }
33 | } )
34 | .Distinct()
35 | .ToDictionary(v => v.String, v => (byte) v.Value);
36 |
37 |
38 | ///
39 | /// Converts an array of 8-bit unsigned integers to its equivalent hexadecimal string representation.
40 | ///
41 | ///
42 | /// An array of 8-bit unsigned integers.
43 | ///
44 | ///
45 | /// One of the format specifiers ("G" and "x" for lower-case hex digits, or "X" for the upper-case).
46 | /// The default is "G".
47 | ///
48 | ///
49 | /// The string representation, in hexadecimal, of the contents of .
50 | ///
51 | public static string Encode(byte[] buffer, string format = "G")
52 | {
53 | string[] hexStrings;
54 | switch (format)
55 | {
56 | case "G":
57 | case "x":
58 | hexStrings = LowerCaseHexStrings;
59 | break;
60 | case "X":
61 | hexStrings = UpperCaseHexStrings;
62 | break;
63 | default:
64 | throw new FormatException(string.Format("Invalid HexString format '{0}', only 'G', 'x' or 'X' are allowed.", format));
65 | }
66 |
67 | StringBuilder s = new StringBuilder(buffer.Length * 2);
68 | foreach (var v in buffer)
69 | s.Append(hexStrings[v]);
70 | return s.ToString();
71 | }
72 |
73 | ///
74 | /// Converts an array of 8-bit unsigned integers to its equivalent hexadecimal string representation.
75 | ///
76 | ///
77 | /// An array of 8-bit unsigned integers.
78 | ///
79 | ///
80 | /// One of the format specifiers ("G" and "x" for lower-case hex digits, or "X" for the upper-case).
81 | /// The default is "G".
82 | ///
83 | ///
84 | /// The string representation, in hexadecimal, of the contents of .
85 | ///
86 | public static string ToHexString(this byte[] buffer, string format = "G")
87 | {
88 | return Encode(buffer, format);
89 | }
90 |
91 | ///
92 | /// Converts the specified , which encodes binary data as hexadecimal digits,
93 | /// to an equivalent 8-bit unsigned integer array.
94 | ///
95 | ///
96 | /// The hexadecimal string to convert.
97 | ///
98 | ///
99 | /// An array of 8-bit unsigned integers that is equivalent to .
100 | ///
101 | public static byte[] Decode(string s)
102 | {
103 | int n = s.Length;
104 | if (n % 2 != 0)
105 | throw new InvalidDataException("The hex string length must be a multiple of 2.");
106 |
107 | var buffer = new byte[n / 2];
108 | for (int i = 0, j = 0; i < n; i += 2, j++)
109 | {
110 | var hex = s.Substring(i, 2);
111 | byte value;
112 | if (!HexBytes.TryGetValue(hex, out value))
113 | throw new InvalidDataException(string.Format("'{0}' is not a valid hexadecimal byte.", hex));
114 | buffer[j] = value;
115 | }
116 |
117 | return buffer;
118 | }
119 |
120 | ///
121 | /// Converts the specified , which encodes binary data as a hexadecimal string,
122 | /// to an equivalent 8-bit unsigned integer array.
123 | ///
124 | ///
125 | /// The hexadecimal string to convert.
126 | ///
127 | ///
128 | /// An array of 8-bit unsigned integers that is equivalent to .
129 | ///
130 | public static byte[] ToHexBuffer(this string s)
131 | {
132 | return Decode(s);
133 | }
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/src/CoreApi/ISwarmApi.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace Ipfs.CoreApi
8 | {
9 | ///
10 | /// Manages the swarm of peers.
11 | ///
12 | ///
13 | /// The swarm is a sequence of connected peer nodes.
14 | ///
15 | /// Swarm API spec
16 | public interface ISwarmApi
17 | {
18 | ///
19 | /// Get the peers in the current swarm.
20 | ///
21 | ///
22 | /// Is used to stop the task. When cancelled, the is raised.
23 | ///
24 | ///
25 | /// A task that represents the asynchronous operation. The task's value
26 | /// is a sequence of peer nodes.
27 | ///
28 | Task> AddressesAsync(CancellationToken cancel = default(CancellationToken));
29 |
30 | ///
31 | /// Get the peers that are connected to this node.
32 | ///
33 | ///
34 | /// Is used to stop the task. When cancelled, the is raised.
35 | ///
36 | ///
37 | /// A task that represents the asynchronous operation. The task's value
38 | /// is a sequence of Connected Peers.
39 | ///
40 | Task> PeersAsync(CancellationToken cancel = default(CancellationToken));
41 |
42 | ///
43 | /// Connect to a peer.
44 | ///
45 | ///
46 | /// An ipfs , such as
47 | /// /ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ.
48 | ///
49 | ///
50 | /// Is used to stop the task. When cancelled, the is raised.
51 | ///
52 | Task ConnectAsync(MultiAddress address, CancellationToken cancel = default(CancellationToken));
53 |
54 | ///
55 | /// Disconnect from a peer.
56 | ///
57 | ///
58 | /// An ipfs , such as
59 | /// /ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ.
60 | ///
61 | ///
62 | /// Is used to stop the task. When cancelled, the is raised.
63 | ///
64 | Task DisconnectAsync(MultiAddress address, CancellationToken cancel = default(CancellationToken));
65 |
66 | ///
67 | /// Adds a new address filter.
68 | ///
69 | ///
70 | /// An allowed address. For example "/ip4/104.131.131.82" or
71 | /// "/ip4/192.168.0.0/ipcidr/16".
72 | ///
73 | ///
74 | /// If true the filter will persist across daemon reboots.
75 | ///
76 | ///
77 | /// Is used to stop the task. When cancelled, the is raised.
78 | ///
79 | ///
80 | /// A task that represents the asynchronous operation. The task's result is
81 | /// the address filter that was added.
82 | ///
83 | ///
84 | Task AddAddressFilterAsync(MultiAddress address, bool persist = false, CancellationToken cancel = default(CancellationToken));
85 |
86 | ///
87 | /// List all the address filters.
88 | ///
89 | ///
90 | /// If true only persisted filters are listed.
91 | ///
92 | ///
93 | /// Is used to stop the task. When cancelled, the is raised.
94 | ///
95 | ///
96 | /// A task that represents the asynchronous operation. The task's result is
97 | /// a sequence of addresses filters.
98 | ///
99 | ///
100 | Task> ListAddressFiltersAsync(bool persist = false, CancellationToken cancel = default(CancellationToken));
101 |
102 | ///
103 | /// Delete the specified address filter.
104 | ///
105 | ///
106 | /// For example "/ip4/104.131.131.82" or
107 | /// "/ip4/192.168.0.0/ipcidr/16".
108 | ///
109 | ///
110 | /// If true the filter is also removed from the persistent store.
111 | ///
112 | ///
113 | /// Is used to stop the task. When cancelled, the is raised.
114 | ///
115 | ///
116 | /// A task that represents the asynchronous operation. The task's result is
117 | /// the address filter that was removed.
118 | ///
119 | ///
120 | Task RemoveAddressFilterAsync(MultiAddress address, bool persist = false, CancellationToken cancel = default(CancellationToken));
121 |
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/src/Registry/Codec.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Ipfs.Registry
6 | {
7 | ///
8 | /// Metadata for IPFS multi-codec.
9 | ///
10 | ///
11 | /// IPFS assigns a unique and to codecs.
12 | /// See table.csv
13 | /// for the currently defined multi-codecs.
14 | ///
15 | ///
16 | public class Codec
17 | {
18 | internal static Dictionary Names = new Dictionary();
19 | internal static Dictionary Codes = new Dictionary();
20 |
21 | ///
22 | /// Register the standard multi-codecs for IPFS.
23 | ///
24 | ///
25 | static Codec()
26 | {
27 | Register("raw", 0x55);
28 | Register("cms", 0x57); // Not official yet, https://github.com/multiformats/multicodec/pull/69
29 | Register("cbor", 0x51);
30 | Register("protobuf", 0x50);
31 | Register("rlp", 0x60);
32 | Register("bencode", 0x63);
33 | Register("multicodec", 0x30);
34 | Register("multihash", 0x31);
35 | Register("multiaddr", 0x32);
36 | Register("multibase", 0x33);
37 | Register("dag-pb", 0x70);
38 | Register("dag-cbor", 0x71);
39 | Register("git-raw", 0x78);
40 | Register("eth-block", 0x90);
41 | Register("eth-block-list", 0x91);
42 | Register("eth-tx-trie", 0x92);
43 | Register("eth-tx", 0x93);
44 | Register("eth-tx-receipt-trie", 0x94);
45 | Register("eth-tx-receipt", 0x95);
46 | Register("eth-state-trie", 0x96);
47 | Register("eth-account-snapshot", 0x97);
48 | Register("eth-storage-trie", 0x98);
49 | Register("bitcoin-block", 0xb0);
50 | Register("bitcoin-tx", 0xb1);
51 | Register("zcash-block", 0xc0);
52 | Register("zcash-tx", 0xc1);
53 | Register("stellar-block", 0xd0);
54 | Register("stellar-tx", 0xd1);
55 | Register("torrent-info", 0x7b);
56 | Register("torrent-file", 0x7c);
57 | Register("ed25519-pub", 0xed);
58 | }
59 |
60 | ///
61 | /// The name of the codec.
62 | ///
63 | ///
64 | /// A unique name.
65 | ///
66 | public string Name { get; private set; }
67 |
68 | ///
69 | /// The IPFS code assigned to the codec.
70 | ///
71 | ///
72 | /// Valid codes at .
73 | ///
74 | public int Code { get; private set; }
75 |
76 | ///
77 | /// Use to create a new instance of a .
78 | ///
79 | Codec()
80 | {
81 | }
82 |
83 | ///
84 | /// The of the codec.
85 | ///
86 | ///
87 | /// The of the codec.
88 | ///
89 | public override string ToString()
90 | {
91 | return Name;
92 | }
93 |
94 | ///
95 | /// Register a new IPFS codec.
96 | ///
97 | ///
98 | /// The name of the codec.
99 | ///
100 | ///
101 | /// The IPFS code assigned to the codec.
102 | ///
103 | ///
104 | /// A new .
105 | ///
106 | ///
107 | /// When the or is already defined.
108 | ///
109 | ///
110 | /// When the is null or empty.
111 | ///
112 | public static Codec Register(string name, int code)
113 | {
114 | if (string.IsNullOrWhiteSpace(name))
115 | throw new ArgumentNullException("name");
116 | if (Names.ContainsKey(name))
117 | throw new ArgumentException(string.Format("The IPFS codec name '{0}' is already defined.", name));
118 | if (Codes.ContainsKey(code))
119 | throw new ArgumentException(string.Format("The IPFS codec code '{0}' is already defined.", code));
120 |
121 | var a = new Codec
122 | {
123 | Name = name,
124 | Code = code
125 | };
126 | Names[name] = a;
127 | Codes[code] = a;
128 |
129 | return a;
130 | }
131 | ///
132 | /// Remove an IPFS codec from the registry.
133 | ///
134 | ///
135 | /// The to remove.
136 | ///
137 | public static void Deregister(Codec codec)
138 | {
139 | Names.Remove(codec.Name);
140 | Codes.Remove(codec.Code);
141 | }
142 |
143 | ///
144 | /// A sequence consisting of all codecs.
145 | ///
146 | ///
147 | /// All the registered codecs.
148 | ///
149 | public static IEnumerable All
150 | {
151 | get { return Names.Values; }
152 | }
153 |
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # net-ipfs-core
2 |
3 | [](https://ci.appveyor.com/project/richardschneider/net-ipfs-core)
4 | [](https://travis-ci.org/richardschneider/net-ipfs-core)
5 | [](https://www.codacy.com/app/makaretu/net-ipfs-core?utm_source=github.com&utm_medium=referral&utm_content=richardschneider/net-ipfs-core&utm_campaign=Badge_Grade)
6 | [](https://coveralls.io/github/richardschneider/net-ipfs-core?branch=master)
7 | [](https://www.nuget.org/packages/Ipfs.Core)
8 | [](https://richardschneider.github.io/net-ipfs-core/articles/intro.html)
9 |
10 | The core objects and interfaces of the [IPFS](https://github.com/ipfs/ipfs) (Inter Planetary File System) for .Net (C#, VB, F# etc.)
11 |
12 | The interplanetary file system is the permanent web. It is a new hypermedia distribution protocol, addressed by content and identities. IPFS enables the creation of completely distributed applications. It aims to make the web faster, safer, and more open.
13 |
14 | It supports the following runtimes
15 | - .NET Framework 4.5
16 | - .NET Standard 1.4
17 | - .NET Standard 2.0
18 |
19 | More information is on the [Documentation](https://richardschneider.github.io/net-ipfs-core/) web site.
20 |
21 | ## Getting started
22 |
23 | Published releases of IPFS Core are available on [NuGet](https://www.nuget.org/packages/ipfs.core/). To install, run the following command in the [Package Manager Console](https://docs.nuget.org/docs/start-here/using-the-package-manager-console).
24 |
25 | PM> Install-Package Ipfs.Core
26 |
27 | Or using [dotnet](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet?tabs=netcore21)
28 |
29 | > dotnet add package Ipfs.Core
30 |
31 |
32 | For the latest build or older non-released builds see [Continuous Integration](https://github.com/richardschneider/net-ipfs-core/wiki/Continuous-Integration).
33 |
34 | ## Major objects
35 |
36 | - [MerkleDag](https://richardschneider.github.io/net-ipfs-core/api/Ipfs.DagNode.html)
37 | - [MultiAddress](https://richardschneider.github.io/net-ipfs-core/api/Ipfs.MultiAddress.html)
38 | - [MultiHash](https://richardschneider.github.io/net-ipfs-core/api/Ipfs.MultiHash.html)
39 |
40 | See the [API Documentation](https://richardschneider.github.io/net-ipfs-core/api/Ipfs.html) for a list of all objects.
41 |
42 | ### MultiHash
43 |
44 | All hashes in IPFS are encoded with [multihash](https://github.com/multiformats/multihash), a self-describing hash format. The actual hash function used depends on security requirements. The cryptosystem of IPFS is upgradeable, meaning that as hash functions are broken, networks can shift to stronger hashes. There is no free lunch, as objects may need to be rehashed, or links duplicated. But ensuring that tools built do not assume a pre-defined length of hash digest means tools that work with today's hash functions will also work with tomorrows longer hash functions too.
45 |
46 | ### MultiAddress
47 |
48 | A standard way to represent a networks address that supports [multiple network protocols](https://github.com/multiformats/multiaddr). It is represented as a series of tuples, a protocol code and an optional value. For example, an IPFS file at a sepcific address over ipv4 and tcp is
49 |
50 | /ip4/10.1.10.10/tcp/80/ipfs/QmVcSqVEsvm5RR9mBLjwpb2XjFVn5bPdPL69mL8PH45pPC
51 |
52 | ### Merkle DAG
53 |
54 | The [DagNode](https://richardschneider.github.io/net-ipfs-core/api/Ipfs.DagNode.html) is a directed acyclic graph whose edges are a
55 | [DagLink](https://richardschneider.github.io/net-ipfs-core/api/Ipfs.DagLink.html). This means that links to objects can authenticate
56 | the objects themselves, and that every object contains a secure
57 | representation of its children.
58 |
59 | Every Merkle is a directed acyclic graph (DAG) because each node is accessed via its name (the hash of `DagNode`). Each branch of Merkle is the hash of its local content (data and links); naming children by their hash instead of their full contents. So after creation there is no way to edit a DagNode. This prevents cycles (assuming there are no hash collisions) since one can not link the first created node to the last note to create the last reference.
60 |
61 | ## Base58
62 |
63 | Most binary data (objects) in IPFS is represented as a [Base-58](https://en.wikipedia.org/wiki/Base58) string; the BitCoin alphabet is used.
64 |
65 | > Base58 is a group of binary-to-text encoding schemes used to represent large integers as alphanumeric text. It is similar to Base64 but has been modified to avoid both non-alphanumeric characters and letters which might look ambiguous when printed. It is therefore designed for human users who manually enter the data, copying from some visual source, but also allows easy copy and paste because a double-click will usually select the whole string.
66 |
67 | ## Related Projects
68 |
69 | - [IPFS DSL](https://github.com/cloveekprojeqt/ipfs-dsl) - A declarative embedded language for building compositional programs and protocols over the InterPlanetary File System.
70 | - [IPFS HTTP Client](https://github.com/richardschneider/net-ipfs-http-client) - A .Net client library for the IPFS HTTP API.
71 | - [IPFS HTTP Gateway](https://github.com/richardschneider/net-ipfs-http-gateway) - Serves IPFS files/directories via HTTP.
72 | - [IPFS Engine](https://github.com/richardschneider/net-ipfs-engine) - Implements the Core API.
73 | - [Peer Talk](https://github.com/richardschneider/peer-talk) - Peer to peer communication.
74 |
75 | ## License
76 | Copyright © 2015-2019 Richard Schneider (makaretu@gmail.com)
77 |
78 | The IPFS Core library is licensed under the [MIT](http://www.opensource.org/licenses/mit-license.php "Read more about the MIT license form") license. Refer to the [LICENSE](https://github.com/richardschneider/net-ipfs-core/blob/master/LICENSE) file for more information.
79 |
80 |
81 |
--------------------------------------------------------------------------------
/src/Cryptography/Keccak.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * The package was named SHA3 it is really Keccak
3 | * https://medium.com/@ConsenSys/are-you-really-using-sha-3-or-old-code-c5df31ad2b0
4 | * See
5 | *
6 | * The SHA3 package doesn't create .Net Standard package.
7 | * This is a copy of https://bitbucket.org/jdluzen/sha3/raw/d1fd55dc225d18a7fb61515b62d3c8f164d2e788/SHA3/SHA3.cs
8 | */
9 | using System;
10 | using System.Collections.Generic;
11 | using System.Linq;
12 | using System.Text;
13 |
14 | namespace Ipfs.Cryptography
15 | {
16 | internal abstract class Keccak :
17 | #if PORTABLE
18 | IHashAlgorithm
19 | #else
20 | System.Security.Cryptography.HashAlgorithm
21 | #endif
22 | {
23 |
24 | #region Implementation
25 | public const int KeccakB = 1600;
26 | public const int KeccakNumberOfRounds = 24;
27 | public const int KeccakLaneSizeInBits = 8 * 8;
28 |
29 | public readonly ulong[] RoundConstants;
30 |
31 | protected ulong[] state;
32 | protected byte[] buffer;
33 | protected int buffLength;
34 | #if PORTABLE || NETSTANDARD14
35 | protected byte[] HashValue;
36 | protected int HashSizeValue;
37 | #endif
38 | protected int keccakR;
39 |
40 | public int KeccakR
41 | {
42 | get
43 | {
44 | return keccakR;
45 | }
46 | protected set
47 | {
48 | keccakR = value;
49 | }
50 | }
51 |
52 | public int SizeInBytes
53 | {
54 | get
55 | {
56 | return KeccakR / 8;
57 | }
58 | }
59 |
60 | public int HashByteLength
61 | {
62 | get
63 | {
64 | return HashSizeValue / 8;
65 | }
66 | }
67 |
68 | public
69 | #if (!PORTABLE && !NETSTANDARD14)
70 | override
71 | #endif
72 | bool CanReuseTransform
73 | {
74 | get
75 | {
76 | return true;
77 | }
78 | }
79 |
80 | protected Keccak(int hashBitLength)
81 | {
82 | if (hashBitLength != 224 && hashBitLength != 256 && hashBitLength != 384 && hashBitLength != 512)
83 | throw new ArgumentException("hashBitLength must be 224, 256, 384, or 512", "hashBitLength");
84 | Initialize();
85 | HashSizeValue = hashBitLength;
86 | switch (hashBitLength)
87 | {
88 | case 224:
89 | KeccakR = 1152;
90 | break;
91 | case 256:
92 | KeccakR = 1088;
93 | break;
94 | case 384:
95 | KeccakR = 832;
96 | break;
97 | case 512:
98 | KeccakR = 576;
99 | break;
100 | }
101 | RoundConstants = new ulong[]
102 | {
103 | 0x0000000000000001UL,
104 | 0x0000000000008082UL,
105 | 0x800000000000808aUL,
106 | 0x8000000080008000UL,
107 | 0x000000000000808bUL,
108 | 0x0000000080000001UL,
109 | 0x8000000080008081UL,
110 | 0x8000000000008009UL,
111 | 0x000000000000008aUL,
112 | 0x0000000000000088UL,
113 | 0x0000000080008009UL,
114 | 0x000000008000000aUL,
115 | 0x000000008000808bUL,
116 | 0x800000000000008bUL,
117 | 0x8000000000008089UL,
118 | 0x8000000000008003UL,
119 | 0x8000000000008002UL,
120 | 0x8000000000000080UL,
121 | 0x000000000000800aUL,
122 | 0x800000008000000aUL,
123 | 0x8000000080008081UL,
124 | 0x8000000000008080UL,
125 | 0x0000000080000001UL,
126 | 0x8000000080008008UL
127 | };
128 | }
129 |
130 | protected ulong ROL(ulong a, int offset)
131 | {
132 | return (((a) << ((offset) % KeccakLaneSizeInBits)) ^ ((a) >> (KeccakLaneSizeInBits - ((offset) % KeccakLaneSizeInBits))));
133 | }
134 |
135 | protected void AddToBuffer(byte[] array, ref int offset, ref int count)
136 | {
137 | int amount = Math.Min(count, buffer.Length - buffLength);
138 | Buffer.BlockCopy(array, offset, buffer, buffLength, amount);
139 | offset += amount;
140 | buffLength += amount;
141 | count -= amount;
142 | }
143 |
144 | public
145 | #if !PORTABLE && !NETSTANDARD14
146 | override
147 | #endif
148 | byte[] Hash
149 | {
150 | get
151 | {
152 | return HashValue;
153 | }
154 | }
155 |
156 | public
157 | #if !PORTABLE
158 | override
159 | #endif
160 | int HashSize
161 | {
162 | get
163 | {
164 | return HashSizeValue;
165 | }
166 | }
167 |
168 | #endregion
169 |
170 | public
171 | #if !PORTABLE
172 | override
173 | #endif
174 | void Initialize()
175 | {
176 | buffLength = 0;
177 | state = new ulong[5 * 5];//1600 bits
178 | HashValue = null;
179 | }
180 |
181 | protected
182 | #if !PORTABLE
183 | override
184 | #endif
185 | void HashCore(byte[] array, int ibStart, int cbSize)
186 | {
187 | if (array == null)
188 | throw new ArgumentNullException("array");
189 | if (ibStart < 0)
190 | throw new ArgumentOutOfRangeException("ibStart");
191 | if (cbSize > array.Length)
192 | throw new ArgumentOutOfRangeException("cbSize");
193 | if (ibStart + cbSize > array.Length)
194 | throw new ArgumentOutOfRangeException("ibStart or cbSize");
195 | }
196 |
197 | #if PORTABLE
198 | public abstract int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset);
199 | public abstract byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount);
200 | #endif
201 | }
202 | }
--------------------------------------------------------------------------------