├── .github ├── nix.conf └── workflows │ └── main.yml ├── .gitignore ├── .huskyrc ├── Cargo.lock ├── Cargo.toml ├── DESIGN.md ├── LICENSE ├── README.md ├── default.nix ├── dna ├── workdir │ ├── dna │ │ └── dna.yaml │ └── happ │ │ └── happ.yaml └── zomes │ ├── attestations │ ├── Cargo.toml │ └── src │ │ ├── attestation.rs │ │ ├── error.rs │ │ ├── lib.rs │ │ ├── nonce.rs │ │ └── signals.rs │ ├── attestations_core │ ├── Cargo.toml │ └── src │ │ └── lib.rs │ ├── profiles │ ├── Cargo.toml │ └── src │ │ └── lib.rs │ └── profiles_core │ ├── Cargo.toml │ └── src │ └── lib.rs ├── nix ├── sources.json └── sources.nix ├── package-lock.json ├── package.json ├── tests ├── .gitignore ├── package.json ├── src │ ├── index.ts │ └── profile.ts └── tsconfig.json ├── tsconfig.json ├── ui ├── apps │ └── attestations │ │ ├── .gitignore │ │ ├── index.html │ │ ├── package.json │ │ ├── rollup.config.js │ │ ├── src │ │ ├── attestations-app.ts │ │ └── index.ts │ │ ├── tsconfig.json │ │ └── web-dev-server.config.mjs └── lib │ ├── .editorconfig │ ├── .eslintrc.js │ ├── .gitignore │ ├── package.json │ ├── rollup.config.js │ ├── src │ ├── attestations.service.ts │ ├── attestations.store.ts │ ├── elements │ │ ├── attestation-folk.ts │ │ ├── attestations-attestation-dialog.ts │ │ ├── attestations-attestation.ts │ │ ├── attestations-controller.ts │ │ ├── attestations-notify-dialog.ts │ │ ├── copiable-content.ts │ │ └── verify-attestation.ts │ ├── index.ts │ ├── sharedStyles.ts │ └── types.ts │ └── tsconfig.json └── workdir └── web-happ.yaml /.github/nix.conf: -------------------------------------------------------------------------------- 1 | substituters = https://cache.nixos.org/ https://cache.holo.host/ 2 | trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= cache.holo.host-1:lNXIXtJgS9Iuw4Cu6X0HINLu9sTfcjEntnrgwMQIMcE= cache.holo.host-2:ZJCkX3AUYZ8soxTLfTb60g+F3MkWD7hkH9y8CgqwhDQ= 3 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: CI 4 | 5 | # Controls when the action will run. Triggers the workflow on push or pull request 6 | # events but only for the main branch 7 | on: 8 | push: 9 | branches: [ main ] 10 | pull_request: 11 | branches: [ main ] 12 | 13 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 14 | jobs: 15 | # This workflow contains a single job called "build" 16 | build-and-test: 17 | runs-on: ubuntu-latest 18 | 19 | # Steps represent a sequence of tasks that will be executed as part of the job 20 | steps: 21 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 22 | # Checks out a copy of your repository on the ubuntu-latest machine 23 | 24 | 25 | - name: Fetch source code 26 | uses: actions/checkout@v2 27 | - name: Use Nix 28 | uses: cachix/install-nix-action@v12 29 | - name: Use Node.js ${{ matrix.node-version }} 30 | uses: actions/setup-node@v1 31 | with: 32 | node-version: ${{ matrix.node-version }} 33 | - name: Configure Nix substituters 34 | run: | 35 | set -xe 36 | mkdir -p ~/.config/nix/ 37 | cp ./.github/nix.conf ~/.config/nix/ 38 | - name: Use cachix 39 | uses: cachix/cachix-action@v10 40 | with: 41 | name: holochain-ci 42 | 43 | - name: Prepare Nix environment 44 | run: | 45 | nix-env -iA cachix -f https://cachix.org/api/v1/install 46 | cachix use holochain-ci 47 | nix-shell --command "echo Completed" 48 | 49 | - name: run-tests 50 | run: | 51 | cd $GITHUB_WORKSPACE 52 | nix-shell . --run "npm ci && npm run test" 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## editors 2 | /.idea 3 | /.vscode 4 | .swp 5 | 6 | ## system files 7 | .DS_Store 8 | 9 | target/ 10 | node_modules/ 11 | dist/ 12 | .cargo/ 13 | .hc* 14 | dna/workdir/dna/*.dna 15 | dna/workdir/happ/*.happ 16 | workdir/*.webhapp 17 | *.tsbuildinfo 18 | .running -------------------------------------------------------------------------------- /.huskyrc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightningrodlabs/attestations/3813fbff9bc6144cfaeccba907e5af4d5a0a61fd/.huskyrc -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.17.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "ahash" 22 | version = "0.7.6" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" 25 | dependencies = [ 26 | "getrandom", 27 | "once_cell", 28 | "version_check", 29 | ] 30 | 31 | [[package]] 32 | name = "android_system_properties" 33 | version = "0.1.4" 34 | source = "registry+https://github.com/rust-lang/crates.io-index" 35 | checksum = "d7ed72e1635e121ca3e79420540282af22da58be50de153d36f81ddc6b83aa9e" 36 | dependencies = [ 37 | "libc", 38 | ] 39 | 40 | [[package]] 41 | name = "arrayref" 42 | version = "0.3.6" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" 45 | 46 | [[package]] 47 | name = "arrayvec" 48 | version = "0.5.2" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" 51 | 52 | [[package]] 53 | name = "attestations" 54 | version = "0.0.1-alpha1" 55 | dependencies = [ 56 | "attestations_core", 57 | "chrono", 58 | "derive_more", 59 | "hdk", 60 | "serde", 61 | "thiserror", 62 | ] 63 | 64 | [[package]] 65 | name = "attestations_core" 66 | version = "0.0.1-alpha1" 67 | dependencies = [ 68 | "derive_more", 69 | "hdi", 70 | "hdk", 71 | "serde", 72 | ] 73 | 74 | [[package]] 75 | name = "autocfg" 76 | version = "1.1.0" 77 | source = "registry+https://github.com/rust-lang/crates.io-index" 78 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 79 | 80 | [[package]] 81 | name = "backtrace" 82 | version = "0.3.65" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" 85 | dependencies = [ 86 | "addr2line", 87 | "cc", 88 | "cfg-if", 89 | "libc", 90 | "miniz_oxide", 91 | "object", 92 | "rustc-demangle", 93 | ] 94 | 95 | [[package]] 96 | name = "base64" 97 | version = "0.13.0" 98 | source = "registry+https://github.com/rust-lang/crates.io-index" 99 | checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" 100 | 101 | [[package]] 102 | name = "bit-set" 103 | version = "0.5.2" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de" 106 | dependencies = [ 107 | "bit-vec", 108 | ] 109 | 110 | [[package]] 111 | name = "bit-vec" 112 | version = "0.6.3" 113 | source = "registry+https://github.com/rust-lang/crates.io-index" 114 | checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" 115 | 116 | [[package]] 117 | name = "bitflags" 118 | version = "1.3.2" 119 | source = "registry+https://github.com/rust-lang/crates.io-index" 120 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 121 | 122 | [[package]] 123 | name = "blake2b_simd" 124 | version = "0.5.11" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" 127 | dependencies = [ 128 | "arrayref", 129 | "arrayvec", 130 | "constant_time_eq", 131 | ] 132 | 133 | [[package]] 134 | name = "bumpalo" 135 | version = "3.10.0" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" 138 | 139 | [[package]] 140 | name = "bytecheck" 141 | version = "0.6.8" 142 | source = "registry+https://github.com/rust-lang/crates.io-index" 143 | checksum = "3a31f923c2db9513e4298b72df143e6e655a759b3d6a0966df18f81223fff54f" 144 | dependencies = [ 145 | "bytecheck_derive", 146 | "ptr_meta", 147 | ] 148 | 149 | [[package]] 150 | name = "bytecheck_derive" 151 | version = "0.6.8" 152 | source = "registry+https://github.com/rust-lang/crates.io-index" 153 | checksum = "edb17c862a905d912174daa27ae002326fff56dc8b8ada50a0a5f0976cb174f0" 154 | dependencies = [ 155 | "proc-macro2", 156 | "quote", 157 | "syn", 158 | ] 159 | 160 | [[package]] 161 | name = "byteorder" 162 | version = "1.4.3" 163 | source = "registry+https://github.com/rust-lang/crates.io-index" 164 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 165 | 166 | [[package]] 167 | name = "cc" 168 | version = "1.0.73" 169 | source = "registry+https://github.com/rust-lang/crates.io-index" 170 | checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" 171 | 172 | [[package]] 173 | name = "cfg-if" 174 | version = "1.0.0" 175 | source = "registry+https://github.com/rust-lang/crates.io-index" 176 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 177 | 178 | [[package]] 179 | name = "chrono" 180 | version = "0.4.22" 181 | source = "registry+https://github.com/rust-lang/crates.io-index" 182 | checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" 183 | dependencies = [ 184 | "iana-time-zone", 185 | "num-integer", 186 | "num-traits", 187 | "serde", 188 | "time", 189 | "winapi", 190 | ] 191 | 192 | [[package]] 193 | name = "constant_time_eq" 194 | version = "0.1.5" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" 197 | 198 | [[package]] 199 | name = "convert_case" 200 | version = "0.4.0" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" 203 | 204 | [[package]] 205 | name = "core-foundation-sys" 206 | version = "0.8.3" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" 209 | 210 | [[package]] 211 | name = "corosensei" 212 | version = "0.1.3" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | checksum = "9847f90f32a50b0dcbd68bc23ff242798b13080b97b0569f6ed96a45ce4cf2cd" 215 | dependencies = [ 216 | "autocfg", 217 | "cfg-if", 218 | "libc", 219 | "scopeguard", 220 | "windows-sys 0.33.0", 221 | ] 222 | 223 | [[package]] 224 | name = "cranelift-bforest" 225 | version = "0.82.3" 226 | source = "registry+https://github.com/rust-lang/crates.io-index" 227 | checksum = "38faa2a16616c8e78a18d37b4726b98bfd2de192f2fdc8a39ddf568a408a0f75" 228 | dependencies = [ 229 | "cranelift-entity", 230 | ] 231 | 232 | [[package]] 233 | name = "cranelift-codegen" 234 | version = "0.82.3" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | checksum = "26f192472a3ba23860afd07d2b0217dc628f21fcc72617aa1336d98e1671f33b" 237 | dependencies = [ 238 | "cranelift-bforest", 239 | "cranelift-codegen-meta", 240 | "cranelift-codegen-shared", 241 | "cranelift-entity", 242 | "gimli", 243 | "log", 244 | "regalloc", 245 | "smallvec", 246 | "target-lexicon", 247 | ] 248 | 249 | [[package]] 250 | name = "cranelift-codegen-meta" 251 | version = "0.82.3" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | checksum = "0f32ddb89e9b89d3d9b36a5b7d7ea3261c98235a76ac95ba46826b8ec40b1a24" 254 | dependencies = [ 255 | "cranelift-codegen-shared", 256 | ] 257 | 258 | [[package]] 259 | name = "cranelift-codegen-shared" 260 | version = "0.82.3" 261 | source = "registry+https://github.com/rust-lang/crates.io-index" 262 | checksum = "01fd0d9f288cc1b42d9333b7a776b17e278fc888c28e6a0f09b5573d45a150bc" 263 | 264 | [[package]] 265 | name = "cranelift-entity" 266 | version = "0.82.3" 267 | source = "registry+https://github.com/rust-lang/crates.io-index" 268 | checksum = "9e3bfe172b83167604601faf9dc60453e0d0a93415b57a9c4d1a7ae6849185cf" 269 | 270 | [[package]] 271 | name = "cranelift-frontend" 272 | version = "0.82.3" 273 | source = "registry+https://github.com/rust-lang/crates.io-index" 274 | checksum = "a006e3e32d80ce0e4ba7f1f9ddf66066d052a8c884a110b91d05404d6ce26dce" 275 | dependencies = [ 276 | "cranelift-codegen", 277 | "log", 278 | "smallvec", 279 | "target-lexicon", 280 | ] 281 | 282 | [[package]] 283 | name = "crc32fast" 284 | version = "1.3.2" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" 287 | dependencies = [ 288 | "cfg-if", 289 | ] 290 | 291 | [[package]] 292 | name = "crossbeam-channel" 293 | version = "0.5.5" 294 | source = "registry+https://github.com/rust-lang/crates.io-index" 295 | checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c" 296 | dependencies = [ 297 | "cfg-if", 298 | "crossbeam-utils", 299 | ] 300 | 301 | [[package]] 302 | name = "crossbeam-deque" 303 | version = "0.8.1" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" 306 | dependencies = [ 307 | "cfg-if", 308 | "crossbeam-epoch", 309 | "crossbeam-utils", 310 | ] 311 | 312 | [[package]] 313 | name = "crossbeam-epoch" 314 | version = "0.9.9" 315 | source = "registry+https://github.com/rust-lang/crates.io-index" 316 | checksum = "07db9d94cbd326813772c968ccd25999e5f8ae22f4f8d1b11effa37ef6ce281d" 317 | dependencies = [ 318 | "autocfg", 319 | "cfg-if", 320 | "crossbeam-utils", 321 | "memoffset", 322 | "once_cell", 323 | "scopeguard", 324 | ] 325 | 326 | [[package]] 327 | name = "crossbeam-utils" 328 | version = "0.8.10" 329 | source = "registry+https://github.com/rust-lang/crates.io-index" 330 | checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83" 331 | dependencies = [ 332 | "cfg-if", 333 | "once_cell", 334 | ] 335 | 336 | [[package]] 337 | name = "darling" 338 | version = "0.13.4" 339 | source = "registry+https://github.com/rust-lang/crates.io-index" 340 | checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" 341 | dependencies = [ 342 | "darling_core 0.13.4", 343 | "darling_macro 0.13.4", 344 | ] 345 | 346 | [[package]] 347 | name = "darling" 348 | version = "0.14.1" 349 | source = "registry+https://github.com/rust-lang/crates.io-index" 350 | checksum = "4529658bdda7fd6769b8614be250cdcfc3aeb0ee72fe66f9e41e5e5eb73eac02" 351 | dependencies = [ 352 | "darling_core 0.14.1", 353 | "darling_macro 0.14.1", 354 | ] 355 | 356 | [[package]] 357 | name = "darling_core" 358 | version = "0.13.4" 359 | source = "registry+https://github.com/rust-lang/crates.io-index" 360 | checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" 361 | dependencies = [ 362 | "fnv", 363 | "ident_case", 364 | "proc-macro2", 365 | "quote", 366 | "syn", 367 | ] 368 | 369 | [[package]] 370 | name = "darling_core" 371 | version = "0.14.1" 372 | source = "registry+https://github.com/rust-lang/crates.io-index" 373 | checksum = "649c91bc01e8b1eac09fb91e8dbc7d517684ca6be8ebc75bb9cafc894f9fdb6f" 374 | dependencies = [ 375 | "fnv", 376 | "ident_case", 377 | "proc-macro2", 378 | "quote", 379 | "strsim", 380 | "syn", 381 | ] 382 | 383 | [[package]] 384 | name = "darling_macro" 385 | version = "0.13.4" 386 | source = "registry+https://github.com/rust-lang/crates.io-index" 387 | checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" 388 | dependencies = [ 389 | "darling_core 0.13.4", 390 | "quote", 391 | "syn", 392 | ] 393 | 394 | [[package]] 395 | name = "darling_macro" 396 | version = "0.14.1" 397 | source = "registry+https://github.com/rust-lang/crates.io-index" 398 | checksum = "ddfc69c5bfcbd2fc09a0f38451d2daf0e372e367986a83906d1b0dbc88134fb5" 399 | dependencies = [ 400 | "darling_core 0.14.1", 401 | "quote", 402 | "syn", 403 | ] 404 | 405 | [[package]] 406 | name = "derive_more" 407 | version = "0.99.17" 408 | source = "registry+https://github.com/rust-lang/crates.io-index" 409 | checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" 410 | dependencies = [ 411 | "convert_case", 412 | "proc-macro2", 413 | "quote", 414 | "rustc_version", 415 | "syn", 416 | ] 417 | 418 | [[package]] 419 | name = "either" 420 | version = "1.7.0" 421 | source = "registry+https://github.com/rust-lang/crates.io-index" 422 | checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" 423 | 424 | [[package]] 425 | name = "enum-iterator" 426 | version = "0.7.0" 427 | source = "registry+https://github.com/rust-lang/crates.io-index" 428 | checksum = "4eeac5c5edb79e4e39fe8439ef35207780a11f69c52cbe424ce3dfad4cb78de6" 429 | dependencies = [ 430 | "enum-iterator-derive", 431 | ] 432 | 433 | [[package]] 434 | name = "enum-iterator-derive" 435 | version = "0.7.0" 436 | source = "registry+https://github.com/rust-lang/crates.io-index" 437 | checksum = "c134c37760b27a871ba422106eedbb8247da973a09e82558bf26d619c882b159" 438 | dependencies = [ 439 | "proc-macro2", 440 | "quote", 441 | "syn", 442 | ] 443 | 444 | [[package]] 445 | name = "enumset" 446 | version = "1.0.11" 447 | source = "registry+https://github.com/rust-lang/crates.io-index" 448 | checksum = "4799cdb24d48f1f8a7a98d06b7fde65a85a2d1e42b25a889f5406aa1fbefe074" 449 | dependencies = [ 450 | "enumset_derive", 451 | ] 452 | 453 | [[package]] 454 | name = "enumset_derive" 455 | version = "0.6.0" 456 | source = "registry+https://github.com/rust-lang/crates.io-index" 457 | checksum = "ea83a3fbdc1d999ccfbcbee717eab36f8edf2d71693a23ce0d7cca19e085304c" 458 | dependencies = [ 459 | "darling 0.13.4", 460 | "proc-macro2", 461 | "quote", 462 | "syn", 463 | ] 464 | 465 | [[package]] 466 | name = "fallible-iterator" 467 | version = "0.2.0" 468 | source = "registry+https://github.com/rust-lang/crates.io-index" 469 | checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" 470 | 471 | [[package]] 472 | name = "fastrand" 473 | version = "1.7.0" 474 | source = "registry+https://github.com/rust-lang/crates.io-index" 475 | checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" 476 | dependencies = [ 477 | "instant", 478 | ] 479 | 480 | [[package]] 481 | name = "fnv" 482 | version = "1.0.7" 483 | source = "registry+https://github.com/rust-lang/crates.io-index" 484 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 485 | 486 | [[package]] 487 | name = "gcollections" 488 | version = "1.5.0" 489 | source = "registry+https://github.com/rust-lang/crates.io-index" 490 | checksum = "2f551fdf23ef80329f754919669147a71c67b6cfe3569cd93b6fabdd62044377" 491 | dependencies = [ 492 | "bit-set", 493 | "num-integer", 494 | "num-traits", 495 | "trilean", 496 | ] 497 | 498 | [[package]] 499 | name = "getrandom" 500 | version = "0.2.7" 501 | source = "registry+https://github.com/rust-lang/crates.io-index" 502 | checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" 503 | dependencies = [ 504 | "cfg-if", 505 | "libc", 506 | "wasi", 507 | ] 508 | 509 | [[package]] 510 | name = "gimli" 511 | version = "0.26.1" 512 | source = "registry+https://github.com/rust-lang/crates.io-index" 513 | checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" 514 | dependencies = [ 515 | "fallible-iterator", 516 | "indexmap", 517 | "stable_deref_trait", 518 | ] 519 | 520 | [[package]] 521 | name = "hashbrown" 522 | version = "0.11.2" 523 | source = "registry+https://github.com/rust-lang/crates.io-index" 524 | checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" 525 | dependencies = [ 526 | "ahash", 527 | ] 528 | 529 | [[package]] 530 | name = "hashbrown" 531 | version = "0.12.1" 532 | source = "registry+https://github.com/rust-lang/crates.io-index" 533 | checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" 534 | dependencies = [ 535 | "ahash", 536 | ] 537 | 538 | [[package]] 539 | name = "hc_zome_profiles_coordinator" 540 | version = "0.0.1" 541 | source = "git+https://github.com/holochain-open-dev/profiles?rev=for-hdk-v0.0.163#a2f8a45e1b28cda530fceacfb67808dcfc275499" 542 | dependencies = [ 543 | "derive_more", 544 | "hc_zome_profiles_integrity", 545 | "hdk", 546 | "serde", 547 | ] 548 | 549 | [[package]] 550 | name = "hc_zome_profiles_integrity" 551 | version = "0.0.1" 552 | source = "git+https://github.com/holochain-open-dev/profiles?rev=for-hdk-v0.0.163#a2f8a45e1b28cda530fceacfb67808dcfc275499" 553 | dependencies = [ 554 | "derive_more", 555 | "hdi", 556 | "serde", 557 | ] 558 | 559 | [[package]] 560 | name = "hdi" 561 | version = "0.1.10" 562 | source = "registry+https://github.com/rust-lang/crates.io-index" 563 | checksum = "1b00f5d62b645552a470898a2d5007117e1e7ed4277b2cd4bbd13c9d0f2da668" 564 | dependencies = [ 565 | "hdk_derive", 566 | "holo_hash", 567 | "holochain_integrity_types", 568 | "holochain_wasmer_guest", 569 | "paste", 570 | "serde", 571 | "serde_bytes", 572 | "tracing", 573 | "tracing-core", 574 | ] 575 | 576 | [[package]] 577 | name = "hdk" 578 | version = "0.0.163" 579 | source = "registry+https://github.com/rust-lang/crates.io-index" 580 | checksum = "f124f57b8954f91ea9adcd4e518edfd9ec8e8d18d668fd20fc074fdb44b6b9c3" 581 | dependencies = [ 582 | "getrandom", 583 | "hdi", 584 | "hdk_derive", 585 | "holo_hash", 586 | "holochain_wasmer_guest", 587 | "holochain_zome_types", 588 | "paste", 589 | "serde", 590 | "serde_bytes", 591 | "thiserror", 592 | "tracing", 593 | "tracing-core", 594 | ] 595 | 596 | [[package]] 597 | name = "hdk_derive" 598 | version = "0.0.56" 599 | source = "registry+https://github.com/rust-lang/crates.io-index" 600 | checksum = "89621d50291649dff008887d00b89645216c25667ac3c973931c1401dfe41157" 601 | dependencies = [ 602 | "darling 0.14.1", 603 | "heck", 604 | "holochain_integrity_types", 605 | "paste", 606 | "proc-macro-error", 607 | "proc-macro2", 608 | "quote", 609 | "syn", 610 | ] 611 | 612 | [[package]] 613 | name = "heck" 614 | version = "0.4.0" 615 | source = "registry+https://github.com/rust-lang/crates.io-index" 616 | checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" 617 | 618 | [[package]] 619 | name = "hermit-abi" 620 | version = "0.1.19" 621 | source = "registry+https://github.com/rust-lang/crates.io-index" 622 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 623 | dependencies = [ 624 | "libc", 625 | ] 626 | 627 | [[package]] 628 | name = "holo_hash" 629 | version = "0.0.35" 630 | source = "registry+https://github.com/rust-lang/crates.io-index" 631 | checksum = "ee968a2eb255d3467b55ac016dfb46c38e615bcb592241eb7ba26afdf975e6c1" 632 | dependencies = [ 633 | "base64", 634 | "blake2b_simd", 635 | "derive_more", 636 | "holochain_serialized_bytes", 637 | "kitsune_p2p_dht_arc", 638 | "serde", 639 | "serde_bytes", 640 | "thiserror", 641 | ] 642 | 643 | [[package]] 644 | name = "holochain_integrity_types" 645 | version = "0.0.25" 646 | source = "registry+https://github.com/rust-lang/crates.io-index" 647 | checksum = "8bee2b9d961baa3ca33c3a97be44eccf15d1887cb33684969d6f57a160833c20" 648 | dependencies = [ 649 | "holo_hash", 650 | "holochain_serialized_bytes", 651 | "kitsune_p2p_timestamp", 652 | "serde", 653 | "serde_bytes", 654 | "subtle", 655 | "tracing", 656 | ] 657 | 658 | [[package]] 659 | name = "holochain_serialized_bytes" 660 | version = "0.0.51" 661 | source = "registry+https://github.com/rust-lang/crates.io-index" 662 | checksum = "9805b3e01e7b5c144782a0823db4dc895fec18a9ccd45a492ce7c7bf157a9e38" 663 | dependencies = [ 664 | "holochain_serialized_bytes_derive", 665 | "rmp-serde", 666 | "serde", 667 | "serde-transcode", 668 | "serde_bytes", 669 | "serde_json", 670 | "thiserror", 671 | ] 672 | 673 | [[package]] 674 | name = "holochain_serialized_bytes_derive" 675 | version = "0.0.51" 676 | source = "registry+https://github.com/rust-lang/crates.io-index" 677 | checksum = "1077232d0c427d64feb9e138fa22800e447eafb1810682d6c13beb95333cb32c" 678 | dependencies = [ 679 | "quote", 680 | "syn", 681 | ] 682 | 683 | [[package]] 684 | name = "holochain_wasmer_common" 685 | version = "0.0.82" 686 | source = "registry+https://github.com/rust-lang/crates.io-index" 687 | checksum = "6ac7305badfd4280f780d5f51bc810e9b6d5f174056801183b3380d17411dd65" 688 | dependencies = [ 689 | "holochain_serialized_bytes", 690 | "serde", 691 | "serde_bytes", 692 | "thiserror", 693 | "wasmer", 694 | "wasmer-engine", 695 | ] 696 | 697 | [[package]] 698 | name = "holochain_wasmer_guest" 699 | version = "0.0.82" 700 | source = "registry+https://github.com/rust-lang/crates.io-index" 701 | checksum = "62190205552e8235f157becbe66c24c23e190bc1916d87db851da84006bae4b6" 702 | dependencies = [ 703 | "holochain_serialized_bytes", 704 | "holochain_wasmer_common", 705 | "parking_lot", 706 | "serde", 707 | "tracing", 708 | ] 709 | 710 | [[package]] 711 | name = "holochain_zome_types" 712 | version = "0.0.58" 713 | source = "registry+https://github.com/rust-lang/crates.io-index" 714 | checksum = "301e71d7091c87d45e58fd24eaf483e5167b1d2b01c3a948e1c27cd44c216ceb" 715 | dependencies = [ 716 | "holo_hash", 717 | "holochain_integrity_types", 718 | "holochain_serialized_bytes", 719 | "holochain_wasmer_common", 720 | "kitsune_p2p_timestamp", 721 | "paste", 722 | "serde", 723 | "serde_bytes", 724 | "subtle", 725 | "thiserror", 726 | "tracing", 727 | ] 728 | 729 | [[package]] 730 | name = "iana-time-zone" 731 | version = "0.1.46" 732 | source = "registry+https://github.com/rust-lang/crates.io-index" 733 | checksum = "ad2bfd338099682614d3ee3fe0cd72e0b6a41ca6a87f6a74a3bd593c91650501" 734 | dependencies = [ 735 | "android_system_properties", 736 | "core-foundation-sys", 737 | "js-sys", 738 | "wasm-bindgen", 739 | "winapi", 740 | ] 741 | 742 | [[package]] 743 | name = "ident_case" 744 | version = "1.0.1" 745 | source = "registry+https://github.com/rust-lang/crates.io-index" 746 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 747 | 748 | [[package]] 749 | name = "indexmap" 750 | version = "1.8.0" 751 | source = "registry+https://github.com/rust-lang/crates.io-index" 752 | checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" 753 | dependencies = [ 754 | "autocfg", 755 | "hashbrown 0.11.2", 756 | "serde", 757 | ] 758 | 759 | [[package]] 760 | name = "instant" 761 | version = "0.1.12" 762 | source = "registry+https://github.com/rust-lang/crates.io-index" 763 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 764 | dependencies = [ 765 | "cfg-if", 766 | ] 767 | 768 | [[package]] 769 | name = "intervallum" 770 | version = "1.4.0" 771 | source = "registry+https://github.com/rust-lang/crates.io-index" 772 | checksum = "c8ccecd834666f695ecec3ff0d5fc32e32c91abea91a28fd0aceb4b35a82cee1" 773 | dependencies = [ 774 | "bit-set", 775 | "gcollections", 776 | "num-integer", 777 | "num-traits", 778 | "trilean", 779 | ] 780 | 781 | [[package]] 782 | name = "itoa" 783 | version = "1.0.1" 784 | source = "registry+https://github.com/rust-lang/crates.io-index" 785 | checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" 786 | 787 | [[package]] 788 | name = "js-sys" 789 | version = "0.3.58" 790 | source = "registry+https://github.com/rust-lang/crates.io-index" 791 | checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27" 792 | dependencies = [ 793 | "wasm-bindgen", 794 | ] 795 | 796 | [[package]] 797 | name = "kitsune_p2p_dht_arc" 798 | version = "0.0.16" 799 | source = "registry+https://github.com/rust-lang/crates.io-index" 800 | checksum = "193e740f15fa89facc652619e2741766e8aea1806fe19c442556e7626006a0f8" 801 | dependencies = [ 802 | "derive_more", 803 | "gcollections", 804 | "intervallum", 805 | "num-traits", 806 | "serde", 807 | ] 808 | 809 | [[package]] 810 | name = "kitsune_p2p_timestamp" 811 | version = "0.0.15" 812 | source = "registry+https://github.com/rust-lang/crates.io-index" 813 | checksum = "715c7310eb3fe1638d380368582cab1f55829cfe1d72aea7d101ea7482787a3c" 814 | dependencies = [ 815 | "chrono", 816 | "derive_more", 817 | "serde", 818 | ] 819 | 820 | [[package]] 821 | name = "lazy_static" 822 | version = "1.4.0" 823 | source = "registry+https://github.com/rust-lang/crates.io-index" 824 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 825 | 826 | [[package]] 827 | name = "leb128" 828 | version = "0.2.5" 829 | source = "registry+https://github.com/rust-lang/crates.io-index" 830 | checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" 831 | 832 | [[package]] 833 | name = "libc" 834 | version = "0.2.126" 835 | source = "registry+https://github.com/rust-lang/crates.io-index" 836 | checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" 837 | 838 | [[package]] 839 | name = "libloading" 840 | version = "0.7.3" 841 | source = "registry+https://github.com/rust-lang/crates.io-index" 842 | checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" 843 | dependencies = [ 844 | "cfg-if", 845 | "winapi", 846 | ] 847 | 848 | [[package]] 849 | name = "lock_api" 850 | version = "0.4.6" 851 | source = "registry+https://github.com/rust-lang/crates.io-index" 852 | checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" 853 | dependencies = [ 854 | "scopeguard", 855 | ] 856 | 857 | [[package]] 858 | name = "log" 859 | version = "0.4.17" 860 | source = "registry+https://github.com/rust-lang/crates.io-index" 861 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" 862 | dependencies = [ 863 | "cfg-if", 864 | ] 865 | 866 | [[package]] 867 | name = "loupe" 868 | version = "0.1.3" 869 | source = "registry+https://github.com/rust-lang/crates.io-index" 870 | checksum = "9b6a72dfa44fe15b5e76b94307eeb2ff995a8c5b283b55008940c02e0c5b634d" 871 | dependencies = [ 872 | "indexmap", 873 | "loupe-derive", 874 | "rustversion", 875 | ] 876 | 877 | [[package]] 878 | name = "loupe-derive" 879 | version = "0.1.3" 880 | source = "registry+https://github.com/rust-lang/crates.io-index" 881 | checksum = "c0fbfc88337168279f2e9ae06e157cfed4efd3316e14dc96ed074d4f2e6c5952" 882 | dependencies = [ 883 | "quote", 884 | "syn", 885 | ] 886 | 887 | [[package]] 888 | name = "mach" 889 | version = "0.3.2" 890 | source = "registry+https://github.com/rust-lang/crates.io-index" 891 | checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" 892 | dependencies = [ 893 | "libc", 894 | ] 895 | 896 | [[package]] 897 | name = "memchr" 898 | version = "2.5.0" 899 | source = "registry+https://github.com/rust-lang/crates.io-index" 900 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 901 | 902 | [[package]] 903 | name = "memmap2" 904 | version = "0.5.4" 905 | source = "registry+https://github.com/rust-lang/crates.io-index" 906 | checksum = "d5172b50c23043ff43dd53e51392f36519d9b35a8f3a410d30ece5d1aedd58ae" 907 | dependencies = [ 908 | "libc", 909 | ] 910 | 911 | [[package]] 912 | name = "memoffset" 913 | version = "0.6.5" 914 | source = "registry+https://github.com/rust-lang/crates.io-index" 915 | checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" 916 | dependencies = [ 917 | "autocfg", 918 | ] 919 | 920 | [[package]] 921 | name = "miniz_oxide" 922 | version = "0.5.3" 923 | source = "registry+https://github.com/rust-lang/crates.io-index" 924 | checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" 925 | dependencies = [ 926 | "adler", 927 | ] 928 | 929 | [[package]] 930 | name = "more-asserts" 931 | version = "0.2.2" 932 | source = "registry+https://github.com/rust-lang/crates.io-index" 933 | checksum = "7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389" 934 | 935 | [[package]] 936 | name = "num-integer" 937 | version = "0.1.44" 938 | source = "registry+https://github.com/rust-lang/crates.io-index" 939 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" 940 | dependencies = [ 941 | "autocfg", 942 | "num-traits", 943 | ] 944 | 945 | [[package]] 946 | name = "num-traits" 947 | version = "0.2.14" 948 | source = "registry+https://github.com/rust-lang/crates.io-index" 949 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 950 | dependencies = [ 951 | "autocfg", 952 | ] 953 | 954 | [[package]] 955 | name = "num_cpus" 956 | version = "1.13.1" 957 | source = "registry+https://github.com/rust-lang/crates.io-index" 958 | checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" 959 | dependencies = [ 960 | "hermit-abi", 961 | "libc", 962 | ] 963 | 964 | [[package]] 965 | name = "object" 966 | version = "0.28.4" 967 | source = "registry+https://github.com/rust-lang/crates.io-index" 968 | checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" 969 | dependencies = [ 970 | "crc32fast", 971 | "hashbrown 0.11.2", 972 | "indexmap", 973 | "memchr", 974 | ] 975 | 976 | [[package]] 977 | name = "once_cell" 978 | version = "1.13.0" 979 | source = "registry+https://github.com/rust-lang/crates.io-index" 980 | checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" 981 | 982 | [[package]] 983 | name = "parking_lot" 984 | version = "0.12.1" 985 | source = "registry+https://github.com/rust-lang/crates.io-index" 986 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" 987 | dependencies = [ 988 | "lock_api", 989 | "parking_lot_core", 990 | ] 991 | 992 | [[package]] 993 | name = "parking_lot_core" 994 | version = "0.9.5" 995 | source = "registry+https://github.com/rust-lang/crates.io-index" 996 | checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" 997 | dependencies = [ 998 | "cfg-if", 999 | "libc", 1000 | "redox_syscall", 1001 | "smallvec", 1002 | "windows-sys 0.42.0", 1003 | ] 1004 | 1005 | [[package]] 1006 | name = "paste" 1007 | version = "1.0.5" 1008 | source = "registry+https://github.com/rust-lang/crates.io-index" 1009 | checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58" 1010 | 1011 | [[package]] 1012 | name = "pin-project-lite" 1013 | version = "0.2.8" 1014 | source = "registry+https://github.com/rust-lang/crates.io-index" 1015 | checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" 1016 | 1017 | [[package]] 1018 | name = "proc-macro-error" 1019 | version = "1.0.4" 1020 | source = "registry+https://github.com/rust-lang/crates.io-index" 1021 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 1022 | dependencies = [ 1023 | "proc-macro-error-attr", 1024 | "proc-macro2", 1025 | "quote", 1026 | "syn", 1027 | "version_check", 1028 | ] 1029 | 1030 | [[package]] 1031 | name = "proc-macro-error-attr" 1032 | version = "1.0.4" 1033 | source = "registry+https://github.com/rust-lang/crates.io-index" 1034 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 1035 | dependencies = [ 1036 | "proc-macro2", 1037 | "quote", 1038 | "version_check", 1039 | ] 1040 | 1041 | [[package]] 1042 | name = "proc-macro2" 1043 | version = "1.0.40" 1044 | source = "registry+https://github.com/rust-lang/crates.io-index" 1045 | checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" 1046 | dependencies = [ 1047 | "unicode-ident", 1048 | ] 1049 | 1050 | [[package]] 1051 | name = "profiles" 1052 | version = "0.0.1-alpha1" 1053 | dependencies = [ 1054 | "hc_zome_profiles_coordinator", 1055 | ] 1056 | 1057 | [[package]] 1058 | name = "profiles_core" 1059 | version = "0.0.1-alpha1" 1060 | dependencies = [ 1061 | "hc_zome_profiles_integrity", 1062 | ] 1063 | 1064 | [[package]] 1065 | name = "ptr_meta" 1066 | version = "0.1.4" 1067 | source = "registry+https://github.com/rust-lang/crates.io-index" 1068 | checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" 1069 | dependencies = [ 1070 | "ptr_meta_derive", 1071 | ] 1072 | 1073 | [[package]] 1074 | name = "ptr_meta_derive" 1075 | version = "0.1.4" 1076 | source = "registry+https://github.com/rust-lang/crates.io-index" 1077 | checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" 1078 | dependencies = [ 1079 | "proc-macro2", 1080 | "quote", 1081 | "syn", 1082 | ] 1083 | 1084 | [[package]] 1085 | name = "quote" 1086 | version = "1.0.20" 1087 | source = "registry+https://github.com/rust-lang/crates.io-index" 1088 | checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" 1089 | dependencies = [ 1090 | "proc-macro2", 1091 | ] 1092 | 1093 | [[package]] 1094 | name = "rayon" 1095 | version = "1.5.3" 1096 | source = "registry+https://github.com/rust-lang/crates.io-index" 1097 | checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" 1098 | dependencies = [ 1099 | "autocfg", 1100 | "crossbeam-deque", 1101 | "either", 1102 | "rayon-core", 1103 | ] 1104 | 1105 | [[package]] 1106 | name = "rayon-core" 1107 | version = "1.9.3" 1108 | source = "registry+https://github.com/rust-lang/crates.io-index" 1109 | checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" 1110 | dependencies = [ 1111 | "crossbeam-channel", 1112 | "crossbeam-deque", 1113 | "crossbeam-utils", 1114 | "num_cpus", 1115 | ] 1116 | 1117 | [[package]] 1118 | name = "redox_syscall" 1119 | version = "0.2.10" 1120 | source = "registry+https://github.com/rust-lang/crates.io-index" 1121 | checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" 1122 | dependencies = [ 1123 | "bitflags", 1124 | ] 1125 | 1126 | [[package]] 1127 | name = "regalloc" 1128 | version = "0.0.34" 1129 | source = "registry+https://github.com/rust-lang/crates.io-index" 1130 | checksum = "62446b1d3ebf980bdc68837700af1d77b37bc430e524bf95319c6eada2a4cc02" 1131 | dependencies = [ 1132 | "log", 1133 | "rustc-hash", 1134 | "smallvec", 1135 | ] 1136 | 1137 | [[package]] 1138 | name = "region" 1139 | version = "3.0.0" 1140 | source = "registry+https://github.com/rust-lang/crates.io-index" 1141 | checksum = "76e189c2369884dce920945e2ddf79b3dff49e071a167dd1817fa9c4c00d512e" 1142 | dependencies = [ 1143 | "bitflags", 1144 | "libc", 1145 | "mach", 1146 | "winapi", 1147 | ] 1148 | 1149 | [[package]] 1150 | name = "remove_dir_all" 1151 | version = "0.5.3" 1152 | source = "registry+https://github.com/rust-lang/crates.io-index" 1153 | checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" 1154 | dependencies = [ 1155 | "winapi", 1156 | ] 1157 | 1158 | [[package]] 1159 | name = "rend" 1160 | version = "0.3.6" 1161 | source = "registry+https://github.com/rust-lang/crates.io-index" 1162 | checksum = "79af64b4b6362ffba04eef3a4e10829718a4896dac19daa741851c86781edf95" 1163 | dependencies = [ 1164 | "bytecheck", 1165 | ] 1166 | 1167 | [[package]] 1168 | name = "rkyv" 1169 | version = "0.7.39" 1170 | source = "registry+https://github.com/rust-lang/crates.io-index" 1171 | checksum = "cec2b3485b07d96ddfd3134767b8a447b45ea4eb91448d0a35180ec0ffd5ed15" 1172 | dependencies = [ 1173 | "bytecheck", 1174 | "hashbrown 0.12.1", 1175 | "ptr_meta", 1176 | "rend", 1177 | "rkyv_derive", 1178 | "seahash", 1179 | ] 1180 | 1181 | [[package]] 1182 | name = "rkyv_derive" 1183 | version = "0.7.39" 1184 | source = "registry+https://github.com/rust-lang/crates.io-index" 1185 | checksum = "6eaedadc88b53e36dd32d940ed21ae4d850d5916f2581526921f553a72ac34c4" 1186 | dependencies = [ 1187 | "proc-macro2", 1188 | "quote", 1189 | "syn", 1190 | ] 1191 | 1192 | [[package]] 1193 | name = "rmp" 1194 | version = "0.8.10" 1195 | source = "registry+https://github.com/rust-lang/crates.io-index" 1196 | checksum = "4f55e5fa1446c4d5dd1f5daeed2a4fe193071771a2636274d0d7a3b082aa7ad6" 1197 | dependencies = [ 1198 | "byteorder", 1199 | "num-traits", 1200 | ] 1201 | 1202 | [[package]] 1203 | name = "rmp-serde" 1204 | version = "0.15.5" 1205 | source = "registry+https://github.com/rust-lang/crates.io-index" 1206 | checksum = "723ecff9ad04f4ad92fe1c8ca6c20d2196d9286e9c60727c4cb5511629260e9d" 1207 | dependencies = [ 1208 | "byteorder", 1209 | "rmp", 1210 | "serde", 1211 | ] 1212 | 1213 | [[package]] 1214 | name = "rustc-demangle" 1215 | version = "0.1.21" 1216 | source = "registry+https://github.com/rust-lang/crates.io-index" 1217 | checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" 1218 | 1219 | [[package]] 1220 | name = "rustc-hash" 1221 | version = "1.1.0" 1222 | source = "registry+https://github.com/rust-lang/crates.io-index" 1223 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 1224 | 1225 | [[package]] 1226 | name = "rustc_version" 1227 | version = "0.4.0" 1228 | source = "registry+https://github.com/rust-lang/crates.io-index" 1229 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" 1230 | dependencies = [ 1231 | "semver", 1232 | ] 1233 | 1234 | [[package]] 1235 | name = "rustversion" 1236 | version = "1.0.7" 1237 | source = "registry+https://github.com/rust-lang/crates.io-index" 1238 | checksum = "a0a5f7c728f5d284929a1cccb5bc19884422bfe6ef4d6c409da2c41838983fcf" 1239 | 1240 | [[package]] 1241 | name = "ryu" 1242 | version = "1.0.9" 1243 | source = "registry+https://github.com/rust-lang/crates.io-index" 1244 | checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" 1245 | 1246 | [[package]] 1247 | name = "scopeguard" 1248 | version = "1.1.0" 1249 | source = "registry+https://github.com/rust-lang/crates.io-index" 1250 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1251 | 1252 | [[package]] 1253 | name = "seahash" 1254 | version = "4.1.0" 1255 | source = "registry+https://github.com/rust-lang/crates.io-index" 1256 | checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" 1257 | 1258 | [[package]] 1259 | name = "semver" 1260 | version = "1.0.5" 1261 | source = "registry+https://github.com/rust-lang/crates.io-index" 1262 | checksum = "0486718e92ec9a68fbed73bb5ef687d71103b142595b406835649bebd33f72c7" 1263 | 1264 | [[package]] 1265 | name = "serde" 1266 | version = "1.0.136" 1267 | source = "registry+https://github.com/rust-lang/crates.io-index" 1268 | checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" 1269 | dependencies = [ 1270 | "serde_derive", 1271 | ] 1272 | 1273 | [[package]] 1274 | name = "serde-transcode" 1275 | version = "1.1.1" 1276 | source = "registry+https://github.com/rust-lang/crates.io-index" 1277 | checksum = "590c0e25c2a5bb6e85bf5c1bce768ceb86b316e7a01bdf07d2cb4ec2271990e2" 1278 | dependencies = [ 1279 | "serde", 1280 | ] 1281 | 1282 | [[package]] 1283 | name = "serde_bytes" 1284 | version = "0.11.5" 1285 | source = "registry+https://github.com/rust-lang/crates.io-index" 1286 | checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9" 1287 | dependencies = [ 1288 | "serde", 1289 | ] 1290 | 1291 | [[package]] 1292 | name = "serde_derive" 1293 | version = "1.0.136" 1294 | source = "registry+https://github.com/rust-lang/crates.io-index" 1295 | checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" 1296 | dependencies = [ 1297 | "proc-macro2", 1298 | "quote", 1299 | "syn", 1300 | ] 1301 | 1302 | [[package]] 1303 | name = "serde_json" 1304 | version = "1.0.78" 1305 | source = "registry+https://github.com/rust-lang/crates.io-index" 1306 | checksum = "d23c1ba4cf0efd44be32017709280b32d1cea5c3f1275c3b6d9e8bc54f758085" 1307 | dependencies = [ 1308 | "indexmap", 1309 | "itoa", 1310 | "ryu", 1311 | "serde", 1312 | ] 1313 | 1314 | [[package]] 1315 | name = "smallvec" 1316 | version = "1.8.0" 1317 | source = "registry+https://github.com/rust-lang/crates.io-index" 1318 | checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" 1319 | 1320 | [[package]] 1321 | name = "stable_deref_trait" 1322 | version = "1.2.0" 1323 | source = "registry+https://github.com/rust-lang/crates.io-index" 1324 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 1325 | 1326 | [[package]] 1327 | name = "strsim" 1328 | version = "0.10.0" 1329 | source = "registry+https://github.com/rust-lang/crates.io-index" 1330 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 1331 | 1332 | [[package]] 1333 | name = "subtle" 1334 | version = "2.4.1" 1335 | source = "registry+https://github.com/rust-lang/crates.io-index" 1336 | checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" 1337 | 1338 | [[package]] 1339 | name = "syn" 1340 | version = "1.0.98" 1341 | source = "registry+https://github.com/rust-lang/crates.io-index" 1342 | checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" 1343 | dependencies = [ 1344 | "proc-macro2", 1345 | "quote", 1346 | "unicode-ident", 1347 | ] 1348 | 1349 | [[package]] 1350 | name = "target-lexicon" 1351 | version = "0.12.4" 1352 | source = "registry+https://github.com/rust-lang/crates.io-index" 1353 | checksum = "c02424087780c9b71cc96799eaeddff35af2bc513278cda5c99fc1f5d026d3c1" 1354 | 1355 | [[package]] 1356 | name = "tempfile" 1357 | version = "3.3.0" 1358 | source = "registry+https://github.com/rust-lang/crates.io-index" 1359 | checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" 1360 | dependencies = [ 1361 | "cfg-if", 1362 | "fastrand", 1363 | "libc", 1364 | "redox_syscall", 1365 | "remove_dir_all", 1366 | "winapi", 1367 | ] 1368 | 1369 | [[package]] 1370 | name = "thiserror" 1371 | version = "1.0.30" 1372 | source = "registry+https://github.com/rust-lang/crates.io-index" 1373 | checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" 1374 | dependencies = [ 1375 | "thiserror-impl", 1376 | ] 1377 | 1378 | [[package]] 1379 | name = "thiserror-impl" 1380 | version = "1.0.30" 1381 | source = "registry+https://github.com/rust-lang/crates.io-index" 1382 | checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" 1383 | dependencies = [ 1384 | "proc-macro2", 1385 | "quote", 1386 | "syn", 1387 | ] 1388 | 1389 | [[package]] 1390 | name = "time" 1391 | version = "0.1.43" 1392 | source = "registry+https://github.com/rust-lang/crates.io-index" 1393 | checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" 1394 | dependencies = [ 1395 | "libc", 1396 | "winapi", 1397 | ] 1398 | 1399 | [[package]] 1400 | name = "tracing" 1401 | version = "0.1.30" 1402 | source = "registry+https://github.com/rust-lang/crates.io-index" 1403 | checksum = "2d8d93354fe2a8e50d5953f5ae2e47a3fc2ef03292e7ea46e3cc38f549525fb9" 1404 | dependencies = [ 1405 | "cfg-if", 1406 | "log", 1407 | "pin-project-lite", 1408 | "tracing-attributes", 1409 | "tracing-core", 1410 | ] 1411 | 1412 | [[package]] 1413 | name = "tracing-attributes" 1414 | version = "0.1.19" 1415 | source = "registry+https://github.com/rust-lang/crates.io-index" 1416 | checksum = "8276d9a4a3a558d7b7ad5303ad50b53d58264641b82914b7ada36bd762e7a716" 1417 | dependencies = [ 1418 | "proc-macro2", 1419 | "quote", 1420 | "syn", 1421 | ] 1422 | 1423 | [[package]] 1424 | name = "tracing-core" 1425 | version = "0.1.22" 1426 | source = "registry+https://github.com/rust-lang/crates.io-index" 1427 | checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23" 1428 | dependencies = [ 1429 | "lazy_static", 1430 | "valuable", 1431 | ] 1432 | 1433 | [[package]] 1434 | name = "trilean" 1435 | version = "1.1.0" 1436 | source = "registry+https://github.com/rust-lang/crates.io-index" 1437 | checksum = "683ba5022fe6dbd7133cad150478ccf51bdb6d861515181e5fc6b4323d4fa424" 1438 | 1439 | [[package]] 1440 | name = "unicode-ident" 1441 | version = "1.0.1" 1442 | source = "registry+https://github.com/rust-lang/crates.io-index" 1443 | checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" 1444 | 1445 | [[package]] 1446 | name = "unicode-width" 1447 | version = "0.1.9" 1448 | source = "registry+https://github.com/rust-lang/crates.io-index" 1449 | checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" 1450 | 1451 | [[package]] 1452 | name = "valuable" 1453 | version = "0.1.0" 1454 | source = "registry+https://github.com/rust-lang/crates.io-index" 1455 | checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" 1456 | 1457 | [[package]] 1458 | name = "version_check" 1459 | version = "0.9.4" 1460 | source = "registry+https://github.com/rust-lang/crates.io-index" 1461 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 1462 | 1463 | [[package]] 1464 | name = "wasi" 1465 | version = "0.11.0+wasi-snapshot-preview1" 1466 | source = "registry+https://github.com/rust-lang/crates.io-index" 1467 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1468 | 1469 | [[package]] 1470 | name = "wasm-bindgen" 1471 | version = "0.2.81" 1472 | source = "registry+https://github.com/rust-lang/crates.io-index" 1473 | checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994" 1474 | dependencies = [ 1475 | "cfg-if", 1476 | "wasm-bindgen-macro", 1477 | ] 1478 | 1479 | [[package]] 1480 | name = "wasm-bindgen-backend" 1481 | version = "0.2.81" 1482 | source = "registry+https://github.com/rust-lang/crates.io-index" 1483 | checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a" 1484 | dependencies = [ 1485 | "bumpalo", 1486 | "lazy_static", 1487 | "log", 1488 | "proc-macro2", 1489 | "quote", 1490 | "syn", 1491 | "wasm-bindgen-shared", 1492 | ] 1493 | 1494 | [[package]] 1495 | name = "wasm-bindgen-macro" 1496 | version = "0.2.81" 1497 | source = "registry+https://github.com/rust-lang/crates.io-index" 1498 | checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa" 1499 | dependencies = [ 1500 | "quote", 1501 | "wasm-bindgen-macro-support", 1502 | ] 1503 | 1504 | [[package]] 1505 | name = "wasm-bindgen-macro-support" 1506 | version = "0.2.81" 1507 | source = "registry+https://github.com/rust-lang/crates.io-index" 1508 | checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048" 1509 | dependencies = [ 1510 | "proc-macro2", 1511 | "quote", 1512 | "syn", 1513 | "wasm-bindgen-backend", 1514 | "wasm-bindgen-shared", 1515 | ] 1516 | 1517 | [[package]] 1518 | name = "wasm-bindgen-shared" 1519 | version = "0.2.81" 1520 | source = "registry+https://github.com/rust-lang/crates.io-index" 1521 | checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be" 1522 | 1523 | [[package]] 1524 | name = "wasm-encoder" 1525 | version = "0.14.0" 1526 | source = "registry+https://github.com/rust-lang/crates.io-index" 1527 | checksum = "f76068e87fe9b837a6bc2ccded66784173eadb828c4168643e9fddf6f9ed2e61" 1528 | dependencies = [ 1529 | "leb128", 1530 | ] 1531 | 1532 | [[package]] 1533 | name = "wasmer" 1534 | version = "2.3.0" 1535 | source = "registry+https://github.com/rust-lang/crates.io-index" 1536 | checksum = "ea8d8361c9d006ea3d7797de7bd6b1492ffd0f91a22430cfda6c1658ad57bedf" 1537 | dependencies = [ 1538 | "cfg-if", 1539 | "indexmap", 1540 | "js-sys", 1541 | "loupe", 1542 | "more-asserts", 1543 | "target-lexicon", 1544 | "thiserror", 1545 | "wasm-bindgen", 1546 | "wasmer-artifact", 1547 | "wasmer-compiler", 1548 | "wasmer-compiler-cranelift", 1549 | "wasmer-derive", 1550 | "wasmer-engine", 1551 | "wasmer-engine-dylib", 1552 | "wasmer-engine-universal", 1553 | "wasmer-types", 1554 | "wasmer-vm", 1555 | "wat", 1556 | "winapi", 1557 | ] 1558 | 1559 | [[package]] 1560 | name = "wasmer-artifact" 1561 | version = "2.3.0" 1562 | source = "registry+https://github.com/rust-lang/crates.io-index" 1563 | checksum = "7aaf9428c29c1d8ad2ac0e45889ba8a568a835e33fd058964e5e500f2f7ce325" 1564 | dependencies = [ 1565 | "enumset", 1566 | "loupe", 1567 | "thiserror", 1568 | "wasmer-compiler", 1569 | "wasmer-types", 1570 | ] 1571 | 1572 | [[package]] 1573 | name = "wasmer-compiler" 1574 | version = "2.3.0" 1575 | source = "registry+https://github.com/rust-lang/crates.io-index" 1576 | checksum = "e67a6cd866aed456656db2cfea96c18baabbd33f676578482b85c51e1ee19d2c" 1577 | dependencies = [ 1578 | "enumset", 1579 | "loupe", 1580 | "rkyv", 1581 | "serde", 1582 | "serde_bytes", 1583 | "smallvec", 1584 | "target-lexicon", 1585 | "thiserror", 1586 | "wasmer-types", 1587 | "wasmparser", 1588 | ] 1589 | 1590 | [[package]] 1591 | name = "wasmer-compiler-cranelift" 1592 | version = "2.3.0" 1593 | source = "registry+https://github.com/rust-lang/crates.io-index" 1594 | checksum = "48be2f9f6495f08649e4f8b946a2cbbe119faf5a654aa1457f9504a99d23dae0" 1595 | dependencies = [ 1596 | "cranelift-codegen", 1597 | "cranelift-entity", 1598 | "cranelift-frontend", 1599 | "gimli", 1600 | "loupe", 1601 | "more-asserts", 1602 | "rayon", 1603 | "smallvec", 1604 | "target-lexicon", 1605 | "tracing", 1606 | "wasmer-compiler", 1607 | "wasmer-types", 1608 | ] 1609 | 1610 | [[package]] 1611 | name = "wasmer-derive" 1612 | version = "2.3.0" 1613 | source = "registry+https://github.com/rust-lang/crates.io-index" 1614 | checksum = "00e50405cc2a2f74ff574584710a5f2c1d5c93744acce2ca0866084739284b51" 1615 | dependencies = [ 1616 | "proc-macro-error", 1617 | "proc-macro2", 1618 | "quote", 1619 | "syn", 1620 | ] 1621 | 1622 | [[package]] 1623 | name = "wasmer-engine" 1624 | version = "2.3.0" 1625 | source = "registry+https://github.com/rust-lang/crates.io-index" 1626 | checksum = "3f98f010978c244db431b392aeab0661df7ea0822343334f8f2a920763548e45" 1627 | dependencies = [ 1628 | "backtrace", 1629 | "enumset", 1630 | "lazy_static", 1631 | "loupe", 1632 | "memmap2", 1633 | "more-asserts", 1634 | "rustc-demangle", 1635 | "serde", 1636 | "serde_bytes", 1637 | "target-lexicon", 1638 | "thiserror", 1639 | "wasmer-artifact", 1640 | "wasmer-compiler", 1641 | "wasmer-types", 1642 | "wasmer-vm", 1643 | ] 1644 | 1645 | [[package]] 1646 | name = "wasmer-engine-dylib" 1647 | version = "2.3.0" 1648 | source = "registry+https://github.com/rust-lang/crates.io-index" 1649 | checksum = "ad0358af9c154724587731175553805648d9acb8f6657880d165e378672b7e53" 1650 | dependencies = [ 1651 | "cfg-if", 1652 | "enum-iterator", 1653 | "enumset", 1654 | "leb128", 1655 | "libloading", 1656 | "loupe", 1657 | "object", 1658 | "rkyv", 1659 | "serde", 1660 | "tempfile", 1661 | "tracing", 1662 | "wasmer-artifact", 1663 | "wasmer-compiler", 1664 | "wasmer-engine", 1665 | "wasmer-object", 1666 | "wasmer-types", 1667 | "wasmer-vm", 1668 | "which", 1669 | ] 1670 | 1671 | [[package]] 1672 | name = "wasmer-engine-universal" 1673 | version = "2.3.0" 1674 | source = "registry+https://github.com/rust-lang/crates.io-index" 1675 | checksum = "440dc3d93c9ca47865a4f4edd037ea81bf983b5796b59b3d712d844b32dbef15" 1676 | dependencies = [ 1677 | "cfg-if", 1678 | "enumset", 1679 | "leb128", 1680 | "loupe", 1681 | "region", 1682 | "rkyv", 1683 | "wasmer-compiler", 1684 | "wasmer-engine", 1685 | "wasmer-engine-universal-artifact", 1686 | "wasmer-types", 1687 | "wasmer-vm", 1688 | "winapi", 1689 | ] 1690 | 1691 | [[package]] 1692 | name = "wasmer-engine-universal-artifact" 1693 | version = "2.3.0" 1694 | source = "registry+https://github.com/rust-lang/crates.io-index" 1695 | checksum = "68f1db3f54152657eb6e86c44b66525ff7801dad8328fe677da48dd06af9ad41" 1696 | dependencies = [ 1697 | "enum-iterator", 1698 | "enumset", 1699 | "loupe", 1700 | "rkyv", 1701 | "thiserror", 1702 | "wasmer-artifact", 1703 | "wasmer-compiler", 1704 | "wasmer-types", 1705 | ] 1706 | 1707 | [[package]] 1708 | name = "wasmer-object" 1709 | version = "2.3.0" 1710 | source = "registry+https://github.com/rust-lang/crates.io-index" 1711 | checksum = "8d831335ff3a44ecf451303f6f891175c642488036b92ceceb24ac8623a8fa8b" 1712 | dependencies = [ 1713 | "object", 1714 | "thiserror", 1715 | "wasmer-compiler", 1716 | "wasmer-types", 1717 | ] 1718 | 1719 | [[package]] 1720 | name = "wasmer-types" 1721 | version = "2.3.0" 1722 | source = "registry+https://github.com/rust-lang/crates.io-index" 1723 | checksum = "39df01ea05dc0a9bab67e054c7cb01521e53b35a7bb90bd02eca564ed0b2667f" 1724 | dependencies = [ 1725 | "backtrace", 1726 | "enum-iterator", 1727 | "indexmap", 1728 | "loupe", 1729 | "more-asserts", 1730 | "rkyv", 1731 | "serde", 1732 | "thiserror", 1733 | ] 1734 | 1735 | [[package]] 1736 | name = "wasmer-vm" 1737 | version = "2.3.0" 1738 | source = "registry+https://github.com/rust-lang/crates.io-index" 1739 | checksum = "30d965fa61f4dc4cdb35a54daaf7ecec3563fbb94154a6c35433f879466247dd" 1740 | dependencies = [ 1741 | "backtrace", 1742 | "cc", 1743 | "cfg-if", 1744 | "corosensei", 1745 | "enum-iterator", 1746 | "indexmap", 1747 | "lazy_static", 1748 | "libc", 1749 | "loupe", 1750 | "mach", 1751 | "memoffset", 1752 | "more-asserts", 1753 | "region", 1754 | "rkyv", 1755 | "scopeguard", 1756 | "serde", 1757 | "thiserror", 1758 | "wasmer-artifact", 1759 | "wasmer-types", 1760 | "winapi", 1761 | ] 1762 | 1763 | [[package]] 1764 | name = "wasmparser" 1765 | version = "0.83.0" 1766 | source = "registry+https://github.com/rust-lang/crates.io-index" 1767 | checksum = "718ed7c55c2add6548cca3ddd6383d738cd73b892df400e96b9aa876f0141d7a" 1768 | 1769 | [[package]] 1770 | name = "wast" 1771 | version = "43.0.0" 1772 | source = "registry+https://github.com/rust-lang/crates.io-index" 1773 | checksum = "408feaebf6dbf9d154957873b14d00e8fba4cbc17a8cbb1bc9e4c1db425c50a8" 1774 | dependencies = [ 1775 | "leb128", 1776 | "memchr", 1777 | "unicode-width", 1778 | "wasm-encoder", 1779 | ] 1780 | 1781 | [[package]] 1782 | name = "wat" 1783 | version = "1.0.45" 1784 | source = "registry+https://github.com/rust-lang/crates.io-index" 1785 | checksum = "2b70bfff0cfaf33dc9d641196dbcd0023a2da8b4b9030c59535cb44e2884983b" 1786 | dependencies = [ 1787 | "wast", 1788 | ] 1789 | 1790 | [[package]] 1791 | name = "which" 1792 | version = "4.2.5" 1793 | source = "registry+https://github.com/rust-lang/crates.io-index" 1794 | checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae" 1795 | dependencies = [ 1796 | "either", 1797 | "lazy_static", 1798 | "libc", 1799 | ] 1800 | 1801 | [[package]] 1802 | name = "winapi" 1803 | version = "0.3.9" 1804 | source = "registry+https://github.com/rust-lang/crates.io-index" 1805 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1806 | dependencies = [ 1807 | "winapi-i686-pc-windows-gnu", 1808 | "winapi-x86_64-pc-windows-gnu", 1809 | ] 1810 | 1811 | [[package]] 1812 | name = "winapi-i686-pc-windows-gnu" 1813 | version = "0.4.0" 1814 | source = "registry+https://github.com/rust-lang/crates.io-index" 1815 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1816 | 1817 | [[package]] 1818 | name = "winapi-x86_64-pc-windows-gnu" 1819 | version = "0.4.0" 1820 | source = "registry+https://github.com/rust-lang/crates.io-index" 1821 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1822 | 1823 | [[package]] 1824 | name = "windows-sys" 1825 | version = "0.33.0" 1826 | source = "registry+https://github.com/rust-lang/crates.io-index" 1827 | checksum = "43dbb096663629518eb1dfa72d80243ca5a6aca764cae62a2df70af760a9be75" 1828 | dependencies = [ 1829 | "windows_aarch64_msvc 0.33.0", 1830 | "windows_i686_gnu 0.33.0", 1831 | "windows_i686_msvc 0.33.0", 1832 | "windows_x86_64_gnu 0.33.0", 1833 | "windows_x86_64_msvc 0.33.0", 1834 | ] 1835 | 1836 | [[package]] 1837 | name = "windows-sys" 1838 | version = "0.42.0" 1839 | source = "registry+https://github.com/rust-lang/crates.io-index" 1840 | checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" 1841 | dependencies = [ 1842 | "windows_aarch64_gnullvm", 1843 | "windows_aarch64_msvc 0.42.0", 1844 | "windows_i686_gnu 0.42.0", 1845 | "windows_i686_msvc 0.42.0", 1846 | "windows_x86_64_gnu 0.42.0", 1847 | "windows_x86_64_gnullvm", 1848 | "windows_x86_64_msvc 0.42.0", 1849 | ] 1850 | 1851 | [[package]] 1852 | name = "windows_aarch64_gnullvm" 1853 | version = "0.42.0" 1854 | source = "registry+https://github.com/rust-lang/crates.io-index" 1855 | checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" 1856 | 1857 | [[package]] 1858 | name = "windows_aarch64_msvc" 1859 | version = "0.33.0" 1860 | source = "registry+https://github.com/rust-lang/crates.io-index" 1861 | checksum = "cd761fd3eb9ab8cc1ed81e56e567f02dd82c4c837e48ac3b2181b9ffc5060807" 1862 | 1863 | [[package]] 1864 | name = "windows_aarch64_msvc" 1865 | version = "0.42.0" 1866 | source = "registry+https://github.com/rust-lang/crates.io-index" 1867 | checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" 1868 | 1869 | [[package]] 1870 | name = "windows_i686_gnu" 1871 | version = "0.33.0" 1872 | source = "registry+https://github.com/rust-lang/crates.io-index" 1873 | checksum = "cab0cf703a96bab2dc0c02c0fa748491294bf9b7feb27e1f4f96340f208ada0e" 1874 | 1875 | [[package]] 1876 | name = "windows_i686_gnu" 1877 | version = "0.42.0" 1878 | source = "registry+https://github.com/rust-lang/crates.io-index" 1879 | checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" 1880 | 1881 | [[package]] 1882 | name = "windows_i686_msvc" 1883 | version = "0.33.0" 1884 | source = "registry+https://github.com/rust-lang/crates.io-index" 1885 | checksum = "8cfdbe89cc9ad7ce618ba34abc34bbb6c36d99e96cae2245b7943cd75ee773d0" 1886 | 1887 | [[package]] 1888 | name = "windows_i686_msvc" 1889 | version = "0.42.0" 1890 | source = "registry+https://github.com/rust-lang/crates.io-index" 1891 | checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" 1892 | 1893 | [[package]] 1894 | name = "windows_x86_64_gnu" 1895 | version = "0.33.0" 1896 | source = "registry+https://github.com/rust-lang/crates.io-index" 1897 | checksum = "b4dd9b0c0e9ece7bb22e84d70d01b71c6d6248b81a3c60d11869451b4cb24784" 1898 | 1899 | [[package]] 1900 | name = "windows_x86_64_gnu" 1901 | version = "0.42.0" 1902 | source = "registry+https://github.com/rust-lang/crates.io-index" 1903 | checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" 1904 | 1905 | [[package]] 1906 | name = "windows_x86_64_gnullvm" 1907 | version = "0.42.0" 1908 | source = "registry+https://github.com/rust-lang/crates.io-index" 1909 | checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" 1910 | 1911 | [[package]] 1912 | name = "windows_x86_64_msvc" 1913 | version = "0.33.0" 1914 | source = "registry+https://github.com/rust-lang/crates.io-index" 1915 | checksum = "ff1e4aa646495048ec7f3ffddc411e1d829c026a2ec62b39da15c1055e406eaa" 1916 | 1917 | [[package]] 1918 | name = "windows_x86_64_msvc" 1919 | version = "0.42.0" 1920 | source = "registry+https://github.com/rust-lang/crates.io-index" 1921 | checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" 1922 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "dna/zomes/attestations", 4 | "dna/zomes/attestations_core", 5 | "dna/zomes/profiles", 6 | "dna/zomes/profiles_core" 7 | ] 8 | 9 | [profile.dev] 10 | opt-level = "z" 11 | 12 | [profile.release] 13 | opt-level = "z" 14 | -------------------------------------------------------------------------------- /DESIGN.md: -------------------------------------------------------------------------------- 1 | # Attestations 2 | 3 | Verifiable claims in the holochain world, i.e. "Who said what about/to whom" 4 | 5 | ## Context 6 | 7 | **Attestations** provides a simple holochain app for recording claims about another agent. 8 | 9 | ## Linking Structure 10 | 11 | When attestations are created they are linked from the creator and from who they are about, as 12 | well as being linked from an anchor hash of the content itself. 13 | 14 | This allows attestations to be retreived by content, by attester and by attestee. 15 | 16 | ## Entry Types 17 | 18 | ### Attestation 19 | 20 | Specifies an attestation 21 | 22 | ``` rust 23 | struct Attestation { 24 | content: String, 25 | about: AgentPubKey64, 26 | } 27 | ``` 28 | 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | # Cryptographic Autonomy License version 1.0 2 | 3 | *This Cryptographic Autonomy License (the “License”) applies to any Work whose owner has marked it with any of the following notices:* 4 | 5 | *“Licensed under the Cryptographic Autonomy License version 1.0,” or* 6 | 7 | *“SPDX-License-Identifier: CAL-1.0,” or* 8 | 9 | *“Licensed under the Cryptographic Autonomy License version 1.0, with Combined Work Exception,” or* 10 | 11 | *“SPDX-License-Identifier: CAL-1.0 with Combined-Work-Exception.”* 12 | 13 | ------ 14 | 15 | ## 1. Purpose 16 | 17 | This License gives You unlimited permission to use and modify the software to which it applies (the “Work”), either as-is or in modified form, for Your private purposes, while protecting the owners and contributors to the software from liability. 18 | 19 | This License also strives to protect the freedom and autonomy of third parties who receive the Work from you. If any non-affiliated third party receives any part, aspect, or element of the Work from You, this License requires that You provide that third party all the permissions and materials needed to independently use and modify the Work without that third party having a loss of data or capability due to your actions. 20 | 21 | The full permissions, conditions, and other terms are laid out below. 22 | 23 | ## 2. Receiving a License 24 | 25 | In order to receive this License, You must agree to its rules. The rules of this License are both obligations of Your agreement with the Licensor and conditions to your License. You must not do anything with the Work that triggers a rule You cannot or will not follow. 26 | 27 | ### 2.1. Application 28 | 29 | The terms of this License apply to the Work as you receive it from Licensor, as well as to any modifications, elaborations, or implementations created by You that contain any licenseable portion of the Work (a “Modified Work”). Unless specified, any reference to the Work also applies to a Modified Work. 30 | 31 | ### 2.2. Offer and Acceptance 32 | 33 | This License is automatically offered to every person and organization. You show that you accept this License and agree to its conditions by taking any action with the Work that, absent this License, would infringe any intellectual property right held by Licensor. 34 | 35 | ### 2.3. Compliance and Remedies 36 | 37 | Any failure to act according to the terms and conditions of this License places Your use of the Work outside the scope of the License and infringes the intellectual property rights of the Licensor. In the event of infringement, the terms and conditions of this License may be enforced by Licensor under the intellectual property laws of any jurisdiction to which You are subject. You also agree that either the Licensor or a Recipient (as an intended third-party beneficiary) may enforce the terms and conditions of this License against You via specific performance. 38 | 39 | ## 3. Permissions and Conditions 40 | 41 | ### 3.1. Permissions Granted 42 | 43 | Conditioned on compliance with section 4, and subject to the limitations of section 3.2, Licensor grants You the world-wide, royalty-free, non-exclusive permission to: 44 | 45 | > a) Take any action with the Work that would infringe the non-patent intellectual property laws of any jurisdiction to which You are subject; and 46 | > 47 | > b) Take any action with the Work that would infringe any patent claims that Licensor can license or becomes able to license, to the extent that those claims are embodied in the Work as distributed by Licensor. 48 | 49 | ### 3.2. Limitations on Permissions Granted 50 | 51 | The following limitations apply to the permissions granted in section 3.1: 52 | 53 | > a) Licensor does not grant any patent license for claims that are only infringed due to modification of the Work as provided by Licensor, or the combination of the Work as provided by Licensor, directly or indirectly, with any other component, including other software or hardware. 54 | > 55 | > b) Licensor does not grant any license to the trademarks, service marks, or logos of Licensor, except to the extent necessary to comply with the attribution conditions in section 4.1 of this License. 56 | 57 | ## 4. Conditions 58 | 59 | If You exercise any permission granted by this License, such that the Work, or any part, aspect, or element of the Work, is distributed, communicated, made available, or made perceptible to a non-Affiliate third party (a “Recipient”), either via physical delivery or via a network connection to the Recipient, You must comply with the following conditions: 60 | 61 | ### 4.1. Provide Access to Source Code 62 | 63 | Subject to the exception in section 4.4, You must provide to each Recipient a copy of, or no-charge unrestricted network access to, the Source Code corresponding to the Work. 64 | 65 | The “Source Code” of the Work means the form of the Work preferred for making modifications, including any comments, configuration information, documentation, help materials, installation instructions, cryptographic seeds or keys, and any information reasonably necessary for the Recipient to independently compile and use the Source Code and to have full access to the functionality contained in the Work. 66 | 67 | #### 4.1.1. Providing Network Access to the Source Code 68 | 69 | Network access to the Notices and Source Code may be provided by You or by a third party, such as a public software repository, and must persist during the same period in which You exercise any of the permissions granted to You under this License and for at least one year thereafter. 70 | 71 | #### 4.1.2. Source Code for a Modified Work 72 | 73 | Subject to the exception in section 4.5, You must provide to each Recipient of a Modified Work Access to Source Code corresponding to those portions of the Work remaining in the Modified Work as well as the modifications used by You to create the Modified Work. The Source Code corresponding to the modifications in the Modified Work must be provided to the Recipient either a) under this License, or b) under a Compatible Open Source License. 74 | 75 | A “Compatible Open Source License” means a license accepted by the Open Source Initiative that allows object code created using both Source Code provided under this License and Source Code provided under the other open source license to be distributed together as a single work. 76 | 77 | #### 4.1.3. Coordinated Disclosure of Security Vulnerabilities 78 | 79 | You may delay providing the Source Code corresponding to a particular modification of the Work for up to ninety (90) days (the “Embargo Period”) if: a) the modification is intended to address a newly-identified vulnerability or a security flaw in the Work, b) disclosure of the vulnerability or security flaw before the end of the Embargo Period would put the data, identity, or autonomy of one or more Recipients of the Work at significant risk, c) You are participating in a coordinated disclosure of the vulnerability or security flaw with one or more additional Licensees, and d) Access to the Source Code pertaining to the modification is provided to all Recipients at the end of the Embargo Period. 80 | 81 | ### 4.2. Maintain User Autonomy 82 | 83 | In addition to providing each Recipient the opportunity to have Access to the Source Code, You cannot use the permissions given under this License to interfere with a Recipient’s ability to fully use an independent copy of the Work generated from the Source Code You provide with the Recipient’s own User Data. 84 | 85 | “User Data” means any data that is an input to or an output from the Work, where the presence of the data is necessary for substantially identical use of the Work in an equivalent context chosen by the Recipient, and where the Recipient has an existing ownership interest, an existing right to possess, or where the data has been generated by, for, or has been assigned to the Recipient. 86 | 87 | #### 4.2.1. No Withholding User Data 88 | 89 | Throughout any period in which You exercise any of the permissions granted to You under this License, You must also provide to any Recipient to whom you provide services via the Work, a no-charge copy, provided in a commonly used electronic form, of the Recipient’s User Data in your possession, to the extent that such User Data is available to You for use in conjunction with the Work. 90 | 91 | #### 4.2.2. No Technical Measures that Limit Access 92 | 93 | You may not, by the use of cryptographic methods applied to anything provided to the Recipient, by possession or control of cryptographic keys, seeds, or hashes, by other technological protection measures, or by any other method, limit a Recipient's ability to access any functionality present in the Recipient's independent copy of the Work, or deny a Recipient full control of the Recipient's User Data. 94 | 95 | #### 4.2.3. No Legal or Contractual Measures that Limit Access 96 | 97 | You may not contractually restrict a Recipient's ability to independently exercise the permissions granted under this License. You waive any legal power to forbid circumvention of technical protection measures that include use of the Work, and You waive any claim that the capabilities of the Work were limited or modified as a means of enforcing the legal rights of third parties against Recipients. 98 | 99 | ### 4.3. Provide Notices and Attribution 100 | 101 | You must retain all licensing, authorship, or attribution notices contained in the Source Code (the “Notices”), and provide all such Notices to each Recipient, together with a statement acknowledging the use of the Work. Notices may be provided directly to a Recipient or via an easy-to-find hyperlink to an Internet location also providing Access to Source Code. 102 | 103 | ### 4.4. Scope of Conditions in this License 104 | 105 | You are required to uphold the conditions of this License only relative to those who are Recipients of the Work from You. Other than providing Recipients with the applicable Notices, Access to Source Code, and a copy of and full control of their User Data, nothing in this License requires You to provide processing services to or engage in network interactions with anyone. 106 | 107 | ### 4.5. Combined Work Exception 108 | 109 | As an exception to condition that You provide Recipients Access to Source Code, any Source Code files marked by the Licensor as having the “Combined Work Exception,” or any object code exclusively resulting from Source Code files so marked, may be combined with other Software into a “Larger Work.” So long as you comply with the requirements to provide Recipients the applicable Notices and Access to the Source Code provided to You by Licensor, and you provide Recipients access to their User Data and do not limit Recipient’s ability to independently work with their User Data, any other Software in the Larger Work as well as the Larger Work as a whole may be licensed under the terms of your choice. 110 | 111 | ## 5. Term and Termination 112 | 113 | The term of this License begins when You receive the Work, and continues until terminated for any of the reasons described herein, or until all Licensor’s intellectual property rights in the Software expire, whichever comes first (“Term”). This License cannot be revoked, only terminated for the reasons listed below. 114 | 115 | ### 5.1. Effect of Termination 116 | 117 | If this License is terminated for any reason, all permissions granted to You under Section 3 by any Licensor automatically terminate. You will immediately cease exercising any permissions granted in this License relative to the Work, including as part of any Modified Work. 118 | 119 | ### 5.2. Termination for Non-Compliance; Reinstatement 120 | 121 | This License terminates automatically if You fail to comply with any of the conditions in section 4. As a special exception to termination for non-compliance, Your permissions for the Work under this License will automatically be reinstated if You come into compliance with all the conditions in section 2 within sixty (60) days of being notified by Licensor or an intended third party beneficiary of Your noncompliance. You are eligible for reinstatement of permissions for the Work one time only, and only for the sixty days immediately after becoming aware of noncompliance. Loss of permissions granted for the Work under this License due to either a) sustained noncompliance lasting more than sixty days or b) subsequent termination for noncompliance after reinstatement, is permanent, unless rights are specifically restored by Licensor in writing. 122 | 123 | ### 5.3 Termination Due to Litigation 124 | 125 | If You initiate litigation against Licensor, or any Recipient of the Work, either direct or indirect, asserting that the Work directly or indirectly infringes any patent, then all permissions granted to You by this License shall terminate. In the event of termination due to litigation, all permissions validly granted by You under this License, directly or indirectly, shall survive termination. Administrative review procedures, declaratory judgment actions, counterclaims in response to patent litigation, and enforcement actions against former Licensees terminated under this section do not cause termination due to litigation. 126 | 127 | ## 6. Disclaimer of Warranty and Limit on Liability 128 | 129 | As far as the law allows, the Work comes AS-IS, without any warranty of any kind, and no Licensor or contributor will be liable to anyone for any damages related to this software or this license, under any kind of legal claim, or for any type of damages, including indirect, special, incidental, or consequential damages of any type arising as a result of this License or the use of the Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, loss of profits, revenue, or any and all other commercial damages or losses. 130 | 131 | ## 7. Other Provisions 132 | 133 | ### 7.1. Affiliates 134 | 135 | An “Affiliate” means any other entity that, directly or indirectly through one or more intermediaries, controls, is controlled by, or is under common control with, the Licensee. Employees of a Licensee and natural persons acting as contractors exclusively providing services to Licensee are also Affiliates. 136 | 137 | ### 7.2. Choice of Jurisdiction and Governing Law 138 | 139 | A Licensor may require that any action or suit by a Licensee relating to a Work provided by Licensor under this License may be brought only in the courts of a particular jurisdiction and under the laws of a particular jurisdiction (excluding its conflict-of-law provisions), if Licensor provides conspicuous notice of the particular jurisdiction to all Licensees. 140 | 141 | ### 7.3. No Sublicensing 142 | 143 | This License is not sublicensable. Each time You provide the Work or a Modified Work to a Recipient, the Recipient automatically receives a license under the terms described in this License. You may not impose any further reservations, conditions, or other provisions on any Recipients’ exercise of the permissions granted herein. 144 | 145 | ### 7.4. Attorneys' Fees 146 | 147 | In any action to enforce the terms of this License, or seeking damages relating thereto, including by an intended third party beneficiary, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. A “prevailing party” is the party that achieves, or avoids, compliance with this License, including through settlement. This section shall survive the termination of this License. 148 | 149 | ### 7.5. No Waiver 150 | 151 | Any failure by Licensor to enforce any provision of this License will not constitute a present or future waiver of such provision nor limit Licensor’s ability to enforce such provision at a later time. 152 | 153 | ### 7.6. Severability 154 | 155 | If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any invalid or unenforceable portion will be interpreted to the effect and intent of the original portion. If such a construction is not possible, the invalid or unenforceable portion will be severed from this License but the rest of this License will remain in full force and effect. 156 | 157 | ### 7.7. License for the Text of this License 158 | 159 | The text of this license is released under the Creative Commons Attribution-ShareAlike 4.0 International License, with the caveat that any modifications of this license may not use the name “Cryptographic Autonomy License” or any name confusingly similar thereto to describe any derived work of this License. 160 | 161 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # attestations 2 | 3 | Verifiable claims in the holochain world, i.e. "Who said what about/to whom" 4 | 5 | ## Context 6 | 7 | Cryptographically verifiable claims are quite usefull for a number of scenarios, see: Wiki. 8 | 9 | Interestingly, every entry committe by an agent in a holochain application can be used as a veriable claim, 10 | because Holochain keeps track of the signed actions of every entry which include the entry hash. Holochain 11 | natively validates these actions to ensure data integrity. 12 | 13 | By creating a very simple entry of the form: 14 | 15 | ```rust 16 | struct Attestation { 17 | content: String, 18 | about: AgentPubKey64, 19 | } 20 | ``` 21 | 22 | agents can claim arbitrary content about any other agent in a holochain DHT space. The signed actions of such 23 | entries can be shared and thus that claim by be confirmed by anyone as having been said by the attester. 24 | 25 | ### Use cases 26 | 27 | #### Membrane Crossing 28 | - **Holochain Membrane Proofs**: Holochain hApps can take membrane proofs that check ability of an agent to join a hApp. Attestations can be easily used as such proofs (see elemental-chat) 29 | - **DAO Discord access**: A common use case for NFTs in web3 happs, is to use them to verify that a given person can, for example take part 30 | in a given Discord channel. One can do the same with an instance of this holochain hApp, where a given agent makes 31 | attestations of other agents permissions, which are read by a discord server bot to allow access. 32 | 33 | #### Transferable NFTs 34 | 35 | Minting an NFT is the same as making an attestation about yourself as being the owner of a given digital asset. The asset could litterally be included in the content of the attestation. Transfering the NFT is just making an attestation that you have done so with the about being who you are transferring it to, and including the hash of the original attestation entry in content. Subsequent transfers simply include the hash of the previous attestation, thus creating a chain of custody. 36 | 37 | #### Reviews/Ratings/Badges/Certificates 38 | 39 | These are kind of obvious as they are all clearly just attestations by some authority about a agent. 40 | 41 | ## Design 42 | 43 | For more details read the [design documents](DESIGN.md). 44 | 45 | ## Installation 46 | 47 | 1. Install the holochain dev environment: https://developer.holochain.org/docs/install/ 48 | 2. Clone this repo: `git clone https://github.com/lightningrodlabs/attestations && cd ./attestations` 49 | 3. Enter the nix shell: `nix-shell` 50 | 4. Install the dependencies with: `npm install` 51 | 52 | ## Building the DNA 53 | 54 | - Build the DNA (assumes you are still in the nix shell for correct rust/cargo versions from step above): 55 | - Assemble the DNA: 56 | 57 | ```bash 58 | npm run build:happ 59 | ``` 60 | 61 | ### Running the DNA tests 62 | 63 | ```bash 64 | npm run test 65 | ``` 66 | 67 | ## UI 68 | 69 | To test out the UI: 70 | 71 | ```bash 72 | npm run start 73 | ``` 74 | 75 | ## Package 76 | 77 | To package the web happ: 78 | 79 | ```bash 80 | npm run package 81 | ``` 82 | 83 | You'll have the `attestations.webhapp` in `workdir`, and it's component `attestations.happ` in `dna/workdir/happ`, and `ui.zip` in `ui/apps/attestations`. 84 | 85 | ## License 86 | 87 | [![License: CAL 1.0](https://img.shields.io/badge/License-CAL%201.0-blue.svg)](https://github.com/holochain/cryptographic-autonomy-license) 88 | 89 | Copyright (C) 2022, Harris-Braun Enterprises, LLC 90 | 91 | This program is free software: you can redistribute it and/or modify it under the terms of the license 92 | provided in the LICENSE file (CAL-1.0). This program is distributed in the hope that it will be useful, 93 | but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 94 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | let 2 | holonixPath = (import ./nix/sources.nix).holonix; # points to the current state of the Holochain repository 3 | holonix = import (holonixPath) { 4 | holochainVersionId = "v0_0_175"; # specifies the Holochain version 5 | }; 6 | nixpkgs = holonix.pkgs; 7 | in nixpkgs.mkShell { 8 | inputsFrom = [ holonix.main ]; 9 | packages = with nixpkgs; [ 10 | niv 11 | nodejs-16_x 12 | # any additional packages needed for this project, e. g. Nodejs 13 | ]; 14 | } -------------------------------------------------------------------------------- /dna/workdir/dna/dna.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | manifest_version: "1" 3 | name: attestations 4 | integrity: 5 | uid: 00000000-0000-0000-0000-000000000000 6 | properties: ~ 7 | origin_time: 2022-02-11T23:05:19.470323Z 8 | zomes: 9 | - name: hc_zome_attestations_core 10 | bundled: ../../../target/wasm32-unknown-unknown/release/attestations_core.wasm 11 | - name: profiles_core 12 | bundled: ../../../target/wasm32-unknown-unknown/release/profiles_core.wasm 13 | coordinator: 14 | zomes: 15 | - name: hc_zome_attestations 16 | bundled: ../../../target/wasm32-unknown-unknown/release/attestations.wasm 17 | dependencies: 18 | - name: hc_zome_attestations_core 19 | - name: profiles 20 | bundled: ../../../target/wasm32-unknown-unknown/release/profiles.wasm 21 | dependencies: 22 | - name: profiles_core 23 | -------------------------------------------------------------------------------- /dna/workdir/happ/happ.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | manifest_version: "1" 3 | name: attestations 4 | description: ~ 5 | roles: 6 | - name: attestations 7 | provisioning: 8 | strategy: create 9 | deferred: false 10 | dna: 11 | bundled: "../dna/attestations.dna" 12 | properties: ~ 13 | uuid: ~ 14 | version: ~ 15 | clone_limit: 0 16 | -------------------------------------------------------------------------------- /dna/zomes/attestations/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["eric@harris-braun.com"] 3 | edition = "2021" 4 | name = "attestations" 5 | version = "0.0.1-alpha1" 6 | 7 | [lib] 8 | crate-type = ["cdylib", "rlib"] 9 | name = "attestations" 10 | 11 | [dependencies] 12 | chrono = { version = "0.4.22", default-features = false, features = ["clock", "std", "oldtime", "serde"], optional = true } 13 | derive_more = "0" 14 | serde = "1" 15 | thiserror = "1.0.20" 16 | attestations_core = { path = "../attestations_core" } 17 | hdk = {version = "0.0.163", features = ["encoding"]} 18 | -------------------------------------------------------------------------------- /dna/zomes/attestations/src/attestation.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | pub use hdk::prelude::*; 4 | use hdk::prelude::holo_hash::{AgentPubKeyB64, EntryHashB64}; 5 | use attestations_core::{EntryTypes, Attestation, LinkTypes}; 6 | 7 | use crate::error::*; 8 | //use crate::signals::*; 9 | 10 | /// Attestation entry definition 11 | #[derive(Clone, Serialize, Deserialize, Debug)] 12 | #[serde(rename_all="camelCase")] 13 | pub struct Verifiable { 14 | pub attestation: Option, 15 | pub signed_actions: Vec, 16 | } 17 | 18 | #[derive(Clone, Serialize, Deserialize, Debug)] 19 | pub struct AttestationContext { 20 | author: AgentPubKeyB64, 21 | timestamp: Timestamp, 22 | } 23 | 24 | #[derive(Clone, Serialize, Deserialize, Debug)] 25 | #[serde(rename_all="camelCase")] 26 | pub struct AttestationOutput { 27 | pub hash: EntryHashB64, 28 | pub attesters: Vec, 29 | pub content: Attestation, 30 | pub verifiable: Verifiable, 31 | } 32 | 33 | fn get_my_attestations_base() -> ExternResult { 34 | let me: AgentPubKey = agent_info()?.agent_latest_pubkey; 35 | Ok(me.into()) 36 | } 37 | 38 | fn get_agent_attestations_base(agent: AgentPubKey) -> ExternResult { 39 | Ok(agent.into()) 40 | } 41 | 42 | #[hdk_extern] 43 | pub fn create_attestation(input: Attestation) -> ExternResult { 44 | let _action_hash = create_entry(EntryTypes::Attestation(input.clone()))?; 45 | let hash = hash_entry(input.clone())?; 46 | // emit_signal(&SignalPayload::new(hash.clone().into(), Message::NewAttestation(input.clone())))?; 47 | create_link(get_my_attestations_base()?, hash.clone(), LinkTypes::By, ())?; 48 | create_link(get_agent_attestations_base(input.about.clone().into())?, hash.clone(), LinkTypes::Of, ())?; 49 | let path = Path::from(input.content); 50 | create_link(path.path_entry_hash()?, hash.clone(), LinkTypes::Who, LinkTag::from(AgentPubKey::from(input.about).as_ref().to_vec()))?; 51 | Ok(hash.into()) 52 | } 53 | 54 | #[derive(Clone, Serialize, Deserialize, Debug)] 55 | pub struct GetAttestationsInput { 56 | pub content: Option, 57 | pub by: Option, 58 | pub of: Option, 59 | } 60 | 61 | /// 62 | #[hdk_extern] 63 | pub fn get_attestations(input: GetAttestationsInput) -> ExternResult> { 64 | match input.content { 65 | Some(content) => { 66 | let base = Path::from(content).path_entry_hash()?; 67 | let (link_type, tag) = match input.of { 68 | Some(agent) => (Some(LinkTypes::Who), Some(LinkTag::new(AgentPubKey::from(agent).as_ref().to_vec()))), 69 | None => (None, None) 70 | }; 71 | let attestations = get_attestations_inner(base, link_type, tag)?; 72 | Ok(attestations) 73 | }, 74 | None => { 75 | // collect results in a hashmap to remove dups 76 | let mut results: HashMap = HashMap::new(); 77 | if let Some(agent) = input.of { 78 | let base = get_agent_attestations_base(agent.into())?; 79 | let attestations = get_attestations_inner(base, Some(LinkTypes::Of), None)?; 80 | for a in attestations { 81 | results.insert(a.hash.clone(), a); 82 | } 83 | }; 84 | if let Some(agent) = input.by { 85 | let base = get_agent_attestations_base(agent.into())?; 86 | let attestations = get_attestations_inner(base, Some(LinkTypes::By), None)?; 87 | for a in attestations { 88 | results.insert(a.hash.clone(), a); 89 | } 90 | }; 91 | Ok(results.into_iter().map(|(_,a)| a).collect()) 92 | } 93 | } 94 | } 95 | 96 | /// 97 | #[hdk_extern] 98 | fn get_my_attestations(_: ()) -> ExternResult> { 99 | let base = get_my_attestations_base()?; 100 | let records = get_attestations_inner(base,Some(LinkTypes::By), None)?; 101 | Ok(records) 102 | } 103 | 104 | 105 | pub fn get_attestations_inner(base: EntryHash, maybe_link_type: Option, maybe_tag: Option) -> AttestationsResult> { 106 | let links = match maybe_link_type { 107 | Some(link_type) => get_links(base, link_type, maybe_tag)?, 108 | None => get_links(base, .., maybe_tag)?, 109 | }; 110 | 111 | let get_input = links 112 | .into_iter() 113 | .map(|link| GetInput::new(EntryHash::from(link.target).into(), GetOptions::default())) 114 | .collect(); 115 | 116 | let attestation_elements = HDK.with(|hdk| hdk.borrow().get_details(get_input))?; 117 | 118 | let attestations: Vec = attestation_elements 119 | .into_iter() 120 | .filter_map(|me| me) 121 | .filter_map(|details| match details { 122 | Details::Entry(EntryDetails { entry, actions, .. }) => { 123 | let attestation: Attestation = entry.try_into().ok()?; 124 | let hash = hash_entry(&attestation).ok()?; 125 | Some(AttestationOutput { 126 | hash: hash.into(), 127 | attesters: actions.clone().into_iter().map(|action| { 128 | let h = action.action(); 129 | AttestationContext { 130 | author: h.author().clone().into(), 131 | timestamp: h.timestamp(), 132 | } 133 | }).collect(), 134 | verifiable: Verifiable { 135 | signed_actions: actions, 136 | attestation: None, 137 | }, 138 | content: attestation, 139 | }) 140 | } 141 | _ => None, 142 | }) 143 | .collect(); 144 | Ok(attestations) 145 | } 146 | 147 | /// 148 | #[hdk_extern] 149 | pub fn verify(input: Verifiable) -> ExternResult<()> { 150 | for signed_action in input.signed_actions { 151 | if let Some(ref attestation) = input.attestation { 152 | let hash = hash_entry(attestation)?; 153 | let action_hash = signed_action.action().entry_hash().ok_or(wasm_error!(WasmErrorInner::Guest("Failed verification: couldn't get hash from action".into())))?; 154 | if *action_hash != hash { 155 | return Err(wasm_error!(WasmErrorInner::Guest("Failed verification: attestation hash doesn't match".into()))); 156 | } 157 | } 158 | let signature = signed_action.signature().clone(); 159 | match verify_signature(signed_action.action().author().clone(), signature, signed_action.action()) { 160 | Ok(verified) => { 161 | if verified { 162 | } else { 163 | return Err(wasm_error!(WasmErrorInner::Guest("Failed verification: signature doesn't match.".into()))) 164 | } 165 | } 166 | Err(e) => { 167 | return Err(wasm_error!(WasmErrorInner::Guest(format!("Failed verification: error checking signature {}", e.to_string())))); 168 | } 169 | } 170 | } 171 | Ok(()) 172 | } -------------------------------------------------------------------------------- /dna/zomes/attestations/src/error.rs: -------------------------------------------------------------------------------- 1 | use hdk::prelude::*; 2 | use std::convert::Infallible; 3 | 4 | #[derive(thiserror::Error, Debug)] 5 | pub enum AttestationsError { 6 | #[error(transparent)] 7 | Serialization(#[from] SerializedBytesError), 8 | #[error(transparent)] 9 | Infallible(#[from] Infallible), 10 | #[error(transparent)] 11 | EntryError(#[from] EntryError), 12 | #[error("Failed to convert an agent link tag to an agent pub key")] 13 | AgentTag, 14 | #[error(transparent)] 15 | Wasm(#[from] WasmError), 16 | #[error(transparent)] 17 | Timestamp(#[from] TimestampError), 18 | } 19 | 20 | pub type AttestationsResult = Result; 21 | 22 | impl From for WasmError { 23 | fn from(c: AttestationsError) -> Self { 24 | wasm_error!(WasmErrorInner::Guest(c.to_string())) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /dna/zomes/attestations/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub use error::{AttestationsError, AttestationsResult}; 2 | 3 | pub use hdk::prelude::Path; 4 | pub use hdk::prelude::*; 5 | 6 | pub mod attestation; 7 | pub mod error; 8 | pub mod nonce; 9 | pub mod signals; 10 | 11 | #[hdk_extern] 12 | fn init(_: ()) -> ExternResult { 13 | // grant unrestricted access to accept_cap_claim so other agents can send us claims 14 | let mut functions = BTreeSet::new(); 15 | functions.insert((zome_info()?.name, "recv_remote_signal".into())); 16 | functions.insert((zome_info()?.name, "recv_fulfillment".into())); 17 | create_cap_grant(CapGrantEntry { 18 | tag: "".into(), 19 | // empty access converts to unrestricted 20 | access: ().into(), 21 | functions, 22 | })?; 23 | Ok(InitCallbackResult::Pass) 24 | } 25 | -------------------------------------------------------------------------------- /dna/zomes/attestations/src/nonce.rs: -------------------------------------------------------------------------------- 1 | use hdk::prelude::{serde_bytes::ByteBuf, holo_hash::{AgentPubKeyB64}}; 2 | pub use hdk::prelude::*; 3 | 4 | use crate::attestation::{self, GetAttestationsInput, Verifiable}; 5 | use attestations_core::{Attestation, Nonce, EntryTypes, UnitEntryTypes}; 6 | 7 | /// Input to the fulfill_nonce call 8 | #[derive(Serialize, Deserialize, SerializedBytes, Debug)] 9 | #[serde(rename_all = "camelCase")] 10 | pub struct CreateNonceInput { 11 | pub with: AgentPubKeyB64, 12 | pub note: String, 13 | } 14 | 15 | pub fn new_nonce(input: CreateNonceInput) -> ExternResult { 16 | let id_bytes = random_bytes(4)?; 17 | let id: u32 = as_u32_be(&id_bytes); 18 | Ok(Nonce { id, with: input.with, note: input.note }) 19 | } 20 | 21 | #[hdk_extern] 22 | fn create_nonce(input: CreateNonceInput) -> ExternResult { 23 | let nonce = new_nonce(input)?; 24 | let _action_hash = create_entry(EntryTypes::Nonce(nonce.clone()))?; 25 | Ok(nonce.id) 26 | } 27 | 28 | /// Input to the fulfill_nonce call 29 | #[derive(Serialize, Deserialize, SerializedBytes, Debug)] 30 | #[serde(rename_all = "camelCase")] 31 | pub struct FulfillNonceInput { 32 | pub with: AgentPubKeyB64, 33 | pub nonce: u32, 34 | } 35 | 36 | #[derive(Serialize, Deserialize, SerializedBytes, Debug)] 37 | #[serde(rename_all = "camelCase")] 38 | pub struct FulfillNonceWire { 39 | pub action: SignedActionHashed, 40 | pub nonce: String, 41 | } 42 | 43 | #[hdk_extern] 44 | fn fulfill_nonce(input: FulfillNonceInput) -> ExternResult<()> { 45 | let a = Attestation { 46 | content: input.nonce.to_string(), 47 | about: input.with.clone(), 48 | }; 49 | attestation::create_attestation(a.clone())?; 50 | let get_input = GetAttestationsInput { 51 | content: Some(a.content.clone()), 52 | of: Some(a.about.clone()), 53 | by: None, 54 | }; 55 | let attestations = attestation::get_attestations(get_input)?; 56 | let fulfillment = FulfillNonceWire { 57 | action: attestations[0].verifiable.signed_actions[0].clone(), 58 | nonce: input.nonce.to_string(), 59 | }; 60 | let result = call_remote( 61 | input.with.into(), 62 | "hc_zome_attestations", 63 | "recv_fulfillment".into(), 64 | None, 65 | ExternIO::encode(fulfillment).map_err(|e| wasm_error!(e))?, //input.one_time_key.to_string(), 66 | )?; 67 | if let ZomeCallResponse::Ok(io) = result { 68 | let decoded_result: () = ExternIO::decode(&io).map_err(|e| wasm_error!(e))?; 69 | debug!("got return value {:?}", decoded_result); 70 | Ok(()) 71 | } else { 72 | Err(wasm_error!(WasmErrorInner::Guest(format!("Nonce error: {:?}", result)))) 73 | } 74 | } 75 | 76 | fn as_u32_be(array: &ByteBuf) -> u32 { 77 | ((array[0] as u32) << 24) + 78 | ((array[1] as u32) << 16) + 79 | ((array[2] as u32) << 8) + 80 | ((array[3] as u32) << 0) 81 | } 82 | 83 | 84 | #[derive(Serialize, Deserialize, SerializedBytes, Debug)] 85 | pub struct NonceReceived { 86 | nonce: String, 87 | from: AgentPubKeyB64, 88 | } 89 | 90 | #[hdk_extern] 91 | fn recv_fulfillment(input: ExternIO) -> ExternResult<()> { 92 | //let me: AgentPubKeyB64 = agent_info()?.agent_latest_pubkey.into(); 93 | let caller: AgentPubKeyB64 = call_info()?.provenance.into(); 94 | let me = agent_info()?.agent_latest_pubkey; 95 | debug!("agent info: {:?}", me); 96 | let meb64: AgentPubKeyB64 = me.into(); 97 | let fulfillment: FulfillNonceWire = ExternIO::decode(&input).map_err(|e| wasm_error!(e))?; 98 | 99 | // lookup nonce private entry locally and confirm that the signature and the caller match 100 | // by building a verifiable with a constructed attestation and calling verify 101 | let q = ChainQueryFilter::default().entry_type(UnitEntryTypes::Nonce.try_into().unwrap()).include_entries(true); 102 | let results : Vec = query(q)?.into_iter().filter_map(|element|{ 103 | let nonce: Nonce = element.entry().to_app_option().ok()??; 104 | if nonce.id.to_string() == fulfillment.nonce && nonce.with == caller { 105 | Some(nonce) 106 | } else { 107 | None 108 | } 109 | }).collect(); 110 | if results.len() == 0 { 111 | return Err(wasm_error!(WasmErrorInner::Guest("No such nonce".into()))) 112 | } 113 | let attestation = Attestation {content: fulfillment.nonce.clone(), about: meb64}; 114 | let verifiable = Verifiable { 115 | attestation: Some(attestation), 116 | signed_actions: vec![fulfillment.action.clone()] 117 | }; 118 | attestation::verify(verifiable.clone())?; 119 | // tell the client we got valid nonce 120 | emit_signal(&NonceReceived{nonce: fulfillment.nonce, from: caller.into()})?; 121 | Ok(()) 122 | } 123 | 124 | -------------------------------------------------------------------------------- /dna/zomes/attestations/src/signals.rs: -------------------------------------------------------------------------------- 1 | use holo_hash::{AgentPubKeyB64, EntryHashB64}; 2 | 3 | use attestations_core::Attestation; 4 | use crate::attestation::*; 5 | 6 | #[derive(Serialize, Deserialize, SerializedBytes, Debug)] 7 | #[serde(tag = "type", content = "content")] 8 | pub enum Message { 9 | NewAttestation(Attestation), 10 | } 11 | 12 | #[derive(Serialize, Deserialize, Debug)] 13 | #[serde(rename_all = "camelCase")] 14 | pub struct SignalPayload { 15 | attestation_hash: EntryHashB64, 16 | message: Message, 17 | } 18 | 19 | impl SignalPayload { 20 | pub fn new(attestation_hash: EntryHashB64, message: Message) -> Self { 21 | SignalPayload { 22 | attestation_hash, 23 | message, 24 | } 25 | } 26 | } 27 | 28 | #[hdk_extern] 29 | fn recv_remote_signal(signal: ExternIO) -> ExternResult<()> { 30 | let sig: SignalPayload = signal.decode().map_err(|e| wasm_error!(e))?; 31 | debug!("Received signal {:?}", sig); 32 | Ok(emit_signal(&sig)?) 33 | } 34 | 35 | /// Input to the notify call 36 | #[derive(Serialize, Deserialize, SerializedBytes, Debug)] 37 | #[serde(rename_all = "camelCase")] 38 | pub struct NotifyInput { 39 | pub folks: Vec, 40 | pub signal: SignalPayload, 41 | } 42 | 43 | #[hdk_extern] 44 | fn notify(input: NotifyInput) -> ExternResult<()> { 45 | let mut folks: Vec = vec![]; 46 | for a in input.folks.clone() { 47 | folks.push(a.into()) 48 | } 49 | debug!("Sending signal {:?} to {:?}", input.signal, input.folks); 50 | remote_signal(ExternIO::encode(input.signal).map_err(|e| wasm_error!(e))?, folks)?; 51 | Ok(()) 52 | } 53 | -------------------------------------------------------------------------------- /dna/zomes/attestations_core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["eric@harris-braun.com"] 3 | edition = "2021" 4 | name = "attestations_core" 5 | version = "0.0.1-alpha1" 6 | 7 | [lib] 8 | crate-type = ["cdylib", "rlib"] 9 | name = "attestations_core" 10 | 11 | [dependencies] 12 | serde = "1" 13 | derive_more = "0" 14 | hdk = {version = "=0.0.163", features = ["encoding"]} 15 | hdi = {version = "=0.1.10"} 16 | 17 | -------------------------------------------------------------------------------- /dna/zomes/attestations_core/src/lib.rs: -------------------------------------------------------------------------------- 1 | use hdi::prelude::*; 2 | 3 | use hdk::prelude::holo_hash::{AgentPubKeyB64}; 4 | 5 | /// Attestation entry definition 6 | #[hdk_entry_helper] 7 | #[serde(rename_all = "camelCase")] 8 | #[derive(Clone)] 9 | pub struct Attestation { 10 | pub content: String, 11 | pub about: AgentPubKeyB64, 12 | } 13 | 14 | /// Nonce entry definition 15 | #[hdk_entry_helper] 16 | #[derive(Clone)] 17 | pub struct Nonce { 18 | pub id: u32, 19 | pub note: String, 20 | pub with: AgentPubKeyB64, 21 | } 22 | 23 | #[hdk_entry_defs] 24 | #[unit_enum(UnitEntryTypes)] 25 | pub enum EntryTypes { 26 | #[entry_def(required_validations = 5)] 27 | Attestation(Attestation), 28 | #[entry_def(required_validations = 5, visibility= "private")] 29 | Nonce(Nonce), 30 | } 31 | 32 | #[hdk_link_types] 33 | pub enum LinkTypes { 34 | Of, 35 | By, 36 | Who, 37 | } 38 | 39 | #[hdk_extern] 40 | pub fn validate(op: Op) -> ExternResult { 41 | match op { 42 | Op::StoreRecord ( _ ) => Ok(ValidateCallbackResult::Valid), 43 | Op::StoreEntry { .. } => Ok(ValidateCallbackResult::Valid), 44 | Op::RegisterCreateLink (create_link) => { 45 | //let hashed = create_link.hashed; 46 | let (create, _action) = create_link.create_link.into_inner(); 47 | let link_type = LinkTypes::try_from(ScopedLinkType { 48 | zome_index: create.zome_index, 49 | zome_type: create.link_type, 50 | })?; 51 | if link_type == LinkTypes::By { 52 | Ok(ValidateCallbackResult::Valid) 53 | } else if link_type == LinkTypes::Of { 54 | Ok(ValidateCallbackResult::Valid) 55 | } else if link_type == LinkTypes::Who { 56 | let attestation: Attestation = must_get_entry(create.target_address.clone().into())?.try_into()?; 57 | let agent = AgentPubKey::try_from(SerializedBytes::try_from(create.tag.clone()).map_err(|e| wasm_error!(e))?).map_err(|e| wasm_error!(e))?; 58 | 59 | if AgentPubKey::from(attestation.about) == agent { 60 | Ok(ValidateCallbackResult::Valid) 61 | } else { 62 | Ok(ValidateCallbackResult::Invalid( 63 | "tag doesn't point to about".to_string(), 64 | )) 65 | } 66 | } else { 67 | Ok(ValidateCallbackResult::Invalid( 68 | "unknown link type".to_string(), 69 | )) 70 | } 71 | } 72 | Op::RegisterDeleteLink (_)=> Ok(ValidateCallbackResult::Invalid( 73 | "deleting links isn't valid".to_string(), 74 | )), 75 | Op::RegisterUpdate { .. } => Ok(ValidateCallbackResult::Invalid( 76 | "updating entries isn't valid".to_string(), 77 | )), 78 | Op::RegisterDelete { .. } => Ok(ValidateCallbackResult::Invalid( 79 | "deleting entries isn't valid".to_string(), 80 | )), 81 | Op::RegisterAgentActivity { .. } => Ok(ValidateCallbackResult::Valid), 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /dna/zomes/profiles/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["eric@harris-braun.com"] 3 | edition = "2021" 4 | name = "profiles" 5 | version = "0.0.1-alpha1" 6 | 7 | [lib] 8 | crate-type = ["cdylib", "rlib"] 9 | name = "profiles" 10 | 11 | [dependencies] 12 | profiles = {git = "https://github.com/holochain-open-dev/profiles", rev = "for-hdk-v0.0.163", package = "hc_zome_profiles_coordinator"} 13 | 14 | -------------------------------------------------------------------------------- /dna/zomes/profiles/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate profiles; 2 | -------------------------------------------------------------------------------- /dna/zomes/profiles_core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["eric@harris-braun.com"] 3 | edition = "2021" 4 | name = "profiles_core" 5 | version = "0.0.1-alpha1" 6 | 7 | [lib] 8 | crate-type = ["cdylib", "rlib"] 9 | name = "profiles_core" 10 | 11 | [dependencies] 12 | profiles_core = {git = "https://github.com/holochain-open-dev/profiles", rev = "for-hdk-v0.0.163", package = "hc_zome_profiles_integrity"} 13 | -------------------------------------------------------------------------------- /dna/zomes/profiles_core/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate profiles_core; 2 | -------------------------------------------------------------------------------- /nix/sources.json: -------------------------------------------------------------------------------- 1 | { 2 | "holonix": { 3 | "branch": "main", 4 | "description": "NixOS && Holochain", 5 | "homepage": "", 6 | "owner": "holochain", 7 | "repo": "holonix", 8 | "rev": "63e20c12486fee9123a146c91cb9ae6094bc7586", 9 | "sha256": "1x8d1xdw00g7l6r7bdf8g29r7s381hldihxn52hmxk5ni43fg0ps", 10 | "type": "tarball", 11 | "url": "https://github.com/holochain/holonix/archive/63e20c12486fee9123a146c91cb9ae6094bc7586.tar.gz", 12 | "url_template": "https://github.com///archive/.tar.gz" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /nix/sources.nix: -------------------------------------------------------------------------------- 1 | # This file has been generated by Niv. 2 | 3 | let 4 | 5 | # 6 | # The fetchers. fetch_ fetches specs of type . 7 | # 8 | 9 | fetch_file = pkgs: name: spec: 10 | let 11 | name' = sanitizeName name + "-src"; 12 | in 13 | if spec.builtin or true then 14 | builtins_fetchurl { inherit (spec) url sha256; name = name'; } 15 | else 16 | pkgs.fetchurl { inherit (spec) url sha256; name = name'; }; 17 | 18 | fetch_tarball = pkgs: name: spec: 19 | let 20 | name' = sanitizeName name + "-src"; 21 | in 22 | if spec.builtin or true then 23 | builtins_fetchTarball { name = name'; inherit (spec) url sha256; } 24 | else 25 | pkgs.fetchzip { name = name'; inherit (spec) url sha256; }; 26 | 27 | fetch_git = name: spec: 28 | let 29 | ref = 30 | if spec ? ref then spec.ref else 31 | if spec ? branch then "refs/heads/${spec.branch}" else 32 | if spec ? tag then "refs/tags/${spec.tag}" else 33 | abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!"; 34 | in 35 | builtins.fetchGit { url = spec.repo; inherit (spec) rev; inherit ref; }; 36 | 37 | fetch_local = spec: spec.path; 38 | 39 | fetch_builtin-tarball = name: throw 40 | ''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`. 41 | $ niv modify ${name} -a type=tarball -a builtin=true''; 42 | 43 | fetch_builtin-url = name: throw 44 | ''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`. 45 | $ niv modify ${name} -a type=file -a builtin=true''; 46 | 47 | # 48 | # Various helpers 49 | # 50 | 51 | # https://github.com/NixOS/nixpkgs/pull/83241/files#diff-c6f540a4f3bfa4b0e8b6bafd4cd54e8bR695 52 | sanitizeName = name: 53 | ( 54 | concatMapStrings (s: if builtins.isList s then "-" else s) 55 | ( 56 | builtins.split "[^[:alnum:]+._?=-]+" 57 | ((x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) name) 58 | ) 59 | ); 60 | 61 | # The set of packages used when specs are fetched using non-builtins. 62 | mkPkgs = sources: system: 63 | let 64 | sourcesNixpkgs = 65 | import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) { inherit system; }; 66 | hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath; 67 | hasThisAsNixpkgsPath = == ./.; 68 | in 69 | if builtins.hasAttr "nixpkgs" sources 70 | then sourcesNixpkgs 71 | else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then 72 | import {} 73 | else 74 | abort 75 | '' 76 | Please specify either (through -I or NIX_PATH=nixpkgs=...) or 77 | add a package called "nixpkgs" to your sources.json. 78 | ''; 79 | 80 | # The actual fetching function. 81 | fetch = pkgs: name: spec: 82 | 83 | if ! builtins.hasAttr "type" spec then 84 | abort "ERROR: niv spec ${name} does not have a 'type' attribute" 85 | else if spec.type == "file" then fetch_file pkgs name spec 86 | else if spec.type == "tarball" then fetch_tarball pkgs name spec 87 | else if spec.type == "git" then fetch_git name spec 88 | else if spec.type == "local" then fetch_local spec 89 | else if spec.type == "builtin-tarball" then fetch_builtin-tarball name 90 | else if spec.type == "builtin-url" then fetch_builtin-url name 91 | else 92 | abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}"; 93 | 94 | # If the environment variable NIV_OVERRIDE_${name} is set, then use 95 | # the path directly as opposed to the fetched source. 96 | replace = name: drv: 97 | let 98 | saneName = stringAsChars (c: if isNull (builtins.match "[a-zA-Z0-9]" c) then "_" else c) name; 99 | ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}"; 100 | in 101 | if ersatz == "" then drv else 102 | # this turns the string into an actual Nix path (for both absolute and 103 | # relative paths) 104 | if builtins.substring 0 1 ersatz == "/" then /. + ersatz else /. + builtins.getEnv "PWD" + "/${ersatz}"; 105 | 106 | # Ports of functions for older nix versions 107 | 108 | # a Nix version of mapAttrs if the built-in doesn't exist 109 | mapAttrs = builtins.mapAttrs or ( 110 | f: set: with builtins; 111 | listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set)) 112 | ); 113 | 114 | # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295 115 | range = first: last: if first > last then [] else builtins.genList (n: first + n) (last - first + 1); 116 | 117 | # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257 118 | stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1)); 119 | 120 | # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269 121 | stringAsChars = f: s: concatStrings (map f (stringToCharacters s)); 122 | concatMapStrings = f: list: concatStrings (map f list); 123 | concatStrings = builtins.concatStringsSep ""; 124 | 125 | # https://github.com/NixOS/nixpkgs/blob/8a9f58a375c401b96da862d969f66429def1d118/lib/attrsets.nix#L331 126 | optionalAttrs = cond: as: if cond then as else {}; 127 | 128 | # fetchTarball version that is compatible between all the versions of Nix 129 | builtins_fetchTarball = { url, name ? null, sha256 }@attrs: 130 | let 131 | inherit (builtins) lessThan nixVersion fetchTarball; 132 | in 133 | if lessThan nixVersion "1.12" then 134 | fetchTarball ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; })) 135 | else 136 | fetchTarball attrs; 137 | 138 | # fetchurl version that is compatible between all the versions of Nix 139 | builtins_fetchurl = { url, name ? null, sha256 }@attrs: 140 | let 141 | inherit (builtins) lessThan nixVersion fetchurl; 142 | in 143 | if lessThan nixVersion "1.12" then 144 | fetchurl ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; })) 145 | else 146 | fetchurl attrs; 147 | 148 | # Create the final "sources" from the config 149 | mkSources = config: 150 | mapAttrs ( 151 | name: spec: 152 | if builtins.hasAttr "outPath" spec 153 | then abort 154 | "The values in sources.json should not have an 'outPath' attribute" 155 | else 156 | spec // { outPath = replace name (fetch config.pkgs name spec); } 157 | ) config.sources; 158 | 159 | # The "config" used by the fetchers 160 | mkConfig = 161 | { sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null 162 | , sources ? if isNull sourcesFile then {} else builtins.fromJSON (builtins.readFile sourcesFile) 163 | , system ? builtins.currentSystem 164 | , pkgs ? mkPkgs sources system 165 | }: rec { 166 | # The sources, i.e. the attribute set of spec name to spec 167 | inherit sources; 168 | 169 | # The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers 170 | inherit pkgs; 171 | }; 172 | 173 | in 174 | mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); } 175 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "attestations-dev", 3 | "private": true, 4 | "workspaces": [ 5 | "ui/apps/*", 6 | "ui/lib", 7 | "tests" 8 | ], 9 | "scripts": { 10 | "start" : "npm run build:happ && npm run start:agent", 11 | "network" : "npm run build:happ && concurrently-repeat \"npm run start:agent\"", 12 | "network-playground" : "npm run build:happ && concurrently-repeat \"npm run start:agent:playground\"", 13 | "network-proxied" : "npm run build:happ && concurrently-repeat \"npm run start:agent-proxied\"", 14 | "start:agent-proxied" : "cross-env HC_PORT=$(port) concurrently \"npm run dev:libs\" \"npm run start:happ-proxied\" \"sleep 5 && npm run start -w attestations\"", 15 | "start:agent" : "cross-env HC_PORT=$(port) concurrently \"npm run dev:libs\" \"npm run start:happ\" \"sleep 5 && npm run start -w attestations\"", 16 | "start:agent:playground": "cross-env HC_PORT=$(port) concurrently \"npm run playground\" \"npm run dev:libs\" \"npm run start:happ\" \"sleep 5 && npm run start -w attestations\"", 17 | "dev:libs" : "npm run build:watch -w @attestations/elements", 18 | "start-proxied" : "npm run build:happ && npm run build -w @attestations/elements && cross-env HC_PORT=$(port) concurrently -k \"npm run start:happ-proxied\" \"npm run start -w attestations\"", 19 | "start-rerun" : "cross-env HC_PORT=8888 concurrently -k \"npm run build:watch -w @attestations/elements\" \"echo \"pass\" | hc s --piped run 0 -p 8888\" \"npm run start -w attestations\"", 20 | "prepare" : "npm run build -w @attestations/elements && npm run build -w attestations", 21 | "test" : "npm run build:happ && npm run build -w @attestations/elements && npm t -w tests", 22 | "start:happ" : "RUST_LOG=warn echo \"pass\" | hc s --piped generate ./dna/workdir/happ/attestations.happ --run=$HC_PORT -a attestations network mdns", 23 | "start:happ-proxied" : "RUST_LOG=warn echo \"pass\" | hc s --piped generate ./dna/workdir/happ/attestations.happ --run=$HC_PORT -a attestations network --bootstrap https://bootstrap-staging.holo.host/ quic -p=kitsune-proxy://SYVd4CF3BdJ4DS7KwLLgeU3_DbHoZ34Y-qroZ79DOs8/kitsune-quic/h/165.22.32.11/p/5779/--", 24 | "package" : "npm run build:happ && npm run build -w @attestations/elements && npm run package -w attestations && hc web-app pack workdir", 25 | "build:happ" : "npm run build:dna && hc app pack ./dna/workdir/happ", 26 | "build:dna" : "npm run build:zome && hc dna pack ./dna/workdir/dna", 27 | "build:zome" : "CARGO_TARGET_DIR=target cargo build --release --target wasm32-unknown-unknown", 28 | "clean" : "rimraf node_modules && rimraf ui/apps/attestations/node_modules/ && rimraf ui/lib/node_modules && rimraf test/node_modules", 29 | "clean:hc" : "rimraf .hc*", 30 | "playground" : "run-singleton \"holochain-playground\"" 31 | }, 32 | "devDependencies": { 33 | "@holochain-playground/cli": "^0.0.8", 34 | "concurrently": "^6.2.1", 35 | "concurrently-repeat": "^0.0.1", 36 | "cross-env": "^7.0.3", 37 | "json-parse-better-errors": "^1.0.2", 38 | "new-port-cli": "^1.0.0", 39 | "rimraf": "^3.0.2", 40 | "run-singleton-cli": "^0.0.5" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | *.log 3 | -------------------------------------------------------------------------------- /tests/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@attestations/tests", 3 | "version": "0.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "npm run test:zome", 8 | "test:zome": "set -o pipefail && TRYORAMA_LOG_LEVEL=debug RUST_BACKTRACE=1 RUST_LOG=holochain::core::ribosome::host_fn::debug=debug TRYORAMA_HOLOCHAIN_PATH=\"holochain\" node --loader ts-node/esm --experimental-specifier-resolution=node src/index.ts | tap-diff" 9 | }, 10 | "author": "", 11 | "license": "CAL-1.0", 12 | "dependencies": { 13 | "@holochain/client": "^0.7.0", 14 | "@msgpack/msgpack": "^2.7.0", 15 | "esm": "^3.2.25", 16 | "js-base64": "^3.6.1", 17 | "lodash-es": "^4.17.21", 18 | "path": "^0.12.7", 19 | "tape": "^5.2.2", 20 | "tape-promise": "^4.0.0", 21 | "ts-node": "^10.4.0", 22 | "typescript": "4.3.5", 23 | "uuidv4": "^6.2.11" 24 | }, 25 | "devDependencies": { 26 | "@detools/tap-diff": "^0.2.2", 27 | "@holochain/tryorama": "^0.7.0", 28 | "@types/lodash": "^4.14.173", 29 | "@types/node": "^14.0.14" 30 | }, 31 | "type": "module" 32 | } 33 | -------------------------------------------------------------------------------- /tests/src/index.ts: -------------------------------------------------------------------------------- 1 | import { ActionHash, DnaSource } from "@holochain/client"; 2 | import { pause, runScenario, Scenario } from "@holochain/tryorama"; 3 | import path from "path"; 4 | import { fileURLToPath } from "url"; 5 | const __filename = fileURLToPath(import.meta.url); 6 | const __dirname = path.dirname(__filename); 7 | const dnaPath = path.join(__dirname, "../../dna/workdir/dna/attestations.dna") 8 | 9 | import * as _ from "lodash"; 10 | import {Attestation, AttestationOutput} from "../../ui/lib/src/types" 11 | import test from "tape-promise/tape.js"; 12 | import {EntryHashB64, AgentPubKeyB64} from "@holochain-open-dev/core-types"; 13 | 14 | import { Base64 } from "js-base64"; 15 | import { delay } from "lodash"; 16 | 17 | function serializeHash(hash: Uint8Array): AgentPubKeyB64 { 18 | return `u${Base64.fromUint8Array(hash, true)}`; 19 | } 20 | 21 | function checkAttestations(t, attestationObject: AttestationOutput, attestation: Attestation, hash: EntryHashB64, attesters: Array) { 22 | t.equal(attestationObject.hash, hash) 23 | t.deepEqual(attestationObject.content, attestation) 24 | attestationObject.attesters.forEach((element,i) => { 25 | t.equal(attesters[i], element.author) 26 | }); 27 | } 28 | 29 | test("attestations basic tests", async (t) => { 30 | await runScenario(async (scenario: Scenario) => { 31 | 32 | 33 | const dnas: DnaSource[] = [{ path: dnaPath }]; 34 | const [alice, bobbo] = await scenario.addPlayersWithHapps([dnas, dnas]); 35 | await scenario.shareAllAgents(); 36 | 37 | 38 | const [alice_attestations] = alice.cells; 39 | const [bobbo_attestations] = bobbo.cells; 40 | const boboAgentKey = serializeHash(bobbo.agentPubKey); 41 | const aliceAgentKey = serializeHash(alice.agentPubKey); 42 | 43 | // Create an attestation 44 | let attestation1 = { 45 | content: "Cool Person", 46 | about: boboAgentKey, 47 | }; 48 | let attestation1_hash: EntryHashB64 = "" 49 | try { 50 | attestation1_hash = await alice_attestations.callZome( { 51 | zome_name: "hc_zome_attestations", 52 | fn_name: "create_attestation", 53 | payload: attestation1 54 | } 55 | ); 56 | t.ok(attestation1_hash); 57 | console.log("attestation1_hash", attestation1_hash); 58 | } catch(e) { 59 | console.log("HERE", e) 60 | } 61 | 62 | let attestations : Array = await alice_attestations.callZome({ 63 | zome_name: "hc_zome_attestations", 64 | fn_name: "get_my_attestations", 65 | payload: null 66 | }); 67 | console.log(attestations); 68 | checkAttestations(t, attestations[0], attestation1, attestation1_hash, [aliceAgentKey]) 69 | 70 | attestations = await alice_attestations.callZome({ 71 | zome_name: "hc_zome_attestations", 72 | fn_name: "get_attestations", 73 | payload: {of: boboAgentKey} 74 | }); 75 | console.log(attestations); 76 | checkAttestations(t,attestations[0], attestation1, attestation1_hash, [aliceAgentKey]) 77 | 78 | attestations = await alice_attestations.callZome({ 79 | zome_name: "hc_zome_attestations", 80 | fn_name: "get_attestations", 81 | payload: {by: aliceAgentKey} 82 | }); 83 | console.log(attestations); 84 | t.is(attestations.length,1) 85 | checkAttestations(t,attestations[0], attestation1, attestation1_hash, [aliceAgentKey]) 86 | 87 | attestations = await alice_attestations.callZome({ 88 | zome_name: "hc_zome_attestations", 89 | fn_name: "get_attestations", 90 | payload: {by: aliceAgentKey, 91 | of: boboAgentKey}} 92 | ); 93 | console.log(attestations); 94 | t.is(attestations.length,1) 95 | checkAttestations(t,attestations[0], attestation1, attestation1_hash, [aliceAgentKey]) 96 | 97 | attestations = await alice_attestations.callZome({ 98 | zome_name: "hc_zome_attestations", 99 | fn_name: "get_attestations", 100 | payload: {content: "Cool Person"} 101 | }); 102 | console.log("Should be bobbo", attestations); 103 | checkAttestations(t,attestations[0], attestation1, attestation1_hash, [aliceAgentKey]) 104 | 105 | 106 | attestations = await alice_attestations.callZome({ 107 | zome_name: "hc_zome_attestations", 108 | fn_name: "get_attestations", 109 | payload: {agent: aliceAgentKey} 110 | }); 111 | console.log("Should be nothing", attestations); 112 | t.deepEqual(attestations, []); 113 | 114 | const attestation2_hash = await bobbo_attestations.callZome({ 115 | zome_name: "hc_zome_attestations", 116 | fn_name: "create_attestation", 117 | payload: attestation1 118 | }); 119 | t.ok(attestation1_hash); 120 | t.equal(attestation2_hash, attestation1_hash) 121 | attestations = await bobbo_attestations.callZome({ 122 | zome_name: "hc_zome_attestations", 123 | fn_name: "get_my_attestations",} 124 | ); 125 | t.equal(attestations[0].attesters.length, 2); 126 | await pause(500) 127 | attestations = await alice_attestations.callZome({ 128 | zome_name: "hc_zome_attestations", 129 | fn_name: "get_my_attestations",} 130 | ); 131 | t.equal(attestations[0].attesters.length, 2); 132 | 133 | // now have bobbo say Alice is a cool person 134 | const attestation2 = { 135 | content: "Cool Person", 136 | about: aliceAgentKey, 137 | }; 138 | const attestation3_hash = await bobbo_attestations.callZome({ 139 | zome_name: "hc_zome_attestations", 140 | fn_name: "create_attestation", 141 | payload: attestation2 142 | }); 143 | 144 | t.ok(attestation3_hash); 145 | console.log("attestation3_hash", attestation1_hash); 146 | 147 | attestations = await bobbo_attestations.callZome({ 148 | zome_name: "hc_zome_attestations", 149 | fn_name: "get_attestations", 150 | payload: //{content: "Cool Person"} 151 | {by: boboAgentKey, 152 | of: boboAgentKey 153 | }} 154 | ); 155 | t.equal(attestations.length,2) 156 | 157 | let nonce = await alice_attestations.callZome({ 158 | zome_name: "hc_zome_attestations", 159 | fn_name: "create_nonce", 160 | payload: {with: boboAgentKey, note: "bobbo"}, 161 | }); 162 | console.log("nonce:", nonce) 163 | /* 164 | a_and_b_conductor.setSignalHandler((signal) => { 165 | console.log("Received Signal:", signal); 166 | t.deepEqual(signal.data.payload, { 167 | nonce: `${nonce}`, 168 | from: boboAgentKey 169 | }); 170 | }); 171 | 172 | let result = await bobbo_attestations.callZome({ 173 | zome_name: "hc_zome_attestations", 174 | fn_name: "fulfill_nonce", 175 | payload: {with: aliceAgentKey, 176 | nonce}, 177 | }); 178 | console.log("result:", result) 179 | attestations = await bobbo_attestations.callZome({ 180 | zome_name: "hc_zome_attestations", 181 | fn_name: "get_attestations", 182 | payload: {by: boboAgentKey} 183 | }); 184 | console.log(attestations); 185 | t.is(attestations.length,3) 186 | */ 187 | }); 188 | }); 189 | -------------------------------------------------------------------------------- /tests/src/profile.ts: -------------------------------------------------------------------------------- 1 | import { InstalledHapp } from '@holochain/tryorama' 2 | import path = require('path') 3 | import * as _ from 'lodash' 4 | const delay = ms => new Promise(r => setTimeout(r, ms)) 5 | import { localConductorConfig, installAgents, awaitIntegration } from './common' 6 | var wait = ms => new Promise((r, j)=>setTimeout(r, ms)) 7 | 8 | export default (orchestrator) => { 9 | 10 | orchestrator.registerScenario('test profile zomes', async (s, t) => { 11 | // spawn the conductor process 12 | const [ conductor ] = await s.players([localConductorConfig]) 13 | const [alice_attestations_happ, bob_attestations_happ] = await installAgents(conductor, ["alice", "bobbo"]) 14 | const [alice] = alice_attestations_happ.cells 15 | const [bobbo] = bob_attestations_happ.cells 16 | 17 | // Trigger init to run in both zomes 18 | await alice.call('attestations', 'list_channels', { category: "General" }); 19 | await bobbo.call('attestations', 'list_channels', { category: "General" }); 20 | 21 | // Create a channel 22 | const profile_input = { 23 | nickname: "Alice", 24 | avatar_url: "https://alice.img" 25 | }; 26 | let profile_hash; 27 | 28 | try{ 29 | profile_hash = await alice.call('profile', 'update_my_profile', profile_input); 30 | console.log("PROFILE_Hash:", profile_hash); 31 | t.ok(profile_hash) 32 | } catch(e) { 33 | console.error("Error: ", e); 34 | t.fail() 35 | } 36 | 37 | let a_check_a_profile = await alice.call('profile', 'get_my_profile', null); 38 | console.log("Alice checks her profile:", a_check_a_profile); 39 | t.ok(a_check_a_profile) 40 | t.equal(profile_input.nickname, a_check_a_profile.nickname) 41 | t.equal(profile_input.avatar_url, a_check_a_profile.avatar_url) 42 | await wait(1000) 43 | await awaitIntegration(alice); 44 | await awaitIntegration(bobbo); 45 | let bobbo_check_alice_profile = await bobbo.call('profile', 'get_profile', a_check_a_profile.agent_address); 46 | console.log("Bobbo checks alice's profile:", bobbo_check_alice_profile); 47 | t.ok(bobbo_check_alice_profile) 48 | t.equal(profile_input.nickname, bobbo_check_alice_profile.nickname) 49 | t.equal(profile_input.avatar_url, bobbo_check_alice_profile.avatar_url) 50 | 51 | await wait(1000) 52 | const updated_profile_input_1 = { 53 | nickname: "Alicia", 54 | avatar_url: "https://alicia.img" 55 | }; 56 | profile_hash = await alice.call('profile', 'update_my_profile', updated_profile_input_1); 57 | console.log("PROFILE_Hash:", profile_hash); 58 | t.ok(profile_hash) 59 | 60 | await wait(1000) 61 | a_check_a_profile = await alice.call('profile', 'get_my_profile', null); 62 | console.log("Alice checks her updated profile:", a_check_a_profile); 63 | t.ok(a_check_a_profile) 64 | t.equal(updated_profile_input_1.nickname, a_check_a_profile.nickname) 65 | t.equal(updated_profile_input_1.avatar_url, a_check_a_profile.avatar_url) 66 | 67 | bobbo_check_alice_profile = await bobbo.call('profile', 'get_profile', a_check_a_profile.agent_address); 68 | console.log("Bobbo checks alice's updated profile:", bobbo_check_alice_profile); 69 | t.ok(bobbo_check_alice_profile) 70 | t.equal(updated_profile_input_1.nickname, bobbo_check_alice_profile.nickname) 71 | t.equal(updated_profile_input_1.avatar_url, bobbo_check_alice_profile.avatar_url) 72 | 73 | await wait(1000) 74 | const updated_profile_input_2 = { 75 | nickname: "Alexandria", 76 | avatar_url: "https://alexandria.img" 77 | }; 78 | profile_hash = await alice.call('profile', 'update_my_profile', updated_profile_input_2); 79 | console.log("PROFILE_Hash:", profile_hash); 80 | t.ok(profile_hash) 81 | 82 | await wait(1000) 83 | a_check_a_profile = await alice.call('profile', 'get_my_profile', null); 84 | console.log("Alice checks her updated profile:", a_check_a_profile); 85 | t.ok(a_check_a_profile) 86 | t.equal(updated_profile_input_2.nickname, a_check_a_profile.nickname) 87 | t.equal(updated_profile_input_2.avatar_url, a_check_a_profile.avatar_url) 88 | 89 | bobbo_check_alice_profile = await bobbo.call('profile', 'get_profile', a_check_a_profile.agent_address); 90 | console.log("Bobbo checks alice's updated profile:", bobbo_check_alice_profile); 91 | t.ok(bobbo_check_alice_profile) 92 | t.equal(updated_profile_input_2.nickname, bobbo_check_alice_profile.nickname) 93 | t.equal(updated_profile_input_2.avatar_url, bobbo_check_alice_profile.avatar_url) 94 | }) 95 | } 96 | -------------------------------------------------------------------------------- /tests/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | /* Basic Options */ 5 | "outDir": "dist", 6 | "target": "ES2017", 7 | "module": "ESNext", 8 | "moduleResolution": "node", 9 | /* Strict Type-Checking Options */ 10 | "strict": true /* Enable all strict type-checking options. */, 11 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, 12 | "noImplicitAny": false /* Raise error on expressions and declarations with an implied 'any' type. */, 13 | /* Advanced Options */ 14 | "skipLibCheck": true /* Skip type checking of declaration files. */, 15 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", 4 | "module": "esnext", 5 | "moduleResolution": "node", 6 | "noEmitOnError": true, 7 | "lib": ["es2017", "dom"], 8 | "strict": true, 9 | "esModuleInterop": false, 10 | "allowSyntheticDefaultImports": true, 11 | "experimentalDecorators": true, 12 | "importHelpers": true, 13 | "sourceMap": true, 14 | "inlineSources": true, 15 | "declaration": true 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ui/apps/attestations/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | .dist 3 | ui.zip 4 | out-tsc/ -------------------------------------------------------------------------------- /ui/apps/attestations/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 14 | 15 | 16 | 17 | 18 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /ui/apps/attestations/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "attestations", 3 | "version": "0.0.1", 4 | "scripts": { 5 | "build": "tsc", 6 | "build:watch": "run-singleton \"tsc -w --incremental --preserveWatchOutput\"", 7 | "start": "concurrently --names tsc,dev-server \"npm run build:watch\" \"web-dev-server --config ./web-dev-server.config.mjs\"", 8 | "package": "rimraf ui.zip && rimraf dist && rollup --config rollup.config.js && cd ./dist && bestzip ../ui.zip * " 9 | }, 10 | "devDependencies": { 11 | "@babel/preset-env": "^7.15.0", 12 | "@rollup/plugin-babel": "^5.3.0", 13 | "@rollup/plugin-commonjs": "18.0.0", 14 | "@rollup/plugin-node-resolve": "^13.0.4", 15 | "@rollup/plugin-replace": "^3.0.0", 16 | "@rollup/plugin-typescript": "^8.2.5", 17 | "@web/dev-server": "^0.1.21", 18 | "@web/rollup-plugin-html": "^1.9.1", 19 | "@web/rollup-plugin-import-meta-assets": "^1.0.7", 20 | "babel-plugin-template-html-minifier": "^4.1.0", 21 | "bestzip": "^2.2.0", 22 | "concurrently": "^5.3.0", 23 | "deepmerge": "^4.2.2", 24 | "exits": "^2.0.1", 25 | "path-exists-cli": "^2.0.0", 26 | "rimraf": "^3.0.2", 27 | "rollup": "^2.56.2", 28 | "rollup-plugin-node-builtins": "^2.1.2", 29 | "rollup-plugin-node-globals": "^1.4.0", 30 | "rollup-plugin-terser": "^7.0.2", 31 | "rollup-plugin-workbox": "^6.2.0", 32 | "run-singleton-cli": "^0.0.5", 33 | "tslib": "^2.3.1", 34 | "typescript": "4.3.5" 35 | }, 36 | "dependencies": { 37 | "@holochain-open-dev/cell-client": "^0.9.1", 38 | "@holochain-open-dev/profiles": "^0.8.0", 39 | "@holochain/client": "^0.10.2", 40 | "@holochain-open-dev/context": "^0.0.3", 41 | "@attestations/elements": "^0.0.1", 42 | "lit": "^2.1.4" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ui/apps/attestations/rollup.config.js: -------------------------------------------------------------------------------- 1 | import nodeResolve from "@rollup/plugin-node-resolve"; 2 | import typescript from "@rollup/plugin-typescript"; 3 | import commonjs from "@rollup/plugin-commonjs"; 4 | import replace from "@rollup/plugin-replace"; 5 | import builtins from "rollup-plugin-node-builtins"; 6 | import globals from "rollup-plugin-node-globals"; 7 | 8 | import babel from "@rollup/plugin-babel"; 9 | import html from "@web/rollup-plugin-html"; 10 | import { importMetaAssets } from "@web/rollup-plugin-import-meta-assets"; 11 | import { terser } from "rollup-plugin-terser"; 12 | import { generateSW } from "rollup-plugin-workbox"; 13 | import path from "path"; 14 | 15 | const HC_PORT = process.env.HC_PORT || 8888; 16 | const DIST_FOLDER = process.env.HC_PORT ? `.dist/${HC_PORT}` : "dist"; 17 | 18 | const production = !process.env.ROLLUP_WATCH; 19 | 20 | export default { 21 | input: "index.html", 22 | output: { 23 | entryFileNames: "[hash].js", 24 | chunkFileNames: "[hash].js", 25 | assetFileNames: "[hash][extname]", 26 | format: "es", 27 | dir: DIST_FOLDER, 28 | }, 29 | watch: { 30 | clearScreen: false, 31 | }, 32 | 33 | plugins: [ 34 | /** Enable using HTML as rollup entrypoint */ 35 | html({ 36 | minify: production, 37 | injectServiceWorker: true, 38 | serviceWorkerPath: "dist/sw.js", 39 | }), 40 | /** Resolve bare module imports */ 41 | nodeResolve({ 42 | browser: true, 43 | preferBuiltins: false, 44 | }), 45 | replace({ 46 | "process.env.NODE_ENV": '"production"', 47 | "process.env.ENV": `"${process.env.ENV}"`, 48 | "process.env.HC_PORT": `"${HC_PORT}"`, 49 | }), 50 | builtins(), 51 | typescript({ experimentalDecorators: true, outDir: DIST_FOLDER }), 52 | commonjs({}), 53 | globals(), 54 | /** Minify JS */ 55 | production && terser(), 56 | /** Bundle assets references via import.meta.url */ 57 | importMetaAssets(), 58 | /** Compile JS to a lower language target */ 59 | production && 60 | babel({ 61 | exclude: /node_modules/, 62 | 63 | babelHelpers: "bundled", 64 | presets: [ 65 | [ 66 | require.resolve("@babel/preset-env"), 67 | { 68 | targets: [ 69 | "last 3 Chrome major versions", 70 | "last 3 Firefox major versions", 71 | "last 3 Edge major versions", 72 | "last 3 Safari major versions", 73 | ], 74 | modules: false, 75 | bugfixes: true, 76 | }, 77 | ], 78 | ], 79 | plugins: [ 80 | [ 81 | require.resolve("babel-plugin-template-html-minifier"), 82 | { 83 | modules: { 84 | lit: ["html", { name: "css", encapsulation: "style" }], 85 | }, 86 | failOnError: false, 87 | strictCSS: true, 88 | htmlMinifier: { 89 | collapseWhitespace: true, 90 | conservativeCollapse: true, 91 | removeComments: true, 92 | caseSensitive: true, 93 | minifyCSS: true, 94 | }, 95 | }, 96 | ], 97 | ], 98 | }), 99 | /** Create and inject a service worker */ 100 | production && 101 | generateSW({ 102 | globIgnores: ["polyfills/*.js", "nomodule-*.js"], 103 | navigateFallback: "/index.html", 104 | // where to output the generated sw 105 | swDest: path.join(DIST_FOLDER, "sw.js"), 106 | // directory to match patterns against to be precached 107 | globDirectory: path.join(DIST_FOLDER), 108 | // cache any html js and css by default 109 | globPatterns: ["**/*.{html,js,css,webmanifest}"], 110 | skipWaiting: true, 111 | clientsClaim: true, 112 | runtimeCaching: [ 113 | { urlPattern: "polyfills/*.js", handler: "CacheFirst" }, 114 | ], 115 | }), 116 | ], 117 | }; 118 | -------------------------------------------------------------------------------- /ui/apps/attestations/src/attestations-app.ts: -------------------------------------------------------------------------------- 1 | import { ContextProvider } from "@lit-labs/context"; 2 | import { state } from "lit/decorators.js"; 3 | import { 4 | AttestationsController, 5 | AttestationsAttestation, 6 | AttestationsStore, 7 | attestationsContext, 8 | } from "@attestations/elements"; 9 | import { 10 | ProfilePrompt, 11 | ProfilesStore, 12 | ProfilesService, 13 | profilesStoreContext, 14 | } from "@holochain-open-dev/profiles"; 15 | import { HolochainClient, CellClient } from "@holochain-open-dev/cell-client"; 16 | import { AppWebsocket } from "@holochain/client"; 17 | import { ScopedElementsMixin } from "@open-wc/scoped-elements"; 18 | import { LitElement, html } from "lit"; 19 | 20 | export class AttestationsApp extends ScopedElementsMixin(LitElement) { 21 | @state() 22 | loaded = false; 23 | 24 | @state() 25 | store: ProfilesStore | undefined; 26 | 27 | async firstUpdated() { 28 | const appWebsocket = await AppWebsocket.connect( 29 | `ws://localhost:${process.env.HC_PORT}` 30 | ); 31 | 32 | const client = new HolochainClient(appWebsocket); 33 | const appInfo = await appWebsocket.appInfo({ 34 | installed_app_id: "attestations", 35 | }); 36 | 37 | const cell = appInfo.cell_data[0]; 38 | const attestationsClient = new CellClient(client, cell); 39 | 40 | this.store = new ProfilesStore(new ProfilesService(attestationsClient), { 41 | avatarMode: "identicon", 42 | }); 43 | 44 | this.store.fetchAllProfiles(); 45 | 46 | new ContextProvider(this, profilesStoreContext, this.store); 47 | 48 | new ContextProvider( 49 | this, 50 | attestationsContext, 51 | new AttestationsStore(attestationsClient, this.store) 52 | ); 53 | 54 | this.loaded = true; 55 | } 56 | 57 | render() { 58 | if (!this.loaded) return html`Loading...`; 59 | return html` 60 | 61 | 62 | 63 | 64 | `; 65 | } 66 | 67 | static get scopedElements() { 68 | return { 69 | "profile-prompt": ProfilePrompt, 70 | "attestations-controller": AttestationsController, 71 | "attestations-attestation": AttestationsAttestation, 72 | }; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /ui/apps/attestations/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './attestations-app'; 2 | -------------------------------------------------------------------------------- /ui/apps/attestations/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "out-tsc", 5 | "rootDir": "./src", 6 | "declaration": false 7 | }, 8 | "include": ["src/**/*.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /ui/apps/attestations/web-dev-server.config.mjs: -------------------------------------------------------------------------------- 1 | // import { hmrPlugin, presets } from '@open-wc/dev-server-hmr'; 2 | import rollupReplace from '@rollup/plugin-replace'; 3 | import rollupCommonjs from '@rollup/plugin-commonjs'; 4 | import { fromRollup } from '@web/dev-server-rollup'; 5 | import rollupBuiltins from 'rollup-plugin-node-builtins'; 6 | 7 | const replace = fromRollup(rollupReplace); 8 | const commonjs = fromRollup(rollupCommonjs); 9 | const builtins = fromRollup(rollupBuiltins); 10 | 11 | /** Use Hot Module replacement by adding --hmr to the start command */ 12 | const hmr = process.argv.includes('--hmr'); 13 | 14 | export default /** @type {import('@web/dev-server').DevServerConfig} */ ({ 15 | open: true, 16 | watch: !hmr, 17 | /** Resolve bare module imports */ 18 | nodeResolve: { 19 | preferBuiltins: false, 20 | browser: true, 21 | exportConditions: ['browser', 'development'], 22 | }, 23 | 24 | /** Compile JS for older browsers. Requires @web/dev-server-esbuild plugin */ 25 | // esbuildTarget: 'auto' 26 | 27 | rootDir: '../../../', 28 | 29 | /** Set appIndex to enable SPA routing */ 30 | appIndex: './index.html', 31 | 32 | plugins: [ 33 | replace({ 34 | 'process.env.NODE_ENV': `"production"`, 35 | 'process.env.ENV': JSON.stringify(process.env.ENV), 36 | 'process.env.HC_PORT': JSON.stringify(process.env.HC_PORT || 8888), 37 | ' COMB =': 'window.COMB =', 38 | delimiters: ['', ''], 39 | }), 40 | builtins(), 41 | commonjs({}), 42 | 43 | /** Use Hot Module Replacement by uncommenting. Requires @open-wc/dev-server-hmr plugin */ 44 | // hmr && hmrPlugin({ exclude: ['**/*/node_modules/**/*'], presets: [presets.litElement] }), 45 | ], 46 | 47 | // See documentation for all available options 48 | }); 49 | -------------------------------------------------------------------------------- /ui/lib/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | 10 | # Change these settings to your own preference 11 | indent_style = space 12 | indent_size = 2 13 | 14 | # We recommend you to keep these unchanged 15 | end_of_line = lf 16 | charset = utf-8 17 | trim_trailing_whitespace = true 18 | insert_final_newline = true 19 | 20 | [*.md] 21 | trim_trailing_whitespace = false 22 | 23 | [*.json] 24 | indent_size = 2 25 | 26 | [*.{html,js,md}] 27 | block_comment_start = /** 28 | block_comment = * 29 | block_comment_end = */ 30 | -------------------------------------------------------------------------------- /ui/lib/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | }, 5 | root: true, 6 | parser: '@typescript-eslint/parser', 7 | plugins: ['@typescript-eslint', 'import', 'html'], 8 | extends: [ 9 | 'eslint:recommended', 10 | 'plugin:@typescript-eslint/eslint-recommended', 11 | 'plugin:@typescript-eslint/recommended', 12 | 'plugin:import/errors', 13 | 'plugin:import/warnings', 14 | ], 15 | rules: { 16 | // disable the rule for all files 17 | '@typescript-eslint/explicit-function-return-type': 'off', 18 | '@typescript-eslint/no-non-null-assertion': 'off', 19 | '@typescript-eslint/explicit-module-boundary-types': 'off', 20 | '@typescript-eslint/camelcase': 'off', 21 | '@typescript-eslint/no-explicit-any': 'off', 22 | 'import/named': 'off', 23 | 'import/no-unresolved': 'off', 24 | 'import/extensions': 'off', 25 | 'prefer-const': 'off' 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /ui/lib/.gitignore: -------------------------------------------------------------------------------- 1 | ## editors 2 | /.idea 3 | /.vscode 4 | 5 | ## system files 6 | .DS_Store 7 | 8 | ## npm 9 | /node_modules/ 10 | /npm-debug.log 11 | 12 | ## testing 13 | /coverage/ 14 | 15 | ## temp folders 16 | /.tmp/ 17 | 18 | # build 19 | /_site/ 20 | /dist/ 21 | /out-tsc/ 22 | /storybook-static/ 23 | .hc -------------------------------------------------------------------------------- /ui/lib/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@attestations/elements", 3 | "version": "0.0.1", 4 | "main": "./dist/index.js", 5 | "module": "./dist/index.js", 6 | "scripts": { 7 | "build": "rimraf dist && rollup -c", 8 | "build:watch": "run-singleton \"rollup -c -w\"", 9 | "analyze": "lit-analyzer src --failFast" 10 | }, 11 | "type": "module", 12 | "devDependencies": { 13 | "@holochain/client": "^0.10.2", 14 | "@rollup/plugin-commonjs": "^20.0.0", 15 | "@rollup/plugin-node-resolve": "^13.0.4", 16 | "@rollup/plugin-typescript": "^8.2.5", 17 | "@types/lodash-es": "^4.17.4", 18 | "lit-analyzer": "^1.2.1", 19 | "rimraf": "^3.0.2", 20 | "rollup": "^2.56.3", 21 | "rollup-plugin-postcss": "^4.0.1", 22 | "rollup-plugin-postcss-lit": "^1.1.1", 23 | "run-singleton-cli": "^0.0.5", 24 | "typescript": "4.3.5", 25 | "watch-cli": "^0.2.3" 26 | }, 27 | "dependencies": { 28 | "@holochain-open-dev/cell-client": "^0.9.1", 29 | "@holochain-open-dev/core-types": "^0.6.2", 30 | "@holochain-open-dev/utils": "^0.6.2", 31 | "@holochain-open-dev/profiles": "^0.8.0", 32 | "@lit-labs/context": "^0.1.2", 33 | "@open-wc/scoped-elements": "^2.1.2", 34 | "@scoped-elements/material-web": "^0.0.19", 35 | "@scoped-elements/shoelace": "^0.0.8", 36 | "cqfill": "^0.6.0", 37 | "emoji-picker-element": "^1.8.2", 38 | "lit": "^2.1.4", 39 | "lit-svelte-stores": "^0.2.1", 40 | "lodash-es": "^4.17.21", 41 | "fast-xml-parser": "^3.20.0", 42 | "@types/randomcolor": "^0.5.6", 43 | "randomcolor": "^0.6.2", 44 | "svelte": "^3.42.4" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /ui/lib/rollup.config.js: -------------------------------------------------------------------------------- 1 | import typescript from '@rollup/plugin-typescript'; 2 | import postcss from 'rollup-plugin-postcss'; 3 | import postcssLit from 'rollup-plugin-postcss-lit'; 4 | import resolve from '@rollup/plugin-node-resolve'; 5 | import commonjs from '@rollup/plugin-commonjs'; 6 | import postcssCQFill from 'cqfill/postcss'; 7 | 8 | const pkg = require('./package.json'); 9 | 10 | export default { 11 | input: `src/index.ts`, 12 | output: [{ dir: 'dist', format: 'es', sourcemap: true }], 13 | // Indicate here external modules you don't wanna include in your bundle (i.e.: 'lodash-es') 14 | external: [...Object.keys(pkg.dependencies), /lit/], 15 | watch: { 16 | include: 'src/**', 17 | clearScreen: false, 18 | }, 19 | plugins: [ 20 | postcss({ 21 | inject: false, 22 | plugins: [postcssCQFill], 23 | }), 24 | postcssLit(), 25 | typescript({ 26 | target: 'es6', 27 | }), 28 | resolve(), 29 | commonjs(), 30 | ], 31 | }; 32 | -------------------------------------------------------------------------------- /ui/lib/src/attestations.service.ts: -------------------------------------------------------------------------------- 1 | import { CellClient } from '@holochain-open-dev/cell-client'; 2 | import { serializeHash } from '@holochain-open-dev/utils'; 3 | import { EntryHashB64, AgentPubKeyB64 } from '@holochain-open-dev/core-types'; 4 | import {AttestationOutput, Attestation, AttestationEntry, Signal, GetAttestationsInput, Verifiable, FulfillNonceInput, CreateNonceInput} from './types'; 5 | 6 | export class AttestationsService { 7 | constructor( 8 | public cellClient: CellClient, 9 | protected zomeName = 'hc_zome_attestations' 10 | ) {} 11 | 12 | get myAgentPubKey() : AgentPubKeyB64 { 13 | return serializeHash(this.cellClient.cell.cell_id[1]); 14 | } 15 | 16 | async createAttestation(attestation: Attestation): Promise { 17 | return this.callZome('create_attestation', attestation); 18 | } 19 | 20 | async getAttestations(input: GetAttestationsInput): Promise> { 21 | return this.callZome('get_attestations', input); 22 | } 23 | 24 | async getMyAttestations(): Promise> { 25 | return this.callZome('get_my_attestations', null); 26 | } 27 | 28 | async notify(signal: Signal, folks: Array): Promise { 29 | return this.callZome('notify', {signal, folks}); 30 | } 31 | 32 | async attestationFromEntry(hash: EntryHashB64, entry: AttestationEntry): Promise { 33 | return { 34 | content : entry.content, 35 | about: entry.about, 36 | } 37 | } 38 | 39 | async createNonce(input: CreateNonceInput): Promise { 40 | return this.callZome('create_nonce', input); 41 | } 42 | 43 | async fulfillNonce(input: FulfillNonceInput): Promise { 44 | return this.callZome('fulfill_nonce', input); 45 | } 46 | 47 | async verify(input: Verifiable): Promise { 48 | try { 49 | await this.callZome('verify', input); 50 | return true 51 | } 52 | catch(e) { 53 | console.log("Error during verify:", e) 54 | return false 55 | } 56 | } 57 | 58 | private callZome(fn_name: string, payload: any) { 59 | return this.cellClient.callZome(this.zomeName, fn_name, payload); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /ui/lib/src/attestations.store.ts: -------------------------------------------------------------------------------- 1 | import { EntryHashB64, ActionHashB64, AgentPubKeyB64 } from '@holochain-open-dev/core-types'; 2 | import { serializeHash, deserializeHash, AgentPubKeyMap } from '@holochain-open-dev/utils'; 3 | import { CellClient } from '@holochain-open-dev/cell-client'; 4 | import { writable, Writable, derived, Readable, get } from 'svelte/store'; 5 | import { HoloHash } from "@holochain/client"; 6 | 7 | import { AttestationsService } from './attestations.service'; 8 | import { 9 | Dictionary, 10 | Attestation, 11 | AttestationOutput, 12 | GetAttestationsInput, 13 | Verifiable, 14 | FulfillNonceInput, 15 | CreateNonceInput, 16 | } from './types'; 17 | import { 18 | ProfilesStore, 19 | Profile, 20 | } from "@holochain-open-dev/profiles"; 21 | 22 | const areEqual = (first: Uint8Array, second: Uint8Array) => 23 | first.length === second.length && first.every((value, index) => value === second[index]); 24 | 25 | export class AttestationsStore { 26 | /** Private */ 27 | private service : AttestationsService 28 | private profiles: ProfilesStore 29 | private knownProfiles: Readable> | undefined 30 | 31 | /** AttestationEh -> Attestation */ 32 | private myAttestationsStore: Writable> = writable({}); 33 | private searchedAttestationsStore: Writable> = writable({}); 34 | 35 | /** Static info */ 36 | myAgentPubKey: AgentPubKeyB64; 37 | 38 | /** Readable stores */ 39 | public myAttestations: Readable> = derived(this.myAttestationsStore, i => i) 40 | public searchedAttestations: Readable> = derived(this.searchedAttestationsStore, i => i) 41 | 42 | constructor( 43 | protected cellClient: CellClient, 44 | profilesStore: ProfilesStore, 45 | zomeName = 'hc_zome_attestations' 46 | ) { 47 | this.myAgentPubKey = serializeHash(cellClient.cell.cell_id[1]); 48 | this.profiles = profilesStore; 49 | this.service = new AttestationsService(cellClient, zomeName); 50 | 51 | cellClient.addSignalHandler( signal => { 52 | if (! areEqual(cellClient.cell.cell_id[0],signal.data.cellId[0]) || !areEqual(cellClient.cell.cell_id[1], signal.data.cellId[1])) { 53 | return 54 | } 55 | console.log("SIGNAL",signal) 56 | const payload = signal.data.payload 57 | switch(payload.message.type) { 58 | case "": 59 | break; 60 | } 61 | }) 62 | } 63 | 64 | private others(): Array { 65 | if (this.knownProfiles) { 66 | const map : AgentPubKeyMap = get(this.knownProfiles) 67 | const x: Array = map.keys().map((key) => serializeHash(key)) 68 | return x.filter((key) => key != this.myAgentPubKey) 69 | } 70 | else { 71 | return [] 72 | } 73 | } 74 | 75 | async fetchProfiles() { 76 | this.knownProfiles = await this.profiles.fetchAllProfiles() 77 | } 78 | 79 | async getProfile(agent: AgentPubKeyB64) : Promise { 80 | return get(await this.profiles.fetchAgentProfile(deserializeHash(agent))) 81 | } 82 | 83 | async pullMyAttestations() : Promise> { 84 | const attestationsOutputs = await this.service.getMyAttestations(); 85 | //console.log({attestations}) 86 | for (const a of attestationsOutputs) { 87 | this.myAttestationsStore.update(attestations => { 88 | attestations[a.hash] = a 89 | return attestations 90 | }) 91 | } 92 | return get(this.myAttestationsStore) 93 | } 94 | 95 | async searchAttestations(search: string) : Promise> { 96 | const input : GetAttestationsInput = {} 97 | if (search.startsWith("uhCA")) { 98 | input.of = search 99 | input.of = search 100 | } else { 101 | input.content = search 102 | } 103 | console.log("searching for", input) 104 | const attestationsOutputs = await this.service.getAttestations(input); 105 | console.log({attestationsOutputs}) 106 | this.searchedAttestationsStore.update(attestations => { 107 | attestations = {} 108 | for (const a of attestationsOutputs) { 109 | attestations[a.hash] = a 110 | } 111 | return attestations 112 | }) 113 | return get(this.searchedAttestationsStore) 114 | } 115 | 116 | 117 | async addAttestation(attestation: Attestation) : Promise { 118 | const s: Attestation = { 119 | content: attestation.content, 120 | about: attestation.about, 121 | }; 122 | const attestationEh: EntryHashB64 = await this.service.createAttestation(s) 123 | await this.pullMyAttestations() 124 | return attestationEh 125 | } 126 | 127 | attestation(attestationEh: EntryHashB64): AttestationOutput { 128 | return get(this.myAttestationsStore)[attestationEh]; 129 | } 130 | 131 | verify(input: Verifiable) : Promise { 132 | return this.service.verify(input) 133 | } 134 | 135 | createNonce(input: CreateNonceInput) : Promise { 136 | return this.service.createNonce(input) 137 | } 138 | 139 | fulfillNonce(input:FulfillNonceInput) : Promise { 140 | return this.service.fulfillNonce(input) 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /ui/lib/src/elements/attestation-folk.ts: -------------------------------------------------------------------------------- 1 | import { css, html, LitElement } from "lit"; 2 | import { property, query, state } from "lit/decorators.js"; 3 | 4 | import { ScopedElementsMixin } from "@open-wc/scoped-elements"; 5 | import { sharedStyles } from "../sharedStyles"; 6 | import { CopyableContent } from "./copiable-content"; 7 | import { 8 | AgentAvatar, 9 | ProfilesStore, 10 | profilesStoreContext, 11 | Profile 12 | } from "@holochain-open-dev/profiles"; 13 | import { TaskSubscriber } from "lit-svelte-stores"; 14 | import { AgentPubKeyB64 } from "@holochain-open-dev/core-types"; 15 | import { deserializeHash } from "@holochain-open-dev/utils"; 16 | import { writable, Writable, derived, Readable, get } from 'svelte/store'; 17 | import { contextProvided } from "@lit-labs/context"; 18 | 19 | export class AttestationFolk extends ScopedElementsMixin(LitElement) { 20 | @property() agent: AgentPubKeyB64 = ""; 21 | @property() showNick: boolean = true 22 | @property() showCopiable: boolean = true 23 | @property() compact: boolean = false 24 | @contextProvided({ context: profilesStoreContext }) 25 | @property({ type: Object }) 26 | _profiles!: ProfilesStore; 27 | 28 | _profileTask = new TaskSubscriber( 29 | this, 30 | () => this._profiles.fetchAgentProfile(deserializeHash(this.agent)), 31 | () => [this._profiles, this.agent] 32 | ); 33 | 34 | static get styles() { 35 | return [ 36 | sharedStyles, 37 | css` 38 | .folk { 39 | margin: 0px; 40 | } 41 | `, 42 | ]; 43 | } 44 | 45 | renderProfile(profile: Profile | undefined) { 46 | if (!profile) return ""; 47 | return html` 48 | ${!this.compact? html`
`:""} 49 | 50 | ${this.showNick ? html`
${profile.nickname}
`:""} 51 | ${this.showCopiable ? html``:""} 52 | ${!this.compact? html`
`:""}` 53 | } 54 | 55 | render() { 56 | return this._profileTask.render({ 57 | complete: profile => this.renderProfile(profile), 58 | pending: () => html`Loading...`, 59 | }); 60 | 61 | 62 | } 63 | static get scopedElements() { 64 | return { 65 | "agent-avatar": AgentAvatar, 66 | "copiable-content": CopyableContent, 67 | }; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /ui/lib/src/elements/attestations-attestation-dialog.ts: -------------------------------------------------------------------------------- 1 | import {css, html, LitElement} from "lit"; 2 | import {property, query, state} from "lit/decorators.js"; 3 | 4 | import {sharedStyles} from "../sharedStyles"; 5 | import { contextProvided } from "@lit-labs/context"; 6 | import {ScopedElementsMixin} from "@open-wc/scoped-elements"; 7 | import {AttestationsStore} from "../attestations.store"; 8 | import {Attestation, attestationsContext, CreateNonceInput, FulfillNonceInput} from "../types"; 9 | import {EntryHashB64, AgentPubKeyB64} from "@holochain-open-dev/core-types"; 10 | import { 11 | Button, 12 | Dialog, 13 | TextField 14 | } from "@scoped-elements/material-web"; 15 | import {Profile, SearchAgent, AgentAvatar} from "@holochain-open-dev/profiles"; 16 | 17 | export enum DialogType { 18 | Attestation, 19 | CreateNonce, 20 | FulfilNonce, 21 | } 22 | 23 | /** 24 | * @element attestations-attestation-dialog 25 | */ 26 | export class AttestationsAttestationDialog extends ScopedElementsMixin(LitElement) { 27 | 28 | @property() myProfile: Profile| undefined = undefined; 29 | @property() type: DialogType = DialogType.Attestation; 30 | 31 | /** Dependencies */ 32 | @contextProvided({ context: attestationsContext }) 33 | _store!: AttestationsStore; 34 | 35 | _attestationToPreload?: EntryHashB64; 36 | 37 | @query('#content-field') 38 | _contentField!: TextField; 39 | 40 | @state() _about: AgentPubKeyB64 = "" 41 | @state() _profile: Profile | undefined = undefined 42 | 43 | dialogTitle(): string { 44 | switch (this.type) { 45 | case DialogType.Attestation: return "New Attestation" 46 | case DialogType.FulfilNonce: return "Fulfill Nonce" 47 | case DialogType.CreateNonce: return "Create Nonce" 48 | } 49 | } 50 | 51 | agentFieldTitle(): string { 52 | switch (this.type) { 53 | case DialogType.Attestation: return "About" 54 | case DialogType.FulfilNonce: return "With" 55 | case DialogType.CreateNonce: return "For" 56 | } 57 | } 58 | 59 | conentFieldTitle(): string { 60 | switch (this.type) { 61 | case DialogType.Attestation: return "Content" 62 | case DialogType.FulfilNonce: return "Nonce" 63 | case DialogType.CreateNonce: return "Notes" 64 | } 65 | } 66 | 67 | /** 68 | * 69 | */ 70 | open(type: DialogType) { 71 | this.type = type 72 | this.requestUpdate(); 73 | const dialog = this.shadowRoot!.getElementById("attestation-dialog") as Dialog 74 | dialog.open = true 75 | } 76 | 77 | /** 78 | * 79 | */ 80 | private async handleOk(e: any) { 81 | /** Check validity */ 82 | 83 | let isValid = true; 84 | if (this.type != DialogType.CreateNonce) { 85 | // contentField 86 | isValid = this._contentField.validity.valid 87 | 88 | if (!this._contentField.validity.valid) { 89 | this._contentField.reportValidity() 90 | } 91 | } 92 | if (!isValid) return 93 | if (!this._about) { 94 | return 95 | } 96 | 97 | switch (this.type) { 98 | case DialogType.Attestation: 99 | const attestation: Attestation = { 100 | content: this._contentField.value, 101 | about: this._about, 102 | }; 103 | // - Add attestation 104 | const newAttestation = await this._store.addAttestation(attestation); 105 | this.dispatchEvent(new CustomEvent('attestation-added', { detail: newAttestation, bubbles: true, composed: true })); 106 | break; 107 | case DialogType.CreateNonce: 108 | const input: CreateNonceInput = { 109 | note: this._contentField.value, 110 | with: this._about, 111 | }; 112 | const nonce = await this._store.createNonce(input); 113 | this.dispatchEvent(new CustomEvent('nonce-created', { detail: nonce, bubbles: true, composed: true })); 114 | break; 115 | case DialogType.FulfilNonce: 116 | const fulfill: FulfillNonceInput = { 117 | nonce: parseInt(this._contentField.value), 118 | with: this._about, 119 | }; 120 | const result = await this._store.fulfillNonce(fulfill); 121 | break; 122 | 123 | } 124 | 125 | 126 | // - Clear all fields 127 | // this.resetAllFields(); 128 | // - Close dialog 129 | const dialog = this.shadowRoot!.getElementById("attestation-dialog") as Dialog; 130 | dialog.close() 131 | } 132 | 133 | resetAllFields() { 134 | if (this._contentField) { 135 | this._contentField.value = '' 136 | } 137 | this._about = "" 138 | } 139 | 140 | private async handleDialogOpened(e: any) { 141 | if (this._attestationToPreload) { 142 | const attestationOutput = this._store.attestation(this._attestationToPreload); 143 | if (attestationOutput) { 144 | const attestation = attestationOutput.content 145 | this._contentField.value = attestation.content; 146 | } 147 | this._attestationToPreload = undefined; 148 | } 149 | this.requestUpdate() 150 | } 151 | 152 | private async handleDialogClosing(e: any) { 153 | this.resetAllFields(); 154 | } 155 | 156 | private async setAbout(e:any) { 157 | console.log("E", e.detail.agentPubKey) 158 | this._about = e.detail.agentPubKey 159 | this._profile = await this._store.getProfile(this._about) 160 | // this.requestUpdate() 161 | } 162 | 163 | render() { 164 | const about = this._profile && this._about ? html` 165 |
  • 166 | 167 |
    ${this._profile.nickname}
    168 |
  • ` :"" 169 | return html` 170 | 171 | 172 | (this.shadowRoot!.getElementById("content-field") as TextField).reportValidity()} 174 | id="content-field" minlength="3" maxlength="64" label=${this.conentFieldTitle()} autoValidate=true required> 175 | 176 | ${this.agentFieldTitle()} : ${about} 177 | e.stopPropagation()} 179 | @agent-selected="${this.setAbout}" 180 | clear-on-select 181 | style="margin-bottom: 16px;" 182 | include-myself> 183 | 184 | ok 185 | cancel 186 | 187 | ` 188 | } 189 | 190 | 191 | static get scopedElements() { 192 | return { 193 | "mwc-button": Button, 194 | "mwc-dialog": Dialog, 195 | "mwc-textfield": TextField, 196 | "search-agent": SearchAgent, 197 | 'agent-avatar': AgentAvatar, 198 | }; 199 | } 200 | static get styles() { 201 | return [ 202 | sharedStyles, 203 | css` 204 | mwc-dialog div { 205 | display: flex; 206 | } 207 | #attestation-dialog { 208 | --mdc-dialog-min-width: 600px; 209 | } 210 | mwc-textfield { 211 | margin-top: 10px; 212 | display: flex; 213 | } 214 | .ui-item { 215 | position: absolute; 216 | pointer-events: none; 217 | text-align: center; 218 | flex-shrink: 0; 219 | } 220 | .folk { 221 | list-style: none; 222 | margin: 2px; 223 | } 224 | 225 | .folk > img { 226 | width: 50px; 227 | border-radius: 10000px; 228 | } 229 | `, 230 | ]; 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /ui/lib/src/elements/attestations-attestation.ts: -------------------------------------------------------------------------------- 1 | import {css, html, LitElement} from "lit"; 2 | import {property, query} from "lit/decorators.js"; 3 | 4 | import { contextProvided } from "@lit-labs/context"; 5 | import {StoreSubscriber} from "lit-svelte-stores"; 6 | import {AgentPubKeyB64} from "@holochain-open-dev/core-types"; 7 | import {sharedStyles} from "../sharedStyles"; 8 | import {Attestation, AttestationOutput, attestationsContext, Verifiable} from "../types"; 9 | import {AttestationsStore} from "../attestations.store"; 10 | import {ScopedElementsMixin} from "@open-wc/scoped-elements"; 11 | import {ProfilesStore, profilesStoreContext, AgentAvatar} from "@holochain-open-dev/profiles"; 12 | import { SlRelativeTime } from "@scoped-elements/shoelace"; 13 | import { CopyableContent } from "./copiable-content"; 14 | import {encode} from "@msgpack/msgpack" 15 | import { AttestationFolk } from "./attestation-folk"; 16 | //import {Button, Dialog, TextField, Fab, Slider} from "@scoped-elements/material-web"; 17 | 18 | /** 19 | * @element attestations-attestation 20 | */ 21 | export class AttestationsAttestation extends ScopedElementsMixin(LitElement) { 22 | constructor() { 23 | super(); 24 | } 25 | 26 | @property({type: Object}) attestationOutput!: AttestationOutput; 27 | @property() display = "full"; 28 | 29 | @contextProvided({ context: attestationsContext }) 30 | _store!: AttestationsStore; 31 | 32 | // @contextProvided({ context: profilesStoreContext }) 33 | // _profiles!: ProfilesStore; 34 | 35 | folk(agent: AgentPubKeyB64) { 36 | return html`` 37 | } 38 | render() { 39 | if (!this.attestationOutput) { 40 | return html`` 41 | } 42 | /** Get current attestation and zoom level */ 43 | const attestation = this.attestationOutput.content 44 | /** Render layout */ 45 | switch (this.display) { 46 | case "compact": 47 | return html`${attestation.content} ` 48 | break; 49 | case "compact-with-who": 50 | const who = this.attestationOutput.attesters.map((a)=> 51 | html``) 52 | return html`${who} ${attestation.content} ` 53 | break; 54 | case "full": 55 | return html` 56 |
    57 |
    58 |

    Attesting:

    ${attestation.content}
    59 |

    About:

    60 |
    61 |
    62 |

    Attesters: ${this.attestationOutput.attesters.length}

    63 |
      64 | ${this.attestationOutput.attesters.map((attester) => { 65 | const date = new Date(attester.timestamp/1000) 66 | return html` 67 |
      68 |
      Who:
      69 |
      When:
      70 |
      Bare Verifiable:
      71 |
      Full Verifiable:
      74 |
      75 | ` 76 | })} 77 |
    78 |
    79 |
    80 | `; 81 | } 82 | } 83 | 84 | 85 | static get scopedElements() { 86 | return { 87 | 'agent-avatar': AgentAvatar, 88 | 'sl-relative-time': SlRelativeTime, 89 | 'copiable-content': CopyableContent, 90 | 'attestation-folk': AttestationFolk 91 | }; 92 | } 93 | static get styles() { 94 | return [ 95 | sharedStyles, 96 | css` 97 | div { 98 | padding: 5px; 99 | } 100 | `, 101 | ]; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /ui/lib/src/elements/attestations-controller.ts: -------------------------------------------------------------------------------- 1 | import { html, css, LitElement } from "lit"; 2 | import { state, property, query } from "lit/decorators.js"; 3 | 4 | import { contextProvided } from "@lit-labs/context"; 5 | import { StoreSubscriber } from "lit-svelte-stores"; 6 | import { Unsubscriber, Readable, get } from "svelte/store"; 7 | 8 | import { sharedStyles } from "../sharedStyles"; 9 | import {attestationsContext, Attestation, AttestationOutput, Dictionary, Signal} from "../types"; 10 | import { AttestationsStore } from "../attestations.store"; 11 | import { AttestationsAttestation } from "./attestations-attestation"; 12 | import { AttestationsAttestationDialog, DialogType } from "./attestations-attestation-dialog"; 13 | import { ScopedElementsMixin } from "@open-wc/scoped-elements"; 14 | import { 15 | ListItem, 16 | Select, 17 | IconButton, 18 | Button, TextField, TopAppBar, Drawer, List, Icon, Switch, Formfield, Menu, 19 | } from "@scoped-elements/material-web"; 20 | import { 21 | profilesStoreContext, 22 | ProfilesStore, 23 | Profile, 24 | AgentAvatar 25 | } from "@holochain-open-dev/profiles"; 26 | import {EntryHashB64} from "@holochain-open-dev/core-types"; 27 | import { VerifyAttestation } from "./verify-attestation"; 28 | import { CopyableContent } from "./copiable-content"; 29 | import { AttestationFolk } from "./attestation-folk"; 30 | import { AttestationsNotifyDialog } from "./attestations-notify-dialog"; 31 | import { serializeHash } from "@holochain-open-dev/utils"; 32 | 33 | /** 34 | * @element attestations-controller 35 | */ 36 | export class AttestationsController extends ScopedElementsMixin(LitElement) { 37 | constructor() { 38 | super(); 39 | } 40 | 41 | /** Public attributes */ 42 | @property({ type: Boolean, attribute: 'dummy' }) 43 | canLoadDummy = false; 44 | 45 | /** Dependencies */ 46 | 47 | @contextProvided({ context: attestationsContext }) 48 | _store!: AttestationsStore; 49 | 50 | @contextProvided({ context: profilesStoreContext }) 51 | _profiles!: ProfilesStore; 52 | 53 | _myProfile!: Readable ; 54 | _myAttestations = new StoreSubscriber(this, () => this._store.myAttestations); 55 | _searchAttestations = new StoreSubscriber(this, () => this._store.searchedAttestations); 56 | 57 | 58 | /** Private properties */ 59 | 60 | @query('#search-field') 61 | _searchField!: TextField; 62 | @query('#search-button') 63 | _searchButton!: Button; 64 | @query("#selected-attestation") 65 | _attestationElem!: AttestationsAttestation 66 | 67 | @query('#my-drawer') 68 | private _drawer!: Drawer; 69 | 70 | @state() _currentAttestationEh = ""; 71 | @state() _currentAttestationOutput : AttestationOutput | undefined; 72 | @state() noneFound = false; 73 | 74 | private initialized = false; 75 | private initializing = false; 76 | 77 | 78 | async createDummyProfile() { 79 | const nickname = "Cam"; 80 | const avatar = "https://cdn3.iconfinder.com/data/icons/avatars-9/145/Avatar_Cat-512.png"; 81 | 82 | try { 83 | const fields: Dictionary = {}; 84 | if (avatar) { 85 | fields['avatar'] = avatar; 86 | } 87 | await this._profiles.createProfile({ 88 | nickname, 89 | fields, 90 | }); 91 | 92 | } catch (e) { 93 | //this._existingUsernames[nickname] = true; 94 | //this._nicknameField.reportValidity(); 95 | } 96 | } 97 | 98 | 99 | get myNickName(): string { 100 | const p = get(this._myProfile) 101 | return p ? p.nickname : ""; 102 | } 103 | get myAvatar(): string { 104 | const p = get(this._myProfile) 105 | return p ? p.fields.avatar : ""; 106 | } 107 | 108 | private async subscribeProfile() { 109 | 110 | this._myProfile = await this._profiles.fetchMyProfile() 111 | /* 112 | let unsubscribe: Unsubscriber; 113 | unsubscribe = this._profiles.myProfile.subscribe(async (profile) => { 114 | if (profile) { 115 | await this.checkInit(); 116 | } 117 | // unsubscribe() 118 | }); */ 119 | } 120 | 121 | async firstUpdated() { 122 | if (this.canLoadDummy) { 123 | await this.createDummyProfile() 124 | } 125 | this.subscribeProfile() 126 | } 127 | 128 | private _getFirst(attestations: Dictionary): EntryHashB64 { 129 | if (Object.keys(attestations).length == 0) { 130 | return ""; 131 | } 132 | for (let attestationEh in attestations) { 133 | // const attestation = attestations[attestationEh] 134 | // if (attestation.visible) { 135 | return attestationEh 136 | // } 137 | } 138 | return ""; 139 | } 140 | 141 | async checkInit() { 142 | if (this.initialized || this.initializing) { 143 | this.initialized = true; 144 | return; 145 | } 146 | this.initializing = true // because checkInit gets call whenever profiles changes... 147 | let attestations = await this._store.pullMyAttestations(); 148 | 149 | /** load up a attestation if there are none */ 150 | if (Object.keys(attestations).length == 0) { 151 | console.log("no attestations found, initializing") 152 | await this.addHardcodedAttestations(); 153 | attestations = await this._store.pullMyAttestations(); 154 | } 155 | if (Object.keys(attestations).length == 0) { 156 | console.error("No attestations found") 157 | } 158 | this._currentAttestationEh = this._getFirst(attestations); 159 | 160 | console.log(" current attestation: ", attestations[this._currentAttestationEh].content, this._currentAttestationEh); 161 | 162 | // request the update so the drawer will be findable 163 | await this.requestUpdate(); 164 | 165 | /** Drawer */ 166 | if (this._drawer) { 167 | const container = this._drawer.parentNode!; 168 | container.addEventListener('MDCTopAppBar:nav', () => { 169 | this._drawer.open = !this._drawer.open; 170 | }); 171 | } 172 | /** Menu */ 173 | const menu = this.shadowRoot!.getElementById("top-menu") as Menu; 174 | const button = this.shadowRoot!.getElementById("menu-button") as IconButton; 175 | menu.anchor = button 176 | // - Done 177 | this.initializing = false 178 | this.initialized = true 179 | } 180 | 181 | async addHardcodedAttestations() { 182 | 183 | /** Attestations */ 184 | await this._store.addAttestation({ 185 | content: "I exist!", 186 | about: this._store.myAgentPubKey, 187 | }); 188 | } 189 | 190 | async refresh() { 191 | console.log("refresh: Pulling data from DHT") 192 | await this._store.pullMyAttestations(); 193 | await this._profiles.fetchAllProfiles() 194 | } 195 | 196 | async openAttestationDialog(type: DialogType) { 197 | this.attestationDialogElem.resetAllFields(); 198 | this.attestationDialogElem.open(type); 199 | } 200 | 201 | async openNotifyDialog(title: string, notification: string) { 202 | const elem = this.notifyDialogElem 203 | elem.notification = notification 204 | elem.title = title 205 | elem.open(); 206 | } 207 | 208 | get attestationDialogElem() : AttestationsAttestationDialog { 209 | return this.shadowRoot!.getElementById("attestation-dialog") as AttestationsAttestationDialog; 210 | } 211 | get notifyDialogElem() : AttestationsNotifyDialog { 212 | return this.shadowRoot!.getElementById("notify-dialog") as AttestationsNotifyDialog; 213 | } 214 | private async handleAttestationSelected(e: any, attestations: Dictionary): Promise { 215 | const index = e.detail.index; 216 | const attestationList = e.target as List; 217 | console.log(e.detail) 218 | console.log("target", attestationList) 219 | console.log("index", index) 220 | console.log("val", attestationList.items[index]) 221 | 222 | if (attestationList.items[index]) { 223 | const value = attestationList.items[index].value; 224 | this._currentAttestationEh = value; 225 | this._currentAttestationOutput = attestations[value]; 226 | } else { 227 | this._currentAttestationEh = ""; 228 | this._currentAttestationOutput = undefined; 229 | 230 | } 231 | } 232 | 233 | openTopMenu() { 234 | const menu = this.shadowRoot!.getElementById("top-menu") as Menu; 235 | menu.open = true; 236 | } 237 | 238 | handleMenuSelect(e: any) { 239 | console.log("handleMenuSelect: " + e.originalTarget.innerHTML) 240 | //console.log({e}) 241 | switch (e.originalTarget.innerHTML) { 242 | case "Generate Nonce": 243 | this.openAttestationDialog(DialogType.CreateNonce) 244 | break; 245 | case "Fulfill Nonce": 246 | this.openAttestationDialog(DialogType.FulfilNonce) 247 | break; 248 | default: 249 | break; 250 | } 251 | } 252 | async search() { 253 | const result = await this._store.searchAttestations(this._searchField.value) 254 | this.noneFound = Object.keys(result).length == 0 255 | } 256 | 257 | makeAttestationList(entries: Dictionary, display: string) { 258 | return Object.entries(entries).map( 259 | ([key, attestationOutput]) => { 260 | const attestation = attestationOutput.content 261 | return html` 262 | 263 | 264 | 265 | ` 266 | }) 267 | } 268 | 269 | render() { 270 | 271 | /** Build attestation list */ 272 | const attestations = this.makeAttestationList(this._myAttestations.value, "compact") 273 | const searched = this.makeAttestationList(this._searchAttestations.value, "compact-with-who") 274 | 275 | return html` 276 | 277 | 278 |
    279 | 280 | 281 | ${this.myNickName} 282 | ${this._profiles.myAgentPubKey} 283 | 284 | 285 |
  • 286 |
    287 |
    288 | 289 | 290 |
    291 | 292 | 293 | 294 |
    Who Said What (to/about Whom)
    295 | this.refresh()} > 296 | this.openTopMenu()}> 297 | 298 | Generate Nonceedit 299 | Fulfill Nonceedit 300 | 301 |
    302 | 303 |
    304 | 305 |
    306 |
    307 |

    My Attestations

    308 |
    309 | 310 |
    311 |
    312 | this.openAttestationDialog(DialogType.Attestation)}>Attestation 313 | 314 | this.handleAttestationSelected(e,this._myAttestations.value)}> 315 | ${attestations} 316 | 317 |
    318 | 319 |
    320 |

    Search Attestations

    321 |
    322 | this._searchButton.disabled = !Boolean(this._searchField.value)}> 323 | this.search()} disabled> 324 |
    325 |
    326 | ${this.noneFound ? "Nothing found" : html` 327 | this.handleAttestationSelected(e, this._searchAttestations.value)}> 328 | ${searched} 329 | `} 330 |
    331 |
    332 | 333 |
    334 |

    Verification

    335 | 336 |
    337 |
    338 | 339 | this._currentAttestationEh = e.detail} 342 | @nonce-created=${(e:any) => this.openNotifyDialog(`Nonce Created`,`Nonce value: ${e.detail}`)} 343 | > 344 | 345 | 346 |
    347 |
    348 | `; 349 | } 350 | 351 | 352 | static get scopedElements() { 353 | return { 354 | "mwc-menu": Menu, 355 | "mwc-switch": Switch, 356 | "mwc-drawer": Drawer, 357 | "mwc-top-app-bar": TopAppBar, 358 | "mwc-textfield": TextField, 359 | "mwc-select": Select, 360 | "mwc-list": List, 361 | "mwc-list-item": ListItem, 362 | "mwc-icon": Icon, 363 | "mwc-icon-button": IconButton, 364 | "mwc-button": Button, 365 | "attestations-attestation-dialog" : AttestationsAttestationDialog, 366 | "attestations-notify-dialog" : AttestationsNotifyDialog, 367 | "attestations-attestation": AttestationsAttestation, 368 | "mwc-formfield": Formfield, 369 | 'agent-avatar': AgentAvatar, 370 | 'verify-attestation': VerifyAttestation, 371 | 'copiable-content': CopyableContent, 372 | 'attestation-folk': AttestationFolk 373 | }; 374 | } 375 | 376 | static get styles() { 377 | return [ 378 | sharedStyles, 379 | css` 380 | :host { 381 | margin: 10px; 382 | } 383 | 384 | .mdc-drawer__header { 385 | display:none; 386 | } 387 | 388 | mwc-top-app-bar { 389 | /**--mdc-theme-primary: #00ffbb;*/ 390 | /**--mdc-theme-on-primary: black;*/ 391 | } 392 | 393 | #app-bar { 394 | /*margin-top: -15px;*/ 395 | } 396 | 397 | #my-drawer { 398 | margin-top: -15px; 399 | } 400 | 401 | .attestations-list { 402 | margin: 10px; 403 | border-right: black 1px solid; 404 | } 405 | 406 | #selected-attestation { 407 | border-right: black 1px solid; 408 | } 409 | 410 | .appBody { 411 | width: 100%; 412 | margin-top: 2px; 413 | display:flex; 414 | } 415 | 416 | .folk { 417 | list-style: none; 418 | margin: 2px; 419 | text-align: center; 420 | font-size: 70%; 421 | } 422 | 423 | .folk > img { 424 | width: 50px; 425 | border-radius: 10000px; 426 | } 427 | 428 | #search-results ul { 429 | list-style:none; 430 | } 431 | 432 | mwc-textfield.rounded { 433 | --mdc-shape-small: 20px; 434 | width: 7em; 435 | margin-top:10px; 436 | } 437 | 438 | mwc-textfield label { 439 | padding: 0px; 440 | } 441 | 442 | @media (min-width: 640px) { 443 | main { 444 | max-width: none; 445 | } 446 | } 447 | `, 448 | ]; 449 | } 450 | } 451 | -------------------------------------------------------------------------------- /ui/lib/src/elements/attestations-notify-dialog.ts: -------------------------------------------------------------------------------- 1 | import {css, html, LitElement} from "lit"; 2 | import {property, state} from "lit/decorators.js"; 3 | 4 | import {sharedStyles} from "../sharedStyles"; 5 | import {contextProvided} from "@lit-labs/context"; 6 | import {ScopedElementsMixin} from "@open-wc/scoped-elements"; 7 | import { 8 | Button, 9 | Dialog, 10 | } from "@scoped-elements/material-web"; 11 | 12 | /** 13 | * @element attestations-attestation-dialog 14 | */ 15 | export class AttestationsNotifyDialog extends ScopedElementsMixin(LitElement) { 16 | @property() title: string = ""; 17 | @property() notification: string = ""; 18 | 19 | /** 20 | * 21 | */ 22 | open() { 23 | this.requestUpdate(); 24 | const dialog = this.shadowRoot!.getElementById("notify-dialog") as Dialog 25 | dialog.open = true 26 | } 27 | render() { 28 | return html` 29 | 33 |
    ${this.notification}
    34 | ok 36 |
    37 | `; 38 | } 39 | 40 | 41 | static get scopedElements() { 42 | return { 43 | "mwc-button": Button, 44 | "mwc-dialog": Dialog, 45 | }; 46 | } 47 | static get styles() { 48 | return [ 49 | sharedStyles, 50 | css` 51 | #notify-dialog { 52 | --mdc-dialog-min-width: 600px; 53 | } 54 | `, 55 | ]; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /ui/lib/src/elements/copiable-content.ts: -------------------------------------------------------------------------------- 1 | import { ScopedElementsMixin } from '@open-wc/scoped-elements'; 2 | import { html, LitElement } from 'lit'; 3 | import { property, query } from 'lit/decorators.js'; 4 | import { IconButton } from '@scoped-elements/material-web'; 5 | import { Snackbar } from '@scoped-elements/material-web'; 6 | import { sharedStyles } from '../sharedStyles'; 7 | import { Base64 } from "js-base64"; 8 | 9 | export class CopyableContent extends ScopedElementsMixin(LitElement) { 10 | @property() 11 | content!: Uint8Array | string; 12 | 13 | @property({ type: Number }) 14 | sliceLength: number = 8; 15 | 16 | @query('#copy-notification') 17 | _copyNotification!: Snackbar; 18 | 19 | get strContent() { 20 | return typeof this.content === 'string' ? this.content : Base64.fromUint8Array(this.content, true); 21 | } 22 | 23 | async copyContent() { 24 | await navigator.clipboard.writeText(this.strContent); 25 | this._copyNotification.show(); 26 | } 27 | 28 | render() { 29 | return html` 30 | 34 |
    35 | ${this.strContent.substring(0, this.sliceLength)}... 38 | this.copyContent()} 42 | > 43 |
    44 | `; 45 | } 46 | 47 | static get styles() { 48 | return sharedStyles; 49 | } 50 | 51 | static get scopedElements() { 52 | return { 53 | 'mwc-icon-button': IconButton, 54 | 'mwc-snackbar': Snackbar, 55 | }; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /ui/lib/src/elements/verify-attestation.ts: -------------------------------------------------------------------------------- 1 | import { css, html, LitElement } from "lit"; 2 | import { property, query, state } from "lit/decorators.js"; 3 | 4 | import { contextProvided } from "@lit-labs/context"; 5 | import { IconButton, TextArea } from "@scoped-elements/material-web"; 6 | import { AttestationsAttestation } from "./attestations-attestation"; 7 | import { ScopedElementsMixin } from "@open-wc/scoped-elements"; 8 | import { sharedStyles } from "../sharedStyles"; 9 | import { Attestation, attestationsContext, Verifiable } from "../types"; 10 | import { AttestationsStore } from "../attestations.store"; 11 | import { Base64 } from "js-base64"; 12 | import { decode } from "@msgpack/msgpack"; 13 | import { AttestationFolk } from "./attestation-folk"; 14 | 15 | export class VerifyAttestation extends ScopedElementsMixin(LitElement) { 16 | @query("#verifiable-field") 17 | _verifiable!: TextArea; 18 | 19 | @state() 20 | _attestation: Attestation | undefined; 21 | @state() 22 | _verified: boolean = false; 23 | @state() 24 | _verificationError: string = ""; 25 | 26 | @contextProvided({ context: attestationsContext }) 27 | _store!: AttestationsStore; 28 | 29 | async check() { 30 | this._verificationError = ""; 31 | try { 32 | const verifiable: Verifiable = decode( 33 | Base64.toUint8Array(this._verifiable.value) 34 | ) as Verifiable; 35 | if (verifiable.attestation) { 36 | this._attestation = verifiable.attestation; 37 | } else { 38 | this._attestation = undefined; 39 | } 40 | this._verified = await this._store.verify(verifiable); 41 | } catch (e) { 42 | this._verified = false; 43 | this._attestation = undefined; 44 | this._verificationError = `Bad verifiable format`; 45 | } 46 | } 47 | render() { 48 | const attestation = this._attestation 49 | ? html` 50 |
    Content: ${this._attestation.content}
    51 |
    About:
    ` 52 | : html`(Bare verifiable)`; 53 | const err = this._verificationError ? html`

    ${this._verificationError}

    `: "" 54 | return html` 55 | 64 |
    65 | ${this._verifiable && this._verifiable.value != "" ? 66 | (this._verified ? html`

    Verified

    ${attestation}` : html`

    Verification Failed!

    ${err}`) 67 | : ""} 68 |
    `; 69 | } 70 | static get styles() { 71 | return [ 72 | sharedStyles, 73 | css` 74 | .verified { 75 | margin: 5px; 76 | } 77 | `, 78 | ]; 79 | } 80 | 81 | static get scopedElements() { 82 | return { 83 | "mwc-icon-button": IconButton, 84 | "mwc-textarea": TextArea, 85 | "attestations-attestation": AttestationsAttestation, 86 | 'attestation-folk': AttestationFolk 87 | }; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /ui/lib/src/index.ts: -------------------------------------------------------------------------------- 1 | // Import the container media queries mixin 2 | import 'cqfill'; 3 | 4 | // TODO: change exports to be available for consumer packages 5 | 6 | export * from './elements/attestations-controller'; 7 | export * from './elements/attestations-attestation'; 8 | export * from './elements/attestation-folk'; 9 | export * from './attestations.service'; 10 | export * from './attestations.store'; 11 | export * from './types'; 12 | -------------------------------------------------------------------------------- /ui/lib/src/sharedStyles.ts: -------------------------------------------------------------------------------- 1 | import { css } from 'lit'; 2 | 3 | export const sharedStyles = css` 4 | .column { 5 | display: flex; 6 | flex-direction: column; 7 | } 8 | .row { 9 | display: flex; 10 | flex-direction: row; 11 | } 12 | 13 | `; 14 | -------------------------------------------------------------------------------- /ui/lib/src/types.ts: -------------------------------------------------------------------------------- 1 | // TODO: add globally available interfaces for your elements 2 | 3 | import { EntryHashB64, AgentPubKeyB64 } from "@holochain-open-dev/core-types"; 4 | import { Timestamp } from "@holochain/client"; 5 | import { createContext } from "@lit-labs/context"; 6 | import { AttestationsStore } from "./attestations.store"; 7 | import {SignedActionHashed } from "@holochain/client" 8 | 9 | export const attestationsContext = createContext('hc_zome_attestations/service'); 10 | 11 | export type Dictionary = { [key: string]: T }; 12 | 13 | export interface Verifiable { 14 | attestation?: Attestation, 15 | signedActions: Array, 16 | } 17 | 18 | export interface AttestationContext { 19 | author: AgentPubKeyB64, 20 | timestamp: number, 21 | } 22 | 23 | export interface AttestationOutput { 24 | hash: EntryHashB64, 25 | attesters: Array, 26 | verifiable: Verifiable, 27 | content: Attestation, 28 | } 29 | 30 | export interface GetAttestationsInput { 31 | content?: string, 32 | by?: AgentPubKeyB64, 33 | of?: AgentPubKeyB64, 34 | } 35 | 36 | export interface AttestationEntry { 37 | content: string; 38 | about: AgentPubKeyB64; 39 | } 40 | 41 | export interface Attestation { 42 | content: string; 43 | about: AgentPubKeyB64; 44 | } 45 | 46 | 47 | export type Signal = 48 | | { 49 | attestationHash: EntryHashB64, message: {type: "NewAttestation", content: AttestationEntry} 50 | } 51 | 52 | export interface FulfillNonceInput { 53 | with: AgentPubKeyB64, 54 | nonce: number, 55 | } 56 | export interface CreateNonceInput { 57 | with: AgentPubKeyB64, 58 | note: string, 59 | } -------------------------------------------------------------------------------- /ui/lib/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "declarationDir": "dist", 6 | "rootDir": "./src", 7 | "declaration": true 8 | }, 9 | 10 | "include": ["src/**/*.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /workdir/web-happ.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | manifest_version: "1" 3 | name: attestations 4 | ui: 5 | bundled: "../ui/apps/attestations/ui.zip" 6 | happ_manifest: 7 | bundled: "../dna/workdir/happ/attestations.happ" 8 | --------------------------------------------------------------------------------