Compare commits

...

11 Commits

39 changed files with 8395 additions and 1999 deletions

View File

@ -16,7 +16,7 @@ jobs:
sudo bash .github/download_marine.sh
- restore_cache:
keys:
- trust-graph00-{{ checksum "./service/Cargo.lock" }}-{{ checksum "./Cargo.lock" }}-{{ checksum "./keypair/Cargo.lock" }}
- trust-graph00-{{ checksum "./Cargo.lock" }}-{{ checksum "./keypair/Cargo.lock" }}
- run: |
rustup target add wasm32-wasi
cargo test --no-fail-fast --release --all-features --

130
Cargo.lock generated
View File

@ -39,9 +39,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.45"
version = "1.0.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee10e43ae4a853c0a3591d4e2ada1719e553be18199d9da9d4a83f5927c2f5c7"
checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203"
[[package]]
name = "arrayref"
@ -529,9 +529,9 @@ dependencies = [
[[package]]
name = "ed25519"
version = "1.2.0"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4620d40f6d2601794401d6dd95a5cf69b6c157852539470eeda433a99b3c0efc"
checksum = "74e1069e39f1454367eb2de793ed062fac4c35c2934b76a81d90dd9abcd28816"
dependencies = [
"serde",
"signature",
@ -656,9 +656,9 @@ checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
[[package]]
name = "fluence-app-service"
version = "0.9.0"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58d92fd37b7673513efafb0d1e0c366b8d6f297b74e9bfcda27c452f400af70a"
checksum = "01c66660de99826038c5ec4ad0f5dccf10b1c8a15924aeaa5315ab49d718bfc9"
dependencies = [
"fluence-faas",
"log",
@ -819,9 +819,9 @@ dependencies = [
[[package]]
name = "futures"
version = "0.3.17"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca"
checksum = "8cd0210d8c325c245ff06fd95a3b13689a1a276ac8cfa8e8720cb840bfb84b9e"
dependencies = [
"futures-channel",
"futures-core",
@ -834,9 +834,9 @@ dependencies = [
[[package]]
name = "futures-channel"
version = "0.3.17"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888"
checksum = "7fc8cd39e3dbf865f7340dce6a2d401d24fd37c6fe6c4f0ee0de8bfca2252d27"
dependencies = [
"futures-core",
"futures-sink",
@ -844,15 +844,15 @@ dependencies = [
[[package]]
name = "futures-core"
version = "0.3.17"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d"
checksum = "629316e42fe7c2a0b9a65b47d159ceaa5453ab14e8f0a3c5eedbb8cd55b4a445"
[[package]]
name = "futures-executor"
version = "0.3.17"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c"
checksum = "7b808bf53348a36cab739d7e04755909b9fcaaa69b7d7e588b37b6ec62704c97"
dependencies = [
"futures-core",
"futures-task",
@ -862,18 +862,16 @@ dependencies = [
[[package]]
name = "futures-io"
version = "0.3.17"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377"
checksum = "e481354db6b5c353246ccf6a728b0c5511d752c08da7260546fc0933869daa11"
[[package]]
name = "futures-macro"
version = "0.3.17"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb"
checksum = "a89f17b21645bc4ed773c69af9c9a0effd4a3f1a3876eadd453469f8854e7fdd"
dependencies = [
"autocfg",
"proc-macro-hack",
"proc-macro2",
"quote",
"syn",
@ -881,15 +879,15 @@ dependencies = [
[[package]]
name = "futures-sink"
version = "0.3.17"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11"
checksum = "996c6442437b62d21a32cd9906f9c41e7dc1e19a9579843fad948696769305af"
[[package]]
name = "futures-task"
version = "0.3.17"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99"
checksum = "dabf1872aaab32c886832f2276d2f5399887e2bd613698a02359e4ea83f8de12"
[[package]]
name = "futures-timer"
@ -899,11 +897,10 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c"
[[package]]
name = "futures-util"
version = "0.3.17"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481"
checksum = "41d22213122356472061ac0f1ab2cee28d2bac8491410fd68c2af53d1cedb83e"
dependencies = [
"autocfg",
"futures-channel",
"futures-core",
"futures-io",
@ -913,8 +910,6 @@ dependencies = [
"memchr",
"pin-project-lite",
"pin-utils",
"proc-macro-hack",
"proc-macro-nested",
"slab",
]
@ -1147,9 +1142,9 @@ dependencies = [
[[package]]
name = "itertools"
version = "0.10.1"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
dependencies = [
"either",
]
@ -1196,9 +1191,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.107"
version = "0.2.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219"
checksum = "f98a04dce437184842841303488f70d0188c5f51437d2a834dc097eafa909a01"
[[package]]
name = "libsecp256k1"
@ -1261,9 +1256,9 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
[[package]]
name = "marine-build-rs-generator"
version = "0.4.0"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c81d725ea49f554e23d3a0eb9464fcdad0bc190e42bb5a5a27699fb56557177c"
checksum = "0108407ef0528984cd5b226e6d69552b1658b205f60c83305ca33179d6e9eee1"
dependencies = [
"marine-test-macro-impl",
]
@ -1303,7 +1298,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edd97bd85072fc540763769be153a7c8ee83391e668b37ef96d6c48decec2cd5"
dependencies = [
"anyhow",
"itertools 0.10.1",
"itertools 0.10.3",
"marine-it-interfaces",
"marine-module-interface",
"nom",
@ -1362,7 +1357,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06bc36ef268bf7436916f1fa9b0c84104692a717ea5eef3c90b9f25c3407f6b7"
dependencies = [
"anyhow",
"itertools 0.10.1",
"itertools 0.10.3",
"marine-it-interfaces",
"nom",
"semver 0.11.0",
@ -1398,9 +1393,9 @@ dependencies = [
[[package]]
name = "marine-rs-sdk-test"
version = "0.4.0"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe77591c893dcfda3acd02b89ad42102a6739ead8200717e4cf325c52ba7001e"
checksum = "03e286a347527936cf97456b928bd6271e0d39fc1c6b78e99461f00e6d74f018"
dependencies = [
"fluence-app-service",
"marine-build-rs-generator",
@ -1451,9 +1446,9 @@ dependencies = [
[[package]]
name = "marine-test-macro"
version = "0.4.0"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c73a012946439eb619375cc825f008ac74489092f826fe596e465d355542cf"
checksum = "bf4d0463358f6c2459089ef8f130983dc911fd0c2aa4cb7c6b59de206f4a816e"
dependencies = [
"marine-test-macro-impl",
"proc-macro-error",
@ -1464,13 +1459,13 @@ dependencies = [
[[package]]
name = "marine-test-macro-impl"
version = "0.4.0"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa833b78d05abb43ca46c2c85cce1e664bde4b8b1926ae2bd420aba426a9b22a"
checksum = "b8f4f1ae0ba20e9241e8882e6eb1b2302daa479d67eee5badb54b1520e17c0cb"
dependencies = [
"darling 0.12.4",
"fluence-app-service",
"itertools 0.10.1",
"itertools 0.10.3",
"marine-it-parser",
"proc-macro-error",
"proc-macro2",
@ -1520,9 +1515,9 @@ dependencies = [
[[package]]
name = "memoffset"
version = "0.6.4"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
dependencies = [
"autocfg",
]
@ -1597,6 +1592,12 @@ dependencies = [
"version_check",
]
[[package]]
name = "nonempty"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9e591e719385e6ebaeb5ce5d3887f7d5676fceca6411d1925ccc95745f3d6f7"
[[package]]
name = "num-integer"
version = "0.1.44"
@ -1803,9 +1804,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkg-config"
version = "0.3.22"
version = "0.3.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f"
checksum = "d1a3ea4f0dd7f1f3e512cf97bf100819aa547f36a6eccac8dbaae839eb92363e"
[[package]]
name = "polyplets"
@ -1858,23 +1859,11 @@ dependencies = [
"version_check",
]
[[package]]
name = "proc-macro-hack"
version = "0.5.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]]
name = "proc-macro-nested"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086"
[[package]]
name = "proc-macro2"
version = "1.0.32"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
checksum = "fb37d2df5df740e582f28f8560cf425f52bb267d872fe58358eadb554909f07a"
dependencies = [
"unicode-xid",
]
@ -2219,9 +2208,9 @@ dependencies = [
[[package]]
name = "ryu"
version = "1.0.5"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
checksum = "3c9613b5a66ab9ba26415184cfc41156594925a9cf3a2057e57f31ff145f6568"
[[package]]
name = "safe-transmute"
@ -2319,9 +2308,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.69"
version = "1.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e466864e431129c7e0d3476b92f20458e5879919a0596c6472738d9fa2d342f8"
checksum = "d0ffa0837f2dfa6fb90868c2b5468cad482e175f7dad97e7421951e663f2b527"
dependencies = [
"itoa",
"ryu",
@ -2425,9 +2414,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]]
name = "syn"
version = "1.0.81"
version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966"
checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59"
dependencies = [
"proc-macro2",
"quote",
@ -2531,6 +2520,7 @@ dependencies = [
"fluence-fork-libp2p-core",
"fluence-keypair",
"log",
"nonempty",
"rand 0.7.3",
"ref-cast",
"serde",
@ -2543,7 +2533,7 @@ dependencies = [
[[package]]
name = "trust-graph-wasm"
version = "0.2.1"
version = "0.3.0"
dependencies = [
"anyhow",
"bincode",
@ -2848,7 +2838,7 @@ dependencies = [
"fluence-it-types",
"it-lilo",
"it-to-bytes",
"itertools 0.10.1",
"itertools 0.10.3",
"log",
"nom",
"safe-transmute",

View File

@ -23,6 +23,7 @@ serde_with = "1.6.0"
thiserror = "1.0.23"
sha2 = "0.9.5"
rand = "0.7.0"
nonempty = "0.7.0"
[workspace]
members = [

View File

@ -1,13 +1,37 @@
### Trust Graph
# Trust Graph
The network-wide peer relationship layer is used to manage connectivity and permissions. Peers keep the distributed graph of relationships, basically a Web of Trust. That graph is used is used to prioritize connections from known peers and avoid Sybil attacks. Also, TrustGraph may be used at the application level in various ways such as prioritization of service execution on authorized peers or a tighter connection of a single companys peers.
Trust Graph is network-wide peer relationship layer. It's designed to be used to prioritize resources and control permissions in open networks. Being a decentralized graph of relationships, basically a Web of Trust, Trust Graph is distributed among all network peers.
### Project structure
Specifically, Trust Graph is used is used to prioritize connections from known peers to counteract Sybil attacks while still keeping network open by reserving resources for unknown peers.
`/.` is the main project with all trust graph logic and in-memory storage as a default
At the same time, Trust Graph can be used at the application level in various ways such as prioritization of service execution on authorized peers or to define an interconnected subnetwork among peers of a single protocol.
`keypair` directory is an abstracted cryptographical layer (key pairs, public keys, signatures, etc.)
## How to Use it in TypeScript
`service` is a package that provides `marine` API and could be compiled to a Wasm file. It is uses `SQLite` as storage.
See [example](./example):
- How to call [`trust-graph`](./example/index.ts) functions in TS/JS
- Step-by-step description [`README`](./example/README.md)
`example` is a `js` script that shows how to issue, sign trusts/revokes, get certificates
## API
Low-level API is defined in the [trust-graph-api.aqua](./aqua/trust-graph-api.aqua) module.
## Directory structure
- [`src`](./src) is the main project with all trust graph logic
- [`keypair`](./keypair) directory is an abstracted cryptographical layer (key pairs, public keys, signatures, etc.)
- [`service`](./service) is a package that provides `marine` API and could be compiled to a Wasm file. It is uses `SQLite` as storage.
- [`example`](./example) is a `js` script that shows how to issue, sign trusts/revocations, export certificates and distinguish Fluence nodes
- [`builtin-package`](./builtin-package) contains blueprint, configs and scripts for generation builtin package locally or via CI
- [`admin`](./admin) is a `js` script used to generate `builtin-package/on_start.json` which contains certificates for Fluence Labs nodes
## Learn Aqua
* [Aqua Book](https://fluence.dev/aqua-book/)
* [Aqua Playground](https://github.com/fluencelabs/aqua-playground)
* [Aqua repo](https://github.com/fluencelabs/aqua)

View File

@ -1,6 +1,12 @@
# How to generate export certificates
1. Go to `local-network`
2. Run `docker compose up -d` to start Fluence node
3. Go back to `../admin`
4. Put `root_secret_key.ed25519` and `issuer_secret_key.ed25519` to folder
5. Run `npm run start`
1. Go to `local-network` if you want to use local node
- Run `docker compose up -d` to start Fluence node
- Go back to `../admin`
2. Put `root_secret_key.ed25519` and `issuer_secret_key.ed25519` to folder
3. Run `npm i`
4. Run `npm run start {env}` where `{env}` should be `testnet`/`krasnodar`/`stage` or `local`
`root_secret_key.ed25519` and `issuer_secret_key.ed25519` are secret and owned by Fluence Labs team. Root key is for
all Fluence Labs relations. Trust from issuer key to any peer id means that this peer is official Fluence Labs peer.
isFluencePeer method from [trust-graph-api.aqua](./aqua/trust-graph-api.aqua) module checks these relations. You can build your own
structure of peers similarly.

126
admin/package-lock.json generated
View File

@ -9,9 +9,9 @@
"version": "1.0.0",
"license": "MIT",
"dependencies": {
"@fluencelabs/aqua": "0.4.1-240",
"@fluencelabs/aqua-lib": "0.2.0",
"@fluencelabs/fluence": "0.14.3",
"@fluencelabs/aqua": "0.5.0-246",
"@fluencelabs/aqua-lib": "0.2.1",
"@fluencelabs/fluence": "0.15.0",
"@fluencelabs/fluence-network-environment": "^1.0.10",
"@fluencelabs/trust-graph": "file:../aqua",
"bs58": "^4.0.1"
@ -79,11 +79,11 @@
"license": "MIT"
},
"node_modules/@fluencelabs/aqua": {
"version": "0.4.1-240",
"resolved": "https://registry.npmjs.org/@fluencelabs/aqua/-/aqua-0.4.1-240.tgz",
"integrity": "sha512-UaeljcyIuAXWL8CpF2p+jnD0YSVyp3lZYaOfTZoqL5XeFdhf0D8C6VhioUwyT0kU0JOziaPe3m9JxzL3atfpfg==",
"version": "0.5.0-246",
"resolved": "https://registry.npmjs.org/@fluencelabs/aqua/-/aqua-0.5.0-246.tgz",
"integrity": "sha512-ab2i7eiPsTaCbo97VGcrshQ3EMJMNMr+1qasf7ryShXMGWu1S9wPB7i7lRToGGOgACnO2D5ScuIAMVYe4D9BMQ==",
"dependencies": {
"@fluencelabs/fluence": "0.12.1"
"@fluencelabs/fluence": "0.15.0"
},
"bin": {
"aqua": "index.js",
@ -91,56 +91,25 @@
}
},
"node_modules/@fluencelabs/aqua-lib": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@fluencelabs/aqua-lib/-/aqua-lib-0.2.0.tgz",
"integrity": "sha512-5eJYQQM/6yzNsrBnATYkhpzK5AA0XBSv19eNOkKoyKZpVbh0WK2jjegzWQY2+X+fSk5fh6fcqy7G9xh2a7Lcbg=="
},
"node_modules/@fluencelabs/aqua/node_modules/@fluencelabs/avm": {
"version": "0.14.4",
"resolved": "https://registry.npmjs.org/@fluencelabs/avm/-/avm-0.14.4.tgz",
"integrity": "sha512-XyR+1H5k0CAc+mDHOkl81viX8XeW1Yqbw793xbsfUfju5bUb/hqk+gHv3q8lAFdbrCG5P45gdOT08a5RNODZaQ==",
"dependencies": {
"base64-js": "1.5.1"
}
},
"node_modules/@fluencelabs/aqua/node_modules/@fluencelabs/fluence": {
"version": "0.12.1",
"resolved": "https://registry.npmjs.org/@fluencelabs/fluence/-/fluence-0.12.1.tgz",
"integrity": "sha512-JrMKMHjYILAHQsLLd5H0fLt/UMZv+/PQYxJYe6h9HFyJlZrN1bUV+EcZnUw1u3DZE5k/RXBx0udfmkahggwrqA==",
"dependencies": {
"@chainsafe/libp2p-noise": "4.0.0",
"@fluencelabs/avm": "0.14.4",
"async": "3.2.0",
"base64-js": "1.5.1",
"bs58": "4.0.1",
"cids": "0.8.1",
"it-length-prefixed": "3.0.1",
"it-pipe": "1.1.0",
"libp2p": "0.32.3",
"libp2p-crypto": "0.19.7",
"libp2p-mplex": "0.10.4",
"libp2p-websockets": "0.16.1",
"loglevel": "1.7.0",
"multiaddr": "10.0.0",
"peer-id": "0.15.3",
"uuid": "8.3.0"
}
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/@fluencelabs/aqua-lib/-/aqua-lib-0.2.1.tgz",
"integrity": "sha512-uLP9mbgFHR1Q1FYhehasNxNBlTclBsjNI9MvIPF8oXtVJtnvPi+R4rGGTOHtRJukunxhpAV/svWQU9a2BRyDmQ=="
},
"node_modules/@fluencelabs/avm": {
"version": "0.16.7",
"resolved": "https://registry.npmjs.org/@fluencelabs/avm/-/avm-0.16.7.tgz",
"integrity": "sha512-tSbEBRdHTz6PCxLuzEWe3ayZQeDiuJu/Dw0qJmdpYe6eJf0jSwUnAnRaEOv2d0ILnzT1b4us9tCKOhac41YlLg==",
"version": "0.16.0-restriction-operator.9",
"resolved": "https://registry.npmjs.org/@fluencelabs/avm/-/avm-0.16.0-restriction-operator.9.tgz",
"integrity": "sha512-34vJqo8TIho5H2+WhEAJOa6WxAPiS+c7Z3WKmRZVi+GAsZN3Hv2NiuiCFNFBmPRoD+juzHe4Dmv5cF7HZc6O6w==",
"dependencies": {
"base64-js": "1.5.1"
}
},
"node_modules/@fluencelabs/fluence": {
"version": "0.14.3",
"resolved": "https://registry.npmjs.org/@fluencelabs/fluence/-/fluence-0.14.3.tgz",
"integrity": "sha512-JlF/B9Wtz0VMBJIfA+hZYZt44nX5AIJzgkhfbT1fKfwzb1CvS6IYaaH6PE8vLcBm556sJic94yYL++FpQrJUmQ==",
"version": "0.15.0",
"resolved": "https://registry.npmjs.org/@fluencelabs/fluence/-/fluence-0.15.0.tgz",
"integrity": "sha512-rZwRpS7gaHdTbNecs/W9fokifh3skzZLHiyezSfZNY8jYnjub1HerFOrN6G8dLe2xIOeNuZWirdQ8V5LSZGOHg==",
"dependencies": {
"@chainsafe/libp2p-noise": "4.0.0",
"@fluencelabs/avm": "0.16.7",
"@fluencelabs/avm": "0.16.0-restriction-operator.9",
"async": "3.2.0",
"base64-js": "1.5.1",
"bs58": "4.0.1",
@ -2482,66 +2451,33 @@
}
},
"@fluencelabs/aqua": {
"version": "0.4.1-240",
"resolved": "https://registry.npmjs.org/@fluencelabs/aqua/-/aqua-0.4.1-240.tgz",
"integrity": "sha512-UaeljcyIuAXWL8CpF2p+jnD0YSVyp3lZYaOfTZoqL5XeFdhf0D8C6VhioUwyT0kU0JOziaPe3m9JxzL3atfpfg==",
"version": "0.5.0-246",
"resolved": "https://registry.npmjs.org/@fluencelabs/aqua/-/aqua-0.5.0-246.tgz",
"integrity": "sha512-ab2i7eiPsTaCbo97VGcrshQ3EMJMNMr+1qasf7ryShXMGWu1S9wPB7i7lRToGGOgACnO2D5ScuIAMVYe4D9BMQ==",
"requires": {
"@fluencelabs/fluence": "0.12.1"
},
"dependencies": {
"@fluencelabs/avm": {
"version": "0.14.4",
"resolved": "https://registry.npmjs.org/@fluencelabs/avm/-/avm-0.14.4.tgz",
"integrity": "sha512-XyR+1H5k0CAc+mDHOkl81viX8XeW1Yqbw793xbsfUfju5bUb/hqk+gHv3q8lAFdbrCG5P45gdOT08a5RNODZaQ==",
"requires": {
"base64-js": "1.5.1"
}
},
"@fluencelabs/fluence": {
"version": "0.12.1",
"resolved": "https://registry.npmjs.org/@fluencelabs/fluence/-/fluence-0.12.1.tgz",
"integrity": "sha512-JrMKMHjYILAHQsLLd5H0fLt/UMZv+/PQYxJYe6h9HFyJlZrN1bUV+EcZnUw1u3DZE5k/RXBx0udfmkahggwrqA==",
"requires": {
"@chainsafe/libp2p-noise": "4.0.0",
"@fluencelabs/avm": "0.14.4",
"async": "3.2.0",
"base64-js": "1.5.1",
"bs58": "4.0.1",
"cids": "0.8.1",
"it-length-prefixed": "3.0.1",
"it-pipe": "1.1.0",
"libp2p": "0.32.3",
"libp2p-crypto": "0.19.7",
"libp2p-mplex": "0.10.4",
"libp2p-websockets": "0.16.1",
"loglevel": "1.7.0",
"multiaddr": "10.0.0",
"peer-id": "0.15.3",
"uuid": "8.3.0"
}
}
"@fluencelabs/fluence": "0.15.0"
}
},
"@fluencelabs/aqua-lib": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@fluencelabs/aqua-lib/-/aqua-lib-0.2.0.tgz",
"integrity": "sha512-5eJYQQM/6yzNsrBnATYkhpzK5AA0XBSv19eNOkKoyKZpVbh0WK2jjegzWQY2+X+fSk5fh6fcqy7G9xh2a7Lcbg=="
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/@fluencelabs/aqua-lib/-/aqua-lib-0.2.1.tgz",
"integrity": "sha512-uLP9mbgFHR1Q1FYhehasNxNBlTclBsjNI9MvIPF8oXtVJtnvPi+R4rGGTOHtRJukunxhpAV/svWQU9a2BRyDmQ=="
},
"@fluencelabs/avm": {
"version": "0.16.7",
"resolved": "https://registry.npmjs.org/@fluencelabs/avm/-/avm-0.16.7.tgz",
"integrity": "sha512-tSbEBRdHTz6PCxLuzEWe3ayZQeDiuJu/Dw0qJmdpYe6eJf0jSwUnAnRaEOv2d0ILnzT1b4us9tCKOhac41YlLg==",
"version": "0.16.0-restriction-operator.9",
"resolved": "https://registry.npmjs.org/@fluencelabs/avm/-/avm-0.16.0-restriction-operator.9.tgz",
"integrity": "sha512-34vJqo8TIho5H2+WhEAJOa6WxAPiS+c7Z3WKmRZVi+GAsZN3Hv2NiuiCFNFBmPRoD+juzHe4Dmv5cF7HZc6O6w==",
"requires": {
"base64-js": "1.5.1"
}
},
"@fluencelabs/fluence": {
"version": "0.14.3",
"resolved": "https://registry.npmjs.org/@fluencelabs/fluence/-/fluence-0.14.3.tgz",
"integrity": "sha512-JlF/B9Wtz0VMBJIfA+hZYZt44nX5AIJzgkhfbT1fKfwzb1CvS6IYaaH6PE8vLcBm556sJic94yYL++FpQrJUmQ==",
"version": "0.15.0",
"resolved": "https://registry.npmjs.org/@fluencelabs/fluence/-/fluence-0.15.0.tgz",
"integrity": "sha512-rZwRpS7gaHdTbNecs/W9fokifh3skzZLHiyezSfZNY8jYnjub1HerFOrN6G8dLe2xIOeNuZWirdQ8V5LSZGOHg==",
"requires": {
"@chainsafe/libp2p-noise": "4.0.0",
"@fluencelabs/avm": "0.16.7",
"@fluencelabs/avm": "0.16.0-restriction-operator.9",
"async": "3.2.0",
"base64-js": "1.5.1",
"bs58": "4.0.1",

View File

@ -13,9 +13,9 @@
"author": "Fluence Labs",
"license": "MIT",
"dependencies": {
"@fluencelabs/aqua": "0.4.1-240",
"@fluencelabs/aqua-lib": "0.2.0",
"@fluencelabs/fluence": "0.14.3",
"@fluencelabs/aqua": "0.5.0-246",
"@fluencelabs/aqua-lib": "0.2.1",
"@fluencelabs/fluence": "0.15.0",
"@fluencelabs/fluence-network-environment": "^1.0.10",
"@fluencelabs/trust-graph": "file:../aqua",
"bs58": "^4.0.1"

78
aqua/export.aqua Normal file
View File

@ -0,0 +1,78 @@
module TrustGraph declares *
import "trust-graph.aqua"
import "trust-graph-api.aqua"
func add_root_trust_wrapped(node: string, max_chain_len: u32, expires_at_sec: u64) -> ?string:
on node:
error <- add_root_trust(max_chain_len, expires_at_sec)
<- error
func add_root_wrapped(node: string, peer_id: string, max_chain_len: u32) -> AddRootResult:
on node:
result <- add_root(peer_id, max_chain_len)
<- result
func get_weight_wrapped(node: string, peer_id: string) -> WeightResult:
on node:
result <- get_weight(peer_id)
<- result
func issue_trust_wrapped(node: string, issued_for_peer_id: string, expires_at_sec: u64) -> ?Trust, ?string:
on node:
result, error <- issue_trust(issued_for_peer_id, expires_at_sec)
<- result, error
func add_trust_wrapped(node: string, issued_for_peer_id: string, expires_at_sec: u64) -> ?string:
on node:
error <- add_trust(issued_for_peer_id, expires_at_sec)
<- error
func import_trust_wrapped(node: string, trust: Trust) -> ?string:
on node:
error <- import_trust(trust)
<- error
func verify_trust_wrapped(node: string, trust: Trust, issuer_peer_id: string) -> VerifyTrustResult:
on node:
result <- verify_trust(trust, issuer_peer_id)
<- result
func issue_revocation_wrapped(node: string, revoked_peer_id: string) -> ?Revocation, ?string:
on node:
result, error <- issue_revocation(revoked_peer_id)
<- result, error
func revoke_wrapped(node: string, revoked_peer_id: string) -> ?string:
on node:
error <- revoke(revoked_peer_id)
<- error
func import_revocation_wrapped(node: string, revocation: Revocation) -> ?string:
on node:
error <- import_revocation(revocation)
<- error
func get_host_certs_from_wrapped(node: string, issuer: string) -> AllCertsResult:
on node:
result <- get_host_certs_from(issuer)
<- result
func get_all_certs_wrapped(node: string, issued_for: string) -> AllCertsResult:
on node:
result <- get_all_certs(issued_for)
<- result
func get_host_certs_wrapped(node: string) -> AllCertsResult:
on node:
result <- get_host_certs()
<- result
func insert_cert_wrapped(node: string, certificate: Certificate) -> InsertResult:
on node:
result <- insert_cert(certificate)
<- result
func isFluencePeer_wrapped(node: string) -> ?bool, ?string:
on node:
result, error <- isFluencePeer()
<- result, error

3070
aqua/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,12 @@
{
"name": "@fluencelabs/trust-graph",
"version": "0.1.12",
"version": "0.2.0",
"description": "Aqua Trust Graph API library",
"files": [
"*.aqua"
],
"dependencies": {
"@fluencelabs/aqua-lib": "0.2.0"
"@fluencelabs/aqua-lib": "^0.3.1"
},
"scripts": {
"generate-aqua": "../service/build.sh",
@ -31,6 +31,6 @@
},
"homepage": "https://github.com/fluencelabs/trust-graph#readme",
"devDependencies": {
"@fluencelabs/aqua": "0.4.1-240"
"@fluencelabs/aqua": "^0.5.2-257"
}
}

View File

@ -1,101 +1,159 @@
import "trust-graph.aqua"
import "@fluencelabs/aqua-lib/builtin.aqua"
func get_trust_bytes(node: string, issued_for_peer_id: string, expires_at_sec: u64, issued_at_sec: u64) -> GetTrustBytesResult:
on node:
result <- TrustGraph.get_trust_bytes(issued_for_peer_id, expires_at_sec, issued_at_sec)
func add_root(peer_id: string, max_chain_len: u32) -> AddRootResult:
weight_factor <- TrustGraph.get_weight_factor(max_chain_len)
result <- TrustGraph.add_root(peer_id, weight_factor)
<- result
func issue_trust(node: string, issued_for_peer_id: string, expires_at_sec: u64, issued_at_sec: u64, trust_bytes: []u8) -> IssueTrustResult:
on node:
result <- TrustGraph.issue_trust(issued_for_peer_id, expires_at_sec, issued_at_sec, trust_bytes)
func get_weight(peer_id: string) -> WeightResult:
timestamp_sec <- Peer.timestamp_sec()
result <- TrustGraph.get_weight(peer_id, timestamp_sec)
<- result
func verify_trust(node: string, trust: Trust, issuer_peer_id: string) -> VerifyTrustResult:
on node:
func issue_trust(issued_for_peer_id: string, expires_at_sec: u64) -> ?Trust, ?string:
issued_at_sec <- Peer.timestamp_sec()
bytes <- TrustGraph.get_trust_bytes(issued_for_peer_id, expires_at_sec, issued_at_sec)
result: ?Trust
error: ?string
if bytes.success:
on %init_peer_id% via HOST_PEER_ID:
signature <- Sig.sign(bytes.result)
issue_result <- TrustGraph.issue_trust(issued_for_peer_id, expires_at_sec, issued_at_sec, signature)
if issue_result.success:
result <<- issue_result.trust
else:
error <<- issue_result.error
else:
error <<- bytes.error
<- result, error
func add_trust(issued_for_peer_id: string, expires_at_sec: u64) -> ?string:
trust, issue_error <- issue_trust(issued_for_peer_id, expires_at_sec)
error: ?string
if trust == nil:
error <<- issue_error!
else:
timestamp_sec <- Peer.timestamp_sec()
result <- TrustGraph.verify_trust(trust, issuer_peer_id, timestamp_sec)
add_result <- TrustGraph.add_trust(trust!, %init_peer_id%, timestamp_sec)
if add_result.success != true:
error <<- add_result.error
<- error
func add_root_trust(max_chain_len: u32, expires_at_sec: u64) -> ?string:
add_root_result <- add_root(%init_peer_id%, max_chain_len)
error: *?string
if add_root_result.success:
error <- add_trust(%init_peer_id%, expires_at_sec)
else:
-- converting string to ?string
tmp: *string
tmp <<- add_root_result.error
error <<- tmp
<- error!
func import_trust(trust: Trust) -> ?string:
error: ?string
timestamp_sec <- Peer.timestamp_sec()
add_result <- TrustGraph.add_trust(trust, %init_peer_id%, timestamp_sec)
if add_result.success != true:
error <<- add_result.error
<- error
func verify_trust(trust: Trust, issuer_peer_id: string) -> VerifyTrustResult:
timestamp_sec <- Peer.timestamp_sec()
result <- TrustGraph.verify_trust(trust, issuer_peer_id, timestamp_sec)
<- result
func add_trust(node: string, trust: Trust, issuer_peer_id: string) -> AddTrustResult:
on node:
func issue_revocation(revoked_peer_id: string) -> ?Revocation, ?string:
issued_at_sec <- Peer.timestamp_sec()
bytes <- TrustGraph.get_revocation_bytes(revoked_peer_id, issued_at_sec)
result: ?Revocation
error: ?string
if bytes.success:
on %init_peer_id% via HOST_PEER_ID:
signature <- Sig.sign(bytes.result)
issue_result <- TrustGraph.issue_revocation(revoked_peer_id, %init_peer_id%, issued_at_sec, signature)
if issue_result.success != true:
result <<- issue_result.revocation
else:
error <<- issue_result.error
else:
error <<- bytes.error
<- result, error
func revoke(revoked_peer_id: string) -> ?string:
revocation, issue_error <- issue_revocation(revoked_peer_id)
error: ?string
if revocation == nil:
error <<- issue_error!
else:
timestamp_sec <- Peer.timestamp_sec()
result <- TrustGraph.add_trust(trust, issuer_peer_id, timestamp_sec)
add_result <- TrustGraph.revoke(revocation!, timestamp_sec)
if add_result.success != true:
error <<- add_result.error
<- error
func import_revocation(revocation: Revocation) -> ?string:
error: ?string
timestamp_sec <- Peer.timestamp_sec()
add_result <- TrustGraph.revoke(revocation, timestamp_sec)
if add_result.success != true:
error <<- add_result.error
<- error
func get_host_certs_from(issuer: string) -> AllCertsResult:
timestamp_sec <- Peer.timestamp_sec()
result <- TrustGraph.get_host_certs_from(issuer, timestamp_sec)
<- result
func add_root(node: string, peer_id: string, weight_factor: u32) -> AddRootResult:
on node:
result <- TrustGraph.add_root(peer_id, weight_factor)
func get_all_certs(issued_for: string) -> AllCertsResult:
timestamp_sec <- Peer.timestamp_sec()
result <- TrustGraph.get_all_certs(issued_for, timestamp_sec)
<- result
func get_weight(node: string, peer_id: string) -> WeightResult:
on node:
timestamp_sec <- Peer.timestamp_sec()
result <- TrustGraph.get_weight(peer_id, timestamp_sec)
func get_host_certs() -> AllCertsResult:
timestamp_sec <- Peer.timestamp_sec()
result <- TrustGraph.get_host_certs(timestamp_sec)
<- result
func get_all_certs(node: string, issued_for: string) -> AllCertsResult:
on node:
timestamp_sec <- Peer.timestamp_sec()
result <- TrustGraph.get_all_certs(issued_for, timestamp_sec)
<- result
func get_host_certs(node: string, issued_for: string) -> AllCertsResult:
on node:
timestamp_sec <- Peer.timestamp_sec()
result <- TrustGraph.get_host_certs(timestamp_sec)
<- result
func get_host_certs_from(node: string, issuer: string) -> AllCertsResult:
on node:
timestamp_sec <- Peer.timestamp_sec()
result <- TrustGraph.get_host_certs_from(issuer, timestamp_sec)
<- result
func insert_cert(node: string, certificate: Certificate) -> InsertResult:
on node:
timestamp_sec <- Peer.timestamp_sec()
result <- TrustGraph.insert_cert(certificate, timestamp_sec)
<- result
func get_revoke_bytes(node: string, revoked_peer_id: string, revoked_at: u64) -> GetRevokeBytesResult:
on node:
result <- TrustGraph.get_revoke_bytes(revoked_peer_id, revoked_at)
<- result
func issue_revocation(node: string, revoked_peer_id: string, revoked_by_peer_id: string, revoked_at_sec: u64, signature_bytes: []u8) -> IssueRevocationResult:
on node:
result <- TrustGraph.issue_revocation(revoked_peer_id, revoked_by_peer_id, revoked_at_sec, signature_bytes)
<- result
func revoke(node: string, revoke: Revoke) -> RevokeResult:
on node:
timestamp_sec <- Peer.timestamp_sec()
result <- TrustGraph.revoke(revoke, timestamp_sec)
func insert_cert(certificate: Certificate) -> InsertResult:
timestamp_sec <- Peer.timestamp_sec()
result <- TrustGraph.insert_cert(certificate, timestamp_sec)
<- result
-- helpers for isFluencePeer
service TrustOp("op"):
array_length(a: []Trust) -> u64
array_length(a: []Trust) -> u32
service BoolOp("op"):
array_length(a: []bool) -> u64
array_length(a: []bool) -> u32
-- https://github.com/fluencelabs/trust-graph/issues/26
func isFluencePeer() -> bool:
certs_result <- get_host_certs_from(HOST_PEER_ID, "12D3KooWM45u7AQxsb4MuQJNYT3NWHHMLU7JTbBV66RTfF3KSzdR")
resultBox: *bool
-- returns `true` if current relay is identified as official Fluence Labs peer
-- returns `false` otherwise
func isFluencePeer() -> ?bool, ?string:
certs_result <- get_host_certs_from("12D3KooWM45u7AQxsb4MuQJNYT3NWHHMLU7JTbBV66RTfF3KSzdR")
result: ?bool
error: ?string
if certs_result.success:
for cert <- certs_result.certificates:
len <- TrustOp.array_length(cert.chain)
if len == 3:
if cert.chain!0.issued_for == "12D3KooWNbZKaPWRZ8wgjGvrxdJFz9Fq5uVwkR6ERV1f74HhPdyB":
if cert.chain!1.issued_for == "12D3KooWM45u7AQxsb4MuQJNYT3NWHHMLU7JTbBV66RTfF3KSzdR":
resultBox <<- true
result_len <- BoolOp.array_length(resultBox)
result: *bool
if result_len == 0:
result <<- false
result <<- true
if result == nil:
result <<- false
else:
result <<- true
<- result!
error <<- certs_result.error
<- result, error

View File

@ -38,7 +38,7 @@ data InsertResult:
success: bool
error: string
data Revoke:
data Revocation:
revoked_peer_id: string
revoked_at: u64
signature: string
@ -48,7 +48,7 @@ data Revoke:
data IssueRevocationResult:
success: bool
error: string
revoke: Revoke
revocation: Revocation
data IssueTrustResult:
success: bool
@ -75,7 +75,7 @@ service TrustGraph("trust-graph"):
get_all_certs(issued_for: string, timestamp_sec: u64) -> AllCertsResult
get_host_certs(timestamp_sec: u64) -> AllCertsResult
get_host_certs_from(issuer: string, timestamp_sec: u64) -> AllCertsResult
get_revoke_bytes(revoked_peer_id: string, revoked_at: u64) -> GetRevokeBytesResult
get_revocation_bytes(revoked_peer_id: string, revoked_at: u64) -> GetRevokeBytesResult
get_trust_bytes(issued_for_peer_id: string, expires_at_sec: u64, issued_at_sec: u64) -> GetTrustBytesResult
get_weight(peer_id: string, timestamp_sec: u64) -> WeightResult
get_weight_factor(max_chain_len: u32) -> u32
@ -83,5 +83,5 @@ service TrustGraph("trust-graph"):
insert_cert_raw(certificate: string, timestamp_sec: u64) -> InsertResult
issue_revocation(revoked_peer_id: string, revoked_by_peer_id: string, revoked_at_sec: u64, signature_bytes: []u8) -> IssueRevocationResult
issue_trust(issued_for_peer_id: string, expires_at_sec: u64, issued_at_sec: u64, trust_bytes: []u8) -> IssueTrustResult
revoke(revoke: Revoke, timestamp_sec: u64) -> RevokeResult
revoke(revoke: Revocation, timestamp_sec: u64) -> RevokeResult
verify_trust(trust: Trust, issuer_peer_id: string, timestamp_sec: u64) -> VerifyTrustResult

View File

@ -2,4 +2,22 @@
1. Go to `local-network`
2. Run `docker compose up -d` to start Fluence node
3. Go back to `../example`
4. Run `npm run start`
4. Run `npm i`
5. Run `npm run start`
## How to use
1. Add the following to your dependencies
- `@fluencelabs/trust-graph`
- `@fluencelabs/aqua`
- `@fluencelabs/aqua-lib`
- `@fluencelabs/fluence`
- `@fluencelabs/fluence-network-environment`
2. Import dependencies
```typescript
import * as tg from "./generated/export";
import { Fluence, KeyPair } from "@fluencelabs/fluence";
import { krasnodar, Node } from "@fluencelabs/fluence-network-environment";
```
3. Add root and issue self-signed root trust.
4. For now, you can sign trusts/revocations only on js side with KeyPair.

View File

@ -0,0 +1,24 @@
import "@fluencelabs/trust-graph/trust-graph-api.aqua"
import "@fluencelabs/trust-graph/trust-graph.aqua"
import "@fluencelabs/aqua-lib/builtin.aqua"
export trusted_computation
service CertOp("op"):
array_length(a: []Certificate) -> u32
service TrustedComputation("op"):
identity(s: u64) -> u64
func trusted_computation(node: string) -> ?u64:
result: ?u64
on node:
certs_result <- get_host_certs_from(%init_peer_id%)
if certs_result.success:
len <- CertOp.array_length(certs_result.certificates)
if len != 0:
result <- TrustedComputation.identity(5)
<- result

View File

@ -1,10 +1,13 @@
import get_trust_bytes, issue_trust, verify_trust, add_trust, add_root, get_weight, get_all_certs, insert_cert, get_revoke_bytes, issue_revocation, revoke, isFluencePeer from "../../aqua/trust-graph-api.aqua"
import "@fluencelabs/trust-graph/export.aqua"
export get_trust_bytes, issue_trust, verify_trust, add_trust, add_root, get_weight, get_all_certs, insert_cert, get_revoke_bytes, issue_revocation, revoke, isFluencePeer
export issue_trust_wrapped as issue_trust, verify_trust_wrapped as verify_trust, add_trust_wrapped as add_trust, import_trust_wrapped as import_trust
export add_root_trust_wrapped as add_root_trust, add_root_wrapped as add_root, get_weight_wrapped as get_weight, get_all_certs_wrapped as get_all_certs, insert_cert_wrapped as insert_cert
export issue_revocation_wrapped as issue_revocation, revoke_wrapped as revoke, isFluencePeer_wrapped as isFluencePeer
import "@fluencelabs/aqua-lib/builtin.aqua"
import Peer from "@fluencelabs/aqua-lib/builtin.aqua"
func timestamp_sec(node: string) -> u64:
on node:
func timestamp_sec() -> u64:
on HOST_PEER_ID:
result <- Peer.timestamp_sec()
<- result

View File

@ -14,21 +14,10 @@
* limitations under the License.
*/
import {
get_trust_bytes,
issue_trust,
verify_trust,
add_trust,
add_root,
get_weight,
timestamp_sec,
get_all_certs,
get_revoke_bytes,
issue_revocation,
revoke
} from "./generated/export";
import { Fluence, KeyPair } from "@fluencelabs/fluence";
import { Node } from "@fluencelabs/fluence-network-environment";
import {trusted_computation} from "./generated/computation";
import * as tg from "./generated/export";
import {Fluence, FluencePeer, KeyPair} from "@fluencelabs/fluence";
import {krasnodar, Node, testNet, stage} from "@fluencelabs/fluence-network-environment";
import assert from "assert";
const bs58 = require('bs58');
@ -43,31 +32,65 @@ let local: Node[] = [
multiaddr:
"/ip4/127.0.0.1/tcp/9991/ws/p2p/12D3KooWRABanQHUn28dxavN9ZS1zZghqoZVAYtFpoN7FdtoGTFv",
},
{
peerId: "12D3KooWFpQ7LHxcC9FEBUh3k4nSCC12jBhijJv3gJbi7wsNYzJ5",
multiaddr:
"/ip4/127.0.0.1/tcp/9992/ws/p2p/12D3KooWFpQ7LHxcC9FEBUh3k4nSCC12jBhijJv3gJbi7wsNYzJ5",
},
];
async function add_trust_helper(node: string, issuer_kp: KeyPair, issuer_peer_id: string, issued_for_peer_id: string, expires_at_sec: number, issued_at_sec: number) {
let trust_metadata = await get_trust_bytes(node, issued_for_peer_id, expires_at_sec, issued_at_sec);
const signed_metadata = await issuer_kp.Libp2pPeerId.privKey.sign(Uint8Array.from(trust_metadata.result));
let trust = await issue_trust(node, issued_for_peer_id, expires_at_sec, issued_at_sec, Array.from(signed_metadata));
console.log("Issued trust %s", trust.trust);
let result = await verify_trust(node, trust.trust, issuer_peer_id);
console.log("Verify trust result: %s", result);
let result_add = await add_trust(node, trust.trust, issuer_peer_id);
console.log("Add trust result: %s", result_add);
async function add_roots() {
let current_time = await tg.timestamp_sec();
let far_future = current_time + 9999999;
for (var node of local) {
let error = await tg.add_root_trust(node.peerId, 2, far_future);
console.log("Added root trust for %s", node.peerId)
assert(error == null);
}
}
async function revoke_helper(node: string, issuer_kp: KeyPair, revoked_by_peer_id: string, revoked_peer_id: string, revoked_at_sec: number) {
let trust_metadata = await get_revoke_bytes(node, revoked_peer_id, revoked_at_sec);
const signed_metadata = await issuer_kp.Libp2pPeerId.privKey.sign(Uint8Array.from(trust_metadata.result));
async function is_fluence_peer(node: string) {
let [result, error] = await tg.isFluencePeer(node);
let revocation = await issue_revocation(node, revoked_peer_id, revoked_by_peer_id, revoked_at_sec, Array.from(signed_metadata));
console.log("Issued revocation %s", revocation.revoke);
console.log("%s %s", result, error);
if (error !== null) {
console.error("Something went wrong: %s", error);
} else {
assert(result !== null);
if (result) {
console.log("Current relay %s identified as Fluence Labs' peer", Fluence.getStatus().relayPeerId)
} else {
console.log("Current relay %s is not Fluence Labs' peer", Fluence.getStatus().relayPeerId)
}
}
}
let result_add = await revoke(node, revocation.revoke);
console.log("Revoke result: %s", result_add);
async function add_new_trust_checked(node: string, issued_for_peer_id: string, expires_at_sec: number) {
let error = await tg.add_trust(node, issued_for_peer_id, expires_at_sec);
if (error !== null) {
console.error("%s", error);
} else {
console.log("Trust to node %s successfully added", node)
}
}
async function revoke_checked(node: string, revoked_peer_id: string) {
let error = await tg.revoke(node, revoked_peer_id);
if (error !== null) {
console.error("%s", error);
} else {
console.log("Trust to node %s revoked", node)
}
}
async function exec_trusted_computation(node: string) {
let result = await trusted_computation(node)
if (result !== null) {
console.log("Trusted computation on node %s successful, result is %s", node, result)
} else {
console.log("Trusted computation on node %s failed", node)
}
}
async function main() {
@ -75,45 +98,37 @@ async function main() {
// key from local-network/builtins_secret_key.ed25519 to connect as builtins owner
let sk = bs58.decode("5FwE32bDcphFzuMca7Y2qW1gdR64fTBYoRNvD4MLE1hecDGhCMQGKn8aseMr5wRo4Xo2CRFdrEAawUNLYkgQD78K").slice(0, 32); // first 32 bytes - secret key, second - public key
let builtins_keypair = await KeyPair.fromEd25519SK(sk);
await Fluence.start({ connectTo: local[0], KeyPair: builtins_keypair});
console.log(
"📗 created a fluence peer %s with relay %s",
Fluence.getStatus().peerId,
Fluence.getStatus().relayPeerId
);
const issued_timestamp_sec = await timestamp_sec(local[0].peerId);
const expires_at_sec = issued_timestamp_sec + 999999999;
const issuer_kp = await KeyPair.fromEd25519SK(bs58.decode("29Apzfedhw2Jxh94Jj4rNSmavQ1TkNe8ALYRA7bMegobwp423aLrURxLk32WtXgXHDqoSz7GAT9fQfoMhVd1e5Ww"));
let add_root_result = await add_root(local[0].peerId, local[0].peerId, 2);
console.log("Add root weight result: %s", add_root_result);
await add_roots();
let nodeA = local[0].peerId
let nodeB = local[1].peerId
let nodeC = local[2].peerId
await revoke_checked(nodeB, nodeB);
await exec_trusted_computation(nodeA);
await exec_trusted_computation(nodeB);
await exec_trusted_computation(nodeC);
// add root trust
await add_trust_helper(local[0].peerId, issuer_kp, local[0].peerId, local[0].peerId, expires_at_sec, issued_timestamp_sec);
let current_time = await tg.timestamp_sec();
let far_future = current_time + 9999999;
let root_weight_result = await get_weight(local[0].peerId, local[0].peerId);
console.log("Root weight: %s", root_weight_result);
await add_new_trust_checked(nodeB, nodeB, far_future);
// issue trust by local[0].peerId for local[1].peerId and add to tg
await add_trust_helper(local[0].peerId, issuer_kp, local[0].peerId, local[1].peerId, expires_at_sec, issued_timestamp_sec);
let weight_result = await get_weight(local[0].peerId, local[1].peerId);
console.log("Trust weight: %s", weight_result);
await exec_trusted_computation(nodeA);
await exec_trusted_computation(nodeB);
await exec_trusted_computation(nodeC);
assert(root_weight_result.weight / 2 === weight_result.weight);
let certs = await get_all_certs(local[0].peerId, local[1].peerId);
console.log("Certs: %s", JSON.stringify(certs.certificates));
assert(certs.certificates.length === 1);
// wait to create revoke after trust (because timestamp in secs)
await new Promise(f => setTimeout(f, 1000));
// revoke local[1].peerId trust
await revoke_helper(local[0].peerId, issuer_kp, local[0].peerId, local[1].peerId, await timestamp_sec(local[0].peerId));
let empty_certs = await get_all_certs(local[0].peerId, local[1].peerId);
assert(empty_certs.certificates.length === 0);
await revoke_checked(nodeB, nodeB);
await exec_trusted_computation(nodeA);
await exec_trusted_computation(nodeB);
await exec_trusted_computation(nodeC);
return;
}

5231
example/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -13,14 +13,14 @@
"author": "Fluence Labs",
"license": "MIT",
"dependencies": {
"@fluencelabs/aqua": "0.4.1-240",
"@fluencelabs/aqua-lib": "0.2.0",
"@fluencelabs/fluence": "0.14.3",
"@fluencelabs/aqua": "^0.5.2-257",
"@fluencelabs/aqua-lib": "^0.3.2",
"@fluencelabs/fluence": "^0.18.0",
"@fluencelabs/fluence-network-environment": "^1.0.10",
"@fluencelabs/trust-graph": "file:../aqua",
"bs58": "^4.0.1"
},
"devDependencies": {
"typescript": "^4.4.3"
"typescript": "^4.5.2"
}
}

View File

@ -43,7 +43,7 @@ impl Keypair {
///
/// [RFC5208]: https://tools.ietf.org/html/rfc5208#section-5
pub fn from_pkcs8(der: &mut [u8]) -> Result<Self, DecodingError> {
let kp = RsaKeyPair::from_pkcs8(&der).map_err(|_| DecodingError::Rsa)?;
let kp = RsaKeyPair::from_pkcs8(der).map_err(|_| DecodingError::Rsa)?;
der.zeroize();
Ok(Keypair(Arc::new(kp)))
}
@ -57,7 +57,7 @@ impl Keypair {
pub fn sign(&self, data: &[u8]) -> Result<Vec<u8>, SigningError> {
let mut signature = vec![0; self.0.public_modulus_len()];
let rng = SystemRandom::new();
match self.0.sign(&RSA_PKCS1_SHA256, &rng, &data, &mut signature) {
match self.0.sign(&RSA_PKCS1_SHA256, &rng, data, &mut signature) {
Ok(()) => Ok(signature),
Err(_) => Err(SigningError::Rsa),
}

View File

@ -98,7 +98,7 @@ impl Signature {
pub fn get_raw_signature(&self) -> RawSignature {
RawSignature {
bytes: self.to_vec().clone().to_vec(),
bytes: self.to_vec().to_vec(),
sig_type: self.get_signature_type(),
}
}

View File

@ -1,17 +1,17 @@
# management secret key is NAB5rGwT4qOEB+6nLQawkTfCOV2eiFSjgQK8bfEdZXY=
services:
fluence-0: # /ip4/127.0.0.1/tcp/9990/ws/p2p/12D3KooWHBG9oaVx4i3vi6c1rSBUm7MLBmyGmmbHoZ23pmjDCnvK
command: -f ed25519 -k 29Apzfedhw2Jxh94Jj4rNSmavQ1TkNe8ALYRA7bMegobwp423aLrURxLk32WtXgXHDqoSz7GAT9fQfoMhVd1e5Ww -m 12D3KooWFRgVmb1uWcmCbmJqLr8tBQghL6ysSpK2VyE2VZbaQ6wy -t 7770 -w 9990 # --bootstraps /dns4/fluence-1/tcp/7771 /dns4/fluence-2/tcp/7772
command: -f ed25519 -k 29Apzfedhw2Jxh94Jj4rNSmavQ1TkNe8ALYRA7bMegobwp423aLrURxLk32WtXgXHDqoSz7GAT9fQfoMhVd1e5Ww -m 12D3KooWFRgVmb1uWcmCbmJqLr8tBQghL6ysSpK2VyE2VZbaQ6wy -t 7770 -w 9990 --bootstraps /dns4/fluence-1/tcp/7771 /dns4/fluence-2/tcp/7772
container_name: fluence-0
environment:
RUST_BACKTRACE: full
RUST_LOG: info,network=trace,aquamarine=info,aquamarine::actor=info,tokio_threadpool=info,tokio_reactor=info,mio=info,tokio_io=info,soketto=info,yamux=info,multistream_select=info,libp2p_secio=info,libp2p_websocket::framed=info,libp2p_ping=info,libp2p_core::upgrade::apply=info,libp2p_kad::kbucket=info,cranelift_codegen=info,wasmer_wasi=info,async_io=info,polling=info,wasmer_interface_types_fl=info,cranelift_codegen=info,wasmer_wasi=info,async_io=info,polling=info,wasmer_interface_types_fl=info,particle_server::behaviour::identify=info,libp2p_mplex=info,libp2p_identify=info,walrus=info,particle_protocol::libp2p_protocol::upgrade=info,kademlia::behaviour=info
WASM_LOG: info
image: fluencelabs/node:latest
image: fluencelabs/node:tg-hl-api_v345
ports:
- 7770:7770 # tcp
- 9990:9990 # ws
- 5000:5001 # ipfs rpc
- 5003:5001 # ipfs rpc
- 4000:4001 # ipfs swarm
- 18080:18080 # /metrics
restart: always
@ -22,56 +22,58 @@ services:
networks:
- fluence
# fluence-1: # /ip4/127.0.0.1/tcp/9991/ws/p2p/12D3KooWRABanQHUn28dxavN9ZS1zZghqoZVAYtFpoN7FdtoGTFv
# command: -f ed25519 -k 5fNENMwkUT4dW3hPs9ZwqV4qA5pdTtUChTazAx9Awe2Vpz1yaJu3VCmcEZow6YgdFBGoZoFAZUZBbF3c2Ebd2iL -m 12D3KooWFRgVmb1uWcmCbmJqLr8tBQghL6ysSpK2VyE2VZbaQ6wy -t 7771 -w 9991 --bootstraps /dns4/fluence-0/tcp/7770 /dns4/fluence-2/tcp/7772 #/dns4/kras-00.fluence.dev/tcp/7770
# container_name: fluence-1
# environment:
# RUST_BACKTRACE: full
# RUST_LOG: info,network=trace,aquamarine=info,aquamarine::actor=info,tokio_threadpool=info,tokio_reactor=info,mio=info,tokio_io=info,soketto=info,yamux=info,multistream_select=info,libp2p_secio=info,libp2p_websocket::framed=info,libp2p_ping=info,libp2p_core::upgrade::apply=info,libp2p_kad::kbucket=info,cranelift_codegen=info,wasmer_wasi=info,async_io=info,polling=info,wasmer_interface_types_fl=info,cranelift_codegen=info,wasmer_wasi=info,async_io=info,polling=info,wasmer_interface_types_fl=info,particle_server::behaviour::identify=info,libp2p_mplex=info,libp2p_identify=info,walrus=info,particle_protocol::libp2p_protocol::upgrade=info,kademlia::behaviour=info
# WASM_LOG: info
# image: fluencelabs/node:latest
# ports:
# - 7771:7771 # tcp
# - 9991:9991 # ws
# - 5001:5001 # ipfs rpc
# - 4001:4001 # ipfs swarm
# - 18081:18080 # /metrics
# restart: always
# volumes:
# - fluence-1:/.fluence
# - data-1:/config
# networks:
# - fluence
#
# fluence-2: # /ip4/127.0.0.1/tcp/9992/ws/p2p/12D3KooWFpQ7LHxcC9FEBUh3k4nSCC12jBhijJv3gJbi7wsNYzJ5
# command: -f ed25519 -k 5DTs9LQS8Ay2dM8xBcikDRwYLMcanhsC6tynSSgpLyBZEv5Ey34LVw1fYcCuUj9A9EfvQJB2bsaGhSRoHQ7D6UE5 -m 12D3KooWFRgVmb1uWcmCbmJqLr8tBQghL6ysSpK2VyE2VZbaQ6wy -t 7772 -w 9992 --bootstraps /dns4/fluence-0/tcp/7770 /dns4/fluence-1/tcp/7771 #/dns4/kras-00.fluence.dev/tcp/7770
# container_name: fluence-2
# environment:
# RUST_BACKTRACE: full
# RUST_LOG: info,network=trace,aquamarine=info,aquamarine::actor=info,tokio_threadpool=info,tokio_reactor=info,mio=info,tokio_io=info,soketto=info,yamux=info,multistream_select=info,libp2p_secio=info,libp2p_websocket::framed=info,libp2p_ping=info,libp2p_core::upgrade::apply=info,libp2p_kad::kbucket=info,cranelift_codegen=info,wasmer_wasi=info,async_io=info,polling=info,wasmer_interface_types_fl=info,cranelift_codegen=info,wasmer_wasi=info,async_io=info,polling=info,wasmer_interface_types_fl=info,particle_server::behaviour::identify=info,libp2p_mplex=info,libp2p_identify=info,walrus=info,particle_protocol::libp2p_protocol::upgrade=info,kademlia::behaviour=info
# WASM_LOG: info
# image: fluencelabs/node:latest
# ports:
# - 7772:7772 # tcp
# - 9992:9992 # ws
# - 5002:5001 # ipfs rpc
# - 4002:4001 # ipfs swarm
# - 18082:18080 # /metrics
# restart: always
# volumes:
# - fluence-2:/.fluence
# - data-2:/config
# networks:
# - fluence
fluence-1: # /ip4/127.0.0.1/tcp/9991/ws/p2p/12D3KooWRABanQHUn28dxavN9ZS1zZghqoZVAYtFpoN7FdtoGTFv
command: -f ed25519 -k 5fNENMwkUT4dW3hPs9ZwqV4qA5pdTtUChTazAx9Awe2Vpz1yaJu3VCmcEZow6YgdFBGoZoFAZUZBbF3c2Ebd2iL -m 12D3KooWFRgVmb1uWcmCbmJqLr8tBQghL6ysSpK2VyE2VZbaQ6wy -t 7771 -w 9991 --bootstraps /dns4/fluence-0/tcp/7770 /dns4/fluence-2/tcp/7772 #/dns4/kras-00.fluence.dev/tcp/7770
container_name: fluence-1
environment:
RUST_BACKTRACE: full
RUST_LOG: info,network=trace,aquamarine=info,aquamarine::actor=info,tokio_threadpool=info,tokio_reactor=info,mio=info,tokio_io=info,soketto=info,yamux=info,multistream_select=info,libp2p_secio=info,libp2p_websocket::framed=info,libp2p_ping=info,libp2p_core::upgrade::apply=info,libp2p_kad::kbucket=info,cranelift_codegen=info,wasmer_wasi=info,async_io=info,polling=info,wasmer_interface_types_fl=info,cranelift_codegen=info,wasmer_wasi=info,async_io=info,polling=info,wasmer_interface_types_fl=info,particle_server::behaviour::identify=info,libp2p_mplex=info,libp2p_identify=info,walrus=info,particle_protocol::libp2p_protocol::upgrade=info,kademlia::behaviour=info
WASM_LOG: info
image: fluencelabs/node:tg-hl-api_v345
ports:
- 7771:7771 # tcp
- 9991:9991 # ws
- 5001:5001 # ipfs rpc
- 4001:4001 # ipfs swarm
- 18081:18080 # /metrics
restart: always
volumes:
- fluence-1:/.fluence
- data-1:/config
- ./builtins_secret_key.ed25519:/.fluence/v1/builtins_secret_key.ed25519
networks:
- fluence
fluence-2: # /ip4/127.0.0.1/tcp/9992/ws/p2p/12D3KooWFpQ7LHxcC9FEBUh3k4nSCC12jBhijJv3gJbi7wsNYzJ5
command: -f ed25519 -k 5DTs9LQS8Ay2dM8xBcikDRwYLMcanhsC6tynSSgpLyBZEv5Ey34LVw1fYcCuUj9A9EfvQJB2bsaGhSRoHQ7D6UE5 -m 12D3KooWFRgVmb1uWcmCbmJqLr8tBQghL6ysSpK2VyE2VZbaQ6wy -t 7772 -w 9992 --bootstraps /dns4/fluence-0/tcp/7770 /dns4/fluence-1/tcp/7771 #/dns4/kras-00.fluence.dev/tcp/7770
container_name: fluence-2
environment:
RUST_BACKTRACE: full
RUST_LOG: info,network=trace,aquamarine=info,aquamarine::actor=info,tokio_threadpool=info,tokio_reactor=info,mio=info,tokio_io=info,soketto=info,yamux=info,multistream_select=info,libp2p_secio=info,libp2p_websocket::framed=info,libp2p_ping=info,libp2p_core::upgrade::apply=info,libp2p_kad::kbucket=info,cranelift_codegen=info,wasmer_wasi=info,async_io=info,polling=info,wasmer_interface_types_fl=info,cranelift_codegen=info,wasmer_wasi=info,async_io=info,polling=info,wasmer_interface_types_fl=info,particle_server::behaviour::identify=info,libp2p_mplex=info,libp2p_identify=info,walrus=info,particle_protocol::libp2p_protocol::upgrade=info,kademlia::behaviour=info
WASM_LOG: info
image: fluencelabs/node:tg-hl-api_v345
ports:
- 7772:7772 # tcp
- 9992:9992 # ws
- 5002:5001 # ipfs rpc
- 4002:4001 # ipfs swarm
- 18082:18080 # /metrics
restart: always
volumes:
- fluence-2:/.fluence
- data-2:/config
- ./builtins_secret_key.ed25519:/.fluence/v1/builtins_secret_key.ed25519
networks:
- fluence
version: "3.5"
volumes:
fluence-0:
# fluence-1:
# fluence-2:
fluence-1:
fluence-2:
data-0:
# data-1:
# data-2:
data-1:
data-2:
networks:
fluence:

View File

@ -1,6 +1,6 @@
[package]
name = "trust-graph-wasm"
version = "0.2.1"
version = "0.3.0"
authors = ["Fluence Labs"]
edition = "2018"
description = "trust graph wasm"

View File

@ -5,12 +5,12 @@ modules_dir = "artifacts/"
logger_enabled = true
[module.wasi]
preopened_files = ["./data"]
mapped_dirs = { "data" = "data" }
preopened_files = ["/tmp"]
mapped_dirs = { "tmp" = "/tmp" }
[[module]]
name = "trust-graph"
logger_enabled = true
[module.wasi]
preopened_files = ["./data"]
mapped_dirs = { "data" = "data" }
preopened_files = ["/tmp"]
mapped_dirs = { "tmp" = "/tmp" }

View File

@ -113,7 +113,7 @@ impl From<trust_graph::Trust> for Trust {
#[marine]
#[derive(Default)]
pub struct Revoke {
pub struct Revocation {
/// who is revoked
pub revoked_peer_id: String,
/// date when revocation was created
@ -126,10 +126,10 @@ pub struct Revoke {
pub revoked_by: String,
}
impl TryFrom<Revoke> for trust_graph::Revoke {
impl TryFrom<Revocation> for trust_graph::Revocation {
type Error = DtoConversionError;
fn try_from(r: Revoke) -> Result<Self, Self::Error> {
fn try_from(r: Revocation) -> Result<Self, Self::Error> {
let revoked_pk = PublicKey::try_from(
PeerId::from_str(&r.revoked_peer_id)
.map_err(|e| PeerIdDecodeError(format!("{:?}", e)))?,
@ -142,7 +142,7 @@ impl TryFrom<Revoke> for trust_graph::Revoke {
let signature = bs58::decode(&r.signature).into_vec()?;
let signature = Signature::from_bytes(KeyFormat::from_str(&r.sig_type)?, signature);
let revoked_at = Duration::from_secs(r.revoked_at);
return Ok(trust_graph::Revoke {
return Ok(trust_graph::Revocation {
pk: revoked_pk,
revoked_at,
revoked_by: revoked_by_pk,
@ -151,14 +151,14 @@ impl TryFrom<Revoke> for trust_graph::Revoke {
}
}
impl From<trust_graph::Revoke> for Revoke {
fn from(r: trust_graph::Revoke) -> Self {
impl From<trust_graph::Revocation> for Revocation {
fn from(r: trust_graph::Revocation) -> Self {
let revoked_by = r.revoked_by.to_peer_id().to_base58();
let revoked_peer_id = r.pk.to_peer_id().to_base58();
let raw_signature = r.signature.get_raw_signature();
let signature = bs58::encode(raw_signature.bytes).into_string();
let revoked_at = r.revoked_at.as_secs();
return Revoke {
return Revocation {
revoked_peer_id,
revoked_at,
signature,

64
service/src/error.rs Normal file
View File

@ -0,0 +1,64 @@
/*
* Copyright 2021 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use thiserror::Error as ThisError;
use crate::dto::DtoConversionError;
use fluence_keypair::error::DecodingError;
use trust_graph::{CertificateError, TrustError, TrustGraphError};
#[derive(ThisError, Debug)]
pub enum ServiceError {
#[error("peer id parse error: {0}")]
PeerIdParseError(String),
#[error("public key extraction from peer id failed: {0}")]
PublicKeyExtractionError(String),
#[error("{0}")]
PublicKeyDecodeError(
#[from]
#[source]
DecodingError,
),
#[error("{0}")]
TGError(
#[from]
#[source]
TrustGraphError,
),
#[error("{0}")]
CertError(
#[from]
#[source]
CertificateError,
),
#[error("{0}")]
DtoError(
#[from]
#[source]
DtoConversionError,
),
#[error("{0}")]
TrustError(
#[from]
#[source]
TrustError,
),
#[error("you should use host peer.timestamp_sec to pass timestamp: {0}")]
InvalidTimestampTetraplet(String),
#[error("{0} can't be issued later than the current timestamp")]
InvalidTimestamp(String),
#[error("Root could add only by trust graph service owner")]
NotOwner,
}

View File

@ -7,12 +7,15 @@ use marine_rs_sdk::WasmLoggerBuilder;
module_manifest!();
mod dto;
mod error;
mod misc;
mod results;
mod service_api;
mod service_impl;
mod storage_impl;
mod tests;
pub static TRUSTED_TIMESTAMP: (&str, &str) = ("peer", "timestamp_sec");
pub fn main() {
WasmLoggerBuilder::new()
.with_log_level(log::LevelFilter::Trace)

76
service/src/misc.rs Normal file
View File

@ -0,0 +1,76 @@
/*
* Copyright 2021 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::error::ServiceError;
use crate::error::ServiceError::*;
use crate::storage_impl::{SQLiteStorage, DB_PATH};
use crate::TRUSTED_TIMESTAMP;
use fluence_keypair::PublicKey;
use libp2p_core::PeerId;
use marine_rs_sdk::CallParameters;
use std::cell::RefCell;
use std::convert::TryFrom;
use std::ops::DerefMut;
use std::str::FromStr;
use trust_graph::TrustGraph;
/// Check timestamps are generated on the current host with builtin ("peer" "timestamp_sec")
pub(crate) fn check_timestamp_tetraplets(
call_parameters: &CallParameters,
arg_number: usize,
) -> Result<(), ServiceError> {
let tetraplets = call_parameters
.tetraplets
.get(arg_number)
.ok_or_else(|| InvalidTimestampTetraplet(format!("{:?}", call_parameters.tetraplets)))?;
let tetraplet = tetraplets
.get(0)
.ok_or_else(|| InvalidTimestampTetraplet(format!("{:?}", call_parameters.tetraplets)))?;
(TRUSTED_TIMESTAMP.eq(&(&tetraplet.service_id, &tetraplet.function_name))
&& tetraplet.peer_pk == call_parameters.host_id)
.then(|| ())
.ok_or_else(|| InvalidTimestampTetraplet(format!("{:?}", tetraplet)))
}
fn parse_peer_id(peer_id: String) -> Result<PeerId, ServiceError> {
libp2p_core::PeerId::from_str(&peer_id)
.map_err(|e| ServiceError::PeerIdParseError(format!("{:?}", e)))
}
thread_local!(static INSTANCE: RefCell<TrustGraph<SQLiteStorage>> = RefCell::new(TrustGraph::new(
SQLiteStorage::new(marine_sqlite_connector::open(DB_PATH).unwrap()),
)));
pub fn with_tg<F, T>(func: F) -> T
where
F: FnOnce(&mut TrustGraph<SQLiteStorage>) -> T,
{
INSTANCE.with(|tg| func(tg.borrow_mut().deref_mut()))
}
pub fn wrapped_try<F, T>(func: F) -> T
where
F: FnOnce() -> T,
{
func()
}
pub fn extract_public_key(peer_id: String) -> Result<PublicKey, ServiceError> {
PublicKey::try_from(
parse_peer_id(peer_id)
.map_err(|e| ServiceError::PublicKeyExtractionError(e.to_string()))?,
)
.map_err(ServiceError::PublicKeyDecodeError)
}

View File

@ -1,5 +1,5 @@
use crate::dto::{Certificate, Revoke, Trust};
use crate::service_impl::ServiceError;
use crate::dto::{Certificate, Revocation, Trust};
use crate::error::ServiceError;
use marine_rs_sdk::marine;
#[marine]
@ -216,21 +216,21 @@ impl From<Result<Vec<u8>, ServiceError>> for GetRevokeBytesResult {
pub struct IssueRevocationResult {
pub success: bool,
pub error: String,
pub revoke: Revoke,
pub revocation: Revocation,
}
impl From<Result<Revoke, ServiceError>> for IssueRevocationResult {
fn from(result: Result<Revoke, ServiceError>) -> Self {
impl From<Result<Revocation, ServiceError>> for IssueRevocationResult {
fn from(result: Result<Revocation, ServiceError>) -> Self {
match result {
Ok(revoke) => IssueRevocationResult {
Ok(revocation) => IssueRevocationResult {
success: true,
error: "".to_string(),
revoke,
revocation,
},
Err(e) => IssueRevocationResult {
success: false,
error: format!("{}", e),
revoke: Revoke::default(),
revocation: Revocation::default(),
},
}
}

View File

@ -1,16 +1,18 @@
use crate::dto::{Certificate, Revoke, Trust};
use crate::dto::{Certificate, Revocation, Trust};
use crate::error::ServiceError;
use crate::misc::{check_timestamp_tetraplets, extract_public_key, with_tg, wrapped_try};
use crate::results::{
AddRootResult, AddTrustResult, AllCertsResult, GetRevokeBytesResult, GetTrustBytesResult,
InsertResult, IssueRevocationResult, IssueTrustResult, RevokeResult, VerifyTrustResult,
WeightResult,
};
use crate::service_impl::{
add_root_impl, add_trust_impl, get_all_certs_impl, get_host_certs_impl, get_revoke_bytes_impl,
get_trust_bytes_impl, get_weight_impl, insert_cert_impl, insert_cert_impl_raw,
issue_revocation_impl, issue_trust_impl, revoke_impl, verify_trust_impl, ServiceError,
};
use crate::storage_impl::SQLiteStorage;
use fluence_keypair::Signature;
use marine_rs_sdk::{get_call_parameters, marine, CallParameters};
use trust_graph::MAX_WEIGHT_FACTOR;
use std::convert::{TryFrom, TryInto};
use std::str::FromStr;
use std::time::Duration;
use trust_graph::{TrustGraph, MAX_WEIGHT_FACTOR};
#[marine]
fn get_weight_factor(max_chain_len: u32) -> u32 {
@ -23,7 +25,12 @@ fn add_root(peer_id: String, weight_factor: u32) -> AddRootResult {
let call_parameters: CallParameters = marine_rs_sdk::get_call_parameters();
let init_peer_id = call_parameters.init_peer_id;
if call_parameters.service_creator_peer_id == init_peer_id {
add_root_impl(peer_id, weight_factor).into()
with_tg(|tg| {
let public_key = extract_public_key(peer_id)?;
tg.add_root_weight_factor(public_key, weight_factor)?;
Ok(())
})
.into()
} else {
return AddRootResult {
success: false,
@ -36,44 +43,82 @@ fn add_root(peer_id: String, weight_factor: u32) -> AddRootResult {
/// add a certificate in string representation to trust graph if it is valid
/// see `trust_graph::Certificate` class for string encoding/decoding
fn insert_cert_raw(certificate: String, timestamp_sec: u64) -> InsertResult {
insert_cert_impl_raw(certificate, timestamp_sec).into()
with_tg(|tg| {
let certificate = trust_graph::Certificate::from_str(&certificate)?;
let timestamp_sec = Duration::from_secs(timestamp_sec);
tg.add(certificate, timestamp_sec)?;
Ok(())
})
.into()
}
#[marine]
/// add a certificate in JSON representation to trust graph if it is valid
/// see `dto::Certificate` class for structure
fn insert_cert(certificate: Certificate, timestamp_sec: u64) -> InsertResult {
insert_cert_impl(certificate, timestamp_sec).into()
with_tg(|tg| {
let timestamp_sec = Duration::from_secs(timestamp_sec);
tg.add(
trust_graph::Certificate::try_from(certificate)?,
timestamp_sec,
)?;
Ok(())
})
.into()
}
fn get_certs(
tg: &mut TrustGraph<SQLiteStorage>,
issued_for: String,
timestamp_sec: u64,
) -> Result<impl Iterator<Item = Certificate>, ServiceError> {
let public_key = extract_public_key(issued_for)?;
let certs = tg.get_all_certs(public_key, Duration::from_secs(timestamp_sec))?;
Ok(certs.into_iter().map(|c| c.into()))
}
#[marine]
fn get_all_certs(issued_for: String, timestamp_sec: u64) -> AllCertsResult {
get_all_certs_impl(issued_for, timestamp_sec).into()
with_tg(|tg| {
check_timestamp_tetraplets(&marine_rs_sdk::get_call_parameters(), 1)?;
get_certs(tg, issued_for, timestamp_sec).map(|iter| iter.collect())
})
.into()
}
#[marine]
fn get_host_certs(timestamp_sec: u64) -> AllCertsResult {
get_host_certs_impl(timestamp_sec).into()
with_tg(|tg| {
let cp = marine_rs_sdk::get_call_parameters();
check_timestamp_tetraplets(&cp, 0)?;
get_certs(tg, cp.host_id, timestamp_sec).map(|iter| iter.collect())
})
.into()
}
#[marine]
fn get_host_certs_from(issuer: String, timestamp_sec: u64) -> AllCertsResult {
let host_id = get_call_parameters().host_id;
get_all_certs_impl(host_id, timestamp_sec)
.map(|certs| {
certs
.into_iter()
.filter(|cert| cert.chain.iter().any(|t| t.issued_for == issuer))
with_tg(|tg| {
let cp = get_call_parameters();
check_timestamp_tetraplets(&cp, 1)?;
get_certs(tg, cp.host_id, timestamp_sec).map(|c| {
c.filter(|cert: &Certificate| cert.chain.iter().any(|t| t.issued_for == issuer))
.collect()
})
.into()
})
.into()
}
#[marine]
fn get_weight(peer_id: String, timestamp_sec: u64) -> WeightResult {
get_weight_impl(peer_id.clone(), timestamp_sec)
.map(|w| (w, peer_id))
.into()
with_tg(|tg| {
check_timestamp_tetraplets(&marine_rs_sdk::get_call_parameters(), 1)?;
let public_key = extract_public_key(peer_id.clone())?;
let weight = tg.weight(public_key, Duration::from_secs(timestamp_sec))?;
Ok(weight)
})
.map(|w| (w, peer_id))
.into()
}
#[marine]
@ -82,7 +127,16 @@ fn get_trust_bytes(
expires_at_sec: u64,
issued_at_sec: u64,
) -> GetTrustBytesResult {
get_trust_bytes_impl(issued_for_peer_id, expires_at_sec, issued_at_sec).into()
wrapped_try(|| {
let public_key = extract_public_key(issued_for_peer_id)?;
Ok(trust_graph::Trust::signature_bytes(
&public_key,
Duration::from_secs(expires_at_sec),
Duration::from_secs(issued_at_sec),
))
})
.into()
}
#[marine]
@ -92,28 +146,67 @@ fn issue_trust(
issued_at_sec: u64,
trust_bytes: Vec<u8>,
) -> IssueTrustResult {
issue_trust_impl(
issued_for_peer_id,
expires_at_sec,
issued_at_sec,
trust_bytes,
)
wrapped_try(|| {
let public_key = extract_public_key(issued_for_peer_id)?;
let expires_at_sec = Duration::from_secs(expires_at_sec);
let issued_at_sec = Duration::from_secs(issued_at_sec);
let signature = Signature::from_bytes(public_key.get_key_format(), trust_bytes);
Ok(Trust::from(trust_graph::Trust::new(
public_key,
expires_at_sec,
issued_at_sec,
signature,
)))
})
.into()
}
#[marine]
fn verify_trust(trust: Trust, issuer_peer_id: String, timestamp_sec: u64) -> VerifyTrustResult {
verify_trust_impl(trust, issuer_peer_id, timestamp_sec).into()
wrapped_try(|| {
check_timestamp_tetraplets(&marine_rs_sdk::get_call_parameters(), 2)?;
let public_key = extract_public_key(issuer_peer_id)?;
trust_graph::Trust::verify(
&trust.try_into()?,
&public_key,
Duration::from_secs(timestamp_sec),
)?;
Ok(())
})
.into()
}
#[marine]
fn add_trust(trust: Trust, issuer_peer_id: String, timestamp_sec: u64) -> AddTrustResult {
add_trust_impl(trust, issuer_peer_id, timestamp_sec).into()
with_tg(|tg| {
let public_key = extract_public_key(issuer_peer_id)?;
check_timestamp_tetraplets(&marine_rs_sdk::get_call_parameters(), 2)?;
if trust.issued_at > timestamp_sec {
return Err(ServiceError::InvalidTimestamp("trust".to_string()));
}
tg.add_trust(
&trust.try_into()?,
public_key,
Duration::from_secs(timestamp_sec),
)
.map_err(ServiceError::TGError)
})
.into()
}
#[marine]
fn get_revoke_bytes(revoked_peer_id: String, revoked_at: u64) -> GetRevokeBytesResult {
get_revoke_bytes_impl(revoked_peer_id, revoked_at).into()
fn get_revocation_bytes(revoked_peer_id: String, revoked_at: u64) -> GetRevokeBytesResult {
wrapped_try(|| {
let public_key = extract_public_key(revoked_peer_id)?;
Ok(trust_graph::Revocation::signature_bytes(
&public_key,
Duration::from_secs(revoked_at),
))
})
.into()
}
#[marine]
@ -123,16 +216,27 @@ fn issue_revocation(
revoked_at_sec: u64,
signature_bytes: Vec<u8>,
) -> IssueRevocationResult {
issue_revocation_impl(
revoked_peer_id,
revoked_by_peer_id,
revoked_at_sec,
signature_bytes,
)
wrapped_try(|| {
let revoked_pk = extract_public_key(revoked_peer_id)?;
let revoked_by_pk = extract_public_key(revoked_by_peer_id)?;
let revoked_at = Duration::from_secs(revoked_at_sec);
let signature = Signature::from_bytes(revoked_by_pk.get_key_format(), signature_bytes);
Ok(trust_graph::Revocation::new(revoked_pk, revoked_by_pk, revoked_at, signature).into())
})
.into()
}
#[marine]
fn revoke(revoke: Revoke, timestamp_sec: u64) -> RevokeResult {
revoke_impl(revoke, timestamp_sec).into()
fn revoke(revoke: Revocation, timestamp_sec: u64) -> RevokeResult {
with_tg(|tg| {
check_timestamp_tetraplets(&marine_rs_sdk::get_call_parameters(), 1)?;
if revoke.revoked_at > timestamp_sec {
return Err(ServiceError::InvalidTimestamp("revoke".to_string()));
}
tg.revoke(revoke.try_into()?).map_err(ServiceError::TGError)
})
.into()
}

View File

@ -1,255 +0,0 @@
use crate::dto::{Certificate, DtoConversionError, Revoke, Trust};
use crate::service_impl::ServiceError::InvalidTimestampTetraplet;
use crate::storage_impl::get_data;
use fluence_keypair::error::DecodingError;
use fluence_keypair::{PublicKey, Signature};
use libp2p_core::PeerId;
use marine_rs_sdk::CallParameters;
use std::convert::{Into, TryFrom, TryInto};
use std::str::FromStr;
use std::time::Duration;
use thiserror::Error as ThisError;
use trust_graph::{CertificateError, TrustError, TrustGraphError};
pub static TRUSTED_TIMESTAMP_SERVICE_ID: &str = "peer";
pub static TRUSTED_TIMESTAMP_FUNCTION_NAME: &str = "timestamp_sec";
/// Check timestamps are generated on the current host with builtin ("peer" "timestamp_sec")
pub(crate) fn check_timestamp_tetraplets(
call_parameters: &CallParameters,
arg_number: usize,
) -> Result<(), ServiceError> {
let tetraplets = call_parameters
.tetraplets
.get(arg_number)
.ok_or(InvalidTimestampTetraplet)?;
let tetraplet = tetraplets.get(0).ok_or(InvalidTimestampTetraplet)?;
(tetraplet.service_id == TRUSTED_TIMESTAMP_SERVICE_ID
&& tetraplet.function_name == TRUSTED_TIMESTAMP_FUNCTION_NAME
&& tetraplet.peer_pk == call_parameters.host_id)
.then(|| ())
.ok_or(InvalidTimestampTetraplet)
}
#[derive(ThisError, Debug)]
pub enum ServiceError {
#[error("peer id parse error: {0}")]
PeerIdParseError(String),
#[error("public key extraction from peer id failed: {0}")]
PublicKeyExtractionError(String),
#[error("{0}")]
PublicKeyDecodeError(
#[from]
#[source]
DecodingError,
),
#[error("{0}")]
TGError(
#[from]
#[source]
TrustGraphError,
),
#[error("{0}")]
CertError(
#[from]
#[source]
CertificateError,
),
#[error("{0}")]
DtoError(
#[from]
#[source]
DtoConversionError,
),
#[error("{0}")]
TrustError(
#[from]
#[source]
TrustError,
),
#[error("you should use host peer.timestamp_sec to pass timestamp")]
InvalidTimestampTetraplet,
#[error("{0} can't be issued later than the current timestamp")]
InvalidTimestamp(String),
#[error("Root could add only by trust graph service owner")]
NotOwner,
}
fn parse_peer_id(peer_id: String) -> Result<PeerId, ServiceError> {
libp2p_core::PeerId::from_str(&peer_id)
.map_err(|e| ServiceError::PeerIdParseError(format!("{:?}", e)))
}
fn extract_public_key(peer_id: String) -> Result<PublicKey, ServiceError> {
PublicKey::try_from(
parse_peer_id(peer_id)
.map_err(|e| ServiceError::PublicKeyExtractionError(e.to_string()))?,
)
.map_err(ServiceError::PublicKeyDecodeError)
}
pub fn get_weight_impl(peer_id: String, timestamp_sec: u64) -> Result<u32, ServiceError> {
check_timestamp_tetraplets(&marine_rs_sdk::get_call_parameters(), 1)?;
let mut tg = get_data().lock();
let public_key = extract_public_key(peer_id)?;
let weight = tg.weight(public_key, Duration::from_secs(timestamp_sec))?;
Ok(weight)
}
fn add_cert(certificate: trust_graph::Certificate, timestamp_sec: u64) -> Result<(), ServiceError> {
let timestamp_sec = Duration::from_secs(timestamp_sec);
let mut tg = get_data().lock();
tg.add(certificate, timestamp_sec)?;
Ok(())
}
pub fn insert_cert_impl_raw(certificate: String, timestamp_sec: u64) -> Result<(), ServiceError> {
let certificate = trust_graph::Certificate::from_str(&certificate)?;
add_cert(certificate, timestamp_sec)?;
Ok(())
}
pub fn get_all_certs_impl(
issued_for: String,
timestamp_sec: u64,
) -> Result<Vec<Certificate>, ServiceError> {
check_timestamp_tetraplets(&marine_rs_sdk::get_call_parameters(), 1)?;
get_certs_helper(issued_for, timestamp_sec)
}
pub fn get_host_certs_impl(timestamp_sec: u64) -> Result<Vec<Certificate>, ServiceError> {
let cp = marine_rs_sdk::get_call_parameters();
check_timestamp_tetraplets(&cp, 0)?;
get_certs_helper(cp.host_id, timestamp_sec)
}
pub fn get_certs_helper(
issued_for: String,
timestamp_sec: u64,
) -> Result<Vec<Certificate>, ServiceError> {
let mut tg = get_data().lock();
let public_key = extract_public_key(issued_for)?;
let certs = tg.get_all_certs(public_key, Duration::from_secs(timestamp_sec))?;
Ok(certs.into_iter().map(|c| c.into()).collect())
}
pub fn insert_cert_impl(certificate: Certificate, timestamp_sec: u64) -> Result<(), ServiceError> {
let certificate: trust_graph::Certificate = certificate.try_into()?;
add_cert(certificate, timestamp_sec)?;
Ok(())
}
pub fn add_root_impl(peer_id: String, weight: u32) -> Result<(), ServiceError> {
let mut tg = get_data().lock();
let public_key = extract_public_key(peer_id)?;
tg.add_root_weight_factor(public_key, weight)?;
Ok(())
}
pub fn get_trust_bytes_impl(
peer_id: String,
expires_at_sec: u64,
issued_at_sec: u64,
) -> Result<Vec<u8>, ServiceError> {
let public_key = extract_public_key(peer_id)?;
Ok(trust_graph::Trust::signature_bytes(
&public_key,
Duration::from_secs(expires_at_sec),
Duration::from_secs(issued_at_sec),
))
}
pub fn issue_trust_impl(
peer_id: String,
expires_at_sec: u64,
issued_at_sec: u64,
trust_bytes: Vec<u8>,
) -> Result<Trust, ServiceError> {
let public_key = extract_public_key(peer_id)?;
let expires_at_sec = Duration::from_secs(expires_at_sec);
let issued_at_sec = Duration::from_secs(issued_at_sec);
let signature = Signature::from_bytes(public_key.get_key_format(), trust_bytes);
Ok(Trust::from(trust_graph::Trust::new(
public_key,
expires_at_sec,
issued_at_sec,
signature,
)))
}
pub fn verify_trust_impl(
trust: Trust,
issuer_peer_id: String,
timestamp_sec: u64,
) -> Result<(), ServiceError> {
check_timestamp_tetraplets(&marine_rs_sdk::get_call_parameters(), 2)?;
let public_key = extract_public_key(issuer_peer_id)?;
trust_graph::Trust::verify(
&trust.try_into()?,
&public_key,
Duration::from_secs(timestamp_sec),
)?;
Ok(())
}
pub fn add_trust_impl(
trust: Trust,
issuer_peer_id: String,
timestamp_sec: u64,
) -> Result<u32, ServiceError> {
let public_key = extract_public_key(issuer_peer_id)?;
check_timestamp_tetraplets(&marine_rs_sdk::get_call_parameters(), 2)?;
if trust.issued_at > timestamp_sec {
return Err(ServiceError::InvalidTimestamp("Trust".to_string()));
}
let mut tg = get_data().lock();
tg.add_trust(
&trust.try_into()?,
public_key,
Duration::from_secs(timestamp_sec),
)
.map_err(ServiceError::TGError)
}
pub fn get_revoke_bytes_impl(
revoked_peer_id: String,
revoked_at: u64,
) -> Result<Vec<u8>, ServiceError> {
let public_key = extract_public_key(revoked_peer_id)?;
Ok(trust_graph::Revoke::signature_bytes(
&public_key,
Duration::from_secs(revoked_at),
))
}
pub fn issue_revocation_impl(
revoked_peer_id: String,
revoked_by_peer_id: String,
revoked_at_sec: u64,
signature_bytes: Vec<u8>,
) -> Result<Revoke, ServiceError> {
let revoked_pk = extract_public_key(revoked_peer_id)?;
let revoked_by_pk = extract_public_key(revoked_by_peer_id)?;
let revoked_at = Duration::from_secs(revoked_at_sec);
let signature = Signature::from_bytes(revoked_by_pk.get_key_format(), signature_bytes);
Ok(trust_graph::Revoke::new(revoked_pk, revoked_by_pk, revoked_at, signature).into())
}
pub fn revoke_impl(revoke: Revoke, timestamp_sec: u64) -> Result<(), ServiceError> {
check_timestamp_tetraplets(&marine_rs_sdk::get_call_parameters(), 1)?;
if revoke.revoked_at > timestamp_sec {
return Err(ServiceError::InvalidTimestamp("Revoke".to_string()));
}
let mut tg = get_data().lock();
tg.revoke(revoke.try_into()?).map_err(ServiceError::TGError)
}

View File

@ -10,8 +10,6 @@ use core::convert::TryFrom;
use fluence_keypair::error::DecodingError;
use fluence_keypair::Signature;
use marine_sqlite_connector::{Connection, Error as InternalSqliteError, Value};
use once_cell::sync::OnceCell;
use parking_lot::Mutex;
use rmp_serde::decode::Error as RmpDecodeError;
use rmp_serde::encode::Error as RmpEncodeError;
use std::convert::From;
@ -19,16 +17,13 @@ use std::str::FromStr;
use std::time::Duration;
use thiserror::Error as ThisError;
use trust_graph::{
Auth, PublicKeyHashable as PK, PublicKeyHashable, Revoke, Storage, StorageError, Trust,
TrustGraph, TrustRelation, WeightFactor,
Auth, PublicKeyHashable as PK, PublicKeyHashable, Revocation, Storage, StorageError, Trust,
TrustRelation, WeightFactor,
};
#[allow(dead_code)]
static INSTANCE: OnceCell<Mutex<TrustGraph<SQLiteStorage>>> = OnceCell::new();
static AUTH_TYPE: i64 = 0;
static REVOKE_TYPE: i64 = 1;
pub static DB_PATH: &str = "data/users12312233.sqlite";
static REVOCATION_TYPE: i64 = 1;
pub static DB_PATH: &str = "/tmp/trust-graph.sqlite";
pub fn create_tables() {
let connection = marine_sqlite_connector::open(DB_PATH).unwrap();
@ -56,14 +51,6 @@ pub fn create_tables() {
.unwrap();
}
#[allow(dead_code)]
pub fn get_data() -> &'static Mutex<TrustGraph<SQLiteStorage>> {
INSTANCE.get_or_init(|| {
let connection = marine_sqlite_connector::open(DB_PATH).unwrap();
Mutex::new(TrustGraph::new(SQLiteStorage::new(connection)))
})
}
pub struct SQLiteStorage {
connection: Connection,
}
@ -85,7 +72,7 @@ impl SQLiteStorage {
}
}
Some(TrustRelation::Revoke(revoke)) => {
Some(TrustRelation::Revocation(revoke)) => {
if revoke.revoked_at < relation.issued_at() {
self.insert(relation)?;
}
@ -98,6 +85,35 @@ impl SQLiteStorage {
Ok(())
}
fn get_relations(
&self,
issued_for: &PublicKeyHashable,
relation_type: i64,
) -> Result<Vec<TrustRelation>, SQLiteStorageError> {
let mut cursor = self
.connection
.prepare(
"SELECT relation_type, issued_for, issued_by, issued_at, expires_at, signature \
FROM trust_relations WHERE issued_for = ? and relation_type = ?",
)?
.cursor();
cursor.bind(&[
Value::String(format!("{}", issued_for)),
Value::Integer(relation_type),
])?;
let mut relations: Vec<TrustRelation> = vec![];
while let Some(row) = cursor.next()? {
match parse_relation(row) {
Ok(r) => relations.push(r),
Err(e) => log::error!("parse_relation: {:?}", e),
}
}
Ok(relations)
}
}
#[derive(ThisError, Debug)]
@ -156,7 +172,7 @@ fn parse_relation(row: &[Value]) -> Result<TrustRelation, SQLiteStorageError> {
issued_by: issued_by.into(),
}))
} else {
Ok(TrustRelation::Revoke(Revoke {
Ok(TrustRelation::Revocation(Revocation {
pk: issued_for.into(),
revoked_at: issued_at,
revoked_by: issued_by.into(),
@ -202,25 +218,34 @@ impl Storage for SQLiteStorage {
}
/// return all auths issued for pk
fn get_authorizations(&self, pk: &PublicKeyHashable) -> Result<Vec<Auth>, Self::Error> {
let mut cursor = self
.connection
.prepare(
"SELECT relation_type, issued_for, issued_by, issued_at, expires_at, signature \
FROM trust_relations WHERE issued_for = ? and relation_type = ?",
)?
.cursor();
fn get_authorizations(&self, issued_for: &PublicKeyHashable) -> Result<Vec<Auth>, Self::Error> {
Ok(self
.get_relations(issued_for, AUTH_TYPE)?
.into_iter()
.fold(vec![], |mut acc, r| {
if let TrustRelation::Auth(a) = r {
acc.push(a);
}
cursor.bind(&[Value::String(format!("{}", pk)), Value::Integer(AUTH_TYPE)])?;
let mut auths: Vec<Auth> = vec![];
acc
}))
}
while let Some(row) = cursor.next()? {
if let TrustRelation::Auth(auth) = parse_relation(row)? {
auths.push(auth);
}
}
/// return all revocations issued for pk
fn get_revocations(
&self,
issued_for: &PublicKeyHashable,
) -> Result<Vec<Revocation>, Self::Error> {
Ok(self
.get_relations(issued_for, REVOCATION_TYPE)?
.into_iter()
.fold(vec![], |mut acc, r| {
if let TrustRelation::Revocation(revocation) = r {
acc.push(revocation);
}
Ok(auths)
acc
}))
}
fn insert(&mut self, relation: TrustRelation) -> Result<(), Self::Error> {
@ -230,7 +255,7 @@ impl Storage for SQLiteStorage {
let relation_type = match relation {
TrustRelation::Auth(_) => AUTH_TYPE,
TrustRelation::Revoke(_) => REVOKE_TYPE,
TrustRelation::Revocation(_) => REVOCATION_TYPE,
};
statement.bind(1, &Value::Integer(relation_type))?;
@ -296,7 +321,6 @@ impl Storage for SQLiteStorage {
let mut roots = vec![];
while let Some(row) = cursor.next()? {
log::info!("row: {:?}", row);
let pk = row[0].as_string().ok_or(PublicKeyConversion)?;
let pk: PK = PK::from_str(pk).map_err(|e| PublicKeyFromStr(e.to_string()))?;
@ -306,8 +330,8 @@ impl Storage for SQLiteStorage {
Ok(roots)
}
fn revoke(&mut self, revoke: Revoke) -> Result<(), Self::Error> {
self.update_relation(TrustRelation::Revoke(revoke))
fn revoke(&mut self, revoke: Revocation) -> Result<(), Self::Error> {
self.update_relation(TrustRelation::Revocation(revoke))
}
fn update_auth(&mut self, auth: Auth, _cur_time: Duration) -> Result<(), Self::Error> {

View File

@ -17,14 +17,13 @@
#[cfg(test)]
mod service_tests {
marine_rs_sdk_test::include_test_env!("/marine_test_env.rs");
use crate::service_impl::{
ServiceError, TRUSTED_TIMESTAMP_FUNCTION_NAME, TRUSTED_TIMESTAMP_SERVICE_ID,
};
use crate::error::ServiceError;
use crate::storage_impl::DB_PATH;
use crate::TRUSTED_TIMESTAMP;
use fluence_keypair::KeyPair;
use libp2p_core::PeerId;
use marine_rs_sdk::{CallParameters, SecurityTetraplet};
use marine_test_env::trust_graph::{Certificate, Revoke, ServiceInterface, Trust};
use marine_test_env::trust_graph::{Certificate, Revocation, ServiceInterface, Trust};
use rusqlite::Connection;
use std::collections::HashMap;
use std::time::{SystemTime, UNIX_EPOCH};
@ -80,8 +79,8 @@ mod service_tests {
cp.tetraplets.push(vec![SecurityTetraplet {
peer_pk: host_id,
service_id: TRUSTED_TIMESTAMP_SERVICE_ID.to_string(),
function_name: TRUSTED_TIMESTAMP_FUNCTION_NAME.to_string(),
service_id: TRUSTED_TIMESTAMP.0.to_string(),
function_name: TRUSTED_TIMESTAMP.1.to_string(),
json_path: "".to_string(),
}]);
@ -201,8 +200,8 @@ mod service_tests {
issuer_kp: &KeyPair,
revoked_peer_id: &PeerId,
revoked_at_sec: u64,
) -> Revoke {
let result = trust_graph.get_revoke_bytes(revoked_peer_id.to_base58(), revoked_at_sec);
) -> Revocation {
let result = trust_graph.get_revocation_bytes(revoked_peer_id.to_base58(), revoked_at_sec);
assert!(result.success, "{}", result.error);
let revoke_bytes = issuer_kp.sign(&result.result).unwrap().to_vec().to_vec();
@ -215,14 +214,14 @@ mod service_tests {
assert!(issue_result.success, "{}", issue_result.error);
let revoke_result = trust_graph.revoke_cp(
issue_result.revoke.clone(),
issue_result.revocation.clone(),
revoked_at_sec,
get_correct_timestamp_cp(1),
);
assert!(revoke_result.success, "{}", revoke_result.error);
issue_result.revoke
issue_result.revocation
}
fn generate_trust_chain_with(
@ -437,39 +436,98 @@ mod service_tests {
assert_eq!(certs.len(), 0);
}
/// 1. peer `A` gives trusts to `B`
/// 2. weight of `B` is not 0
/// 3. peer `A` revokes `B`
/// 4. there is no path from `A` to `B`, weight of `A` is 0
#[test]
fn revoke_test() {
fn trust_direct_revoke_test() {
let mut trust_graph = marine_test_env::trust_graph::ServiceInterface::new();
clear_env();
let root_kp = KeyPair::generate_ed25519();
let peerA_kp = KeyPair::generate_ed25519();
let mut cur_time = 100u64;
add_root_with_trust(&mut trust_graph, &root_kp, cur_time, cur_time + 9999, 4u32);
add_root_with_trust(&mut trust_graph, &peerA_kp, cur_time, cur_time + 9999, 4u32);
let trust_kp = KeyPair::generate_ed25519();
let peerB_kp = KeyPair::generate_ed25519();
add_trust(
&mut trust_graph,
&root_kp,
&trust_kp.get_peer_id(),
&peerA_kp,
&peerB_kp.get_peer_id(),
cur_time,
cur_time + 99999,
);
let weight = get_weight(&mut trust_graph, trust_kp.get_peer_id(), cur_time);
let weight = get_weight(&mut trust_graph, peerB_kp.get_peer_id(), cur_time);
assert_ne!(weight, 0u32);
cur_time += 1;
// A revokes B and cancels trust
revoke(
&mut trust_graph,
&root_kp,
&trust_kp.get_peer_id(),
&peerA_kp,
&peerB_kp.get_peer_id(),
cur_time,
);
let weight = get_weight(&mut trust_graph, trust_kp.get_peer_id(), cur_time);
let weight = get_weight(&mut trust_graph, peerB_kp.get_peer_id(), cur_time);
assert_eq!(weight, 0u32);
}
/// There is chain of trusts [0] -> [1] -> [2] -> [3] -> [4]
/// 1. [1] revokes [4]
/// 2. there is no path from [0] to [4], weight of [4] is 0
/// 3. [0] gives trust to [2]
/// 4. now there is path [0] -> [2] -> [3] -> [4]
/// 5. weight of [4] is not 0
#[test]
fn indirect_revoke_test() {
let mut trust_graph = marine_test_env::trust_graph::ServiceInterface::new();
clear_env();
let (key_pairs, trusts) =
generate_trust_chain_with_len(&mut trust_graph, 5, HashMap::new());
let mut cur_time = current_time();
let root_peer_id = key_pairs[0].get_peer_id();
add_root_peer_id(&mut trust_graph, root_peer_id, 2);
add_trusts(&mut trust_graph, &trusts, cur_time);
let target_peer_id = key_pairs[4].get_peer_id();
let revoked_by = &key_pairs[1];
let weight = get_weight(&mut trust_graph, target_peer_id, cur_time);
assert_ne!(weight, 0u32);
cur_time += 1;
// [1] revokes [4]
revoke(&mut trust_graph, &revoked_by, &target_peer_id, cur_time);
// now there are no path from root to [4]
let weight = get_weight(&mut trust_graph, target_peer_id, cur_time);
assert_eq!(weight, 0u32);
// [0] trusts [2]
add_trust(
&mut trust_graph,
&key_pairs[0],
&key_pairs[2].get_peer_id(),
cur_time,
cur_time + 99999,
);
// [2] trusts [4]
add_trust(
&mut trust_graph,
&key_pairs[2],
&target_peer_id,
cur_time,
cur_time + 99999,
);
// now we have [0] -> [2] -> [4] path
let weight = get_weight(&mut trust_graph, target_peer_id, cur_time);
assert_ne!(weight, 0u32);
}
#[test]
fn test_add_one_trust_to_cert_last() {
let mut trust_graph = ServiceInterface::new();
@ -780,7 +838,7 @@ mod service_tests {
add_trust_checked(&mut trust_graph, auth.trust.clone(), auth.issuer, cur_time);
}
let mut cp = get_correct_timestamp_cp_with_host_id(
let cp = get_correct_timestamp_cp_with_host_id(
0,
key_pairs.last().unwrap().get_peer_id().to_base58(),
);
@ -799,7 +857,7 @@ mod service_tests {
fn test_get_one_host_cert_from() {
let mut trust_graph = ServiceInterface::new();
clear_env();
let (key_pairs, mut trusts) =
let (key_pairs, trusts) =
generate_trust_chain_with_len(&mut trust_graph, 5, HashMap::new());
let cur_time = current_time();
@ -810,7 +868,7 @@ mod service_tests {
add_trust_checked(&mut trust_graph, auth.trust.clone(), auth.issuer, cur_time);
}
let mut cp = get_correct_timestamp_cp_with_host_id(
let cp = get_correct_timestamp_cp_with_host_id(
1,
key_pairs.last().unwrap().get_peer_id().to_base58(),
);

47
src/chain.rs Normal file
View File

@ -0,0 +1,47 @@
/*
* Copyright 2021 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::{Auth, PublicKeyHashable, Revocation};
use fluence_keypair::PublicKey;
use nonempty::NonEmpty;
use std::collections::HashSet;
#[derive(Clone)]
pub(crate) struct Chain {
pub(crate) auths: NonEmpty<Auth>,
revoked_by: HashSet<PublicKeyHashable>,
}
impl Chain {
pub(crate) fn new(auths: NonEmpty<Auth>, revocations: Vec<Revocation>) -> Self {
let mut chain = Self {
auths,
revoked_by: Default::default(),
};
chain.add_revocations(revocations);
chain
}
pub(crate) fn can_be_extended_by(&self, pk: &PublicKey) -> bool {
!self.revoked_by.contains(pk.as_ref())
&& !self.auths.iter().any(|a| a.trust.issued_for.eq(pk))
}
pub(crate) fn add_revocations(&mut self, revocations: Vec<Revocation>) {
revocations.into_iter().for_each(move |r| {
self.revoked_by.insert(r.revoked_by.into());
});
}
}

View File

@ -29,6 +29,7 @@
mod certificate;
pub mod certificate_serde;
mod chain;
mod misc;
mod public_key_hashable;
mod revoke;
@ -40,7 +41,7 @@ mod trust_relation;
pub use crate::certificate::{Certificate, CertificateError};
pub use crate::misc::current_time;
pub use crate::public_key_hashable::PublicKeyHashable;
pub use crate::revoke::Revoke;
pub use crate::revoke::Revocation;
pub use crate::trust::{Trust, TrustError};
pub use crate::trust_graph::{TrustGraph, TrustGraphError, WeightFactor, MAX_WEIGHT_FACTOR};
pub use crate::trust_graph_storage::{Storage, StorageError};

View File

@ -36,7 +36,7 @@ pub enum RevokeError {
/// "A document" that cancels trust created before.
/// TODO delete pk from Revoke (it is already in a trust node)
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Revoke {
pub struct Revocation {
/// who is revoked
pub pk: PublicKey,
/// date when revocation was created
@ -47,7 +47,7 @@ pub struct Revoke {
pub signature: Signature,
}
impl Revoke {
impl Revocation {
#[allow(dead_code)]
pub fn new(
pk: PublicKey,
@ -66,10 +66,10 @@ impl Revoke {
/// Creates new revocation signed by a revoker.
#[allow(dead_code)]
pub fn create(revoker: &KeyPair, to_revoke: PublicKey, revoked_at: Duration) -> Self {
let msg = Revoke::signature_bytes(&to_revoke, revoked_at);
let msg = Revocation::signature_bytes(&to_revoke, revoked_at);
let signature = revoker.sign(&msg).unwrap();
Revoke::new(to_revoke, revoker.public(), revoked_at, signature)
Revocation::new(to_revoke, revoker.public(), revoked_at, signature)
}
pub fn signature_bytes(pk: &PublicKey, revoked_at: Duration) -> Vec<u8> {
@ -83,8 +83,8 @@ impl Revoke {
}
/// Verifies that revocation is cryptographically correct.
pub fn verify(revoke: &Revoke) -> Result<(), RevokeError> {
let msg = Revoke::signature_bytes(&revoke.pk, revoke.revoked_at);
pub fn verify(revoke: &Revocation) -> Result<(), RevokeError> {
let msg = Revocation::signature_bytes(&revoke.pk, revoke.revoked_at);
revoke
.revoked_by
@ -104,9 +104,9 @@ mod tests {
let duration = Duration::new(100, 0);
let revoke = Revoke::create(&revoker, to_revoke.public(), duration);
let revoke = Revocation::create(&revoker, to_revoke.public(), duration);
assert_eq!(Revoke::verify(&revoke).is_ok(), true);
assert_eq!(Revocation::verify(&revoke).is_ok(), true);
}
#[test]
@ -116,16 +116,16 @@ mod tests {
let duration = Duration::new(100, 0);
let revoke = Revoke::create(&revoker, to_revoke.public(), duration);
let revoke = Revocation::create(&revoker, to_revoke.public(), duration);
let duration2 = Duration::new(95, 0);
let corrupted_revoke = Revoke::new(
let corrupted_revoke = Revocation::new(
to_revoke.public(),
revoker.public(),
duration2,
revoke.signature,
);
assert_eq!(Revoke::verify(&corrupted_revoke).is_ok(), false);
assert_eq!(Revocation::verify(&corrupted_revoke).is_ok(), false);
}
}

View File

@ -16,8 +16,9 @@
use crate::certificate::CertificateError::CertificateLengthError;
use crate::certificate::{Certificate, CertificateError};
use crate::chain::Chain;
use crate::public_key_hashable::PublicKeyHashable as PK;
use crate::revoke::Revoke;
use crate::revoke::Revocation;
use crate::revoke::RevokeError;
use crate::trust::Trust;
use crate::trust_graph::TrustGraphError::{
@ -27,6 +28,7 @@ use crate::trust_graph_storage::Storage;
use crate::trust_relation::Auth;
use crate::{StorageError, TrustError};
use fluence_keypair::public_key::PublicKey;
use nonempty::NonEmpty;
use std::borrow::Borrow;
use std::collections::{HashSet, VecDeque};
use std::convert::{From, Into};
@ -93,7 +95,7 @@ impl From<TrustGraphError> for String {
}
pub fn get_weight_from_factor(wf: WeightFactor) -> u32 {
2u32.pow(MAX_WEIGHT_FACTOR.checked_sub(wf).unwrap_or(0u32))
2u32.pow(MAX_WEIGHT_FACTOR.saturating_sub(wf))
}
impl<S> TrustGraph<S>
@ -245,12 +247,14 @@ where
roots: HashSet<&PK>,
) -> Result<Vec<Vec<Auth>>, TrustGraphError> {
// queue to collect all chains in the trust graph (each chain is a path in the trust graph)
let mut chains_queue: VecDeque<Vec<Auth>> = VecDeque::new();
let mut chains_queue: VecDeque<Chain> = VecDeque::new();
let node_auths: Vec<Auth> = self.storage.get_authorizations(pk)?;
let node_revocations = self.storage.get_revocations(pk)?;
// put all auth in the queue as the first possible paths through the graph
for auth in node_auths {
chains_queue.push_back(vec![auth]);
chains_queue.push_back(Chain::new(NonEmpty::new(auth), node_revocations.clone()));
}
// List of all chains that converge (terminate) to known roots
@ -261,22 +265,21 @@ where
.pop_front()
.expect("`chains_queue` always has at least one element");
let last = cur_chain
.last()
.expect("`cur_chain` always has at least one element");
let last = cur_chain.auths.last();
let auths = self
.storage
.get_authorizations(&last.issued_by.clone().into())?;
for auth in auths {
// if there is auth, that we not visited in the current chain, copy chain and append this auth
if !cur_chain
.iter()
.any(|a| a.trust.issued_for == auth.issued_by)
{
// if there is auth, that we not visited in the current chain and no revocations to any chain member -- copy chain and append this auth
if cur_chain.can_be_extended_by(&auth.issued_by) {
let mut new_chain = cur_chain.clone();
new_chain.push(auth);
new_chain.add_revocations(
self.storage
.get_revocations(&auth.issued_by.clone().into())?,
);
new_chain.auths.push(auth);
chains_queue.push_back(new_chain);
}
}
@ -289,8 +292,8 @@ where
let issued_by: &PK = last.issued_by.as_ref();
let converges_to_root = roots.contains(issued_by);
if self_signed && converges_to_root && cur_chain.len() > 1 {
terminated_chains.push(cur_chain);
if self_signed && converges_to_root && cur_chain.auths.len() > 1 {
terminated_chains.push(cur_chain.auths.into());
}
}
@ -334,9 +337,11 @@ where
}
/// Mark public key as revoked.
pub fn revoke(&mut self, revoke: Revoke) -> Result<(), TrustGraphError> {
Revoke::verify(&revoke)?;
/// Every chain that contains path from `revoked_by` to revoked `pk`
/// will be excluded from valid certificates until revocation canceled by giving trust
pub fn revoke(&mut self, revocation: Revocation) -> Result<(), TrustGraphError> {
Revocation::verify(&revocation)?;
Ok(self.storage.revoke(revoke)?)
Ok(self.storage.revoke(revocation)?)
}
}

View File

@ -1,5 +1,5 @@
use crate::public_key_hashable::PublicKeyHashable as PK;
use crate::revoke::Revoke;
use crate::revoke::Revocation;
use crate::trust_graph::WeightFactor;
use crate::trust_relation::{Auth, TrustRelation};
use std::fmt::Display;
@ -16,13 +16,15 @@ pub trait Storage {
issued_by: &PK,
) -> Result<Option<TrustRelation>, Self::Error>;
fn get_authorizations(&self, pk: &PK) -> Result<Vec<Auth>, Self::Error>;
fn get_authorizations(&self, issued_for: &PK) -> Result<Vec<Auth>, Self::Error>;
fn get_revocations(&self, issued_for: &PK) -> Result<Vec<Revocation>, Self::Error>;
fn insert(&mut self, node: TrustRelation) -> Result<(), Self::Error>;
fn get_root_weight_factor(&self, pk: &PK) -> Result<Option<WeightFactor>, Self::Error>;
fn add_root_weight_factor(&mut self, pk: PK, weight: WeightFactor) -> Result<(), Self::Error>;
fn root_keys(&self) -> Result<Vec<PK>, Self::Error>;
fn revoke(&mut self, revoke: Revoke) -> Result<(), Self::Error>;
fn revoke(&mut self, revocation: Revocation) -> Result<(), Self::Error>;
fn update_auth(&mut self, auth: Auth, cur_time: Duration) -> Result<(), Self::Error>;
fn remove_expired(&mut self, current_time: Duration) -> Result<(), Self::Error>;
}

View File

@ -1,206 +0,0 @@
/*
* Copyright 2020 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::public_key_hashable::PublicKeyHashable;
use crate::revoke::Revoke;
use crate::trust::Trust;
use failure::_core::time::Duration;
use fluence_keypair::public_key::PublicKey;
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
enum TrustRelation {
Auth(Auth),
Revoke(Revoke),
}
impl TrustRelation {
/// Returns timestamp of when this relation was created
pub fn issued_at(&self) -> Duration {
match self {
TrustRelation::Auth(auth) => auth.trust.issued_at,
TrustRelation::Revoke(revoke) => revoke.revoked_at,
}
}
/// Returns public key of the creator of this relation
pub fn issued_by(&self) -> &PublicKey {
match self {
TrustRelation::Auth(auth) => &auth.issued_by,
TrustRelation::Revoke(revoke) => &revoke.revoked_by,
}
}
}
/// Represents who give a certificate
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Auth {
/// proof of this authorization
pub trust: Trust,
/// the issuer of this authorization
pub issued_by: PublicKey,
}
/// An element of trust graph that store relations (trust or revoke)
/// that given by some owners of public keys.
#[serde_as]
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct TrustNode {
/// identity key of this element
pub pk: PublicKey,
/// one public key could be authorized or revoked by multiple certificates
#[serde_as(as = "Vec<(_, _)>")]
trust_relations: HashMap<PublicKeyHashable, TrustRelation>,
/// for maintain
pub verified_at: Duration,
}
#[allow(dead_code)]
impl TrustNode {
pub fn new(pk: PublicKey, verified_at: Duration) -> Self {
Self {
pk,
trust_relations: HashMap::new(),
verified_at,
}
}
pub fn get_auth(&self, pk: PublicKey) -> Option<Auth> {
match self.trust_relations.get(&pk.into()) {
Some(TrustRelation::Auth(auth)) => Some(auth.clone()),
_ => None,
}
}
pub fn get_revoke(&self, pk: PublicKey) -> Option<Revoke> {
match self.trust_relations.get(&pk.into()) {
Some(TrustRelation::Revoke(rev)) => Some(rev.clone()),
_ => None,
}
}
pub fn authorizations(&self) -> impl Iterator<Item = &Auth> + '_ {
self.trust_relations.values().filter_map(|tr| {
if let TrustRelation::Auth(auth) = tr {
Some(auth)
} else {
None
}
})
}
pub fn revocations(&self) -> impl Iterator<Item = &Revoke> + '_ {
self.trust_relations.values().filter_map(|tr| {
if let TrustRelation::Revoke(revoke) = tr {
Some(revoke)
} else {
None
}
})
}
/// Adds authorization. If the trust node already has this authorization,
/// add auth with later expiration date.
pub fn update_auth(&mut self, auth: Auth) {
self.update_relation(TrustRelation::Auth(auth));
}
// insert new trust relation, ignore if there is another one with same public key
fn insert(&mut self, pk: PublicKeyHashable, tr: TrustRelation) {
self.trust_relations.insert(pk, tr);
}
fn update_relation(&mut self, relation: TrustRelation) {
let issued_by = relation.issued_by().as_ref();
match self.trust_relations.get(issued_by) {
Some(TrustRelation::Auth(auth)) => {
if auth.trust.issued_at < relation.issued_at() {
self.insert(issued_by.clone(), relation)
}
}
Some(TrustRelation::Revoke(existed_revoke)) => {
if existed_revoke.revoked_at < relation.issued_at() {
self.insert(issued_by.clone(), relation)
}
}
None => self.insert(issued_by.clone(), relation),
};
}
pub fn update_revoke(&mut self, revoke: Revoke) {
self.update_relation(TrustRelation::Revoke(revoke));
}
}
#[cfg(test)]
mod tests {
use std::time::Duration;
use fluence_keypair::key_pair::KeyPair;
use super::*;
#[test]
fn test_auth_and_revoke_trust_node() {
let kp = KeyPair::generate_ed25519();
let now = Duration::new(50, 0);
let past = Duration::new(5, 0);
let future = Duration::new(500, 0);
let mut trust_node = TrustNode {
pk: kp.public(),
trust_relations: HashMap::new(),
verified_at: now,
};
let truster = KeyPair::generate_ed25519();
let revoke = Revoke::create(&truster, kp.public(), now);
trust_node.update_revoke(revoke);
assert!(trust_node.get_revoke(truster.public()).is_some());
let old_trust = Trust::create(&truster, kp.public(), Duration::new(60, 0), past);
let old_auth = Auth {
trust: old_trust,
issued_by: truster.public(),
};
trust_node.update_auth(old_auth);
assert!(trust_node.get_revoke(truster.public()).is_some());
assert!(trust_node.get_auth(truster.public()).is_none());
let trust = Trust::create(&truster, kp.public(), Duration::new(60, 0), future);
let auth = Auth {
trust,
issued_by: truster.public(),
};
trust_node.update_auth(auth);
assert!(trust_node.get_auth(truster.public()).is_some());
assert!(trust_node.get_revoke(truster.public()).is_none());
}
}

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
use crate::revoke::Revoke;
use crate::revoke::Revocation;
use crate::trust::Trust;
use failure::_core::time::Duration;
use fluence_keypair::public_key::PublicKey;
@ -33,7 +33,7 @@ pub struct Auth {
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum TrustRelation {
Auth(Auth),
Revoke(Revoke),
Revocation(Revocation),
}
impl TrustRelation {
@ -41,7 +41,7 @@ impl TrustRelation {
pub fn issued_at(&self) -> Duration {
match self {
TrustRelation::Auth(auth) => auth.trust.issued_at,
TrustRelation::Revoke(revoke) => revoke.revoked_at,
TrustRelation::Revocation(r) => r.revoked_at,
}
}
@ -49,28 +49,29 @@ impl TrustRelation {
pub fn issued_by(&self) -> &PublicKey {
match self {
TrustRelation::Auth(auth) => &auth.issued_by,
TrustRelation::Revoke(revoke) => &revoke.revoked_by,
TrustRelation::Revocation(r) => &r.revoked_by,
}
}
pub fn issued_for(&self) -> &PublicKey {
match self {
TrustRelation::Auth(auth) => &auth.trust.issued_for,
TrustRelation::Revoke(revoke) => &revoke.pk,
TrustRelation::Revocation(r) => &r.pk,
}
}
pub fn expires_at(&self) -> Duration {
match self {
TrustRelation::Auth(auth) => auth.trust.expires_at,
TrustRelation::Revoke(_) => Duration::from_secs(0),
// revocations never expire
TrustRelation::Revocation(_) => Duration::from_secs(0),
}
}
pub fn signature(&self) -> &Signature {
match self {
TrustRelation::Auth(auth) => &auth.trust.signature,
TrustRelation::Revoke(revoke) => &revoke.signature,
TrustRelation::Revocation(r) => &r.signature,
}
}
}