git ssb

1+

Daan Patchwork / patchwork



Commit 6df8f9822940a85660caf16ce3b5f32f30589248

Merge pull request #1440 from ssbc/mnemonic

settings changes
Daan Wynen authored on 4/5/2021, 11:14:50 AM
GitHub committed on 4/5/2021, 11:14:50 AM
Parent: 2c11a9dc2541a07740f246f2ab4dd2d8e0b679fb
Parent: d1627bb325d9d1acbb1ba98a75ceb37a6b537c85

Files changed

assets/mnemonic_warning.mdadded
lib/depject/index.jschanged
lib/depject/page/html/render/settings.jschanged
lib/depject/page/html/render/mnemonic.jsadded
lib/main-window.jschanged
locales/en.jsonchanged
package-lock.jsonchanged
package.jsonchanged
styles/dark/base.mcsschanged
styles/dracula/base.mcsschanged
styles/light/base.mcsschanged
assets/mnemonic_warning.mdView
@@ -1,0 +1,194 @@
1 +**Warning: mishandling exported keys will lead to a broken feed.** If you break your feed, you will have to create a new identity and start from scratch. You will lose all your connections and possibly your previous posts, and **nobody will be able to fix this**.
2 +
3 +At the bottom of this page you will find instructions for how to use these keys safely, but do yourself a favour and read this page before.
4 +
5 +## Do I need this key export?
6 +
7 +You only need to do this if you intend to move (not copy!) your Patchwork identity to a different *device*.
8 +If you want to migrate to a different client, but stay on the *same* device, then you very likely do not need this key export.
9 +
10 +## What can I use the exported keys for?
11 +
12 +This page allows you to export your `secret`, i.e. your ssb feed's private key as a series of common words. Other clients, first and foremost [manyverse](https://manyver.se), can *import* the secret in this form. This allows you to discontinue Patchwork (which is unmaintained) and instead interact with the ssb network through the new client. We'll be talking about manyverse pretty much exclusively here because it is *currently* the only client that can import this export. But for other clients, the procedure should be very similar.
13 +
14 +## What can I *not* do with the exported keys?
15 +
16 +You can *not* use the keys to use the same identity on multiple devices.
17 +To be precise: if you try this you will regret it very quickly, since the most likely outcome is that you will eventually "fork" your feed.
18 +Keeping your feed intact is your own responability. Neither the Patchwork developers, nor the manyverse developers, nor anyone else will be able to help you if you fork your feed.
19 +
20 +## What does it mean to "fork" a feed?
21 +
22 +Scuttlebutt relies, among other things, on one basic property of ssb feeds: that they are linear.
23 +In practice, that means that every message contains a reference to the preceding one, so that they form one long chain all the way back to the first message of the feed.
24 +And for each message, ssb also computes a `hash`, i.e. a strong check-sum, *from* the message.
25 +Let's pretend that the `hash` of a message is computed by selecting the *one* emoji that best represents it.
26 +Here are some examples from a feed called `@Carol`:
27 +
28 +sequence | hash | previous | type | content
29 +:-|:-|:-|:-|:-
30 +98 | :bird: | | post | Look at this cute bird!
31 +99 | :cake: | :bird: | post | Happy birthday Bob!
32 +100 | :thumbsup: | :cake: | like | \<Carol likes Alice's post\>
33 +
34 +Note how for every message the `sequence` number increases by exactly one, and the `previous` corresponds to the `hash` of the preceding message.
35 +This makes replication very easy.
36 +
37 +### Example: How ssb peers replicate data
38 +
39 +Let's say that the computer of Alice connects to the computer of Bob to exchange messages.
40 +Alice asks for updates about Carol. Here is how they do it, in very simplified terms:
41 +
42 +```
43 +Alice: Hi Bob, do you have messages from Carol?
44 +
45 +Bob: Yes, the latest message I have is number 100.
46 +
47 +Alice: The latest message I have is number 99.
48 + Please send me the missing message.
49 +
50 +Bob: Here is the missing message.
51 +
52 +Alice: Ah yes, this is number 100, signed by Carol alright
53 + The "previous" 🍰 matches the "hash" 🍰 from number 99.
54 + Ohh, the message says that Carol loves my #foffee post!
55 + Excellent!
56 +```
57 +
58 +As you can see, this is dead simple.
59 +Once Alice receives message number `100` she checks that the `previous` :cake: of this message matches the `hash` :cake: she knows from message `99`.
60 +If they match, all is good and she considers message `100` as valid. She saves it to her local database with the `hash` :thumbsup:.
61 +
62 +### How does a fork happen?
63 +
64 +This is the sad story of how Carol forked her feed.
65 +Carol had been using Patchwork for a while already. As the development of Patchwork had seized she decide to give manyverse a go.
66 +But Carol skipped reading this explanation. She tried to get to her key export as fast as possible without understanding what she was doing.
67 +With her key export in hand she quit Patchwork and immediately set up manyverse on her phone.
68 +After the import she was greeted with an empty screen. But she just went ahead, got an invite to an ssb room, and connected to some random stranger. The import worked fine. After a while she could see all her posts, and in celebration of this fact she posted a :cat2: picture from this morning.
69 +
70 +And just like that, Carol had forked her feed. Carol didn't know it yet, but from here on out, people would barely be reading her messages.
71 +Soon after, Carol stopped using ssb, feeling left alone by her friends who seemed to have abandoned her.
72 +
73 +**But what had happened with Carol's feed that was so bad?**
74 +When Carol connected to the ssb room, she synced her old messages from the first peer she connected with.
75 +This stranger, called Dan, however, had not seen her last message :thumbsup: number `100` yet.
76 +What Carol didn't realize was that the posts she saw stopped at number `99`. Dan had not transmitted the :thumbsup: message `100` because he hadn't seen it yet.
77 +That last message number :thumbsup: `100` that she had sent out, the one that made Alice so happy, was not actually a *post*, it was a *reaction* and Carol had missed the fact that this reaction was not being shown in the manyverse interface; an easy mistake to make, right?
78 +So now Carol had made a new message :cat2:, numbered it `100` and sent it off to Dan.
79 +Dan in turn had forwarded the :cat2: messsage `100` to a few of his own peers.
80 +All the while, Alice and Bob had been broadcasting the :tada: message `100`.
81 +
82 +Later that evening, Alice and Dan's computers connected:
83 +
84 +```
85 +Alice: Hey Dan, do you have updates from Alice?
86 +
87 +Dan: Yes, the last number I have is 100.
88 +
89 +Alice: The latest message I have is number 100, too.
90 + Okay thank you then, nothing to do here.
91 +```
92 +
93 +And none of them realized what had just happened.
94 +
95 +The next day, Alice saw the most beautiful sunrise :sunrise:. She snapped a picture and sent it off via manyverse with the number `101`.
96 +
97 +sequence | hash | previous | type | content
98 +:-|:-|:-|:-|:-
99 +101 | :sunrise: | :cat2: | post | Good morning sunshine!
100 +
101 +Her phone connected to Dan and gossiped away happily. Dan liked the photo!
102 +But Alice and Bob never saw it. Here is how it went down when Alice's computer talked to Dan's later that day:
103 +
104 +```
105 +Alice: Hey Dan, do you have updates from Alice?
106 +
107 +Dan: Yes, the last number I have is 101.
108 +
109 +Alice: The latest message I have is number 100.
110 + Please send me the missing message.
111 +
112 +Dan: Here is the missing message.
113 +
114 +Alice: Ah, this is number 101, signed by Carol alright.
115 + But the "previous" 🐈 does not match the
116 + "hash" 🍰 from number 100! PANIC!?!
117 + There is something seriously wrong here! :(
118 + I can't save this like that.
119 +```
120 +
121 +From this point on, only some of Carol's friends ever got to see her posts: those that happened to see the :cat2: message before the :thumbsup: one. Some of her friends were using ssb clients with stricter enforcement; those clients marked her entire feed as not trustworthy when they saw the fork.
122 +And she never knew.
123 +
124 +Don't be like Carol. Be careful and don't fork your feed.
125 +
126 +## How do I *safely* migrate to a different client?
127 +
128 +Now that you're appropriately scared to fork your feed, let's look at how to *still* migrate your identity to manyverse.
129 +But first, to re-iterate:
130 +**You only *need* to do this if you intend to move to a mobile device, and you *must* stop using the identity in Patchwork.**
131 +
132 +The following instructions should keep the risk of forking at a minimum. They also explain *why* the steps are necessary, that should reduce the risk of misunderstandings.
133 +However, if you do end up with a forked feed, it may be hard to *realize* it, and it will probably be *impossible* to fix.
134 +The only way to go forward in that case is a new identity.
135 +
136 +So beware, here be dragons!
137 +
138 +What you will need:
139 +
140 +* PC/Mac running Patchwork
141 + This is the device you're migrating *from* and that you're probably reading this on right now. We'll just call it "PC" from now on.
142 +* Phone/Tablet with Manyverse installed
143 + This is the device you're migrating *to*. We use manyverse as an example since it is the only client supporting key import at the time of writing. We'll just call it "phone" from here on.
144 +* Wifi.
145 + You will be transferring data directly between the two devices, so they need to be able to see each other on some local network, and Wifi is the obvious choice for that.
146 +* A piece of paper and a pen.
147 + To write your key export down. If you're feeling paranoid, some matches and an ashtray will be helpful to get rid of it later. :slightly_smiling_face:
148 +
149 +And now, without further ado:
150 +
151 +1. Read *and understand* this page in its entirety. Make a copy of this checklist; screenshot, copy/paste, whatever suits you.
152 +2. Export your keys at the bottom of the page. Write it on a piece of paper. Double and triple-check it.
153 +3. Make one last post on Patchwork.
154 + This serves two purposes: First, it signals to your peers that trouble may be ahead if things go wrong. Second, it makes it clearly *visible* what your last feed activity was. So make it distinctive. Later on, you'll be checking in manyverse whether you can see this post, to know when it's safe to post from manyverse for the first time.
155 +4. Stop *all* activity in Patchwork.
156 + It is important that the post you just created stays the very *last* one of your feed. Pretty much any activity in Patchwork will break that assumption: liking/unliking posts, joining/unjoining events, subscribing/unsubscribing to/from channels, private messages, public posts, profile updates, follows/unfollows; all of these generate messages that would add to your feed. So don't do *any* of those.
157 + Bonus: verify that your latest post has showed up on some *other* machine. You can ask a friend (by phone or mail, but not by ssb of course, since that would produce new messages!) to verify that they can see your post. That way you know that the post made it to the network. If you enabled `publicWebHosting` before, then your post should show up on public ssb-viewer instances. If you see someone liking or replying to your last post, that's also a good way to know someone has received it.
158 +5. Quit Patchwork.
159 +6. Move your `secret` out of the way.
160 + You don't want to delete it *just yet*, but we need to make Patchwork believe it is someone else, to avoid any identity confusion when the key-imported manyverse connects to the PC and talks to "itself".
161 + On the PC, your private key lives in a file called `secret` inside the `.ssb` folder. Here's where you typically find this file:
162 + * Linux: `/home/<username>/.ssb/` where you replace `<username>` with your own. Note that `.ssb` is considered hidden since it starts with a `"."` so you may have to "show hidden files" or such in your file manager. If you installed patchwork with `sudo snap install ssb-patchwork` then you're looking for `~/snap/ssb-patchwork/3/.ssb/` where you might need to replace `3` with a different number.
163 + * MacOS: like on Linux, look for `~/.ssb/`
164 + * Windows: `%userprofile%\.ssb` which typically points to `C:\Users\<username>\.ssb`
165 + Once you find the file, just rename it to `secret_bak` or such. Patchwork will generate a new, random `secret` when it starts the next time.
166 +7. Start Patchwork
167 + It will launch with a popup asking you to create your basic profile, because the feed it just randomly created has never posted anything. You can go ahead and give yourself a name, or not, as you please.
168 +8. Put your phone into airplane mode.
169 + We don't want it reaching out to other peers just yet.
170 +9. Launch manyverse and import your key.
171 + **Do not post anything, like anything, or update your profile!**
172 + From this moment on, your phone is the sole holder of this identity, but for now it doesn't know its own history.
173 + Remember Carol? You don't want to produce *any* messages on the phone until you're sure that it is fully synced.
174 +10. Go to the manyverse settings and reduce the hop count to 1.
175 + This is optional and simply aims to ease the load of the initial sync. Keeping this sync short will reduce the total amount of stress you will experience during the process. You can reset the hops count to any other value once you're finished.
176 +11. Disable airplane mode.
177 + Check the connections tab in manyverse, and the connections tab in Patchwork. The devices should now be able to see each other.
178 + **Do not follow the patchwork identity!**
179 + Again: following someone will create a message and fork your feed. But inside manyverse, you can "Connect" to the Patchwork peer, which means just that: connecting to them to exchange messages, without necessarily following them. In Patchwork it is now safe to *follow* the manyverse identity, since Patchwork now runs a different identity.
180 + Either of the two actions, connecting from manyverse or following from Patchwork, should trigger the desired initial sync.
181 +12. Wait for the initial sync to finish.
182 + This might take a while, and manyverse should update you on the status with a progress indicator.
183 + Remember that post you made all the way back in step 3? Once you see *that* exact post at the top of your profile in manyverse, you're good.
184 + At this point there may still be a lot of data left to index from *other* feeds, especially if you reset the hop count to 2 or more. But your own feed is now back up to date and manyverse is now safe to use.
185 +13. Clean up: on the PC, remove the `secret_bak` file from step 6.
186 + You don't want your secret lying around on two machines. If you want a backup of your key, keep the piece of paper with the key export in a safe place.
187 +14. Update your friends on ssb about your adventure. Thank the developers of manyverse for the amazing work (quality *and* quantity) that they've been pouring into it.
188 +
189 +### Troubleshooting
190 +
191 +As stated repeatedly before, this is a risky operation and we (anyone) can't really give support for it.
192 +If the above goes wrong, honestly the best way to proceed is to just create a new manyverse identity. Depending on how & when things go wrong, you might be forked and it might be really hard to tell. Just create a new identity, follow the same feeds you followed before, and also follow your own old feed.
193 +Don't be sad; forking your feed is also a bit of a rite of passage.
194 +We did warn you, didn't we? :slightly_smiling_face:
lib/depject/index.jsView
@@ -138,8 +138,9 @@
138138 public: require('./page/html/render/public.js'),
139139 search: require('./page/html/render/search.js'),
140140 settings: require('./page/html/render/settings.js'),
141141 status: require('./page/html/render/status.js'),
142 + mnemonic: require('./page/html/render/mnemonic.js'),
142143 tag: require('./page/html/render/tag.js'),
143144 'your-posts': require('./page/html/render/your-posts.js'),
144145 'attending-gatherings': require('./page/html/render/attending-gatherings.js')
145146 }
lib/depject/page/html/render/settings.jsView
@@ -6,8 +6,9 @@
66 const themeNames = Object.keys(require('../../../../../styles'))
77 const electron = require('electron')
88
99 exports.needs = nest({
10 + 'app.navigate': 'first',
1011 'settings.obs.get': 'first',
1112 'intl.sync.locales': 'first',
1213 'intl.sync.i18n': 'first',
1314 'intl.sync.localeNames': 'first'
@@ -167,8 +168,24 @@
167168 // ])
168169 // ]),
169170
170171 h('section', [
172 + h('h2', i18n('Key export')),
173 +
174 + h('p', [
175 + i18n('Click'), ' ',
176 + h('a', {
177 + href: '#',
178 + 'ev-click': function () {
179 + api.app.navigate('/mnemonic', {})
180 + }
181 + }, i18n('here')), ' ',
182 + i18n('to export your secret as a mnemonic.'),
183 + ' (', 'English only, sorry.',')',
184 + ])
185 + ]),
186 +
187 + h('section', [
171188 h('h2', i18n('Information')),
172189
173190 h('p', `${packageInfo.productName} ${packageInfo.version}`)
174191 ])
lib/depject/page/html/render/mnemonic.jsView
@@ -1,0 +1,224 @@
1 +const fs = require("fs");
2 +const fsPath = require("path");
3 +const { computed, h, Value } = require("mutant");
4 +const nest = require("depnest");
5 +const ssbMnemonic = require("ssb-keys-mnemonic");
6 +const watch = require("mutant/watch");
7 +
8 +exports.needs = nest({
9 + "message.html.markdown": "first",
10 + "intl.sync.i18n": "first",
11 + "keys.sync.load": "first",
12 +});
13 +
14 +exports.gives = nest("page.html.render");
15 +
16 +exports.create = function (api) {
17 + return nest("page.html.render", function channel(path) {
18 + const assetPath = fsPath.join(
19 + __dirname,
20 + "..",
21 + "..",
22 + "..",
23 + "..",
24 + "..",
25 + "assets",
26 + "mnemonic_warning.md"
27 + );
28 + const markdown = api.message.html.markdown
29 + const warningText = fs.readFileSync(assetPath, "utf8");
30 + const warningHtml = markdown(warningText);
31 +
32 + const confirmationText = Value("");
33 +
34 + if (path !== "/mnemonic") return;
35 + const i18n = api.intl.sync.i18n;
36 +
37 + const keys = api.keys.sync.load();
38 + const words = ssbMnemonic.keysToWords(keys).split(" ");
39 + const wordBatches = [];
40 + const maxLen = words.reduce(
41 + (currMax, currWord) =>
42 + currWord.length > currMax ? currWord.length : currMax,
43 + 0
44 + );
45 + for (let i = 0; i < words.length; i = i + 4) {
46 + const batchLine = words
47 + .slice(i, i + 4)
48 + .map((s) => s.padEnd(maxLen, " "))
49 + .join(" ");
50 + wordBatches.push(batchLine);
51 + }
52 + const mnemonic = wordBatches.join("\n");
53 +
54 + const prepend = [
55 + h("PageHeading", [h("h1", [h("strong", i18n("Key Export"))])]),
56 + ];
57 +
58 + const content = [h("section", warningHtml), h("hr")];
59 +
60 + let showNextChallenge = Value(false)
61 + const showFirstChallenge = showNextChallenge
62 + content.push(
63 + h(
64 + "form",
65 + {
66 + style: {
67 + margin: "1em auto",
68 + },
69 + action: "",
70 + "ev-submit": (ev) => {
71 + ev.preventDefault();
72 + showFirstChallenge.set(true);
73 + },
74 + },
75 + h(
76 + "button",
77 + {
78 + disabled: showFirstChallenge,
79 + style: {
80 + margin: "1em auto",
81 + "background-color": "#51c067",
82 + color: "white",
83 + },
84 + },
85 + "I still want to export my keys"
86 + ),
87 + )
88 + );
89 +
90 + function addChallenge(challenge, response) {
91 + const showChalllenge = showNextChallenge;
92 + const showNext = Value(false);
93 + content.push(
94 + h(
95 + "section",
96 + { hidden: computed(showChalllenge, (b) => !b) },
97 + challenge
98 + ),
99 + h(
100 + "form",
101 + {
102 + hidden: computed(showChalllenge, (b) => !b),
103 + style: {
104 + margin: "1em auto",
105 + },
106 + action: "",
107 + "ev-submit": (ev) => {
108 + ev.preventDefault();
109 + if (confirmationText().toLowerCase() === response.toLowerCase()) {
110 + showNext.set(true);
111 + }
112 + },
113 + },
114 + [
115 + h("input", {
116 + disabled: showNext,
117 + hooks: [ValueHook(confirmationText), ScrollHook(showChalllenge)],
118 + size: response.length + 1 < 30 ? 30 : response.length + 1,
119 + "ev-paste": (ev) => {
120 + ev.preventDefault();
121 + },
122 + }),
123 + ]
124 + )
125 + );
126 + showNextChallenge = showNext
127 + }
128 +
129 + addChallenge(
130 + [
131 + markdown('> ' + i18n("To confirm you understand the risks and responsibilities here, we will play a little game. Are you ready?")),
132 + i18n("Type 'yes' and it return to continue"),
133 + ],
134 + i18n('yes'),
135 + );
136 + addChallenge(
137 + markdown('> ' + i18n("This will be annoying and slow. That's intentional. It's a feature, not a bug. You really need to understand that we can't help you if this goes wrong. Type 'I understand' to confirm")),
138 + i18n('I understand'),
139 + );
140 + addChallenge(
141 + markdown('> ' + i18n("Good. You'll answer a bunch of questions. The prize for getting them right is one giant foot-gun. Aka: your key export\nLet's start easy: What's the name of the person posting the bird picture?")),
142 + i18n('Carol'),
143 + );
144 + addChallenge(
145 + markdown('> ' + i18n("Excellent job. And that's the same person as the one posting about #foffee, right?")),
146 + i18n('no'),
147 + );
148 + addChallenge(
149 + markdown('> ' + i18n("Well *someone* has been paying attention. Good catch! So, who was it then?")),
150 + i18n('Alice'),
151 + );
152 + addChallenge(
153 + markdown('> ' + i18n("You made it quite far into the text, that's good news!\nChange of gears: Will this procedure allow you to use the same identity on multiple two or more devices?")),
154 + i18n('no'),
155 + );
156 + const sameAsChallenge = i18n('I understand that exporting my key will not allow me to use it on more than one device.')
157 + addChallenge(
158 + markdown('> ' + i18n("That's right. But let's be clear here. Please type this out:")+'\n> '+sameAsChallenge),
159 + sameAsChallenge,
160 + );
161 + addChallenge(
162 + markdown('> ' + i18n("At which step of the process does manyverse become the sole holder of your identity?")),
163 + i18n('9'),
164 + );
165 + addChallenge(
166 + markdown('> ' + i18n("Correct. Just after you import the key.\nIs it safe to post at that point then?")),
167 + i18n('no'),
168 + );
169 + addChallenge(
170 + markdown('> ' + i18n("Okay, looks like you're getting it. One last one then:\nIf any of this goes wrong, who can most likely help you?\n* The patchwork devs\n* The manyverse devs\n* Nobody")),
171 + i18n('nobody'),
172 + );
173 +
174 + content.push(
175 + h("hr", { hidden: computed(showNextChallenge, (b) => !b) }),
176 + h("div", { hidden: computed(showNextChallenge, (b) => !b) }, [
177 + h("p", i18n("Congrats, you made it. Here your mnemonic representation of your secret:")),
178 + h("pre.mnemonic", {
179 + hooks: [ScrollHook(showNextChallenge)],
180 + }, mnemonic),
181 + h(
182 + "p",
183 + i18n(
184 + "Again: be very careful with it. Keep it secret, and don't use this key on multiple devices, including this one."
185 + )
186 + ),
187 + ])
188 + );
189 +
190 + return h("Scroller", { style: { overflow: "auto" } }, [
191 + h("div.wrapper", [
192 + h(
193 + "section.prepend",
194 + h("PageHeading", [h("h1", [h("strong", i18n("Key Export"))])])
195 + ),
196 + h("section.content", content),
197 + ]),
198 + ]);
199 + });
200 +};
201 +
202 +function ValueHook(obs) {
203 + return function (element) {
204 + element.value = obs();
205 + element.oninput = function () {
206 + obs.set(element.value.trim());
207 + };
208 + };
209 +}
210 +
211 +function ScrollHook(obs) {
212 + return function(element) {
213 + var scrolledOnce = false
214 + watch(obs, (visible) => {
215 + if (!scrolledOnce && visible) {
216 + scrolledOnce = true
217 + element.scrollIntoViewIfNeeded()
218 + try {
219 + element.focus()
220 + } catch {}
221 + }
222 + })
223 + }
224 +}
lib/main-window.jsView
@@ -260,9 +260,9 @@
260260 tab(i18n('Profile'), id),
261261 computed(includeParticipating, (includeParticipating) => {
262262 if (includeParticipating) return tab(i18n('Participating'), '/participating')
263263 }),
264- tab(i18n('Mentions'), '/mentions')
264 + tab(i18n('Mentions'), '/mentions'),
265265 ])
266266 ]),
267267 when(latestUpdate,
268268 h('div.info', [
locales/en.jsonView
@@ -1,5 +1,6 @@
11 {
2 + "9": "9",
23 "Publishing...": "Publishing...",
34 "Publish": "Publish",
45 "Preview & Publish Privately": "Preview & Publish Privately",
56 "Preview & Publish": "Preview & Publish",
@@ -349,6 +350,31 @@
349350 "sv": "sv",
350351 "ta": "ta",
351352 "tg": "tg",
352353 "tr": "tr",
353- "vi": "vi"
354 + "vi": "vi",
355 + "Key export": "Key export",
356 + "Key Export": "Key Export",
357 + "To confirm you understand the risks and responsibilities here, we will play a little game. Are you ready?": "To confirm you understand the risks and responsibilities here, we will play a little game. Are you ready?",
358 + "Type 'yes' and it return to continue": "Type 'yes' and it return to continue",
359 + "yes": "yes",
360 + "This will be annoying and slow. That's intentional. It's a feature, not a bug. You really need to understand that we can't help you if this goes wrong. Type 'I understand' to confirm": "This will be annoying and slow. That's intentional. It's a feature, not a bug. You really need to understand that we can't help you if this goes wrong. Type 'I understand' to confirm",
361 + "I understand": "I understand",
362 + "Good. You'll answer a bunch of questions. The prize for getting them right is one giant foot-gun. Aka: your key export\nLet's start easy: What's the name of the person posting the bird picture?": "Good. You'll answer a bunch of questions. The prize for getting them right is one giant foot-gun. Aka: your key export\nLet's start easy: What's the name of the person posting the bird picture?",
363 + "Carol": "Carol",
364 + "Excellent job. And that's the same person as the one posting about #foffee, right?": "Excellent job. And that's the same person as the one posting about #foffee, right?",
365 + "no": "no",
366 + "Well *someone* has been paying attention. Good catch! So, who was it then?": "Well *someone* has been paying attention. Good catch! So, who was it then?",
367 + "Alice": "Alice",
368 + "You made it quite far into the text, that's good news!\nChange of gears: Will this procedure allow you to use the same identity on multiple two or more devices?": "You made it quite far into the text, that's good news!\nChange of gears: Will this procedure allow you to use the same identity on multiple two or more devices?",
369 + "I understand that exporting my key will not allow me to use it on more than one device.": "I understand that exporting my key will not allow me to use it on more than one device.",
370 + "That's right. But let's be clear here. Please type this out:": "That's right. But let's be clear here. Please type this out:",
371 + "At which step of the process does manyverse become the sole holder of your identity?": "At which step of the process does manyverse become the sole holder of your identity?",
372 + "Correct. Just after you import the key.\nIs it safe to post at that point then?": "Correct. Just after you import the key.\nIs it safe to post at that point then?",
373 + "Okay, looks like you're getting it. One last one then:\nIf any of this goes wrong, who can most likely help you?\n* The patchwork devs\n* The manyverse devs\n* Nobody": "Okay, looks like you're getting it. One last one then:\nIf any of this goes wrong, who can most likely help you?\n* The patchwork devs\n* The manyverse devs\n* Nobody",
374 + "nobody": "nobody",
375 + "Congrats, you made it. Here your mnemonic representation of your secret:": "Congrats, you made it. Here your mnemonic representation of your secret:",
376 + "Again: be very careful with it. Keep it secret, and don't use this key on multiple devices, including this one.": "Again: be very careful with it. Keep it secret, and don't use this key on multiple devices, including this one.",
377 + "Click": "Click",
378 + "here": "here",
379 + "to export your secret as a mnemonic.": "to export your secret as a mnemonic."
354380 }
package-lock.jsonView
The diff is too large to show. Use a local git client to view these changes.
Old file size: 479630 bytes
New file size: 485494 bytes
package.jsonView
@@ -76,8 +76,9 @@
7676 "ssb-ebt": "^5.6.7",
7777 "ssb-friends": "^4.4.4",
7878 "ssb-invite": "^2.1.3",
7979 "ssb-keys": "^8.0.1",
80 + "ssb-keys-mnemonic": "^1.0.1",
8081 "ssb-lan": "^1.0.0",
8182 "ssb-logging": "^1.0.0",
8283 "ssb-markdown": "github:ssbc/ssb-markdown",
8384 "ssb-master": "^1.0.3",
styles/dark/base.mcssView
@@ -7,4 +7,23 @@
77 :hover {
88 color: #aaa
99 }
1010 }
11 +
12 +div {
13 + -mnemonicWarning {
14 + border: 1px solid #ffba4e
15 + background: #5f410b
16 + color: #ffdda7
17 + padding: 0.5em 1em
18 + display:inline-block
19 + }
20 +}
21 +pre.mnemonic {
22 + border: 1px #aeaeae solid
23 + background: #434141
24 + color: #aaa
25 + white-space: pre-wrap
26 + line-height: 1.5
27 + padding: 0.5em
28 + display:inline-block
29 +}
styles/dracula/base.mcssView
@@ -17,4 +17,23 @@
1717 :hover {
1818 color: #aaa
1919 }
2020 }
21 +
22 +div {
23 + -mnemonicWarning {
24 + border: 1px solid #ffba4e
25 + background: #5f410b
26 + color: #ffdda7
27 + padding: 0.5em 1em
28 + display:inline-block
29 + }
30 +}
31 +pre.mnemonic {
32 + border: 1px #aeaeae solid
33 + background: #44475a
34 + color: #aaa
35 + white-space: pre-wrap
36 + line-height: 1.5
37 + padding: 0.5em
38 + display:inline-block
39 +}
styles/light/base.mcssView
@@ -7,4 +7,23 @@
77 :hover {
88 color: #5eabff
99 }
1010 }
11 +
12 +div {
13 + -mnemonicWarning {
14 + border: 1px solid #ffc965
15 + background: #ffebcc
16 + color: #8a6800
17 + padding: 0.5em 1em
18 + display:inline-block
19 + }
20 +}
21 +pre.mnemonic {
22 + border: 1px gainsboro solid
23 + background: #fafafa
24 + color: #7c7c7c
25 + white-space: pre-wrap
26 + line-height: 1.5
27 + padding: 0.5em 1em
28 + display:inline-block
29 +}

Built with git-ssb-web