Documentation | Linux/macOS/Windows |
---|---|
MaidSafe website | SAFE Dev Forum | SAFE Network Forum |
---|
This crate implements a CLI (Command Line Interface) for the SAFE Network.
The SAFE CLI provides all the tools necessary to interact with the SAFE Network, including storing and browsing data of any kind, following links that are contained in the data and using their addresses on the network. Thus using the CLI users have access to any type of operation that can be made on SAFE Network data, allowing them to also use it for automated scripts in a piped chain of commands.
For further information please see https://safenetforum.org/t/safe-cli-high-level-design-document/28690
In order to build this CLI from source code you need to make sure you have rustc v1.35.0
(or higher) installed. Please take a look at this notes about Rust installation if you need help with installing it. We recommend you install it with rustup
which will install cargo
tool since this guide makes use of it.
Once Rust and its toolchain are installed, run the following commands to clone this repository and build the safe_cli
crate (the build process may take several minutes the first time you run it on this crate):
$ git clone https://github.com/maidsafe/safe-cli.git
$ cd safe-cli
$ cargo build
Right now the CLI is under active development. Here we're listing commands ready to be tested (against mock).
The base command, if built is $ safe
, or all commands can be run via $ cargo run -- <command>
.
Various global flags are available (those commented out are not yet implemented):
--dry-run Dry run of command. No data will be written. No coins spent.
-h, --help Prints help information
--json Sets JSON as output serialisation format (alias of '--output json')
# --root The account's Root Container address
-V, --version Prints version information
# -v, --verbose Increase output verbosity. (More logs!)
-o, --output <output_fmt> Output data serlialisation. Currently only supported 'json'
# -q, --query <query> Enable to query the output via SPARQL eg.
--xorurl <xorurl_base> Base encoding to be used for XOR-URLs generated. Currently supported: base32z
(default), base32 and base64
All commands have a --help
function which will list args, options and subcommands.
The CLI is just another client SAFE application, therefore it needs to be authorised by the user to gain access to the SAFE Network on behalf of the user. The CLI auth
command allows us to obtain such authorisation from the account owner (the user) via the SAFE Authenticator.
This command simply sends an authorisation request to the Authenticator available, e.g. the safe_auth CLI daemon (see further bellow for explanation of how to run it), and it then stores the authorisation response (credentials) in <user's home directory>/.safe/credentials
file. Any subsequent CLI command will read the ~/.safe/credentials
file, to obtain the credentials and connect to the network for the corresponding operation.
You need the SAFE Authenticator CLI running locally and exposing its WebService interface for authorising applications, and also be logged in to a SAFE account created on the mock network (i.e. MockVault
file), making sure the port number you set is 41805
, and enabling the mock-network
feature.
Please open a second/separate terminal console to execute the following commands (again, please make sure you have rustc v1.35.0
or higher):
$ git clone https://github.com/maidsafe/safe-authenticator-cli.git
$ cd safe-authenticator-cli
$ cargo run --features mock-network -- --daemon 41805
Now that the Authenticator is running and ready to authorise applications, we can simply invoke the auth
command:
$ safe auth
At this point, you need to authorise the application on the Authenticator, you should see a prompt like the following:
The following application authorisation request was received:
+------------------+----------+------------------+------------------------+
| Id | Name | Vendor | Permissions requested |
+------------------+----------+------------------+------------------------+
| net.maidsafe.cli | SAFE CLI | MaidSafe.net Ltd | Own container: false |
| | | | Default containers: {} |
+------------------+----------+------------------+------------------------+
Allow authorisation? [y/N]:
Key
management allows users to generate sign/encryption key pairs that can be used for different type of operations, like choosing which sign key to use for uploading files (and therefore paying for the storage used), or signing a message posted on some social application when a Key
is linked from a public profile (e.g. a WebID/SAFE-ID), or even for encrypting messages that are privately sent to another party so it can verify the authenticity of the sender.
Users can record Key
's in a Wallet
(see further below for more details about Wallet
's), having friendly names to refer to them, but they can also be created as throw away Key
's which are not linked from any Wallet
, container, or any other type of data on the network.
Note that even though the key pair is automatically generated by the CLI, Key
s don’t hold the secret key on the network but just the public key, and Key
s optionally can have a safecoin balance attached to it. Thus Key
's can also be used for safecoin transactions. In this sense, a Key
can be compared to a Bitcoin address, it has a coin balance associated to it, such balance can be queried using the public key (since its location on the network is based on the public key itself), but in order to spend its balance the corresponding secret key needs to be provided in the transfer
request. The secret key can be provided by the user, or retrieved from a Wallet
, at the moment of creating the transaction (again, see the Wallet
section below for more details)
To generate a key pair and create a new Key
on the network, the secret key of another Key
is needed to pay for storage costs:
$ safe keys create --pay-with <secret key>
But we can also create a Key
with test-coins since we are using the mock network:
$ safe keys create --test-coins --preload 15.342
New Key created at: "safe://bbkulcbnrmdzhdkrfb6zbbf7fisbdn7ggztdvgcxueyq2iys272koaplks"
Key pair generated:
pk = b62c1e4e3544a1f64212fca89046df98d998ea615e84c4348c4b5fd29c07ad52a970539df819e31990c1edf09b882e61
sk = c4cc596d7321a3054d397beff82fe64f49c3896a07a349d31f29574ac9f56965
Once we have some Key
's with some test-coins we can use them to pay for the creation of new Key
's, thus if we use the Key
we just created with test-coins we can create a second Key
:
$ safe keys create --preload 8.15 --pay-with c4cc596d7321a3054d397beff82fe64f49c3896a07a349d31f29574ac9f56965
New Key created at: "safe://bbkulcbf2uuqwawvuonevraqa4ieu375qqrdpwvzi356edwkdjhwgd4dum"
Key pair generated:
pk = 9754a42c0b568e692b10401c4129bff61088df6ae51bef883b28693d8c3e0e8ce23054e236bd64edc45791549ef60ce1
sk = 2f211ad4606c716c2c2965e8ea2bd76a63bfc5a5936b792cda448ddea70a031c
Other optional args that can be used with keys create
sub-command are:
--pk <pk> Don't generate a key pair and just use the provided public key
--preload <preload> Preload the Key with a coin balance
We can retrieve a given Key
's balance simply using its secret key, which we can pass to keys balance
subcommand with --sk <secret key>
argument, or we can enter it when the CLI prompts us.
We can optionally also pass the Key
's XorUrl to have the CLI to verify they correspond to each other, i.e. if the Key
's XorUrl is provided, the CLI will check if it corresponds to the public key derived from the passed secret key, and throw an error in it doesn't.
The target Key
's secret key can be passed as an argument (or it will be retrieved from stdin
), let's check the balance of the Key
we created in previous section:
$ safe keys balance
Enter secret key corresponding to the Key to query the balance from: c4cc596d7321a3054d397beff82fe64f49c3896a07a349d31f29574ac9f56965
Key's current balance: 15.342
There are some scenarios that being able to generate a sign/encryption key-pair, without creating and/or storing a Key
on the network, is required.
As an example, if we want to have a friend to create a Key
for us, and preload it with some safecoins, we can generate a key-pair, and share with our friend only the public key so they can generate the Key
to be owned by it (this is where we can use the --pk
argument on the keys create
sub-command).
Thus, let's see how this use case would work. First we create a key-pair:
$ safe keypair
Key pair generated:
pk = b2371df48684dc9456988f45b56d7640df63895fea3d7cee45c79b26ba268d259b864330b83fa28669ab910a1725b833
sk = 62e323615235122f7e20c7f05ddf56c5e5684853d21f65fca686b0bfb2ed851a
We now take note of both the public key, and the secret key. Now, we only share the public key with our friend, who can use it to generate a Key
to be owned by it and preload it with some test-coins:
$ safe keys create --test-coins --preload 64.24 --pk b2371df48684dc9456988f45b56d7640df63895fea3d7cee45c79b26ba268d259b864330b83fa28669ab910a1725b833
New Key created at: "safe://hodby8y3qgina9nqzxmsoi8ytjfh6gwnia7hdupo49ibt8yy3ytgdq"
Finally, our friend gives us the XOR-URL of the Key
they have created for us, and we can now use the Key
for any other operation, we own the balance it contains since we have the secret key associated to it.
A Wallet
is a specific type of Container on the network, holding a set of spendable safecoin balances.
A Wallet
effectively contains links to Key
's which have safecoin balances attached to them, but the Wallet
also stores the secret keys needed to spend them. Wallet
's are stored encrypted and only accessible to the owner by default.
There are several sub-commands that can be used to manage the Wallet
's with the safe wallet
command (those commented out are not yet implemented):
SUBCOMMANDS:
balance Query a Wallet's total balance
# check-tx Check the status of a given transaction
create Create a new Wallet
help Prints this message or the help of the given subcommand(s)
insert Insert a spendable balance into a Wallet
# sweep Move all coins within a Wallet to a second given Wallet or Key
transfer Transfer safecoins from one Wallet, Key or pk, to another.
USAGE:
safe wallet create [FLAGS] [OPTIONS]
FLAGS:
-n, --dry-run Dry run of command. No data will be written. No coins spent
-h, --help Prints help information
--no-balance If true, do not create a spendable balance
--json Sets JSON as output serialisation format (alias of '--output json')
--test-coins Create a Key, allocate test-coins onto it, and add the Key to the Wallet
-V, --version Prints version information
OPTIONS:
--keyurl <keyurl> An existing Key's safe://xor-url. If this is not supplied, a new Key will be
automatically generated and inserted. The corresponding secret key will be prompted if
not provided with '--sk'
--name <name> The name to give the spendable balance
-o, --output <output_fmt> Output data serlialisation. Currently only supported 'json'
-w, --pay-with <pay_with> The secret key of a Key for paying the operation costs
--preload <preload> Preload the key with a balance
--sk <secret> Pass the secret key needed to make the balance spendable, it will be prompted if not
provided
--xorurl <xorurl_base> Base encoding to be used for XOR-URLs generated. Currently supported: base32z
(default), base32 and base64
Right now, only a secret key (of a Key
with coins) can be used to pay for the costs, but in the future a Wallet
will be also allowed for this purpose.
For example, if we use the secret key we obtained when creating a Key
in our example in previous section to pay for the costs, we can create a Wallet
with a new spendable balance by simply running:
$ safe wallet create --pay-with 62e323615235122f7e20c7f05ddf56c5e5684853d21f65fca686b0bfb2ed851a
New Key created at: "safe://hodqmc6ht5ezpprkh1cbw54n3mjyckcpm95qmygon897ft5dq8oxpc"
Key pair generated:
pk = a7086bbc7f7dad7db400a99ace99fd46abfef652d04788dbc3b9d1b6e45dec08806ee9cd318ee914577fae6a58009cae
sk = 65f7cd252d3b66456239611f293325f94f4f89e1eda0b3b1d5bc41743999003c
Wallet created at: "safe://hbymipwqmm3ityq3ox5xuu6j7mjm8aw11nhnjnzpy1dib4cgmr63rc1jao"
The balance of a given Wallet
can be queried using its XorUrl. This returns the balance of the whole Wallet
, including the contained spendable balances, or any child/nested Wallet
's (this is not implemented just yet).
The target Wallet
can be passed as an argument (or it will be retrieved from stdin
):
$ safe wallet balance safe://hbymipwqmm3ityq3ox5xuu6j7mjm8aw11nhnjnzpy1dib4cgmr63rc1jao
Wallet at "safe://hbymipwqmm3ityq3ox5xuu6j7mjm8aw11nhnjnzpy1dib4cgmr63rc1jao" has a total balance of 0 safecoins
As mentioned before, a Key
doesn't hold the secret key on the network, therefore even if it has some non-zero coin balance, it cannot be spent. This is where the Wallet
comes into play, holding the links to Key
's, and making their balances spendable by storing the corresponding secret keys.
Aside from at wallet creation, we can add more keys to use as spendable balances by insert
-ing into a Wallet
a link to a Key
, making it a spendable balance.
USAGE:
safe wallet insert [FLAGS] [OPTIONS] <target>
FLAGS:
--default Set the inserted Key as the default one in the target Wallet
-n, --dry-run Dry run of command. No data will be written. No coins spent
-h, --help Prints help information
--json Sets JSON as output serialisation format (alias of '--output json')
-V, --version Prints version information
OPTIONS:
--keyurl <keyurl> The Key's safe://xor-url to verify it matches/corresponds to the secret key provided.
The corresponding secret key will be prompted if not provided with '--sk'
--name <name> The name to give this spendable balance
-o, --output <output_fmt> Output data serlialisation. Currently only supported 'json'
-w, --pay-with <pay_with> The secret key of a Key for paying the operation costs. If not provided, the default
wallet from the account will be used
--sk <secret> Pass the secret key needed to make the balance spendable, it will be prompted if not
provided
--xorurl <xorurl_base> Base encoding to be used for XOR-URLs generated. Currently supported: base32z
(default), base32 and base64
ARGS:
<target> The target Wallet to insert the spendable balance
- The
<target>
is theWallet
to insert the spendable balance to - The
--name
is an optional nickname to give a spendable balance for easy reference - The
--default
flag sets this new spendable balance as the default for the containingWallet
. This can be used by wallet applications to apply some logic on how to spend and/or choose the balances for a transaction
With the above options, the user will be prompted to input the secret key corresponding to the Key
to be inserted, unless it was already provided with --sk
. This is stored in the Wallet
.
The --sk
argument can also be combined with --keyurl
to pass the Key
's XorUrl as part of the command line instruction itself, e.g.:
$ safe wallet insert safe://<wallet-xorurl> --keyurl safe://<key-xor-url> --name my_default_balance --default
Enter secret key corresponding to public key at safe://<key-xor-url>:
b493a84e3b35239cbffdf10b8ebfa49c0013a5d1b59e5ef3c000320e2d303311
Spendable balance inserted with name 'my_default_balance' in Wallet located at "safe://<wallet-xorurl>"
Once a Wallet
contains some spendable balance/s, we can transfer <from>
a Wallet
an <amount>
of safecoins <to>
another Wallet
or Key
. The destination Wallet
/Key
currently must be passed as a XorUrl in the arguments list, but reading it from stdin
will be supported later on.
Both the <from>
and <to>
Wallets must have a default spendable balance for the transfer to succeed. In the future different type of logics will be implemented for using different Wallet's balances and not just the default one.
$ safe wallet transfer <amount> <to> <from>
E.g.:
$ safe wallet transfer 323.23 safe://hbyek1io7m6we5ges83fcn16xd51bqrrjjea4yyhu4hbu9yunyc5mucjao safe://hodn6ny9jwhrnokdrgrfmn1jyksh7exctuuzh9w35bpuw5wmpp7hhp
Success. TX_ID: 6183829450183485238
Uploading files and folders onto the network is also possible with the CLI application, and as we'll see here it's extremely simple to not just upload them but also keep them in sync with any modifications made locally to the folders and files.
Files are uploaded on the Network and stored as Published ImmutableData
files, and the folders and sub-folders hierarchy is flattened out and stored in a container mapping each files's path with the corresponding ImmutableData
XOR-URL. This map is maintained on the Network in a special container called FilesContainer
, which is stored as Published AppendOnlyData
data. The data representation in the FilesContainer
is planned to be implemented with RDF and the corresponding FilesContainer
RFC will be submitted, but at this stage this is being done only using a simple serialised structure.
The most simple scenario is to upload all files and sub-folders found within a local ./to-upload/
directory, recursively, onto a FilesContainer
on the Network, obtaining the XOR-URL of the newly created container, as well as the XOR-URL of each of the files uploaded:
$ safe files put ./to-upload/ --recursive
FilesContainer created at: "safe://bbkulcb5hsl2zbsia4af5i7myv2ujbet7di4gx5bstduikwgobru67esqu"
+ ./to-upload/index.html safe://bbkulcax6ulw7ovqhpsindkybsum4tusmvuc7ovtr2bu5gj6m4ugtu7euh
+ ./to-upload/myfolder/notes.txt safe://bbkulcan3may5gmqxqonwaoz2cjlkuc4cflrhwitmzy7ur4paof4u57yxz
+ ./to-upload/img.jpeg safe://bbkulcbtiq3vg4xehqbrjd2gz4kljguqtds5ko5khexya3v3k7scymcphj
Note that the +
sign means the files were all added to the FilesContainer
, which will make more sense later on when we see how to use the files sync
command to update and/or delete files.
A single file can also be uploaded using the files put
command, which will create a FilesContainer
as well but this time only a single file will be added to the map:
$ safe files put ./to-upload/myfile.txt
FilesContainer created at: "safe://bbkulca25xhzwo6mcxlji7ocf5tm5hgn2x3mxtg62qzycculur4aixeywm"
+ ./to-upload/myfile.txt safe://bbkulcbxk23cfnj7gz3r4y7624kpb5spwf4b7jogu2rofhuj5xiqa5huh7
When uploading files onto a FilesContainer
with the CLI, the base path for the files in the container is set by default to be /
. All the files at the source are published on the FilesContainer
with an absolute path with base /
path.
As an example, if we upload three files, which at source are located at /to-upload/file1.txt
, /to-upload/myfolder/file2.txt
, and /to-upload/myotherfolder/subfolder/file3.txt
, the files will be published on the FilesContainer
with paths /file1.txt
, /myfolder/file2.txt
, and /myotherfolder/subfolder/file3.txt
respectively.
We can additionally pass a destination path argument to set a base path for each of the paths in the FilesContainer
, e.g. if we provide /mychosenroot/
destination path argument to the files put
command when uploading the above files, they will be published on the FilesContainer
with paths /mychosenroot/file1.txt
, /mychosenroot/myfolder/file2.txt
, and /mychosenroot/myotherfolder/subfolder/file3.txt
respectively. This can be verified by querying the FilesContainer
content with the safe cat
command, please see further below for details of how this command.
Once a set of files, folders and subfolders, have been uploaded to the Network onto a FilesContainer
using the files put
command, local changes made to those files and folders can be easily synced up using the files sync
command. This command takes care of finding the differences/changes on the local files and folders, creating new Published ImmutableData
files as necessary, and updating the FilesContainer
by publishing a new version of it at the same location on the Network.
The files sync
command follows a very similar logic to the well known rsync
command supporting a subset of the functionality provided by it. The subset of features supported will be gradually expanded with more features. Users knowing how to use rsync
can easily start using the SAFE CLI and the SAFE Network for uploading files and folders, making it also easy to integrate existing automated systems which are currently making use of rsync
.
As an example, let's suppose we uploaded all files and subfolders found within the ./to-upload/
local directory, recursively, using files put
command:
$ safe files put ./to-upload/ --recursive
FilesContainer created at: "safe://hbyw8kkqr3tcwfqiiqh4qeaehzr1e9boiuyfw5bqqx1adyh9sawdhboj5w"
+ ./to-upload/another.md safe://hoxm5aps8my8he8cpgdqh8k5wuox5p7kzed6bsbajayc3gc8pgp36s
+ ./to-upload/subfolder/subexists.md safe://hoqc6etdwbx6s86u3bkxenos3rf7dtr51eqdt17smxsw7aejot81dc
+ ./to-upload/test.md safe://hoxibhqth9awkjgi35sz73u35wyyscuht65m3ztrznb6thd5z8hepx
All the content of the ./to-upload/
local directory is now stored and published on the SAFE Network. Now, let's say we make the following changes to our local files within the ./to-upload/
folder:
- We edit
./to-upload/another.md
and change its content - We create a new file at
./to-upload/new.md
- And we remove the file
./to-upload/test.md
We can now sync up all the changes we just made, recursively, with the FilesContainer
we previously created:
$ safe files sync ./to-upload/ safe://hbyw8kkqr3tcwfqiiqh4qeaehzr1e9boiuyfw5bqqx1adyh9sawdhboj5w --recursive --delete
FilesContainer synced up (version 2): "safe://hbyw8kkqr3tcwfqiiqh4qeaehzr1e9boiuyfw5bqqx1adyh9sawdhboj5w"
* ./to-upload/another.md safe://hox6jstso13b7wzfkw1wbs3kwn9gpssudqunk6sw5yt3d6pnmaec53
+ ./to-upload/new.md safe://hoxpdc8ywz18twkg7wboarj45hem3pq6ou6sati9i3dud68tzutw34
- /test.md safe://hoxibhqth9awkjgi35sz73u35wyyscuht65m3ztrznb6thd5z8hepx
The *
, +
and -
signs mean that the files were updated, added, and removed respectively.
Also, please note we provided the optional --delete
flag to the command above, this forces the deletion of those files which are found at the targeted FilesContainer
that are not found in the source location, like the case of ./to-upload/test.md
file in our example above. If we didn't provide such flag, only the modification and creation of files would have been updated on the FilesContainer
, like the case of ./to-upload/another.md
and ./to-upload/new
files in our example above. Note that --delete
is only allowed if the --recursive
flag is also provided.
The files sync
command also supports to be passed a destination path as the files put
command, but in this case the destination path needs to be provided as part of the target XOR-URL. E.g., we can sync a FilesContainer
using the local path and provide a specific destination path new-files
in the target XOR-URL:
$ safe files sync ./other-folder/ safe://hbyw8kkqr3tcwfqiiqh4qeaehzr1e9boiuyfw5bqqx1adyh9sawdhboj5w/new-files
FilesContainer synced up (version 3): "safe://hbyw8kkqr3tcwfqiiqh4qeaehzr1e9boiuyfw5bqqx1adyh9sawdhboj5w"
+ ./other-folder/file1.txt safe://hoqi7papyp7c6riyxiez6y5fh5ugj4xc7syqhmex774ws4g4b1z1xq
The ./other-folder/file1.txt
file will be uploaded and published in the FilesContainer
with path /new-files/file1.txt
.
The cat
command is probably the most straight forward command, it allows users to fetch data from the Network using a URL, and render it according to the type of data being fetched:
$ safe cat safe://<XOR-URL>
If the XOR-URL targets a published FilesContainer
, the cat
command will fetch the content of it and render it showing the list of files contained (linked) from it, along with the corresponding XOR-URLs for each of the linked files.
Let's see this in action, if we upload some folder using the files put
command, e.g.:
$ safe files put ./to-upload/ --recursive
FilesContainer created at: "safe://hnyynyw4gsy3i6ixu5xkpt8smxrihq3dy65qcoau5gznnuee71ogmns1jrbnc"
+ ./to-upload/another.md safe://hbyyyynhci18zwrjmiwqgpf5ofukf3dtryrkeizk1yxda3a5zoew6mgeox
+ ./to-upload/subfolder/subexists.md safe://hbyyyydo4dhazjnj4i1sb4gpz94m19u31asrjaq3d8rzzc8s648w6xkzpb
+ ./to-upload/test.md safe://hbyyyydx1c168rwuqi6hcctwfbf1ihf9dfhr4bkmb6kzacs96uyj7bp4n6
We can then use safe cat
command with the XOR-URL of the FilesContainer
just created to render the list of files linked from it:
$ safe cat safe://hnyynyw4gsy3i6ixu5xkpt8smxrihq3dy65qcoau5gznnuee71ogmns1jrbnc
Files of FilesContainer (version 1) at "safe://hnyynyw4gsy3i6ixu5xkpt8smxrihq3dy65qcoau5gznnuee71ogmns1jrbnc":
+-------------------------+------+----------------------+----------------------+-------------------------------------------------------------------+
| Name | Size | Created | Modified | Link |
+-------------------------+------+----------------------+----------------------+-------------------------------------------------------------------+
| /another.md | 6 | 2019-07-24T13:22:49Z | 2019-07-24T13:22:49Z | safe://hbyyyynhci18zwrjmiwqgpf5ofukf3dtryrkeizk1yxda3a5zoew6mgeox |
+-------------------------+------+----------------------+----------------------+-------------------------------------------------------------------+
| /subfolder/subexists.md | 7 | 2019-07-24T13:22:49Z | 2019-07-24T13:22:49Z | safe://hbyyyydo4dhazjnj4i1sb4gpz94m19u31asrjaq3d8rzzc8s648w6xkzpb |
+-------------------------+------+----------------------+----------------------+-------------------------------------------------------------------+
| /test.md | 12 | 2019-07-24T13:22:49Z | 2019-07-24T13:22:49Z | safe://hbyyyydx1c168rwuqi6hcctwfbf1ihf9dfhr4bkmb6kzacs96uyj7bp4n6 |
+-------------------------+------+----------------------+----------------------+-------------------------------------------------------------------+
We could also take any of the XOR-URLs of the individual files and have the cat
command to fetch the content of the file and show it in the output, e.g. let's use the XOR-URL of the /test.md
file to fetch its content:
$ safe cat safe://hbyyyydx1c168rwuqi6hcctwfbf1ihf9dfhr4bkmb6kzacs96uyj7bp4n6
hello tests!
Alternatively, we could use the XOR-URL of the FilesContainer
and provide the path of the file we are trying to fetch, in this case the cat
command will resolve the path and follow the corresponding link to read the file's content directly for us. E.g. we can also read the content of the /test.md
file with the following command:
$ safe cat safe://hnyynyw4gsy3i6ixu5xkpt8smxrihq3dy65qcoau5gznnuee71ogmns1jrbnc/test.md
hello tests!
As seen above, the safe cat
command can be used to fetch any type of content from the SAFE Network, at this point it only supports files (ImmutableData
), FilesContainer
's and NRS-Container
's (see further below about NRS Containers and commands), but it will be expanded as more types are supported by the CLI and its API.
In order to get additional information about the native data type holding the data of a specific content, we can pass the --info
flag to the cat
command:
$ safe cat safe://hbyit4fq3pwk9yzcytrstcgbi68q7yr9o8j1mnrxh194m6jmjanear1j5w --info
Native data type: PublishedSeqAppendOnlyData
Type tag: 1100
XOR name: 0x346b0335f55f3dbd4d89ecb792bc76460f6dcc8627b35c429a11d940cb15a492
Files of FilesContainer (version 1) at "safe://hnyynyw4gsy3i6ixu5xkpt8smxrihq3dy65qcoau5gznnuee71ogmns1jrbnc":
+-------------------------+------+----------------------+----------------------+-------------------------------------------------------------------+
| Name | Size | Created | Modified | Link |
+-------------------------+------+----------------------+----------------------+-------------------------------------------------------------------+
| /another.md | 6 | 2019-07-24T13:22:49Z | 2019-07-24T13:22:49Z | safe://hbyyyynhci18zwrjmiwqgpf5ofukf3dtryrkeizk1yxda3a5zoew6mgeox |
+-------------------------+------+----------------------+----------------------+-------------------------------------------------------------------+
| /subfolder/subexists.md | 7 | 2019-07-24T13:22:49Z | 2019-07-24T13:22:49Z | safe://hbyyyydo4dhazjnj4i1sb4gpz94m19u31asrjaq3d8rzzc8s648w6xkzpb |
+-------------------------+------+----------------------+----------------------+-------------------------------------------------------------------+
| /test.md | 12 | 2019-07-24T13:22:49Z | 2019-07-24T13:22:49Z | safe://hbyyyydx1c168rwuqi6hcctwfbf1ihf9dfhr4bkmb6kzacs96uyj7bp4n6 |
+-------------------------+------+----------------------+----------------------+-------------------------------------------------------------------+
And of course that can be used also with other type of content like ImmutableData
files:
$ safe cat safe://hnyynyw4gsy3i6ixu5xkpt8smxrihq3dy65qcoau5gznnuee71ogmns1jrbnc/subfolder/subexists.md --info
Native data type: ImmutableData (published)
XOR name: 0xc343e62e9127559583a336ffd2e5f9e658b11387646725eec3dbda3d3cf55da1
Raw content of the file:
hello from a subfolder!
As we've seen in all the above sections, every piece of data on the SAFE Network has a unique location. Such location is determined by the XoR name given to it in the Network's XoR address space, as well as some other information which depend on the native date type, like in the case of MutableData
data types which also has a type tag associated to it apart from its XoR address.
So far all commands were using the XOR-URLs to either inform of the new data created/stored on the Network, as well as for retrieving data form the Network.
While XOR-URLs are simply a way to encode SAFE Network data unique location into a URL, there are some incentive for having more human friendly URLs that can be easily remembered and recognisable when trying to share them with other people, or use them with tools and applications like the SAFE CLI or the SAFE Browser.
This is why the SAFE Network also supports having such human friendly URLs through what it's called a Name Resolution System (NRS)
. The NRS allows users to create friendly names that are resolvable to a unique location on the Network. This friendly names can be used in the form of a URL (NRS-URL) to share with other people the location of websites, web applications, files and folders, safecoin wallets for receiving transfers, SAFE IDs, etc.
In this section we will explore the CLI commands which allow users to generate, administer, and use the NRS and its NRS-URLs for publishing and retrieving data to/from the SAFE Network.
Creating a friendly name on the Network can be achieved with the nrs create
subcommand. This subcommand generates an NRS Container automatically linking it to any data we decide to link the friendly name to. An NRS Container is stored on the Network as a Published AppendOnlyData
data, and it contains an NRS Map using RDF for its data representation (since this is still under development, pseudo-RDF data is now being used temporarily), this Map has a list of subnames and where each of them are being linked to, e.g. mysubname
can be created as a subname of mywebsite
NRS name by having mysubname
linked to a particular FilesContainer
XOR-URL so that if can be fetched with safe://mysubname.mywebsite
.
Let's imagine we have uploaded the files and folders of a website we want to publish on the SAFE Network with files put
command:
$ safe files put ./website-to-publish/ --recursive`
FilesContainer created at: "safe://hnyynyie8kccparz3pcxj9uisdc4gyzcpem9dfhehhjd6hpzwf8se5w1zobnc"
+ ./website-to-publish/index.html safe://hbyyyydhp7y3mb6zcj4herpqm53ywnbycstamb54yhniud1cij7frjfe8c
+ ./website-to-publish/image.jpg safe://hbyyyynkt8ak5mxmbqkdt81hqceota8fu83e49gi3weszddujfc8fxcugp
+ ./website-to-publish/contact/form.html safe://hbyyyyd1sw4dd57k1xeeijukansatia6mthaz1h6htnb8pjoh9naskoaks
As we know that website is now publicly available on the SAFE Network for anyone who wants to visit using its XOR-URL "safe://hnyynyie8kccparz3pcxj9uisdc4gyzcpem9dfhehhjd6hpzwf8se5w1zobnc" with either $ safe cat
command, or a SAFE Browser. But let's now create a NRS name for it and obtain its human friendly NRS-URL:
$ safe nrs create mywebsite --link safe://hnyynyie8kccparz3pcxj9uisdc4gyzcpem9dfhehhjd6hpzwf8se5w1zobnc
New NRS Map for "safe://mywebsite" created at: "safe://hnyydyz7utb6npt9kg3aksgorfwmkphet8u8z3or4nsu8n3bj8yiep4a91bqh"
+ mywebsite safe://hnyynyie8kccparz3pcxj9uisdc4gyzcpem9dfhehhjd6hpzwf8se5w1zobnc
We can now share the NRS-URL safe://mywebsite
to anyone who wants to visit our website. Using this NRS-URL we can now fetch the same content we would do when using the FilesContainer
XOR-URL we linked to it, thus we can fetch it using the following command:
$ safe cat safe://mywebsite
Files of FilesContainer (version 1) at "safe://mywebsite":
+-------------------------+------+----------------------+----------------------+-------------------------------------------------------------------+
| Name | Size | Created | Modified | Link |
+-------------------------+------+----------------------+----------------------+-------------------------------------------------------------------+
| /index.html | 146 | 2019-07-24T14:31:42Z | 2019-07-24T14:31:42Z | safe://hbyyyydhp7y3mb6zcj4herpqm53ywnbycstamb54yhniud1cij7frjfe8c |
+-------------------------+------+----------------------+----------------------+-------------------------------------------------------------------+
| /image.jpg | 391 | 2019-07-24T14:31:42Z | 2019-07-24T14:31:42Z | safe://hbyyyynkt8ak5mxmbqkdt81hqceota8fu83e49gi3weszddujfc8fxcugp |
+-------------------------+------+----------------------+----------------------+-------------------------------------------------------------------+
| /contact/form.html | 23 | 2019-07-24T14:31:42Z | 2019-07-24T14:31:42Z | safe://hbyyyyd1sw4dd57k1xeeijukansatia6mthaz1h6htnb8pjoh9naskoaks |
+-------------------------+------+----------------------+----------------------+-------------------------------------------------------------------+
In this example the cat
simply prints out the content of the top level folder (FilesContainer
) as we've learned from previous sections of this guide, but any other tool or application would be treating this in different ways, e.g. the SAFE Browser would be automatically fetching the index.html
file from it and rendering the website to the user.
We can obviously fetch the content of any of the files published at this NRS-URL using the corresponding path:
$ safe cat safe://mywebsite/contact/form.html
<!DOCTYPE html>
<html>
<body>
<h2>Contact Form</h2>
<form>
...
</form>
</body>
</html>
Much like the old internet, the NRS system provides increased flexibility for those wanting to have a variety of resources available under one public name, via using Sub Names
. This is done by creating a Public name and using a .
(dot) character to separate it into various, individually controllable parts.
For example, you may wish to have safe://mywebsite
to be about you in general, whereas safe://blog.mywebsite
point to a different site which is your blog.
To create a public name with subnames, you need to only pass the full string with .
separators, just like any traditional URL, to the CLI:
$ safe nrs create blog.mywebsite --link safe://hnyynyie8kccparz3pcxj9uisdc4gyzcpem9dfhehhjd6hpzwf8se5w1zobnc
New NRS Map for "safe://blog.mywebsite" created at: "safe://hnyydyz7utb6npt9kg3aksgorfwmkphet8u8z3or4nsu8n3bj8yiep4a91bqh"
+ blog.mywebsite safe://hnyynyie8kccparz3pcxj9uisdc4gyzcpem9dfhehhjd6hpzwf8se5w1zobnc
As the NRS CLI advances, you'll be able to individually add to both blog.mywebsite
, or indeed just mywebsite
, as well as change what the default
resource to retrieve is for both.
Once a public name has been created with nrs create
command, more sub names can be added to it using the nrs add
command. This command expects the same arguments as nrs create
command but it only requires and assumes that the public name already exists.
Let's add profile
sub name to the mywebsite
NRS name we created before:
$ safe nrs add profile.mywebsite --link safe://hnyynyipybem7ihnzqya3w31seezj4i6u8ckg9d7s39exz37z3nxue3cnkbnc
NRS Map updated (version 2): "safe://hnyydyz7utb6npt9kg3aksgorfwmkphet8u8z3or4nsu8n3bj8yiep4a91bqh"
+ profile.mywebsite safe://hnyynyz8m4pkok41qrn9gkrwz35fu8zxfkwrc9xrt595wjtodacx9n8u3wbnc
Removing sub names from an NRS Map Container it's very simple and straight forward, since the only information required to do so is just the NRS-URL. The nrs remove
command will remove only the sub name specified in the provided NRS-URL without touching any of the other existing sub names, e.g. if the safe://sub-b.sub-a.mypubname
NRS-URL is provided then only sub-b
sub name will be removed from mypubname
NRS Map Container (by creating a new version of it, remember this is all part of the perpetual web).
Let's remove the profile
sub name from the mywebsite
NRS name we added before:
$ safe nrs remove profile.mywebsite
NRS Map updated (version 3): "safe://hnyydyz7utb6npt9kg3aksgorfwmkphet8u8z3or4nsu8n3bj8yiep4a91bqh"
- profile.mywebsite safe://hnyynyz8m4pkok41qrn9gkrwz35fu8zxfkwrc9xrt595wjtodacx9n8u3wbnc
The CLI can update itself to the latest available version. If you run safe update
, the application will check if a newer release is available on GitHub. After prompting to confirm if you want to take the latest version, it will be downloaded and the binary will be updated.
You can discuss development-related topics on the SAFE Dev Forum.
If you are just starting to develop an application for the SAFE Network, it's very advisable to visit the SAFE Network Dev Hub where you will find a lot of relevant information.
If you find any issues, or have ideas for improvements and/or new features for this application and the project, please raise them by creating a new issue in this repository.
This SAFE Network application is licensed under the General Public License (GPL), version 3 (LICENSE http://www.gnu.org/licenses/gpl-3.0.en.html).
Copyrights in the SAFE Network are retained by their contributors. No copyright assignment is required to contribute to this project.