Note: We are no longer using monotone. The project has migrated all source repos to git.
This is a revised version of Complication's original guide detailing the use of Monotone in I2P development. For basic instructions see the quick-start guide.
I2P has a distributed development model. The source code is replicated across independently administered Monotone ("MTN") repositories. Developers with commit rights are able to push their changes to the repository (a license agreement needs to be signed before commit rights are granted).
Some of Monotone's noteworthy qualities are: distributed version control, cryptographic authentication, access control, its small size, having few dependencies, storage of projects in a compressed SQLite database file, and having the ability to resume interrupted synchronization attempts.
Operating a Monotone Client
Generating Monotone keys
A transport key grants you the ability to push your changes to a Monotone repository server. In order to commit code into Monotone (in essence signing your code), a commit key is also needed. None of the public Monotone servers on I2P currently require a key in order to read (or pull) the source code.
Without a transport key, one cannot:
- pull code from a server which doesn't allow global read access
- push code to any server
- run a Monotone server
Without a commit key, one cannot:
- commit any code
Om du bara avser att hämta kod från MTN, kan du hoppa över till nästa avsnitt. Om du vill generera nycklar, läs följande.
By convention keys are named like an e-mail addresses, but a corresponding e-mail address does not need to exist. For example, your keys might be named:
- yourname@mail.i2p
- yourname-transport@mail.i2p
Monotone stores keys under $HOME/.monotone/keys
in text files which
are named identically to the keys. For example:
/home/complication/.monotone/keys/complication@mail.i2p
To generate transport and commit keys, enter the following commands at a prompt:
$ mtn genkey yourname-transport@someplace
$ mtn genkey yourname@someplace
Monotone will prompt you for a password to protect your keys. You are very strongly encouraged to set a password for the commit key. Many users will leave an empty password for the transport key, especially those running a Monotone server.
Trust, and initializing your repository
Monotone's security model helps to ensure that nobody can easily impersonate a developer without it being noticed. Since developers can make mistakes and become compromised,only manual review can ensure quality of code. Monotone's trust model will ensure that you read the right diffs. It does not replace reading diffs.
A Monotone repository is a single file (a compressed SQLite database) which contains all of the project's source code and history.
After importing the developers' keys into Monotone and setting up trust evaluation hooks, Monotone will prevent untrusted code from being checked out into your workspace. There are commands available to clean untrusted code from your workspace but in practice they've not been needed due to the push access policies in place.
A repository can hold many branches. For example, our repository holds the following main branches:
- i2p.i2p — The I2P router and associated programs
- i2p.www — The I2P project website
- i2p.syndie — Syndie, a distributed forums tool
By convention, the I2P Monotone repository is named i2p.mtn
. Before pulling
source code from servers, a database for your repository will need to be initialized.
To initialize your local repository, change into the directory that you want the
i2p.mtn
file and branch directories to be stored and issue the following
command:
$ mtn --db="i2p.mtn" db init
Obtaining and deploying developers' keys
Keys which developers use to commit code are essential for trust evaluation in Monotone. The other developers' transport keys are only required for Monotone server operators.
Developers' commit keys are provided GPG-signed on another page.
To import developers' keys after verifying their authenticity, copy all of the keys into a new
file. Create this file (e.g. keys.txt
) in the same directory where i2p.mtn
is located. Import the keys with the command:
$ mtn --db="i2p.mtn" read < keys.txt
Note: Never add keys to $HOME/.monotone/keys
manually.
Setting up trust evaluation hooks
The default Monotone trust policy is way too lax for our requirements: every committer is trusted by default. That is not acceptable for I2P development.
Change into the directory $HOME/.monotone
and open the file
monotonerc
with a text editor. Copy and paste the following two functions into this file:
-- This implements a list of trusted signers.
-- It is used on checkout and update.
-- It is not used for repo sync/push/pull.
-- If you do not include this function in ~/.monotone/monotonerc, the
-- default is to trust everybody, which is probably a bad thing
-- in an anonymous network.
-- Update the list below to reflect the signers YOU trust.
--
-- ref: http://www.monotone.ca/docs/Trust-Evaluation-Hooks.html
-- Modified to use key identities instead of key names, since
-- monotone allows duplicate key names, so any key-name-based
-- trust system is insecure.
--
-- Modified from intersection() to use key identities instead of key names, since
-- monotone allows duplicate key names.
--
-- a: table of ID structures (see above)
-- b: table of hex IDs
--
function keyintersection(a,b)
local s={}
local t={}
for k,v in pairs(a) do s[v.id] = 1 end
for k,v in pairs(b) do if s[v] ~= nil then table.insert(t,v) end end
return t
end
--
-- from mtn source project.hh and lua_hooks.cc:
-- signers is a table of integers (starting with 1) to the following ID structure:
-- struct ID
-- {
-- id: (key_id in key_identity_info) hex of revision id hash;
-- given_name: (given_name in key_identity_info) // name given when creating the key
-- name: (official_name in key_identity_info) // name returned by hooks or (once implented) policy
-- };
-- id: hex of revision id hash;
-- name: cert_name
-- val: cert_value
--
function get_revision_cert_trust(signers, id, name, val)
local trusted_signers = {
"5bc185cfd680eb512fdb9626b9fb4298e136215e", -- BlubMail@mail.i2p
"f6706ac205e6b5d7a7e3ea4244ab0ef497f0a099", -- cervantes@mail.i2p
"690f278ff6c6157cbaf23b0d602b6d6dcf368313", -- complication@mail.i2p
"eb4ac08d5ddbb2bd73889f86c1211424025a6f07", -- dev@robertfoss.se
"aae785027c240ebbb0a883fd8ebcf8d6ecee4104", -- dev@welterde.de
"86478595288d1b96b58f0c8cd8a8971bc430f8fd", -- dg2@mail.i2p
-- completed dev agreement 2013-07 but never checked in anything
--"5f75b8f0769770edc3267c21ddc9a00ddae31394", -- digit@mail.i2p
"4ebaace9973913416af92ee8d0fb93d64753df4c", -- dream@mail.i2p
"7e498ae94c9c322404adfc61b16bed388095906b", -- duck@mail.i2p
"6c728b0ffed3c2bf7fb0f3c583b30f966d9bacd5", -- echelon2@mail.i2p
"0e4e7ebebafbdf4cdacc45a47ba155b1215d8e8b", -- forget@mail.i2p
"f332b3d3b11b2efdae220cea75b9d5ba9ec3b52d", -- hamada@mail.i2p
"d681db14fd98da1efd6f8ceb2be6b91d784bdf5c", -- hankhill19580@gmail.com
"e246444b4fe69ba599e13403c4ab931066de902f", -- hiddenz@mail.i2p
"a61146ee69ddb9fcf3b82b19a62b8114b60d367e", -- HungryHobo@mail.i2p
"4844b1fd45f5a68744fa28d2f3e3b61a3cf83b95", -- kytv@mail.i2p
"6b2acfc9fe2f69b796631a514660fd7bdd237e2d", -- laziestgravy@mail.i2p
"c9b970f5e8917eada663d4c6b22096617021c95c", -- m1xxy@mail.i2p
"3be64909d6ab7c3d7afe16f20f24e672708b576b", -- magma@mail.i2p
"2977a6f4e11819a3f928783175caadc0071fc4de", -- mathiasdm@mail.i2p
"de9d196e8057e1629178edbfa1ed754c648d7340", -- meeh@mail.i2p
"2a0bba98558d7a9d7e4b1bd807789601252c0024", -- mkvore-commit@mail.i2p
"6ade4b7a9a6425194f482ab351950e4230dbbc85", -- neutron@mail.i2p
"bc74b49fd8a20513b2745a3d13414b7e9818dd18", -- Oldaris@mail.i2p
"3fb8d1ee1e82981a8076ddbcbf4d18f372b8bba7", -- privateer@mail.i2p
"e3815f0c985663182534fbd7d6a2bf93204a0bd0", -- russiansponsor@mail.i2p
"2ef1ae1e73a30e1afc0b4a7af89b4380b3dd46b7", -- slumlord@mail.i2p
"1092773c40f5813b9179d52a8ab7b499b9554da3", -- sponge@mail.i2p
"01265f0c817b24548478341fb75e672720a78b21", -- str4d@mail.i2p
"38fe2aa37e1eb9a300a2061ef153265c48031c6b", -- walking@mail.i2p
"a0eb78d437efad120dd9edcd776a327ec2c2adde", -- zab@mail.i2p
"2158706490e62a17c8140b6e9eabca965b681bc7", -- zab2@mail.i2p
"56810cd6434ab33593260e188b32bb83e4e9a139", -- z3r0fox@mail.i2p
"896e399990704373125f782ae2ee19b6611ac612" -- zzz@mail.i2p
}
local t = keyintersection(signers, trusted_signers)
if t == nil then return false end
if #t>= 1 then return true end
return false
end
The first function determines an intersection between two sets, in our case a revision's signers and trusted signers.
The second function determines trust in a given revision, by calling the first function with "signers" and "trusted" as arguments. If the intersection is null, the revision is not trusted. If the intersection is not empty, the revision is trusted. Otherwise, the revision is not trusted.
More information about Trust Evaluation Hooks can be found in the official Monotone documentation.
Pulling the i2p.i2p
, i2p.www
and i2p.syndie
branches
I2P is shipped with a pre-configured tunnel pointing to the project Monotone server. Ensure that the tunnel has been started within I2PTunnel before attempting to pull the source code from 127.0.0.1:8998.
Enter the directory where you initialized i2p.mtn
. Depending on whether you
want only I2P sources, or also sources for the I2P website and Syndie, you can
perform the pull
operation in different ways.
If you only want I2P sources:
$ mtn --db="i2p.mtn" -k "" pull "mtn://127.0.0.1:8998?i2p.i2p"
If you want all branches:
$ mtn --db="i2p.mtn" -k "" pull "mtn://127.0.0.1:8998?i2p.*"
Pulling in the above examples is done anonymously by specifying an empty transport key. If everyone pulls anonymously it will be harder for an attacker who gains control of the server to selectively provide some people with tampered data.
Verifying that trust evaluation works
To verify that trust evaluation works:
- Make a backup of your
monotonerc
file. - Modify
monotonerc
by setting the trusted_signers variable in the following way:local trusted_signers = {}
-
With
monotonerc
configured as above, Monotone will no longer trust any committers. Confirm this by changing into the directory wherei2p.mtn
was created and attempt a checkout of the I2P branch:$ mtn --db="i2p.mtn" co --branch="i2p.i2p"
A directory named
i2p.i2p
should not appear. You should encounter many error messages like:mtn: warning: trust function disliked 1 signers of branch cert on revision 523c15f6f50cad3bb002f830111fc189732f693b mtn: warning: trust function disliked 1 signers of branch cert on revision 8ac13edc2919dbd5bb596ed9f203aa780bf23ff0 mtn: warning: trust function disliked 1 signers of branch cert on revision 8c4dd8ad4053baabb102a01cd3f91278142a2cd1 mtn: misuse: branch 'i2p.i2p' is empty
If you are satisfied with results, restore the backup of
monotonerc
that was created above. If you didn't create a backup as advised, re-read Setting up trust evaluation hooks.Checking out a working copy of the latest version
If you already have a branch checked out, skip to the next section.
Change into the directory where
i2p.mtn
is located. Over there issue:- $
mtn --db="i2p.mtn" co --branch="i2p.i2p"
The checkout should complete without error messages and a directory named
i2p.i2p
should appear in the current directory. Congratulations! You have successfully checked out the latest I2P sources, ready to be compiled.Updating your working copy to the latest version
If you haven't done this already, pull fresh code from the server to your local Monotone repository. To accomplish this, change into the directory where
i2p.mtn
is located and issue:- $
mtn --db="i2p.mtn" -k "" pull "mtn://127.0.0.1:8998?i2p.i2p"
Now change into your
i2p.i2p
directory, and over there issue:- $
mtn update
As long as there were no errors…Congratulations! You have successfully updated to the latest I2P sources. They should be ready to compile.
Operating a Monotone Server
Obtaining and deploying developers' transport keys
As a server operator you may want to grant push access to certain developers.
Granting push and pull access
By default the Monotone server denies all access.
To grant pull access to all clients, set the following in
$HOME/.monotone/read-permissions
:pattern "*" allow "*"
No one will not be able to push code to your server without permission being explicitly granted. To grant push access:
-
Add the name of the user's transport key to
$HOME/.monotone/write-permissions
, such as
with one key per line.zzz-transport@mail.i2p complication-transport@mail.i2p
- Import the transport key(s) into your database. The procedure for importing transport keys is the same as for importing commit keys, which is described in the section Obtaining and deploying developers' keys.
Running Monotone in server mode
A separate database should be used for your Monotone server because monotone will lock the database while it is served to others. Make a copy of your development database, then start the server with:
- $
mtn serve --bind="127.0.0.1:8998" --db="i2p.mtn" --key "myserver-transport@mail.i2p"
For your server to be accessible for others over I2P, you will need to create a server tunnel for it. Use the "Standard" tunnel type and "Bulk" profile.
Differences under Debian GNU/Linux
Debian (amongst other distributions) has integrated Monotone into their framework of daemons/services. Although Monotone servers can still be run "the ordinary way" on Debian systems, doing it the "Debian way" may be more straightforward.
Permissions are granted by editing the files
/etc/monotone/read-permissions
and/etc/monotone/write-permissions
. You'll also need to edit/etc/default/monotone
to enable monotone to start at boot or to customize the host, port, or database location.