render_example_test.gno
5.06 Kb · 137 lines
1package wesh
2
3import (
4 "encoding/hex"
5
6 "gno.land/p/moul/x/wesh/v0"
7 "gno.land/p/nt/avl/v0"
8 "gno.land/p/nt/testutils/v0"
9)
10
11// seedDemo puts the realm into a fixed state for the examples below.
12//
13// It writes the globals directly instead of going through the crossing API:
14// realm globals persist for the whole test binary and examples run after every
15// Test, so an example that did not reset would pin whatever the last test left
16// behind. Heights are literals for the same reason.
17func seedDemo() {
18 byName = avl.Tree{}
19 byOwner = avl.Tree{}
20 byAccount = avl.Tree{}
21
22 pk, _ := hex.DecodeString("2152f8d19b791d24453242e15f2eab6cb7cffa7b6a5ed30097960e069881db12")
23 seed1, _ := hex.DecodeString("abababababababababababababababababababababababababababababababab")
24 seed2, _ := hex.DecodeString("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee")
25 dev1, _ := hex.DecodeString("0707070707070707070707070707070707070707070707070707070707070707")
26 dev2, _ := hex.DecodeString("0909090909090909090909090909090909090909090909090909090909090909")
27 d1, _ := hex.DecodeString("bc51799b5d012dc7ce806b4c63474b1e2db515e7d1622ecd5900b23e1d6a9519")
28 d2, _ := hex.DecodeString("b0da03f83e5349e92bc524714862daa850750f756ca6fd47264333fbf2175c15")
29 d3, _ := hex.DecodeString("ef0c1d0614420c7d660f8416b18651206118e49e8f46ac0360bef61ae6b9100d")
30
31 alice := &identity{
32 name: "alice",
33 owner: testutils.TestAddress("alice"),
34 accountPK: pk,
35 payload: seed2,
36 revision: 2,
37 displayName: "Alice, support line",
38 history: []rotation{
39 {revision: 1, payload: seed1, height: 100},
40 {revision: 2, payload: seed2, height: 140},
41 },
42 devices: []deviceEntry{
43 {seq: 0, op: wesh.OpAdd, devicePK: dev1, digest: d1, height: 110},
44 {seq: 1, op: wesh.OpAdd, devicePK: dev2, digest: d2, height: 120},
45 {seq: 2, op: wesh.OpRevoke, devicePK: dev1, digest: d3, height: 130},
46 },
47 head: d3,
48 }
49 byName.Set(alice.name, alice)
50 byOwner.Set(alice.owner.String(), alice.name)
51 byAccount.Set(hex.EncodeToString(pk), alice.name)
52}
53
54// ExampleRender pins the directory index.
55func ExampleRender() {
56 seedDemo()
57 print(Render(""))
58 // Output:
59 // # Wesh directory
60 //
61 // Resolvable, self-signed [Wesh protocol](https://berty.tech/docs/protocol/) identities, on top of [`p/moul/x/wesh`](/p/moul/x/wesh/v0).
62 //
63 // A Berty identity normally travels out of band as a QR code, cannot be looked up, cannot announce a seed rotation, and can never revoke a device. This realm addresses those three, and stores no secret of any kind.
64 //
65 // | name | owner | rev | mode | devices |
66 // |---|---|---|---|---|
67 // | [alice](/r/moul/x/wesh/v0:alice) | `g1v9kxjcm9ta047h6lta047h6lta047h6lzd40gh` | 2 | published | 1 active / 3 entries |
68 //
69 // 1 identity.
70}
71
72// ExampleRender_identity pins one identity card: the Berty link, today's
73// rendezvous point, the device sigchain and the rotation history.
74func ExampleRender_identity() {
75 seedDemo()
76 print(Render("alice"))
77 // Output:
78 // # alice
79 //
80 // _Alice, support line_
81 //
82 // | field | value |
83 // |---|---|
84 // | owner | `g1v9kxjcm9ta047h6lta047h6lta047h6lzd40gh` |
85 // | account key | `2152f8d19b791d24453242e15f2eab6cb7cffa7b6a5ed30097960e069881db12` |
86 // | mode | published |
87 // | revision | 2 |
88 // | registered | block 100 |
89 //
90 // ## Contact
91 //
92 // Scan or open this in Berty to send a contact request:
93 //
94 // ```
95 // https://berty.tech/id#contact/oZBLGHCDNRB847rT1zHe1xnon58fpWTUsuNntmAo9TK42aKzt14A1V5W67QoN5YzMouuVcucUiBWjN9d2qzy6gUNM4Jio4M/name=Alice%2C+support+line
96 // ```
97 //
98 // | field | value |
99 // |---|---|
100 // | rendezvous seed | `eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee` |
101 // | rendezvous point, period 1234483200 | `08ab5591fbd91f0251a7efe4856fc736a02d1a2252139483ddc8ca85f4616e07` |
102 //
103 // The point is `HMAC-SHA256(accountPK || seed, be64(period))`, derived exactly as weshnet derives it, and it rotates every 24h. Anyone can recompute it and check the DHT, so this entry is verifiable rather than merely asserted.
104 //
105 // ## Devices
106 //
107 // Every entry below was signed by the account key and verified on chain, and chains to the digest of the one before it.
108 //
109 // | seq | op | device | block | digest |
110 // |---|---|---|---|---|
111 // | 0 | add | `07070707…07070707` | 110 | `bc51799b…1d6a9519` |
112 // | 1 | add | `09090909…09090909` | 120 | `b0da03f8…f2175c15` |
113 // | 2 | revoke | `07070707…07070707` | 130 | `ef0c1d06…e6b9100d` |
114 //
115 // Head: `ef0c1d0614420c7d660f8416b18651206118e49e8f46ac0360bef61ae6b9100d`
116 //
117 // ## Rotation history
118 //
119 // Weshnet has no way to announce that a seed was reset, so every link ever shared dies silently. These are the superseded values, kept so a stale link can be recognised as stale.
120 //
121 // | rev | value | block |
122 // |---|---|---|
123 // | 1 | `abababab…abababab` | 100 |
124 // | 2 (current) | `eeeeeeee…eeeeeeee` | 140 |
125 //
126 // [Back to the directory](/r/moul/x/wesh/v0) · chain `dev`
127}
128
129// ExampleRender_unknown pins the miss.
130func ExampleRender_unknown() {
131 seedDemo()
132 print(Render("nobody"))
133 // Output:
134 // # Not found
135 //
136 // No identity named `nobody`. [Back to the directory](/r/moul/x/wesh/v0).
137}